在@Value注解内使用SPEL自定义函数方式
作者:daijiguo
这篇文章主要介绍了在@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); }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。