Lightning project login

1. Technical introduction

Front-end: Freemarker, LayUI, jQuery
Back-end: SpringBoot, MyBatisPlus, Lombok
Middleware: RabbitMQ, Redis (redisson)
Distributed coordination framework: zookeeper

2. Preparation

① Create a new empty project

② Import dependencies

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.hmf</groupId>
    <artifactId>seckill</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>seckill</name>
    <description>seckill</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.4.1</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</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>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- mybatis plus依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <!--mybatis-plus生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.2</version>
        </dependency>
        <!-- MD5依赖 -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
        <!-- valid验证依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <!--redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--hariki-->
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.4.1</version>
                <configuration>
                    <mainClass>com.hmf.seckill.SeckillApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

③Import the tables we need

④application.yml 

spring:
  application:
    name: seckill
  datasource:
    url: jdbc:mysql://localhost:3306/user?useSSL=false&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    hikari:
      # 最小空闲连接数量
      minimum-idle: 5
      # 空闲连接存活最大时间,默认600000(10分钟)
      idle-timeout: 180000
      # 连接池最大连接数,默认是10
      maximum-pool-size: 10
      # 此属性控制从池返回的连接的默认自动提交行为,默认值:true
      auto-commit: true
      # 连接池名称
      pool-name: MyHikariCP
      # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
      max-lifetime: 1800000
      # 数据库连接超时时间,默认30秒,即30000
      connection-timeout: 30000
  freemarker:
    #设置编码格式
    charset: UTF-8
    #后缀
    suffix: .ftl
    #文档类型
    content-type: text/html
    #模板前端
    template-loader-path: classpath:/templates/
    #启用模板
    enabled: true
    #开启静态资源
  mvc:
    static-path-pattern: /static/**
mybatis-plus:
  mapper-locations: classpath*:/mapper/*Mapper.xml
  type-aliases-package: com.hmf.seckill.model
  #可以使用驼峰命名
  configuration:
    map-underscore-to-camel-case: true
    #可以使用日志
logging:
  level:
    com.hmf.seckill.mapper: debug

Add these annotations on the startup class

automatic generator

(1) Create a new generator package and build the MybatisPlusGenerator class

create a directory

MybatisPlusGenerator.java

package com.hmf.seckill.generator;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@SuppressWarnings("all")
@Slf4j
@Data
public class MybatisPlusGenerator {

    protected static String URL = "jdbc:mysql://www.hmf.com/user?useEncoding=utf8mb4&serverTimezone=Asia/Shanghai&useSSL=false";
    protected static String USERNAME = "root";
    protected static String PASSWORD = "123456";

    protected static DataSourceConfig.Builder DATA_SOURCE_CONFIG = new DataSourceConfig.Builder(URL, USERNAME, PASSWORD);

    public static void main(String[] args) {
        FastAutoGenerator.create(DATA_SOURCE_CONFIG)
                .globalConfig(
                        (scanner/*lamdba*/, builder/*变量*/) ->
                                builder.author(scanner.apply("请输入作者名称?"))
                                        .enableSwagger()
                                        .fileOverride()
                                        .outputDir(System.getProperty("user.dir") + "\\src\\main\\java")
                                        .commentDate("yyyy-MM-dd")
                                        .dateType(DateType.TIME_PACK)
                )
                .packageConfig((builder) ->
                        builder.parent("com.hmf.seckill")
                                .entity("pojo")
                                .service("service")
                                .serviceImpl("service.impl")
                                .mapper("mapper")
                                .xml("mapper.xml")
                                .pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "\\src\\main\\resources\\mapper"))
                )
                .injectionConfig((builder) ->
                        builder.beforeOutputFile(
                                (a, b) -> log.warn("tableInfo: " + a.getEntityName())
                        )
                )
                .strategyConfig((scanner, builder) ->
                        builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
                                .addTablePrefix("tb_", "t_")
                                .entityBuilder()
                                .enableChainModel()
                                .enableLombok()
                                .enableTableFieldAnnotation()
                                .addTableFills(
                                        new Column("create_time", FieldFill.INSERT)
                                )
                                .controllerBuilder()
                                .enableRestStyle()
                                .enableHyphenStyle()
                                .build())
                .templateEngine(new FreemarkerTemplateEngine())
                .execute();
    }

    protected static List<String> getTables(String tables) {
        return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
    }

}

