欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

超詳細講解Java秒殺項目登陸模塊的實現(xiàn)

 更新時間:2022年03月18日 09:14:13   作者:愛嚶斯塔  
這是一個主要使用java開發(fā)的秒殺系統(tǒng),項目比較大,所以本篇只實現(xiàn)了登陸模塊,代碼非常詳盡,感興趣的朋友快來看看

一、項目前準備

1、新建項目

2、導(dǎo)入依賴

<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>
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
    </dependencies>

3、執(zhí)行sql腳本

得到表:

 首先查看登錄的表數(shù)據(jù):

4、配置yml文件

spring:
application:
name: seckill
datasource:
url: jdbc:mysql://localhost:3306/seckill?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:
# 最小空閑連接數(shù)量
minimum-idle: 5
# 空閑連接存活最大時間,默認600000(10分鐘)
idle-timeout: 180000
# 連接池最大連接數(shù),默認是10
maximum-pool-size: 10
# 此屬性控制從池返回的連接的默認自動提交行為,默認值:true
auto-commit: true
# 連接池名稱
pool-name: MyHikariCP
# 此屬性控制池中連接的最長生命周期,值0表示無限生命周期,默認1800000即30分鐘
max-lifetime: 1800000
# 數(shù)據(jù)庫連接超時時間,默認30秒,即30000
connection-timeout: 30000
freemarker:
#設(shè)置編碼格式
charset: UTF-8
#后綴
suffix: .ftl
#文檔類型
content-type: text/html
#模板前端
template-loader-path: classpath:/templates/
#啟用模板
enabled: true
# 開啟靜態(tài)資源
mvc:
static-path-pattern: /static/**
mybatis-plus:
mapper-locations: classpath*:/mapper/*Mapper.xml
type-aliases-package: com.example.seckill.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
com.example.seckill.mapper: debug

由于2.4.1版本是沒有templates目錄,而我配置的模板的位置在此處,所以在resource內(nèi)新建templates目錄

5、在啟動類加入注解

SeckillApplication類:

//開啟切面
@EnableAspectJAutoProxy
//開啟事務(wù)
@EnableTransactionManagement
//掃描mapper層
@MapperScan("com.example.seckill.mapper")

6、自動生成器

package com.example.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://localhost:3306/seckill?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.example.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(","));
    }
 
}

 相關(guān)文件生成:

 自動生成時,mapper文件未加入注解,無法加載到spring容器中

@Repository

二、前端構(gòu)建

1、導(dǎo)入layui

2、將界面放到template

 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>

goodsList.ftl文件:

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

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>

3、在js目錄下新建目錄project

新建JavaScript文件login:

layui.define(()=>{
    // 得到layui中封裝的jquery
    let $=layui.jquery
    // 給登錄按鈕設(shè)置事件
    $(login).click(()=>{
     // 取到表單的值
    let mobile = $("#mobile").val();
    let password=$("#password").val();
    // 將數(shù)據(jù)給后臺(前后端分離axios,普通開發(fā)ajax)
       $.ajax({
           url:"",//后臺登錄接口
           data:{
             // 需要攜帶的數(shù)據(jù)
               mobile,
               password
           },
           datatype: "json",//后端給你的數(shù)據(jù)類型
           success(e){
               // 成功的回調(diào)函數(shù)
 
           },
           error(e){
               // 報錯的回調(diào)函數(shù)
 
           }
 
       })
    })
 
 
})

4、新建controller類

專門用于跳轉(zhuǎn)路徑:PathController類

package com.example.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;
    }
 
}

得到界面:

三、MD5加密

1、導(dǎo)入幫助包與exception包

①、exception

package com.example.seckill.exception;
 
import com.example.seckill.util.response.ResponseResultCode;
import lombok.Data;
 
@SuppressWarnings("all")
@Data
public class BusinessException extends RuntimeException {
 
    private ResponseResultCode responseResultCode;
 
    public BusinessException(ResponseResultCode responseResultCode) {
        this.responseResultCode = responseResultCode;
    }
 
}

②、response包,用于后面的全局異常

JsonResponseParse :

package com.example.seckill.util.response;
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
 
@SuppressWarnings("all")
@RestControllerAdvice
@Slf4j
public class JsonResponseParse implements ResponseBodyAdvice {
 
    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        //返回值決定他是否需要進入beforeBodyWrite
        return methodParameter.getMethod().isAnnotationPresent(JsonResponseResult.class);
    }
 
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        //更改返回值
        if (o == null) {
            return ResponseResult.success();
        }
        if (o instanceof Integer) {
            return ResponseResult.failure(ResponseResultCode.queryCode((Integer) o));
        }
        if (o instanceof ResponseResultCode) {
            return ResponseResult.failure((ResponseResultCode) o);
        }
        if (o instanceof ResponseResult) {
            return o;
        }
        return ResponseResult.success(o);
    }
 
}

JsonResponseResult :

package com.example.seckill.util.response;
 
import java.lang.annotation.*;
 
@SuppressWarnings("all")
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.METHOD})
public @interface JsonResponseResult {
 
}

ResponseResult:

package com.example.seckill.util.response;
 
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
 
import java.io.Serializable;
 
@SuppressWarnings("all")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResponseResult<T> implements Serializable {
 
    private int code;
    private String message;
    private T data;
    private Long total;
 
    /**
     * 私有構(gòu)造, 只允許通過static調(diào)用構(gòu)造
     *
     * @param resultCode 結(jié)果枚舉
     * @param data       響應(yīng)數(shù)據(jù)
     */
    private ResponseResult(ResponseResultCode resultCode, T data) {
        this.code = resultCode.getCode();
        this.message = resultCode.getMessage();
        this.data = data;
    }
 
    /**
     * 私有構(gòu)造, 只允許通過static調(diào)用構(gòu)造
     *
     * @param resultCode 結(jié)果枚舉
     * @param data       響應(yīng)數(shù)據(jù)
     */
    private ResponseResult(ResponseResultCode resultCode, Long total, T data) {
        this.code = resultCode.getCode();
        this.message = resultCode.getMessage();
        this.data = data;
        this.total = total;
    }
 
    /**
     * 成功調(diào)用返回的結(jié)果(無數(shù)據(jù)攜帶)
     */
    public static ResponseResult success() {
        return success(null);
    }
 
    /**
     * 成功調(diào)用返回的結(jié)果(數(shù)據(jù)攜帶)
     *
     * @param data 攜帶的數(shù)據(jù)
     */
    public static <T> ResponseResult success(T data) {
        return new ResponseResult(ResponseResultCode.SUCCESS, data);
    }
 
    /**
     * 成功調(diào)用返回的結(jié)果(分頁使用)
     *
     * @param data  攜帶的數(shù)據(jù)
     * @param total 數(shù)據(jù)總條數(shù)
     */
    public static <T> ResponseResult success(T data, Long total) {
        return new ResponseResult(ResponseResultCode.SUCCESS, total, data);
    }
 
    /**
     * 失敗調(diào)用返回的結(jié)果(數(shù)據(jù)攜帶)
     *
     * @param resultCode 狀態(tài)枚舉
     * @param data       攜帶的數(shù)據(jù)
     */
    public static <T> ResponseResult failure(ResponseResultCode resultCode, T data) {
        return new ResponseResult(resultCode, data);
    }
 
    /**
     * 失敗調(diào)用返回的結(jié)果(無數(shù)據(jù)攜帶)
     *
     * @param resultCode 狀態(tài)枚舉
     */
    public static ResponseResult failure(ResponseResultCode resultCode) {
        return failure(resultCode, null);
    }
 
}

