在@Value注解内使用SPEL自定义函数方式
作者:daijiguo 发布时间:2022-04-26 20:59:41
标签:@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);
? ? }
来源:https://daijiguo.blog.csdn.net/article/details/99403458


猜你喜欢
- 前言Spark Sql可以通过UDF来对DataFrame的Column进行自定义操作。在特定场景下定义UDF可能需要用到Spark Con
- 本文实例为大家分享了Android Camera实现可复用相机组件的具体代码,供大家参考,具体内容如下若自己的应用需要使用camera,有两
- 下面Demo中我使用了2种排序方式1.让Employee继承IComparable 接口,实现CompareTo方法排序2.定义一个方法使用
- SpringBoot2.3.1版本源码一、SpringBoot启动的时候加载主配置类,通过@EnableAutoConfiguration注解
- 在一些场合,我们往往需要使用印章来给每页文档加盖一个印章,以表示该文档经过某个部门的认证的,常规的做法就是打印文档后盖章,如果需要电子档再行
- vscode Java 开发环境配置博客地址VsCode官网教程系统需安装jdk1.8,配置好环境变量JAVA_HOME 打开vscode,
- Oracle的jdbc驱动三种主要分类:1、JDBC OCI: oci是oracle call interface的缩写,此驱动类似于传统的
- 本文实例讲述了Android TabLayout(选项卡布局)简单用法。分享给大家供大家参考,具体如下:我们在应用viewpager的时候,
- 本文实例讲述了Android编程入门之HelloWorld项目目录结构。分享给大家供大家参考,具体如下:我们介绍了如何搭建Android开发
- 存储访问框架,简称:SAF, 就是系统文件选择器+文件操作API。先选择文件,在用文件操作API处理文件。系统文件选择器,就和Windows
- 默认情况下Spring Boot使用了内嵌的Tomcat服务器,项目最终被打成jar包运行,每个jar包可以被看作一个独立的Web服务器。传
- 一个很常用的功能,一个ViewPager会自动滚动,并且有一排小圆点黑和白来指示当前的滚动进度首先写一个ViewPager的适配器,这里这个
- spring-mybatis获取mapper方式汇总项目背景:pojo下面有一个user实体类Dao包下面写了usermapper.xml
- 代码如下:/** * 动态生成SQ及SQL参数L * @param ve 接收到的消息的CHGLIST &nbs
- Java以命令模式设计模式1、简单介绍意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。主要解决:在软件系统中,行为
- Java集合的主要分为三种类型:• Set(集)• List(列表)• Map(映射)要深入理解集合首先要了解
- 原理简介 & OpenGL 的优势裸眼 3D 效果的本质是——将整个图片结构分为 3 层:上
- 前言今天在逛某知名论坛的时候,看到一篇"请不要使用包装类型,避免造成性能损失"的文章。一下子就吸引了我的注意。大意就是,
- 上一次自己写了一个多线程断点续传下载的demo,过于麻烦,bug超多,所以我学习使用xutils来完成此功能。先将xutils依赖搭建好(上
- 一、实现效果本篇文章实现了简单的图片轮播,初始化3张资源图片,初始化3秒更换一次图片背景,轮换播放。二、知识点Thread线程start()