一.分析:
使用spring 的 aop技术切到自定义注解上,针对不同注解标志进行参数解析,记录日志,缺点是要针对每个不同的注解标志进行分别取注解标志,获取参数进行日志记录输出
二.思路分析
1. 通过自定义注解,注解到需要aop切入的方法上
2. 声明一个aspect切入面,注入数据层dao, 将上面的注解类设成切入点, 通过反射获取到自定义注解上的某个属性,来区分是不同的记录日志需求。进行不同程度的封装Log实体对象。
3. 然后通过数据层,写入到日志表。
三.步骤
- 自定义方法注解类,注解到方法上,用于标识需要切入的点
package com.mtpc.admin.annotation;
import java.lang.annotation.*;
/**
* todo:
* 类SysLog的功能描述:
* 系统日志注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
String value() default "";
}
2.切面的实现
package com.mtpc.admin.controller;
import com.alibaba.fastjson.JSONObject;
import com.mtpc.admin.base.MySysUser;
import com.mtpc.admin.entity.SysLog;
import com.mtpc.admin.exception.GlobalExceptionHandler;
import com.mtpc.admin.util.ToolUtil;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
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 org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Map;
/**
*
* todo:
*/
@Aspect
@Order(5)
@Component
public class WebLogAspect {
private ThreadLocal<Long> startTime = new ThreadLocal<>();
@Autowired
private GlobalExceptionHandler exceptionHandle;
private SysLog sysLog = null;
/**
切点
*/
@Pointcut("@annotation(com.mtpc.admin.annotation.SysLog)")
public void webLog(){}
/**
切面
*/
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) {
startTime.set(System.currentTimeMillis());
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
HttpSession session = (HttpSession) attributes.resolveReference(RequestAttributes.REFERENCE_SESSION);
sysLog = new SysLog();
sysLog.setClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
sysLog.setHttpMethod(request.getMethod());
//获取传入目标方法的参数
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
Object o = args[i];
if(o instanceof ServletRequest || (o instanceof ServletResponse) || o instanceof MultipartFile){
args[i] = o.toString();
}
}
String str = JSONObject.toJSONString(args);
sysLog.setParams(str.length()>5000?JSONObject.toJSONString("请求参数数据过长不与显示"):str);
String ip = ToolUtil.getClientIp(request);
if("0.0.0.0".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip) || "localhost".equals(ip) || "127.0.0.1".equals(ip)){
ip = "127.0.0.1";
}
sysLog.setRemoteAddr(ip);
sysLog.setRequestUri(request.getRequestURL().toString());
if(session != null){
sysLog.setSessionId(session.getId());
}
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
com.mtpc.admin.annotation.SysLog mylog = method.getAnnotation(com.mtpc.admin.annotation.SysLog.class);
if(mylog != null){
//注解上的描述
sysLog.setTitle(mylog.value());
}
Map<String,String> browserMap = ToolUtil.getOsAndBrowserInfo(request);
sysLog.setBrowser(browserMap.get("os")+"-"+browserMap.get("browser"));
if(!"127.0.0.1".equals(ip)){
Map<String,String> map = ToolUtil.getAddressByIP(ToolUtil.getClientIp(request));
sysLog.setArea(map.get("area"));
sysLog.setProvince(map.get("province"));
sysLog.setCity(map.get("city"));
sysLog.setIsp(map.get("isp"));
}
sysLog.setType(ToolUtil.isAjax(request)?"Ajax请求":"普通请求");
if(MySysUser.ShiroUser() != null) {
sysLog.setUsername(StringUtils.isNotBlank(MySysUser.nickName()) ? MySysUser.nickName() : MySysUser.loginName());
}
}
@Around("webLog()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
try {
Object obj = proceedingJoinPoint.proceed();
return obj;
} catch (Exception e) {
e.printStackTrace();
sysLog.setException(e.getMessage());
throw e;
}
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) {
if(MySysUser.ShiroUser() != null) {
sysLog.setUsername(StringUtils.isNotBlank(MySysUser.nickName()) ? MySysUser.nickName() : MySysUser.loginName());
}
String retString = JSONObject.toJSONString(ret);
sysLog.setResponse(retString.length()>5000?JSONObject.toJSONString("请求参数数据过长不与显示"):retString);
sysLog.setUseTime(System.currentTimeMillis() - startTime.get());
sysLog.insert();
}
}
3.日志实体, 根据需求自定义
package com.mtpc.admin.entity;
import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.activerecord.Model;
import com.baomidou.mybatisplus.annotations.TableName;
import com.mtpc.admin.base.DataEntity;
/**
* <p>
* 系统日志
* </p>
*
*/
@TableName("sys_log")
public class SysLog extends DataEntity<SysLog> {
private static final long serialVersionUID = 1L;
/**
* 请求类型
*/
private String type;
/**
* 日志标题
*/
private String title;
/**
* 操作IP地址
*/
@TableField("remote_addr")
private String remoteAddr;
/**
* 操作用户昵称
*/
private String username;
/**
* 请求URI
*/
@TableField("request_uri")
private String requestUri;
/**
* 操作方式
*/
@TableField("http_method")
private String httpMethod;
/**
* 请求类型.方法
*/
@TableField("class_method")
private String classMethod;
/**
* 操作提交的数据
*/
private String params;
/**
* sessionId
*/
@TableField("session_id")
private String sessionId;
/**
* 返回内容
*/
private String response;
/**
* 方法执行时间
*/
@TableField("use_time")
private Long useTime;
/**
* 浏览器信息
*/
private String browser;
/**
* 地区
*/
private String area;
/**
* 省
*/
private String province;
/**
* 市
*/
private String city;
/**
* 网络服务提供商
*/
private String isp;
/**
* 异常信息
*/
private String exception;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getRemoteAddr() {
return remoteAddr;
}
public void setRemoteAddr(String remoteAddr) {
this.remoteAddr = remoteAddr;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getRequestUri() {
return requestUri;
}
public void setRequestUri(String requestUri) {
this.requestUri = requestUri;
}
public String getHttpMethod() {
return httpMethod;
}
public void setHttpMethod(String httpMethod) {
this.httpMethod = httpMethod;
}
public String getClassMethod() {
return classMethod;
}
public void setClassMethod(String classMethod) {
this.classMethod = classMethod;
}
public String getParams() {
return params;
}
public void setParams(String params) {
this.params = params;
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
public Long getUseTime() {
return useTime;
}
public void setUseTime(Long useTime) {
this.useTime = useTime;
}
public String getBrowser() {
return browser;
}
public void setBrowser(String browser) {
this.browser = browser;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getIsp() {
return isp;
}
public void setIsp(String isp) {
this.isp = isp;
}
public String getException() {
return exception;
}
public void setException(String exception) {
this.exception = exception;
}
@Override
public String toString() {
return "Log{" +
", type=" + type +
", title=" + title +
", remoteAddr=" + remoteAddr +
", username=" + username +
", requestUri=" + requestUri +
", httpMethod=" + httpMethod +
", classMethod=" + classMethod +
", params=" + params +
", sessionId=" + sessionId +
", response=" + response +
", useTime=" + useTime +
", browser=" + browser +
", area=" + area +
", province=" + province +
", city=" + city +
", isp=" + isp +
", exception=" + exception +
"}";
}
}
4.日志切入, 添加注解
@GetMapping("/pm/pmPgDevice")
@SysLog("企业设备")
public String pmPgDeviceList(Model model ) {
List productionGroupList = getProductionGroupList();
model.addAttribute("productionGroupList",productionGroupList);
return "/pm/device/pmPgDevice";
}
注:加入springboot配置
<!--spring切面aop依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
在application.properties文件里加这样一条配置
spring.aop.auto=true
在springboot项目里加这两条配置即可,就可以开启aop功能
数据显示