使用者註冊登陸&引數校驗器&全域性捕獲異常&分散式session
阿新 • • 發佈:2018-12-12
工具類準備
分散式ID工具類
package com.example.miaosha_xdp.util;
import java.util.UUID;
public class UUIDUtil {
public static String uuid(){
/**
*用java.util.UUID生成隨機字串
*將字串裡面的"-"替換
*/
return UUID.randomUUID().toString().replace("-", "");
}
}
全域性捕獲異常
定義我們自己的全域性異常類
package com.example.miaosha_xdp.exception; import com.example.miaosha_xdp.result.CodeMsg; import lombok.Getter; @Getter public class GlobalException extends RuntimeException { private static final long serialVersionUID = 1L; private CodeMsg codeMsg; public GlobalException(CodeMsg codeMsg) { super(codeMsg.toString()); this.codeMsg = codeMsg; } }
定義我們的全域性異常處理器
package com.example.miaosha_xdp.exception; import com.example.miaosha_xdp.result.CodeMsg; import com.example.miaosha_xdp.result.Result; import org.springframework.validation.BindException; import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import java.util.List; @ControllerAdvice @ResponseBody public class GlobalExceptionHandler { @ExceptionHandler(value = Exception.class) public Result<String> exceptionHandler(Exception e){ e.printStackTrace(); if (e instanceof GlobalException){ GlobalException globalException = (GlobalException) e; return Result.error(globalException.getCodeMsg()); } if (e instanceof BindException){ BindException bindException = (BindException) e; List<ObjectError> errors = bindException.getAllErrors(); ObjectError error = errors.get(0); String errorDefaultMessage = error.getDefaultMessage(); return Result.error(CodeMsg.BIND_ERROR.fillArgs(errorDefaultMessage)); } return Result.error(CodeMsg.SERVER_ERROR); } }
使用引數校驗器
引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
定義我們自己的校驗器
package com.example.miaosha_xdp.util;
import org.springframework.util.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ValidatorUtil {
/**
* 定義正則表示式規則
*/
public static final Pattern MOBILE_PATTERN = Pattern.compile("1\\d{10}");
/**
* 校驗手機號
* @param str
* @return
*/
public static boolean isMObile(String str){
if (StringUtils.isEmpty(str)){
return false;
}
Matcher matcher = MOBILE_PATTERN.matcher(str);
return matcher.matches();
}
}
package com.example.miaosha_xdp.validator;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.groups.Default;
import java.lang.annotation.*;
@Target({ElementType.METHOD,ElementType.FIELD,ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {IsMobileValidator.class})
public @interface IsMobile {
boolean required() default true;//註解裡面必須有這個屬性,預設為空
String message() default "手機號碼格式錯誤";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default{};
}
package com.example.miaosha_xdp.validator;
import com.example.miaosha_xdp.util.ValidatorUtil;
import org.springframework.util.StringUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.annotation.Annotation;
public class IsMobileValidator implements ConstraintValidator<IsMobile,String> {
private boolean requried =false;
@Override
public void initialize(IsMobile constraintAnnotation) {
requried=constraintAnnotation.required();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
if (requried){
return ValidatorUtil.isMObile(value);
}
if (StringUtils.isEmpty(value)){
return true;
}
return ValidatorUtil.isMObile(value);
}
}
建立一個VO類
package com.example.miaosha_xdp.VO;
import com.example.miaosha_xdp.validator.IsMobile;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotNull;
@Getter
@Setter
@ToString
public class LoginVo {
/**
* 這裡使用的是引數校驗器的註解
*/
@NotNull
@IsMobile
private String mobile;
@NotNull
@Length(min = 32)
private String password;
}
編寫service層
package com.example.miaosha_xdp.service;
import com.example.miaosha_xdp.VO.LoginVo;
import com.example.miaosha_xdp.entity.User;
import com.example.miaosha_xdp.exception.GlobalException;
import com.example.miaosha_xdp.mapper.UserMapper;
import com.example.miaosha_xdp.redis.MiaoshaUserKey;
import com.example.miaosha_xdp.redis.RedisService;
import com.example.miaosha_xdp.result.CodeMsg;
import com.example.miaosha_xdp.result.Result;
import com.example.miaosha_xdp.util.MD5Util;
import com.example.miaosha_xdp.util.UUIDUtil;
import org.hibernate.validator.constraints.Length;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
@Service
@Transactional
public class UserService {
public static final String TOKEN = "token";
@Autowired
private UserMapper userMapper;
@Autowired
private RedisService redisService;
/**
* 登陸
* @param response
* @param loginVo
* @return
*/
public boolean login(HttpServletResponse response, LoginVo loginVo){
if (loginVo==null){
throw new GlobalException(CodeMsg.SERVER_ERROR);
}
@NotNull String mobile = loginVo.getMobile();
@NotNull @Length(min = 32) String password = loginVo.getPassword();
//檢視使用者是否存在
long longMobile = Long.parseLong(mobile);
User user = byId(longMobile);
if (user==null){
throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
}
//驗證密碼
String userPassword = user.getPassword();
String salt = user.getSalt();
String saltPassword = MD5Util.formPassToDBPass(userPassword, salt);
if (!saltPassword.equals(password)){
throw new GlobalException(CodeMsg.PASSWORD_ERROR);
}
//生成token
String token = UUIDUtil.uuid();
addCookie(response,token,user);
return true;
}
/**
*根據token進行查詢
* @param response
* @param token
* @return
*/
public User byToken(HttpServletResponse response,String token){
if (StringUtils.isEmpty(token)){
return null;
}
User user = redisService.get(MiaoshaUserKey.token, token, User.class);
//延長有效期
if(user!=null){
addCookie(response,token,user);
}
return user;
}
/**
* 新增cookie
* @param response
* @param token
* @param user
*/
private void addCookie(HttpServletResponse response,String token,User user){
redisService.set(MiaoshaUserKey.token,token,user);
Cookie cookie = new Cookie(TOKEN, token);
cookie.setMaxAge(MiaoshaUserKey.token.expireSeconds());
cookie.setPath("/");
response.addCookie(cookie);
}
/**
* 根據id查詢使用者
* @param id
* @return
*/
public User byId(Long id){
return userMapper.selectByPrimaryKey(id);
}
}
編寫控制層
package com.example.miaosha_xdp.controller;
import com.example.miaosha_xdp.VO.LoginVo;
import com.example.miaosha_xdp.entity.User;
import com.example.miaosha_xdp.redis.RedisService;
import com.example.miaosha_xdp.result.CodeMsg;
import com.example.miaosha_xdp.result.Result;
import com.example.miaosha_xdp.service.UserService;
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.*;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
@Controller
@RequestMapping("/user")
public class UserController {
public static final String LOGIN = "login";
private static Logger logger= LoggerFactory.getLogger(UserController.class);
@Autowired
private UserService userService;
@Autowired
private RedisService redisService;
/**
* 跳轉到登陸頁面
* @return
*/
@GetMapping("/login")
public String login(){
return LOGIN;
}
/**
* 實現登陸
* @Valid 註解不能少,表示開啟引數校驗器
* @param response
* @param loginVo
* @return
*/
@RequestMapping("/to_login")
@ResponseBody
public Result<Boolean> to_login(HttpServletResponse response,@Valid LoginVo loginVo){
logger.info(loginVo.toString());
userService.login(response,loginVo);
return Result.success(true);
}
}
前端程式碼
匯入靜態資源
編寫我們的common.js
//展示loading
function g_showLoading(){
var idx = layer.msg('處理中...', {icon: 16,shade: [0.5, '#f5f5f5'],scrollbar: false,offset: '0px', time:100000}) ;
return idx;
}
//salt
var g_passsword_salt="1a2b3c4d"
在登陸頁面引入相關需要
<!-- 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>
編寫登陸頁面的Js
<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: "/user/to_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>
這裡我們需要再編寫一個商品列表頁面goods_list.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>商品列表</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'hello:'+${user.nickname}" ></p>
</body>
</html>
再編寫一個商品列表控制器
package com.example.miaosha_xdp.controller;
import com.example.miaosha_xdp.entity.User;
import com.example.miaosha_xdp.redis.RedisService;
import com.example.miaosha_xdp.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/goods")
public class GoodsController {
@Autowired
UserService userService;
@Autowired
RedisService redisService;
@RequestMapping("/to_list")
public String list(Model model, User user) {
model.addAttribute("user", user);
return "goods_list";
}
}
測試