切面方式
- 定义@SysLog注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
String value() default "";
}
- 实现切面类
/**
* 系统日志,切面处理类
*
*/
@Aspect
@Component
public class SysLogAspect {
@Autowired
private SysLogService sysLogService;
@Pointcut("@annotation(io.acm.common.annotation.SysLog)")
public void logPointCut() {
}
/**
*通过@Pointcut注解定义了一个切点,用于匹配所有标记有@SysLog注解的方法。
*around方法使用@Around注解,表示环绕通知,在方法执行前后都会执行。在方法执行前后分别记录时间并保存系统日志。
*/
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
//执行方法
Object result = point.proceed();
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
//保存日志
saveSysLog(point, time);
return result;
}
/**
*通过反射获取方法上的@SysLog注解的值,并记录为操作内容。
*/
private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SysLogEntity sysLog = new SysLogEntity();
SysLog syslog = method.getAnnotation(SysLog.class);
if(syslog != null){
//注解上的描述
sysLog.setOperation(syslog.value());
}
//请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLog.setMethod(className + "." + methodName + "()");
//请求的参数
Object[] args = joinPoint.getArgs();
try{
String params = new Gson().toJson(args);
sysLog.setParams(params);
}catch (Exception e){
}
//获取request
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
//设置IP地址
sysLog.setIp(IPUtils.getIpAddr(request));
//用户名
String username = ((SysUserEntity) SecurityUtils.getSubject().getPrincipal()).getUsername();
sysLog.setUsername(username);
sysLog.setTime(time);
sysLog.setCreateDate(new Date());
//保存系统日志
sysLogService.save(sysLog);
}
}
实现了Spring框架HandlerMethodArgumentResolver接口
1.定义注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {
}
- 当有请求到达Spring MVC的Controller层,并且该请求对应的方法中存在使用
@LoginUser
注解的AppUserEntity
类型的参数时。Spring框架会自动调用LoginUserHandlerMethodArgumentResolver
中的方法来解析并注入当前登录用户的信息。
@Component
public class LoginUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().isAssignableFrom(AppUserEntity.class) && parameter.hasParameterAnnotation(LoginUser.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer container,
NativeWebRequest request, WebDataBinderFactory factory) throws Exception {
//获取用户ID
Object object = request.getAttribute(AuthorizationInterceptor.USER_KEY, RequestAttributes.SCOPE_REQUEST);
if (object == null) {
return null;
}
AppUserEntity userInfo = redisUtils.get("userId:" + object, AppUserEntity.class);
if (userInfo != null) {
return userInfo;
}
//重新获取用户信息
AppUserEntity user = userService.getById((Long) object);
redisUtils.set("userId:" + object, user, 7200);
return user;
}
}
HandlerMethodArgumentResolver
是Spring MVC中的一个接口,用于解析方法参数并将解析后的结果注入到Controller方法中。 所以可通过实现HandlerMethodArgumentResolver
接口来定义自己的参数解析器,实现自定义的参数解析逻辑