mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 12:56:28 +08:00
5.1
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
# changelog
|
# changelog
|
||||||
|
|
||||||
|
## 5.1
|
||||||
|
|
||||||
|
接入smart-doc
|
||||||
|
|
||||||
## 5.0
|
## 5.0
|
||||||
|
|
||||||
全面重构,欢迎体验:[文档](https://www.yuque.com/u1604442/sop)
|
全面重构,欢迎体验:[文档](https://www.yuque.com/u1604442/sop)
|
||||||
|
@@ -84,6 +84,25 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<!-- 文档推送 -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.ly.smart-doc</groupId>
|
||||||
|
<artifactId>smart-doc-maven-plugin</artifactId>
|
||||||
|
<version>3.0.9</version>
|
||||||
|
<configuration>
|
||||||
|
<!--指定生成文档的使用的配置文件-->
|
||||||
|
<configFile>./src/main/resources/smart-doc.json</configFile>
|
||||||
|
<!--指定项目名称-->
|
||||||
|
<projectName>${project.artifactId}</projectName>
|
||||||
|
</configuration>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.gitee.sop</groupId>
|
||||||
|
<artifactId>sop-service-support</artifactId>
|
||||||
|
<version>5.0.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
1
sop-example/example-payment/push-doc.sh
Normal file
1
sop-example/example-payment/push-doc.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
mvn -Dfile.encoding=UTF-8 -Dcheckstyle.skip=true smart-doc:torna-rpc
|
@@ -5,29 +5,32 @@ import com.gitee.sop.payment.open.req.PayTradeWapPayRequest;
|
|||||||
import com.gitee.sop.payment.open.resp.PayOrderSearchResponse;
|
import com.gitee.sop.payment.open.resp.PayOrderSearchResponse;
|
||||||
import com.gitee.sop.payment.open.resp.PayTradeWapPayResponse;
|
import com.gitee.sop.payment.open.resp.PayTradeWapPayResponse;
|
||||||
import com.gitee.sop.support.annotation.Open;
|
import com.gitee.sop.support.annotation.Open;
|
||||||
import io.swagger.annotations.Api;
|
|
||||||
import io.swagger.annotations.ApiOperation;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付接口
|
* 支付接口
|
||||||
*
|
*
|
||||||
* @author 六如
|
* @author 六如
|
||||||
*/
|
*/
|
||||||
@Api("支付接口")
|
|
||||||
public interface OpenPayment {
|
public interface OpenPayment {
|
||||||
|
|
||||||
@ApiOperation(
|
/**
|
||||||
value = "手机网站支付接口",
|
* 手机网站支付接口
|
||||||
notes = "该接口是页面跳转接口,用于生成用户访问跳转链接。" +
|
*
|
||||||
"请在服务端执行SDK中pageExecute方法,读取响应中的body()结果。" +
|
* @apiNote 该接口是页面跳转接口,用于生成用户访问跳转链接。
|
||||||
"该结果用于跳转到页面,返回到用户浏览器渲染或重定向跳转到页面。" +
|
* 请在服务端执行SDK中pageExecute方法,读取响应中的body()结果。
|
||||||
"具体使用方法请参考 <a href=\"https://torna.cn\" target=\"_blank\">接入指南</a>"
|
* 该结果用于跳转到页面,返回到用户浏览器渲染或重定向跳转到页面。
|
||||||
)
|
* 具体使用方法请参考 <a href="https://torna.cn" target="_blank">接入指南</a>
|
||||||
|
*/
|
||||||
@Open("pay.trade.wap.pay")
|
@Open("pay.trade.wap.pay")
|
||||||
PayTradeWapPayResponse tradeWapPay(PayTradeWapPayRequest request);
|
PayTradeWapPayResponse tradeWapPay(PayTradeWapPayRequest request);
|
||||||
|
|
||||||
|
|
||||||
@ApiOperation(value = "订单查询接口")
|
/**
|
||||||
|
* 订单查询接口
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
@Open("pay.order.search")
|
@Open("pay.order.search")
|
||||||
PayOrderSearchResponse orderSearch(PayOrderSearchRequest request);
|
PayOrderSearchResponse orderSearch(PayOrderSearchRequest request);
|
||||||
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
package com.gitee.sop.payment.open.req;
|
package com.gitee.sop.payment.open.req;
|
||||||
|
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.hibernate.validator.constraints.Length;
|
import org.hibernate.validator.constraints.Length;
|
||||||
|
|
||||||
@@ -19,81 +18,93 @@ import java.util.List;
|
|||||||
public class PayTradeWapPayRequest {
|
public class PayTradeWapPayRequest {
|
||||||
|
|
||||||
|
|
||||||
@ApiModelProperty(value = "商户网站唯一订单号", required = true, example = "70501111111S001111119")
|
/**
|
||||||
|
* 商户网站唯一订单号
|
||||||
|
*
|
||||||
|
* @mock 70501111111S001111119
|
||||||
|
*/
|
||||||
@Length(max = 64)
|
@Length(max = 64)
|
||||||
@NotBlank(message = "商户网站唯一订单号必填")
|
@NotBlank(message = "商户网站唯一订单号必填")
|
||||||
private String outTradeNo;
|
private String outTradeNo;
|
||||||
|
|
||||||
@ApiModelProperty(value = "订单总金额.单位为元,精确到小数点后两位,取值范围:[0.01,100000000] ",
|
/**
|
||||||
required = true, example = "9.00")
|
* 订单总金额.单位为元,精确到小数点后两位,取值范围:[0.01,100000000]
|
||||||
|
*
|
||||||
|
* @mock 9.00
|
||||||
|
*/
|
||||||
@NotNull(message = "订单总金额不能为空")
|
@NotNull(message = "订单总金额不能为空")
|
||||||
private BigDecimal totalAmount;
|
private BigDecimal totalAmount;
|
||||||
|
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "订单标题。注意:不可使用特殊字符,如 /,=,& 等。",
|
* 订单标题。注意:不可使用特殊字符,如 /,=,& 等。
|
||||||
required = true,
|
*
|
||||||
example = "大乐透"
|
* @mock 大乐透
|
||||||
)
|
*/
|
||||||
@Length(max = 256)
|
@Length(max = 256)
|
||||||
@NotBlank(message = "订单标题不能为空")
|
@NotBlank(message = "订单标题不能为空")
|
||||||
private String subject;
|
private String subject;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "销售产品码,商家和支付平台签约的产品码。手机网站支付为:QUICK_WAP_WAY",
|
* 销售产品码,商家和支付平台签约的产品码。手机网站支付为:QUICK_WAP_WAY
|
||||||
required = true,
|
*
|
||||||
example = "QUICK_WAP_WAY"
|
* @mock QUICK_WAP_WAY
|
||||||
)
|
*/
|
||||||
@NotBlank(message = "销售产品码不能为空")
|
@NotBlank(message = "销售产品码不能为空")
|
||||||
@Length(max = 64)
|
@Length(max = 64)
|
||||||
private String productCode;
|
private String productCode;
|
||||||
|
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "针对用户授权接口,获取用户相关数据时,用于标识用户授权关系",
|
* 针对用户授权接口,获取用户相关数据时,用于标识用户授权关系
|
||||||
example = "appopenBb64d181d0146481ab6a762c00714cC27"
|
*
|
||||||
)
|
* @mock appopenBb64d181d0146481ab6a762c00714cC27
|
||||||
|
*/
|
||||||
@Length(max = 40)
|
@Length(max = 40)
|
||||||
private String authToken;
|
private String authToken;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "用户付款中途退出返回商户网站的地址",
|
* 用户付款中途退出返回商户网站的地址
|
||||||
example = "http://www.taobao.com/product/113714.html"
|
*
|
||||||
)
|
* @mock http://www.taobao.com/product/113714.html
|
||||||
|
*/
|
||||||
@Length(max = 400)
|
@Length(max = 400)
|
||||||
private String quit_url;
|
private String quit_url;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "订单包含的商品列表信息,json格式,其它说明详见商品明细说明"
|
* 订单包含的商品列表信息,json格式,其它说明详见商品明细说明
|
||||||
)
|
*/
|
||||||
private List<GoodsDetail> goodsDetail;
|
private List<GoodsDetail> goodsDetail;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "绝对超时时间,格式为yyyy-MM-dd HH:mm:ss。超时时间范围:1m~15d。",
|
* 绝对超时时间,格式为yyyy-MM-dd HH:mm:ss。超时时间范围:1m~15d。
|
||||||
example = "2016-12-31 10:05:00"
|
*
|
||||||
)
|
* @mock 2016-12-31 10:05:00
|
||||||
|
*/
|
||||||
@Length(max = 32)
|
@Length(max = 32)
|
||||||
private String timeExpire;
|
private String timeExpire;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "商户传入业务信息,具体值要和支付平台约定,应用于安全,营销等参数直传场景,格式为json格式",
|
* 商户传入业务信息,具体值要和支付平台约定,应用于安全,营销等参数直传场景,格式为json格式
|
||||||
example = "{\"mc_create_trade_ip\":\"127.0.0.1\"}"
|
*
|
||||||
)
|
* @mock {"mc_create_trade_ip":"127.0.0.1"}
|
||||||
|
*/
|
||||||
@Length(max = 512)
|
@Length(max = 512)
|
||||||
private String businessParams;
|
private String businessParams;
|
||||||
|
|
||||||
|
/**
|
||||||
@ApiModelProperty(
|
* 公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数。支付平台只会在同步返回(包括跳转回商户网站)和异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付平台。
|
||||||
value = "公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数。支付平台只会在同步返回(包括跳转回商户网站)和异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付平台。",
|
*
|
||||||
example = "merchantBizType%3d3C%26merchantBizNo%3d2016010101111"
|
* @mock merchantBizType%3d3C%26merchantBizNo%3d2016010101111
|
||||||
)
|
*/
|
||||||
@Length(max = 512)
|
@Length(max = 512)
|
||||||
private String passbackParams;
|
private String passbackParams;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "商户原始订单号,最大长度限制32位",
|
* 商户原始订单号,最大长度限制32位
|
||||||
example = "{\"mc_create_trade_ip\":\"127.0.0.1\"}"
|
*
|
||||||
)
|
* @mock {"mc_create_trade_ip":"127.0.0.1"}
|
||||||
|
*/
|
||||||
@Length(max = 32)
|
@Length(max = 32)
|
||||||
private String merchantOrderNo;
|
private String merchantOrderNo;
|
||||||
|
|
||||||
@@ -101,73 +112,78 @@ public class PayTradeWapPayRequest {
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class GoodsDetail {
|
public static class GoodsDetail {
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "商品的编号",
|
* 商品的编号
|
||||||
required = true,
|
*
|
||||||
example = "apple-01"
|
* @mock apple-01
|
||||||
)
|
*/
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@Length(max = 64)
|
@Length(max = 64)
|
||||||
private String goodsId;
|
private String goodsId;
|
||||||
|
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "商品名称",
|
* 商品名称
|
||||||
required = true,
|
*
|
||||||
example = "ipad"
|
* @mock ipad
|
||||||
)
|
*/
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@Length(max = 256)
|
@Length(max = 256)
|
||||||
private String goodsName;
|
private String goodsName;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "商品数量",
|
* 商品数量
|
||||||
required = true,
|
*
|
||||||
example = "1"
|
* @mock 1
|
||||||
)
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
private Integer quantity;
|
private Integer quantity;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "商品单价,单位为元",
|
* 商品单价,单位为元
|
||||||
required = true,
|
*
|
||||||
example = "2000"
|
* @mock 2000
|
||||||
)
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
private BigDecimal price;
|
private BigDecimal price;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "支付平台定义的统一商品编号",
|
* 支付平台定义的统一商品编号
|
||||||
example = "20010001"
|
*
|
||||||
)
|
* @mock 20010001
|
||||||
|
*/
|
||||||
@Length(max = 32)
|
@Length(max = 32)
|
||||||
private String alipayGoodsId;
|
private String alipayGoodsId;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "商品类目",
|
* 商品类目
|
||||||
example = "34543238"
|
*
|
||||||
)
|
* @mock 34543238
|
||||||
|
*/
|
||||||
@Length(max = 24)
|
@Length(max = 24)
|
||||||
private String goodsCategory;
|
private String goodsCategory;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "商品类目树,从商品类目根节点到叶子节点的类目id组成,类目id值使用|分割",
|
* 商品类目树,从商品类目根节点到叶子节点的类目id组成,类目id值使用|分割
|
||||||
example = "124868003|126232002|126252004"
|
*
|
||||||
)
|
* @mock 124868003|126232002|126252004
|
||||||
|
*/
|
||||||
@Length(max = 128)
|
@Length(max = 128)
|
||||||
private String categoriesTree;
|
private String categoriesTree;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "商品描述信息",
|
* 商品描述信息
|
||||||
example = "特价手机"
|
*
|
||||||
)
|
* @mock 特价手机
|
||||||
|
*/
|
||||||
@Length(max = 1000)
|
@Length(max = 1000)
|
||||||
private String body;
|
private String body;
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "商品的展示地址",
|
* 商品的展示地址
|
||||||
example = "http://www.alipay.com/xxx.jpg"
|
*
|
||||||
)
|
* @mock http://www.alipay.com/xxx.jpg
|
||||||
|
*/
|
||||||
@Length(max = 400)
|
@Length(max = 400)
|
||||||
private String showUrl;
|
private String showUrl;
|
||||||
|
|
||||||
|
@@ -1,19 +1,21 @@
|
|||||||
package com.gitee.sop.payment.open.resp;
|
package com.gitee.sop.payment.open.resp;
|
||||||
|
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 六如
|
* @author 六如
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class PayTradeWapPayResponse {
|
public class PayTradeWapPayResponse {
|
||||||
|
|
||||||
@ApiModelProperty(
|
/**
|
||||||
value = "用于跳转支付平台页面的信息,POST和GET方法生成内容不同:使用POST方法执行,结果为html form表单,在浏览器渲染即可;使用GET方法会得到支付平台URL,需要打开或重定向到该URL。建议使用POST方式。具体使用方法请参考",
|
* 用于跳转支付平台页面的信息,POST和GET方法生成内容不同:使用POST方法执行,结果为html form表单,在浏览器渲染即可<br>使用GET方法会得到支付平台URL,需要打开或重定向到该URL。建议使用POST方式。
|
||||||
required = true,
|
*
|
||||||
example = "请参考响应示例"
|
* @mock 请参考响应示例
|
||||||
)
|
*/
|
||||||
|
@NotNull
|
||||||
private String pageRedirectionData;
|
private String pageRedirectionData;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"framework": "sop",
|
||||||
|
"outPath": "target/doc",
|
||||||
|
"projectName": "项目",
|
||||||
|
"packageFilters": "com.gitee.sop.payment.open.*",
|
||||||
|
"openUrl": "http://localhost:7700/api", // torna服务器地址
|
||||||
|
"appToken": "34ff76952462413982d21219cf099d46", // torna应用token
|
||||||
|
"debugEnvName":"本地环境",
|
||||||
|
"debugEnvUrl":"http://127.0.0.1:8081",
|
||||||
|
"tornaDebug": true,
|
||||||
|
"replace": true,
|
||||||
|
"showValidation": false
|
||||||
|
}
|
@@ -89,6 +89,25 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<!-- 文档推送 -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.ly.smart-doc</groupId>
|
||||||
|
<artifactId>smart-doc-maven-plugin</artifactId>
|
||||||
|
<version>3.0.9</version>
|
||||||
|
<configuration>
|
||||||
|
<!--指定生成文档的使用的配置文件-->
|
||||||
|
<configFile>./src/main/resources/smart-doc.json</configFile>
|
||||||
|
<!--指定项目名称-->
|
||||||
|
<projectName>${project.artifactId}</projectName>
|
||||||
|
</configuration>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.gitee.sop</groupId>
|
||||||
|
<artifactId>sop-service-support</artifactId>
|
||||||
|
<version>5.0.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
@@ -13,13 +13,20 @@ import javax.validation.constraints.Size;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开放接口定义
|
* 故事服务
|
||||||
*
|
*
|
||||||
* @author 六如
|
* @author 六如
|
||||||
|
* @dubbo
|
||||||
*/
|
*/
|
||||||
@Api("故事服务")
|
@Api("故事服务")
|
||||||
public interface OpenStory {
|
public interface OpenStory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增故事
|
||||||
|
*
|
||||||
|
* @param storySaveRequest 入参
|
||||||
|
* @return 返回id
|
||||||
|
*/
|
||||||
@Open("story.save")
|
@Open("story.save")
|
||||||
Integer save(StorySaveRequest storySaveRequest);
|
Integer save(StorySaveRequest storySaveRequest);
|
||||||
|
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
package com.gitee.sop.storyweb.open.req;
|
package com.gitee.sop.storyweb.open.req;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.hibernate.validator.constraints.Length;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
@@ -14,9 +16,16 @@ import java.util.Date;
|
|||||||
public class StorySaveRequest implements Serializable {
|
public class StorySaveRequest implements Serializable {
|
||||||
private static final long serialVersionUID = -1214422742659231037L;
|
private static final long serialVersionUID = -1214422742659231037L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 故事名称
|
||||||
|
*/
|
||||||
@NotBlank(message = "故事名称必填")
|
@NotBlank(message = "故事名称必填")
|
||||||
|
@Length(max = 64)
|
||||||
private String storyName;
|
private String storyName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加时间
|
||||||
|
*/
|
||||||
@NotNull(message = "添加时间必填")
|
@NotNull(message = "添加时间必填")
|
||||||
private Date addTime;
|
private Date addTime;
|
||||||
|
|
||||||
|
13
sop-example/example-story/src/main/resources/smart-doc.json
Normal file
13
sop-example/example-story/src/main/resources/smart-doc.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"framework": "sop",
|
||||||
|
"outPath": "target/doc",
|
||||||
|
"projectName": "项目",
|
||||||
|
"packageFilters": "com.gitee.sop.storyweb.open.*",
|
||||||
|
"openUrl": "http://localhost:7700/api", // torna服务器地址
|
||||||
|
"appToken": "a358e4059b17440aae66343f4ec89001", // torna应用token
|
||||||
|
"debugEnvName":"本地环境",
|
||||||
|
"debugEnvUrl":"http://127.0.0.1:8081",
|
||||||
|
"tornaDebug": true,
|
||||||
|
"replace": true,
|
||||||
|
"showValidation": false
|
||||||
|
}
|
@@ -4,39 +4,52 @@ import com.gitee.sop.support.message.I18nMessage;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 六如
|
* @author 六如
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum CodeEnum implements I18nMessage {
|
public enum CodeEnum implements I18nMessage {
|
||||||
SUCCESS("0"),
|
SUCCESS("0", "成功"),
|
||||||
/**
|
/**
|
||||||
* 认证异常
|
* 认证异常
|
||||||
*/
|
*/
|
||||||
AUTH("20001"),
|
AUTH("20001", "认证异常"),
|
||||||
/**
|
/**
|
||||||
* 缺少参数
|
* 缺少参数
|
||||||
*/
|
*/
|
||||||
MISSING("40001"),
|
MISSING("40001", "缺少参数"),
|
||||||
/**
|
/**
|
||||||
* 错误参数
|
* 错误参数
|
||||||
*/
|
*/
|
||||||
INVALID("40002"),
|
INVALID("40002", "错误参数"),
|
||||||
/**
|
/**
|
||||||
* 业务异常
|
* 业务异常
|
||||||
*/
|
*/
|
||||||
BIZ("50003"),
|
BIZ("50003", "业务异常"),
|
||||||
/**
|
/**
|
||||||
* 权限异常
|
* 权限异常
|
||||||
*/
|
*/
|
||||||
ISV_PERM("40006"),
|
ISV_PERM("40006", "权限异常"),
|
||||||
/**
|
/**
|
||||||
* 未知异常
|
* 未知异常
|
||||||
*/
|
*/
|
||||||
UNKNOWN("99999");
|
UNKNOWN("99999", "未知异常");
|
||||||
|
|
||||||
private final String configKey;
|
private final String configKey;
|
||||||
|
private final String configValue;
|
||||||
|
|
||||||
|
public static CodeEnum of(String code) {
|
||||||
|
for (CodeEnum value : CodeEnum.values()) {
|
||||||
|
if (Objects.equals(value.configKey, code)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getCode() {
|
public String getCode() {
|
||||||
return configKey;
|
return configKey;
|
||||||
|
@@ -0,0 +1,79 @@
|
|||||||
|
package com.gitee.sop.gateway;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONWriter;
|
||||||
|
import com.gitee.sop.gateway.message.CodeEnum;
|
||||||
|
import com.gitee.sop.gateway.message.ErrorEnum;
|
||||||
|
import com.gitee.sop.support.message.OpenMessageFactory;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 六如
|
||||||
|
*/
|
||||||
|
public class ErrorCodePrintTest {
|
||||||
|
@Test
|
||||||
|
public void print() {
|
||||||
|
OpenMessageFactory.initMessage();
|
||||||
|
|
||||||
|
ErrorEnum[] values = ErrorEnum.values();
|
||||||
|
Map<String, List<ErrorEnum>> codeMap = Stream.of(values)
|
||||||
|
.collect(Collectors.groupingBy(ErrorEnum::getCode));
|
||||||
|
|
||||||
|
AtomicInteger id = new AtomicInteger();
|
||||||
|
List<ErrorInfo> errorList = codeMap.entrySet()
|
||||||
|
.stream()
|
||||||
|
.map(entry -> {
|
||||||
|
ErrorInfo errorInfo = new ErrorInfo();
|
||||||
|
errorInfo.setId(id.incrementAndGet());
|
||||||
|
errorInfo.setCode(entry.getKey());
|
||||||
|
errorInfo.setMsg(CodeEnum.of(entry.getKey()).getConfigValue());
|
||||||
|
|
||||||
|
List<SubError> collect = entry.getValue()
|
||||||
|
.stream()
|
||||||
|
.filter(errorEnum -> StringUtils.hasText(errorEnum.getSubCode()))
|
||||||
|
.map(errorEnum -> {
|
||||||
|
SubError subError = new SubError();
|
||||||
|
subError.setId(id.incrementAndGet());
|
||||||
|
subError.setSub_code(errorEnum.getSubCode());
|
||||||
|
subError.setSub_msg(errorEnum.getError(Locale.CHINESE).getSubMsg());
|
||||||
|
subError.setSolution("");
|
||||||
|
return subError;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
errorInfo.setChildren(collect);
|
||||||
|
|
||||||
|
return errorInfo;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
System.out.println(JSON.toJSONString(errorList, JSONWriter.Feature.PrettyFormat));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
static class ErrorInfo {
|
||||||
|
private Integer id;
|
||||||
|
private String code;
|
||||||
|
private String msg;
|
||||||
|
private List<SubError> children;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
static class SubError {
|
||||||
|
private Integer id;
|
||||||
|
private String sub_code;
|
||||||
|
private String sub_msg;
|
||||||
|
private String solution;
|
||||||
|
}
|
||||||
|
}
|
@@ -37,6 +37,12 @@
|
|||||||
<version>1.18.34</version>
|
<version>1.18.34</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- 文档生成 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.ly.smart-doc</groupId>
|
||||||
|
<artifactId>smart-doc</artifactId>
|
||||||
|
<version>3.0.9</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
|
@@ -0,0 +1,22 @@
|
|||||||
|
package com.gitee.sop.support.doc;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 六如
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class OpenAnnotationInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口名
|
||||||
|
*/
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 版本号
|
||||||
|
*/
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,235 @@
|
|||||||
|
package com.gitee.sop.support.doc;
|
||||||
|
|
||||||
|
import com.gitee.sop.support.doc.constants.OpenAnnotationConstants;
|
||||||
|
import com.gitee.sop.support.doc.helper.ParamsBuildHelper;
|
||||||
|
import com.ly.doc.builder.ProjectDocConfigBuilder;
|
||||||
|
import com.ly.doc.constants.DocGlobalConstants;
|
||||||
|
import com.ly.doc.constants.DocTags;
|
||||||
|
import com.ly.doc.constants.ParamTypeConstants;
|
||||||
|
import com.ly.doc.model.ApiConfig;
|
||||||
|
import com.ly.doc.model.ApiParam;
|
||||||
|
import com.ly.doc.model.RpcJavaMethod;
|
||||||
|
import com.ly.doc.model.annotation.FrameworkAnnotations;
|
||||||
|
import com.ly.doc.template.RpcDocBuildTemplate;
|
||||||
|
import com.ly.doc.utils.DocClassUtil;
|
||||||
|
import com.ly.doc.utils.DocUtil;
|
||||||
|
import com.ly.doc.utils.JavaClassUtil;
|
||||||
|
import com.ly.doc.utils.JavaClassValidateUtil;
|
||||||
|
import com.ly.doc.utils.JavaFieldUtil;
|
||||||
|
import com.power.common.util.StringUtil;
|
||||||
|
import com.thoughtworks.qdox.model.JavaAnnotation;
|
||||||
|
import com.thoughtworks.qdox.model.JavaClass;
|
||||||
|
import com.thoughtworks.qdox.model.JavaMethod;
|
||||||
|
import com.thoughtworks.qdox.model.JavaParameter;
|
||||||
|
import com.thoughtworks.qdox.model.JavaType;
|
||||||
|
import com.thoughtworks.qdox.model.expression.AnnotationValue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析文档
|
||||||
|
* <p>
|
||||||
|
* 参考:<a href="https://smart-doc-group.github.io/zh/guide/advanced/expand">smart-doc扩展</a>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author 六如
|
||||||
|
*/
|
||||||
|
public class SopDocBuildTemplate extends RpcDocBuildTemplate {
|
||||||
|
|
||||||
|
public static final String DEFAULT_VERSION = "1.0";
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsFramework(String s) {
|
||||||
|
return "sop".equalsIgnoreCase(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ApiParam> requestParams(final JavaMethod javaMethod, ProjectDocConfigBuilder builder,
|
||||||
|
AtomicInteger atomicInteger, Map<String, JavaType> actualTypesMap) {
|
||||||
|
boolean isStrict = builder.getApiConfig().isStrict();
|
||||||
|
boolean isShowJavaType = builder.getApiConfig().getShowJavaType();
|
||||||
|
boolean isShowValidation = builder.getApiConfig().isShowValidation();
|
||||||
|
String className = javaMethod.getDeclaringClass().getCanonicalName();
|
||||||
|
Map<String, String> paramTagMap = DocUtil.getCommentsByTag(javaMethod, DocTags.PARAM, className);
|
||||||
|
List<JavaParameter> parameterList = javaMethod.getParameters();
|
||||||
|
if (parameterList.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ClassLoader classLoader = builder.getApiConfig().getClassLoader();
|
||||||
|
List<ApiParam> paramList = new ArrayList<>();
|
||||||
|
ParamsBuildHelper paramsBuildHelper = new ParamsBuildHelper();
|
||||||
|
for (JavaParameter parameter : parameterList) {
|
||||||
|
boolean required = false;
|
||||||
|
String paramName = parameter.getName();
|
||||||
|
String typeName = this.replaceTypeName(parameter.getType().getGenericCanonicalName(), actualTypesMap,
|
||||||
|
Boolean.FALSE);
|
||||||
|
String simpleName = this.replaceTypeName(parameter.getType().getValue(), actualTypesMap, Boolean.FALSE)
|
||||||
|
.toLowerCase();
|
||||||
|
String fullTypeName = this.replaceTypeName(parameter.getType().getFullyQualifiedName(), actualTypesMap,
|
||||||
|
Boolean.FALSE);
|
||||||
|
String paramPre = "";
|
||||||
|
if (!paramTagMap.containsKey(paramName) && JavaClassValidateUtil.isPrimitive(fullTypeName) && isStrict) {
|
||||||
|
throw new RuntimeException("ERROR: Unable to find javadoc @param for actual param \"" + paramName
|
||||||
|
+ "\" in method " + javaMethod.getName() + " from " + className);
|
||||||
|
}
|
||||||
|
StringBuilder comment = new StringBuilder(this.paramCommentResolve(paramTagMap.get(paramName)));
|
||||||
|
String mockValue = JavaFieldUtil.createMockValue(paramTagMap, paramName, typeName, typeName);
|
||||||
|
JavaClass javaClass = builder.getJavaProjectBuilder().getClassByName(fullTypeName);
|
||||||
|
List<JavaAnnotation> annotations = parameter.getAnnotations();
|
||||||
|
for (JavaAnnotation a : annotations) {
|
||||||
|
if (JavaClassValidateUtil.isJSR303Required(a.getType().getValue())) {
|
||||||
|
required = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
comment.append(JavaFieldUtil.getJsrComment(isShowValidation, classLoader, annotations));
|
||||||
|
Set<String> groupClasses = JavaClassUtil.getParamGroupJavaClass(annotations,
|
||||||
|
builder.getJavaProjectBuilder());
|
||||||
|
Set<String> paramJsonViewClasses = JavaClassUtil.getParamJsonViewClasses(annotations, builder);
|
||||||
|
if (JavaClassValidateUtil.isCollection(fullTypeName) || JavaClassValidateUtil.isArray(fullTypeName)) {
|
||||||
|
if (JavaClassValidateUtil.isCollection(typeName)) {
|
||||||
|
typeName = typeName + "<T>";
|
||||||
|
}
|
||||||
|
String[] gicNameArr = DocClassUtil.getSimpleGicName(typeName);
|
||||||
|
String gicName = gicNameArr[0];
|
||||||
|
if (JavaClassValidateUtil.isArray(gicName)) {
|
||||||
|
gicName = gicName.substring(0, gicName.indexOf("["));
|
||||||
|
}
|
||||||
|
if (JavaClassValidateUtil.isPrimitive(gicName)) {
|
||||||
|
String processedType = isShowJavaType ? JavaClassUtil.getClassSimpleName(typeName)
|
||||||
|
: DocClassUtil.processTypeNameForParams(simpleName);
|
||||||
|
ApiParam param = ApiParam.of()
|
||||||
|
.setId(atomicInteger.incrementAndGet())
|
||||||
|
.setField(paramName)
|
||||||
|
.setDesc(comment + " (children type : " + gicName + ")")
|
||||||
|
.setRequired(required)
|
||||||
|
.setType(processedType);
|
||||||
|
paramList.add(param);
|
||||||
|
} else {
|
||||||
|
paramList.addAll(paramsBuildHelper.buildParams(gicNameArr[0], paramPre, 0, "true", Boolean.FALSE,
|
||||||
|
new HashMap<>(16), builder, groupClasses, paramJsonViewClasses, 0, Boolean.FALSE,
|
||||||
|
atomicInteger));
|
||||||
|
}
|
||||||
|
} else if (JavaClassValidateUtil.isPrimitive(fullTypeName)) {
|
||||||
|
ApiParam param = ApiParam.of()
|
||||||
|
.setId(atomicInteger.incrementAndGet())
|
||||||
|
.setField(paramName)
|
||||||
|
.setType(JavaClassUtil.getClassSimpleName(typeName))
|
||||||
|
.setDesc(comment.toString())
|
||||||
|
.setRequired(required)
|
||||||
|
.setMaxLength(JavaFieldUtil.getParamMaxLength(parameter.getAnnotations()))
|
||||||
|
.setValue(mockValue)
|
||||||
|
.setVersion(DocGlobalConstants.DEFAULT_VERSION);
|
||||||
|
paramList.add(param);
|
||||||
|
} else if (JavaClassValidateUtil.isMap(fullTypeName)) {
|
||||||
|
if (JavaClassValidateUtil.isMap(typeName)) {
|
||||||
|
ApiParam apiParam = ApiParam.of()
|
||||||
|
.setId(atomicInteger.incrementAndGet())
|
||||||
|
.setField(paramName)
|
||||||
|
.setType(typeName)
|
||||||
|
.setDesc(comment.toString())
|
||||||
|
.setRequired(required)
|
||||||
|
.setVersion(DocGlobalConstants.DEFAULT_VERSION);
|
||||||
|
paramList.add(apiParam);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String[] gicNameArr = DocClassUtil.getSimpleGicName(typeName);
|
||||||
|
paramList.addAll(paramsBuildHelper.buildParams(gicNameArr[1], paramPre, 0, "true", Boolean.FALSE,
|
||||||
|
new HashMap<>(16), builder, groupClasses, paramJsonViewClasses, 0, Boolean.FALSE,
|
||||||
|
atomicInteger));
|
||||||
|
} else if (javaClass.isEnum()) {
|
||||||
|
ApiParam param = ApiParam.of()
|
||||||
|
.setId(atomicInteger.incrementAndGet())
|
||||||
|
.setField(paramName)
|
||||||
|
.setType(ParamTypeConstants.PARAM_TYPE_ENUM)
|
||||||
|
.setRequired(required)
|
||||||
|
.setDesc(comment.toString())
|
||||||
|
.setVersion(DocGlobalConstants.DEFAULT_VERSION);
|
||||||
|
paramList.add(param);
|
||||||
|
} else {
|
||||||
|
List<ApiParam> aTrue = paramsBuildHelper.buildParams(typeName, paramPre, 0, "true", Boolean.FALSE, new HashMap<>(16),
|
||||||
|
builder, groupClasses, paramJsonViewClasses, 0, Boolean.FALSE, atomicInteger);
|
||||||
|
|
||||||
|
paramList.addAll(
|
||||||
|
aTrue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return paramList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RpcJavaMethod convertToJavadocJavaMethod(ApiConfig apiConfig, JavaMethod method, Map<String, JavaType> actualTypesMap) {
|
||||||
|
RpcJavaMethod rpcJavaMethod = super.convertToJavadocJavaMethod(apiConfig, method, actualTypesMap);
|
||||||
|
Optional<OpenAnnotationInfo> openAnnotationInfoOpt = getOpenAnnotationInfo(method);
|
||||||
|
rpcJavaMethod.setVersion(openAnnotationInfoOpt.map(OpenAnnotationInfo::getVersion).orElse(DEFAULT_VERSION));
|
||||||
|
|
||||||
|
String desc = DocUtil.getEscapeAndCleanComment(method.getComment());
|
||||||
|
if (StringUtil.isEmpty(desc)) {
|
||||||
|
desc = openAnnotationInfoOpt.map(OpenAnnotationInfo::getValue).orElse("");
|
||||||
|
}
|
||||||
|
rpcJavaMethod.setDesc(desc);
|
||||||
|
return rpcJavaMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回接口名称+版本号
|
||||||
|
// 格式:接口名称#版本号
|
||||||
|
@Override
|
||||||
|
public String methodDefinition(JavaMethod method, Map<String, JavaType> actualTypesMap) {
|
||||||
|
return getOpenAnnotationInfo(method)
|
||||||
|
.map(this::buildUrl)
|
||||||
|
.orElseThrow(() -> new RuntimeException("未指定@Open"));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String buildUrl(OpenAnnotationInfo openAnnotationInfo) {
|
||||||
|
return openAnnotationInfo.getValue() + "#" + openAnnotationInfo.getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getVersion(JavaMethod method) {
|
||||||
|
return getOpenAnnotationInfo(method).map(OpenAnnotationInfo::getVersion)
|
||||||
|
.orElse(DEFAULT_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Optional<OpenAnnotationInfo> getOpenAnnotationInfo(JavaMethod method) {
|
||||||
|
List<JavaAnnotation> annotations = method.getAnnotations();
|
||||||
|
for (JavaAnnotation annotation : annotations) {
|
||||||
|
String simpleAnnotationName = annotation.getType().getValue();
|
||||||
|
if (OpenAnnotationConstants.OPEN_ANNOTATION_NAME.equalsIgnoreCase(simpleAnnotationName)) {
|
||||||
|
AnnotationValue value = annotation.getProperty(OpenAnnotationConstants.PROP_VALUE);
|
||||||
|
AnnotationValue version = annotation.getProperty(OpenAnnotationConstants.PROP_VERSION);
|
||||||
|
OpenAnnotationInfo openAnnotationInfo = new OpenAnnotationInfo();
|
||||||
|
openAnnotationInfo.setValue(StringUtil.removeQuotes(value.toString()));
|
||||||
|
openAnnotationInfo.setVersion(Optional.ofNullable(version)
|
||||||
|
.map(annotationValue -> StringUtil.removeQuotes(annotationValue.toString()))
|
||||||
|
.orElse(DEFAULT_VERSION));
|
||||||
|
return Optional.of(openAnnotationInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEntryPoint(JavaClass javaClass, FrameworkAnnotations frameworkAnnotations) {
|
||||||
|
// 必须是接口
|
||||||
|
if (!javaClass.isInterface()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<JavaMethod> methods = javaClass.getMethods();
|
||||||
|
if (methods == null || methods.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (JavaMethod method : methods) {
|
||||||
|
if (getOpenAnnotationInfo(method).isPresent()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,13 @@
|
|||||||
|
package com.gitee.sop.support.doc.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author 六如
|
||||||
|
*/
|
||||||
|
public class OpenAnnotationConstants {
|
||||||
|
|
||||||
|
public static final String OPEN_ANNOTATION_NAME = "Open";
|
||||||
|
|
||||||
|
public static final String PROP_VALUE = "value";
|
||||||
|
|
||||||
|
public static final String PROP_VERSION = "version";
|
||||||
|
}
|
@@ -0,0 +1,295 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2024 smart-doc
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package com.gitee.sop.support.doc.helper;
|
||||||
|
|
||||||
|
import com.ly.doc.builder.ProjectDocConfigBuilder;
|
||||||
|
import com.ly.doc.constants.DocAnnotationConstants;
|
||||||
|
import com.ly.doc.constants.DocTags;
|
||||||
|
import com.ly.doc.constants.JSRAnnotationConstants;
|
||||||
|
import com.ly.doc.model.CustomField;
|
||||||
|
import com.ly.doc.model.CustomFieldInfo;
|
||||||
|
import com.ly.doc.model.DocJavaField;
|
||||||
|
import com.ly.doc.model.FieldJsonAnnotationInfo;
|
||||||
|
import com.ly.doc.utils.DocUtil;
|
||||||
|
import com.ly.doc.utils.JavaClassUtil;
|
||||||
|
import com.ly.doc.utils.JavaClassValidateUtil;
|
||||||
|
import com.power.common.util.CollectionUtil;
|
||||||
|
import com.power.common.util.StringEscapeUtil;
|
||||||
|
import com.power.common.util.StringUtil;
|
||||||
|
import com.thoughtworks.qdox.model.JavaAnnotation;
|
||||||
|
import com.thoughtworks.qdox.model.JavaField;
|
||||||
|
import com.thoughtworks.qdox.model.expression.AnnotationValue;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract Base helper
|
||||||
|
*
|
||||||
|
* @author yu3.sun on 2022/10/14
|
||||||
|
*/
|
||||||
|
public abstract class BaseHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get field value from mock tag
|
||||||
|
*
|
||||||
|
* @param subTypeName subType name
|
||||||
|
* @param tagsMap tags map
|
||||||
|
* @param typeSimpleName type simple name
|
||||||
|
* @return field value
|
||||||
|
*/
|
||||||
|
protected String getFieldValueFromMockForJson(String subTypeName, Map<String, String> tagsMap,
|
||||||
|
String typeSimpleName) {
|
||||||
|
String fieldValue = "";
|
||||||
|
if (tagsMap.containsKey(DocTags.MOCK) && StringUtil.isNotEmpty(tagsMap.get(DocTags.MOCK))) {
|
||||||
|
fieldValue = tagsMap.get(DocTags.MOCK);
|
||||||
|
fieldValue = StringEscapeUtil.unescapeJava(fieldValue);
|
||||||
|
if (!DocUtil.javaPrimaryType(typeSimpleName) && !JavaClassValidateUtil.isCollection(subTypeName)
|
||||||
|
&& !JavaClassValidateUtil.isMap(subTypeName) && !JavaClassValidateUtil.isArray(subTypeName)) {
|
||||||
|
fieldValue = StringEscapeUtil.escapeJava(fieldValue, true);
|
||||||
|
fieldValue = DocUtil.handleJsonStr(fieldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get field value from mock tag
|
||||||
|
*
|
||||||
|
* @param tagsMap tags map
|
||||||
|
* @return field value
|
||||||
|
*/
|
||||||
|
protected String getFieldValueFromMock(Map<String, String> tagsMap) {
|
||||||
|
String fieldValue = "";
|
||||||
|
if (tagsMap.containsKey(DocTags.MOCK) && StringUtil.isNotEmpty(tagsMap.get(DocTags.MOCK))) {
|
||||||
|
fieldValue = StringEscapeUtil.unescapeJava(tagsMap.get(DocTags.MOCK));
|
||||||
|
}
|
||||||
|
return fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check custom field is ignored
|
||||||
|
*
|
||||||
|
* @param docField doc field
|
||||||
|
* @param isResp is resp
|
||||||
|
* @param customRequestField custom request field
|
||||||
|
* @param customResponseField custom response field
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected boolean isIgnoreCustomField(DocJavaField docField, boolean isResp, CustomField customRequestField,
|
||||||
|
CustomField customResponseField) {
|
||||||
|
if (Objects.nonNull(customRequestField) && JavaClassUtil.isTargetChildClass(docField.getDeclaringClassName(),
|
||||||
|
customRequestField.getOwnerClassName()) && (customRequestField.isIgnore()) && !isResp) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return Objects.nonNull(customResponseField) && JavaClassUtil
|
||||||
|
.isTargetChildClass(docField.getDeclaringClassName(), customResponseField.getOwnerClassName())
|
||||||
|
&& (customResponseField.isIgnore()) && isResp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check field is transient
|
||||||
|
*
|
||||||
|
* @param field field
|
||||||
|
* @param projectBuilder project builder
|
||||||
|
* @param isResp is resp
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected boolean isTransientField(JavaField field, ProjectDocConfigBuilder projectBuilder, boolean isResp) {
|
||||||
|
if (field.isTransient()) {
|
||||||
|
return (projectBuilder.getApiConfig().isSerializeRequestTransients() && !isResp)
|
||||||
|
|| (projectBuilder.getApiConfig().isSerializeResponseTransients() && isResp);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a field JSON annotation information for a given field.
|
||||||
|
*
|
||||||
|
* @param projectBuilder the project builder
|
||||||
|
* @param docField the doc of java field
|
||||||
|
* @param isResp the response flag for the parameter
|
||||||
|
* @param groupClasses the group classes
|
||||||
|
* @param methodJsonViewClasses the method JSON view classes
|
||||||
|
* @return the field JSON annotation information {@link FieldJsonAnnotationInfo}
|
||||||
|
*/
|
||||||
|
protected FieldJsonAnnotationInfo getFieldJsonAnnotationInfo(ProjectDocConfigBuilder projectBuilder,
|
||||||
|
DocJavaField docField, boolean isResp, Set<String> groupClasses, Set<String> methodJsonViewClasses) {
|
||||||
|
FieldJsonAnnotationInfo fieldJsonAnnotationInfo = new FieldJsonAnnotationInfo();
|
||||||
|
// Handle @JsonView; if the field is not annotated with @JsonView, skip
|
||||||
|
if (!methodJsonViewClasses.isEmpty() && isResp && docField.getAnnotations().isEmpty()) {
|
||||||
|
return fieldJsonAnnotationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (JavaAnnotation annotation : docField.getAnnotations()) {
|
||||||
|
// if the field is annotated with @JsonIgnore || @JsonProperty, then
|
||||||
|
// check if it belongs to the groupClasses
|
||||||
|
if (JavaClassValidateUtil.isIgnoreFieldJson(annotation, isResp)) {
|
||||||
|
fieldJsonAnnotationInfo.setIgnore(true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Handle @JsonView
|
||||||
|
if (JavaClassUtil.shouldExcludeFieldFromJsonView(annotation, methodJsonViewClasses, isResp,
|
||||||
|
projectBuilder)) {
|
||||||
|
fieldJsonAnnotationInfo.setIgnore(true);
|
||||||
|
return fieldJsonAnnotationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
String annotationName = annotation.getType().getValue();
|
||||||
|
// if the field is annotated with @JsonSerialize
|
||||||
|
if (DocAnnotationConstants.SHORT_JSON_SERIALIZE.equals(annotationName)
|
||||||
|
&& DocAnnotationConstants.TO_STRING_SERIALIZER_USING
|
||||||
|
.equals(annotation.getNamedParameter(DocAnnotationConstants.USING_PROP))) {
|
||||||
|
fieldJsonAnnotationInfo.setToStringSerializer(true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// if the field is annotated with @Null And isResp is false
|
||||||
|
if (JSRAnnotationConstants.NULL.equals(annotationName) && !isResp) {
|
||||||
|
if (CollectionUtil.isEmpty(groupClasses)) {
|
||||||
|
fieldJsonAnnotationInfo.setIgnore(true);
|
||||||
|
return fieldJsonAnnotationInfo;
|
||||||
|
}
|
||||||
|
Set<String> groupClassList = JavaClassUtil.getParamGroupJavaClass(annotation);
|
||||||
|
for (String javaClass : groupClassList) {
|
||||||
|
if (groupClasses.contains(javaClass)) {
|
||||||
|
fieldJsonAnnotationInfo.setIgnore(true);
|
||||||
|
return fieldJsonAnnotationInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle @JSONField
|
||||||
|
if (DocAnnotationConstants.SHORT_JSON_FIELD.equals(annotationName)) {
|
||||||
|
if (null != annotation.getProperty(DocAnnotationConstants.NAME_PROP)) {
|
||||||
|
AnnotationValue annotationValue = annotation.getProperty(DocAnnotationConstants.NAME_PROP);
|
||||||
|
String fieldName = DocUtil.resolveAnnotationValue(projectBuilder.getApiConfig().getClassLoader(),
|
||||||
|
annotationValue);
|
||||||
|
fieldJsonAnnotationInfo.setFieldName(fieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle @JsonProperty
|
||||||
|
else if (DocAnnotationConstants.SHORT_JSON_PROPERTY.equals(annotationName)
|
||||||
|
|| DocAnnotationConstants.GSON_ALIAS_NAME.equals(annotationName)) {
|
||||||
|
AnnotationValue annotationValue = annotation.getProperty(DocAnnotationConstants.VALUE_PROP);
|
||||||
|
String fieldName = DocUtil.resolveAnnotationValue(projectBuilder.getApiConfig().getClassLoader(),
|
||||||
|
annotationValue);
|
||||||
|
fieldJsonAnnotationInfo.setFieldName(fieldName);
|
||||||
|
}
|
||||||
|
// Handle JSR303 required
|
||||||
|
if (JavaClassValidateUtil.isJSR303Required(annotationName) && !isResp) {
|
||||||
|
Set<String> groupClassList = JavaClassUtil.getParamGroupJavaClass(annotation);
|
||||||
|
// Check if groupClasses contains any element from
|
||||||
|
// groupClassList
|
||||||
|
boolean hasGroup = groupClassList.stream().anyMatch(groupClasses::contains);
|
||||||
|
|
||||||
|
if (hasGroup) {
|
||||||
|
fieldJsonAnnotationInfo.setStrRequired(true);
|
||||||
|
} else if (CollectionUtil.isEmpty(groupClasses)) {
|
||||||
|
// If the annotation is @Valid or @Validated, the Default
|
||||||
|
// group is added by default and groupClasses will not be
|
||||||
|
// empty;
|
||||||
|
// In other cases, if groupClasses is still empty, then
|
||||||
|
// strRequired is false.
|
||||||
|
fieldJsonAnnotationInfo.setStrRequired(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Handle @JsonFormat
|
||||||
|
if (DocAnnotationConstants.JSON_FORMAT.equals(annotationName)) {
|
||||||
|
fieldJsonAnnotationInfo.setFieldJsonFormatType(
|
||||||
|
DocUtil.processFieldTypeNameByJsonFormat(projectBuilder.getApiConfig().getShowJavaType(),
|
||||||
|
docField.getTypeFullyQualifiedName(), annotation));
|
||||||
|
fieldJsonAnnotationInfo
|
||||||
|
.setFieldJsonFormatValue(DocUtil.getJsonFormatString(docField.getJavaField(), annotation));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return fieldJsonAnnotationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the custom field information for a given field.
|
||||||
|
*
|
||||||
|
* @param projectBuilder the project builder
|
||||||
|
* @param docField the doc of java field
|
||||||
|
* @param customResponseField the custom response field
|
||||||
|
* @param customRequestField the custom request field
|
||||||
|
* @param isResp the response flag for the parameter
|
||||||
|
* @param simpleName the simple name of the field
|
||||||
|
* @return the custom field information {@link CustomFieldInfo}
|
||||||
|
*/
|
||||||
|
protected CustomFieldInfo getCustomFieldInfo(ProjectDocConfigBuilder projectBuilder, DocJavaField docField,
|
||||||
|
CustomField customResponseField, CustomField customRequestField, boolean isResp, String simpleName) {
|
||||||
|
CustomFieldInfo customFieldInfo = new CustomFieldInfo();
|
||||||
|
|
||||||
|
// ignore custom field, if true return quickly
|
||||||
|
if (isIgnoreCustomField(docField, isResp, customRequestField, customResponseField)) {
|
||||||
|
customFieldInfo.setIgnore(true);
|
||||||
|
return customFieldInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cover response value
|
||||||
|
if (Objects.nonNull(customResponseField) && isResp && Objects.nonNull(customResponseField.getValue())
|
||||||
|
&& JavaClassUtil.isTargetChildClass(simpleName, customResponseField.getOwnerClassName())) {
|
||||||
|
|
||||||
|
customFieldInfo.setFieldValue(String.valueOf(customResponseField.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// cover request value
|
||||||
|
if (Objects.nonNull(customRequestField) && !isResp && Objects.nonNull(customRequestField.getValue())
|
||||||
|
&& JavaClassUtil.isTargetChildClass(simpleName, customRequestField.getOwnerClassName())) {
|
||||||
|
|
||||||
|
customFieldInfo.setFieldValue(String.valueOf(customRequestField.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// cover required
|
||||||
|
if (Objects.nonNull(customRequestField) && !isResp
|
||||||
|
&& JavaClassUtil.isTargetChildClass(simpleName, customRequestField.getOwnerClassName())
|
||||||
|
&& customRequestField.isRequire()) {
|
||||||
|
|
||||||
|
customFieldInfo.setStrRequired(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// cover comment
|
||||||
|
if (Objects.nonNull(customRequestField) && StringUtil.isNotEmpty(customRequestField.getDesc())
|
||||||
|
&& JavaClassUtil.isTargetChildClass(simpleName, customRequestField.getOwnerClassName()) && !isResp) {
|
||||||
|
customFieldInfo.setComment(customRequestField.getDesc());
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(customResponseField) && StringUtil.isNotEmpty(customResponseField.getDesc())
|
||||||
|
&& JavaClassUtil.isTargetChildClass(simpleName, customResponseField.getOwnerClassName()) && isResp) {
|
||||||
|
customFieldInfo.setComment(customResponseField.getDesc());
|
||||||
|
}
|
||||||
|
|
||||||
|
// cover fieldName
|
||||||
|
if (Objects.nonNull(customRequestField) && StringUtil.isNotEmpty(customRequestField.getReplaceName())
|
||||||
|
&& JavaClassUtil.isTargetChildClass(simpleName, customRequestField.getOwnerClassName()) && !isResp) {
|
||||||
|
customFieldInfo.setFieldName(customRequestField.getReplaceName());
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(customResponseField) && StringUtil.isNotEmpty(customResponseField.getReplaceName())
|
||||||
|
&& JavaClassUtil.isTargetChildClass(simpleName, customResponseField.getOwnerClassName()) && isResp) {
|
||||||
|
|
||||||
|
customFieldInfo.setFieldName(customResponseField.getReplaceName());
|
||||||
|
}
|
||||||
|
return customFieldInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,962 @@
|
|||||||
|
/*
|
||||||
|
* smart-doc https://github.com/smart-doc-group/smart-doc
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018-2024 smart-doc
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package com.gitee.sop.support.doc.helper;
|
||||||
|
|
||||||
|
import com.ly.doc.builder.ProjectDocConfigBuilder;
|
||||||
|
import com.ly.doc.constants.DocGlobalConstants;
|
||||||
|
import com.ly.doc.constants.DocTags;
|
||||||
|
import com.ly.doc.constants.JavaTypeConstants;
|
||||||
|
import com.ly.doc.constants.ParamTypeConstants;
|
||||||
|
import com.ly.doc.extension.json.PropertyNameHelper;
|
||||||
|
import com.ly.doc.extension.json.PropertyNamingStrategies;
|
||||||
|
import com.ly.doc.model.ApiConfig;
|
||||||
|
import com.ly.doc.model.ApiDataDictionary;
|
||||||
|
import com.ly.doc.model.ApiParam;
|
||||||
|
import com.ly.doc.model.CustomField;
|
||||||
|
import com.ly.doc.model.CustomFieldInfo;
|
||||||
|
import com.ly.doc.model.DocJavaField;
|
||||||
|
import com.ly.doc.model.FieldJsonAnnotationInfo;
|
||||||
|
import com.ly.doc.model.torna.EnumInfoAndValues;
|
||||||
|
import com.ly.doc.utils.DocClassUtil;
|
||||||
|
import com.ly.doc.utils.DocUtil;
|
||||||
|
import com.ly.doc.utils.JavaClassUtil;
|
||||||
|
import com.ly.doc.utils.JavaClassValidateUtil;
|
||||||
|
import com.ly.doc.utils.JavaFieldUtil;
|
||||||
|
import com.ly.doc.utils.ParamUtil;
|
||||||
|
import com.power.common.model.EnumDictionary;
|
||||||
|
import com.power.common.util.StringUtil;
|
||||||
|
import com.thoughtworks.qdox.model.JavaAnnotation;
|
||||||
|
import com.thoughtworks.qdox.model.JavaClass;
|
||||||
|
import com.thoughtworks.qdox.model.JavaField;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ApiParam Builder {@link ApiParam }
|
||||||
|
*
|
||||||
|
* @author yu 2019/12/21.
|
||||||
|
*/
|
||||||
|
public class ParamsBuildHelper extends BaseHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a parameter list based on field information.
|
||||||
|
*
|
||||||
|
* @param className The name of the generic type.
|
||||||
|
* @param pre A prefix builder for nested fields.
|
||||||
|
* @param level The next level of nesting.
|
||||||
|
* @param isRequired Indicates whether the parameter is required.
|
||||||
|
* @param isResp Indicates whether the parameter is a response parameter.
|
||||||
|
* @param registryClasses A collection of registered classes.
|
||||||
|
* @param projectBuilder A project builder instance.
|
||||||
|
* @param groupClasses A collection of JSR303 grouped classes.
|
||||||
|
* @param methodJsonViewClasses A set of valid `@JsonView` classes on controller
|
||||||
|
* method.
|
||||||
|
* @param pid The parent ID of the field.
|
||||||
|
* @param jsonRequest The JSON request object.
|
||||||
|
* @param atomicInteger An AtomicInteger for ID generation.
|
||||||
|
* <p>
|
||||||
|
* This method handles various types of fields and their values, including handling
|
||||||
|
* self-referential loops, maps, arrays, objects, and primitive types. It adds
|
||||||
|
* parameters to the paramList based on the type and structure of the given field,
|
||||||
|
* recursively calling itself for nested or complex types.
|
||||||
|
* @return A List of ApiParam instances representing the built parameters.
|
||||||
|
*/
|
||||||
|
public List<ApiParam> buildParams(String className, String pre, int level, String isRequired, boolean isResp,
|
||||||
|
Map<String, String> registryClasses, ProjectDocConfigBuilder projectBuilder, Set<String> groupClasses,
|
||||||
|
Set<String> methodJsonViewClasses, int pid, boolean jsonRequest, AtomicInteger atomicInteger) {
|
||||||
|
|
||||||
|
if (StringUtil.isEmpty(className)) {
|
||||||
|
throw new RuntimeException("Class name can't be null or empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursion limit check cached for efficiency
|
||||||
|
ApiConfig apiConfig = projectBuilder.getApiConfig();
|
||||||
|
int recursionLimit = apiConfig.getRecursionLimit();
|
||||||
|
if (level > recursionLimit) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
int nextLevel = level + 1;
|
||||||
|
// Check circular reference
|
||||||
|
if (registryClasses.containsKey(className) && level > registryClasses.size()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registry class
|
||||||
|
registryClasses.put(className, className);
|
||||||
|
String simpleName = DocClassUtil.getSimpleName(className);
|
||||||
|
String[] globGicName = DocClassUtil.getSimpleGicName(className);
|
||||||
|
|
||||||
|
if (Objects.isNull(globGicName) || globGicName.length < 1) {
|
||||||
|
JavaClass cls = projectBuilder.getClassByName(simpleName);
|
||||||
|
// obtain generics from parent class
|
||||||
|
JavaClass superJavaClass = Objects.nonNull(cls) ? cls.getSuperJavaClass() : null;
|
||||||
|
if (Objects.nonNull(superJavaClass)
|
||||||
|
&& !JavaTypeConstants.OBJECT_SIMPLE_NAME.equals(superJavaClass.getSimpleName())) {
|
||||||
|
globGicName = DocClassUtil.getSimpleGicName(superJavaClass.getGenericFullyQualifiedName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isShowJavaType = apiConfig.getShowJavaType();
|
||||||
|
|
||||||
|
// if is primitive
|
||||||
|
if (JavaClassValidateUtil.isPrimitive(simpleName)) {
|
||||||
|
return handlePrimitiveType(simpleName, isShowJavaType, atomicInteger, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle collection types
|
||||||
|
if (JavaClassValidateUtil.isCollection(simpleName) || JavaClassValidateUtil.isArray(simpleName)) {
|
||||||
|
return handleCollectionOrArrayType(globGicName, pre, level, isRequired, isResp, registryClasses,
|
||||||
|
projectBuilder, groupClasses, methodJsonViewClasses, pid, jsonRequest, atomicInteger, simpleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle map types
|
||||||
|
if (JavaClassValidateUtil.isMap(simpleName)) {
|
||||||
|
return buildMapParam(globGicName, pre, level, isRequired, isResp, registryClasses, projectBuilder,
|
||||||
|
groupClasses, methodJsonViewClasses, pid, jsonRequest, nextLevel, atomicInteger);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle generic object types
|
||||||
|
if (JavaTypeConstants.JAVA_OBJECT_FULLY.equals(className)) {
|
||||||
|
return buildGenericObjectParam(className, pre, isRequired, atomicInteger, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Reactor types
|
||||||
|
if (JavaClassValidateUtil.isReactor(simpleName)) {
|
||||||
|
if (globGicName.length > 0) {
|
||||||
|
return buildParams(globGicName[0], pre, nextLevel, isRequired, isResp, registryClasses, projectBuilder,
|
||||||
|
groupClasses, methodJsonViewClasses, pid, jsonRequest, atomicInteger);
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle Class Field
|
||||||
|
return processFields(className, pre, level, isRequired, isResp, registryClasses, projectBuilder, groupClasses,
|
||||||
|
methodJsonViewClasses, pid, jsonRequest, atomicInteger);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes fields of a given class and populates a list of API parameters based on
|
||||||
|
* the field types and properties.
|
||||||
|
*
|
||||||
|
* @param className The name of the class containing the fields.
|
||||||
|
* @param pre A prefix to prepend to field names.
|
||||||
|
* @param level The current level of nested fields.
|
||||||
|
* @param isRequired Indicates if the field is required.
|
||||||
|
* @param isResp Indicates if the field is part of a response.
|
||||||
|
* @param registryClasses A map of registry classes used for type resolution.
|
||||||
|
* @param projectBuilder The project builder used to access project-specific details.
|
||||||
|
* @param groupClasses A set of group classes relevant to the field processing.
|
||||||
|
* @param methodJsonViewClasses A set of JSON view classes applicable to methods.
|
||||||
|
* @param pid The parent ID of the current field.
|
||||||
|
* @param jsonRequest Indicates if the field is part of a JSON request.
|
||||||
|
* @param atomicInteger An AtomicInteger used for generating unique IDs.
|
||||||
|
* @return A list of API parameters representing the processed fields.
|
||||||
|
*/
|
||||||
|
public List<ApiParam> processFields(String className, String pre, int level, String isRequired,
|
||||||
|
boolean isResp, Map<String, String> registryClasses, ProjectDocConfigBuilder projectBuilder,
|
||||||
|
Set<String> groupClasses, Set<String> methodJsonViewClasses, int pid, boolean jsonRequest,
|
||||||
|
AtomicInteger atomicInteger) {
|
||||||
|
|
||||||
|
if (StringUtil.isEmpty(className)) {
|
||||||
|
throw new RuntimeException("Class name can't be null or empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for recursion limit to avoid infinite loops
|
||||||
|
int recursionLimit = projectBuilder.getApiConfig().getRecursionLimit();
|
||||||
|
|
||||||
|
// Early exit when recursion limit is hit
|
||||||
|
if (level > recursionLimit) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid processing the same class multiple times
|
||||||
|
if (registryClasses.containsKey(className) && level > registryClasses.size()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ApiParam> paramList = new ArrayList<>();
|
||||||
|
String simpleName = DocClassUtil.getSimpleName(className);
|
||||||
|
|
||||||
|
JavaClass cls = projectBuilder.getClassByName(simpleName);
|
||||||
|
boolean isShowJavaType = projectBuilder.getApiConfig().getShowJavaType();
|
||||||
|
boolean requestFieldToUnderline = projectBuilder.getApiConfig().isRequestFieldToUnderline();
|
||||||
|
boolean responseFieldToUnderline = projectBuilder.getApiConfig().isResponseFieldToUnderline();
|
||||||
|
boolean displayActualType = projectBuilder.getApiConfig().isDisplayActualType();
|
||||||
|
ClassLoader classLoader = projectBuilder.getApiConfig().getClassLoader();
|
||||||
|
|
||||||
|
PropertyNamingStrategies.NamingBase fieldNameConvert = null;
|
||||||
|
// ignore
|
||||||
|
if (Objects.nonNull(cls)) {
|
||||||
|
List<JavaAnnotation> clsAnnotation = cls.getAnnotations();
|
||||||
|
fieldNameConvert = PropertyNameHelper.translate(clsAnnotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] globGicName = DocClassUtil.getSimpleGicName(className);
|
||||||
|
Map<String, String> genericMap = new HashMap<>(globGicName.length);
|
||||||
|
JavaClassUtil.genericParamMap(genericMap, cls, globGicName);
|
||||||
|
|
||||||
|
Map<String, String> ignoreFields = JavaClassUtil.getClassJsonIgnoreFields(cls);
|
||||||
|
List<DocJavaField> fields = JavaClassUtil.getFields(cls, 0, new LinkedHashMap<>(), classLoader);
|
||||||
|
for (DocJavaField docField : fields) {
|
||||||
|
JavaField field = docField.getJavaField();
|
||||||
|
// ignore transient field
|
||||||
|
if (isTransientField(field, projectBuilder, isResp)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String maxLength = JavaFieldUtil.getParamMaxLength(field.getAnnotations());
|
||||||
|
StringBuilder comment = new StringBuilder();
|
||||||
|
comment.append(docField.getComment());
|
||||||
|
|
||||||
|
String fieldName = docField.getFieldName();
|
||||||
|
if (Objects.nonNull(fieldNameConvert)) {
|
||||||
|
fieldName = fieldNameConvert.translate(fieldName);
|
||||||
|
}
|
||||||
|
if (ignoreFields.containsKey(fieldName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String subTypeName = docField.getTypeFullyQualifiedName();
|
||||||
|
boolean needToUnderline = (responseFieldToUnderline && isResp) || (requestFieldToUnderline && !isResp);
|
||||||
|
if (needToUnderline) {
|
||||||
|
fieldName = StringUtil.camelToUnderline(fieldName);
|
||||||
|
}
|
||||||
|
String typeSimpleName = field.getType().getSimpleName();
|
||||||
|
String fieldGicName = docField.getTypeGenericCanonicalName();
|
||||||
|
List<JavaAnnotation> javaAnnotations = docField.getAnnotations();
|
||||||
|
|
||||||
|
Map<String, String> tagsMap = DocUtil.getFieldTagsValue(field, docField);
|
||||||
|
// since tag value
|
||||||
|
String since = DocGlobalConstants.DEFAULT_VERSION;
|
||||||
|
|
||||||
|
if (tagsMap.containsKey(DocTags.SINCE)) {
|
||||||
|
since = tagsMap.get(DocTags.SINCE);
|
||||||
|
}
|
||||||
|
// handle extension
|
||||||
|
Map<String, String> extensions = DocUtil.getCommentsByTag(field.getTagsByName(DocTags.EXTENSION),
|
||||||
|
DocTags.EXTENSION);
|
||||||
|
Map<String, Object> extensionParams = new HashMap<>(extensions.size());
|
||||||
|
if (!extensions.isEmpty()) {
|
||||||
|
extensions.forEach((k, v) -> extensionParams.put(k, DocUtil.detectTagValue(v)));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean strRequired = false;
|
||||||
|
CustomField.Key key = CustomField.Key.create(docField.getDeclaringClassName(), fieldName);
|
||||||
|
|
||||||
|
CustomField customResponseField = CustomField.nameEquals(key, projectBuilder.getCustomRespFieldMap());
|
||||||
|
CustomField customRequestField = CustomField.nameEquals(key, projectBuilder.getCustomReqFieldMap());
|
||||||
|
|
||||||
|
CustomFieldInfo customFieldInfo = getCustomFieldInfo(projectBuilder, docField, customResponseField,
|
||||||
|
customRequestField, isResp, simpleName);
|
||||||
|
// ignore custom field
|
||||||
|
if (Boolean.TRUE.equals(customFieldInfo.getIgnore())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// field json annotation
|
||||||
|
FieldJsonAnnotationInfo annotationInfo = getFieldJsonAnnotationInfo(projectBuilder, docField, isResp,
|
||||||
|
groupClasses, methodJsonViewClasses);
|
||||||
|
if (Boolean.TRUE.equals(annotationInfo.getIgnore())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// the param type from @JsonFormat
|
||||||
|
String fieldJsonFormatType = annotationInfo.getFieldJsonFormatType();
|
||||||
|
// the param value from @JsonFormat
|
||||||
|
String fieldJsonFormatValue = annotationInfo.getFieldJsonFormatValue();
|
||||||
|
// has Annotation @JsonSerialize And using ToStringSerializer
|
||||||
|
boolean toStringSerializer = Boolean.TRUE.equals(annotationInfo.getToStringSerializer());
|
||||||
|
if (Objects.nonNull(annotationInfo.getFieldName())) {
|
||||||
|
fieldName = annotationInfo.getFieldName();
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(annotationInfo.getStrRequired())) {
|
||||||
|
strRequired = annotationInfo.getStrRequired();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (JavaAnnotation annotation : field.getAnnotations()) {
|
||||||
|
if (JavaClassValidateUtil.isJSR303Required(annotation.getType().getValue())) {
|
||||||
|
strRequired = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
comment.append(JavaFieldUtil.getJsrComment(projectBuilder.getApiConfig().isShowValidation(), classLoader,
|
||||||
|
javaAnnotations));
|
||||||
|
// fix mock post form curl example error
|
||||||
|
String fieldValue = getFieldValueFromMock(tagsMap);
|
||||||
|
|
||||||
|
if (StringUtil.isNotEmpty(customFieldInfo.getFieldValue())) {
|
||||||
|
fieldValue = customFieldInfo.getFieldValue();
|
||||||
|
}
|
||||||
|
if (StringUtil.isNotEmpty(customFieldInfo.getFieldName())) {
|
||||||
|
fieldName = customFieldInfo.getFieldName();
|
||||||
|
}
|
||||||
|
if (StringUtil.isNotEmpty(customFieldInfo.getComment())) {
|
||||||
|
comment = new StringBuilder(customFieldInfo.getComment());
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(customFieldInfo.getStrRequired())) {
|
||||||
|
strRequired = customFieldInfo.getStrRequired();
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldName = fieldName.trim();
|
||||||
|
|
||||||
|
int nextLevel = level + 1;
|
||||||
|
// Analyzing File Type Field
|
||||||
|
if (JavaClassValidateUtil.isFile(fieldGicName)) {
|
||||||
|
ApiParam param = ApiParam.of()
|
||||||
|
.setField(pre + fieldName)
|
||||||
|
.setType(ParamTypeConstants.PARAM_TYPE_FILE)
|
||||||
|
.setClassName(className)
|
||||||
|
.setPid(pid)
|
||||||
|
.setId(atomicOrDefault(atomicInteger, paramList.size() + pid + 1))
|
||||||
|
.setMaxLength(maxLength)
|
||||||
|
.setDesc(comment.toString())
|
||||||
|
.setRequired(strRequired)
|
||||||
|
.setVersion(since)
|
||||||
|
.setExtensions(extensionParams);
|
||||||
|
if (fieldGicName.contains("[]") || fieldGicName.endsWith(">")) {
|
||||||
|
param.setType(ParamTypeConstants.PARAM_TYPE_FILE);
|
||||||
|
param.setDesc(comment.append("(array of file)").toString());
|
||||||
|
param.setHasItems(true);
|
||||||
|
}
|
||||||
|
paramList.add(param);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Analyzing Map Type Field
|
||||||
|
if (JavaClassValidateUtil.isMap(subTypeName)) {
|
||||||
|
ApiParam param = ApiParam.of()
|
||||||
|
.setField(pre + fieldName)
|
||||||
|
.setType(ParamTypeConstants.PARAM_TYPE_OBJECT)
|
||||||
|
.setClassName(className)
|
||||||
|
.setPid(pid)
|
||||||
|
.setId(atomicOrDefault(atomicInteger, paramList.size() + pid + 1))
|
||||||
|
.setMaxLength(maxLength)
|
||||||
|
.setDesc(comment.toString())
|
||||||
|
.setRequired(strRequired)
|
||||||
|
.setVersion(since)
|
||||||
|
.setExtensions(extensionParams);
|
||||||
|
paramList.add(param);
|
||||||
|
|
||||||
|
List<ApiParam> apiParams = buildMapParam(DocClassUtil.getSimpleGicName(fieldGicName),
|
||||||
|
DocUtil.getIndentByLevel(level), level + 1, isRequired, isResp, registryClasses, projectBuilder,
|
||||||
|
groupClasses, methodJsonViewClasses, param.getId(), jsonRequest, nextLevel, atomicInteger);
|
||||||
|
paramList.addAll(apiParams);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Analyzing Primitive Type Field
|
||||||
|
if (JavaClassValidateUtil.isPrimitive(subTypeName)) {
|
||||||
|
if (StringUtil.isEmpty(fieldValue)) {
|
||||||
|
fieldValue = StringUtil.isNotEmpty(fieldJsonFormatValue) ? fieldJsonFormatValue : StringUtil
|
||||||
|
.removeQuotes(DocUtil.getValByTypeAndFieldName(typeSimpleName, field.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiParam param = ApiParam.of()
|
||||||
|
.setClassName(className)
|
||||||
|
.setField(pre + fieldName)
|
||||||
|
.setPid(pid)
|
||||||
|
.setMaxLength(maxLength)
|
||||||
|
.setValue(fieldValue);
|
||||||
|
param.setId(atomicOrDefault(atomicInteger, paramList.size() + param.getPid() + 1));
|
||||||
|
String processedType = (isResp && toStringSerializer) ? "string"
|
||||||
|
: StringUtil.isNotEmpty(fieldJsonFormatType) ? fieldJsonFormatType
|
||||||
|
: processFieldTypeName(isShowJavaType, subTypeName);
|
||||||
|
param.setType(processedType);
|
||||||
|
param.setExtensions(extensionParams);
|
||||||
|
// handle param
|
||||||
|
commonHandleParam(paramList, param, isRequired, comment.toString(), since, strRequired);
|
||||||
|
|
||||||
|
JavaClass enumClass = ParamUtil.handleSeeEnum(param, field, projectBuilder, isResp || jsonRequest,
|
||||||
|
tagsMap, fieldJsonFormatValue);
|
||||||
|
if (Objects.nonNull(enumClass)) {
|
||||||
|
String enumClassComment = DocGlobalConstants.EMPTY;
|
||||||
|
if (StringUtil.isNotEmpty(enumClass.getComment())) {
|
||||||
|
enumClassComment = enumClass.getComment();
|
||||||
|
}
|
||||||
|
comment = new StringBuilder(
|
||||||
|
StringUtils.isEmpty(comment.toString()) ? enumClassComment : comment.toString());
|
||||||
|
String enumComment = handleEnumComment(enumClass, projectBuilder);
|
||||||
|
param.setDesc(comment + enumComment);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String appendComment = "";
|
||||||
|
if (displayActualType) {
|
||||||
|
if (globGicName.length > 0) {
|
||||||
|
String gicName = genericMap.get(subTypeName) != null ? genericMap.get(subTypeName)
|
||||||
|
: globGicName[0];
|
||||||
|
if (!simpleName.equals(gicName)) {
|
||||||
|
appendComment = " (ActualType: " + JavaClassUtil.getClassSimpleName(gicName) + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(docField.getActualJavaType())) {
|
||||||
|
appendComment = " (ActualType: "
|
||||||
|
+ JavaClassUtil.getClassSimpleName(docField.getActualJavaType()) + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder preBuilder = DocUtil.getStringBuilderByLevel(level);
|
||||||
|
int fieldPid;
|
||||||
|
ApiParam param = ApiParam.of()
|
||||||
|
.setField(pre + fieldName)
|
||||||
|
.setClassName(className)
|
||||||
|
.setPid(pid)
|
||||||
|
.setMaxLength(maxLength);
|
||||||
|
param.setId(atomicOrDefault(atomicInteger, paramList.size() + param.getPid() + 1));
|
||||||
|
param.setExtensions(extensionParams);
|
||||||
|
String processedType;
|
||||||
|
if (fieldGicName.length() == 1) {
|
||||||
|
String gicName = JavaTypeConstants.JAVA_OBJECT_FULLY;
|
||||||
|
if (Objects.nonNull(genericMap.get(typeSimpleName))) {
|
||||||
|
gicName = genericMap.get(subTypeName);
|
||||||
|
} else {
|
||||||
|
if (globGicName.length > 0) {
|
||||||
|
gicName = globGicName[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (JavaClassValidateUtil.isPrimitive(gicName)) {
|
||||||
|
processedType = DocClassUtil.processTypeNameForParams(gicName);
|
||||||
|
} else {
|
||||||
|
processedType = DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
processedType = StringUtil.isNotEmpty(fieldJsonFormatType) ? fieldJsonFormatType
|
||||||
|
: processFieldTypeName(isShowJavaType, subTypeName);
|
||||||
|
}
|
||||||
|
param.setType(processedType);
|
||||||
|
JavaClass javaClass = field.getType();
|
||||||
|
if (javaClass.isEnum()) {
|
||||||
|
comment.append(handleEnumComment(javaClass, projectBuilder));
|
||||||
|
ParamUtil.handleSeeEnum(param, field, projectBuilder, isResp || jsonRequest, tagsMap,
|
||||||
|
fieldJsonFormatValue);
|
||||||
|
// hand Param
|
||||||
|
commonHandleParam(paramList, param, isRequired, comment + appendComment, since, strRequired);
|
||||||
|
} else if (JavaClassValidateUtil.isCollection(subTypeName)
|
||||||
|
|| JavaClassValidateUtil.isArray(subTypeName)) {
|
||||||
|
if (isShowJavaType) {
|
||||||
|
// rpc
|
||||||
|
param.setType(
|
||||||
|
JavaFieldUtil.convertToSimpleTypeName(docField.getTypeGenericFullyQualifiedName()));
|
||||||
|
} else {
|
||||||
|
param.setType(ParamTypeConstants.PARAM_TYPE_ARRAY);
|
||||||
|
}
|
||||||
|
if (tagsMap.containsKey(DocTags.MOCK) && StringUtil.isNotEmpty(tagsMap.get(DocTags.MOCK))) {
|
||||||
|
param.setValue(fieldValue);
|
||||||
|
}
|
||||||
|
if (globGicName.length > 0 && JavaTypeConstants.JAVA_LIST_FULLY.equals(fieldGicName)) {
|
||||||
|
// no generic, just object
|
||||||
|
fieldGicName = fieldGicName + "<T>";
|
||||||
|
}
|
||||||
|
if (JavaClassValidateUtil.isArray(subTypeName)) {
|
||||||
|
fieldGicName = fieldGicName.substring(0, fieldGicName.lastIndexOf("["));
|
||||||
|
fieldGicName = "java.util.List<" + fieldGicName + ">";
|
||||||
|
}
|
||||||
|
String[] gNameArr = DocClassUtil.getSimpleGicName(fieldGicName);
|
||||||
|
if (gNameArr.length == 0) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
String gName = DocClassUtil.getSimpleGicName(fieldGicName)[0];
|
||||||
|
JavaClass javaClass1 = projectBuilder.getJavaProjectBuilder().getClassByName(gName);
|
||||||
|
comment.append(handleEnumComment(javaClass1, projectBuilder));
|
||||||
|
}
|
||||||
|
String gName = gNameArr[0];
|
||||||
|
if (JavaClassValidateUtil.isPrimitive(gName)) {
|
||||||
|
String builder = DocUtil.jsonValueByType(gName) + "," + DocUtil.jsonValueByType(gName);
|
||||||
|
|
||||||
|
if (StringUtil.isEmpty(fieldValue)) {
|
||||||
|
param.setValue(DocUtil.handleJsonStr(builder));
|
||||||
|
} else {
|
||||||
|
param.setValue(fieldValue);
|
||||||
|
}
|
||||||
|
commonHandleParam(paramList, param, isRequired, comment + appendComment, since, strRequired);
|
||||||
|
} else {
|
||||||
|
commonHandleParam(paramList, param, isRequired, comment + appendComment, since, strRequired);
|
||||||
|
fieldPid = Optional.ofNullable(atomicInteger).isPresent() ? param.getId()
|
||||||
|
: paramList.size() + pid;
|
||||||
|
if (!simpleName.equals(gName)) {
|
||||||
|
JavaClass arraySubClass = projectBuilder.getJavaProjectBuilder().getClassByName(gName);
|
||||||
|
if (arraySubClass.isEnum()) {
|
||||||
|
EnumInfoAndValues enumInfoAndValue = JavaClassUtil.getEnumInfoAndValue(arraySubClass,
|
||||||
|
projectBuilder, Boolean.FALSE);
|
||||||
|
if (Objects.nonNull(enumInfoAndValue)) {
|
||||||
|
param.setValue("[\"" + enumInfoAndValue.getValue() + "\"]")
|
||||||
|
.setEnumInfoAndValues(enumInfoAndValue)
|
||||||
|
.setType(enumInfoAndValue.getType());
|
||||||
|
}
|
||||||
|
} else if (gName.length() == 1) {
|
||||||
|
// handle generic
|
||||||
|
int len = globGicName.length;
|
||||||
|
if (len < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String gicName = genericMap.get(gName) != null ? genericMap.get(gName) : globGicName[0];
|
||||||
|
|
||||||
|
if (!JavaClassValidateUtil.isPrimitive(gicName) && !simpleName.equals(gicName)) {
|
||||||
|
paramList.addAll(buildParams(gicName, preBuilder.toString(), nextLevel, isRequired,
|
||||||
|
isResp, registryClasses, projectBuilder, groupClasses,
|
||||||
|
methodJsonViewClasses, fieldPid, jsonRequest, atomicInteger));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
paramList.addAll(buildParams(gName, preBuilder.toString(), nextLevel, isRequired,
|
||||||
|
isResp, registryClasses, projectBuilder, groupClasses, methodJsonViewClasses,
|
||||||
|
fieldPid, jsonRequest, atomicInteger));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
param.setSelfReferenceLoop(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (JavaClassValidateUtil.isMap(subTypeName)) {
|
||||||
|
if (tagsMap.containsKey(DocTags.MOCK) && StringUtil.isNotEmpty(tagsMap.get(DocTags.MOCK))) {
|
||||||
|
param.setType(ParamTypeConstants.PARAM_TYPE_MAP);
|
||||||
|
param.setValue(fieldValue);
|
||||||
|
}
|
||||||
|
commonHandleParam(paramList, param, isRequired, comment + appendComment, since, strRequired);
|
||||||
|
fieldPid = Optional.ofNullable(atomicInteger).isPresent() ? param.getId() : paramList.size() + pid;
|
||||||
|
String valType = DocClassUtil.getMapKeyValueType(fieldGicName).length == 0 ? fieldGicName
|
||||||
|
: DocClassUtil.getMapKeyValueType(fieldGicName)[1];
|
||||||
|
if (JavaClassValidateUtil.isMap(fieldGicName)
|
||||||
|
|| JavaTypeConstants.JAVA_OBJECT_FULLY.equals(valType)) {
|
||||||
|
ApiParam param1 = ApiParam.of()
|
||||||
|
.setField(preBuilder + "any object")
|
||||||
|
.setId(atomicOrDefault(atomicInteger, fieldPid + 1))
|
||||||
|
.setPid(fieldPid)
|
||||||
|
.setClassName(className)
|
||||||
|
.setMaxLength(maxLength)
|
||||||
|
.setType(ParamTypeConstants.PARAM_TYPE_OBJECT)
|
||||||
|
.setDesc(DocGlobalConstants.ANY_OBJECT_MSG)
|
||||||
|
.setVersion(DocGlobalConstants.DEFAULT_VERSION)
|
||||||
|
.setExtensions(extensionParams);
|
||||||
|
paramList.add(param1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!JavaClassValidateUtil.isPrimitive(valType)) {
|
||||||
|
if (valType.length() == 1) {
|
||||||
|
String gicName = genericMap.get(valType);
|
||||||
|
if (!JavaClassValidateUtil.isPrimitive(gicName) && !simpleName.equals(gicName)) {
|
||||||
|
paramList.addAll(buildParams(gicName, preBuilder.toString(), nextLevel, isRequired,
|
||||||
|
isResp, registryClasses, projectBuilder, groupClasses, methodJsonViewClasses,
|
||||||
|
fieldPid, jsonRequest, atomicInteger));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
paramList.addAll(buildParams(valType, preBuilder.toString(), nextLevel, isRequired, isResp,
|
||||||
|
registryClasses, projectBuilder, groupClasses, methodJsonViewClasses, fieldPid,
|
||||||
|
jsonRequest, atomicInteger));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (JavaTypeConstants.JAVA_OBJECT_FULLY.equals(fieldGicName)) {
|
||||||
|
if (StringUtil.isEmpty(param.getDesc())) {
|
||||||
|
param.setDesc(DocGlobalConstants.ANY_OBJECT_MSG);
|
||||||
|
}
|
||||||
|
commonHandleParam(paramList, param, isRequired, comment + appendComment, since, strRequired);
|
||||||
|
} else if (fieldGicName.length() == 1) {
|
||||||
|
commonHandleParam(paramList, param, isRequired, comment + appendComment, since, strRequired);
|
||||||
|
fieldPid = Optional.ofNullable(atomicInteger).isPresent() ? param.getId() : paramList.size() + pid;
|
||||||
|
// handle java generic or object
|
||||||
|
if (!simpleName.equals(className)) {
|
||||||
|
if (globGicName.length > 0) {
|
||||||
|
String gicName = genericMap.get(subTypeName) != null ? genericMap.get(subTypeName)
|
||||||
|
: globGicName[0];
|
||||||
|
String simple = DocClassUtil.getSimpleName(gicName);
|
||||||
|
// set type array
|
||||||
|
if (JavaClassValidateUtil.isArray(gicName)) {
|
||||||
|
param.setType(ParamTypeConstants.PARAM_TYPE_ARRAY);
|
||||||
|
}
|
||||||
|
if (JavaClassValidateUtil.isPrimitive(simple)) {
|
||||||
|
// do nothing
|
||||||
|
} else if (gicName.contains("<")) {
|
||||||
|
if (JavaClassValidateUtil.isCollection(simple)) {
|
||||||
|
param.setType(ParamTypeConstants.PARAM_TYPE_ARRAY);
|
||||||
|
String gName = DocClassUtil.getSimpleGicName(gicName)[0];
|
||||||
|
if (!JavaClassValidateUtil.isPrimitive(gName)) {
|
||||||
|
paramList.addAll(buildParams(gName, preBuilder.toString(), nextLevel,
|
||||||
|
isRequired, isResp, registryClasses, projectBuilder, groupClasses,
|
||||||
|
methodJsonViewClasses, fieldPid, jsonRequest, atomicInteger));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
paramList.addAll(buildParams(gicName, preBuilder.toString(), nextLevel, isRequired,
|
||||||
|
isResp, registryClasses, projectBuilder, groupClasses,
|
||||||
|
methodJsonViewClasses, fieldPid, jsonRequest, atomicInteger));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
paramList.addAll(buildParams(gicName, preBuilder.toString(), nextLevel, isRequired,
|
||||||
|
isResp, registryClasses, projectBuilder, groupClasses, methodJsonViewClasses,
|
||||||
|
fieldPid, jsonRequest, atomicInteger));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
paramList.addAll(buildParams(subTypeName, preBuilder.toString(), nextLevel, isRequired,
|
||||||
|
isResp, registryClasses, projectBuilder, groupClasses, methodJsonViewClasses,
|
||||||
|
fieldPid, jsonRequest, atomicInteger));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (simpleName.equals(subTypeName)) {
|
||||||
|
// reference self
|
||||||
|
ApiParam param1 = ApiParam.of()
|
||||||
|
.setField(pre + fieldName)
|
||||||
|
.setPid(pid)
|
||||||
|
.setId(atomicOrDefault(atomicInteger, paramList.size() + pid + 1))
|
||||||
|
.setClassName(subTypeName)
|
||||||
|
.setMaxLength(maxLength)
|
||||||
|
.setType(ParamTypeConstants.PARAM_TYPE_OBJECT)
|
||||||
|
.setDesc(comment.append(" $ref... self").toString())
|
||||||
|
.setVersion(DocGlobalConstants.DEFAULT_VERSION)
|
||||||
|
.setExtensions(extensionParams);
|
||||||
|
paramList.add(param1);
|
||||||
|
} else {
|
||||||
|
commonHandleParam(paramList, param, isRequired, comment + appendComment, since, strRequired);
|
||||||
|
fieldGicName = DocUtil.formatFieldTypeGicName(genericMap, fieldGicName);
|
||||||
|
fieldPid = Optional.ofNullable(atomicInteger).isPresent() ? param.getId() : paramList.size() + pid;
|
||||||
|
paramList.addAll(buildParams(fieldGicName, preBuilder.toString(), nextLevel, isRequired, isResp,
|
||||||
|
registryClasses, projectBuilder, groupClasses, methodJsonViewClasses, fieldPid, jsonRequest,
|
||||||
|
atomicInteger));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return paramList;
|
||||||
|
// end field
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a list of {@link ApiParam} objects for a map parameter.
|
||||||
|
*
|
||||||
|
* @param globGicName the global generic name array
|
||||||
|
* @param pre the prefix string
|
||||||
|
* @param level the level of the parameter
|
||||||
|
* @param isRequired the requirement status of the parameter
|
||||||
|
* @param isResp the response flag
|
||||||
|
* @param registryClasses the map of registry classes
|
||||||
|
* @param projectBuilder the project configuration builder
|
||||||
|
* @param groupClasses the set of group classes
|
||||||
|
* @param jsonViewClasses A set of valid `@JsonView` classes.
|
||||||
|
* @param pid the parent ID
|
||||||
|
* @param jsonRequest the JSON request flag
|
||||||
|
* @param nextLevel the next level of the parameter
|
||||||
|
* @param atomicInteger the atomic integer for generating unique IDs
|
||||||
|
* @return a list of {@link ApiParam} objects
|
||||||
|
*/
|
||||||
|
public List<ApiParam> buildMapParam(String[] globGicName, String pre, int level, String isRequired,
|
||||||
|
boolean isResp, Map<String, String> registryClasses, ProjectDocConfigBuilder projectBuilder,
|
||||||
|
Set<String> groupClasses, Set<String> jsonViewClasses, int pid, boolean jsonRequest, int nextLevel,
|
||||||
|
AtomicInteger atomicInteger) {
|
||||||
|
if (globGicName.length != 2) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// mock map key param
|
||||||
|
String mapKeySimpleName = DocClassUtil.getSimpleName(globGicName[0]);
|
||||||
|
String valueSimpleName = DocClassUtil.getSimpleName(globGicName[1]);
|
||||||
|
// get map key class
|
||||||
|
JavaClass mapKeyClass = projectBuilder.getJavaProjectBuilder().getClassByName(mapKeySimpleName);
|
||||||
|
|
||||||
|
boolean isShowJavaType = projectBuilder.getApiConfig().getShowJavaType();
|
||||||
|
String valueSimpleNameType = processFieldTypeName(isShowJavaType, valueSimpleName);
|
||||||
|
List<ApiParam> paramList = new ArrayList<>();
|
||||||
|
// map key is enum
|
||||||
|
if (Objects.nonNull(mapKeyClass) && mapKeyClass.isEnum() && !mapKeyClass.getEnumConstants().isEmpty()) {
|
||||||
|
Integer keyParentId = null;
|
||||||
|
for (JavaField enumConstant : mapKeyClass.getEnumConstants()) {
|
||||||
|
ApiParam apiParam = ApiParam.of()
|
||||||
|
.setField(pre + enumConstant.getName())
|
||||||
|
.setType(valueSimpleNameType)
|
||||||
|
.setClassName(valueSimpleName)
|
||||||
|
.setDesc(StringUtil.isEmpty(enumConstant.getComment()) ? enumConstant.getName()
|
||||||
|
: enumConstant.getComment() + " "
|
||||||
|
+ Optional.ofNullable(projectBuilder.getClassByName(valueSimpleName))
|
||||||
|
.map(JavaClass::getComment)
|
||||||
|
.orElse(DocGlobalConstants.DEFAULT_MAP_KEY_DESC))
|
||||||
|
.setVersion(DocGlobalConstants.DEFAULT_VERSION)
|
||||||
|
.setPid(null == keyParentId ? pid : keyParentId);
|
||||||
|
apiParam.setId(apiParam.getPid() + paramList.size() + 1);
|
||||||
|
if (null == keyParentId) {
|
||||||
|
keyParentId = apiParam.getPid();
|
||||||
|
}
|
||||||
|
paramList.add(apiParam);
|
||||||
|
// in foreach, need remove enum class in registry
|
||||||
|
registryClasses.remove(valueSimpleName);
|
||||||
|
List<ApiParam> apiParams = addValueParams(valueSimpleName, globGicName, level, isRequired, isResp,
|
||||||
|
registryClasses, projectBuilder, groupClasses, jsonViewClasses, apiParam.getId(), jsonRequest,
|
||||||
|
nextLevel, atomicInteger);
|
||||||
|
paramList.addAll(apiParams);
|
||||||
|
}
|
||||||
|
return paramList;
|
||||||
|
}
|
||||||
|
// map key is primitive
|
||||||
|
if (JavaClassValidateUtil.isPrimitive(mapKeySimpleName)) {
|
||||||
|
ApiParam apiParam = ApiParam.of()
|
||||||
|
.setField(pre + "mapKey")
|
||||||
|
.setType(valueSimpleNameType)
|
||||||
|
.setClassName(valueSimpleName)
|
||||||
|
.setDesc(Optional.ofNullable(projectBuilder.getClassByName(valueSimpleName))
|
||||||
|
.map(JavaClass::getComment)
|
||||||
|
.orElse(DocGlobalConstants.DEFAULT_MAP_KEY_DESC))
|
||||||
|
.setVersion(DocGlobalConstants.DEFAULT_VERSION)
|
||||||
|
.setPid(pid)
|
||||||
|
.setId(atomicOrDefault(atomicInteger, ++pid));
|
||||||
|
paramList.add(apiParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
paramList.addAll(addValueParams(valueSimpleName, globGicName, level, isRequired, isResp, registryClasses,
|
||||||
|
projectBuilder, groupClasses, jsonViewClasses, pid, jsonRequest, nextLevel, atomicInteger));
|
||||||
|
return paramList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds parameters for the map value to the parameter list.
|
||||||
|
*
|
||||||
|
* @param valueSimpleName the simple name of the value type
|
||||||
|
* @param globGicName the global generic name array
|
||||||
|
* @param level the level of the parameter
|
||||||
|
* @param isRequired the requirement status of the parameter
|
||||||
|
* @param isResp the response flag
|
||||||
|
* @param registryClasses the map of registry classes
|
||||||
|
* @param projectBuilder the project configuration builder
|
||||||
|
* @param groupClasses the set of group classes
|
||||||
|
* @param jsonViewClasses A set of valid `@JsonView` classes.
|
||||||
|
* @param pid the parent ID
|
||||||
|
* @param jsonRequest the JSON request flag
|
||||||
|
* @param nextLevel the next level of the parameter
|
||||||
|
* @param atomicInteger the atomic integer for generating unique IDs
|
||||||
|
* @return the list of {@link ApiParam} objects
|
||||||
|
*/
|
||||||
|
public List<ApiParam> addValueParams(String valueSimpleName, String[] globGicName, int level,
|
||||||
|
String isRequired, boolean isResp, Map<String, String> registryClasses,
|
||||||
|
ProjectDocConfigBuilder projectBuilder, Set<String> groupClasses, Set<String> jsonViewClasses, int pid,
|
||||||
|
boolean jsonRequest, int nextLevel, AtomicInteger atomicInteger) {
|
||||||
|
// build param when map value is not primitive
|
||||||
|
if (JavaClassValidateUtil.isPrimitive(valueSimpleName)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return buildParams(globGicName[1], DocUtil.getIndentByLevel(level), nextLevel, isRequired, isResp,
|
||||||
|
registryClasses, projectBuilder, groupClasses, jsonViewClasses, pid, jsonRequest, atomicInteger);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String dictionaryListComment(List<EnumDictionary> enumDataDict) {
|
||||||
|
return enumDataDict.stream()
|
||||||
|
.map(apiDataDictionary -> apiDataDictionary.getName() + "-(\"" + apiDataDictionary.getValue() + "\",\""
|
||||||
|
+ apiDataDictionary.getDesc() + "\")")
|
||||||
|
.collect(Collectors.joining(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ApiParam> primitiveReturnRespComment(String typeName, AtomicInteger atomicInteger, int pid) {
|
||||||
|
String comments = "Return " + typeName + ".";
|
||||||
|
ApiParam apiParam = ApiParam.of()
|
||||||
|
.setClassName(typeName)
|
||||||
|
.setId(atomicOrDefault(atomicInteger, pid + 1))
|
||||||
|
.setField("-")
|
||||||
|
.setPid(pid)
|
||||||
|
.setType(typeName)
|
||||||
|
.setDesc(comments)
|
||||||
|
.setVersion(DocGlobalConstants.DEFAULT_VERSION);
|
||||||
|
|
||||||
|
List<ApiParam> paramList = new ArrayList<>();
|
||||||
|
paramList.add(apiParam);
|
||||||
|
return paramList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void commonHandleParam(List<ApiParam> paramList, ApiParam param, String isRequired, String comment,
|
||||||
|
String since, boolean strRequired) {
|
||||||
|
if (StringUtil.isEmpty(isRequired)) {
|
||||||
|
param.setDesc(comment).setVersion(since);
|
||||||
|
} else {
|
||||||
|
param.setDesc(comment).setVersion(since).setRequired(strRequired);
|
||||||
|
}
|
||||||
|
paramList.add(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the generation of comments for enum types in a Java class. If the class is
|
||||||
|
* an enum, it generates the corresponding enum comment based on the project
|
||||||
|
* configuration; otherwise, it returns an empty comment string.
|
||||||
|
*
|
||||||
|
* @param javaClass The JavaClass object containing class information.
|
||||||
|
* @param projectBuilder The ProjectDocConfigBuilder object containing project
|
||||||
|
* configuration information.
|
||||||
|
* @return The generated enum comment string.
|
||||||
|
*/
|
||||||
|
public String handleEnumComment(JavaClass javaClass, ProjectDocConfigBuilder projectBuilder) {
|
||||||
|
String comment = "";
|
||||||
|
if (!javaClass.isEnum()) {
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
String enumComments = javaClass.getComment();
|
||||||
|
if (Boolean.TRUE.equals(projectBuilder.getApiConfig().getInlineEnum())) {
|
||||||
|
ApiDataDictionary dataDictionary = projectBuilder.getApiConfig()
|
||||||
|
.getDataDictionary(javaClass.getCanonicalName());
|
||||||
|
if (Objects.isNull(dataDictionary)) {
|
||||||
|
// the output format should be unified ( as same as the "else" output)
|
||||||
|
comment = comment + "<br/>[Enum: " + JavaClassUtil.getEnumParams(javaClass) + "]";
|
||||||
|
} else {
|
||||||
|
Class<?> enumClass = dataDictionary.getEnumClass();
|
||||||
|
if (enumClass.isInterface()) {
|
||||||
|
ClassLoader classLoader = projectBuilder.getApiConfig().getClassLoader();
|
||||||
|
try {
|
||||||
|
enumClass = classLoader.loadClass(javaClass.getFullyQualifiedName());
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
comment = comment + "<br/>[Enum: " + dictionaryListComment(dataDictionary.getEnumDataDict(enumClass))
|
||||||
|
+ "]";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (StringUtil.isNotEmpty(enumComments)) {
|
||||||
|
comment = comment + "<br/>(See: " + enumComments + ")";
|
||||||
|
}
|
||||||
|
comment = StringUtil.removeQuotes(comment);
|
||||||
|
}
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the next value of the specified atomic integer or the default value if the
|
||||||
|
* atomic integer is null.
|
||||||
|
*
|
||||||
|
* @param atomicInteger the atomic integer
|
||||||
|
* @param defaultVal the default value
|
||||||
|
* @return the next value of the atomic integer or the default value
|
||||||
|
*/
|
||||||
|
public int atomicOrDefault(AtomicInteger atomicInteger, int defaultVal) {
|
||||||
|
if (null != atomicInteger) {
|
||||||
|
return atomicInteger.incrementAndGet();
|
||||||
|
}
|
||||||
|
return defaultVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the field type name based on the specified flag.
|
||||||
|
*
|
||||||
|
* @param isShowJavaType a flag indicating whether to show the Java type or not
|
||||||
|
* @param fieldTypeName the field type name to be processed
|
||||||
|
* @return the processed field type name
|
||||||
|
*/
|
||||||
|
public String processFieldTypeName(boolean isShowJavaType, String fieldTypeName) {
|
||||||
|
if (isShowJavaType) {
|
||||||
|
return JavaFieldUtil.convertToSimpleTypeName(fieldTypeName);
|
||||||
|
} else {
|
||||||
|
return DocClassUtil.processTypeNameForParams(fieldTypeName.toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles primitive types and returns a list of {@link ApiParam} objects.
|
||||||
|
*
|
||||||
|
* @param simpleName the simple name of the primitive type
|
||||||
|
* @param isShowJavaType a flag indicating whether to show the Java type or not
|
||||||
|
* @param atomicInteger the atomic integer for generating unique IDs
|
||||||
|
* @param pid the parent ID
|
||||||
|
* @return the list of {@link ApiParam} objects
|
||||||
|
*/
|
||||||
|
public List<ApiParam> handlePrimitiveType(String simpleName, boolean isShowJavaType,
|
||||||
|
AtomicInteger atomicInteger, int pid) {
|
||||||
|
String processedType = processFieldTypeName(isShowJavaType, simpleName);
|
||||||
|
return primitiveReturnRespComment(processedType, atomicInteger, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a list of {@link ApiParam} objects for a map type.
|
||||||
|
*
|
||||||
|
* @param globGicName the generic canonical name of the map type
|
||||||
|
* @param pre the prefix for the field name
|
||||||
|
* @param level the level of the parameter
|
||||||
|
* @param isRequired the required flag for the parameter
|
||||||
|
* @param isResp the response flag for the parameter
|
||||||
|
* @param registryClasses the registry classes
|
||||||
|
* @param projectBuilder the project builder
|
||||||
|
* @param groupClasses the group classes
|
||||||
|
* @param methodJsonViewClasses the method JSON view classes
|
||||||
|
* @param pid the parent ID
|
||||||
|
* @param jsonRequest the request flag for the parameter
|
||||||
|
* @param atomicInteger the atomic integer for generating unique IDs
|
||||||
|
* @param simpleName the simple name of the collection type
|
||||||
|
*/
|
||||||
|
public List<ApiParam> handleCollectionOrArrayType(String[] globGicName, String pre, int level,
|
||||||
|
String isRequired, boolean isResp, Map<String, String> registryClasses,
|
||||||
|
ProjectDocConfigBuilder projectBuilder, Set<String> groupClasses, Set<String> methodJsonViewClasses,
|
||||||
|
int pid, boolean jsonRequest, AtomicInteger atomicInteger, String simpleName) {
|
||||||
|
List<ApiParam> paramList = new ArrayList<>();
|
||||||
|
if (!JavaClassValidateUtil.isCollection(globGicName[0])) {
|
||||||
|
String gNameTemp = globGicName[0];
|
||||||
|
String gName = JavaClassValidateUtil.isArray(gNameTemp) ? gNameTemp.substring(0, gNameTemp.indexOf("["))
|
||||||
|
: globGicName[0];
|
||||||
|
if (JavaClassValidateUtil.isPrimitive(gName)) {
|
||||||
|
String processedType = projectBuilder.getApiConfig().getShowJavaType()
|
||||||
|
? JavaFieldUtil.convertToSimpleTypeName(simpleName)
|
||||||
|
: DocClassUtil.processTypeNameForParams(gName);
|
||||||
|
ApiParam param = ApiParam.of()
|
||||||
|
.setId(atomicOrDefault(atomicInteger, pid + 1))
|
||||||
|
.setField(pre + " -")
|
||||||
|
.setType("array[" + processedType + "]")
|
||||||
|
.setPid(pid)
|
||||||
|
.setDesc("array of " + processedType)
|
||||||
|
.setVersion(DocGlobalConstants.DEFAULT_VERSION)
|
||||||
|
.setRequired(Boolean.parseBoolean(isRequired));
|
||||||
|
paramList.add(param);
|
||||||
|
} else {
|
||||||
|
if (JavaClassValidateUtil.isArray(gNameTemp)) {
|
||||||
|
gNameTemp = gNameTemp.substring(0, gNameTemp.indexOf("["));
|
||||||
|
}
|
||||||
|
paramList.addAll(buildParams(gNameTemp, pre, level + 1, isRequired, isResp, registryClasses,
|
||||||
|
projectBuilder, groupClasses, methodJsonViewClasses, pid, jsonRequest, atomicInteger));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return paramList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a list of {@link ApiParam} objects for a generic object type.
|
||||||
|
*
|
||||||
|
* @param className the canonical name of the generic object type
|
||||||
|
* @param pre the prefix for the field name
|
||||||
|
* @param isRequired the required flag for the parameter
|
||||||
|
* @param atomicInteger the atomic integer for generating unique IDs
|
||||||
|
* @param pid the parent ID
|
||||||
|
* @return the list of {@link ApiParam} objects
|
||||||
|
*/
|
||||||
|
public List<ApiParam> buildGenericObjectParam(String className, String pre, String isRequired,
|
||||||
|
AtomicInteger atomicInteger, int pid) {
|
||||||
|
List<ApiParam> paramList = new ArrayList<>();
|
||||||
|
ApiParam apiParam = ApiParam.of()
|
||||||
|
.setClassName(className)
|
||||||
|
.setId(atomicOrDefault(atomicInteger, pid + 1))
|
||||||
|
.setField(pre + "any object")
|
||||||
|
.setType(ParamTypeConstants.PARAM_TYPE_OBJECT)
|
||||||
|
.setPid(pid)
|
||||||
|
.setDesc(DocGlobalConstants.ANY_OBJECT_MSG)
|
||||||
|
.setVersion(DocGlobalConstants.DEFAULT_VERSION)
|
||||||
|
.setRequired(Boolean.parseBoolean(isRequired));
|
||||||
|
paramList.add(apiParam);
|
||||||
|
return paramList;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1 @@
|
|||||||
|
com.gitee.sop.support.doc.SopDocBuildTemplate
|
@@ -28,6 +28,14 @@ const permissionRouter = {
|
|||||||
title: "签名算法",
|
title: "签名算法",
|
||||||
showLink: false
|
showLink: false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/doc/code",
|
||||||
|
name: "DocCode",
|
||||||
|
meta: {
|
||||||
|
title: "公共错误码",
|
||||||
|
showLink: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
334
sop-website/sop-website-frontend/public/static/code.json
Normal file
334
sop-website/sop-website-frontend/public/static/code.json
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
|
||||||
|
],
|
||||||
|
"code":"0",
|
||||||
|
"id":1,
|
||||||
|
"msg":"成功"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"id":3,
|
||||||
|
"solution":"重新获取token",
|
||||||
|
"sub_code":"aop.invalid-auth-token",
|
||||||
|
"sub_msg":"无效的访问令牌"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":4,
|
||||||
|
"solution":"重新获取token",
|
||||||
|
"sub_code":"aop.auth-token-time-out",
|
||||||
|
"sub_msg":"访问令牌已过期"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":5,
|
||||||
|
"solution":"重新获取token",
|
||||||
|
"sub_code":"aop.invalid-app-auth-token",
|
||||||
|
"sub_msg":"无效的应用授权令牌"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":6,
|
||||||
|
"solution":"联系平台进行授权",
|
||||||
|
"sub_code":"aop.invalid-app-auth-token-no-api",
|
||||||
|
"sub_msg":"商户未授权当前接口"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":7,
|
||||||
|
"solution":"重新获取token",
|
||||||
|
"sub_code":"aop.app-auth-token-time-out",
|
||||||
|
"sub_msg":"应用授权令牌已过期"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":8,
|
||||||
|
"solution":"联系平台处理",
|
||||||
|
"sub_code":"aop.no-product-reg-by-partner",
|
||||||
|
"sub_msg":"商户未签约任何产品"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code":"20001",
|
||||||
|
"id":2,
|
||||||
|
"msg":"认证异常"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"id":10,
|
||||||
|
"solution":"检查参数正确",
|
||||||
|
"sub_code":"isv.invalid-parameter",
|
||||||
|
"sub_msg":"参数无效"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":11,
|
||||||
|
"solution":"检查传参",
|
||||||
|
"sub_code":"isv.error-parameter",
|
||||||
|
"sub_msg":"参数不正确"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":12,
|
||||||
|
"solution":"检查上传文件",
|
||||||
|
"sub_code":"isv.upload-fail",
|
||||||
|
"sub_msg":"文件上传失败"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":13,
|
||||||
|
"solution":"检查文件后缀名",
|
||||||
|
"sub_code":"isv.invalid-file-extension",
|
||||||
|
"sub_msg":"文件扩展名无效"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":14,
|
||||||
|
"solution":"检查文档大小",
|
||||||
|
"sub_code":"isv.invalid-file-size",
|
||||||
|
"sub_msg":"{0}文件大小无效,单文件不得超过{1}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":15,
|
||||||
|
"solution":"检查接口名称是否正确",
|
||||||
|
"sub_code":"isv.invalid-method",
|
||||||
|
"sub_msg":"不存在的方法名"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":16,
|
||||||
|
"solution":"检查format参数是否正确",
|
||||||
|
"sub_code":"isv.invalid-format",
|
||||||
|
"sub_msg":"无效的数据格式"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":17,
|
||||||
|
"solution":"检查sign_type是否正确",
|
||||||
|
"sub_code":"isv.invalid-signature-type",
|
||||||
|
"sub_msg":"无效的签名类型"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":18,
|
||||||
|
"solution":"检查签名结果是否正确",
|
||||||
|
"sub_code":"isv.invalid-signature",
|
||||||
|
"sub_msg":"无效签名"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":19,
|
||||||
|
"solution":"检查签名结果是否正确",
|
||||||
|
"sub_code":"isv.invalid-encrypt-type",
|
||||||
|
"sub_msg":"无效的加密类型"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":20,
|
||||||
|
"solution":"检查签名结果是否正确",
|
||||||
|
"sub_code":"isv.invalid-encrypt",
|
||||||
|
"sub_msg":"解密异常"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":21,
|
||||||
|
"solution":"检查appId是否正确",
|
||||||
|
"sub_code":"isv.invalid-app-id",
|
||||||
|
"sub_msg":"无效的 appId 参数"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":22,
|
||||||
|
"solution":"检查时间戳格式是否正确",
|
||||||
|
"sub_code":"isv.invalid-timestamp",
|
||||||
|
"sub_msg":"非法的时间戳参数"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":23,
|
||||||
|
"solution":"检查charset参数是否正确",
|
||||||
|
"sub_code":"isv.invalid-charset",
|
||||||
|
"sub_msg":"字符集错误"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":24,
|
||||||
|
"solution":"检查签名",
|
||||||
|
"sub_code":"isv.invalid-digest",
|
||||||
|
"sub_msg":"摘要错误"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":25,
|
||||||
|
"solution":"",
|
||||||
|
"sub_code":"isv.decryption-error-not-valid-encrypt-type",
|
||||||
|
"sub_msg":"解密出错,不支持的加密算法"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":26,
|
||||||
|
"solution":"",
|
||||||
|
"sub_code":"isv.decryption-error-not-valid-encrypt-key",
|
||||||
|
"sub_msg":"解密出错, 未配置加密密钥或加密密钥格式错误"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":27,
|
||||||
|
"solution":"",
|
||||||
|
"sub_code":"isv.decryption-error-unknown",
|
||||||
|
"sub_msg":"解密出错,未知异常"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":28,
|
||||||
|
"solution":"",
|
||||||
|
"sub_code":"isv.missing-signature-config",
|
||||||
|
"sub_msg":"验签出错, 未配置对应签名算法的公钥或者证书"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":29,
|
||||||
|
"solution":"",
|
||||||
|
"sub_code":"isv.not-support-app-auth",
|
||||||
|
"sub_msg":"本接口不支持第三方代理调用"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":30,
|
||||||
|
"solution":"",
|
||||||
|
"sub_code":"isv.suspected-attack",
|
||||||
|
"sub_msg":"可疑的攻击请求"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":31,
|
||||||
|
"solution":"",
|
||||||
|
"sub_code":"isv.invalid-content-type",
|
||||||
|
"sub_msg":"无效的 content-type"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code":"40002",
|
||||||
|
"id":9,
|
||||||
|
"msg":"错误参数"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"id":33,
|
||||||
|
"solution":"检查接口名",
|
||||||
|
"sub_code":"isv.missing-method",
|
||||||
|
"sub_msg":"缺少方法名参数"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":34,
|
||||||
|
"solution":"检查签名sign参数",
|
||||||
|
"sub_code":"isv.missing-signature",
|
||||||
|
"sub_msg":"缺少签名参数"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":35,
|
||||||
|
"solution":"检查签名类型参数",
|
||||||
|
"sub_code":"isv.missing-signature-type",
|
||||||
|
"sub_msg":"缺少签名类型参数"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":36,
|
||||||
|
"solution":"",
|
||||||
|
"sub_code":"isv.missing-signature-key",
|
||||||
|
"sub_msg":"缺少签名配置"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":37,
|
||||||
|
"solution":"appId参数必填",
|
||||||
|
"sub_code":"isv.missing-app-id",
|
||||||
|
"sub_msg":"缺少 appId 参数"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":38,
|
||||||
|
"solution":"时间戳参数必填",
|
||||||
|
"sub_code":"isv.missing-timestamp",
|
||||||
|
"sub_msg":"缺少时间戳参数"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":39,
|
||||||
|
"solution":"版本号参数必填",
|
||||||
|
"sub_code":"isv.missing-version",
|
||||||
|
"sub_msg":"缺少版本参数"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":40,
|
||||||
|
"solution":"",
|
||||||
|
"sub_code":"isv.decryption-error-missing-encrypt-type",
|
||||||
|
"sub_msg":"解密出错, 未指定加密算法"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code":"40001",
|
||||||
|
"id":32,
|
||||||
|
"msg":"缺少参数"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"id":42,
|
||||||
|
"solution":"网关异常",
|
||||||
|
"sub_code":"isp.unknown-error",
|
||||||
|
"sub_msg":"服务暂不可用"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":43,
|
||||||
|
"solution":"服务提供异常",
|
||||||
|
"sub_code":"isp.service-unknown-error",
|
||||||
|
"sub_msg":"服务不可用"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":44,
|
||||||
|
"solution":"服务不可用",
|
||||||
|
"sub_code":"isp.service-not-available",
|
||||||
|
"sub_msg":"服务暂不可用"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":45,
|
||||||
|
"solution":"联系平台排查日志",
|
||||||
|
"sub_code":"isp.gateway-response-timeout",
|
||||||
|
"sub_msg":"网关响应超时"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":46,
|
||||||
|
"solution":"联系平台排查日志",
|
||||||
|
"sub_code":"isv.service-busy",
|
||||||
|
"sub_msg":"服务器忙"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code":"99999",
|
||||||
|
"id":41,
|
||||||
|
"msg":"未知异常"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"id":48,
|
||||||
|
"solution":"接口无权限,联系平台授权",
|
||||||
|
"sub_code":"isv.insufficient-isv-permissions",
|
||||||
|
"sub_msg":"请检查配置的账户是否有当前接口权限"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":49,
|
||||||
|
"solution":"联系平台授权",
|
||||||
|
"sub_code":"isv.insufficient-user-permissions",
|
||||||
|
"sub_msg":"代理的商户没有当前接口权限"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":50,
|
||||||
|
"solution":"联系平台授权",
|
||||||
|
"sub_code":"isv.route-no-permissions",
|
||||||
|
"sub_msg":"没有当前接口权限"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":51,
|
||||||
|
"solution":"访问首先",
|
||||||
|
"sub_code":"isv.access-forbidden",
|
||||||
|
"sub_msg":"无权访问"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":52,
|
||||||
|
"solution":"IP受限",
|
||||||
|
"sub_code":"isv.ip-forbidden",
|
||||||
|
"sub_msg":"IP无权访问"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code":"40006",
|
||||||
|
"id":47,
|
||||||
|
"msg":"权限异常"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"id":54,
|
||||||
|
"solution":"",
|
||||||
|
"sub_code":"isp.biz-error",
|
||||||
|
"sub_msg":"业务异常"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"code":"50003",
|
||||||
|
"id":53,
|
||||||
|
"msg":"业务异常"
|
||||||
|
}
|
||||||
|
]
|
@@ -224,7 +224,5 @@ export const http = new PureHttp();
|
|||||||
* @param path 相对于public文件夹路径,如文件在public/static/sign.md,填:static/sign.md
|
* @param path 相对于public文件夹路径,如文件在public/static/sign.md,填:static/sign.md
|
||||||
*/
|
*/
|
||||||
export function getFile(path) {
|
export function getFile(path) {
|
||||||
return Axios.get(path, {
|
return Axios.get(path);
|
||||||
responseType: "text"
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@@ -138,7 +138,19 @@ const defaultProps = {
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="描述" prop="description" />
|
<el-table-column label="描述" prop="description">
|
||||||
|
<template #default="scope">
|
||||||
|
<span v-if="scope.row.name === 'code'">
|
||||||
|
网关返回码,详见
|
||||||
|
<router-link :to="{ name: 'DocCode' }" target="_blank">
|
||||||
|
公共错误码
|
||||||
|
</router-link>
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
{{ scope.row.description }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="示例值" prop="example" width="200" />
|
<el-table-column label="示例值" prop="example" width="200" />
|
||||||
</el-table>
|
</el-table>
|
||||||
<h4>业务返回参数</h4>
|
<h4>业务返回参数</h4>
|
||||||
|
@@ -0,0 +1,31 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
import { getFile } from "@/utils/http";
|
||||||
|
|
||||||
|
const tableData = ref([]);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getFile("static/code.json").then(resp => {
|
||||||
|
console.log(resp.data);
|
||||||
|
tableData.value = resp.data;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<h3>公共错误码</h3>
|
||||||
|
<div class="isp-info">
|
||||||
|
<el-table :data="tableData" row-key="id" default-expand-all border>
|
||||||
|
<el-table-column label="code" prop="code" width="200" />
|
||||||
|
<el-table-column label="msg" prop="msg" width="200" />
|
||||||
|
<el-table-column
|
||||||
|
label="sub_code(详细错误码)"
|
||||||
|
prop="sub_code"
|
||||||
|
width="250"
|
||||||
|
/>
|
||||||
|
<el-table-column label="sub_msg(详细错误信息)" prop="sub_msg" />
|
||||||
|
<el-table-column label="解决方案" prop="solution" />
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
@@ -1,3 +0,0 @@
|
|||||||
import { ref } from "vue";
|
|
||||||
|
|
||||||
export const value = ref("");
|
|
@@ -1,10 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { value } from "./index";
|
import { onMounted, ref } from "vue";
|
||||||
import { getFile } from "@/utils/http";
|
import { getFile } from "@/utils/http";
|
||||||
import MarkdownEditor from "@/components/MarkdownEditor";
|
import MarkdownEditor from "@/components/MarkdownEditor";
|
||||||
|
|
||||||
getFile("static/md/sign.md").then(resp => {
|
const value = ref("");
|
||||||
|
onMounted(() => {
|
||||||
|
getFile("static/md/sign.md").then(resp => {
|
||||||
value.value = resp.data;
|
value.value = resp.data;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
Reference in New Issue
Block a user