首頁 > 軟體

在@Value註解內使用SPEL自定義函數方式

2022-02-17 13:01:20

@Value註解內使用SPEL自定義函數

@Value("#{T(com.cheetah.provider.utils.StringUtil).lower('${cluster.vendor.type}')}")

其中,${cluster.vendor.type}取的application.properties中的設定,com.cheetah.provider.utils.StringUtil#lower是使用者自定義函數,

T()運運算元的結果是一Class物件,它的真正價值在於它能夠存取目標型別的靜態方法和常數

自定義註解支援SpEL表示式

利用AOP生成使用者操作紀錄檔

1.定義紀錄檔註解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
    //普通的操作說明
    String value() default "";
    
    //spel表示式的操作說明
    String spelValue() default "";
}

2.定義spel解析工具類

public class SpelUtil {
    /**
     * 用於SpEL表示式解析.
     */
    private static SpelExpressionParser parser = new SpelExpressionParser();
    /**
     * 用於獲取方法引數定義名字.
     */
    private static DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
    public static String generateKeyBySpEL(String spELString, ProceedingJoinPoint joinPoint) {
        // 通過joinPoint獲取被註解方法
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        // 使用spring的DefaultParameterNameDiscoverer獲取方法形參名陣列
        String[] paramNames = nameDiscoverer.getParameterNames(method);
        // 解析過後的Spring表示式物件
        Expression expression = parser.parseExpression(spELString);
        // spring的表示式上下文物件
        EvaluationContext context = new StandardEvaluationContext();
        // 通過joinPoint獲取被註解方法的形參
        Object[] args = joinPoint.getArgs();
        // 給上下文賦值
        for (int i = 0; i < args.length; i++) {
            context.setVariable(paramNames[i], args[i]);
        }
        // 表示式從上下文中計算出實際引數值
        /*如:
            @annotation(key="#student.name")
             method(Student student)
             那麼就可以解析出方法形參的某屬性值,return 「xiaoming」;
          */
        return expression.getValue(context).toString();
    }
}

3.定義切面類

@Aspect
@Component
public class SysLogAspect {
    @Autowired
    private LogService logService;
    @Autowired
    private HttpServletRequest request;
    @Pointcut("@annotation(com.ztri.common.annotation.SysLog)")
    public void logPointCut() {
    }
    @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;
    }
    private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Log sysLog = new Log();
        sysLog.setTime(time);
        SysLog syslog = method.getAnnotation(SysLog.class);
        if (syslog != null) {
            //註解上的描述
            if (StrUtil.isNotBlank(syslog.value())) {
                sysLog.setOperation(syslog.value());
            }
            if (StrUtil.isNotBlank(syslog.spelValue())) {
                String spelValue = SpelUtil.generateKeyBySpEL(syslog.spelValue(), joinPoint);
                sysLog.setOperation(spelValue);
            }
        }
        //請求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setMethod(className + "." + methodName + "()");
        //請求的引數
        Object[] args = joinPoint.getArgs();
        try {
            String params = JSONUtil.toJsonStr(args);
            sysLog.setParams(params);
        } catch (Exception e) {
        }
        //設定IP地址
        sysLog.setIp(ServletUtil.getClientIP(request));
        UserAgent ua = UserAgentUtil.parse(request.getHeader("User-Agent"));
        sysLog.setBrowser(ua.getBrowser().toString());
        //儲存系統紀錄檔
        logService.create(sysLog);
    }
}

4.方法上使用紀錄檔註解

    @ApiOperation("高階搜尋(包含點選1.熱門列表 2.更多跳轉頁面)")
    @PostMapping("searchData")
    @SysLog(spelValue = "'高階搜尋' + #searchVo.keyWord")
    public ResponseEntity<Object> searchData(@RequestBody SearchVo searchVo) throws IOException {
        SearchDto searchDto = searchService.searchData(searchVo);
        return new ResponseEntity<>(searchDto, HttpStatus.OK);
    }
    @ApiOperation("登入授權")
    @PostMapping("/login")
    @SysLog("使用者登入")
    public ResponseEntity<Object> login(@Validated(User.Create.class) @RequestBody LoginUser loginUser) {
        return ResponseEntity.ok(authInfo);
    }

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com