generate code

 We're missing something after we generate

 

 layui official website

 Now that our series of work is ready, we can upload the code

came in

 3. Front-end construction

1. Templates add related interface

<!DOCTYPE html>
<html lang="zh">
<head>
    <#include "common/head.ftl"/>
    <style>
        .layui-panel {
            position: absolute;
            width: 400px;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            padding: 15px 15px 0px 15px;
            border-radius: 20px;
        }

        .layui-form-label {
            padding: 9px 0px;
        }

        h3 {
            text-align: center;
            line-height: 45px;
            font-size: 40px;
            color: white;
            padding-bottom: 15px;
        }
    </style>
</head>
<body>
<div>
    <div class="layui-panel layui-bg-cyan">
        <h3>用户登录</h3>
        <div class="layui-form-item">
            <label class="layui-form-label">用户账号</label>
            <div class="layui-input-block">
                <input type="text" id="mobile" autocomplete="on" class="layui-input" value="18684671234">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">用户密码</label>
            <div class="layui-input-block">
                <input type="password" id="password" autocomplete="on" class="layui-input" value="123456">
            </div>
        </div>
        <div class="layui-form-item" style="text-align:center;">
            <button class="layui-btn" id="login" style="width:46%">登录</button>
            <button class="layui-btn layui-btn-normal" id="register" style="width:46%">注册</button>
        </div>
    </div>
</div>
<script src="${ctx}/static/asset/js/md5.js"></script>
<script src="${ctx}/static/asset/js/project/login.js"></script>
</body>
</html>

common directory head.ftl

<meta charset="UTF-8">
<title>秒杀项目</title>
<script src="/static/asset/js/layui/layui.js" type="text/javascript"></script>
<link href="/static/asset/js/layui/css/layui.css" rel="stylesheet" type="text/css"/>
<meta http-equiv="Expires" content="0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-control" content="no-cache">
<meta http-equiv="Cache" content="no-cache">
<#assign ctx>
    ${springMacroRequestContext.getContextPath()}
</#assign>

goods directory, goodsList.ftl

<!DOCTYPE html>
<html lang="en">
<head>
    <#include "../common/head.ftl">
</head>
<body>
<h1>这是商品展示界面</h1>
</body>
</html>

import layui

Create a new project directory under resources->static->asset->js

①. Create a new JavaScript file named login

layui.use(["jquery","layer"],()=>{
    //得到layuo中封装的jQuery
    let $=layui.jquery
    let layer=layui.layer
    //给登录按钮设置事件
    $(login).click(()=>{
        console.log("login....")
        //取表单的值
        let mobile=$("#mobile").val()
        let password=$("#password").val()
        //前端加密的盐
        let salt = "f1g2h3j4";
        if(password){
            //将密码和盐混一起
            password=salt.charAt(1) + "" + salt.charAt(5) + password + salt.charAt(0) + "" + salt.charAt(3);
            //进行md5加密
            password=md5(password)
        }
        console.log(password)
        //将数据给后台(前端分离axios  普通开发ajax)
        $.ajax({
            url: "/user/login",//后台登录接口
            data:{ //需要携带的数据
                mobile,
                password
            },
            dataType:"json",//后台给你的数据类型
            success(e){//成功的回调函数
                layer.msg(e.message,{icon:6})
            },
            error(e){//报错的回调函数

            },
        })
    })
  }
)

Create a new PathController class (under the controller package)

(1) Specially used for jumping paths: PathController class

package com.hmf.seckill.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class PathController {

    //跳首页
    @RequestMapping("/")
    public String toPath(){
        return "login";
    }

    //跳二级页面
    @RequestMapping("/{dir}/{path}")
    public String toPath(@PathVariable("dir") String dir,@PathVariable("path") String path){
        //处理操作
        return dir+"/"+path;
    }
}

It's not good to provide all the source code because there are too many

so I just provide some important

4. MD5 encryption

1. Import help package and exception package

2. Passing values ​​from the front and back ends

Create a new vo package and build a uservo class

package com.hmf.seckill.vo;

