spring's Custom Annotation Analysis

Preface

spring provides rich annotations, but sometimes does not meet the complex needs of existing businesses. We can refine our business framework by customizing annotations.

Sending:
The only way to success is to make things perfect and reward people for their diligence.

Note Creation Notes

@Target

@Target - Where is the comment used and the default value is any element, indicating where the comment is used.Available ElementType s specify parameters
ElementType.CONSTRUCTOR: Used to describe constructors
ElementType.FIELD: Member variables, objects, attributes (including enum instances)
ElementType.LOCAL_VARIABLE: Used to describe local variables
ElementType.METHOD: Used to describe methods
ElementType.PACKAGE: Used to describe packages
ElementType.PARAMETER: Used to describe parameters
ElementType.TYPE: Used to describe classes, interfaces (including annotation types), or enum declarations

@Retention

Indicates at what level the annotation information needs to be saved.
When to use this annotation, the life cycle of the annotation, specified using RetentionPolicy
RetentionPolicy.SOURCE: Discarded at compile time.These annotations have no meaning after compilation, so they do not write byte codes.@Override, @SuppressWarnings are notes of this type.
RetentionPolicy.CLASS: Discarded when class loads.Useful in the processing of byte code files.Annotations use this method by default
RetentionPolicy.RUNTIME: This annotation is never discarded and is maintained during runtime, so you can use a reflection mechanism to read its information.This is often the way we customize annotations.

@Document

Include comments in Javadoc

@Inherited

Allow subclasses to inherit comments from their parent

Example description

OperationType.java

`package com.basic.bl.rest.demo.aop;
public enum OperationType {

/**
 * Operation type
 */
UNKNOWN("unknown"),
DELETE("delete"),
SELECT("select"),
UPDATE("update"),
INSERT("insert");

private String value;

public String getValue() {
    return value;
}

public void setValue(String value) {
    this.value = value;
}

OperationType(String s) {
    this.value = s;
}

}`

OperationUnit.java

`package com.basic.bl.rest.demo.aop;

public enum OperationUnit {

/**
 * Unit to be operated on
 */
UNKNOWN("unknown"),
USER("user"),
EMPLOYEE("employee"),
SELLER("seller");

private String value;

OperationUnit(String value) {
    this.value = value;
}

public String getValue() {
    return value;
}

public void setValue(String value) {
    this.value = value;
}

}
`

OperationLog.java

`package com.basic.bl.rest.demo.aop;

import java.util.Date;

public class OperationLog {

private String id;
private Date createTime;
/**
 * Log Level
 */
private Integer level;
/**
 * Operated Objects
 */
private String operationUnit;
/**
 * Method Name
 */
private String method;
/**
 * parameter
 */
private String args;
/**
 * Operator id
 */
private String userId;
/**
 * Operator
 */
private String userName;
/**
 * Log Description
 */
private String describe;
/**
 * Operation type
 */
private String operationType;
/**
 * Method Runtime
 */
private Long runTime;
/**
 * Method Return Value
 */
private String returnValue;

@Override
public String toString() {
    return "OperationLog{" +
            "id='" + id + '\'' +
            ", createTime=" + createTime +
            ", level=" + level +
            ", operationUnit='" + operationUnit + '\'' +
            ", method='" + method + '\'' +
            ", args='" + args + '\'' +
            ", userId='" + userId + '\'' +
            ", userName='" + userName + '\'' +
            ", describe='" + describe + '\'' +
            ", operationType='" + operationType + '\'' +
            ", runTime=" + runTime +
            ", returnValue='" + returnValue + '\'' +
            '}';
}

public Long getRunTime() {
    return runTime;
}

public void setRunTime(Long runTime) {
    this.runTime = runTime;
}

public String getReturnValue() {
    return returnValue;
}

public void setReturnValue(String returnValue) {
    this.returnValue = returnValue;
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public Date getCreateTime() {
    return createTime;
}

public void setCreateTime(Date createTime) {
    this.createTime = createTime;
}

public Integer getLevel() {
    return level;
}

public void setLevel(Integer level) {
    this.level = level;
}

public String getOperationUnit() {
    return operationUnit;
}

public void setOperationUnit(String operationUnit) {
    this.operationUnit = operationUnit;
}

public String getMethod() {
    return method;
}

public void setMethod(String method) {
    this.method = method;
}

public String getArgs() {
    return args;
}

public void setArgs(String args) {
    this.args = args;
}

public String getUserId() {
    return userId;
}

public void setUserId(String userId) {
    this.userId = userId;
}

public String getUserName() {
    return userName;
}

public void setUserName(String userName) {
    this.userName = userName;
}

public String getDescribe() {
    return describe;
}

public void setDescribe(String describe) {
    this.describe = describe;
}

public String getOperationType() {
    return operationType;
}

public void setOperationType(String operationType) {
    this.operationType = operationType;
}

}
`

