java反射注解妙用-获取所有接口说明
转载请注明出处:https://www.cnblogs.com/wenjunwei/p/10293490.html
前言
最近在做项目权限,使用 shiro 实现 restful 接口权限管理,对整个项目都进行了重构。而权限管理需要用到所有的接口配置,包括接口 url 地址, 接口唯一编码等。想要收集所有的接口信息,如果工程接口很多,工作量可想而知。
这里用了反射,来获取所有接口的信息,接口再多,也不过几秒钟的事。
使用
Auth.java
接口信息对象
主要包括授权地址,权限唯一标识,权限名称,创建时间,请求方式
package com.wwj.springboot.model;import java.io.Serializable;
import java.util.Date;public class Auth implements Serializable {
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String authName; </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String authUrl; </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String authUniqueMark; </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Date createTime; </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String methodType; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">get set 省略</span>
}
UserController.java
用户接口
用于测试的接口。
这里使用了标准的 restful 接口风格,swagger 自动 API 接口,shiro 接口权限注解 @RequiresPermissions 组合成的一个 controller。当然也可以使用其他技术,只要能获取到接口信息就行。
注解不重要,重要的是注解里的信息。
package com.wwj.springboot.controller;import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/users")
@Api(value = "用户管理", tags = {"用户管理"})
public class UserController {@GetMapping @ApiOperation(</span>"获取列表"<span style="color: rgba(0, 0, 0, 1)">) @RequiresPermissions(</span>"user:list"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> list() { System.out.println(); } @GetMapping(path </span>= "/{userId}"<span style="color: rgba(0, 0, 0, 1)">) @ApiOperation(</span>"获取详情"<span style="color: rgba(0, 0, 0, 1)">) @RequiresPermissions(</span>"user:get"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> getUserById(@PathVariable("userId"<span style="color: rgba(0, 0, 0, 1)">) String userId) { System.out.println(); } @PostMapping @ApiOperation(</span>"新增一个用户"<span style="color: rgba(0, 0, 0, 1)">) @RequiresPermissions(</span>"user:save"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> save() { System.out.println(); } @PutMapping(</span>"/{userId}"<span style="color: rgba(0, 0, 0, 1)">) @ApiOperation(</span>"修改保存"<span style="color: rgba(0, 0, 0, 1)">) @RequiresPermissions(</span>"user:update"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> editSave(@PathVariable String userId) { System.out.println(); }
}
主函数
这里通过反射,获取了 UserController 的所有接口的说明,并存入数据库中。这是最主要的类。
1. 设置扫描的 package 路径
Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage(scanPackage)).setScanners(new MethodAnnotationsScanner()));
2. 获取到扫描包内带有 @RequiresPermissions 注解的所有方法集合
Set<Method> methods = reflections.getMethodsAnnotatedWith(RequiresPermissions.class);
3. 通过反射获取类上的注解
method.getDeclaringClass().getAnnotation(RequestMapping.class);
4. 通过反射获取方法上的注解
method.getAnnotation(PutMapping.class);
5. 获取注解中的某个属性 (这里是获取 value 属性)
method.getAnnotation(PutMapping.class).value();
完整的主函数代码
package com.wwj.springboot;import com.alibaba.fastjson.JSON;
import com.wwj.springboot.model.Auth;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.springframework.web.bind.annotation.*;import java.lang.reflect.Method;
public class AnnoTest {
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) { getRequestMappingMethod(</span>"com.wwj.springboot.controller"<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> scanPackage 需要扫描的包路径 </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> getRequestMappingMethod(String scanPackage) { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">设置扫描路径</span> Reflections reflections = <span style="color: rgba(0, 0, 255, 1)">new</span> Reflections(<span style="color: rgba(0, 0, 255, 1)">new</span> ConfigurationBuilder().setUrls(ClasspathHelper.forPackage(scanPackage)).setScanners(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MethodAnnotationsScanner())); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">扫描包内带有@RequiresPermissions注解的所有方法集合</span> Set<Method> methods = reflections.getMethodsAnnotatedWith(RequiresPermissions.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); List</span><Auth> list = <span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList<><span style="color: rgba(0, 0, 0, 1)">(); Date now </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">循环获取方法</span> methods.forEach(method -><span style="color: rgba(0, 0, 0, 1)"> { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">用于保存方法的请求类型</span> String methodType = ""<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取类上的@RequestMapping注解的值,作为请求的基础路径</span> String authUrl = method.getDeclaringClass().getAnnotation(RequestMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>).value()[0<span style="color: rgba(0, 0, 0, 1)">]; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取方法上的@PutMapping,@GetMapping,@PostMapping,@DeleteMapping注解的值,作为请求路径,并区分请求方式</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (method.getAnnotation(PutMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>) != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) { methodType </span>= "put"<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">if</span> (method.getAnnotation(PutMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>).value().length > 0<span style="color: rgba(0, 0, 0, 1)">) { authUrl </span>= method.getAnnotation(PutMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>).value()[0<span style="color: rgba(0, 0, 0, 1)">]; } } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (method.getAnnotation(GetMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>) != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) { methodType </span>= "get"<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">if</span> (method.getAnnotation(GetMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>).value().length > 0<span style="color: rgba(0, 0, 0, 1)">) { authUrl </span>= method.getAnnotation(GetMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>).value()[0<span style="color: rgba(0, 0, 0, 1)">]; } } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (method.getAnnotation(PostMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>) != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) { methodType </span>= "post"<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">if</span> (method.getAnnotation(PostMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>).value().length > 0<span style="color: rgba(0, 0, 0, 1)">) { authUrl </span>= method.getAnnotation(PostMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>).value()[0<span style="color: rgba(0, 0, 0, 1)">]; } } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (method.getAnnotation(DeleteMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>) != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) { </span><span style="color: rgba(0, 0, 255, 1)">if</span> (method.getAnnotation(DeleteMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>).value().length > 0<span style="color: rgba(0, 0, 0, 1)">) { authUrl </span>= method.getAnnotation(DeleteMapping.<span style="color: rgba(0, 0, 255, 1)">class</span>).value()[0<span style="color: rgba(0, 0, 0, 1)">]; } } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用Auth对象来保存值</span> Auth auth = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Auth(); auth.setMethodType(methodType); auth.setAuthUniqueMark(method.getAnnotation(RequiresPermissions.</span><span style="color: rgba(0, 0, 255, 1)">class</span>).value()[0<span style="color: rgba(0, 0, 0, 1)">]); auth.setAuthUrl(authUrl); auth.setAuthName(method.getDeclaringClass().getAnnotation(Api.</span><span style="color: rgba(0, 0, 255, 1)">class</span>).value() + "-" + method.getAnnotation(ApiOperation.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">).value()); auth.setCreateTime(now); list.add(auth); }); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">TODO 输出到控制台,此处存数据库即可</span>
System.out.println(JSON.toJSONString(list));
}
}
通过上面所说的方法即可获取到注解中的值,这样就可以获取到我们想要的接口信息了,执行结果如下
[{"authName":"用户管理 - 获取详情","authUniqueMark":"user:get","authUrl":"/users","createTime":1540977757616,"methodType":"get"}, {"authName":"用户管理 - 新增一个用户","authUniqueMark":"user:save","authUrl":"/users","createTime":1540977757616,"methodType":"post"}, {"authName":"用户管理 - 修改保存","authUniqueMark":"user:update","authUrl":"/{userId}","createTime":1540977757616,"methodType":"put"}, {"authName":"用户管理 - 获取列表","authUniqueMark":"user:list","authUrl":"/users","createTime":1540977757616,"methodType":"get"}]
感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮。本文欢迎各位转载,但是转载文章之后必须在文章开头给出原文链接。