ResponseResultCode :

package com.example.seckill.util.response;
 
import java.io.Serializable;
 
@SuppressWarnings("all")
public enum ResponseResultCode implements Serializable {
 
    /* 正常狀態(tài) */
    SUCCESS(200, "成功"),
    FAILURE(300, "失敗"),
    UNKNOWN(400, "未知錯誤"),
    /**
     * 用戶code范圍: 1000;
     */
    USER_ACCOUNT_NOT_FIND(1001, "用戶名不存在"),
    USER_ACCOUNT_DISABLED(1002, "該用戶已被禁用"),
    USER_PASSWORD_NOT_MATCH(1003, "該用戶密碼不一致"),
    USER_PERMISSION_ERROR(1004, "該用戶不具備訪問權(quán)限"),
    USER_STATE_OFF_LINE(1005, "該用戶未登錄"),
    USER_CREDENTIAL_NOT_BE_EMPTY(1006, "用戶的登錄信息不能為空值"),
    USER_ACCOUNT_NOT_MOBLIE(1007, "該用戶登錄信息格式不符合"),
    USER_LOGIN_ERROR(1008, "登錄失敗"),
    /**
     * 其它異常: 4000;
     */
    TICKET_ERROR(4001, "TICKET失效,請重新登錄"),
    /**
     * 商品異常: 6000;
     */
    GOODS_ADD_ERROR(6001, "商品添加失敗"),
    GOODS_EDIT_ERROR(6002, "商品修改失敗"),
    GOODS_REMOVE_ERROR(6003, "商品刪除失敗"),
    /**
     * 秒殺商品異常: 8000
     */
    SECKILL_GOODS_ADD_ERROR(8001, "秒殺商品增加失敗"),
    /**
     * 秒殺訂單異常: 10000
     */
    SECKILL_ORDER_ERROR(10001, "秒殺訂單增加失敗"),
    SECKILL_ORDER_QUANTITY_ERROR(10002, "秒殺商品數(shù)量不足"),
    SECKILL_ORDER_EXISTS_ERROR(10002, "秒殺訂單已經(jīng)存在"),
    ;
 
