1-1 用户登录功能

1. 数据库建表

新建表MiaoshaUser,用于存储所有用户的用户名和密码等信息,该表有以下几个字段:
  • id:用户名
  • nickname:昵称
  • password:密码
  • salt:随机字符串,用于和密码拼接计算MD5值
  • head:头像
  • register_date:注册时间
  • last_login_time:上一次登陆时间
  • login_count:登录次数

2. 定义MiaoshaUser类

属性与数据库字段相对应
package com.miaosha.pojo;
import lombok.Data;
import java.util.Date;

@Data
public class MiaoshaUser {
    private Long id;
    private String nickname;
    private String password;
    private String salt;
    private String head;
    private Date registerDate;
    private Date lastLoginDate;
    private Integer loginCount;
}

3. MiaoshaUser表的Dao层

登录功能主要是查询用户是否存在,代码如下:
package com.miaosha.dao;
import com.miaosha.pojo.MiaoshaUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface MiaosahaUserDao {
    @Select("select * from miaosha_user where id = #{id}")
    public MiaoshaUser getById(@Param("id") long id);
}

4. 登录前端界面

前端对用户输入的密码做一次MD5计算后,通过AJAX异步传输给后端做参数校验
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>登录</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    
    <!-- jquery -->
    <script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
    <!-- bootstrap -->
    <link rel="stylesheet" type="text/css" th:href="@{/bootstrap/css/bootstrap.min.css}" />
    <script type="text/javascript" th:src="@{/bootstrap/js/bootstrap.min.js}"></script>
    <!-- jquery-validator -->
    <script type="text/javascript" th:src="@{/jquery-validation/jquery.validate.min.js}"></script>
    <script type="text/javascript" th:src="@{/jquery-validation/localization/messages_zh.min.js}"></script>
    <!-- layer -->
    <script type="text/javascript" th:src="@{/layer/layer.js}"></script>
    <!-- md5.js -->
    <script type="text/javascript" th:src="@{/js/md5.min.js}"></script>
    <!-- common.js -->
    <script type="text/javascript" th:src="@{/js/common.js}"></script>
    
</head>
<body>

<form name="loginForm" id="loginForm" method="post"  style="width:50%; margin:0 auto">

	<h2 style="text-align:center; margin-bottom: 20px">用户登录</h2>
	
	<div class="form-group">
       	<div class="row">
	       	<label class="form-label col-md-4">请输入手机号码</label>
	        <div class="col-md-5">
	        	<input id="mobile" name = "mobile" class="form-control" type="text" placeholder="手机号码" required="true"  minlength="11" maxlength="11" />
	    	</div>
	    	<div class="col-md-1">
	    	</div>
    	</div>
    </div>
    
    <div class="form-group">
     		<div class="row">
		        <label class="form-label col-md-4">请输入密码</label>
		        <div class="col-md-5">
		        	<input id="password" name="password" class="form-control" type="password"  placeholder="密码" required="true" minlength="6" maxlength="16" />
	       		</div>
      		</div>
	</div>
	
	<div class="row">
		     	<div class="col-md-5">
	       	 		<button class="btn btn-primary btn-block" type="reset" onclick="reset()">重置</button>
	       	 	</div>
	       	 	<div class="col-md-5">
	       	 		<button class="btn btn-primary btn-block" type="submit" onclick="login()">登录</button>
	       	 	</div>
	 </div>
	 
</form>
</body>
<script>
function login(){
	$("#loginForm").validate({
        submitHandler:function(form){
             doLogin();
        }    
    });
}
function doLogin(){
	g_showLoading();
	var inputPass = $("#password").val();
	var salt = g_passsword_salt;
	var str = ""+salt.charAt(0)+salt.charAt(2) + inputPass +salt.charAt(5) + salt.charAt(4);
	var password = md5(str);
	
	$.ajax({
	    url: "/login/do_login", 
	    type: "POST",
	    data:{
	    	mobile:$("#mobile").val(),
	    	password: password
	    },
	    success:function(data){
	    	layer.closeAll();
	    	if(data.code == 0){
	    		layer.msg("成功");
	    		window.location.href="/goods/to_list";
	    	}else{
	    		layer.msg(data.msg);
	    	}
	    },
	    error:function(){
	    	layer.closeAll();
	    }
	});
}
</script>
</html>

5. Controller层

后端的doLogin方法对前端传输的用户名和密码进行参数校验,loginVo是一个Java Bean对象,它里面的属性和前端传输的数据的字段名是一一对应的,所以前端传输的登录数据可以自动封装到loginVo对象里面。
package com.miaosha.controller;
import com.miaosha.redis.RedisService;
import com.miaosha.result.Result;
import com.miaosha.service.MiaoshaUserService;
import com.miaosha.vo.LoginVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

@Controller
@RequestMapping("/login")
public class LoginController {
    private static Logger log = LoggerFactory.getLogger(LoginController.class);

    @Autowired
    MiaoshaUserService userService;

    @Autowired
    RedisService redisService;

    @RequestMapping("/to_login")
    public String toLogin() {
        return "login";
    }

    @RequestMapping("/do_login")
    @ResponseBody
    public Result<Boolean> doLogin(@Valid LoginVo loginVo) {
        log.info(loginVo.toString());
        //登录
        userService.login(loginVo);
        return Result.success(true);
    }
}

@Valid注解是验证合法性的第一道关卡,它用于验证变量是否符合要求,在这里它会依次验证mobile和password属性上的注解是否满足,@IsMobile是自定义的用于验证手机号是否合法的注解,

package com.miaosha.vo;
import com.miaosha.validator.IsMobile;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotNull;

@Data
public class LoginVo {
    @NotNull
    @IsMobile
    private String mobile;
    @NotNull
    @Length(min=32)
    private String password;
}

6. Service层

Service层利用Dao层的查询结果完成登录功能。通过数据合法性的检验之后,就会调用login()方法判断是否存在该用户,如果存在,再判断密码是否正确,处于安全考虑,密码会做两次MD5运算之后才存入数据库。GlobalException是自定义的异常类,CodeMsg里面自定义了一些异常代码以及对应的错误提示信息。
package com.miaosha.service;
import com.miaosha.dao.MiaosahaUserDao;
import com.miaosha.exception.GlobalException;
import com.miaosha.pojo.MiaoshaUser;
import com.miaosha.redis.RedisService;
import com.miaosha.result.CodeMsg;
import com.miaosha.util.MD5Util;
import com.miaosha.vo.LoginVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MiaoshaUserService {

    @Autowired
    MiaosahaUserDao miaosahaUserDao;

    @Autowired
    RedisService redisService;

    public MiaoshaUser getById(long id){
        return miaosahaUserDao.getById(id);
    }

    public boolean login(LoginVo loginVo){
        if(loginVo == null) {
            throw new GlobalException(CodeMsg.SERVER_ERROR);
        }
        String mobile = loginVo.getMobile();
        String formPass = loginVo.getPassword();
        //判断手机号是否存在
        MiaoshaUser user = getById(Long.parseLong(mobile));
        if(user == null) {
            throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
        }

        //验证密码
        String dbPass = user.getPassword();
        String saltDB = user.getSalt();
        String calcPass = MD5Util.formPassToDBPass(formPass, saltDB);
        if(!calcPass.equals(dbPass)) {
            throw new GlobalException(CodeMsg.PASSWORD_ERROR);
        }
        return true;
    }
}

7. 总结

知识点:参数校验、自定义注解
posted @ 2022-06-12 16:39  学海无涯#  阅读(175)  评论(0)    收藏  举报