1. 程式人生 > >使用者註冊登陸&引數校驗器&全域性捕獲異常&分散式session

使用者註冊登陸&引數校驗器&全域性捕獲異常&分散式session

工具類準備

分散式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";
    }
    
}

測試

 

碼源