SpringBoot+2次MD5登录密码加密+MyBatisPlus+Thymeleaf+Bootstrap简单实现登录功能,一文轻松搞定!

news2024/11/15 10:58:41

这里写目录标题

  • 一、演示GIF
  • 二、开发前期准备
    • 1、数据库
    • 2、依赖POM.XML
    • 3、idea结构目录
  • 三、后端
    • 1、实体类
    • 2、mapper接口
    • 3、mapper.xml
    • 4、Servicce接口
    • 5、Impl实现
    • 6、Controller控制器
    • 7、全局异常处理类
      • GlobalException
      • GlobalExceptionHandler
    • 8、工具类
      • MD5Util
      • UUIDUtil
      • CookieUtil
      • ValidatorUtil
    • 9、手机号处理类
      • validator
      • IsMobileValidator
    • 10、Vo类
      • LoginVo
      • RespBean
      • RespBeanEnum
  • 四、前端
      • login.html
      • list.html

一、演示GIF

在这里插入图片描述
本文通过SpringBoot+2次MD5登录密码加密+MyBatisPlus+Thymeleaf+bootstrap简单实现登录功能

  • 登录时手机号作为账号有验证
  • 密码作为2次MD5加密
  • MybatisPlus开发时方便 高效
  • Bootstrap作为前端框架

二、开发前期准备

1、数据库

CREATE TABLE `t_user` (
  `id` bigint(20) NOT NULL COMMENT '用户ID shoujihaoma',
  `nickname` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `pasword` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'MD5二次加密',
  `slat` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `head` varchar(128) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '头像',
  `register_date` datetime DEFAULT NULL COMMENT '注册时间',
  `last_login_date` datetime DEFAULT NULL COMMENT '最后一次登录时间',
  `login_count` int(11) DEFAULT '0' COMMENT '登录次数',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

2、依赖POM.XML

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--        mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

<!--        MD5依赖-->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
        </dependency>
        <!--   validation   参数校验-->`在这里插入代码片`
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

3、idea结构目录

在这里插入图片描述

三、后端

1、实体类

package com.seckilldemo.pojo;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;
import java.util.Date;

/**
 * <p>
 *
 * </p>
 *
 * @author syj
 * @since 2023-01-14
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_user")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 用户ID shoujihaoma
     */
    private Long id;

    private String nickname;

    /**
     * MD5二次加密
     */
    private String pasword;

    private String slat;

    /**
     * 头像
     */
    private String head;

    /**
     * 注册时间
     */
    private Date registerDate;

    /**
     * 最后一次登录时间
     */
    private Date lastLoginDate;

    /**
     * 登录次数
     */
    private Integer loginCount;


}

2、mapper接口

package com.seckilldemo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.seckilldemo.pojo.User;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author syj
 * @since 2023-01-14
 */
public interface UserMapper extends BaseMapper<User> {

}

3、mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.seckilldemo.mapper.UserMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.seckilldemo.pojo.User">
        <id column="id" property="id" />
        <result column="nickname" property="nickname" />
        <result column="pasword" property="pasword" />
        <result column="slat" property="slat" />
        <result column="head" property="head" />
        <result column="register_date" property="registerDate" />
        <result column="last_login_date" property="lastLoginDate" />
        <result column="login_count" property="loginCount" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, nickname, pasword, slat, head, register_date, last_login_date, login_count
    </sql>

</mapper>

4、Servicce接口

package com.seckilldemo.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.seckilldemo.pojo.User;
import com.seckilldemo.vo.LoginVo;
import com.seckilldemo.vo.RespBean;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author syj
 * @since 2023-01-14
 */
public interface IUserService extends IService<User> {

    RespBean doLogin(LoginVo loginVo, HttpServletResponse response, HttpServletRequest request);
}

5、Impl实现

