需求:在项目中需要针对接口去实现定制化日志,有的接口要记录日志,有的不需要,所以要实现一个注解的定制化日志,直接作用到接口上。
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* BaseInterceptorAdapter.
*
* @author cf
* @version 1.0
*/
@Component
public abstract class AbstractHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
return preHandles(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
postHandles(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
afterCompletions(request, response, handler, ex);
}
public abstract boolean preHandles(HttpServletRequest request, HttpServletResponse response, Object handler) ;
protected abstract void postHandles(HttpServletRequest r, HttpServletResponse re, Object ha, ModelAndView mo) ;
protected abstract void afterCompletions(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) ;
}
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Map;
/**
* @author cf
* @date 2021/10/2216:13
*/
@Configuration
public class InterceptorAdapterConfig implements WebMvcConfigurer, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void addInterceptors(InterceptorRegistry interceptorRegistry) {
final Map<String, AbstractHandlerInterceptor> beansOfType = applicationContext.getBeansOfType(AbstractHandlerInterceptor.class);
if (!beansOfType.isEmpty()) {
beansOfType.forEach((k,v) -> interceptorRegistry.addInterceptor(v));
}
}
@Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
注意有些实体和入库操作需要自己实现,直接粘贴会报错。
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.concurrent.CompletableFuture;
/**
* 系统中的拦截器配置
*/
@Component
@Slf4j
public class LogInterceptorConfigurer extends AbstractHandlerInterceptor {
public static final String GET_METHOD = "get";
public static final String POST_METHOD = "post";
public static final String TRUE_STR = "true";
public static final String FALSE_STR = "false";
@Autowired
private LogServiceClient logServiceClient;
@Override
public boolean preHandles(HttpServletRequest request, HttpServletResponse response, Object handler) {
return true;
}
@Override
public void postHandles(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
ModelAndView modelAndView) {
// Do nothing because of X and Y.
}
@Override
public void afterCompletions(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
Object handler, Exception e) {
try {
if (!(handler instanceof HandlerMethod)) {
return;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
ApiLog logAnnotation = handlerMethod.getMethodAnnotation(ApiLog.class);
if (logAnnotation == null) {
return;
}
SystemLog systemLog = fillLogEntity(e, handlerMethod, logAnnotation, httpServletResponse);
//收集方法参数
fillParam(httpServletRequest, logAnnotation, systemLog);
//参数整合完成,日志落库
CompletableFuture.runAsync(() -> {
logServiceClient.saveLog(systemLog);
});
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
}
/**
* ThreadLocalUserConfigurer.getUserId()
*
* @param e
* @param handlerMethod
* @param logAnnotation
* @return
*/
private SystemLog fillLogEntity(Exception e, HandlerMethod handlerMethod, ApiLog logAnnotation, HttpServletResponse httpServletResponse) {
final String responseBody = getResponseBody(httpServletResponse);
SystemLog systemLog = new SystemLog();
systemLog.setId(IdUtil.objectId());
systemLog.setCreateTime(Timestamp.from(Instant.now()));
systemLog.setSystem(logAnnotation.system());
systemLog.setModule(logAnnotation.module());
systemLog.setName(logAnnotation.name());
systemLog.setMethod(handlerMethod.getMethod().getName());
systemLog.setType(logAnnotation.type().getValue());
systemLog.setOpera(logAnnotation.opera());
UserInfo user = UserInfoContext.getUser();
if (user != null) {
systemLog.setUserId(user.getId());
systemLog.setUserName(user.getUserName());
systemLog.setRoleName(logServiceClient.getUserRole(user.getId()));
log.info("-----------------fillLogEntity------------------------" + JSON.toJSONString(systemLog));
} else {
systemLog.setUserId(" ");
systemLog.setUserName(" ");
systemLog.setRoleName(" ");
}
//处理接口请求结果
try {
//响应结果转json
JSONObject jsonObject = JSON.parseObject(responseBody);
if (jsonObject.get("success") == null) {
int status = httpServletResponse.getStatus();
if (status >= 200 && status < 300) {
systemLog.setFlag(TRUE_STR);
systemLog.setRemark("成功");
} else {
systemLog.setFlag(FALSE_STR);
systemLog.setRemark("失败");
}
} else {
final boolean status = jsonObject.getBoolean("success");
if (ObjectUtil.isEmpty(responseBody)) {
systemLog.setFlag(TRUE_STR);
systemLog.setRemark("成功");
} else {
systemLog.setFlag(status ? TRUE_STR : FALSE_STR);
systemLog.setRemark(status ? "成功" : "失败");
}
}
if (e != null) {
systemLog.setFlag(FALSE_STR);
systemLog.setRemark(e.getMessage());
}
} catch (Exception exception) {
if (isJSON2(responseBody)) {
log.error(exception.getMessage(), exception);
systemLog.setFlag(FALSE_STR);
systemLog.setRemark("失败");
}else{
int status = httpServletResponse.getStatus();
if (status >= 200 && status < 300) {
systemLog.setFlag(TRUE_STR);
systemLog.setRemark("成功");
} else {
systemLog.setFlag(FALSE_STR);
systemLog.setRemark("失败");
}
}
}
return systemLog;
}
private void fillParam(HttpServletRequest httpServletRequest, ApiLog logAnnotation, SystemLog systemLog) {
//是否需要记录参数
if (logAnnotation.params()) {
if (httpServletRequest.getMethod().equalsIgnoreCase(GET_METHOD)) {
//如果是GET请求,直接取参数map
String body = JSON.toJSONString(httpServletRequest.getParameterMap());
systemLog.setParams(body);
log.info("请求体:{}", body);
}
if (httpServletRequest.getMethod().equalsIgnoreCase(POST_METHOD)) {
String body = null;
try {
byte[] bodyBytes = ((ContentCachingRequestWrapper) httpServletRequest).getContentAsByteArray();
body = new String(bodyBytes, httpServletRequest.getCharacterEncoding());
} catch (UnsupportedEncodingException e) {
log.error("com.qax.tsgz.toolbox.system.api.adapter.LogInterceptorConfigurer.fillParam ERROR:{}", e);
body = "";
}
systemLog.setParams(body);
log.info("请求体=======================:{}", body);
}
}
}
private String getResponseBody(HttpServletResponse servletResponseWrapper) {
if (servletResponseWrapper instanceof ContentCachingResponseWrapper) {
ContentCachingResponseWrapper responseWrapper = (ContentCachingResponseWrapper) servletResponseWrapper;
String responseBody = "";
responseBody = new String(responseWrapper.getContentAsByteArray());
return responseBody;
} else {
return "";
}
}
private String getRequest(HttpServletRequest httpServletRequest) throws UnsupportedEncodingException {
if (httpServletRequest instanceof ContentCachingRequestWrapper) {
ContentCachingRequestWrapper requestWrapper = (ContentCachingRequestWrapper) httpServletRequest;
return "new String(requestWrapper.getBody(), httpServletRequest.getCharacterEncoding())";
} else {
return "";
}
}
public static boolean isJSON2(String str) {
boolean result = false;
try {
JSON.parse(str);
result = true;
} catch (Exception e) {
result = false;
}
return result;
}
import
import java.lang.annotation.*;
/**
* ApiLog.
*
* @author cf
* @version 1.0
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiLog {
//项目名字
String system() default "";
//模块名字
String module() default "";
//接口名字
String name() default "";
//接口动作
String opera() default "";
//操作日志类型
SysLogType type() default SysLogType.OPER;
//请求参数
boolean params() default false;
}
/**
* 基础常量接口操作标识
*/
public class OperaConstant {
private OperaConstant(){}
public static final String ADD = "新增";
public static final String DELETE = "删除";
public static final String UPDATE = "修改";
public static final String QUERY = "查询";
public static final String LOGIN = "登录";
public static final String IMPORT = "导入";
public static final String EXPORT = "导出";
public static final String OTHER = "其他";
public static final String UPLOAD = "上传文件";
public static final String DOWNLOAD = "下载文件";
}
/**
* 操作日志类型
*/
public enum SysLogType {
LOGIN("1"),
AECCESS("2"),
OPER("3"),
EXCEPTION("4");
public String value;
private SysLogType(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
}
/**
* 根据字典类型查询字典
*
* @param dictType
* @return
*/
@ResponseBody
@ResponseResult(exclude = {"children","isDefault"})
@GetMapping(value = "/*****")
@ApiLog(system = "*****", userId = "",module = "系统管理", name = "根据字典类型查询字典", opera = OperaConstant.QUERY, type = SysLogType.OPER, params = true)
public ApiResult getDictByType(@RequestParam String dictType) {
return ApiResult.success(dictDataService.getDictByType(dictType));
}
/**
* 保存配置
*/
@PostMapping(value = "/*****")
@ApiLog(system = "*****", module = "通用配置", name = "保存配置", opera = OperaConstant.UPDATE, type = SysLogType.OPER, params = true)
public ApiResult saveConfig(@Validated @RequestBody SystemConfigReq systemConfigReq) {
systemConfigService.saveConfig(systemConfigReq);
return ApiResult.success(new Object());
}