    private final Integer code;
    private final String message;
 
    ResponseResultCode(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
 
    public static ResponseResultCode queryCode(Integer code) {
        for (ResponseResultCode value : values()) {
            if (code.equals(value.code)) {
                return value;
            }
        }
        return UNKNOWN;
    }
 
    public Integer getCode() {
        return code;
    }
 
    public String getMessage() {
        return message;
    }
 
}

RestThrowableAdvice :

package com.example.seckill.util.response;
import com.example.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;
 
import java.util.Arrays;
 
@SuppressWarnings("all")
@RestControllerAdvice
@Slf4j
public class RestThrowableAdvice {
 
    @JsonResponseResult
    @ExceptionHandler(value = {BusinessException.class})
    public Object globalBusinessException(Model m, Exception e) {
        log.error(e.toString());
        return ((BusinessException) e).getResponseResultCode();
    }
 
    @JsonResponseResult
    @ExceptionHandler(value = {BindException.class})
    public Object globalBindException(Model m, Exception e) {
        log.error(e.toString());
        BindException error = (BindException) e;
        return Arrays
                .stream(error.getFieldError().getArguments())
                .filter(arg -> arg instanceof ResponseResultCode)
                .findAny()
                .orElse(ResponseResultCode.UNKNOWN);
    }
 
    @JsonResponseResult
    @ExceptionHandler(value = {Throwable.class})
    public Object globalException(Model m, Exception e) {
        log.error(e.toString());
        return ResponseResultCode.UNKNOWN;
    }
 
}

③、MD5Utils

package com.example.seckill.util;
 
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Component;
 
import java.util.UUID;
 
/**
 * MD5加密
 * 用戶端:password=MD5(明文+固定Salt)
 * 服務(wù)端:password=MD5(用戶輸入+隨機Salt)
 * 用戶端MD5加密是為了防止用戶密碼在網(wǎng)絡(luò)中明文傳輸,服務(wù)端MD5加密是為了提高密碼安全性,雙重保險。
 */
@Component
@SuppressWarnings("all")
public class MD5Utils {
 
    //加密鹽,與前端一致
    private static String salt = "f1g2h3j4";
 
    /**
     * md5加密
     *
     * @param src
     * @return
     */
    public static String md5(String src) {
        return DigestUtils.md5Hex(src);
    }
 
    /**
     * 獲取加密的鹽
     *
     * @return
     */
    public static String createSalt() {
        return UUID.randomUUID().toString().replace("-", "");
    }
 