OperationLogDetail.java

`package com.basic.bl.rest.demo.aop;

import java.lang.annotation.*;

//@OperationLogDetail(detail = Get user name from mobile number [{{tel}}], level = 3,operationUnit = OperationUnit.USER,operationType = OperationType.SELECT)
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface OperationLogDetail {

/**
 * Method description, using placeholders to get parameters: {{tel}}
 */
String detail() default "";

/**
 * Log Level: Self-defined, 1-9 here
 */
int level() default 0;

/**
 * Operation type (enum): mainly select,insert,update,delete
 */
OperationType operationType() default OperationType.UNKNOWN;

/**
 * The object being manipulated (enum is used here): can be any object, such as a table name (user), or a tool (redis)
 */
OperationUnit operationUnit() default OperationUnit.UNKNOWN;

}
`

LogAspect.java

`package com.basic.bl.rest.demo.aop;

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Aspect
@Component
public class LogAspect {

/**
 * The point of tangency here is the way you annotate, or you can achieve the same effect by using a package name
 * '@Pointcut("execution(* com.basic.bl.rest.demo.aop.service.impl.*.*(..))")'
 */
@Pointcut("@annotation(com.basic.bl.rest.demo.aop.OperationLogDetail)")
public void operationLog(){}


/**
 * Enhanced surround, equivalent to MethodInterceptor
 */
@Around("operationLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
    Object res = null;
    long time = System.currentTimeMillis();
    try {
        res =  joinPoint.proceed();
        time = System.currentTimeMillis() - time;
        return res;
    } finally {
        try {
            //Add log after method execution
            addOperationLog(joinPoint,res,time);
        }catch (Exception e){
            System.out.println("LogAspect Operation failed:" + e.getMessage());
            e.printStackTrace();
        }
    }
}

private void addOperationLog(JoinPoint joinPoint, Object res, long time){
    MethodSignature signature = (MethodSignature)joinPoint.getSignature();
    OperationLog operationLog = new OperationLog();
    operationLog.setRunTime(time);
    operationLog.setReturnValue(JSON.toJSONString(res));
    operationLog.setId(UUID.randomUUID().toString());
    operationLog.setArgs(JSON.toJSONString(joinPoint.getArgs()));
    operationLog.setCreateTime(new Date());
    operationLog.setMethod(signature.getDeclaringTypeName() + "." + signature.getName());
    operationLog.setUserId("#{currentUserId}");
    operationLog.setUserName("#{currentUserName}");
    OperationLogDetail annotation = signature.getMethod().getAnnotation(OperationLogDetail.class);
    if(annotation != null){
        operationLog.setLevel(annotation.level());
        operationLog.setDescribe(getDetail(((MethodSignature)joinPoint.getSignature()).getParameterNames(),joinPoint.getArgs(),annotation));
        operationLog.setOperationType(annotation.operationType().getValue());
        operationLog.setOperationUnit(annotation.operationUnit().getValue());
    }
    //TODO Save Log Here
    System.out.println("Logging:" + operationLog.toString());

// operationLogService.insert(operationLog);

}

/**
 * Processing of current logged-in users and placeholders
 * @param argNames Array of method parameter names
 * @param args Array of method parameters
 * @param annotation annotation
 * @return Return description after processing
 */
private String getDetail(String[] argNames, Object[] args, OperationLogDetail annotation){

    Map<Object, Object> map = new HashMap<>(4);
    for(int i = 0;i < argNames.length;i++){
        map.put(argNames[i],args[i]);
    }

    String detail = annotation.detail();
    try {
        detail = "'" + "#{currentUserName}" + "'=>" + annotation.detail();
        for (Map.Entry<Object, Object> entry : map.entrySet()) {
            Object k = entry.getKey();
            Object v = entry.getValue();
            detail = detail.replace("{{" + k + "}}", JSON.toJSONString(v));
        }
    }catch (Exception e){
        e.printStackTrace();
    }
    return detail;
}

@Before("operationLog()")
public void doBeforeAdvice(JoinPoint joinPoint){
    System.out.println("Execute before entering method.....");

}

/**
 * After processing the request, return the content
 * @param ret
 */
@AfterReturning(returning = "ret", pointcut = "operationLog()")
public void doAfterReturning(Object ret) {
    System.out.println("Return value of method : " + ret);
}

/**
 * Post-exception notification
 */
@AfterThrowing("operationLog()")
public void throwss(JoinPoint jp){
    System.out.println("Execute on Method Exception.....");
}


/**
 * Post-final notification, final enhancement, executed regardless of exception throw or normal exit
 */
@After("operationLog()")
public void after(JoinPoint jp){
    System.out.println("Method Last Execution.....");
}

}`

