(009)java实现自定义注解
2018-10-10 本文已影响0人
Lindm
一、前言
自定义注解可用于记录系统操作日志、查阅记录等,使编码更加灵活。
二、步骤
(1) pom.xml导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
(2)新建自定义注解类
package com.business.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 查阅记录注解<br/>
* 文档id:直接从HttpServletRequest上获取参数“docId”
* @author lindm
* @date 2018/10/10
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadLog {
String docId() default "";
// 模块编码
String moduleId() default "DISPATCH";
}
(3)新建切面类
package com.business.annotation.impl;
import com.business.annotation.ReadLog;
import com.business.constant.AnnotationConstant;
import com.business.service.DocReadLogMng;
import com.egov.utils.exception.BusinessException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.mp4parser.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
/**
* 查阅记录注解切面类
* 注解无法实现动态传参,可采用其他迂回的方式获取参数
* @author lindm
* @date 2018/10/10
*/
@Aspect
@Component
public class ReadLogImpl {
@Resource
private DocReadLogMng docReadLogMng;
@Pointcut(value = "@annotation(com.business.annotation.ReadLog)")
public void insertReadLog(){
}
/**
* 方法执行后
*
* @param joinPoint
* @return
*/
// TODO 待完善
@After(value = "@annotation(com.business.annotation.ReadLog)")
public void after(JoinPoint joinPoint) {
try {
// 获取请求参数
// 对于HttpServletRequest在非控制层的操作,使用RequestContextHolder是线程安全的
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
String docId = request.getParameter(AnnotationConstant.PARAM_ID);
// 获取方法签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//java reflect相关类,通过反射得到注解
Method method = signature.getMethod();
//获取方法注解Log
ReadLog methodAnnotation = method.getAnnotation(ReadLog.class);
String moduleId = AnnotationConstant.MODULE_ID;
if (methodAnnotation != null) {
// 获取注解静态变量值
moduleId = methodAnnotation.moduleId();
}
// 新增记录
docReadLogMng.insertReadLog(docId, moduleId);
} catch (Throwable throwable) {
throwable.printStackTrace();
throw new BusinessException("新增查阅记录出现异常");
}
}
}
(4)新建注解常量类
package com.business.constant;
/**
* 注解使用的常量
* @author lindm
* @date 2018/10/10
*/
public class AnnotationConstant {
public static final String MODULE_ID = "EMAIL";
public static final String PARAM_ID = "docId";
}
(5)使用@ReadLog注解
/**
* 根据ID得到详细信息
*
* @return
*/
@GetMapping("/getDetailById")
@ReadLog(moduleId = "EMAIL")
public JSONObject getDetailById(@RequestParam("docId") String docId) {
return this.mng.getDetailById(docId, aid);
}
(6)新建Mock测试类
package com.web;
import com.business.CommonBusinessConfiguration;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {CommonWebConfiguration.class, CommonBusinessConfiguration.class})
public class DocReadLogTest {
private MockMvc mvc;
/**
* web项目上下文
*/
@Autowired
private WebApplicationContext webApplicationContext;
/**
* 所有测试方法执行之前执行该方法
*/
@Before
public void before() {
//获取mockmvc对象实例
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
/**
* 查询
* @throws Exception
*/
@Test
@WithUserDetails("test")
public void getDetailById() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("getDetailById?docId=123"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print());
}
}
三、参考链接
(1)自定义注解实现方法入参与出参的日志打印:
https://my.oschina.net/xiaomingnevermind/blog/1619274
(2)java自定义注解:
https://www.jianshu.com/p/7dcd59bdbb0a
(3)由HttpServletRequest的传值引发的线程安全性问题:
https://www.jianshu.com/p/c7f49658ad04