Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -58,6 +58,12 @@
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--aop-->
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot 3.x 适配:Jakarta EE Servlet API(仅编译期依赖) -->
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.sdm.common.feign.impl.system;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.sdm.common.common.SdmResponse;
|
||||
import com.sdm.common.feign.inter.system.ISysLogFeignClient;
|
||||
import com.sdm.common.log.dto.SysLogDTO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SysLogFeignClientImpl implements ISysLogFeignClient {
|
||||
|
||||
@Autowired
|
||||
private ISysLogFeignClient sysLogFeignClient;
|
||||
|
||||
@Override
|
||||
public SdmResponse saveLog(SysLogDTO req) {
|
||||
SdmResponse response=null ;
|
||||
try {
|
||||
response = sysLogFeignClient.saveLog(req);
|
||||
if(response==null || !response.isSuccess()){
|
||||
log.error("saveLog failed response:{}", JSONObject.toJSONString(Optional.ofNullable(response)));
|
||||
return SdmResponse.failed("记录日志失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("saveLog error response:{}", JSONObject.toJSONString(Optional.ofNullable(response)));
|
||||
return SdmResponse.failed("记录日志异常");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.sdm.common.feign.inter.system;
|
||||
|
||||
import com.sdm.common.common.SdmResponse;
|
||||
import com.sdm.common.log.dto.SysLogDTO;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
|
||||
@FeignClient(name = "system",contextId = "systemLogClient")
|
||||
public interface ISysLogFeignClient {
|
||||
|
||||
@PostMapping("/systemLog/saveLog")
|
||||
SdmResponse saveLog(@RequestBody SysLogDTO req);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2018-2025, honeycom All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the pig4cloud.com developer nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* Author: honeycom
|
||||
*
|
||||
*/
|
||||
|
||||
package com.sdm.common.log.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 操作日志注解
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface SysLog {
|
||||
|
||||
/**
|
||||
* 描述
|
||||
* @return {String}
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* spel 表达式
|
||||
* @return 日志描述
|
||||
*/
|
||||
String expression() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sdm.common.log.aspect;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.sdm.common.common.ThreadLocalContext;
|
||||
import com.sdm.common.log.annotation.SysLog;
|
||||
import com.sdm.common.log.dto.SysLogDTO;
|
||||
import com.sdm.common.log.event.SpringContextHolder;
|
||||
import com.sdm.common.log.event.SysLogEvent;
|
||||
import com.sdm.common.log.utils.LogTypeEnum;
|
||||
import com.sdm.common.log.utils.SysLogUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 操作日志使用spring event异步入库
|
||||
*/
|
||||
@Aspect
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SysLogAspect {
|
||||
|
||||
@Around("@annotation(sysLog)")
|
||||
@SneakyThrows
|
||||
public Object around(ProceedingJoinPoint point, SysLog sysLog) {
|
||||
String strClassName = point.getTarget().getClass().getName();
|
||||
String strMethodName = point.getSignature().getName();
|
||||
log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);
|
||||
|
||||
String value = sysLog.value();
|
||||
|
||||
SysLogDTO logVo = SysLogUtils.getSysLog();
|
||||
logVo.setTitle(value);
|
||||
// 获取请求body参数
|
||||
if (StrUtil.isBlank(logVo.getParams())) {
|
||||
logVo.setBody(point.getArgs());
|
||||
}
|
||||
// 发送异步日志事件
|
||||
Long startTime = System.currentTimeMillis();
|
||||
Object obj;
|
||||
|
||||
try {
|
||||
obj = point.proceed();
|
||||
}
|
||||
catch (Exception e) {
|
||||
logVo.setLogType(LogTypeEnum.ERROR.getType());
|
||||
logVo.setException(e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
Long endTime = System.currentTimeMillis();
|
||||
logVo.setTime(endTime - startTime);
|
||||
logVo.setTenantId(ThreadLocalContext.getTenantId());
|
||||
SpringContextHolder.publishEvent(new SysLogEvent(logVo));
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sdm.common.log.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 日志配置类
|
||||
*
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "sys.log")
|
||||
public class SysLogProperties {
|
||||
|
||||
/**
|
||||
* 开启日志记录
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* 记录请求报文体
|
||||
*/
|
||||
private boolean requestEnabled = true;
|
||||
|
||||
/**
|
||||
* 放行字段,password,mobile,idcard,phone
|
||||
*/
|
||||
@Value("${log.exclude-fields:password,mobile,idcard,phone}")
|
||||
private List<String> excludeFields;
|
||||
|
||||
/**
|
||||
* 请求报文最大存储长度
|
||||
*/
|
||||
private Integer maxLength = 2000;
|
||||
|
||||
}
|
||||
98
common/src/main/java/com/sdm/common/log/dto/SysLogDTO.java
Normal file
98
common/src/main/java/com/sdm/common/log/dto/SysLogDTO.java
Normal file
@@ -0,0 +1,98 @@
|
||||
package com.sdm.common.log.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 日志查询传输对象
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "日志查询对象")
|
||||
public class SysLogDTO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 日志类型
|
||||
*/
|
||||
@NotBlank(message = "日志类型不能为空")
|
||||
private String logType;
|
||||
|
||||
/**
|
||||
* 日志标题
|
||||
*/
|
||||
@NotBlank(message = "日志标题不能为空")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 操作IP地址
|
||||
*/
|
||||
private String remoteAddr;
|
||||
|
||||
/**
|
||||
* 用户代理
|
||||
*/
|
||||
private String userAgent;
|
||||
|
||||
/**
|
||||
* 请求URI
|
||||
*/
|
||||
private String requestUri;
|
||||
|
||||
/**
|
||||
* 操作方式
|
||||
*/
|
||||
private String method;
|
||||
|
||||
/**
|
||||
* 操作提交的数据
|
||||
*/
|
||||
private String params;
|
||||
|
||||
/**
|
||||
* 参数重写成object
|
||||
*/
|
||||
private Object body;
|
||||
|
||||
/**
|
||||
* 执行时间
|
||||
*/
|
||||
private Long time;
|
||||
|
||||
/**
|
||||
* 异常信息
|
||||
*/
|
||||
private String exception;
|
||||
|
||||
/**
|
||||
* 服务ID
|
||||
*/
|
||||
private String serviceId;
|
||||
|
||||
/**
|
||||
* 创建时间区间 [开始时间,结束时间]
|
||||
*/
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2018-2025, honeycom All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the pig4cloud.com developer nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
* Author: honeycom
|
||||
*
|
||||
*/
|
||||
|
||||
package com.sdm.common.log.event;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author honeycom
|
||||
* Spring 工具类
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@Lazy(false)
|
||||
public class SpringContextHolder implements BeanFactoryPostProcessor, ApplicationContextAware, DisposableBean {
|
||||
|
||||
private static ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
private static ApplicationContext applicationContext = null;
|
||||
|
||||
/**
|
||||
* 取得存储在静态变量中的ApplicationContext.
|
||||
*/
|
||||
public static ApplicationContext getApplicationContext() {
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* BeanFactoryPostProcessor, 注入Context到静态变量中.
|
||||
*/
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
|
||||
SpringContextHolder.beanFactory = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
SpringContextHolder.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public static ListableBeanFactory getBeanFactory() {
|
||||
return null == beanFactory ? applicationContext : beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getBean(String name) {
|
||||
return (T) getBeanFactory().getBean(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从静态变量applicationContext中取得Bean, Map<Bean名称,实现类></>
|
||||
*/
|
||||
public static <T> Map<String, T> getBeansOfType(Class<T> type) {
|
||||
return getBeanFactory().getBeansOfType(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
public static <T> T getBean(Class<T> requiredType) {
|
||||
return getBeanFactory().getBean(requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除SpringContextHolder中的ApplicationContext为Null.
|
||||
*/
|
||||
public static void clearHolder() {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
|
||||
}
|
||||
applicationContext = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布事件
|
||||
* @param event
|
||||
*/
|
||||
public static void publishEvent(ApplicationEvent event) {
|
||||
if (applicationContext == null) {
|
||||
return;
|
||||
}
|
||||
applicationContext.publishEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现DisposableBean接口, 在Context关闭时清理静态变量.
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
SpringContextHolder.clearHolder();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sdm.common.log.event;
|
||||
|
||||
import com.sdm.common.log.dto.SysLogDTO;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* @author honeycom 系统日志事件
|
||||
*/
|
||||
public class SysLogEvent extends ApplicationEvent {
|
||||
|
||||
public SysLogEvent(SysLogDTO source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sdm.common.log.event;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonFilter;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ser.FilterProvider;
|
||||
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
|
||||
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
|
||||
import com.sdm.common.feign.inter.system.ISysLogFeignClient;
|
||||
import com.sdm.common.log.config.SysLogProperties;
|
||||
import com.sdm.common.log.dto.SysLogDTO;
|
||||
import com.sdm.common.log.utils.JavaTimeModule;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author honeycom 异步监听日志事件
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class SysLogListener implements InitializingBean {
|
||||
|
||||
/**
|
||||
* 忽略序列化的对象类型
|
||||
*/
|
||||
private final static Class[] ignoreClass = { ServletRequest.class, BindingResult.class };
|
||||
|
||||
/**
|
||||
* new 一个 避免日志脱敏策略影响全局ObjectMapper
|
||||
*/
|
||||
private final static ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private final ISysLogFeignClient sysLogFeignClient;
|
||||
|
||||
private final SysLogProperties logProperties;
|
||||
|
||||
@SneakyThrows
|
||||
@Async
|
||||
@Order
|
||||
@EventListener(SysLogEvent.class)
|
||||
public void saveSysLog(SysLogEvent event) {
|
||||
SysLogDTO source = (SysLogDTO) event.getSource();
|
||||
|
||||
// json 格式刷参数放在异步中处理,提升性能
|
||||
if (Objects.nonNull(source.getBody()) && logProperties.isRequestEnabled()) {
|
||||
Object[] args = (Object[]) source.getBody();
|
||||
List<Object> list = CollUtil.toList(args);
|
||||
// 删除部分无法序列化的参数
|
||||
list.removeIf(obj -> Arrays.stream(ignoreClass).anyMatch(clazz -> clazz.isAssignableFrom(obj.getClass())));
|
||||
|
||||
try {
|
||||
// 序列化参数
|
||||
String params = objectMapper.writeValueAsString(list);
|
||||
source.setParams(StrUtil.subPre(params, logProperties.getMaxLength()));
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("请求参数序列化异常:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
source.setBody(null);
|
||||
sysLogFeignClient.saveLog(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
objectMapper.addMixIn(Object.class, PropertyFilterMixIn.class);
|
||||
String[] ignorableFieldNames = logProperties.getExcludeFields().toArray(new String[0]);
|
||||
|
||||
FilterProvider filters = new SimpleFilterProvider().addFilter("filter properties by name",
|
||||
SimpleBeanPropertyFilter.serializeAllExcept(ignorableFieldNames));
|
||||
objectMapper.setFilterProvider(filters);
|
||||
objectMapper.registerModule(new JavaTimeModule());
|
||||
}
|
||||
|
||||
@JsonFilter("filter properties by name")
|
||||
class PropertyFilterMixIn {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.sdm.common.log.utils;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.PackageVersion;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.InstantSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* java 8 时间默认序列化
|
||||
*/
|
||||
public class JavaTimeModule extends SimpleModule {
|
||||
|
||||
/**
|
||||
* 指定序列化规则
|
||||
*/
|
||||
public JavaTimeModule() {
|
||||
super(PackageVersion.VERSION);
|
||||
|
||||
// ======================= 时间序列化规则 ===============================
|
||||
// yyyy-MM-dd HH:mm:ss
|
||||
this.addSerializer(LocalDateTime.class,
|
||||
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
|
||||
// yyyy-MM-dd
|
||||
this.addSerializer(LocalDate.class,
|
||||
new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
|
||||
// HH:mm:ss
|
||||
this.addSerializer(LocalTime.class,
|
||||
new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
|
||||
|
||||
// Instant 类型序列化
|
||||
this.addSerializer(Instant.class, InstantSerializer.INSTANCE);
|
||||
|
||||
// ======================= 时间反序列化规则 ==============================
|
||||
// yyyy-MM-dd HH:mm:ss
|
||||
this.addDeserializer(LocalDateTime.class,
|
||||
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
|
||||
// yyyy-MM-dd
|
||||
this.addDeserializer(LocalDate.class,
|
||||
new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
|
||||
// HH:mm:ss
|
||||
this.addDeserializer(LocalTime.class,
|
||||
new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
|
||||
// Instant 反序列化
|
||||
this.addDeserializer(Instant.class, InstantDeserializer.INSTANT);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.sdm.common.log.utils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 日志类型
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum LogTypeEnum {
|
||||
|
||||
/**
|
||||
* 正常日志类型
|
||||
*/
|
||||
NORMAL("0", "正常日志"),
|
||||
|
||||
/**
|
||||
* 错误日志类型
|
||||
*/
|
||||
ERROR("9", "错误日志");
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final String type;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.sdm.common.log.utils;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.extra.servlet.JakartaServletUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.sdm.common.common.ThreadLocalContext;
|
||||
import com.sdm.common.log.config.SysLogProperties;
|
||||
import com.sdm.common.log.dto.SysLogDTO;
|
||||
import com.sdm.common.utils.DateUtils;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 系统日志工具类
|
||||
*
|
||||
* @author L.cm
|
||||
*/
|
||||
@UtilityClass
|
||||
public class SysLogUtils {
|
||||
|
||||
public SysLogDTO getSysLog() {
|
||||
HttpServletRequest request = ((ServletRequestAttributes) Objects
|
||||
.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
|
||||
SysLogDTO sysLog = new SysLogDTO();
|
||||
sysLog.setLogType(LogTypeEnum.NORMAL.getType());
|
||||
sysLog.setRequestUri(URLUtil.getPath(request.getRequestURI()));
|
||||
sysLog.setMethod(request.getMethod());
|
||||
sysLog.setRemoteAddr(JakartaServletUtil.getClientIP(request));
|
||||
sysLog.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
|
||||
sysLog.setCreateBy(ObjectUtils.isNotEmpty(ThreadLocalContext.getUserName()) ? ThreadLocalContext.getUserName() : "anonymousUser");
|
||||
// 获取服务名称
|
||||
sysLog.setServiceId("simulation-" + SpringUtil.getProperty("spring.application.name"));
|
||||
|
||||
// get 参数脱敏
|
||||
SysLogProperties logProperties = SpringUtil.getBean(SysLogProperties.class);
|
||||
Map<String, String[]> paramsMap = MapUtil.removeAny(request.getParameterMap(), ArrayUtil.toArray(logProperties.getExcludeFields(), String.class));
|
||||
sysLog.setParams(HttpUtil.toParams(paramsMap));
|
||||
return sysLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取spel 定义的参数值
|
||||
* @param context 参数容器
|
||||
* @param key key
|
||||
* @param clazz 需要返回的类型
|
||||
* @param <T> 返回泛型
|
||||
* @return 参数值
|
||||
*/
|
||||
public <T> T getValue(EvaluationContext context, String key, Class<T> clazz) {
|
||||
SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
|
||||
Expression expression = spelExpressionParser.parseExpression(key);
|
||||
return expression.getValue(context, clazz);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user