import com.hmf.seckill.util.response.ResponseResultCode;
import com.hmf.seckill.util.validate.IsMobile;
import com.hmf.seckill.util.validate.IsRequired;
import lombok.Data;
import org.aspectj.apache.bcel.classfile.Code;

import javax.validation.constraints.NotEmpty;

@Data
public class UserVo {

    private String mobile;
    private String password;

}

3. Login method:

(1) Service layer:

①, IUserService interface

package com.hmf.seckill.service;

import com.hmf.seckill.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;
import com.hmf.seckill.util.response.ResponseResult;
import com.hmf.seckill.vo.UserVo;

/**
 * <p>
 * 用户信息表 服务类
 * </p>
 *
 * @author hmf-git
 * @since 2022-03-15
 */
public interface IUserService extends IService<User> {

    ResponseResult<?> findByAccount(UserVo userVo);
}

②, implement the interface UserServiceImpl

package com.hmf.seckill.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hmf.seckill.exception.BusinessException;
import com.hmf.seckill.pojo.User;
import com.hmf.seckill.mapper.UserMapper;
import com.hmf.seckill.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmf.seckill.util.MD5Utils;
import com.hmf.seckill.util.ValidatorUtils;
import com.hmf.seckill.util.response.ResponseResult;
import com.hmf.seckill.util.response.ResponseResultCode;
import com.hmf.seckill.vo.UserVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.swing.text.BadLocationException;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author hmf-git
 * @since 2022-03-15
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Override
    public ResponseResult<?> findByAccount(UserVo userVo) {
        //先判断信息是否符合
        if(!ValidatorUtils.isMobile(userVo.getMobile())){
            throw new BusinessException(ResponseResultCode.USER_ACCOUNT_NOT_MOBLIE);
        }
        if(StringUtils.isBlank(userVo.getPassword())){
            throw new BusinessException(ResponseResultCode.USER_ACCOUNT_NOT_MOBLIE);
        }
        //再看数据库查出对应的用户
        User user=this.getOne(new QueryWrapper<User>().eq("id",userVo.getMobile()));
        if(user==null){
            throw new BusinessException(ResponseResultCode.USER_ACCOUNT_NOT_FIND);
        }
        //在比较密码
        //二重加密
        String salt=user.getSalt();
        String newPassword=MD5Utils.formPassToDbPass(userVo.getPassword(),salt);
        //将前台的加密和后端的盐再次加密
        if(newPassword.equals(user.getPassword())){
            throw new BusinessException(ResponseResultCode.USER_PASSWORD_NOT_MATCH);
        }
        return ResponseResult.success();
    }

}

Controller layer

①、UserController

package com.hmf.seckill.controller;

import com.hmf.seckill.service.IUserService;
import com.hmf.seckill.util.response.ResponseResult;
import com.hmf.seckill.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

/**
 * <p>
 * 用户信息表 前端控制器
 * </p>
 *
 * @author hmf-git
 * @since 2022-03-15
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private IUserService userService; 

    @RequestMapping("/login") 
    public ResponseResult<?> login(@Valid UserVo userVo){ 
        //Call the login verification of service 
        System.out.println("aaaaaa"); 
        return userService.findByAccount(userVo) ; 
    } 
}

password encryption

 login.ftl

<!DOCTYPE html>
<html lang="zh">
<head>
    <#include "common/head.ftl"/>
    <style>
        .layui-panel {
            position: absolute;
            width: 400px;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            padding: 15px 15px 0px 15px;
            border-radius: 20px;
        }

        .layui-form-label {
            padding: 9px 0px;
        }

        h3 {
            text-align: center;
            line-height: 45px;
            font-size: 40px;
            color: white;
            padding-bottom: 15px;
        }
    </style>
</head>
<body>
<div>
    <div class="layui-panel layui-bg-cyan">
        <h3>用户登录</h3>
        <div class="layui-form-item">
            <label class="layui-form-label">用户账号</label>
            <div class="layui-input-block">
                <input type="text" id="mobile" autocomplete="on" class="layui-input" value="18684671234">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">用户密码</label>
            <div class="layui-input-block">
                <input type="password" id="password" autocomplete="on" class="layui-input" value="123456">
            </div>
        </div>
        <div class="layui-form-item" style="text-align:center;">
            <button class="layui-btn" id="login" style="width:46%">登录</button>
            <button class="layui-btn layui-btn-normal" id="register" style="width:46%">注册</button>
        </div>
    </div>
</div>
<script src="${ctx}/static/asset/js/md5.js"></script>
<script src="${ctx}/static/asset/js/project/login.js"></script>
</body>
</html>

md5.js

/*
 * JavaScript MD5
 * https://github.com/blueimp/JavaScript-MD5
 *
 * Copyright 2011, Sebastian Tschan
 * https://blueimp.net
 *
 * Licensed under the MIT license:
 * https://opensource.org/licenses/MIT
 *
 * Based on
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */

