@Target:注解的作用目标
用于自定义注解时
@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包
package java.lang.annotation;
/**
* The constants of this enumerated type provide a simple classification of the
* syntactic locations where annotations may appear in a Java program. These
* constants are used in {@link Target java.lang.annotation.Target}
* meta-annotations to specify where it is legal to write annotations of a
* given type.
* @author Joshua Bloch
* @since 1.5
* @jls 9.6.4.1 @Target
* @jls 4.1 The Kinds of Types and Values
*/
public enum ElementType {
/** 类, 接口 (包括注释类型), 或 枚举 声明 */
TYPE,
/** 字段声明(包括枚举常量) */
FIELD,
/** 方法声明(Method declaration) */
METHOD,
/** 正式的参数声明 */
PARAMETER,
/** 构造函数声明 */
CONSTRUCTOR,
/** 局部变量声明 */
LOCAL_VARIABLE,
/** 注释类型声明 */
ANNOTATION_TYPE,
/** 包声明 */
PACKAGE,
/**
* 类型参数声明
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* 使用的类型
*
* @since 1.8
*/
TYPE_USE
}
@Retention:注解的保留位置
RetentionPolicy.SOURCE:这种类型的Annotations只在源代码级别保留,编译时就会被忽略,在class字节码文件中不包含。
RetentionPolicy.CLASS:这种类型的Annotations编译时被保留,默认的保留策略,在class文件中存在,但JVM将会忽略,运行时无法获得。
RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
package java.lang.annotation;
/**
* Annotation retention policy. The constants of this enumerated type
* describe the various policies for retaining annotations. They are used
* in conjunction with the {@link Retention} meta-annotation type to specify
* how long annotations are to be retained.
*
* @author Joshua Bloch
* @since 1.5
*/
public enum RetentionPolicy {
/**
* 注释只在源代码级别保留,编译时被忽略
*/
SOURCE,
/**
* 注释将被编译器在类文件中记录
* 但在运行时不需要JVM保留。这是默认的
* 行为.
*/
CLASS,
/**
*注释将被编译器记录在类文件中
*在运行时保留VM,因此可以反读。
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
实际运用
定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ReSubmit {
// 是否允许重复提交(默认不允许)
boolean allow() default false;
}
切面类
@Aspect
@Component
public class ControllerAspect {
private static final Logger logger = LoggerFactory.getLogger(ControllerAspect.class);
@Autowired
private OperationLogService operationLogService;
@Autowired
private RedisService redisService;
private static final String[] NO_ASPECT_LOG = {"/login","/loginAgain","/validateCode","/logout"};
private static final String CUT = "execution(*com.sk.Controller..*.*(..))";
@Around(CUT)
public Object doAround(ProceedingJoinPoint joinPoint){
Date requestTime = new Date();
Signature signature = joinPoint.getSignature();
String methodName = signature.getName();
Object[] objs = joinPoint.getArgs();
String traceId = CommonUtils.getUUID();
RpcContext.getContext().setAttachment(CommonConstant.TRACE_ID, traceId);
MDC.put(CommonConstant.TRACE_ID, traceId);
String requestInfo = JSON.toJSONString(objs);
if(logger.isInfoEnabled()) {
logger.info(" ### {} start and param : {}", methodName, requestInfo);
}
ResponseVO<?> returnValue = null;
try {
// 单位时间(2秒)内重复提交限制
checkResubmit(signature, requestInfo);
//TODO 服务型功能码过期判断
//TODO 参数特殊字符处理
Object returnObj = joinPoint.proceed();
if(returnObj instanceof ResponseVO) {
returnValue = (ResponseVO<?>)returnObj;
}
} catch(BusinessException e) {
if(logger.isErrorEnabled()) {
logger.error(" process exception", e);
}
returnValue = ResponseVO.failed(e);
} catch (Throwable e) {
if(logger.isErrorEnabled()) {
logger.error(" process exception", e);
}
returnValue = ResponseVO.failed();
} finally {
if(logger.isInfoEnabled()) {
logger.info(" ### {} finish and use time {} ms, returnvalue : {} ", new Object[] {methodName, System.currentTimeMillis()-requestTime.getTime(), JSON.toJSONString(returnValue)});
}
MDC.remove(CommonConstant.TRACE_ID);
}
// 操作日志记录
try {
BaseController b = (BaseController)joinPoint.getTarget();
String operateUri = WebUtils.getPathWithinApplication(b.getRequest());
if(!Arrays.toString(NO_ASPECT_LOG).contains(operateUri)) {
SysOperationLogVo operVo = new SysOperationLogVo();
operVo.setOperateUri(operateUri);
operVo.setChannel(ChannelEnum.WEB.toString());
operVo.setRequestTime(requestTime);
operVo.setUseTime(System.currentTimeMillis()-requestTime.getTime());
operVo.setResponseTime(new Date());
operVo.setRequestParams(JSON.toJSONString(objs));
operVo.setResponseCode(null==returnValue ? "unknown" : returnValue.getCode());
operVo.setResponseInfo(null==returnValue ? "unknown" : JSON.toJSONString(returnValue));
SessionUser sessionUser = SessionUtil.getSessionUser();
if(sessionUser != null) {
operVo.setOperateUser(sessionUser.getUserId());
operVo.setOperateUserName(sessionUser.getUserName());
operVo.setPermitName(sessionUser.getPermsMap().get(operateUri));
}
AsyncTaskUtil.asyncTask(new OperationLogAsyncTask(operationLogService, operVo));
}
}catch (Exception e) {
logger.error(" operationLogService.insertSysOperationLog error ", e);
}
return returnValue;
}
private void checkResubmit(Signature signature, String requestInfo) {
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
ReSubmit reSubmit = method.getAnnotation(ReSubmit.class);
if(reSubmit != null) {
boolean allow = reSubmit.allow();
if(!allow) {
String md5Key = DigestUtils.md5Hex(new StringBuilder("").append(requestInfo).toString()).toLowerCase();
String value = (String)redisService.get(md5Key);
if(!CommonUtils.isNullOrEmpty(value)) {
throw ManagerWebException.RE_SUBMIT;
}else {
redisService.set(md5Key, "1", 2);
}
}
}
}
}
(https://blog.csdn.net/fengcai0123/article/details/90544338)
(https://blog.csdn.net/liang100k/article/details/79515910?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task)