package com.seckilldemo.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.seckilldemo.exception.GlobalException;
import com.seckilldemo.mapper.UserMapper;
import com.seckilldemo.pojo.User;
import com.seckilldemo.service.IUserService;
import com.seckilldemo.utils.CookieUtil;
import com.seckilldemo.utils.MD5Util;
import com.seckilldemo.utils.UUIDUtil;
import com.seckilldemo.utils.ValidatorUtil;
import com.seckilldemo.vo.LoginVo;
import com.seckilldemo.vo.RespBean;
import com.seckilldemo.vo.RespBeanEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author syj
 * @since 2023-01-14
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public RespBean doLogin(LoginVo loginVo, HttpServletResponse response, HttpServletRequest request){
        String mobile = loginVo.getMobile();
        String password = loginVo.getPassword();
//        if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)){
//            return RespBean.error(RespBeanEnum.LOGIN_ERROR);
//        }
//        if(!ValidatorUtil.isMobile(mobile)){
//            return RespBean.error(RespBeanEnum.MOBILE_ERROR);
//        }
        User user = userMapper.selectById(mobile);
        //根据手机号获取用户
        if (null == user){
            throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
        }
        //判断密码是否正确
        if(!MD5Util.fromPassToDBPass(password,user.getSlat()).equals(user.getPasword())){
            throw new GlobalException(RespBeanEnum.LOGIN_ERROR);
        }
        //生成cokie
        String ticket = UUIDUtil.uuid();
        request.getSession().setAttribute(ticket,user);
        CookieUtil.setCookie(request,response,"userTicket",ticket);
        return RespBean.success();
    }
}

6、Controller控制器

package com.seckilldemo.controller;

import com.seckilldemo.service.IUserService;
import com.seckilldemo.utils.ValidatorUtil;
import com.seckilldemo.vo.LoginVo;
import com.seckilldemo.vo.RespBean;
import com.seckilldemo.vo.RespBeanEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

@Controller
@RequestMapping("/login")
@Slf4j
public class LoginController {

    @Autowired
    private IUserService userService;


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


    @RequestMapping("/doLogin")
    @ResponseBody
    public RespBean doLogin(@Valid LoginVo loginVo, HttpServletRequest request, HttpServletResponse response){
        return userService.doLogin(loginVo,response,request);
    }

}

7、全局异常处理类

  • GlobalException

package com.seckilldemo.exception;

import com.seckilldemo.vo.RespBean;
import com.seckilldemo.vo.RespBeanEnum;

/**
 * 全局异常
 *
 * @author: LC
 * @date 2022/3/2 5:32 下午
 * @ClassName: GlobalException
 */
public class GlobalException extends RuntimeException {

    private RespBeanEnum respBeanEnum;

    public RespBeanEnum getRespBeanEnum() {
        return respBeanEnum;
    }

    public void setRespBeanEnum(RespBeanEnum respBeanEnum) {
        this.respBeanEnum = respBeanEnum;
    }

    public GlobalException(RespBeanEnum respBeanEnum) {
        this.respBeanEnum = respBeanEnum;
    }
}

  • GlobalExceptionHandler

package com.seckilldemo.exception;

import com.seckilldemo.vo.RespBean;
import com.seckilldemo.vo.RespBeanEnum;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;


/**
 * 全局异常处理类
 *
 * @author: LC
 * @date 2022/3/2 5:33 下午
 * @ClassName: GlobalExceptionHandler
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public RespBean ExceptionHandler(Exception e) {
        if (e instanceof GlobalException) {
            GlobalException exception = (GlobalException) e;
            return RespBean.error(exception.getRespBeanEnum());
        } else if (e instanceof BindException) {
            BindException bindException = (BindException) e;
            RespBean respBean = RespBean.error(RespBeanEnum.BIND_ERROR);
            respBean.setMessage("参数校验异常:" + bindException.getBindingResult().getAllErrors().get(0).getDefaultMessage());
            return respBean;
        }
        System.out.println("异常信息" + e);
        return RespBean.error(RespBeanEnum.ERROR);
    }
}

8、工具类

  • CookieUtil
package com.seckilldemo.utils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * Cookie工具类
 *
 * @author: LC
 * @date 2022/3/2 5:48 下午
 * @ClassName: CookieUtil
 */
public final class CookieUtil {