    /**
     * 將前端的明文密碼通過MD5加密方式加密成后端服務(wù)所需密碼
     * 注意:該步驟實際是在前端完成!?。?
     *
     * @param inputPass 明文密碼
     * @return
     */
    public static String inputPassToFormpass(String inputPass) {
        //混淆固定鹽salt,安全性更可靠
        String str = salt.charAt(1) + "" + salt.charAt(5) + inputPass + salt.charAt(0) + "" + salt.charAt(3);
        return md5(str);
    }
 
    /**
     * 將后端密文密碼+隨機salt生成數(shù)據(jù)庫的密碼
     *
     * @param formPass
     * @param salt
     * @return
     */
    public static String formPassToDbPass(String formPass, String salt) {
        //混淆固定鹽salt,安全性更可靠
        String str = salt.charAt(7) + "" + salt.charAt(9) + formPass + salt.charAt(1) + "" + salt.charAt(5);
        return md5(str);
    }
 
    /**
     * 將用戶輸入的密碼轉(zhuǎn)換成數(shù)據(jù)庫的密碼
     *
     * @param inputPass 明文密碼
     * @param salt      鹽
     * @return
     */
    public static String inputPassToDbPass(String inputPass, String salt) {
        String formPass = inputPassToFormpass(inputPass);
        String dbPass = formPassToDbPass(formPass, salt);
        return dbPass;
    }
 
    public static void main(String[] args) {
        String formPass = inputPassToFormpass("123456");
        System.out.println("前端加密密碼:" + formPass);
        String salt = createSalt();
        System.out.println("后端加密隨機鹽:" + salt);
        String dbPass = formPassToDbPass(formPass, salt);
        System.out.println("后端加密密碼:" + dbPass);
        String dbPass1 = inputPassToDbPass("123456", salt);
        System.out.println("最終加密密碼:" + dbPass1);
    }
}

ValidatorUtils :

package com.example.seckill.util;
 
import org.apache.commons.lang3.StringUtils;
 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
@SuppressWarnings("all")
public class ValidatorUtils {
 
    private static final Pattern mobile_pattern = Pattern.compile("[1]([0-9])[0-9]{9}$");
 
    public static boolean isMobile(String mobile) {
        if (StringUtils.isEmpty(mobile)) {
            return false;
        }
        Matcher matcher = mobile_pattern.matcher(mobile);
        return matcher.matches();
    }
 
}

2、新建vo類

用于前后端傳值:

package com.example.seckill.vo;
 
import lombok.Data;
 
@Data
public class UserVo {
 
//    手機號
    private String mobile;
//    密碼
    private String password;
 
}

3、登錄方法:

IUserService層:

package com.example.seckill.service;
 
import com.example.seckill.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.seckill.util.response.ResponseResult;
import com.example.seckill.vo.UserVo;
 
/**
 * <p>
 * 用戶信息表 服務(wù)類
 * </p>
 *
 * @author lv
 * @since 2022-03-15
 */
public interface IUserService extends IService<User> {
 
    ResponseResult<?> findByAccount(UserVo userVo);
}

UserServiceImpl類:

package com.example.seckill.service.impl;
 
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.seckill.pojo.User;
import com.example.seckill.mapper.UserMapper;
import com.example.seckill.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.seckill.util.ValidatorUtils;
import com.example.seckill.util.response.ResponseResult;
import com.example.seckill.util.response.ResponseResultCode;
import com.example.seckill.vo.UserVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
 
/**
 * <p>
 * 用戶信息表 服務(wù)實現(xiàn)類
 * </p>
 *
 * @author lv
 * @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())){
             return ResponseResult.failure(ResponseResultCode.USER_ACCOUNT_NOT_MOBLIE);
         }
         if(!StringUtils.isBlank(userVo.getPassword())){
             return ResponseResult.failure(ResponseResultCode.USER_PASSWORD_NOT_MATCH);
         }
//         再去數(shù)據(jù)庫查出對應(yīng)的用戶(mobile)
        User user=this.getOne(new QueryWrapper<User>().eq("id",userVo.getMobile()));
        if(user==null){
            return ResponseResult.failure(ResponseResultCode.USER_ACCOUNT_NOT_FIND);
        }
//        比較密碼
        if(userVo.getPassword().equals(user.getPassword())){
            return ResponseResult.failure(ResponseResultCode.USER_PASSWORD_NOT_MATCH);
        }
        return ResponseResult.success();
    }
}

UserController類:

package com.example.seckill.controller;
 
import com.example.seckill.service.IUserService;
import com.example.seckill.util.response.ResponseResult;
import com.example.seckill.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
/**
 * <p>
 * 用戶信息表 前端控制器
 * </p>
 *
 * @author lv
 * @since 2022-03-15
 */
@RestController
@RequestMapping("/user")
public class UserController {
 
