SpringBoot 之SpringAOP 请求日志记录功能(支持POST和GET)解析
熊孩纸
阅读:671
2021-03-31 17:00:21
评论:0
首先请参考:SpringBoot 之 SpringMVC拦截器从Request中获取参数并解决request的请求流只能读取一次的问题
参考完上面的代码,现在开始编辑请求日志记录功能,核心功能代码如下:
1、日志注解标签定义:
import java.lang.annotation.*;
@Target({ ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CatchErr {
}
2、Spirng AOP 切面功能代码:
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.fastjson.JSON;
import com.***.common.http.HttpUtils;
import com.***.common.http.wrapper.CustomerHttpServletRequestWrapper;
import com.***.common.uuid.SnowflakeIdGenerator;
import com.***.ucas.api.SysLogErrService;
import com.***.ucas.domain.SysLogErr;
@Aspect
@Component
public class ErrAspect {
@Autowired
private SysLogErrService sysLogErrService;
@Pointcut("@annotation(com.digipower.ucas.annotion.CatchErr)")
public void pointcut() {
}
@Around("pointcut()")
public Object saveErr(ProceedingJoinPoint joinPoint) {
System.out.println("spring aop 是否执行");
Object result = null;
SysLogErr logErr = new SysLogErr();
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
CustomerHttpServletRequestWrapper requestWrapper = null;
HttpServletRequest request = null;
if(sra.getRequest() instanceof CustomerHttpServletRequestWrapper){
requestWrapper = (CustomerHttpServletRequestWrapper) sra.getRequest();
} else {
request = sra.getRequest();
}
String methodType = null;
if(requestWrapper != null){
methodType = requestWrapper.getMethod();
}else {
methodType = request.getMethod();
}
String requestBody = null;
if ("POST".equalsIgnoreCase(methodType)) {
// CustomerHttpServletRequestWrapper wrapper = new CustomerHttpServletRequestWrapper(request);
requestBody = requestWrapper.getBody();
} else {
Enumeration<String> names = request.getParameterNames();
// 请求参数转换JSON 对象
List<Map> container = new ArrayList<Map>();
while (names.hasMoreElements()) {
Map<String, String> map = new HashMap<String, String>();
String key = names.nextElement();
String value = request.getParameter(key);
map.put(key, value);
container.add(map);
}
requestBody = JSON.toJSONString(container);
}
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取切入点所在的方法
Method method = signature.getMethod();
// 获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
// 获取请求的方法名
String methodName = method.getName();
// 请求url
String url = null;
if(requestWrapper != null){
url = requestWrapper.getRequestURI();
} else {
url = request.getRequestURI();
}
// ip地址
String ip = null;
if(requestWrapper != null){
ip = HttpUtils.getIpAddress(requestWrapper);
} else {
ip = HttpUtils.getIpAddress(request);
}
String account = "未知用户";
// 分布式Id生成器
SnowflakeIdGenerator snowflake = new SnowflakeIdGenerator(0, 0);
logErr.setSid(Long.toBinaryString(snowflake.nextId()));
logErr.setClassMethod(className + "." + methodName);
logErr.setRequestParam(requestBody);
logErr.setAccount(account);
logErr.setIp(ip);
logErr.setCreateTime(new Date());
sysLogErrService.insert(logErr);
try {
// 执行方法
result = joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
return result;
}
}
3、 日志实体对象:
import java.util.Date;
import com.***.common.model.BaseModel;
@SuppressWarnings("serial")
public class SysLogErr extends BaseModel {
private String sid;
private String account;
private String ip;
private String classMethod;
private String requestParam;
private Date createTime;
private String content;
private String stackTrace;
private String traceId;
private String serviceContent;
private String serviceStackTrace;
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getClassMethod() {
return classMethod;
}
public void setClassMethod(String classMethod) {
this.classMethod = classMethod;
}
public String getServiceContent() {
return serviceContent;
}
public void setServiceContent(String serviceContent) {
this.serviceContent = serviceContent;
}
public String getServiceStackTrace() {
return serviceStackTrace;
}
public void setServiceStackTrace(String serviceStackTrace) {
this.serviceStackTrace = serviceStackTrace;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account == null ? null : account.trim();
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip == null ? null : ip.trim();
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content == null ? null : content.trim();
}
public String getRequestParam() {
return requestParam;
}
public void setRequestParam(String requestParam) {
this.requestParam = requestParam == null ? null : requestParam.trim();
}
public String getStackTrace() {
return stackTrace;
}
public void setStackTrace(String stackTrace) {
this.stackTrace = stackTrace == null ? null : stackTrace.trim();
}
public String getTraceId() {
return traceId;
}
public void setTraceId(String traceId) {
this.traceId = traceId;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", sid=").append(sid);
sb.append(", account=").append(account);
sb.append(", ip=").append(ip);
sb.append(", classMethod=").append(classMethod);
sb.append(", requestParam=").append(requestParam);
sb.append(", createTime=").append(createTime);
sb.append(", content=").append(content);
sb.append(", stackTrace=").append(stackTrace);
sb.append(", traceId=").append(traceId);
sb.append(", serviceContent=").append(serviceContent);
sb.append(", serviceStackTrace=").append(serviceStackTrace);
sb.append("]");
return sb.toString();
}
}
SpirngBoot 添加HttpServlet 的转换工具类
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class CustomerHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public CustomerHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
InputStream inputStream = null;
try {
inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
body = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
}
SpringBoot 添加Fileter 完成HttpServletRequest 向自定义CustomerHttpServletRequestWrapper 的转换
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import com.digipower.common.http.wrapper.CustomerHttpServletRequestWrapper;
public class MVCFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
System.out.println("Filter 方法先执行");
ServletRequest requestWrapper = null;
if(servletRequest instanceof HttpServletRequest) {
requestWrapper = new CustomerHttpServletRequestWrapper((HttpServletRequest) servletRequest);
}
if (requestWrapper == null) {
chain.doFilter(servletRequest, servletResponse);
} else {
chain.doFilter(requestWrapper, servletResponse);
}
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
SpringBoot 添加filter
@Bean
public FilterRegistrationBean MVCFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MVCFilter());
registration.addUrlPatterns("/*");
registration.setName("nvcFilter");
return registration;
}
springboot + mybatis 实现数据入库:
springboot + springsecurity 工具类封装:
声明
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。