DemoController.java

`package com.basic.bl.rest.demo.aop;
import com.basic.bl.rest.demo.aop.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("demo")
public class DemoController {

@Autowired
private DemoService demoService;

/**
 * Access path http://localhost:11000/user/findUserNameByTel?tel=1234567
 * @param tel Cell-phone number
 * @return userName
 */
@ResponseBody
@RequestMapping("/findUserNameByTel")
public String findUserNameByTel(@RequestParam("tel") String tel){
    return demoService.findUserName(tel);
}

}
``

DemoServiceImpl.java

`package com.basic.bl.rest.demo.aop.service.impl;

import com.basic.bl.rest.demo.aop.OperationLogDetail;
import com.basic.bl.rest.demo.aop.OperationType;
import com.basic.bl.rest.demo.aop.OperationUnit;
import com.basic.bl.rest.demo.aop.service.DemoService;
import org.springframework.stereotype.Service;

@Service
public class DemoServiceImpl implements DemoService {

@OperationLogDetail(detail = "Via mobile number[{{tel}}]Get User Name",level = 3,operationUnit = OperationUnit.USER,operationType = OperationType.SELECT)
@Override
public String findUserName(String tel) {
    System.out.println("tel:" + tel);
    return "zhangsan";
}

}`

DemoService.java

`package com.basic.bl.rest.demo.aop.service;
public interface DemoService {

/**
 * Get user information
 * @return
 * @param tel
 */
String findUserName(String tel);

}
`

Result



Execute before entering the method...
tel:1721212121
Log records: OperationLog {id='b8dc5682-0c68-4efb-9841-8a929dc91663', createTime=Tue Dec 03 00:45:26 CST 2019, level=3, operationUnit='user', method='com.basic.bl.rest.rest.demo.aop.service.impl.DemoServiceImpl.findUserName', args='[''172121212121''', userId='###{currentuserId}' ###{currentuserId}', userName}', userName}, level=3, 45:26 CST 2019, level=3, operationUnit='user'='#{currentUserName}', describe=''#{currentUserName}'= via mobile phoneNumber ["17212121"] Get user name', operationType='select', runTime=5, returnValue=''zhangsan'}
Method last executed...
Return value of method: zhangsan

Tags: Java REST JSON Mobile

Posted on Wed, 04 Dec 2019 17:01:27 -0500 by mjm7867