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;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

public class AnnoTest {
</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&lt;Method&gt; methods = reflections.getMethodsAnnotatedWith(RequiresPermissions.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);

    List</span>&lt;Auth&gt; list = <span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList&lt;&gt;<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 -&gt;<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 &gt; 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 &gt; 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 &gt; 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 &gt; 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"}]

 

感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮。本文欢迎各位转载,但是转载文章之后必须在文章开头给出原文链接。