/* global define */

(function ($) {
    'use strict'

    /*
    * Add integers, wrapping at 2^32. This uses 16-bit operations internally
    * to work around bugs in some JS interpreters.
    */
    function safeAdd (x, y) {
        var lsw = (x & 0xffff) + (y & 0xffff)
        var msw = (x >> 16) + (y >> 16) + (lsw >> 16)
        return (msw << 16) | (lsw & 0xffff)
    }

    /*
    * Bitwise rotate a 32-bit number to the left.
    */
    function bitRotateLeft (num, cnt) {
        return (num << cnt) | (num >>> (32 - cnt))
    }

    /*
    * These functions implement the four basic operations the algorithm uses.
    */
    function md5cmn (q, a, b, x, s, t) {
        return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b)
    }
    function md5ff (a, b, c, d, x, s, t) {
        return md5cmn((b & c) | (~b & d), a, b, x, s, t)
    }
    function md5gg (a, b, c, d, x, s, t) {
        return md5cmn((b & d) | (c & ~d), a, b, x, s, t)
    }
    function md5hh (a, b, c, d, x, s, t) {
        return md5cmn(b ^ c ^ d, a, b, x, s, t)
    }
    function md5ii (a, b, c, d, x, s, t) {
        return md5cmn(c ^ (b | ~d), a, b, x, s, t)
    }

    /*
    * Calculate the MD5 of an array of little-endian words, and a bit length.
    */
    function binlMD5 (x, len) {
        /* append padding */
        x[len >> 5] |= 0x80 << (len % 32)
        x[((len + 64) >>> 9 << 4) + 14] = len

        var i
        var olda
        var oldb
        var oldc
        var oldd
        var a = 1732584193
        var b = -271733879
        var c = -1732584194
        var d = 271733878

        for (i = 0; i < x.length; i += 16) {
            olda = a
            oldb = b
            oldc = c
            oldd = d

            a = md5ff(a, b, c, d, x[i], 7, -680876936)
            d = md5ff(d, a, b, c, x[i + 1], 12, -389564586)
            c = md5ff(c, d, a, b, x[i + 2], 17, 606105819)
            b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330)
            a = md5ff(a, b, c, d, x[i + 4], 7, -176418897)
            d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426)
            c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341)
            b = md5ff(b, c, d, a, x[i + 7], 22, -45705983)
            a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416)
            d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417)
            c = md5ff(c, d, a, b, x[i + 10], 17, -42063)
            b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162)
            a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682)
            d = md5ff(d, a, b, c, x[i + 13], 12, -40341101)
            c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290)
            b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329)

            a = md5gg(a, b, c, d, x[i + 1], 5, -165796510)
            d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632)
            c = md5gg(c, d, a, b, x[i + 11], 14, 643717713)
            b = md5gg(b, c, d, a, x[i], 20, -373897302)
            a = md5gg(a, b, c, d, x[i + 5], 5, -701558691)
            d = md5gg(d, a, b, c, x[i + 10], 9, 38016083)
            c = md5gg(c, d, a, b, x[i + 15], 14, -660478335)
            b = md5gg(b, c, d, a, x[i + 4], 20, -405537848)
            a = md5gg(a, b, c, d, x[i + 9], 5, 568446438)
            d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690)
            c = md5gg(c, d, a, b, x[i + 3], 14, -187363961)
            b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501)
            a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467)
            d = md5gg(d, a, b, c, x[i + 2], 9, -51403784)
            c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473)
            b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734)

            a = md5hh(a, b, c, d, x[i + 5], 4, -378558)
            d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463)
            c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562)
            b = md5hh(b, c, d, a, x[i + 14], 23, -35309556)
            a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060)
            d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353)
            c = md5hh(c, d, a, b, x[i + 7], 16, -155497632)
            b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640)
            a = md5hh(a, b, c, d, x[i + 13], 4, 681279174)
            d = md5hh(d, a, b, c, x[i], 11, -358537222)
            c = md5hh(c, d, a, b, x[i + 3], 16, -722521979)
            b = md5hh(b, c, d, a, x[i + 6], 23, 76029189)
            a = md5hh(a, b, c, d, x[i + 9], 4, -640364487)
            d = md5hh(d, a, b, c, x[i + 12], 11, -421815835)
            c = md5hh(c, d, a, b, x[i + 15], 16, 530742520)
            b = md5hh(b, c, d, a, x[i + 2], 23, -995338651)

            a = md5ii(a, b, c, d, x[i], 6, -198630844)
            d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415)
            c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905)
            b = md5ii(b, c, d, a, x[i + 5], 21, -57434055)
            a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571)
            d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606)
            c = md5ii(c, d, a, b, x[i + 10], 15, -1051523)
            b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799)
            a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359)
            d = md5ii(d, a, b, c, x[i + 15], 10, -30611744)
            c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380)
            b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649)
            a = md5ii(a, b, c, d, x[i + 4], 6, -145523070)
            d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379)
            c = md5ii(c, d, a, b, x[i + 2], 15, 718787259)
            b = md5ii(b, c, d, a, x[i + 9], 21, -343485551)

            a = safeAdd(a, olda)
            b = safeAdd(b, oldb)
            c = safeAdd(c, oldc)
            d = safeAdd(d, oldd)
        }
        return [a, b, c, d]
    }

    /*
    * Convert an array of little-endian words to a string
    */
    function binl2rstr (input) {
        var i
        var output = ''
        var length32 = input.length * 32
        for (i = 0; i < length32; i += 8) {
            output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xff)
        }
        return output
    }

    /*
    * Convert a raw string to an array of little-endian words
    * Characters >255 have their high-byte silently ignored.
    */
    function rstr2binl (input) {
        var i
        var output = []
        output[(input.length >> 2) - 1] = undefined
        for (i = 0; i < output.length; i += 1) {
            output[i] = 0
        }
        var length8 = input.length * 8
        for (i = 0; i < length8; i += 8) {
            output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << (i % 32)
        }
        return output
    }

    /*
    * Calculate the MD5 of a raw string
    */
    function rstrMD5 (s) {
        return binl2rstr(binlMD5(rstr2binl(s), s.length * 8))
    }

    /*
    * Calculate the HMAC-MD5, of a key and some data (raw strings)
    */
    function rstrHMACMD5 (key, data) {
        var i
        var bkey = rstr2binl(key)
        var ipad = []
        var opad = []
        var hash
        ipad[15] = opad[15] = undefined
        if (bkey.length > 16) {
            bkey = binlMD5(bkey, key.length * 8)
        }
        for (i = 0; i < 16; i += 1) {
            ipad[i] = bkey[i] ^ 0x36363636
            opad[i] = bkey[i] ^ 0x5c5c5c5c
        }
        hash = binlMD5(ipad.concat(rstr2binl(data)), 512 + data.length * 8)
        return binl2rstr(binlMD5(opad.concat(hash), 512 + 128))
    }

    /*
    * Convert a raw string to a hex string
    */
    function rstr2hex (input) {
        var hexTab = '0123456789abcdef'
        var output = ''
        var x
        var i
        for (i = 0; i < input.length; i += 1) {
            x = input.charCodeAt(i)
            output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f)
        }
        return output
    }

    /*
    * Encode a string as utf-8
    */
    function str2rstrUTF8 (input) {
        return unescape(encodeURIComponent(input))
    }

    /*
    * Take string arguments and return either raw or hex encoded strings
    */
    function rawMD5 (s) {
        return rstrMD5(str2rstrUTF8(s))
    }
    function hexMD5 (s) {
        return rstr2hex(rawMD5(s))
    }
    function rawHMACMD5 (k, d) {
        return rstrHMACMD5(str2rstrUTF8(k), str2rstrUTF8(d))
    }
    function hexHMACMD5 (k, d) {
        return rstr2hex(rawHMACMD5(k, d))
    }

    function md5 (string, key, raw) {
        if (!key) {
            if (!raw) {
                return hexMD5(string)
            }
            return rawMD5(string)
        }
        if (!raw) {
            return hexHMACMD5(key, string)
        }
        return rawHMACMD5(key, string)
    }

    if (typeof define === 'function' && define.amd) {
        define(function () {
            return md5
        })
    } else if (typeof module === 'object' && module.exports) {
        module.exports = md5
    } else {
        $.md5 = md5
    }
})(this)

