一、數據庫表的設計與建立
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 加密方式
- 對稱加密:AES、3DES。密鑰+明文 = 密文。解密:從庫中拿到密文,解出密鑰加明文,減去密鑰拿到明文,與用户輸入明文比對。
- hash加密:不可逆的,MD5、SHA256。解密:用户明文 -》hash得到密文,與庫中密文對比。
- 加鹽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);
}