自定义注解的使用
- 注解+拦截器 实现登录校验
项目中在进入方法之前判断用户是否登录、登录了则继续执行方法,未登录则返回异常信息。
a.先定义一个注解@NeedLogin
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedLogin {
}
b.再写个拦截器,控制具体逻辑
public class NeedLoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 反射获取方法上的NeedLogin注解
if (handler instanceof HandlerMethod){
/**
* 注意:
* 当接口顶层没有设置根路劲时,Spring boot 将接口理解为静态资源(ResourceHttpRequestHandler)
* @see com.yds.start.controller.DemoErrorController
* (HandlerMethod)handler 会报错(ClassCastException)
*
* ResourceHttpRequestHandler是用来处理静态资源的;而HandlerMethod则是springMVC中用@Controller声明的一个bean及对应的处理方法.
*
*/
HandlerMethod handlerMethod = (HandlerMethod)handler;
NeedLogin loginRequired = handlerMethod.getMethod().getAnnotation(NeedLogin.class);
if(loginRequired != null){
// 有NeedLogin注解说明需要登录,提示用户登录
response.setContentType("text/plain; charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print("你访问的资源需要登录");
writer.flush();
writer.close();
return false;
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
c.看效果(写两个接口一个带@NeedLogin,一个不带)
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@NeedLogin
@GetMapping(value = "/getMyInfo")
public String getMyInfo() {
String myInfo = userService.getMyInfo();
return myInfo;
}
@GetMapping(value = "/login")
public String login() {
return "login";
}
}
- 注解+AOP 日志打印
项目中可以根据注解自定义打印日志
a.定义注解@MyLog
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface MyLog {
}
b.AOP 实现逻辑
@Slf4j
@Aspect
@Component
public class LogAspect {
/**
* PointCut表示这是一个切点,@annotation表示这个切点切到一个注解上,后面带该注解的全类名
* 切面最主要的就是切点,所有的故事都围绕切点发生
* logPointCut()代表切点名称
*/
@Pointcut("@annotation(com.yds.start.common.annotation.MyLog)")
public void logPointCut() {
}
/**
* 环绕通知
* @param joinPoint
*/
@Around("logPointCut()")
public void logAround(ProceedingJoinPoint joinPoint){
// 获取方法名称
String methodName = joinPoint.getSignature().getName();
// 获取入参
Object[] param = joinPoint.getArgs();
StringBuilder sb = new StringBuilder();
for(Object o : param){
sb.append(o + "; ");
}
log.info("进入[{}]方法,参数为:{}" ,methodName, sb);
// 继续执行方法
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
log.info(methodName + "方法执行结束");
}
}
c.看效果(写个接口,加上@MyLog注解)
@MyLog
@GetMapping(value = "/test")
public String test(String str) {
return str;
}
访问http://127.0.0.1:8080/demo/test?str=123
观察控制台输出:
2022-02-23 10:10:04.317 INFO 95922 --- [nio-8080-exec-6] com.yds.start.common.aop.LogAspect : 进入[test]方法,参数为:123;
2022-02-23 10:10:04.318 INFO 95922 --- [nio-8080-exec-6] com.yds.start.common.aop.LogAspect : test方法执行结束