front-end password encryption

①, login.js file

layui.use(["jquery","layer"],()=>{ 
    //get jQuery encapsulated in layuo 
    let $=layui.jquery 
    let layer=layui.layer 
    //set event for login button 
    $(login) .click(()=>{ 
        console.log("login....") 
        //Get the value of the form 
        let mobile=$("#mobile").val() 
        let password=$("#password") .val() //Salt for front-end encryption 
        let salt = "f1g2h3j4"; 
        if(password){ 
            //Mix password and salt together 
            password=salt.charAt(1) + "" + salt.charAt(5) + password + salt.charAt(0) + "" + salt.charAt(3); 
            //Encrypt md5 
            password=md5(password) 
        } 
        console.log(password)
       
        //Send data to the background (separate axios from the front end and develop ajax normally) 
        $.ajax({
            url: "/user/login",//Background login interface 
            data:{ //Data that needs to be carried 
                mobile, 
                password 
            }, 
            dataType: "json",//Data type given to you by the background 
            success(e){//Success Callback function 
                layer.msg(e.message,{icon:6}) 
            }, 
            error(e){//Callback function for error reporting 

            }, 
        }) 
    }) 
  } 
)

UserServiceImpl:

//Comparing passwords 
//Double encryption 
String salt=user.getSalt(); 
String newPassword=MD5Utils.formPassToDbPass(userVo.getPassword(),salt); 
//Encrypt the front-end encryption and back-end salt again 
if(newPassword .equals(user.getPassword())){ 
    throw new BusinessException(ResponseResultCode.USER_PASSWORD_NOT_MATCH); 
} 
return ResponseResult.success();

