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;
}
}

浙公网安备 33010602011771号