完善 Access Log 的记录
This commit is contained in:
@@ -1,58 +0,0 @@
|
||||
package cn.iocoder.mall.spring.boot.swagger;
|
||||
|
||||
import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||
|
||||
/**
|
||||
* 简单的 Swagger2 自动配置类
|
||||
*
|
||||
* 较为完善的,可以了解 https://mvnrepository.com/artifact/com.spring4all/spring-boot-starter-swagger
|
||||
*/
|
||||
@Configuration
|
||||
@EnableSwagger2
|
||||
@EnableSwaggerBootstrapUI
|
||||
@ConditionalOnClass({Docket.class, ApiInfoBuilder.class})
|
||||
@ConditionalOnProperty(prefix = "swagger", value = "enable", matchIfMissing = true) // 允许使用 swagger.enable=false 禁用 Swagger
|
||||
@EnableConfigurationProperties(SwaggerProperties.class)
|
||||
@Deprecated
|
||||
public class SwaggerAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SwaggerProperties swaggerProperties() {
|
||||
return new SwaggerProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Docket createRestApi() {
|
||||
SwaggerProperties properties = swaggerProperties();
|
||||
// 创建 Docket 对象
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.apiInfo(apiInfo(properties))
|
||||
.select()
|
||||
.apis(RequestHandlerSelectors.basePackage(properties.getBasePackage()))
|
||||
.paths(PathSelectors.any())
|
||||
.build();
|
||||
}
|
||||
|
||||
private ApiInfo apiInfo(SwaggerProperties properties) {
|
||||
return new ApiInfoBuilder()
|
||||
.title(properties.getTitle())
|
||||
.description(properties.getDescription())
|
||||
.version(properties.getVersion())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package cn.iocoder.mall.spring.boot.swagger;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties("swagger")
|
||||
@Deprecated
|
||||
public class SwaggerProperties {
|
||||
|
||||
private String title;
|
||||
private String description;
|
||||
private String version;
|
||||
private String basePackage;
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package cn.iocoder.mall.spring.boot.web.handler;
|
||||
|
||||
import cn.iocoder.common.framework.util.MallUtil;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
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.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
|
||||
@ControllerAdvice
|
||||
public class GlobalResponseBodyHandler implements ResponseBodyAdvice {
|
||||
|
||||
@Override
|
||||
public boolean supports(MethodParameter returnType, Class converterType) {
|
||||
if (returnType.getMethod() == null) {
|
||||
return false;
|
||||
}
|
||||
return returnType.getMethod().getReturnType() == CommonResult.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType,
|
||||
ServerHttpRequest request, ServerHttpResponse response) {
|
||||
MallUtil.setCommonResult(((ServletServerHttpRequest) request).getServletRequest(), (CommonResult) body);
|
||||
return body;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package cn.iocoder.mall.spring.boot.web.interceptor;
|
||||
|
||||
import cn.iocoder.common.framework.util.HttpUtil;
|
||||
import cn.iocoder.common.framework.util.MallUtil;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.system.api.SystemLogService;
|
||||
import cn.iocoder.mall.system.api.dto.systemlog.AccessLogAddDTO;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 访问日志拦截器
|
||||
*/
|
||||
@Component
|
||||
public class AccessLogInterceptor extends HandlerInterceptorAdapter {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private static final ThreadLocal<Date> START_TIME = new ThreadLocal<>();
|
||||
|
||||
@Reference(validation = "true", version = "${dubbo.consumer.AdminAccessLogService.version:1.0.0}")
|
||||
private SystemLogService systemAccessLogService;
|
||||
|
||||
@Value("${spring.application.name}")
|
||||
private String applicationName;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
// 记录当前时间
|
||||
START_TIME.set(new Date());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||
AccessLogAddDTO accessLog = new AccessLogAddDTO();
|
||||
try {
|
||||
// 初始化 accessLog
|
||||
initAccessLog(accessLog, request);
|
||||
// 执行插入 accessLog
|
||||
addAccessLog(accessLog);
|
||||
// TODO 提升:暂时不考虑 ELK 的方案。而是基于 MySQL 存储。如果访问日志比较多,需要定期归档。
|
||||
} catch (Throwable th) {
|
||||
logger.error("[afterCompletion][插入访问日志({}) 发生异常({})", JSON.toJSONString(accessLog), ExceptionUtils.getRootCauseMessage(th));
|
||||
} finally {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void initAccessLog(AccessLogAddDTO accessLog, HttpServletRequest request) {
|
||||
// 设置用户编号
|
||||
accessLog.setUserId(MallUtil.getUserId(request));
|
||||
if (accessLog.getUserId() == null) {
|
||||
accessLog.setUserId(AccessLogAddDTO.USER_ID_NULL);
|
||||
}
|
||||
accessLog.setUserType(MallUtil.getUserType(request));
|
||||
// 设置访问结果
|
||||
CommonResult result = MallUtil.getCommonResult(request);
|
||||
Assert.isTrue(result != null, "result 必须非空");
|
||||
accessLog.setErrorCode(result.getCode())
|
||||
.setErrorMessage(result.getMessage());
|
||||
// 设置其它字段
|
||||
accessLog.setTraceId(MallUtil.getTraceId())
|
||||
.setApplicationName(applicationName)
|
||||
.setUri(request.getRequestURI()) // TODO 提升:如果想要优化,可以使用 Swagger 的 @ApiOperation 注解。
|
||||
.setQueryString(HttpUtil.buildQueryString(request))
|
||||
.setMethod(request.getMethod())
|
||||
.setUserAgent(HttpUtil.getUserAgent(request))
|
||||
.setIp(HttpUtil.getIp(request))
|
||||
.setStartTime(START_TIME.get())
|
||||
.setResponseTime((int) (System.currentTimeMillis() - accessLog.getStartTime().getTime())); // 默认响应时间设为 0
|
||||
}
|
||||
|
||||
@Async // 异步入库
|
||||
public void addAccessLog(AccessLogAddDTO accessLog) {
|
||||
try {
|
||||
systemAccessLogService.addAccessLog(accessLog);
|
||||
} catch (Throwable th) {
|
||||
logger.error("[addAccessLog][插入访问日志({}) 发生异常({})", JSON.toJSONString(accessLog), ExceptionUtils.getRootCauseMessage(th));
|
||||
}
|
||||
}
|
||||
|
||||
private static void clear() {
|
||||
START_TIME.remove();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.iocoder.mall.spring.boot.web.AdminMVCAutoConfiguration, \
|
||||
cn.iocoder.mall.spring.boot.web.UserMVCAutoConfiguration, \
|
||||
cn.iocoder.mall.spring.boot.swagger.SwaggerAutoConfiguration, \
|
||||
cn.iocoder.mall.spring.boot.metrics.MetricsAutoConfiguration
|
||||
|
||||
Reference in New Issue
Block a user