Encrypted password implementation

Five, global exception error

UserVo added related comments

package com.hmf.seckill.vo;

import com.hmf.seckill.util.response.ResponseResultCode;
import com.hmf.seckill.util.validate.IsMobile;
import com.hmf.seckill.util.validate.IsRequired;
import lombok.Data;
import org.aspectj.apache.bcel.classfile.Code;

import javax.validation.constraints.NotEmpty;

@Data
public class UserVo {

    @IsMobile(code = ResponseResultCode.USER_ACCOUNT_NOT_MOBLIE)
    private String mobile;
    @IsRequired(code = ResponseResultCode.USER_CREDENTIAL_NOT_BE_EMPTY)
    private String password;
}

Import help package validate, exception capture

(1)IsIsMobile 

package com.hmf.seckill.util.validate;

import com.hmf.seckill.util.response.ResponseResultCode;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

//文档
@Documented
@Constraint(
        validatedBy = {IsIsMobileValidator.class}
)
@Target({ElementType.METHOD, ElementType.FIELD,ElementType.PARAMETER})
//运行的作用域
@Retention(RetentionPolicy.RUNTIME)
public @interface IsMobile {

    ResponseResultCode code() default ResponseResultCode.UNKNOWN;

    String message() default "{javax.validation.constraints.NotEmpty.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

IsMobileValidator (analysis class of IsMobile)

package com.hmf.seckill.util.validate;

import com.hmf.seckill.util.ValidatorUtils;

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

/**
 * ismobile的解析类
 */
public class IsIsMobileValidator implements ConstraintValidator<IsMobile,String> {

