1.业务背景
针对公司提供的对外接口,需要在系统内部进行管理。需要对内对外接口实现分离。
2.想法
1、针对对外接口本质就是接口文档,就无需提供增删改,仅供查询即可,数据存放数据库,请求头和请求体都是json字符串,另外就是请求类型 请求携带参数的方式。
2、提供增删改查功能,由前端凭借json,后端单表的crud
3、由于是系统内部接口,所以可以在程序启动或者某个点拦截代理获取的这些信息,存放到数据库
所以我就傻不拉几针对以第一三种方式开始我的码农生活。
3.实现
1.可以使用拦截和代理两种方式,我个人认为开机启动一次,设置拦截有点多余。所以我想法是在代理对象注册为容器的调用初始化方法这个点。
2.自定义注解
/**
* 外部接口自启动
*
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autorun {
}
3. 使用注解
@Autorun
@RestController
@RequestMapping("/system/foreign")
public class SysForeignUnstructTransferTaskController extends BaseController {}
4.定义说明注解
考虑到每个属性需要有说明,就像swagger定义了一个注解,逻辑就是通过类获取类的方法再去校验每个类上的注解和参数,通过参数有可以获取属性的上面注解的说明
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiExplain {
/**
* 说明
* @return
*/
String explain() default "";
/**
* 分组
* @return
*/
GroupType[] group() default {GroupType.ADD, GroupType.EDIT, GroupType.REMOVE, GroupType.SELECT};
enum GroupType {
ADD,
EDIT,
REMOVE,
SELECT
}
}
5.设置切面逻辑
@Aspect
@Component
public class AutorunAspect {
@Value("${server.port}")
private String port;
@Value("${server.host:localhost}")
private String host;
/**
* 存放方法需要的参数
*/
private static Map<String, String> param = new HashMap<>();
static {
param.put("/system/foreign/add/unstruct/transfer/task", "value" );
param.put("/system/foreign/edit/unstruct/transfer/task", "value2");
param.put("/system/foreign/remove/unstruct/transfer/task/2", "value2");
param.put("/system/foreign/get/unstruct/transfer/task/2", "value2");
param.put("/system/foreign/get/unstruct/transfer/task/list", "value2");
param.put("/system/foreign/copy/unstruct/transfer/task/2", "value2");
param.put("/system/foreign/switch/unstruct/transfer/task/2", "value2");
param.put("/system/foreign/export/unstruct/transfer/task/2", "value2");
}
@Before("@within(com.trinity.common.annotation.Autorun)")
public void before(JoinPoint joinPoint) {
StringBuffer prefix = new StringBuffer(String.format("http://%s:%s", host, port));
Class<?> targetClass = joinPoint.getTarget().getClass();
Method[] methods = targetClass.getDeclaredMethods();
if (targetClass.isAnnotationPresent(RequestMapping.class)){
prefix.append(targetClass.getAnnotation(RequestMapping.class).value()[0]);
}
for (Method method : methods) {
ApiManag apiManag = new ApiManag();
StringBuffer url = new StringBuffer(prefix);
apiManag.setVisibleScope(1L);
// 获取api的名字
if (method.isAnnotationPresent(ApiOperation.class)) {
ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
apiManag.setApiName(apiOperation.value());
}else {
apiManag.setApiName(method.getName());
}
if (method.isAnnotationPresent(GetMapping.class)) {
GetMapping getMapping = method.getAnnotation(GetMapping.class);
url.append(getMapping.value()[0]);
apiManag.setRequestMethod(1L);
}
if (method.isAnnotationPresent(DeleteMapping.class)) {
DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
url.append(deleteMapping.value()[0]);
apiManag.setRequestMethod(4L);
}
if (method.isAnnotationPresent(PostMapping.class)) {
PostMapping postMapping = method.getAnnotation(PostMapping.class);
url.append(postMapping.value()[0]);
apiManag.setRequestMethod(2L);
}
if (method.isAnnotationPresent(PutMapping.class)) {
PutMapping putMapping = method.getAnnotation(PutMapping.class);
url.append(putMapping.value()[0]);
apiManag.setRequestMethod(3L);
}
ApiExplain explain = getExplain(method);
apiManag.setRequestUrl(url.toString());
apiManag.setDescribe(explain == null ? "" : explain.explain());
}
}
/**
* 获取属性说明
* @param method
* @return
*/
private ApiExplain getExplain(Method method){
// 获取方法的参数类型
Class<?>[] paramTypes = method.getParameterTypes();
// 遍历参数类型数组
for (int i = 0; i < paramTypes.length; i++) {
// 获取类的所有字段(包括私有、保护、公共字段)
Field[] fields = paramTypes[i].getDeclaredFields();
// 遍历字段数组
for (Field field : fields) {
// 打印字段名和类型
// 检查字段上是否存在指定的注解
if (field.isAnnotationPresent(ApiExplain.class)) {
// 获取字段上的注解
return field.getAnnotation(ApiExplain.class);
}
}
}
return null;
}
}
6.失败
写到这,准备发送请求才发现这个行不通或者还得修改表的数据结构。因为要获取接口返回值,如果是写入操作务必对产生脏数据,所以还是单表crud 简单轻松。
4.总结
写的代码越多发现自己错的越多,但是辛苦绞尽脑汁的写的代码头大,想法都是出奇的奇怪。删了删了重写