Aop实现日志处理
前言: 我们在这里做一个登录日志的demo 每次登录时记录是谁登录的 登录的ip时间等等
1.自定义注解
package com.aisile.crowd_funding.common.annotion;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//自定义声明注解
@Target(ElementType.METHOD)//声明此注解用到方法上
@Retention(RetentionPolicy.RUNTIME)//声明此注解的使用时机
//该注解必须用@interface声明 我这里给它声明为log 声明好之后 定义个value 属性就可以使用它了 使用方法(@Log(“登录方法”))
public @interface Log {
//定义value属性 默认值为空
String value() default “”;
}
2.
*/
@Aspect//注解当前类为切面类
@Component//必须加上这个才能被spring 管理
public class LogAspect {
@Autowired
LogService logService;
//pointcut 注解是表明哪些方法要被切面处理这里我们定义好了一个注解意思就是凡是被这个注解标注的方法被切面处理
@Pointcut("@annotation(com.aisile.crowd_funding.common.annotion.Log)")/这个是定义切面
public void Pointcut(){
}
//前置通知
@Before("Pointcut()")
public void beforeHandler(){
System.out.println("前置通知被触发了");
}
@After("Pointcut()")
public void after(){
System.out.println("后置通知被触发了");
}
//环绕通知
@Around(“Pointcut()”)
public Object Around(ProceedingJoinPoint point) throws Throwable{
Object proceed=null;
try {
SysLog log=new SysLog();
log.setGmtCreate(new Date());
//在这写就是前置通知
//获取当前毫秒
Long startTime=System.currentTimeMillis();
//可以把它看成获取到的方法proceed是一个最大的类操作完成之后return
proceed=point.proceed();
//获取当前毫秒
Long endTime=System.currentTimeMillis();
//算出方法的执行时间
log.setTime((int)(endTime-startTime));
System.out.print(endTime-startTime);
//获取当前操作用户因为是用的shiro所以能通过seccurity得到它
SysUser sysUser= ShiroUtils.getSubject();
log.setUserId(sysUser.getUserId());
log.setUsername(sysUser.getUsername());
//利用反射获取注解从而知道当前是一个什么操作
MethodSignature methodSignature=(MethodSignature)point.getSignature();
Method method = methodSignature.getMethod();
//利用反射获取方法上的注解
Log annotation = method.getAnnotation(Log.class);
//得到注解里的值
String opertioan=annotation.value();
//获取方法名称
log.setOperation(opertioan);
log.setMethod(method.getName());
//获取方法所在类
method.getDeclaringClass().toString();
//获取ip这个就可以知道哪一台电脑操作的
//得到request Ip需要request对象获取 (得到request的方法)
HttpServletRequest request=((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//获取本地Ip
request.getLocalAddr();
//获取远程Ip
log.setIp(request.getRemoteAddr());
//在这写就是后置通知
logService.insert(log);
}catch (Exception e){
//在这写就是异常通知
}finally {
//在这写就是最终通知
}
return proceed;
}
}
3. @Log(“登录方法”)//这个是自定义的注解 凡是被这个注解注释的就交给切面处理
@RequestMapping(“loginSign”)
@ResponseBody
public R loginSign(String username,String password){
// 效验参数
if(StringUtils.isBlank(username)){
return R.error("用户名不能为空");
}
if(StringUtils.isBlank(password)){
return R.error("密码不能为空");
}
//认证创建一个subject对象
org.apache.shiro.subject.Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username, MD5Utils.encrypt(password));
try {
subject.login(usernamePasswordToken);
}catch (UnknownAccountException e) {
return R.error("未查询到该用户");
}catch(LockedAccountException e){
return R.error("用户认证失败");
}catch(Exception e){
return R.error("登录失败");
}
return R.ok();
}