    @Autowired
    private IUserService userService;
 
//    用戶登錄
    @RequestMapping("/login")
 public ResponseResult<?> login(UserVo userVo){
//     調(diào)用service的登錄驗證
     return userService.findByAccount(userVo);
 }
 
}

4、密碼加密

①、將md5.js放到j(luò)s文件中

②、前端密碼進行加密

login.js文件:

layui.use(["jquery","layer"],()=>{
    // 得到layui中封裝的jquery
    let $=layui.jquery
    let layer=layui.layer
    // 給登錄按鈕設(shè)置事件
    $(login).click(()=>{
     // 取到表單的值
    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)
    // 將數(shù)據(jù)給后臺(前后端分離axios,普通開發(fā)ajax)
       $.ajax({
           url:"/user/login",//后臺登錄接口
           data:{
             // 需要攜帶的數(shù)據(jù)
               mobile,
               password
           },
           datatype: "json",//后端給你的數(shù)據(jù)類型
           success(e){
               // 成功的回調(diào)函數(shù)
            layer.msg(e.message,{icon: 6});
           },
           error(e){
               // 報錯的回調(diào)函數(shù)

           }

       })
    })


})

UserServiceImpl文件:

package com.example.seckill.service.impl;

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

/**
 * <p>
 * 用戶信息表 服務(wù)實現(xiàn)類
 * </p>
 *
 * @author lv
 * @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())){
             return ResponseResult.failure(ResponseResultCode.USER_ACCOUNT_NOT_MOBLIE);
         }
         if(StringUtils.isBlank(userVo.getPassword())){
             return ResponseResult.failure(ResponseResultCode.USER_PASSWORD_NOT_MATCH);
         }
//         再去數(shù)據(jù)庫查出對應(yīng)的用戶(mobile)
        User user=this.getOne(new QueryWrapper<User>().eq("id",userVo.getMobile()));
        if(user==null){
            return ResponseResult.failure(ResponseResultCode.USER_ACCOUNT_NOT_FIND);
        }
//        比較密碼
//        二重加密(前端->后端,后端->數(shù)據(jù)庫)
        String salt=user.getSalt();
//        將前臺的加密密碼和后端的鹽再次進行加密
        String newPassword=MD5Utils.formPassToDbPass(userVo.getPassword(),salt);
        if(!newPassword.equals(user.getPassword())){
            return ResponseResult.failure(ResponseResultCode.USER_PASSWORD_NOT_MATCH);
        }
        return ResponseResult.success();
    }
}

得到密鑰,登錄成功: 

四、 全局異常抓獲

1、給實體類userVo加入注解

package com.example.seckill.vo;
 
import com.example.seckill.util.response.ResponseResultCode;
import com.example.seckill.util.validate.IsMobile;
import com.example.seckill.util.validate.IsRequired;
import lombok.Data;
 
import javax.validation.constraints.NotEmpty;
 
@Data
public class UserVo {
 
//    手機號
    @IsMobile(code = ResponseResultCode.USER_ACCOUNT_NOT_FIND)
    private String mobile;
//    密碼
    @IsRequired(code = ResponseResultCode.USER_CREDENTIAL_NOT_BE_EMPTY)
    private String password;
 
 
}

2、導(dǎo)入幫助包validate,異常抓獲

IsMobile:

package com.example.seckill.util.validate;
 
 
import com.example.seckill.util.response.ResponseResultCode;
 
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
 
@SuppressWarnings("all")
@Documented
@Constraint(
//        告知使用哪個解析器
        validatedBy = {IsMobileValidator.class}
)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsMobile {
 
    ResponseResultCode code() default ResponseResultCode.UNKNOWN;
     String message() default "";
 
    Class<?>[] groups() default {};
 
    Class<? extends Payload>[] payload() default {};
 
}

IsMobileValidator:

package com.example.seckill.util.validate;
 
 
import com.example.seckill.util.ValidatorUtils;
 
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
 
//IsMobile的解析類
public class IsMobileValidator implements ConstraintValidator<IsMobile, String> {
 
    @Override
    public boolean isValid(String mobile, ConstraintValidatorContext context) {
//       調(diào)用幫助類判斷格式是否正確
        return ValidatorUtils.isMobile(mobile);
    }
 
}

IsRequired:

package com.example.seckill.util.validate;
 
import com.example.seckill.util.response.ResponseResultCode;
 
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
 
@SuppressWarnings("all")
@Documented
@Constraint(
//        告知使用哪個解析器
        validatedBy = {IsRequiredValidator.class}
)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface IsRequired {
 
    ResponseResultCode code() default ResponseResultCode.UNKNOWN;
 
    String message() default "";
 
    Class<?>[] groups() default {};
 
    Class<? extends Payload>[] payload() default {};
 
}

IsRequiredValidator:

package com.example.seckill.util.validate;
 
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
 
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
 
 
@Slf4j
public class IsRequiredValidator implements ConstraintValidator<IsRequired, String> {
 
    @Override
    public boolean isValid(String str, ConstraintValidatorContext context) {
        return StringUtils.isNotBlank(str);
    }
 
}

ThrowableAdvice:

package com.example.seckill.util.response;
import com.example.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;
 
/**
 * 全局異常
 */
 
