# bin-router
**Repository Path**: tuhe32/bin-router
## Basic Information
- **Project Name**: bin-router
- **Description**: 扔掉Controller层,直接在Service注册接口,统一返回格式,统一异常处理。 无侵入实现API文档,接口文档。
- **Primary Language**: Java
- **License**: LGPL-2.1
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-11-24
- **Last Updated**: 2022-11-29
## Categories & Tags
**Categories**: Uncategorized
**Tags**: 路由封装, API接口文档, API
## README
# 工程简介
基于Spring的适配器路由,将原先的Controller层封装,直接在Service层暴露路由,兼容原有Controller写法。
- 直接在Service注册路由信息
- 自定义的接口返回格式封装
- 自定义异常处理
- 可生成routes全局路由表,intellij安装play2routes插件后,可以直接跳转到路由映射接口
- 可根据接口注释的@tag标签生成API文档,可导出到Apifox等接口文档管理软件中,方便mock和前端联调
# 使用说明
- 引用:Maven
  ```xml
  
    io.github.tuhe32
    adapter-api-spring-boot-starter
    1.0.5
  
  ```
- 基本使用:
  1、@GetApiMapping,@PostApiMapping等注解,注册相应路由(支持正则路由)
  2、在Service类上使用@ApiMapping("/xxx")可作为接口前缀
  2、@apiNote,@param,@return会自动整合到API接口文档中
  ```java
  /**
   * @apiNote 用户信息
   */
  @Service
  public class UserServiceImpl {
  
      /**
       * @apiNote 获取用户资料
       * @param userId 用户标识
       * @return 用户信息
       */
      @GetApiMapping(value = "/getUser")
      public UserInfo getUser(Long userId) {
          if (userId == 1) {
              throw new PlatformException("参数 'userId'不能为空");
          }
          return mock();
      }
  
      public UserInfo mock() {
          UserInfo info = new UserInfo();
          info.setName("小明");
          info.setSex("男");
          info.setUserId(111L);
          info.setIdcard("430527198108145443");
          return info;
      }
  
      /**
       * @apiNote 用户登录
       * @param userId 用户标识
       * @param password 用户密码
       * @return 用户信息
       */
      @GetApiMapping(value = "/login/{userId}/{password}")
      public UserInfo login(Long userId, String password)  {
          System.out.println("userId: "+userId);
          System.out.println("password: "+password);
          return mock();
      }
  
  }
  ```
- 生成routes全局路由表
  浏览器请求 http://127.0.0.1:[端口号]/doc/router,如http://127.0.0.1:8080/doc/router。
  访问后resources目录下会生成routes路由表文件
  
- 生成API文档
  浏览器请求 http://127.0.0.1:[端口号]/doc/api-json/[项目名] ,
  如http://127.0.0.1:8080/doc/api-json/shopAdmin。
  访问后resources目录下会生成基于OpenApi3.0格式的openapi.json文件,可导入到Apifox中实现接口的Mock以及前后端对接
- 自定义接口返回格式:1.实现ResponseProcessor接口,2.用@Component注解标记。
  ```java
  @Component
  public class ResponseTest implements ResponseProcessor {
  
      @Override
      public Object buildSuccess(Object t) {
          return Result.ok(t);
      }
  
      @Override
      public Object buildFailure(String errCode, String errMessage) {
          return Result.fail(Integer.parseInt(errCode), errMessage);
      }
  }
  ```
- 自定义异常处理:
  1.实现GlobalExceptionResolver接口
  2.用@Component注解标记,
  3.@ExceptionHandler(PlatformException.class)标记自定义异常处理方法
  4.@ResponseStatus(HttpStatus.OK)标记返回的HttpStatus
  ```java
  @Component
  public class GlobalExceptionHandler implements GlobalExceptionResolver {
      private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
  
      /**
       * 处理内部警告异常
       */
      @ExceptionHandler(PlatformException.class)
      @ResponseStatus(HttpStatus.OK)
      public Result handlePlatformException(PlatformException e) {
          logger.error("系统警告:{}",e.getMessage());
          if(e.getCode() == null) return Result.fail(e.getMessage());
          return Result.fail(e.getCode(),e.getMessage());
      }
  
  }
  ```
# 注意事项
- 支持Java Bean Validation,使用方式如下,【方法参数上只支持@Valid,不支持@Validated】
  ```java
  // 若没有接口,直接在实现类增加校验注解
  // 若类上有@Override,必须在父类或接口上写校验注解
  // 即使只有@Valid,类上也要用@Validated注解标记
  @Validated
  public interface UserService {
  
      UserInfo getUser(@NotNull @Min(1) Long userId);
  
      void saveUser(@NotNull @Valid UserInfo userInfo);
  
      UserInfo login(@NotNull @Positive Long userId, @NotNull String password);
  }
  ```
  ```java
  // 在参数实体增加检验注解
  public class UserInfo {
  
     @NotNull
     private String name;
  
     @NotNull
     @Positive
     private Long userId;
  
     private String sex;
  
     private String idcard;
  }
  ```
- 如果配置文件中设置了context-path,会使所有请求路径前强行增加/api前缀,需要增加设置
  ```yaml
  server:
    servlet:
      context-path: /api
     
  # 需要设置以下,不然会默认/api
  # 接口前缀设置
  adapter-api:
    apiPrefix:
    docUrlPrefix: /doc
  ```
# 延伸阅读
正则路由匹配问题参考:[fast-route](https://www.scienjus.com/fastroute-spring/ )
根据自带的tag生成API文档使用:[smart-doc](https://smart-doc-group.github.io/#/zh-cn/start/quickstart )
接口参数解析以及封装参考:[jfinal](https://jfinal.com/doc/3-3 )
重写springMvc的RequestMappingInfoHandlerMapping
项目整体思路参考one-api
默认返回结果封装成Response,使用了cola-component-dto工具包
默认异常处理,使用了cola-component-exception工具包