SpringBoot 之SpringAOP 请求日志记录功能(支持POST和GET)分析

熊孩纸 阅读:266 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.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
KIKK导航

KIKK导航

排行榜
关注我们

一个IT知识分享的公众号