    /**
     * 得到Cookie的值, 不编码
     *
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName) {
        return getCookieValue(request, cookieName, false);
    }

    /**
     * 得到Cookie的值,
     *
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    if (isDecoder) {
                        retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
                    } else {
                        retValue = cookieList[i].getValue();
                    }
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return retValue;
    }

    /**
     * 得到Cookie的值,
     *
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return retValue;
    }

    /**
     * 设置Cookie的值 不设置生效时间默认浏览器关闭即失效,也不编码
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue) {
        setCookie(request, response, cookieName, cookieValue, -1);
    }

    /**
     * 设置Cookie的值 在指定时间内生效,但不编码
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue, int cookieMaxage) {
        setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
    }

    /**
     * 设置Cookie的值 不设置生效时间,但编码
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue, boolean isEncode) {
        setCookie(request, response, cookieName, cookieValue, -1, isEncode);
    }

    /**
     * 设置Cookie的值 在指定时间内生效, 编码参数
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue, int cookieMaxage, boolean isEncode) {
        doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
    }

    /**
     * 设置Cookie的值 在指定时间内生效, 编码参数(指定编码)
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue, int cookieMaxage, String encodeString) {
        doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
    }

    /**
     * 删除Cookie带cookie域名
     */
    public static void deleteCookie(HttpServletRequest request, HttpServletResponse response,
                                    String cookieName) {
        doSetCookie(request, response, cookieName, "", -1, false);
    }