//RestController的增強類
@RestControllerAdvice
@Slf4j
//抓取異常
public class ThrowableAdvice {
 
//    第一種方法
//    將你的結(jié)果直接封裝為ResponseResult
    @JsonResponseResult
//    抓捕一個異常
    @ExceptionHandler(value = {BusinessException.class})
    public ResponseResultCode globalBusinessException(Model m, Exception e) {
        log.error(e.toString());
        e.printStackTrace();
        return ((BusinessException) e).getResponseResultCode();
    }
//    第二種方法
//@JsonResponseResult
//@ExceptionHandler(value = {BusinessException.class})
//public Object globalBusinessException(Model m, Exception e) {
//    Object[] arguments=((BindException)e).getFieldError().getArguments();
//   找到該注解上的響應(yīng)碼并且返回
//    return Arrays.stream(arguments)
//            .filter(t->t instanceof ResponseResultCode)
//            .findAny()
//            .orElse(ResponseResultCode.UNKNOWN);
//}
    @JsonResponseResult
    @ExceptionHandler(value = {BindException.class})
    public ResponseResultCode globalBindException(Model m, Exception e) {
        log.error(e.toString());
        BindException error = (BindException) e;
        e.printStackTrace();
        return (ResponseResultCode) error.getFieldError().getArguments()[1];
    }
 
    @JsonResponseResult
    @ExceptionHandler(value = {Throwable.class})
    public ResponseResultCode globalException(Model m, Exception e) {
        log.error(e.toString());
        e.printStackTrace();
        return ResponseResultCode.UNKNOWN;
    }
 
}

3、在UserController類方法中加入注解

開啟jsr303驗證

@Valid

4、實現(xiàn)類拋出異常

package com.example.seckill.service.impl;

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

import java.util.Date;

