实现 BCSdfApiService 中 sm4 加解密接口
This commit is contained in:
parent
b500a4e9cc
commit
a98659f3a9
@ -0,0 +1,36 @@
|
||||
package com.sunyard.chsm.enums;
|
||||
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* 算法的轮模式
|
||||
* @author Cheney
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AlgMode {
|
||||
ECB("ECB", "ECB"),
|
||||
CBC( "CBC", "CBC"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
||||
|
||||
public static AlgMode of(String code) {
|
||||
if (code == null || code.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Arrays.stream(AlgMode.values())
|
||||
.filter(it -> Objects.equals(it.getCode(), code))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.sunyard.chsm.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 数据的填充模式
|
||||
* @author Cheney
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Padding {
|
||||
NOPadding("NoPadding", "NoPadding"),
|
||||
PCKS5Padding( "PKCS5Padding", "PKCS5Padding"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
||||
|
||||
public static Padding of(String code) {
|
||||
if (code == null || code.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Arrays.stream(Padding.values())
|
||||
.filter(it -> Objects.equals(it.getCode(), code))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package com.sunyard.chsm.sdf;
|
||||
|
||||
import com.sunyard.chsm.enums.AlgMode;
|
||||
import com.sunyard.chsm.enums.KeyAlg;
|
||||
import com.sunyard.chsm.enums.Padding;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.sunyard.chsm.utils.gm.BCSM4Utils.DEFAULT_KEY_SIZE;
|
||||
|
||||
/**
|
||||
* 实现 SdfApiService 接口中的通用逻辑
|
||||
* 处理参数缺失时的默认参数,确保下层入参没有 null
|
||||
* @author Cheney
|
||||
*/
|
||||
public abstract class AbstractSdfApiService implements SdfApiService {
|
||||
|
||||
private static final Map<KeyAlg, Integer> algKeyLen = new HashMap<>();
|
||||
static {
|
||||
algKeyLen.put( KeyAlg.SM4, DEFAULT_KEY_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理算法的默认密钥长度
|
||||
* @param alg 算法,只支持对称算法
|
||||
* 密钥长度根据 alg 指定的算法自动选择。
|
||||
* @return 密钥
|
||||
*/
|
||||
@Override
|
||||
public byte[] genSymKey(KeyAlg alg) {
|
||||
return genSymKey( alg, algKeyLen.get( alg ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 对称加密
|
||||
* 内部实现和解密共用逻辑
|
||||
* @param alg 算法,只支持对称算法
|
||||
* @param key 密钥值,明文
|
||||
* @param data 原始数据
|
||||
*/
|
||||
@Override
|
||||
public byte[] symEncrypt(KeyAlg alg, byte[] key, byte[] data){
|
||||
return symEncrypt( alg, AlgMode.ECB, Padding.PCKS5Padding, key, data );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 对称解密
|
||||
* 内部实现和加密共用逻辑
|
||||
* @param alg 算法,只支持对称算法
|
||||
* @param key 密钥值,明文
|
||||
* @param data 密文数据
|
||||
*/
|
||||
@Override
|
||||
public byte[] symDecrypt(KeyAlg alg, byte[] key, byte[] data) {
|
||||
return symDecrypt( alg, AlgMode.ECB, Padding.PCKS5Padding, key, data );
|
||||
}
|
||||
|
||||
}
|
@ -1,29 +1,50 @@
|
||||
package com.sunyard.chsm.sdf;
|
||||
|
||||
|
||||
import com.sunyard.chsm.enums.AlgMode;
|
||||
import com.sunyard.chsm.enums.KeyAlg;
|
||||
import com.sunyard.chsm.enums.KeyCategory;
|
||||
import com.sunyard.chsm.enums.Padding;
|
||||
import com.sunyard.chsm.sdf.model.EccKey;
|
||||
import com.sunyard.chsm.sdf.util.LangUtils;
|
||||
import com.sunyard.chsm.utils.gm.BCSM2Utils;
|
||||
import com.sunyard.chsm.utils.gm.BCSM3Utils;
|
||||
import com.sunyard.chsm.utils.gm.BCSM4Utils;
|
||||
import lombok.SneakyThrows;
|
||||
import org.bouncycastle.crypto.digests.SM3Digest;
|
||||
import org.bouncycastle.crypto.macs.HMac;
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
|
||||
import org.bouncycastle.util.BigIntegers;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.SecureRandom;
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import java.security.*;
|
||||
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* 基于 BC 库的国密软算法实现
|
||||
* 当前实现类的接口返回的对称密钥和私钥认为是明文,在上层 Service 进行使用和存储时的加密和解密运算。
|
||||
* <p>
|
||||
* 主密钥:
|
||||
* - 生成。 软随机数。项目启动时不存在则自动生成。
|
||||
* - 存储。 存储在 SC_PARAM_CONF 表, KEY 为 mk 的字段,值为固定的 48 字节,以 HEX 格式 96 字节存储。
|
||||
* 前 16 字节为主密钥值,后 32 字节为主密钥值使用 SM3 计算的校验值。
|
||||
* - 同步。基于数据库进行导入、导出、和备份、恢复。多台应用服务器连接同一个数据库,无需同步。
|
||||
* - 使用。顶层密钥,用于保护其他存于数据的密钥。
|
||||
*
|
||||
* @author liulu 、Cheney
|
||||
* @since 2024/10/23
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class BCSdfApiService implements SdfApiService {
|
||||
public class BCSdfApiService extends AbstractSdfApiService {
|
||||
|
||||
public BCSdfApiService() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generateRandom(int len) {
|
||||
@ -32,6 +53,82 @@ public class BCSdfApiService implements SdfApiService {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成对称算法密钥
|
||||
*
|
||||
* @param alg 算法,只支持对称算法
|
||||
* @param keyLen 密钥长度(bit),只针对密钥长度可变的算法。
|
||||
* 禁止传 null
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public byte[] genSymKey(KeyAlg alg, Integer keyLen) {
|
||||
switch (alg) {
|
||||
case SM4: {
|
||||
if (null == keyLen || keyLen != BCSM4Utils.DEFAULT_KEY_SIZE) {
|
||||
throw new IllegalArgumentException("Invalid key length: " + keyLen);
|
||||
}
|
||||
try {
|
||||
return BCSM4Utils.generateKey();
|
||||
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
|
||||
throw new RuntimeException("算法实现错误", e);
|
||||
}
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException("Unsupported algorithm: " + alg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) {
|
||||
return symCalc(Cipher.ENCRYPT_MODE, alg, mode, padding, key, data);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) {
|
||||
return symCalc(Cipher.DECRYPT_MODE, alg, mode, padding, key, data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 对称加解密的统一实现
|
||||
*
|
||||
* @param alg 算法,只支持对称算法
|
||||
* @param key 密钥值,明文
|
||||
* @param data 加密时明文数据,解密时为密文数据
|
||||
*/
|
||||
private byte[] symCalc(int cipherMode, KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) {
|
||||
if (alg.getCategory() != KeyCategory.SYM_KEY) {
|
||||
throw new IllegalArgumentException("Must SYM_KEY, unsupported algorithm: " + alg);
|
||||
}
|
||||
|
||||
// 算法
|
||||
String algName = null;
|
||||
if (alg == KeyAlg.SM4) {
|
||||
algName = "SM4/";
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported algorithm: " + alg);
|
||||
}
|
||||
|
||||
// 算法轮模式
|
||||
algName += mode.getCode() + "/";
|
||||
|
||||
// 填充模式
|
||||
algName += padding.getCode();
|
||||
|
||||
|
||||
Cipher cipher = null;
|
||||
try {
|
||||
cipher = BCSM4Utils.generateECBCipher(algName, cipherMode, key);
|
||||
return cipher.doFinal(data);
|
||||
} catch (IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException e) {
|
||||
throw new RuntimeException("算法执行错误", e);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public EccKey genKeyPairEcc() {
|
||||
@ -53,14 +150,7 @@ public class BCSdfApiService implements SdfApiService {
|
||||
|
||||
@Override
|
||||
public byte[] hmac(byte[] key, byte[] srcData) {
|
||||
KeyParameter keyParameter = new KeyParameter(key);
|
||||
SM3Digest digest = new SM3Digest();
|
||||
HMac mac = new HMac(digest);
|
||||
mac.init(keyParameter);
|
||||
mac.update(srcData, 0, srcData.length);
|
||||
byte[] result = new byte[mac.getMacSize()];
|
||||
mac.doFinal(result, 0);
|
||||
return result;
|
||||
return BCSM3Utils.hmac(key, srcData);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,8 +1,12 @@
|
||||
package com.sunyard.chsm.sdf;
|
||||
|
||||
|
||||
import com.sunyard.chsm.enums.AlgMode;
|
||||
import com.sunyard.chsm.enums.KeyAlg;
|
||||
import com.sunyard.chsm.enums.Padding;
|
||||
import com.sunyard.chsm.sdf.model.EccKey;
|
||||
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/10/23
|
||||
@ -18,6 +22,44 @@ public interface SdfApiService {
|
||||
*/
|
||||
byte[] generateRandom(int len);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 生成对称密钥
|
||||
* @param alg 算法,只支持对称算法
|
||||
* @param keyLen 密钥长度(bit),只针对密钥长度可变的算法。
|
||||
* 禁止传 null
|
||||
* @return 对称密钥
|
||||
*/
|
||||
byte[] genSymKey(KeyAlg alg, Integer keyLen);
|
||||
byte[] genSymKey(KeyAlg alg);
|
||||
|
||||
|
||||
/**
|
||||
* 对称加密
|
||||
* @param alg 算法,只支持对称算法
|
||||
* @param mode 轮模式
|
||||
* @param padding 填充模式
|
||||
* @param key 密钥值,明文
|
||||
* @param data 原始数据
|
||||
*/
|
||||
byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data);
|
||||
byte[] symEncrypt(KeyAlg alg, byte[] key, byte[] data);
|
||||
|
||||
/**
|
||||
* 对称解密
|
||||
* @param alg 算法,只支持对称算法
|
||||
* @param key 密钥值,明文
|
||||
* @param mode 轮模式
|
||||
* @param padding 填充模式
|
||||
* @param data 密文数据
|
||||
*/
|
||||
byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data);
|
||||
byte[] symDecrypt(KeyAlg alg, byte[] key, byte[] data);
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 产生ECC密钥对并输出
|
||||
*
|
||||
|
@ -170,7 +170,7 @@ public class BCSM4Utils extends GMBaseUtil {
|
||||
return mac.doFinal();
|
||||
}
|
||||
|
||||
private static Cipher generateECBCipher(String algorithmName, int mode, byte[] key)
|
||||
public static Cipher generateECBCipher(String algorithmName, int mode, byte[] key)
|
||||
throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
|
||||
InvalidKeyException {
|
||||
Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
|
||||
@ -179,7 +179,7 @@ public class BCSM4Utils extends GMBaseUtil {
|
||||
return cipher;
|
||||
}
|
||||
|
||||
private static Cipher generateCBCCipher(String algorithmName, int mode, byte[] key, byte[] iv)
|
||||
public static Cipher generateCBCCipher(String algorithmName, int mode, byte[] key, byte[] iv)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
|
||||
NoSuchProviderException, NoSuchPaddingException {
|
||||
Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
|
||||
|
@ -19,6 +19,21 @@
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- JUnit 5 API (仅单元测试使用)-->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.8.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Spring Boot Test (仅单元测试使用) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sunyard.chsm</groupId>
|
||||
<artifactId>chsm-common</artifactId>
|
||||
|
34
chsm-web-server/src/test/java/sdf/BCSdfApiServiceTest.java
Normal file
34
chsm-web-server/src/test/java/sdf/BCSdfApiServiceTest.java
Normal file
@ -0,0 +1,34 @@
|
||||
package sdf;
|
||||
import com.sunyard.chsm.WebServerApp;
|
||||
import com.sunyard.chsm.enums.KeyAlg;
|
||||
import com.sunyard.chsm.sdf.BCSdfApiService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.Assert;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@SpringBootTest(classes = WebServerApp.class)
|
||||
public class BCSdfApiServiceTest {
|
||||
|
||||
@Autowired
|
||||
private BCSdfApiService bcSdfApiService;
|
||||
|
||||
// 对称加密解密测试
|
||||
@Test
|
||||
void testSym() {
|
||||
byte[] data = new byte[128];
|
||||
new Random().nextBytes( data );
|
||||
|
||||
byte[] key = bcSdfApiService.genSymKey( KeyAlg.SM4 );
|
||||
byte[] enData = bcSdfApiService.symEncrypt( KeyAlg.SM4, key, data );
|
||||
byte[] deData = bcSdfApiService.symDecrypt( KeyAlg.SM4, key, enData );
|
||||
|
||||
Assert.assertArrayEquals( data, deData );
|
||||
|
||||
}
|
||||
}
|
62
chsm-web-server/src/test/resources/application.yml
Normal file
62
chsm-web-server/src/test/resources/application.yml
Normal file
@ -0,0 +1,62 @@
|
||||
server:
|
||||
port: 89
|
||||
tomcat:
|
||||
uri-encoding: UTF-8
|
||||
threads:
|
||||
max: 1000
|
||||
min-spare: 30
|
||||
|
||||
spring:
|
||||
main:
|
||||
allow-circular-references: true
|
||||
# 数据源
|
||||
datasource:
|
||||
driverClassName: dm.jdbc.driver.DmDriver
|
||||
url: jdbc:dm://172.16.17.236:5236?schema=SSP&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&useSSL=true&characterEncoding=UTF-8
|
||||
username: SUNYARD
|
||||
# Jasypt加密 可到common-utils中找到JasyptUtil加解密工具类生成加密结果 格式为ENC(加密结果)
|
||||
password: 123456
|
||||
hikari:
|
||||
minimum-idle: 5
|
||||
maximum-pool-size: 100
|
||||
idle-timeout: 600000 # 空闲连接的最大等待时间,单位为毫秒 (10 分钟)
|
||||
max-lifetime: 1800000 # 连接池中连接的最大存活时间,单位为毫秒 (30 分钟)
|
||||
connection-timeout: 30000 # 获取连接的超时时间,单位为毫秒 (30 秒)
|
||||
leak-detection-threshold: 2000 # 连接泄漏检测阈值,单位为毫秒 (2 秒)
|
||||
# 连接测试配置,确保连接有效性
|
||||
connection-test-query: SELECT 1
|
||||
validation-timeout: 5000 # 验证连接的超时时间,单位为毫秒 (5 秒)
|
||||
jackson:
|
||||
time-zone: GMT+8
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
|
||||
mybatis-plus:
|
||||
mapper-locations: classpath*:mapper/**/*Mapper.xml
|
||||
# 原生配置
|
||||
configuration:
|
||||
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||
map-underscore-to-camel-case: true
|
||||
cache-enabled: false
|
||||
lazy-loading-enabled: false
|
||||
global-config:
|
||||
# 数据库相关配置
|
||||
db-config:
|
||||
#主键类型 AUTO:"数据库ID自增", INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
|
||||
id-type: AUTO
|
||||
#驼峰下划线转换
|
||||
table-underline: true
|
||||
#是否开启大写命名,默认不开启
|
||||
capital-mode: true
|
||||
#逻辑删除配置
|
||||
#logic-delete-value: 1
|
||||
#logic-not-delete-value: 0
|
||||
|
||||
logging:
|
||||
level:
|
||||
root: info
|
||||
com.sunyard.chsm.mapper: debug
|
||||
# org.springframework.web: trace
|
||||
# config: classpath:log4j2.xml
|
||||
|
||||
|
||||
|
91
chsm-web-server/src/test/resources/logback.xml
Normal file
91
chsm-web-server/src/test/resources/logback.xml
Normal file
@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<!--<include resource="org/springframework/boot/logging/logback/base.xml"/>-->
|
||||
<!-- 定义log文件的目录 -->
|
||||
<property name="LOG_HOME" value="logs"/>
|
||||
<!-- 加载 Spring 配置文件信息 -->
|
||||
<springProperty scope="context" name="applicationName" source="spring.application.name" defaultValue="localhost"/>
|
||||
<!-- 日志输出格式 -->
|
||||
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %X{tl} [%thread] %-5level [%logger{0}:%L]- %msg%n%ex{15}"/>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<!--日志文件输出格式-->
|
||||
<encoder>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset> <!-- 设置字符集 -->
|
||||
</encoder>
|
||||
</appender>
|
||||
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/info.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/%d{yyyy-MM}/INFO-%d{yyyy-MM-dd}_%i.log</fileNamePattern>
|
||||
<!--单个文件-->
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
<!--文件保存时间(天)-->
|
||||
<maxHistory>30</maxHistory>
|
||||
<!--总文件日志最大的大小-->
|
||||
<totalSizeCap>20GB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<!--日志文件输出格式-->
|
||||
<encoder>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset> <!-- 设置字符集 -->
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/debug.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/%d{yyyy-MM}/sspweb-DEBUG-%d{yyyy-MM-dd}_%i.log</fileNamePattern>
|
||||
<!--单个文件-->
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
<!--文件保存时间(天)-->
|
||||
<maxHistory>30</maxHistory>
|
||||
<!--总文件日志最大的大小-->
|
||||
<totalSizeCap>20GB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<!--日志文件输出格式-->
|
||||
<encoder>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset> <!-- 设置字符集 -->
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>DEBUG</level>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/error.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/%d{yyyy-MM}/ERROR-%d{yyyy-MM-dd}_%i.log</fileNamePattern>
|
||||
<!--单个文件-->
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
<!--文件保存时间(天)-->
|
||||
<maxHistory>30</maxHistory>
|
||||
<!--总文件日志最大的大小-->
|
||||
<totalSizeCap>20GB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<!--日志文件输出格式-->
|
||||
<encoder>
|
||||
<pattern>${LOG_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset> <!-- 设置字符集 -->
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>ERROR</level>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="INFO_FILE"/>
|
||||
<appender-ref ref="DEBUG_FILE"/>
|
||||
<appender-ref ref="ERROR_FILE"/>
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user