AOP基于切面编程,这里的日志管理俩种分别是
不需要配置xml文件
1、切面类不做实际操作,切入点针对所有的controller类,各个需要保存日志的操作方法,分别执行日志保存的方法,更具有针对性。
2、通过自定义注解,针对方法级别,各个需要保存日志的方法上加自定义注解进行保存操作,实际相当于将日志保存方法提取出来,然后以注解方式应用在每个需要的方法上。
先把第一种介绍一下
LogAspect.java
@Aspect
@Component
public class LogAspect {
/**
* 这句话是方法切入点
* 1 execution (* com.my.blog.website.controller..*.*(..))
* 2 execution : 表示执行
* 3 第一个*号 : 表示返回值类型, *可以是任意类型
* 4 com.my.blog.website.controller : 代表扫描的包
* 5 .. : 代表其底下的子包也进行拦截
* 6 第二个*号 : 代表对哪个类进行拦截,*代表所有类
* 7 第三个*号 : 代表方法 *代表任意方法
* 8 (..) : 代表方法的参数有无都可以
*/
//配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点
@Pointcut("execution( * com.my.blog.website.controller..*.*(..))")
public void webLog(){}
//前置通知等可以没有JoinPoint参数
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
LOGGER.info("URL : " + request.getRequestURL().toString() + ",IP : " + request.getRemoteAddr() + ",CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName() + ",ARGS : " + Arrays.toString(joinPoint.getArgs()));
}
//配置后置返回通知,使用在方法webLog()上注册的切入点
@AfterReturning(returning = "object", pointcut = "webLog()")
public void doAfterReturning(Object object) throws Throwable {
// 处理完请求,返回内容
LOGGER.info("RESPONSE :" + object);
}
}
应用:
@PostMapping(value = "/profile")
@ResponseBody
@Transactional(rollbackFor = TipException.class)
public RestResponseBo saveProfile(@RequestParam String screenName, @RequestParam String email, HttpServletRequest request, HttpSession session) {
UserVo users = this.user(request);
if (StringUtils.isNotBlank(screenName) && StringUtils.isNotBlank(email)) {
UserVo temp = new UserVo();
temp.setUid(users.getUid());
temp.setScreenName(screenName);
temp.setEmail(email);
userService.updateByUid(temp);
//这里需要单独保存日志信息,
logService.insertLog(LogActions.UP_INFO.getAction(), GsonUtils.toJsonString(temp), request.getRemoteAddr(), this.getUid(request));
//更新session中的数据
UserVo original = (UserVo) session.getAttribute(WebConst.LOGIN_SESSION_KEY);
original.setScreenName(screenName);
original.setEmail(email);
session.setAttribute(WebConst.LOGIN_SESSION_KEY, original);
}
return RestResponseBo.ok();
}
第二种
SysLogAspect.java
@Aspect //定义切面
@Component //声明组件
public class SysLogAspect {
@Autowired
private ILogService logService;
//这里切入点是自定义注解,下面有注解的代码
@Pointcut("@annotation(com.my.blog.website.annotation.SysLog)")
public void logPointCut(){
}
//配置环绕通知,使用在方法logPointCut()上注册的切入点
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point)throws Throwable{
long beginTime=System.currentTimeMillis();
//执行方法
Object result=point.proceed();
//可以设置time,监控方法执行的时间,但是我没有去实现
long time=System.currentTimeMillis()-beginTime;
saveSysLog(point,time);
return result;
}
private void saveSysLog(ProceedingJoinPoint point, long time){
MethodSignature signature=(MethodSignature) point.getSignature();
Method method=signature.getMethod();
LogVo log=new LogVo();
SysLog sysLog=method.getAnnotation(SysLog.class);
HttpServletRequest request=((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
//从session中获取用户
UserVo user=(UserVo) request.getSession().getAttribute(WebConst.LOGIN_SESSION_KEY);
//获取请求参数
Object[] args=point.getArgs();
logService.insertLog(sysLog.value().getAction(), GsonUtils.toJsonString(args[0]), request.getRemoteAddr(), user.getUid());
}
}
注解代码:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
LogActions value() default LogActions.LOGIN;
}
枚举类用来存放操作的名字
public enum LogActions {
LOGIN("登录后台"), UP_PWD("修改密码"), UP_INFO("修改个人信息"),
DEL_ARTICLE("删除文章"), DEL_PAGE("删除页面"), SYS_BACKUP("系统备份"),DEL_COMMENT("删除评论"),
SYS_SETTING("保存系统设置"), INIT_SITE("初始化站点");
private String action;
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
LogActions(String action) {
this.action = action;
}
应用:
@SysLog(LogActions.UP_INFO)
@PostMapping(value = "/profile")
@ResponseBody
@Transactional(rollbackFor = TipException.class)
public RestResponseBo saveProfile(@RequestParam String screenName, @RequestParam String email, HttpServletRequest request, HttpSession session) {
UserVo users = this.user(request);
if (StringUtils.isNotBlank(screenName) && StringUtils.isNotBlank(email)) {
UserVo temp = new UserVo();
temp.setUid(users.getUid());
temp.setScreenName(screenName);
temp.setEmail(email);
userService.updateByUid(temp);
//更新session中的数据
UserVo original = (UserVo) session.getAttribute(WebConst.LOGIN_SESSION_KEY);
original.setScreenName(screenName);
original.setEmail(email);
session.setAttribute(WebConst.LOGIN_SESSION_KEY, original);
}
return RestResponseBo.ok();
}
这种只需要在你的方法上加上注解@SysLog(LogActions.UP_INFO),LogActions.UP_INFO这个是自定义的一个类型,这里可以直接放string类型的数据,不过需要修改注解定义那里。
至此,两种AOP日志管理搞定,主要是要做个记录,同时熟悉熟悉AOP这个技巧,真的很实用,希望可以帮到需要的人。