/**
 * <p>
 * 用戶信息表 服務(wù)實現(xiàn)類
 * </p>
 *
 * @author lv
 * @since 2022-03-15
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Override
    public ResponseResult<?> findByAccount(UserVo 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_PASSWORD_NOT_MATCH);
//         }
//         再去數(shù)據(jù)庫查出對應(yīng)的用戶(mobile)
        User user=this.getOne(new QueryWrapper<User>().eq("id",userVo.getMobile()));
        if(user==null){
            throw new BusinessException(ResponseResultCode.USER_ACCOUNT_NOT_FIND);
        }
//        比較密碼
//        二重加密(前端->后端,后端->數(shù)據(jù)庫)
        String salt=user.getSalt();
//        將前臺的加密密碼和后端的鹽再次進行加密
        String newPassword=MD5Utils.formPassToDbPass(userVo.getPassword(),salt);
        if(!newPassword.equals(user.getPassword())){
            throw new BusinessException(ResponseResultCode.USER_PASSWORD_NOT_MATCH);
        }
//        修改最后的登錄時間
        this.update(new UpdateWrapper<User>().eq("id",userVo.getMobile()).set("last_login_date",new Date()).setSql("login_count=login_count+1"));
        return ResponseResult.success();
    }
}

密碼錯誤時不會報錯:

本期內(nèi)容結(jié)束~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

到此這篇關(guān)于超詳細講解Java秒殺項目登陸模塊的實現(xiàn)的文章就介紹到這了,更多相關(guān)Java 登陸模塊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java調(diào)用shell腳本及注意事項說明

    java調(diào)用shell腳本及注意事項說明

    這篇文章主要介紹了java調(diào)用shell腳本及注意事項說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java中使用輾轉(zhuǎn)相除法求最大公約數(shù)

    Java中使用輾轉(zhuǎn)相除法求最大公約數(shù)

    這篇文章主要介紹了Java中使用輾轉(zhuǎn)相除法求最大公約數(shù),本文直接給出代碼實例,需要的朋友可以參考下
    2015-05-05
  • Spring boot實現(xiàn)熱部署的兩種方式詳解

    Spring boot實現(xiàn)熱部署的兩種方式詳解

    這篇文章主要介紹了Spring boot實現(xiàn)熱部署的兩種方式,這兩種方法分別是使用 Spring Loaded和使用spring-boot-devtools進行熱部署,文中給出了詳細示例代碼和介紹,需要的朋友可以參考學(xué)習(xí),下面來一起看看吧。
    2017-04-04
  • SpringBoot項目如何將Bean注入到普通類中

    SpringBoot項目如何將Bean注入到普通類中

    這篇文章主要介紹了SpringBoot項目如何將Bean注入到普通類中,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Spring Boot和Kotlin的無縫整合與完美交融

    Spring Boot和Kotlin的無縫整合與完美交融

    這篇文章主要給大家介紹了關(guān)于Spring Boot和Kotlin的無縫整合與完美交融的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-06-06
  • SpringBoot時間格式化的方法小結(jié)

    SpringBoot時間格式化的方法小結(jié)

    SpringBoot中的時間格式化通常指的是將Java中的日期時間類型轉(zhuǎn)換為指定格式的字符串,或者將字符串類型的時間解析為Java中的日期時間類型,本文小編將給大家詳細總結(jié)了SpringBoot時間格式化的方法,剛興趣的小伙伴跟著小編一起來看看吧
    2023-10-10
  • java中實現(xiàn)對象排序的兩種方法(Comparable,Comparator)

    java中實現(xiàn)對象排序的兩種方法(Comparable,Comparator)

    這篇文章主要給大家介紹了關(guān)于java中實現(xiàn)對象排序的兩種方法,一種是實現(xiàn)Comparable進行排序,另一種是實現(xiàn)Comparator進行排序,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-12-12
  • Java基礎(chǔ):徹底搞懂java多線程

    Java基礎(chǔ):徹底搞懂java多線程

    篇文章主要介紹了Java多線程的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java線程相關(guān)知識,感興趣的朋友可以了解下,希望能給你帶來幫助
    2021-08-08
  • freemarker?jsp?java內(nèi)存方式實現(xiàn)分頁示例

    freemarker?jsp?java內(nèi)存方式實現(xiàn)分頁示例

    這篇文章主要介紹了freemarker?jsp?java內(nèi)存方式實現(xiàn)分頁示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • Java獲取時間打印到控制臺代碼實例

    Java獲取時間打印到控制臺代碼實例

    這篇文章主要介紹了Java獲取時間打印到控制臺代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02

最新評論