    //当前是否验证成功
    @Override
    public boolean isValid(String mobile, ConstraintValidatorContext constraintValidatorContext) {
        return ValidatorUtils.isMobile(mobile);
    }
}

IsRequired 

package com.hmf.seckill.util.validate; 

import com.hmf.seckill.util.response.ResponseResultCode; 

import javax.validation.Constraint; 
import javax.validation.Payload; 
import java.lang.annotation.*; 

//documentation 
@Documented 
@Constraint( 
        /** 
         * tells which parser to use 
        */ 
        validatedBy = {IsRequiredValidator.class} 
) 
@Target({ElementType.METHOD, ElementType.FIELD,ElementType.PARAMETER}) 
//The scope of operation 
@Retention (RetentionPolicy.RUNTIME) 
public @interface IsRequired { 

    String message() default "{javax.validation.constraints.NotEmpty.message}"; 

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    ResponseResultCode code();
}

IsRequiredValidator 

package com.hmf.seckill.util.validate;

import com.hmf.seckill.util.ValidatorUtils;

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

/**
 * ismobile的解析类
 */
public class IsRequiredValidator implements ConstraintValidator<IsRequired,String> {

    //当前是否验证成功
    @Override
    public boolean isValid(String mobile, ConstraintValidatorContext constraintValidatorContext) {
        return ValidatorUtils.isMobile(mobile);
    }
}

ThrowableAdvice

package com.hmf.seckill.util.response;

import com.hmf.seckill.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ui.Model;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@SuppressWarnings("all")
@RestControllerAdvice
@Slf4j
public class ThrowableAdvice {

    @JsonResponseResult
    @ExceptionHandler(value = {BusinessException.class})
    public ResponseResultCode globalBusinessException(Model m, Exception e) {
        log.error(e.toString());
        return ((BusinessException) e).getResponseResultCode();
    }

    @JsonResponseResult
    @ExceptionHandler(value = {BindException.class})
    public ResponseResultCode globalBindException(Model m, Exception e) {
        log.error(e.toString());
        BindException error = (BindException) e;
        return (ResponseResultCode) error.getFieldError().getArguments()[1];
    }

    @JsonResponseResult
    @ExceptionHandler(value = {Throwable.class})
    public ResponseResultCode globalException(Model m, Exception e) {
        log.error(e.toString());
        return ResponseResultCode.UNKNOWN;
    }

}

Add annotations to UserController class methods

The implementation class throws an exception

(1)UserServiceImpl:

package com.hmf.seckill.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hmf.seckill.exception.BusinessException;
import com.hmf.seckill.pojo.User;
import com.hmf.seckill.mapper.UserMapper;
import com.hmf.seckill.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmf.seckill.util.MD5Utils;
import com.hmf.seckill.util.ValidatorUtils;
import com.hmf.seckill.util.response.ResponseResult;
import com.hmf.seckill.util.response.ResponseResultCode;
import com.hmf.seckill.vo.UserVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.swing.text.BadLocationException; 

/** 
 * <p> 
 * User information table service implementation class 
 * </p> 
 * 
 * @author hmf-git 
 * @since 2022-03-15 
 */ 
@Service 
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService { 

    @Override 
    public ResponseResult<?> findByAccount(UserVo userVo) { 
        //First determine whether the information meets 
        if(!ValidatorUtils.isMobile(userVo.getMobile())){ throw new BusinessException(ResponseResultCode .USER_ACCOUNT_NOT_MOBLIE); 
        } 
        if(StringUtils.isBlank(userVo.getPassword())){ throw new BusinessException(ResponseResultCode.USER_ACCOUNT_NOT_MOBLIE);
           
            
        } 
        //Look at the database to find out the corresponding user 
        User user=this.getOne(new QueryWrapper<User>().eq("id",userVo.getMobile())); 
        if(user==null){ throw new BusinessException(ResponseResultCode.USER_ACCOUNT_NOT_FIND); 
        } 
        //Comparing passwords 
        //double encryption 
        String salt=user.getSalt(); 
        String newPassword=MD5Utils.formPassToDbPass(userVo.getPassword(),salt); 
        //Combine the encryption and Salt re-encryption on the backend 
        if(newPassword.equals(user.getPassword())){ throw new BusinessException(ResponseResultCode.USER_PASSWORD_NOT_MATCH); 
        } 
        return ResponseResult.success(); 
    } 
}
            
            

test

Finish 

Guess you like

Origin blog.csdn.net/m0_60375943/article/details/123509050