# japi-plus **Repository Path**: zhan_pu/japi-plus ## Basic Information - **Project Name**: japi-plus - **Description**: 基于一款快速集成springboot,适用于java接口开的starter - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-06-19 - **Last Updated**: 2025-03-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## japi-plus ### 描述 基于java+springboot快速集成接口开发的一款starter ### 使用说明 #### 引入maven坐标 ```xml top.v5it japi-plus-spring-boot-starter 0.0.1 ``` #### application.yml 配置 ```yml spring: japi: # 防XSS攻击配置 xss: enabled: true include-rich-text: true exclude: includes: - /** interceptor: # 配置自定义拦截器,clazz拦截器路径,order拦截器order序号,includes拦截器拦截地址,excludes排除不拦截地址 properties: - clazz: com.xx.yy.MyInterceptor order: 60 excludes: - /v1/produc - /v1/order # http请求自定义head名称前缀 head-prefix: Example # http请求token验证 token: enabled: true excludes: - /v1/example # 加解密算法 eada: algorithm: AES includes: - /** excludes: - /v1/example/post - /v1/example/get # http请求授权认证 authorized: diff-time: 6000 timeout: 10 type: HMAC_SHA256 # 自定义缓存key名称前缀 cache-prefix: example timeout: 3000 # 自定义异常全限定名称路径 exception-set: - top.v5it.japi.plus.support.limit.FrequencyLimitedException # 参数验证配置 validator: enabled: true fail-fast: true # id生成配置 idcenter: id-type: redis worker-id: 10 datacenter-id: 2 # http请求流量限制 limit: sliding_win # 初始化,数据缺失情况是否抛出异常 init: load-throw: false ssl: cert-filepath: /xxx/yyy.cer private-key-filepath: /xxx/yyy.der ``` #### 启动类 ```java @EnableJdbcAuditing @EnableJapiOperLog @EnableJapiLimit @EnableJapiWrapper @EntityScan @EnableJdbcRepositories @SpringBootApplication @Import({OperLogConfigurationSelector.class}) public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } } ``` ### 请求日志 > 在配置类上添加 @EnableJapiOperLog 启动操作日志记录 > > 在 Controller 类方法上面添加 @JapiOperLog("测试") 针对单个请求记录操作日志 > > 具体日志详情参考 top.v5it.japi.plus.log.OperLog 类 ### 请求限流 > 在配置类上添加 @EnableJapiLimit 启动限流 > > 1、在 Controller 类方法上面添加 @JapiLimit(limit = 5, time = 10) 针对单个请求10秒限制5次请求 > > 2、或在 Controller 类方法上面添加 @JapiLimit 添加resources/limit.cnf文件,文件写入具体限流参数[limit.cnf](#限流配置) > > 具体限流详情参考 top.v5it.japi.plus.support.limit.JapiLimit 类 > > 配置限流方式(count|sliding_win) > >```yml > spring: > japi: > limit: sliding_win > ``` #### 限流配置 ```text # 若引入“其他(统一controller)”全局配置[global],在没有具体配置按此全局限流,未引入可以不配置[global] [global] # controller方法请求地址,限止大小,时间,类型(GLOBAL|SIGNAL) query/{bean},120,60,GLOBAL orm/{bean}/{method},180,60,GLOBAL batch/{bean}/{method},80,60,GLOBAL [more] query/product,600,60,GLOBAL orm/product/add,300,60,GLOBAL v1/person/{id},2,5,GLOBAL ``` ### 统一响应 > 在配置类上添加 @EnableJapiWrapper 启动统一响应 > > 在 Controller 类方法上面添加 @JapiEada(isDecrypt = false) 针对单个请求响应结果 resource 中敏感信息进行加密并统一响应 > > 在 Controller 类上添加 @JapiEada(isDecrypt = false) 针对整个 Controller 中所有方法请求响应结果 resource 中敏感信息进行加密并统一响应 > > 在 Controller 类上或者类中方法上加 @JapiEada(isEncrypt = false, isDecrypt = false) 等同于默认不加 @JapiEada 注解,只统一响应 > >> - 响应失败示例 >> ``` >> HTTP/1.1 401 Unauthorized >> Connection: keep-alive >> Content-Type: application/json;charset=UTF-8 >> Content-Length: 59 >> Date: Wed, 20 Jul 2022 10:08:38 GMT >> >> { >> "message": "验证签名失败", >> "return_code": "SIGN_ERROR" >> } >> ``` > >> - 响应成功示例 >> ``` >> HTTP/1.1 200 OK >> Example-Channel: 65faf9e0803f41d0967ce9c4aa7e5563 >> Request-ID: af0b5bc8-75d0-4a8e-9c73-acd347cdf540 >> Example-Nonce: 4441145cb03549669ebc0db45f06dbcb >> Date: Wed, 20 Jul 2022 10:21:05 GMT >> Connection: keep-alive >> Transfer-Encoding: chunked >> Content-Type: application/json >> Example-Signature: ff0733a99b5c7460e26425c6e340d54c92324b65c27d4869712d5c7c3c6dbaea >> Example-Timestamp: 1658312465 >> >> { >> "id": 1, >> "name": "zhangshan", >> "sex": "男", >> "birthday": "1999-12-20", >> "resource": "uOnvViBfvkGM4Yx9Pb2QmIe6Sj/jJK0/qMxuqK5mDMkJdGJ9R8M0ar9uCmMoOCCKORX2aqbJpCY5WDe7vEiMdQ==", >> "resourceType": "ENCRYPT" >> } >> >> ``` > > 具体加解密详情参考 top.v5it.japi.plus.core.spring.web.JapiEada 类 ### 自定义拦截器 #### 实现自定义拦截器 ```java @Slf4j public class MyInterceptor extends AbstractJapiInterceptor { public MyInterceptor(OperLogService operLogService) { super(operLogService); log.info("MyInterceptor初始化成功"); } @Override protected void preHandle(HttpServletRequest request, HttpServletResponse response, long startTime) throws Exception { log.info("MyInterceptor#preHandle"); } @Override protected void prePostHandle(HttpServletRequest request, HttpServletResponse response, Map authMap, long startTime) throws Exception { log.info("MyInterceptor#prePostHandle"); } } ``` #### 加载自定义拦截器 > 在工程 resources 下面添加 META-INF/services/org.springframework.web.servlet.HandlerInterceptor 文件,写入自定义拦截器的包名和类名称(com.xx.yy.MyInterceptor) #### 配置自定义拦截器 ```yml spring: japi: interceptor: # 配置自定义拦截器,clazz拦截器路径,order拦截器order序号,includes拦截器拦截地址,excludes排除不拦截地址 properties: - clazz: com.xx.yy.MyInterceptor order: 60 excludes: - /v1/produc - /v1/order ``` ### 敏感信息加解密 #### 定义传输对象 ```java @Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) public class TestExampleDTO implements Serializable { private static final long serialVersionUID = 1356075427403479014L; private Long id; private String name; private String sex; private LocalDate birthday; private Resource resource; /** * 申明需要加解的密敏感信息放在Resource中 */ @Data public static class Resource { /** * 手机号 */ private String tel; /** * 身份证号 */ private String idNum; } } ``` #### 配置加解密算法(AES|RSA) ```yml spring: japi: interceptor: # 加解密算法 eada: algorithm: AES ``` #### [开启统一响应](#统一响应) ### API认证 #### 配置认证 ```yml spring: japi: interceptor: # http请求自定义head名称前缀 head-prefix: Example includes: - /** excludes: - /v1/example/post - /v1/example/get # http请求授权认证 authorized: diff-time: 6000 timeout: 10 type: HMAC_SHA256 ``` #### 认证类型 > >> SHA256_RSA2048 >> >> ``` >> Authorization: EXAMPLE-SHA256-RSA2048 signature=I4puMuoB3+FW/we87lBiAjLkW/aodvH0SIRCJGscsqYpV9NyRDW26nQscF3EYjgx7q7LnoLnkm28L+/pvpKMcsXgC+tz/Wf61dzuFWxSq15NuA1YHM9e+7Y3R2xdNLCJ25Kz/3/f3WcE/fRK7JS61V7KWSnopqx4KrJbvR9Nxs1t2VHrys0laFB10SJl/MUwk3TP86jd/eozEGA4ZOnBTdO756zjHQ3Gqcx8VtB0uhhKhXUQl/W5P4/f0B1sgpm/Y8EfOL7l/veAQQ695ePHR3DIyccIx85I0aK4kUDsuudbrwLocDC6ptcXW/FUJRDxzrqsNchmXeAQPFFarfqqAA==,serial_no=277758666191060001921921044729396318802466633735,timestamp=1655893653,nonce_str=fj790ijkjhoiufdu3jlf9uhdwk3jvlsnvoej,channel=0dae0b38284a4a7d9532908bc20cdab5 >> ``` >> >> HMAC_SHA256 >> >> ``` >> Authorization: EXAMPLE-HMAC-SHA256 signature=f049804df52eed2149b3b95ebffbc155e4080f94a67190656c33eadd78e08618,timestamp=1655882456,nonce_str=fjoej,channel=65faf9e0803f41d0967ce9c4aa7e5563 >> ``` ### 统一异常处理 #### 实现自定义异常 ```java public class ExampleException extends JapiException { public ExampleException() { } public ExampleException(ResultStatusTemplate resultStatusTemplate) { super(resultStatusTemplate); } public ExampleException(ResultStatusTemplate resultStatusTemplate, String messageTemplate, Object... params) { super(resultStatusTemplate, messageTemplate, params); } public ExampleException(ResultStatusTemplate resultStatusTemplate, Throwable cause, String messageTemplate, Object... params) { super(resultStatusTemplate, cause, messageTemplate, params); } public ExampleException(ResultStatusTemplate resultStatusTemplate, Throwable cause) { super(resultStatusTemplate, cause); } } ``` #### 配置异常 ```yml spring: japi: exception-set: - com.xx.yy.ExampleException ``` - 响应码说明 > 常见响应码参考 top.v5it.japi.plus.core.api.ResultStatus ### 参数检验 #### 编写检验规则 ```java @NotBlank(message = "用户名称不能为空") private String name; ``` > 常见检验规则 javax.validation.constraints 包路径下注解 #### 开启参数检验 ```yml spring: japi: validator: enabled: true fail-fast: true ``` ### 唯一ID #### 开启生成唯一ID(redis|snow) ```yml spring: japi: idcenter: id-type: snow worker-id: 10 datacenter-id: 2 ``` ### 其他(统一controller) > > 所有http请求按照(JapiQueryController|JapiOrmController|JapiBatchController)三个controller进入处理,引入系统无需再开发controller可以更专注业务与数据处理 > >> JapiQueryController:对应分页查询(query/{bean}),支持GET和POST方法[请求示例-分页查询](#分页查询) > >> JapiOrmController:对应CRUD操作(orm/{bean}/{method}),支持GET和POST方法[请求示例-CRUD操作](#CRUD操作) > >> JapiBatchController:对应批量操作(batch/{bean}/{method}),支持GET和POST方法[请求示例-批量操作](#批量操作) > > 如若拒绝某方法访问添加resources/deny.cnf文件,文件写入拒绝的某方法[deny.cnf](#拒绝请求配置) > #### 引入maven坐标 ```xml top.v5it japi-plus-extra 1.0 ``` #### 拒绝请求配置 ```text # 全局配置 [global] removeAllInBatch changeAllInBatch removeById remove count removeAll existsById exists removeInBatch searchAll # 账户配置 [product] searchProdut ``` #### 请求示例 ##### 分页查询 ```http request ### GET方法请求 GET http://localhost:7474/query/product?page=1&size=10&sort=desc&properties=createTime&name=book Content-Type: application/x-www-form-urlencoded Accept: application/json ### POST方法请求 GET http://localhost:7474/query/product Content-Type: application/json Accept: application/json { "page": 1, "size": 10, "sort": "desc", "properties": "createTime", "name": "book" } ``` ##### CRUD操作 ```http request ### GET方法请求 GET http://localhost:7474/orm/product/add?name=book&price=5000&quantity=10&remark=apple book&year=2020 Content-Type: application/x-www-form-urlencoded Accept: application/json ### POST方法请求 GET http://localhost:7474/orm/product/add Content-Type: application/json Accept: application/json { "price": 5000, "quantity": 10, "remark": "apple book", "year": 2020, "name": "book" } ``` ##### 批量操作 ```http request ### GET方法请求,一个集合参数 POST http://localhost:7474/batch/trade/addInBatch Content-Type: application/json Accept: application/json [ { "name": "adb", "amount": 10000 }, { "name": "ddb", "amount": 10000 } ] ### POST方法请求,第一个参数为集合参数,第二个参数为常量,其他参数按依次通过url传参 GET http://localhost:7474/batch/account/addInBatch?batchSize=100 Content-Type: application/json Accept: application/json [ { "name": "adb", "amount": 10000 }, { "name": "ddb", "amount": 10000 }, ... ] ```