    /**
     * 设置Cookie的值,并使其在指定时间内生效
     *
     * @param cookieMaxage cookie生效的最大秒数
     */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
                                          String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
        try {
            if (cookieValue == null) {
                cookieValue = "";
            } else if (isEncode) {
                cookieValue = URLEncoder.encode(cookieValue, "utf-8");
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0)
                cookie.setMaxAge(cookieMaxage);
            if (null != request) {// 设置域名的cookie
                String domainName = getDomainName(request);
                System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
                    cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置Cookie的值,并使其在指定时间内生效
     *
     * @param cookieMaxage cookie生效的最大秒数
     */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
                                          String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
        try {
            if (cookieValue == null) {
                cookieValue = "";
            } else {
                cookieValue = URLEncoder.encode(cookieValue, encodeString);
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0) {
                cookie.setMaxAge(cookieMaxage);
            }
            if (null != request) {// 设置域名的cookie
                String domainName = getDomainName(request);
                System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
                    cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 得到cookie的域名
     */
    private static final String getDomainName(HttpServletRequest request) {
        String domainName = null;
        // 通过request对象获取访问的url地址
        String serverName = request.getRequestURL().toString();
        if (serverName == null || serverName.equals("")) {
            domainName = "";
        } else {
            // 将url地下转换为小写
            serverName = serverName.toLowerCase();
            // 如果url地址是以http://开头  将http://截取
            if (serverName.startsWith("http://")) {
                serverName = serverName.substring(7);
            }
            int end = serverName.length();
            // 判断url地址是否包含"/"
            if (serverName.contains("/")) {
                //得到第一个"/"出现的位置
                end = serverName.indexOf("/");
            }

            // 截取
            serverName = serverName.substring(0, end);
            // 根据"."进行分割
            final String[] domains = serverName.split("\\.");
            int len = domains.length;
            if (len > 3) {
                // www.xxx.com.cn
                domainName = domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
            } else if (len <= 3 && len > 1) {
                // xxx.com or xxx.cn
                domainName = domains[len - 2] + "." + domains[len - 1];
            } else {
                domainName = serverName;
            }
        }

        if (domainName != null && domainName.indexOf(":") > 0) {
            String[] ary = domainName.split("\\:");
            domainName = ary[0];
        }
        return domainName;
    }
}

  • MD5Util

package com.seckilldemo.utils;

import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Component;

@Component
public class MD5Util {

    public static String md5(String src){
        return DigestUtils.md5Hex(src);
    }

    private static final String salt="1a2b3c4d";

    public static String inpuntPassToFromPass(String inputPass){
        String str = "" +salt.charAt(0)+salt.charAt(2)+inputPass+salt.charAt(5)+salt.charAt(4);
        return md5(str);
    }

    public static String fromPassToDBPass(String fromPass,String salt){
        String str = "" +salt.charAt(0)+salt.charAt(2)+fromPass+salt.charAt(5)+salt.charAt(4);
        return md5(str);
    }

    public static String inputPassToDBPass(String inputPass,String salt){
        String fromPass = inpuntPassToFromPass(inputPass);
        String dbPass = fromPassToDBPass(fromPass, salt);
        return dbPass;
    }

    public static void main(String[] args) {
        //d3b1294a61a07da9b49b6e22b2cbd7f9
        System.out.println(inpuntPassToFromPass("123456"));
        System.out.println(fromPassToDBPass("d3b1294a61a07da9b49b6e22b2cbd7f9","1a2b3c4d"));
        System.out.println(inputPassToDBPass("123456","1a2b3c4d"));
    }
}

  • UUIDUtil

package com.seckilldemo.utils;

import java.util.UUID;

/**
 * UUID工具类
 *
 * @author: LC
 * @date 2022/3/2 5:46 下午
 * @ClassName: UUIDUtil
 */
public class UUIDUtil {

    public static String uuid() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}

  • CookieUtil

package com.seckilldemo.utils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * Cookie工具类
 *
 * @author: LC
 * @date 2022/3/2 5:48 下午
 * @ClassName: CookieUtil
 */
public final class CookieUtil {

    /**
     * 得到Cookie的值, 不编码
     *
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName) {
        return getCookieValue(request, cookieName, false);
    }

    /**
     * 得到Cookie的值,
     *
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    if (isDecoder) {
                        retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
                    } else {
                        retValue = cookieList[i].getValue();
                    }
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return retValue;
    }

    /**
     * 得到Cookie的值,
     *
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return retValue;
    }

    /**
     * 设置Cookie的值 不设置生效时间默认浏览器关闭即失效,也不编码
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue) {
        setCookie(request, response, cookieName, cookieValue, -1);
    }

    /**
     * 设置Cookie的值 在指定时间内生效,但不编码
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue, int cookieMaxage) {
        setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
    }

    /**
     * 设置Cookie的值 不设置生效时间,但编码
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue, boolean isEncode) {
        setCookie(request, response, cookieName, cookieValue, -1, isEncode);
    }

    /**
     * 设置Cookie的值 在指定时间内生效, 编码参数
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue, int cookieMaxage, boolean isEncode) {
        doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
    }

    /**
     * 设置Cookie的值 在指定时间内生效, 编码参数(指定编码)
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                                 String cookieValue, int cookieMaxage, String encodeString) {
        doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
    }

    /**
     * 删除Cookie带cookie域名
     */
    public static void deleteCookie(HttpServletRequest request, HttpServletResponse response,
                                    String cookieName) {
        doSetCookie(request, response, cookieName, "", -1, false);
    }

    /**
     * 设置Cookie的值,并使其在指定时间内生效
     *
     * @param cookieMaxage cookie生效的最大秒数
     */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
                                          String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
        try {
            if (cookieValue == null) {
                cookieValue = "";
            } else if (isEncode) {
                cookieValue = URLEncoder.encode(cookieValue, "utf-8");
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0)
                cookie.setMaxAge(cookieMaxage);
            if (null != request) {// 设置域名的cookie
                String domainName = getDomainName(request);
                System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
                    cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置Cookie的值,并使其在指定时间内生效
     *
     * @param cookieMaxage cookie生效的最大秒数
     */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
                                          String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
        try {
            if (cookieValue == null) {
                cookieValue = "";
            } else {
                cookieValue = URLEncoder.encode(cookieValue, encodeString);
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0) {
                cookie.setMaxAge(cookieMaxage);
            }
            if (null != request) {// 设置域名的cookie
                String domainName = getDomainName(request);
                System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
                    cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 得到cookie的域名
     */
    private static final String getDomainName(HttpServletRequest request) {
        String domainName = null;
        // 通过request对象获取访问的url地址
        String serverName = request.getRequestURL().toString();
        if (serverName == null || serverName.equals("")) {
            domainName = "";
        } else {
            // 将url地下转换为小写
            serverName = serverName.toLowerCase();
            // 如果url地址是以http://开头  将http://截取
            if (serverName.startsWith("http://")) {
                serverName = serverName.substring(7);
            }
            int end = serverName.length();
            // 判断url地址是否包含"/"
            if (serverName.contains("/")) {
                //得到第一个"/"出现的位置
                end = serverName.indexOf("/");
            }

            // 截取
            serverName = serverName.substring(0, end);
            // 根据"."进行分割
            final String[] domains = serverName.split("\\.");
            int len = domains.length;
            if (len > 3) {
                // www.xxx.com.cn
                domainName = domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
            } else if (len <= 3 && len > 1) {
                // xxx.com or xxx.cn
                domainName = domains[len - 2] + "." + domains[len - 1];
            } else {
                domainName = serverName;
            }
        }

        if (domainName != null && domainName.indexOf(":") > 0) {
            String[] ary = domainName.split("\\:");
            domainName = ary[0];
        }
        return domainName;
    }
}

  • ValidatorUtil

package com.seckilldemo.utils;

import org.thymeleaf.util.StringUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ValidatorUtil {
    private static final Pattern mobile_patten = Pattern.compile("[1]([3-9])[0-9]{9}$");

    public static boolean isMobile(String mobile){
        if(StringUtils.isEmpty(mobile)){
            return false;
        }
        Matcher matcher = mobile_patten.matcher(mobile);
        return matcher.matches();
    }

}

9、手机号处理类

  • validator

package com.seckilldemo.validator;
import com.seckilldemo.utils.ValidatorUtil;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.Validator;
import javax.validation.constraints.NotNull;
import java.lang.annotation.*;

/**
 * 验证手机号
 *
 * @author: LC
 * @date 2022/3/2 3:05 下午
 * @ClassName: isMobile
 */
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@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 {};
}

  • IsMobileValidator

package com.seckilldemo.validator;

import com.seckilldemo.utils.ValidatorUtil;
import org.thymeleaf.util.StringUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

/**
 * 手机号码校验规则
 *
 * @author: LC
 * @date 2022/3/2 3:08 下午
 * @ClassName: IsMobileValidator
 */
public class IsMobileValidator implements ConstraintValidator<IsMobile, String> {

    private boolean required = false;

    @Override
    public void initialize(IsMobile constraintAnnotation) {
//        ConstraintValidator.super.initialize(constraintAnnotation);
        required = constraintAnnotation.required();
    }

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        if (required) {
            return ValidatorUtil.isMobile(s);
        } else {
            if (StringUtils.isEmpty(s)) {
                return true;
            } else {
                return ValidatorUtil.isMobile(s);
            }
        }
    }
}

10、Vo类

  • LoginVo

package com.seckilldemo.vo;

import com.seckilldemo.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;

}

  • RespBean

package com.seckilldemo.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 公共返回对象
 *
 * @author: LC
 * @date 2022/3/2 1:50 下午
 * @ClassName: RespBean
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RespBean {

    private long code;
    private String message;
    private Object object;

    public static RespBean success() {
        return new RespBean(RespBeanEnum.SUCCESS.getCode(), RespBeanEnum.SUCCESS.getMessage(), null);
    }

    public static RespBean success(Object object) {
        return new RespBean(RespBeanEnum.SUCCESS.getCode(), RespBean.success().getMessage(), object);
    }

    public static RespBean error(RespBeanEnum respBeanEnum) {
        return new RespBean(respBeanEnum.getCode(), respBeanEnum.getMessage(), null);
    }

    public static RespBean error(RespBeanEnum respBeanEnum, Object object) {
        return new RespBean(respBeanEnum.getCode(), respBeanEnum.getMessage(), object);
    }

}

  • RespBeanEnum

package com.seckilldemo.vo;


import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;

/**
 * 公共返回对象枚举
 *
 * @author: LC
 * @date 2022/3/2 1:44 下午
 * @ClassName: RespBean
 */
@Getter
@ToString
@AllArgsConstructor
public enum RespBeanEnum {
    //通用
    SUCCESS(200, "SUCCESS"),
    ERROR(500, "服务端异常"),

    //登录模块
    LOGIN_ERROR(500210, "用户名或者密码不正确"),
    MOBILE_ERROR(500211, "手机号码格式不正确"),
    BIND_ERROR(500212, "参数校验异常"),
    MOBILE_NOT_EXIST(500213, "手机号码不存在"),
    PASSWORD_UPDATE_FAIL(500214, "更新密码失败"),
    SESSION_ERROR(500215, "用户SESSION不存在"),


    //秒杀模块
    EMPTY_STOCK(500500, "库存不足"),
    REPEATE_ERROR(500501, "该商品每人限购一件"),
    REQUEST_ILLEGAL(500502, "请求非法,请重新尝试"),
    ERROR_CAPTCHA(500503, "验证码错误,请重新输入"),
    ACCESS_LIMIT_REACHED(500504, "访问过于频繁,请稍后重试"),
    //订单模块5003xx
    ORDER_NOT_EXIST(500300, "订单不存在"),


    ;

    private final Integer code;
    private final String message;

}

四、前端

  • login.html

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>登录</title>
  <!-- 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/doLogin",
      type: "POST",
      data: {
        mobile: $("#mobile").val(),
        password: password
      },
      success: function (data) {
        layer.closeAll();
        if (data.code == 200) {
          layer.msg("成功");
          console.log(data);
          document.cookie = "userTicket=" + data.object;
          window.location.href = "/goods/toList";
        } else {
          layer.msg(data.message);
        }
      },
      error: function () {
        layer.closeAll();
      }
    });
  }
</script>
</html>

  • list.html

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>商品列表</title>
</head>
<body>
  <p th:text="'Hello:'+${user.nickname}"></p>
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/165935.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

消息批处理端口说明

为满足用户需要对多文件做批处理的需求&#xff0c;在2022版本的知行之桥中&#xff0c;开发人员开发设计了3个新的端口&#xff0c;分别是Batch Create 端口、Batch Merge 端口和Batch Split 端口。 功能是对传入端口的消息做批处理&#xff0c;使得消息可以在批处理组中分组在…

mybatis-plus分布式id重复问题

问题起因 k8s 部署的一个服务的两个节点集群 最近频繁报错&#xff0c;数据库主键ID重复&#xff0c;导致数据插入报错 问题定位 还在定位。。。。 问题解决 解决办法主要有两个 指定mybatis-plus workerId dataCenterId 全局配置 #注意这里使用的随机策略 随机区间 …

智能边缘网关

背景介绍 调研发现&#xff0c;数字经济为工业物联网、智能交通以及智慧医疗等场景提出了新的解决方案。工程师利用传感器边缘网关云服务器的系统架构&#xff0c;通过大数据及人工智能算法进行辅助决策&#xff0c;最终为工业设备赋能&#xff0c;提高加工生产效率。近年来&am…

sqli-labs 11~14 多命通关攻略(报错注入)

sqli-labs 11~14 多命通关攻略&#xff08;报错注入&#xff09;描述判断注入类型返回结果错误输入总结符号注释判断返回结果中的列数判断返回结果中的列数为 1判断返回结果中的列数为 2报错注入通过报错注入爆破数据库中的表名通过报错注入爆破数据库中的表名&#xff08;逻辑…

【高阶数据结构】封装unordered_map 和 unordered_set

&#x1f308;欢迎来到数据结构专栏~~封装unordered_map 和 unordered_set (꒪ꇴ꒪(꒪ꇴ꒪ )&#x1f423;,我是Scort目前状态&#xff1a;大三非科班啃C中&#x1f30d;博客主页&#xff1a;张小姐的猫~江湖背景快上车&#x1f698;&#xff0c;握好方向盘跟我有一起打天下嘞&…

【北京理工大学-Python 数据分析-3.1Pandas库的基本使用】

Pandas库的引用&#xff0c;常用两大功能Series(一维&#xff09;和DataFrame&#xff08;二维和多维&#xff09; Pandas是Python第三方库&#xff0c;提供高性能易用数据类型的分析工具。 Pandas基于NumPy实现&#xff0c;常与NumPy和Matplotlib一起使用。 Numpy和Pandas的…

SpringCloud-Netflix学习笔记03——什么是Eureka

什么是Eureka Eureka&#xff1a;怎么读&#xff1f; Netflix 在设计Eureka 时&#xff0c;遵循的就是AP原则。 1、CAP原则又称CAP定理&#xff0c;指的是在一个分布式系统中 2、一致性&#xff08;Consistency&#xff09; 3、可用性&#xff08;Availability&#xff09; 4、…

详细实例说明+典型案例实现 对动态规划法进行全面分析 | C++

第三章 动态规划法 目录 ●第三章 动态规划法 ●前言 ●一、动态规划法是什么&#xff1f; 1.简要介绍 2.生活实例 ●二、动态规划法对斐波那契数列的优化 1.优化方法 2.优化核心代码片段 3.代码实现以及结果展示 ●三、动态规划法的典型案例——最短总距离 …

c语言文件操作(万字解析)

c语言文件操作一.文件的打开与关闭1.文件指针-FILE*2.文件的打开与关闭二.文件的顺序读写1.字符操作函数-fgetc和fputc2.字符串操作函数-fgets和fputs3.格式化函数-fprintf和fscanf4.二进制函数-fread和fwrite5.对比一组函数三.文件的随机读写1.fseek和ftell2.调整指针-rewind四…

Python NumPy 数组索引

前言NumPy&#xff08;Numerical Python的缩写&#xff09;是一个开源的Python科学计算库。使用NumPy&#xff0c;就可以很自然地使用数组和矩阵。NumPy包含很多实用的数学函数&#xff0c;涵盖线性代数运算、傅里叶变换和随机数生成等功能。本文主要介绍Python NumPy 数组索引…

动态内容管理

这期我们来看动态内存管理的相关知识&#xff0c;话不多说&#xff0c;我们来看今天的正题 目录 1.为什么要有动态内存管理&#xff1f; 2.动态内存函数的介绍 2.1.malloc和free 2.2.calloc 2.3.realloc 3. 常见的动态内存错误 3.1 对NULL指针的解引用操作 3.2 对动态开…

Pytorch DataLoader中的num_workers (选择最合适的num_workers值)

一、概念 num_workers是Dataloader的概念&#xff0c;默认值是0。是告诉DataLoader实例要使用多少个子进程进行数据加载(和CPU有关&#xff0c;和GPU无关) 如果num_worker设为0&#xff0c;意味着每一轮迭代时&#xff0c;dataloader不再有自主加载数据到RAM这一步骤&#xff0…

滑动列表中使用粒子特效层级问题

前言 前面几个月疯狂堆功能,现在开始疯狂加动效,每次一说到动效就脑壳痛,还不如让我写功能。这不,今天又遇到问题了。滑动列表中mask粒子特效问题遮挡。 情况1 步骤1:使用粒子特效的层级应该>当前ui层级。 例如:当前界面所在层级为2000,其上的粒子特效至少为2001。…

dp(八)买卖股票的最好时机 (一,二、三)

目录 买卖股票的最好时机(一)_牛客题霸_牛客网 买卖股票的最好时机(二)_牛客题霸_牛客网 买卖股票的最好时机(三)_牛客题霸_牛客网 假设你有一个数组prices&#xff0c;长度为n&#xff0c;其中prices[i]是股票在第i天的价格&#xff0c;请根据这个价格数组&#xff0c;返回买…

基于云的文档管理系统:DocuWare Cloud

云文档管理软件&#xff1a;DocuWare Cloud 一流的云文档管理软件和工作流自动化内容服务&#xff0c;适用于任何规模的团队和公司——在多租户云平台上交付。 DocuWare Cloud 可在订阅的基础上为不同规模的公司提供灵活的许可证。 每个订阅都涵盖全方位的服务&#xff0c;包…

dvwa中的爆破

环境&#xff1a;dvwa: 192.168.11.135 dvwa版本&#xff1a; Version 1.9 (Release date: 2015-09-19)kail机器&#xff1a;192.168.11.1561、Low级别代码&#xff1a;1、启动 burpsuite 开始抓包&#xff0c;然后点击 login&#xff0c;然后在 bp 里面就能看见抓包到的包。这…

Java集合常见面试题(二)

Collection 子接口之 List ArrayList 和 Vector 的区别? ArrayList 是 List 的主要实现类&#xff0c;底层使用 Object[]存储&#xff0c;适用于频繁的查找工作&#xff0c;线程不安全 &#xff1b;Vector 是 List 的古老实现类&#xff0c;底层使用Object[] 存储&#xff0…

谷粒学院复习

一、Mybatis Plus复习分布式系统唯一ID主键策略(面试)面试的时候就说知道有以下四种策略&#xff0c;分别介绍一下每一种&#xff0c;然后说一下项目中用的是雪花算法分类自动增长 AUTO INCREMENT就是自动增长&#xff0c;每次都会自动加一。缺点&#xff1a;如果在分库分表的场…

VUE: Vue3+TS的项目搭建及基础使用

简介 通过 Vue-cli4 创建的 Vue3TS 的项目&#xff0c;并进行一些基础使用的举例。 项目搭建 1. 进入命令提示符窗口 在要搭建项目的文件夹中&#xff0c;点击路径&#xff0c;输入CMD并按回车 2. 查看node版本、Vue-cli版本 2.1 node版本&#xff08;14.x以上&#xf…

基于域控的SSO单点登录

大家好&#xff0c;好久不见&#xff0c;今天老吕给大家来一篇偏冷门知识的文章。一、需求大型集团企业内部会有许多业务系统&#xff0c;工作人员也往往需要登录多个业务系统才能完成工作&#xff0c;这就可能会存在一些问题1、多套账号与密码需要记录或者记忆2、多次登录&…