一、數據庫表的設計與建立

1.1 ⽤⼾表 user

字段

類型

非空(Y/N)

主鍵(Y/N)

默認值

備註

id

bigint

Y

Y


主鍵

gmt_create

datetime

Y

N

當前時間

創建時間

gmt_modified

datetime

Y

N

當前時間

更新時間

user_name

varchar(255)

Y

N


用户姓名

email

varchar(255)

Y

N


郵箱

phone_number

varchar(255)

Y

N


手機號

password

varchar(255)

Y

N


登錄密碼

identity

varchar(255)

Y

N


用户身份

SQL語句:

-- ----------------------------
-- Table structure for user
-- ----------------------------
drop table IF EXISTS `user`;
create TABLE `user`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT comment '主鍵',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP comment '創建時間',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON update CURRENT_TIMESTAMP comment '更新時間',
  `user_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '用户姓名',
  `email` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '郵箱',
  `phone_number` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '手機號',
  `password` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL comment '登錄密碼',
  `identity` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '用户身份',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `uk_id`(`id` ASC) USING BTREE,
  UNIQUE INDEX `uk_email`(`email`(30) ASC) USING BTREE,
  UNIQUE INDEX `uk_phone_number`(`phone_number`(11) ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 39 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;

1.2 活動表 activity

字段

類型

非空(Y/N)

主鍵(Y/N)

默認值

備註

id

bigint

Y

Y


主鍵

gmt_create

datetime

Y

N


創建時間

gmt_modified

datetime

Y

N

當前時間

更新時間

activity_name

varchar(255)

Y

N


活動名稱

description

varchar(255)

Y

N


活動描述

status

varchar(255)

Y

N


活動狀態

SQL語句:

-- ----------------------------
-- Table structure for activity
-- ----------------------------
drop table IF EXISTS `activity`;
create TABLE `activity`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT comment '主鍵',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP comment '創建時間',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON update CURRENT_TIMESTAMP comment '更新時間',
  `activity_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '活動名稱',
  `description` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '活動描述',
  `status` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '活動狀態',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `uk_id`(`id` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;

1.3 獎品表 prize

字段

類型

非空(Y/N)

主鍵(Y/N)

默認值

備註

id

bigint

Y

Y


主鍵

gmt_create

datetime

Y

N


創建時間

gmt_modified

datetime

Y

N

當前時間

更新時間

name

varchar(255)

Y

N


獎品名稱

description

varchar(255)

Y

N


獎品描述

price

decimal(10, 2)

N

N

NULL

獎品價值

image_url

varchar(2048)

N

N

NULL

活動狀態

SQL語句:

-- ----------------------------
-- Table structure for prize
-- ----------------------------
drop table IF EXISTS `prize`;
create TABLE `prize`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT comment '主鍵',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP comment '創建時間',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON update CURRENT_TIMESTAMP comment '更新時間',
  `name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '獎品名稱',
  `description` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL comment '獎品描述',
  `price` decimal(10, 2) NOT NULL comment '獎品價值',
  `image_url` varchar(2048) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL comment '獎品展示圖',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `uk_id`(`id` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;

1.4 活動獎品關聯表 activity_prize

字段

類型

非空(Y/N)

主鍵(Y/N)

默認值

備註

id

bigint

Y

Y


主鍵

gmt_create

datetime

Y

N


創建時間

gmt_modified

datetime

Y

N

當前時間

更新時間

activity_id

bigint

Y

N


活動id

prize_id

bigint

Y

N


活動關聯的獎品id

prize_amount

bigint

Y

N

1

關聯獎品的數量

prize_tiers

varchar(255)

Y

N


獎品等級

status

varchar(255)

Y

N


活動獎品狀態

SQL語句:

-- ----------------------------
-- Table structure for activity_prize
-- ----------------------------
drop table IF EXISTS `activity_prize`;
create TABLE `activity_prize`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT comment '主鍵',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP comment '創建時間',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON update CURRENT_TIMESTAMP comment '更新時間',
  `activity_id` bigint NOT NULL comment '活動id',
  `prize_id` bigint NOT NULL comment '活動關聯的獎品id',
  `prize_amount` bigint NOT NULL DEFAULT 1 comment '關聯獎品的數量',
  `prize_tiers` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '獎品等級',
  `status` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '活動獎品狀態',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `uk_id`(`id` ASC) USING BTREE,
  UNIQUE INDEX `uk_a_p_id`(`activity_id` ASC, `prize_id` ASC) USING BTREE,
  INDEX `idx_activity_id`(`activity_id` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;

1.5 活動⽤⼾關聯表 activity_user

字段

類型

非空(Y/N)

主鍵(Y/N)

默認值

備註

id

bigint

Y

Y


主鍵

gmt_create

datetime

Y

N


創建時間

gmt_modified

datetime

Y

N

當前時間

更新時間

activity_id

bigint

Y

N


活動id

user_id

bigint

Y

N


圈選的用户id

user_name

varchar(255)

Y

N


用户名

status

varchar(255)

Y

N


用户狀態

SQL語句:

-- ----------------------------
-- Table structure for activity_user
-- ----------------------------
drop table IF EXISTS `activity_user`;
create TABLE `activity_user`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT comment '主鍵',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP comment '創建時間',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON update CURRENT_TIMESTAMP comment '更新時間',
  `activity_id` bigint NOT NULL comment '活動id',
  `user_id` bigint NOT NULL comment '圈選的用户id',
  `user_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '用户名',
  `status` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '用户狀態',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `uk_id`(`id` ASC) USING BTREE,
  UNIQUE INDEX `uk_a_u_id`(`activity_id` ASC, `user_id` ASC) USING BTREE,
  INDEX `idx_activity_id`(`activity_id` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;

1.6 中獎記錄表 winning_record

字段

類型

非空(Y/N)

主鍵(Y/N)

默認值

備註

id

bigint

Y

Y


主鍵

gmt_create

datetime

Y

N


創建時間

gmt_modified

datetime

Y

N

當前時間

更新時間

activity_id

bigint

Y

N


活動id

activity_name

varchar(255)

Y

N


活動名稱

prize_id

bigint

Y

N


獎品id

prize_name

varchar(255)

Y

N


獎品名稱

prize_tier

varchar(255)

Y

N


獎品等級

winner_id

bigint

Y

N


中獎人id

winner_name

varchar(255)

Y

N


中獎人姓名

winner_email

varchar(255)

Y

N


中獎人郵箱

winner_phone_number

varchar(255)

Y

N


中獎人電話

winning_time

datetime

Y

N


中獎時間

SQL語句:

-- ----------------------------
-- Table structure for winning_record
-- ----------------------------
drop table IF EXISTS `winning_record`;
create TABLE `winning_record`  (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT comment '主鍵',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP comment '創建時間',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON update CURRENT_TIMESTAMP comment '更新時間',
  `activity_id` bigint NOT NULL comment '活動id',
  `activity_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '活動名稱',
  `prize_id` bigint NOT NULL comment '獎品id',
  `prize_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '獎品名稱',
  `prize_tier` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '獎品等級',
  `winner_id` bigint NOT NULL comment '中獎人id',
  `winner_name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '中獎人姓名',
  `winner_email` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '中獎人郵箱',
  `winner_phone_number` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL comment '中獎人電話',
  `winning_time` datetime NOT NULL comment '中獎時間',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `uk_id`(`id` ASC) USING BTREE,
  UNIQUE INDEX `uk_w_a_p_id`(`winner_id` ASC, `activity_id` ASC, `prize_id` ASC) USING BTREE,
  INDEX `idx_activity_id`(`activity_id` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 69 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = DYNAMIC;

二、創建工程及分層

創建Spring Boot項目:

分層: controller:與前端接口交互,調用service service:業務邏輯,此項目service層與mapper層合併了 dao:與數據庫交互 common:公共代碼層

三、功能模塊設計

3.1 錯誤碼定義

這次項目我們錯誤碼使用類來定義,不使用枚舉。 com.yj.lottery_system.common.errorcode 包下定義:

  • 錯誤碼類型:ErrorCode 類
package com.yj.lottery_system.common.errorcode;

import lombok.Data;

@Data
public class ErrorCode {
    //錯誤碼
    private final Integer code;
    //錯誤信息
    private final String msg;

    public ErrorCode(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}
  • 定義全局錯誤碼:GlobalErrorCodeConstants 類
package com.yj.lottery_system.common.errorcode;

public interface GlobalErrorCodeConstants {
    ErrorCode SUCCESS = new ErrorCode(200, "成功...");
    
    //服務端異常
    ErrorCode INTERNAL_SERVICE_ERROR = new ErrorCode(500, "系統異常..");
    ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未實現/未開啓..");
    ErrorCode ERROR_CONFIGURATION = new ErrorCode(502, "錯誤的配置項..");

    //未知異常
    ErrorCode UNKNOWN = new ErrorCode(999, "未知錯誤....");


}
  • 定義業務錯誤碼--controller層錯誤碼:ControllerErrorCodeConstants 類,隨着業務代碼的完成補充
package com.yj.lottery_system.common.errorcode;

public interface ControllerErrorCodeConstants {
    //人員模塊錯誤碼
    //活動模塊錯誤碼
    //獎品模塊錯誤碼
    //抽獎錯誤碼
}
  • 定義業務錯誤碼--service層錯誤碼:ServiceErrorCodeConstants 類,隨着業務代碼的完成補充
package com.yj.lottery_system.common.errorcode;

public interface ServiceErrorCodeConstants {
    //人員模塊錯誤碼
    //活動模塊錯誤碼
    //獎品模塊錯誤碼
    //抽獎錯誤碼
}

3.2 自定義異常類

com.yj.lottery_system.common.exception 下定義異常類: 為了使我們的 @Data 註解能夠帶上父類的屬性生成equals和hashCode方法,我們使用註解@EqualsAndHashCode(callSuper = true)

  • ControllerException:controller 層異常類
package com.yj.lottery_system.common.exception;

import com.yj.lottery_system.common.errorcode.ErrorCode;
import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper = true)
public class ControllerException extends RuntimeException {
    //異常碼
    private Integer code;
    //異常信息
    private String msg;

    //序列化使用
    public ControllerException() {
    }

    public ControllerException(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public ControllerException(ErrorCode errorCode) {
        this.code = errorCode.getCode();
        this.msg = errorCode.getMsg();
    }

}
  • ServiceException:service 層異常類
package com.yj.lottery_system.common.exception;

import com.yj.lottery_system.common.errorcode.ErrorCode;
import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper = true)
public class ServiceException extends RuntimeException{
    //異常碼
    private Integer code;
    //異常信息
    private String msg;

    //序列化使用
    public ServiceException() {
    }

    public ServiceException(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public ServiceException(ErrorCode errorCode) {
         super(errorCode.getMsg());
        this.code = errorCode.getCode();
        this.msg = errorCode.getMsg();
    }

}

3.3 統一返回結果

CommonResult 作為控制器層⽅法的返回類型,封裝 HTTP 接⼝調⽤的結果,包括成功數據、錯誤信息和狀態碼。它可以被 Spring Boot 框架等⾃動轉換為 JSON 或其他格式的響應體,發送給客⼾端。

com.yj.lottery_system.common.pojo 包下:

  • 為實現序列化,要繼承 Serializable
  • 提供兩種方法,成功success,失敗error
  • 成功的時候,需要返回數據
  • 失敗的時候,傳錯誤碼斷言,判斷一下錯誤碼是不是成功碼200
package com.yj.lottery_system.common.pojo;

import com.yj.lottery_system.common.errorcode.ErrorCode;
import com.yj.lottery_system.common.errorcode.GlobalErrorCodeConstants;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.Assert;

import java.io.Serializable;
@Data
@AllArgsConstructor         // 全參構造
@NoArgsConstructor          // 無參構造(Jackson 反序列化需要)
public class CommonResult <T> implements Serializable {
    //返回錯誤碼
    private Integer code;
    //返回錯誤信息
    private String msg;
    //返回正常數據
    private T data;
    public static <T> CommonResult<T> success( T data) {
        CommonResult<T> commonResult = new CommonResult<>();
        commonResult.code = GlobalErrorCodeConstants.SUCCESS.getCode();
        commonResult.msg = GlobalErrorCodeConstants.SUCCESS.getMsg();
        commonResult.data = data;
        return commonResult;

    }
    public static <T> CommonResult<T> error( Integer code, String msg) {
        //斷言
        Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code),"code: "+code+" 不是一個異常的錯誤碼");

        CommonResult<T> commonResult = new CommonResult<>();
        commonResult.code = code;
        commonResult.msg = msg;
        commonResult.data = null;

        return commonResult;

    }

    public static <T> CommonResult<T> error(ErrorCode errorCode) {
        //斷言
        Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(errorCode.getCode()),"code: "+errorCode.getCode()+" 不是一個異常的錯誤碼");

        CommonResult<T> commonResult = new CommonResult<>();
        commonResult.code = errorCode.getCode();
        commonResult.msg = errorCode.getMsg();

        return commonResult;

    }
}

3.4 工具類

我們要創建一個序列化工具,在日誌打印,使用中間件的時候使用該工具。我們使用Jackson來序列化。 com.yj.lottery_system.common.utils包下:JacksonUtil 類 邏輯:

  • 我們仿照spring中的jackson來實現
  • 在類中將原本序列化要調用ObjectMapper 在類中單例化實現
  • 將異常處理仿照 AbstractJsonParser.class 處理異常,使用lambda表達式處理異常
  • 封裝序列化方法和反序列化類與List的方法
package com.yj.lottery_system.common.utils;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yj.lottery_system.common.pojo.CommonResult;
import org.springframework.boot.json.JsonParseException;
import org.springframework.util.ReflectionUtils;

import java.util.List;
import java.util.concurrent.Callable;

public class JacksonUtil {
    public JacksonUtil() {
    }

    //單例操作
    private final static ObjectMapper OBJECT_MAPPER;
    static {
        OBJECT_MAPPER = new ObjectMapper();
    }

    public static ObjectMapper getObjectMapper() {
        return OBJECT_MAPPER;
    }

    //仿照json\AbstractJsonParser.class,處理異常
    private static  <T> T tryParse(Callable<T> parser) {
        return tryParse(parser, JacksonException.class);
    }
    private static  <T> T tryParse(Callable<T> parser, Class<? extends Exception> check) {
        try {
            return parser.call();
        } catch (Exception var4) {
            if (check.isAssignableFrom(var4.getClass())) {
                throw new JsonParseException(var4);
            }
            throw new IllegalStateException(var4);
        }
    }
    //序列化
    public static String writeValueAsString(Object o) {
        return JacksonUtil.tryParse( ()->{
            return JacksonUtil.getObjectMapper().writeValueAsString(o);
        });
    }
    //反序列化
    public static <T> T readValue(String s, Class<T> valueType) {
        return JacksonUtil.tryParse(() -> {
            return JacksonUtil.getObjectMapper().readValue(s, valueType);
        });
    }

    //反序列化list
    public static <T> T readListValue(String s, Class<?> paramClasses) {
        JavaType javaType = JacksonUtil.getObjectMapper().getTypeFactory().constructParametricType(List.class, paramClasses);

        return JacksonUtil.tryParse(() -> {
            return JacksonUtil.getObjectMapper().readValue(s, javaType);
        });
    }
}

使用測試: 測試方法:

@Test
    void jacksonUtilTest() {
        CommonResult<String> commonResult = CommonResult.error(500,"系統錯誤");
        //序列化
        String s = JacksonUtil.writeValueAsString(commonResult);
        System.out.println(s);

        //反序列化
        CommonResult<String> commonResult1 = JacksonUtil.readValue(s, CommonResult.class);
        System.out.println(commonResult1.equals(commonResult));

        //序列化List
        List<CommonResult<String>> commonResults = new ArrayList<>();
        commonResults.add(CommonResult.error(500,"系統錯誤"));
        commonResults.add(CommonResult.success("success"));
        String s2 = JacksonUtil.writeValueAsString(commonResults);
        System.out.println(s2);

        //反序列化List
        List<CommonResult<String>> commonResults1 = JacksonUtil.readListValue(s2, CommonResult.class);
        System.out.println(commonResults1.equals(commonResults));
    }

結果:

3.5 日誌配置

application.yml 配置:

spring:
  application:
    name: lottery_system

  profiles:
    active: dev     # 本地環境 部署後需要變成 spring.profiles.active=test


## logback xml ##
logging:
  config: classpath:logback-spring.xml

新增 logback-spring.xml :

<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" scanPeriod="60 seconds" debug="false">
    <springProfile name="dev">
        <!--輸出到控制枱-->
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n%ex</pattern>
            </encoder>
        </appender>
        <root level="info">
            <appender-ref ref="console" />
        </root>
    </springProfile>

    <springProfile name="prod,test">
        <!--ERROR級別的日誌放在logErrorDir目錄下,INFO級別的日誌放在logInfoDir目錄下-->
        <property name="logback.logErrorDir" value="/lottery-system/logs/error"/>
        <property name="logback.logInfoDir" value="/lottery-system/logs/info"/>
        <property name="logback.appName" value="lotterySystem"/>
        <contextName>${logback.appName}</contextName>

        <!--ERROR級別的日誌配置如下-->
        <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!--日誌名稱,如果沒有File 屬性,那麼只會使用FileNamePattern的文件路徑規則
                如果同時有<File>和<FileNamePattern>,那麼當天日誌是<File>,明天會自動把今天
                的日誌改名為今天的日期。即,<File> 的日誌都是當天的。
            -->
            <File>${logback.logErrorDir}/error.log</File>
            <!-- 日誌level過濾器,保證error.***.log中只記錄ERROR級別的日誌-->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <!--滾動策略,按照時間滾動 TimeBasedRollingPolicy-->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--文件路徑,定義了日誌的切分方式——把每一天的日誌歸檔到一個文件中,以防止日誌填滿整個磁盤空間-->
                <FileNamePattern>${logback.logErrorDir}/error.%d{yyyy-MM-dd}.log</FileNamePattern>
                <!--只保留最近14天的日誌-->
                <maxHistory>14</maxHistory>
                <!--用來指定日誌文件的上限大小,那麼到了這個值,就會刪除舊的日誌-->
                <!--<totalSizeCap>1GB</totalSizeCap>-->
            </rollingPolicy>
            <!--日誌輸出編碼格式化-->
            <encoder>
                <charset>UTF-8</charset>
                <pattern>%d [%thread] %-5level %logger{36} %line - %msg%n%ex</pattern>
            </encoder>
        </appender>

        <!--INFO級別的日誌配置如下-->
        <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!--日誌名稱,如果沒有File 屬性,那麼只會使用FileNamePattern的文件路徑規則
                如果同時有<File>和<FileNamePattern>,那麼當天日誌是<File>,明天會自動把今天
                的日誌改名為今天的日期。即,<File> 的日誌都是當天的。
            -->
            <File>${logback.logInfoDir}/info.log</File>
            <!--自定義過濾器,保證info.***.log中只打印INFO級別的日誌, 填寫全限定路徑-->
            <filter class="com.yj.lottery_system.common.filter.InfoLevelFilter"/>
            <!--滾動策略,按照時間滾動 TimeBasedRollingPolicy-->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--文件路徑,定義了日誌的切分方式——把每一天的日誌歸檔到一個文件中,以防止日誌填滿整個磁盤空間-->
                <FileNamePattern>${logback.logInfoDir}/info.%d{yyyy-MM-dd}.log</FileNamePattern>
                <!--只保留最近14天的日誌-->
                <maxHistory>14</maxHistory>
                <!--用來指定日誌文件的上限大小,那麼到了這個值,就會刪除舊的日誌-->
                <!--<totalSizeCap>1GB</totalSizeCap>-->
            </rollingPolicy>
            <!--日誌輸出編碼格式化-->
            <encoder>
                <charset>UTF-8</charset>
                <pattern>%d [%thread] %-5level %logger{36} %line - %msg%n%ex</pattern>
            </encoder>
        </appender>
        <root level="info">
            <appender-ref ref="fileErrorLog" />
            <appender-ref ref="fileInfoLog"/>
        </root>
    </springProfile>
</configuration>

自定義日誌過濾器: com.yj.lottery_system.common.filter 包下:InfoLevelFilter 類

package com.yj.lottery_system.common.filter;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;

public class InfoLevelFilter extends Filter<ILoggingEvent> {
   @Override
   public FilterReply decide(ILoggingEvent iLoggingEvent) {
     if (iLoggingEvent.getLevel().toInt() == Level.INFO.toInt()){

      return FilterReply.ACCEPT;
     }
    return FilterReply.DENY;

   }

 }

日誌測試:

package com.yj.lottery_system;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class LogTest {
 private static final Logger logger = LoggerFactory.getLogger(LogTest.class);
  @Test
  void testLog() {
   System.out.println("hello print");
   logger.info("hello log");
  }
}

測試結果:

3.6 加密

3.6.1 加密方式

  1. 對稱加密:AES、3DES。密鑰+明文 = 密文。解密:從庫中拿到密文,解出密鑰加明文,減去密鑰拿到明文,與用户輸入明文比對。
  2. hash加密:不可逆的,MD5、SHA256。解密:用户明文 -》hash得到密文,與庫中密文對比。
  3. 加鹽hash:鹽就是隨機生成的擾動字符,把鹽和明文一起進行hash加密,數據庫記錄加密結果和鹽。解密:數據庫拿到鹽與用户輸入明文hash得到密文與數據庫密文進行比對。

前面spring論壇系統我們使用的加鹽加密,我們這裏使用對稱加密對手機號加密,hash加密對密碼加密。

3.6.2 實現工具類

Maven 倉庫地址:https://mvnrepository.com/artifact/cn.hutool HuTool 官⽹地址:https://hutool.cn/

引入依賴

<!-- hutool 工具 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.25</version>
        </dependency>

密碼加密:直接調用 DigestUtil.sha256Hex 測試:

//密碼hash加密 sha256
    @Test
    void sha256Test() {
        System.out.println(DigestUtil.sha256Hex("14545"));
    }

手機號對稱加密 aes加密:密鑰必須是 16、24 或 32 字節,加密先調用 SecureUtil.aes 方法傳密鑰拿到Aes類,再調用Aes的encryptHex方法加密,解密調用Aes的decryptStr。 測試:

@Test
    void aesTest() {
        //密鑰必須是 16、24 或 32 字節
        byte[] key = "123456saa1456566".getBytes(StandardCharsets.UTF_8);
        //加密
        AES aes = SecureUtil.aes(key);
        String s = aes.encryptHex("123456789");
        System.out.println(s);

        //解密
        String s1 = aes.decryptStr(s);
        System.out.println(s1);
    }