在@Value註解內使用SPEL自定義函數方式
@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); }
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- springboot通過spel結合aop實現動態傳參的案例
- 支持SpEL表達式的自定義日志註解@SysLog介紹
- 詳解Spring AOP自定義可重復註解沒有生效問題
- 基於SpringAop中JoinPoint對象的使用說明
- SpringBoot日志註解與緩存優化詳解