commit:同步2.0版本
@@ -161,7 +161,7 @@ public class LoginController {
|
|||||||
@PostMapping("/changePassword")
|
@PostMapping("/changePassword")
|
||||||
public ResponseResult<Void> changePassword(
|
public ResponseResult<Void> changePassword(
|
||||||
@MyRequestBody String oldPass, @MyRequestBody String newPass) throws Exception {
|
@MyRequestBody String oldPass, @MyRequestBody String newPass) throws Exception {
|
||||||
if (MyCommonUtil.existBlankArgument(oldPass, oldPass)) {
|
if (MyCommonUtil.existBlankArgument(newPass, oldPass)) {
|
||||||
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
|
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
|
||||||
}
|
}
|
||||||
TokenData tokenData = TokenData.takeFromRequest();
|
TokenData tokenData = TokenData.takeFromRequest();
|
||||||
|
|||||||
@@ -10,14 +10,12 @@ import com.flow.demo.common.core.object.*;
|
|||||||
import com.flow.demo.common.core.util.*;
|
import com.flow.demo.common.core.util.*;
|
||||||
import com.flow.demo.common.core.constant.*;
|
import com.flow.demo.common.core.constant.*;
|
||||||
import com.flow.demo.common.core.annotation.MyRequestBody;
|
import com.flow.demo.common.core.annotation.MyRequestBody;
|
||||||
import com.flow.demo.common.core.validator.UpdateGroup;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import javax.validation.groups.Default;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,7 +42,7 @@ public class SysDeptController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/add")
|
@PostMapping("/add")
|
||||||
public ResponseResult<Long> add(@MyRequestBody SysDeptDto sysDeptDto) {
|
public ResponseResult<Long> add(@MyRequestBody SysDeptDto sysDeptDto) {
|
||||||
String errorMessage = MyCommonUtil.getModelValidationError(sysDeptDto);
|
String errorMessage = MyCommonUtil.getModelValidationError(sysDeptDto, false);
|
||||||
if (errorMessage != null) {
|
if (errorMessage != null) {
|
||||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
}
|
}
|
||||||
@@ -70,7 +68,7 @@ public class SysDeptController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/update")
|
@PostMapping("/update")
|
||||||
public ResponseResult<Void> update(@MyRequestBody SysDeptDto sysDeptDto) {
|
public ResponseResult<Void> update(@MyRequestBody SysDeptDto sysDeptDto) {
|
||||||
String errorMessage = MyCommonUtil.getModelValidationError(sysDeptDto, Default.class, UpdateGroup.class);
|
String errorMessage = MyCommonUtil.getModelValidationError(sysDeptDto, true);
|
||||||
if (errorMessage != null) {
|
if (errorMessage != null) {
|
||||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
}
|
}
|
||||||
@@ -188,16 +186,20 @@ public class SysDeptController {
|
|||||||
@MyRequestBody SysPostDto sysPostDtoFilter,
|
@MyRequestBody SysPostDto sysPostDtoFilter,
|
||||||
@MyRequestBody MyOrderParam orderParam,
|
@MyRequestBody MyOrderParam orderParam,
|
||||||
@MyRequestBody MyPageParam pageParam) {
|
@MyRequestBody MyPageParam pageParam) {
|
||||||
ResponseResult<Void> verifyResult = this.doSysDeptPostVerify(deptId);
|
if (MyCommonUtil.isNotBlankOrNull(deptId) && !sysDeptService.existId(deptId)) {
|
||||||
if (!verifyResult.isSuccess()) {
|
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
|
||||||
return ResponseResult.errorFrom(verifyResult);
|
|
||||||
}
|
}
|
||||||
if (pageParam != null) {
|
if (pageParam != null) {
|
||||||
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
|
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
|
||||||
}
|
}
|
||||||
SysPost filter = MyModelUtil.copyTo(sysPostDtoFilter, SysPost.class);
|
SysPost filter = MyModelUtil.copyTo(sysPostDtoFilter, SysPost.class);
|
||||||
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysPost.class);
|
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysPost.class);
|
||||||
List<SysPost> sysPostList = sysPostService.getNotInSysPostListByDeptId(deptId, filter, orderBy);
|
List<SysPost> sysPostList;
|
||||||
|
if (MyCommonUtil.isNotBlankOrNull(deptId)) {
|
||||||
|
sysPostList = sysPostService.getNotInSysPostListByDeptId(deptId, filter, orderBy);
|
||||||
|
} else {
|
||||||
|
sysPostList = sysPostService.getSysPostList(filter, orderBy);
|
||||||
|
}
|
||||||
return ResponseResult.success(MyPageUtil.makeResponseData(sysPostList, SysPost.INSTANCE));
|
return ResponseResult.success(MyPageUtil.makeResponseData(sysPostList, SysPost.INSTANCE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,13 +214,12 @@ public class SysDeptController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/listSysDeptPost")
|
@PostMapping("/listSysDeptPost")
|
||||||
public ResponseResult<MyPageData<SysPostVo>> listSysDeptPost(
|
public ResponseResult<MyPageData<SysPostVo>> listSysDeptPost(
|
||||||
@MyRequestBody Long deptId,
|
@MyRequestBody(required = true) Long deptId,
|
||||||
@MyRequestBody SysPostDto sysPostDtoFilter,
|
@MyRequestBody SysPostDto sysPostDtoFilter,
|
||||||
@MyRequestBody MyOrderParam orderParam,
|
@MyRequestBody MyOrderParam orderParam,
|
||||||
@MyRequestBody MyPageParam pageParam) {
|
@MyRequestBody MyPageParam pageParam) {
|
||||||
ResponseResult<Void> verifyResult = this.doSysDeptPostVerify(deptId);
|
if (!sysDeptService.existId(deptId)) {
|
||||||
if (!verifyResult.isSuccess()) {
|
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
|
||||||
return ResponseResult.errorFrom(verifyResult);
|
|
||||||
}
|
}
|
||||||
if (pageParam != null) {
|
if (pageParam != null) {
|
||||||
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
|
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
|
||||||
@@ -229,16 +230,6 @@ public class SysDeptController {
|
|||||||
return ResponseResult.success(MyPageUtil.makeResponseData(sysPostList, SysPost.INSTANCE));
|
return ResponseResult.success(MyPageUtil.makeResponseData(sysPostList, SysPost.INSTANCE));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResponseResult<Void> doSysDeptPostVerify(Long deptId) {
|
|
||||||
if (MyCommonUtil.existBlankArgument(deptId)) {
|
|
||||||
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
|
|
||||||
}
|
|
||||||
if (!sysDeptService.existId(deptId)) {
|
|
||||||
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
|
|
||||||
}
|
|
||||||
return ResponseResult.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量添加部门管理和 [岗位管理] 对象的多对多关联关系数据。
|
* 批量添加部门管理和 [岗位管理] 对象的多对多关联关系数据。
|
||||||
*
|
*
|
||||||
@@ -253,12 +244,10 @@ public class SysDeptController {
|
|||||||
if (MyCommonUtil.existBlankArgument(deptId, sysDeptPostDtoList)) {
|
if (MyCommonUtil.existBlankArgument(deptId, sysDeptPostDtoList)) {
|
||||||
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
|
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
|
||||||
}
|
}
|
||||||
for (SysDeptPostDto sysDeptPost : sysDeptPostDtoList) {
|
String errorMessage = MyCommonUtil.getModelValidationError(sysDeptPostDtoList);
|
||||||
String errorMessage = MyCommonUtil.getModelValidationError(sysDeptPost);
|
|
||||||
if (errorMessage != null) {
|
if (errorMessage != null) {
|
||||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Set<Long> postIdSet = sysDeptPostDtoList.stream().map(SysDeptPostDto::getPostId).collect(Collectors.toSet());
|
Set<Long> postIdSet = sysDeptPostDtoList.stream().map(SysDeptPostDto::getPostId).collect(Collectors.toSet());
|
||||||
if (!sysDeptService.existId(deptId) || !sysPostService.existUniqueKeyList("postId", postIdSet)) {
|
if (!sysDeptService.existId(deptId) || !sysPostService.existUniqueKeyList("postId", postIdSet)) {
|
||||||
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
|
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import com.flow.demo.common.core.util.*;
|
|||||||
import com.flow.demo.common.core.constant.*;
|
import com.flow.demo.common.core.constant.*;
|
||||||
import com.flow.demo.common.core.annotation.MyRequestBody;
|
import com.flow.demo.common.core.annotation.MyRequestBody;
|
||||||
import com.flow.demo.common.core.validator.AddGroup;
|
import com.flow.demo.common.core.validator.AddGroup;
|
||||||
import com.flow.demo.common.core.validator.UpdateGroup;
|
|
||||||
import com.flow.demo.webadmin.config.ApplicationConfig;
|
import com.flow.demo.webadmin.config.ApplicationConfig;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
@@ -19,7 +18,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import javax.validation.groups.Default;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户管理操作控制器类。
|
* 用户管理操作控制器类。
|
||||||
@@ -54,7 +52,7 @@ public class SysUserController {
|
|||||||
@MyRequestBody String deptPostIdListString,
|
@MyRequestBody String deptPostIdListString,
|
||||||
@MyRequestBody String dataPermIdListString,
|
@MyRequestBody String dataPermIdListString,
|
||||||
@MyRequestBody String roleIdListString) {
|
@MyRequestBody String roleIdListString) {
|
||||||
String errorMessage = MyCommonUtil.getModelValidationError(sysUserDto, Default.class, AddGroup.class);
|
String errorMessage = MyCommonUtil.getModelValidationError(sysUserDto, false);
|
||||||
if (errorMessage != null) {
|
if (errorMessage != null) {
|
||||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
}
|
}
|
||||||
@@ -86,7 +84,7 @@ public class SysUserController {
|
|||||||
@MyRequestBody String deptPostIdListString,
|
@MyRequestBody String deptPostIdListString,
|
||||||
@MyRequestBody String dataPermIdListString,
|
@MyRequestBody String dataPermIdListString,
|
||||||
@MyRequestBody String roleIdListString) {
|
@MyRequestBody String roleIdListString) {
|
||||||
String errorMessage = MyCommonUtil.getModelValidationError(sysUserDto, Default.class, UpdateGroup.class);
|
String errorMessage = MyCommonUtil.getModelValidationError(sysUserDto, true);
|
||||||
if (errorMessage != null) {
|
if (errorMessage != null) {
|
||||||
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,13 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public interface SysDeptMapper extends BaseDaoMapper<SysDept> {
|
public interface SysDeptMapper extends BaseDaoMapper<SysDept> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量插入对象列表。
|
||||||
|
*
|
||||||
|
* @param sysDeptList 新增对象列表。
|
||||||
|
*/
|
||||||
|
void insertList(List<SysDept> sysDeptList);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取过滤后的对象列表。
|
* 获取过滤后的对象列表。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -14,6 +14,13 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public interface SysUserMapper extends BaseDaoMapper<SysUser> {
|
public interface SysUserMapper extends BaseDaoMapper<SysUser> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量插入对象列表。
|
||||||
|
*
|
||||||
|
* @param sysUserList 新增对象列表。
|
||||||
|
*/
|
||||||
|
void insertList(List<SysUser> sysUserList);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取过滤后的对象列表。
|
* 获取过滤后的对象列表。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -13,6 +13,31 @@
|
|||||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
|
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
|
<insert id="insertList">
|
||||||
|
INSERT INTO zz_sys_dept
|
||||||
|
(dept_id,
|
||||||
|
dept_name,
|
||||||
|
show_order,
|
||||||
|
parent_id,
|
||||||
|
deleted_flag,
|
||||||
|
create_user_id,
|
||||||
|
update_user_id,
|
||||||
|
create_time,
|
||||||
|
update_time)
|
||||||
|
VALUES
|
||||||
|
<foreach collection="list" index="index" item="item" separator="," >
|
||||||
|
(#{item.deptId},
|
||||||
|
#{item.deptName},
|
||||||
|
#{item.showOrder},
|
||||||
|
#{item.parentId},
|
||||||
|
#{item.deletedFlag},
|
||||||
|
#{item.createUserId},
|
||||||
|
#{item.updateUserId},
|
||||||
|
#{item.createTime},
|
||||||
|
#{item.updateTime})
|
||||||
|
</foreach>
|
||||||
|
</insert>
|
||||||
|
|
||||||
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
|
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
|
||||||
<sql id="filterRef">
|
<sql id="filterRef">
|
||||||
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
|
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
|
||||||
|
|||||||
@@ -17,6 +17,39 @@
|
|||||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
|
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
|
<insert id="insertList">
|
||||||
|
INSERT INTO zz_sys_user
|
||||||
|
(user_id,
|
||||||
|
login_name,
|
||||||
|
password,
|
||||||
|
show_name,
|
||||||
|
dept_id,
|
||||||
|
user_type,
|
||||||
|
head_image_url,
|
||||||
|
user_status,
|
||||||
|
deleted_flag,
|
||||||
|
create_user_id,
|
||||||
|
update_user_id,
|
||||||
|
create_time,
|
||||||
|
update_time)
|
||||||
|
VALUES
|
||||||
|
<foreach collection="list" index="index" item="item" separator="," >
|
||||||
|
(#{item.userId},
|
||||||
|
#{item.loginName},
|
||||||
|
#{item.password},
|
||||||
|
#{item.showName},
|
||||||
|
#{item.deptId},
|
||||||
|
#{item.userType},
|
||||||
|
#{item.headImageUrl},
|
||||||
|
#{item.userStatus},
|
||||||
|
#{item.deletedFlag},
|
||||||
|
#{item.createUserId},
|
||||||
|
#{item.updateUserId},
|
||||||
|
#{item.createTime},
|
||||||
|
#{item.updateTime})
|
||||||
|
</foreach>
|
||||||
|
</insert>
|
||||||
|
|
||||||
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
|
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
|
||||||
<sql id="filterRef">
|
<sql id="filterRef">
|
||||||
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
|
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import lombok.Data;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SysDeptVO对象。
|
* SysDeptVO视图对象。
|
||||||
*
|
*
|
||||||
* @author Jerry
|
* @author Jerry
|
||||||
* @date 2021-06-06
|
* @date 2021-06-06
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import java.util.Map;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SysUserVO对象。
|
* SysUserVO视图对象。
|
||||||
*
|
*
|
||||||
* @author Jerry
|
* @author Jerry
|
||||||
* @date 2021-06-06
|
* @date 2021-06-06
|
||||||
|
|||||||
@@ -362,6 +362,52 @@ public abstract class BaseService<M, K extends Serializable> extends ServiceImpl
|
|||||||
return mapper().selectList(queryWrapper);
|
return mapper().selectList(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回符合主键 in (idValues) 条件的所有数据。同时返回关联数据。
|
||||||
|
*
|
||||||
|
* @param idValues 主键值集合。
|
||||||
|
* @param relationParam 实体对象数据组装的参数构建器。
|
||||||
|
* @return 检索后的数据列表。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<M> getInListWithRelation(Set<K> idValues, MyRelationParam relationParam) {
|
||||||
|
List<M> resultList = this.getInList(idValues);
|
||||||
|
this.buildRelationForDataList(resultList, relationParam);
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回符合 inFilterField in (inFilterValues) 条件的所有数据。同时返回关联数据。
|
||||||
|
*
|
||||||
|
* @param inFilterField 参与(In-list)过滤的Java字段。
|
||||||
|
* @param inFilterValues 参与(In-list)过滤的Java字段值集合。
|
||||||
|
* @param relationParam 实体对象数据组装的参数构建器。
|
||||||
|
* @return 检索后的数据列表。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> List<M> getInListWithRelation(String inFilterField, Set<T> inFilterValues, MyRelationParam relationParam) {
|
||||||
|
List<M> resultList = this.getInList(inFilterField, inFilterValues);
|
||||||
|
this.buildRelationForDataList(resultList, relationParam);
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回符合 inFilterField in (inFilterValues) 条件的所有数据,并根据orderBy字段排序。同时返回关联数据。
|
||||||
|
*
|
||||||
|
* @param inFilterField 参与(In-list)过滤的Java字段。
|
||||||
|
* @param inFilterValues 参与(In-list)过滤的Java字段值集合。
|
||||||
|
* @param orderBy 排序字段。
|
||||||
|
* @param relationParam 实体对象数据组装的参数构建器。
|
||||||
|
* @return 检索后的数据列表。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> List<M> getInListWithRelation(
|
||||||
|
String inFilterField, Set<T> inFilterValues, String orderBy, MyRelationParam relationParam) {
|
||||||
|
List<M> resultList = this.getInList(inFilterField, inFilterValues, orderBy);
|
||||||
|
this.buildRelationForDataList(resultList, relationParam);
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用参数对象作为过滤条件,获取数据数量。
|
* 用参数对象作为过滤条件,获取数据数量。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -121,6 +121,37 @@ public interface IBaseService<M, K extends Serializable> extends IService<M>{
|
|||||||
*/
|
*/
|
||||||
<T> List<M> getInList(String inFilterField, Set<T> inFilterValues, String orderBy);
|
<T> List<M> getInList(String inFilterField, Set<T> inFilterValues, String orderBy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回符合主键 in (idValues) 条件的所有数据。同时返回关联数据。
|
||||||
|
*
|
||||||
|
* @param idValues 主键值集合。
|
||||||
|
* @param relationParam 实体对象数据组装的参数构建器。
|
||||||
|
* @return 检索后的数据列表。
|
||||||
|
*/
|
||||||
|
List<M> getInListWithRelation(Set<K> idValues, MyRelationParam relationParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回符合 inFilterField in (inFilterValues) 条件的所有数据。同时返回关联数据。
|
||||||
|
*
|
||||||
|
* @param inFilterField 参与(In-list)过滤的Java字段。
|
||||||
|
* @param inFilterValues 参与(In-list)过滤的Java字段值集合。
|
||||||
|
* @param relationParam 实体对象数据组装的参数构建器。
|
||||||
|
* @return 检索后的数据列表。
|
||||||
|
*/
|
||||||
|
<T> List<M> getInListWithRelation(String inFilterField, Set<T> inFilterValues, MyRelationParam relationParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回符合 inFilterField in (inFilterValues) 条件的所有数据,并根据orderBy字段排序。同时返回关联数据。
|
||||||
|
*
|
||||||
|
* @param inFilterField 参与(In-list)过滤的Java字段。
|
||||||
|
* @param inFilterValues 参与(In-list)过滤的Java字段值集合。
|
||||||
|
* @param orderBy 排序字段。
|
||||||
|
* @param relationParam 实体对象数据组装的参数构建器。
|
||||||
|
* @return 检索后的数据列表。
|
||||||
|
*/
|
||||||
|
<T> List<M> getInListWithRelation(
|
||||||
|
String inFilterField, Set<T> inFilterValues, String orderBy, MyRelationParam relationParam);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用参数对象作为过滤条件,获取数据数量。
|
* 用参数对象作为过滤条件,获取数据数量。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -5,10 +5,13 @@ import cn.hutool.core.util.ReflectUtil;
|
|||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.crypto.digest.DigestUtil;
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
import com.flow.demo.common.core.constant.AppDeviceType;
|
import com.flow.demo.common.core.constant.AppDeviceType;
|
||||||
|
import com.flow.demo.common.core.validator.AddGroup;
|
||||||
|
import com.flow.demo.common.core.validator.UpdateGroup;
|
||||||
|
|
||||||
import javax.validation.ConstraintViolation;
|
import javax.validation.ConstraintViolation;
|
||||||
import javax.validation.Validation;
|
import javax.validation.Validation;
|
||||||
import javax.validation.Validator;
|
import javax.validation.Validator;
|
||||||
|
import javax.validation.groups.Default;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -109,12 +112,76 @@ public class MyCommonUtil {
|
|||||||
* @return 没有错误返回null,否则返回具体的错误信息。
|
* @return 没有错误返回null,否则返回具体的错误信息。
|
||||||
*/
|
*/
|
||||||
public static <T> String getModelValidationError(T model, Class<?>...groups) {
|
public static <T> String getModelValidationError(T model, Class<?>...groups) {
|
||||||
|
if (model != null) {
|
||||||
Set<ConstraintViolation<T>> constraintViolations = VALIDATOR.validate(model, groups);
|
Set<ConstraintViolation<T>> constraintViolations = VALIDATOR.validate(model, groups);
|
||||||
if (!constraintViolations.isEmpty()) {
|
if (!constraintViolations.isEmpty()) {
|
||||||
Iterator<ConstraintViolation<T>> it = constraintViolations.iterator();
|
Iterator<ConstraintViolation<T>> it = constraintViolations.iterator();
|
||||||
ConstraintViolation<T> constraint = it.next();
|
ConstraintViolation<T> constraint = it.next();
|
||||||
return constraint.getMessage();
|
return constraint.getMessage();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断模型对象是否通过校验,没有通过返回具体的校验错误信息。
|
||||||
|
*
|
||||||
|
* @param model 带校验的model。
|
||||||
|
* @param forUpdate 是否为更新。
|
||||||
|
* @return 没有错误返回null,否则返回具体的错误信息。
|
||||||
|
*/
|
||||||
|
public static <T> String getModelValidationError(T model, boolean forUpdate) {
|
||||||
|
if (model != null) {
|
||||||
|
Set<ConstraintViolation<T>> constraintViolations;
|
||||||
|
if (forUpdate) {
|
||||||
|
constraintViolations = VALIDATOR.validate(model, Default.class, UpdateGroup.class);
|
||||||
|
} else {
|
||||||
|
constraintViolations = VALIDATOR.validate(model, Default.class, AddGroup.class);
|
||||||
|
}
|
||||||
|
if (!constraintViolations.isEmpty()) {
|
||||||
|
Iterator<ConstraintViolation<T>> it = constraintViolations.iterator();
|
||||||
|
ConstraintViolation<T> constraint = it.next();
|
||||||
|
return constraint.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断模型对象是否通过校验,没有通过返回具体的校验错误信息。
|
||||||
|
*
|
||||||
|
* @param modelList 带校验的model列表。
|
||||||
|
* @param groups Validate绑定的校验组。
|
||||||
|
* @return 没有错误返回null,否则返回具体的错误信息。
|
||||||
|
*/
|
||||||
|
public static <T> String getModelValidationError(List<T> modelList, Class<?>... groups) {
|
||||||
|
if (CollUtil.isNotEmpty(modelList)) {
|
||||||
|
for (T model : modelList) {
|
||||||
|
String errorMessage = getModelValidationError(model, groups);
|
||||||
|
if (StrUtil.isNotBlank(errorMessage)) {
|
||||||
|
return errorMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断模型对象是否通过校验,没有通过返回具体的校验错误信息。
|
||||||
|
*
|
||||||
|
* @param modelList 带校验的model列表。
|
||||||
|
* @param forUpdate 是否为更新。
|
||||||
|
* @return 没有错误返回null,否则返回具体的错误信息。
|
||||||
|
*/
|
||||||
|
public static <T> String getModelValidationError(List<T> modelList, boolean forUpdate) {
|
||||||
|
if (CollUtil.isNotEmpty(modelList)) {
|
||||||
|
for (T model : modelList) {
|
||||||
|
String errorMessage = getModelValidationError(model, forUpdate);
|
||||||
|
if (StrUtil.isNotBlank(errorMessage)) {
|
||||||
|
return errorMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ public class MyModelUtil {
|
|||||||
* @return copy后的目标类型对象集合。
|
* @return copy后的目标类型对象集合。
|
||||||
*/
|
*/
|
||||||
public static <S, T> List<T> copyCollectionTo(Collection<S> sourceCollection, Class<T> targetClazz) {
|
public static <S, T> List<T> copyCollectionTo(Collection<S> sourceCollection, Class<T> targetClazz) {
|
||||||
|
if (sourceCollection == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
List<T> targetList = new LinkedList<>();
|
List<T> targetList = new LinkedList<>();
|
||||||
if (CollectionUtils.isNotEmpty(sourceCollection)) {
|
if (CollectionUtils.isNotEmpty(sourceCollection)) {
|
||||||
for (S source : sourceCollection) {
|
for (S source : sourceCollection) {
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ public class DataFilterProperties {
|
|||||||
/**
|
/**
|
||||||
* 是否启用租户过滤。
|
* 是否启用租户过滤。
|
||||||
*/
|
*/
|
||||||
@Value("${datafilter.tenant.enabled}")
|
@Value("${datafilter.tenant.enabled:false}")
|
||||||
private Boolean enabledTenantFilter;
|
private Boolean enabledTenantFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否启动数据权限过滤。
|
* 是否启动数据权限过滤。
|
||||||
*/
|
*/
|
||||||
@Value("${datafilter.dataperm.enabled}")
|
@Value("${datafilter.dataperm.enabled:false}")
|
||||||
private Boolean enabledDataPermFilter;
|
private Boolean enabledDataPermFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -85,8 +85,7 @@ public class MybatisDataFilterInterceptor implements Interceptor {
|
|||||||
if (proxy == null) {
|
if (proxy == null) {
|
||||||
proxy = ReflectUtil.getFieldValue(mapperProxy, "CGLIB$CALLBACK_0");
|
proxy = ReflectUtil.getFieldValue(mapperProxy, "CGLIB$CALLBACK_0");
|
||||||
}
|
}
|
||||||
Class<?> mapperClass =
|
Class<?> mapperClass = (Class<?>) ReflectUtil.getFieldValue(proxy, "mapperInterface");
|
||||||
(Class<?>) ReflectUtil.getFieldValue(proxy, "mapperInterface");
|
|
||||||
if (properties.getEnabledTenantFilter()) {
|
if (properties.getEnabledTenantFilter()) {
|
||||||
loadTenantFilterData(mapperClass);
|
loadTenantFilterData(mapperClass);
|
||||||
}
|
}
|
||||||
@@ -111,8 +110,7 @@ public class MybatisDataFilterInterceptor implements Interceptor {
|
|||||||
tenantInfo.setFieldName(field.getName());
|
tenantInfo.setFieldName(field.getName());
|
||||||
tenantInfo.setColumnName(MyModelUtil.mapToColumnName(field, modelClass));
|
tenantInfo.setColumnName(MyModelUtil.mapToColumnName(field, modelClass));
|
||||||
// 判断当前dao中是否包括不需要自动注入租户Id过滤的方法。
|
// 判断当前dao中是否包括不需要自动注入租户Id过滤的方法。
|
||||||
DisableTenantFilter disableTenantFilter =
|
DisableTenantFilter disableTenantFilter = mapperClass.getAnnotation(DisableTenantFilter.class);
|
||||||
mapperClass.getAnnotation(DisableTenantFilter.class);
|
|
||||||
if (disableTenantFilter != null) {
|
if (disableTenantFilter != null) {
|
||||||
// 这里开始获取当前Mapper已经声明的的SqlId中,有哪些是需要排除在外的。
|
// 这里开始获取当前Mapper已经声明的的SqlId中,有哪些是需要排除在外的。
|
||||||
// 排除在外的将不进行数据过滤。
|
// 排除在外的将不进行数据过滤。
|
||||||
@@ -280,16 +278,14 @@ public class MybatisDataFilterInterceptor implements Interceptor {
|
|||||||
String dataPermSessionKey = RedisKeyUtil.makeSessionDataPermIdKey(tokenData.getSessionId());
|
String dataPermSessionKey = RedisKeyUtil.makeSessionDataPermIdKey(tokenData.getSessionId());
|
||||||
String dataPermData = redissonClient.getBucket(dataPermSessionKey).get().toString();
|
String dataPermData = redissonClient.getBucket(dataPermSessionKey).get().toString();
|
||||||
if (StringUtils.isBlank(dataPermData)) {
|
if (StringUtils.isBlank(dataPermData)) {
|
||||||
throw new NoDataPermException(
|
throw new NoDataPermException("No Related DataPerm found for SQL_ID [ " + sqlId + " ].");
|
||||||
"No Related DataPerm found for SQL_ID [ " + sqlId + " ].");
|
|
||||||
}
|
}
|
||||||
Map<Integer, String> dataPermMap = new HashMap<>(8);
|
Map<Integer, String> dataPermMap = new HashMap<>(8);
|
||||||
for (Map.Entry<String, Object> entry : JSON.parseObject(dataPermData).entrySet()) {
|
for (Map.Entry<String, Object> entry : JSON.parseObject(dataPermData).entrySet()) {
|
||||||
dataPermMap.put(Integer.valueOf(entry.getKey()), entry.getValue().toString());
|
dataPermMap.put(Integer.valueOf(entry.getKey()), entry.getValue().toString());
|
||||||
}
|
}
|
||||||
if (MapUtils.isEmpty(dataPermMap)) {
|
if (MapUtils.isEmpty(dataPermMap)) {
|
||||||
throw new NoDataPermException(
|
throw new NoDataPermException("No Related DataPerm found for SQL_ID [ " + sqlId + " ].");
|
||||||
"No Related DataPerm found for SQL_ID [ " + sqlId + " ].");
|
|
||||||
}
|
}
|
||||||
if (dataPermMap.containsKey(DataPermRuleType.TYPE_ALL)) {
|
if (dataPermMap.containsKey(DataPermRuleType.TYPE_ALL)) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.flow.demo.common.flow.base.service;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.flow.demo.common.core.base.service.BaseService;
|
||||||
|
import com.flow.demo.common.flow.constant.FlowApprovalType;
|
||||||
|
import com.flow.demo.common.flow.constant.FlowTaskStatus;
|
||||||
|
import com.flow.demo.common.flow.model.FlowTaskComment;
|
||||||
|
import com.flow.demo.common.flow.service.FlowApiService;
|
||||||
|
import com.flow.demo.common.flow.service.FlowWorkOrderService;
|
||||||
|
import org.flowable.engine.runtime.ProcessInstance;
|
||||||
|
import org.flowable.task.api.Task;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public abstract class BaseFlowService<M, K extends Serializable> extends BaseService<M, K> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private FlowApiService flowApiService;
|
||||||
|
@Autowired
|
||||||
|
private FlowWorkOrderService flowWorkOrderService;
|
||||||
|
|
||||||
|
public void startAndTakeFirst(
|
||||||
|
String processDefinitionId, K dataId, FlowTaskComment comment, JSONObject variables) {
|
||||||
|
ProcessInstance instance = flowApiService.startAndTakeFirst(
|
||||||
|
processDefinitionId, dataId, comment, variables);
|
||||||
|
flowWorkOrderService.saveNew(instance, dataId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void takeFirstTask(
|
||||||
|
String processInstanceId, String taskId, K dataId, FlowTaskComment comment, JSONObject variables) {
|
||||||
|
Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId);
|
||||||
|
flowApiService.setBusinessKeyForProcessInstance(processInstanceId, dataId);
|
||||||
|
flowApiService.completeTask(task, comment, variables);
|
||||||
|
ProcessInstance instance = flowApiService.getProcessInstance(processInstanceId);
|
||||||
|
flowWorkOrderService.saveNew(instance, dataId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void takeTask(Task task, K dataId, FlowTaskComment comment, JSONObject variables) {
|
||||||
|
int flowStatus = FlowTaskStatus.APPROVING;
|
||||||
|
if (comment.getApprovalType().equals(FlowApprovalType.REFUSE)) {
|
||||||
|
flowStatus = FlowTaskStatus.REFUSED;
|
||||||
|
}
|
||||||
|
flowWorkOrderService.updateFlowStatusByBusinessKey(dataId.toString(), flowStatus);
|
||||||
|
flowApiService.completeTask(task, comment, variables);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ import lombok.Data;
|
|||||||
public class FlowWorkOrderDto {
|
public class FlowWorkOrderDto {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程状态。
|
* 流程状态。参考FlowTaskStatus常量值对象。
|
||||||
*/
|
*/
|
||||||
private Integer flowStatus;
|
private Integer flowStatus;
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public class FlowWorkOrder {
|
|||||||
private String businessKey;
|
private String businessKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程状态。
|
* 流程状态。参考FlowTaskStatus常量值对象。
|
||||||
*/
|
*/
|
||||||
@TableField(value = "flow_status")
|
@TableField(value = "flow_status")
|
||||||
private Integer flowStatus;
|
private Integer flowStatus;
|
||||||
|
|||||||
@@ -57,6 +57,14 @@ public interface FlowWorkOrderService extends IBaseService<FlowWorkOrder, Long>
|
|||||||
*/
|
*/
|
||||||
List<FlowWorkOrder> getFlowWorkOrderListWithRelation(FlowWorkOrder filter, String orderBy);
|
List<FlowWorkOrder> getFlowWorkOrderListWithRelation(FlowWorkOrder filter, String orderBy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据流程实例Id,查询关联的工单对象。
|
||||||
|
*
|
||||||
|
* @param processInstanceId 流程实例Id。
|
||||||
|
* @return 工作流工单对象。
|
||||||
|
*/
|
||||||
|
FlowWorkOrder getFlowWorkOrderByProcessInstanceId(String processInstanceId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据业务主键,查询是否存在指定的工单。
|
* 根据业务主键,查询是否存在指定的工单。
|
||||||
*
|
*
|
||||||
@@ -66,6 +74,13 @@ public interface FlowWorkOrderService extends IBaseService<FlowWorkOrder, Long>
|
|||||||
*/
|
*/
|
||||||
boolean existByBusinessKey(Object businessKey, boolean unfinished);
|
boolean existByBusinessKey(Object businessKey, boolean unfinished);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据业务数据的主键Id,更新流程状态。
|
||||||
|
* @param businessKey 业务数据主键Id。
|
||||||
|
* @param flowStatus 新的流程状态值。
|
||||||
|
*/
|
||||||
|
void updateFlowStatusByBusinessKey(String businessKey, int flowStatus);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据流程实例Id,更新流程状态。
|
* 根据流程实例Id,更新流程状态。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.flow.demo.common.flow.service.impl;
|
package com.flow.demo.common.flow.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.flow.demo.common.core.base.dao.BaseDaoMapper;
|
import com.flow.demo.common.core.base.dao.BaseDaoMapper;
|
||||||
import com.flow.demo.common.core.constant.GlobalDeletedFlag;
|
import com.flow.demo.common.core.constant.GlobalDeletedFlag;
|
||||||
import com.flow.demo.common.core.object.MyRelationParam;
|
import com.flow.demo.common.core.object.MyRelationParam;
|
||||||
@@ -109,6 +110,13 @@ public class FlowWorkOrderServiceImpl extends BaseService<FlowWorkOrder, Long> i
|
|||||||
return resultList;
|
return resultList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FlowWorkOrder getFlowWorkOrderByProcessInstanceId(String processInstanceId) {
|
||||||
|
FlowWorkOrder filter = new FlowWorkOrder();
|
||||||
|
filter.setProcessInstanceId(processInstanceId);
|
||||||
|
return flowWorkOrderMapper.selectOne(new QueryWrapper<>(filter));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean existByBusinessKey(Object businessKey, boolean unfinished) {
|
public boolean existByBusinessKey(Object businessKey, boolean unfinished) {
|
||||||
LambdaQueryWrapper<FlowWorkOrder> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<FlowWorkOrder> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
@@ -120,6 +128,20 @@ public class FlowWorkOrderServiceImpl extends BaseService<FlowWorkOrder, Long> i
|
|||||||
return flowWorkOrderMapper.selectCount(queryWrapper) > 0;
|
return flowWorkOrderMapper.selectCount(queryWrapper) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Override
|
||||||
|
public void updateFlowStatusByBusinessKey(String businessKey, int flowStatus) {
|
||||||
|
FlowWorkOrder flowWorkOrder = new FlowWorkOrder();
|
||||||
|
flowWorkOrder.setFlowStatus(flowStatus);
|
||||||
|
if (FlowTaskStatus.FINISHED != flowStatus) {
|
||||||
|
flowWorkOrder.setUpdateTime(new Date());
|
||||||
|
flowWorkOrder.setUpdateUserId(TokenData.takeFromRequest().getUserId());
|
||||||
|
}
|
||||||
|
LambdaQueryWrapper<FlowWorkOrder> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.eq(FlowWorkOrder::getBusinessKey, businessKey);
|
||||||
|
flowWorkOrderMapper.update(flowWorkOrder, queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@Override
|
@Override
|
||||||
public void updateFlowStatusByProcessInstanceId(String processInstanceId, int flowStatus) {
|
public void updateFlowStatusByProcessInstanceId(String processInstanceId, int flowStatus) {
|
||||||
|
|||||||
@@ -7,11 +7,14 @@ import com.alibaba.fastjson.JSON;
|
|||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.flow.demo.common.core.constant.ErrorCodeEnum;
|
import com.flow.demo.common.core.constant.ErrorCodeEnum;
|
||||||
|
import com.flow.demo.common.core.object.CallResult;
|
||||||
import com.flow.demo.common.core.object.ResponseResult;
|
import com.flow.demo.common.core.object.ResponseResult;
|
||||||
import com.flow.demo.common.core.object.TokenData;
|
import com.flow.demo.common.core.object.TokenData;
|
||||||
import com.flow.demo.common.core.util.MyModelUtil;
|
import com.flow.demo.common.core.util.MyModelUtil;
|
||||||
|
import com.flow.demo.common.flow.constant.FlowApprovalType;
|
||||||
import com.flow.demo.common.flow.constant.FlowConstant;
|
import com.flow.demo.common.flow.constant.FlowConstant;
|
||||||
import com.flow.demo.common.flow.constant.FlowTaskStatus;
|
import com.flow.demo.common.flow.constant.FlowTaskStatus;
|
||||||
|
import com.flow.demo.common.flow.dto.FlowTaskCommentDto;
|
||||||
import com.flow.demo.common.flow.dto.FlowWorkOrderDto;
|
import com.flow.demo.common.flow.dto.FlowWorkOrderDto;
|
||||||
import com.flow.demo.common.flow.model.FlowEntry;
|
import com.flow.demo.common.flow.model.FlowEntry;
|
||||||
import com.flow.demo.common.flow.model.FlowEntryPublish;
|
import com.flow.demo.common.flow.model.FlowEntryPublish;
|
||||||
@@ -22,8 +25,11 @@ import com.flow.demo.common.flow.service.FlowEntryService;
|
|||||||
import com.flow.demo.common.flow.vo.FlowWorkOrderVo;
|
import com.flow.demo.common.flow.vo.FlowWorkOrderVo;
|
||||||
import com.flow.demo.common.flow.vo.TaskInfoVo;
|
import com.flow.demo.common.flow.vo.TaskInfoVo;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.flowable.engine.history.HistoricProcessInstance;
|
||||||
|
import org.flowable.engine.runtime.ProcessInstance;
|
||||||
import org.flowable.task.api.Task;
|
import org.flowable.task.api.Task;
|
||||||
import org.flowable.task.api.TaskInfo;
|
import org.flowable.task.api.TaskInfo;
|
||||||
|
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -71,6 +77,103 @@ public class FlowOperationHelper {
|
|||||||
return ResponseResult.success(flowEntry);
|
return ResponseResult.success(flowEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作流静态表单的参数验证工具方法。根据流程定义标识,获取关联的流程并对其进行合法性验证。
|
||||||
|
*
|
||||||
|
* @param processDefinitionKey 流程定义标识。
|
||||||
|
* @return 返回流程对象。
|
||||||
|
*/
|
||||||
|
public ResponseResult<FlowEntry> verifyFullAndGetFlowEntry(String processDefinitionKey) {
|
||||||
|
String errorMessage;
|
||||||
|
// 验证流程管理数据状态的合法性。
|
||||||
|
ResponseResult<FlowEntry> flowEntryResult = this.verifyAndGetFlowEntry(processDefinitionKey);
|
||||||
|
if (!flowEntryResult.isSuccess()) {
|
||||||
|
return ResponseResult.errorFrom(flowEntryResult);
|
||||||
|
}
|
||||||
|
// 验证流程一个用户任务的合法性。
|
||||||
|
FlowEntryPublish flowEntryPublish = flowEntryResult.getData().getMainFlowEntryPublish();
|
||||||
|
if (!flowEntryPublish.getActiveStatus()) {
|
||||||
|
errorMessage = "数据验证失败,当前流程发布对象已被挂起,不能启动新流程!";
|
||||||
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
|
}
|
||||||
|
ResponseResult<TaskInfoVo> taskInfoResult =
|
||||||
|
this.verifyAndGetInitialTaskInfo(flowEntryPublish, true);
|
||||||
|
if (!taskInfoResult.isSuccess()) {
|
||||||
|
return ResponseResult.errorFrom(taskInfoResult);
|
||||||
|
}
|
||||||
|
return flowEntryResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作流静态表单的参数验证工具方法。根据参数验证并获取指定的流程任务对象。
|
||||||
|
*
|
||||||
|
* @param processInstanceId 流程实例Id。
|
||||||
|
* @param taskId 流程任务Id。
|
||||||
|
* @param flowTaskComment 流程审批对象。
|
||||||
|
* @return 验证后的流程任务对象。
|
||||||
|
*/
|
||||||
|
public ResponseResult<Task> verifySubmitAndGetTask(
|
||||||
|
String processInstanceId, String taskId, FlowTaskCommentDto flowTaskComment) {
|
||||||
|
// 验证流程任务的合法性。
|
||||||
|
Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId);
|
||||||
|
ResponseResult<TaskInfoVo> taskInfoResult = this.verifyAndGetRuntimeTaskInfo(task);
|
||||||
|
if (!taskInfoResult.isSuccess()) {
|
||||||
|
return ResponseResult.errorFrom(taskInfoResult);
|
||||||
|
}
|
||||||
|
CallResult assigneeVerifyResult = flowApiService.verifyAssigneeOrCandidateAndClaim(task);
|
||||||
|
if (!assigneeVerifyResult.isSuccess()) {
|
||||||
|
return ResponseResult.errorFrom(assigneeVerifyResult);
|
||||||
|
}
|
||||||
|
ProcessInstance instance = flowApiService.getProcessInstance(processInstanceId);
|
||||||
|
if (StrUtil.isBlank(instance.getBusinessKey())) {
|
||||||
|
return ResponseResult.success(task);
|
||||||
|
}
|
||||||
|
String errorMessage;
|
||||||
|
if (StrUtil.equals(flowTaskComment.getApprovalType(), FlowApprovalType.TRANSFER)) {
|
||||||
|
if (StrUtil.isBlank(flowTaskComment.getDelegateAssginee())) {
|
||||||
|
errorMessage = "数据验证失败,加签或转办任务指派人不能为空!!";
|
||||||
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ResponseResult.success(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作流静态表单的参数验证工具方法。根据参数验证并获取指定的历史流程实例对象。
|
||||||
|
* 仅当登录用户为任务的分配人时,才能通过验证。
|
||||||
|
*
|
||||||
|
* @param processInstanceId 历史流程实例Id。
|
||||||
|
* @param taskId 历史流程任务Id。
|
||||||
|
* @return 验证后并返回的历史流程实例对象。
|
||||||
|
*/
|
||||||
|
public ResponseResult<HistoricProcessInstance> verifyAndHistoricProcessInstance(String processInstanceId, String taskId) {
|
||||||
|
String errorMessage;
|
||||||
|
// 验证流程实例的合法性。
|
||||||
|
HistoricProcessInstance instance = flowApiService.getHistoricProcessInstance(processInstanceId);
|
||||||
|
if (instance == null) {
|
||||||
|
errorMessage = "数据验证失败,指定的流程实例Id并不存在,请刷新后重试!";
|
||||||
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
|
}
|
||||||
|
String loginName = TokenData.takeFromRequest().getLoginName();
|
||||||
|
if (StrUtil.isBlank(taskId)) {
|
||||||
|
if (!StrUtil.equals(loginName, instance.getStartUserId())) {
|
||||||
|
errorMessage = "数据验证失败,指定历史流程的发起人与当前用户不匹配!";
|
||||||
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
HistoricTaskInstance taskInstance = flowApiService.getHistoricTaskInstance(processInstanceId, taskId);
|
||||||
|
if (taskInstance == null) {
|
||||||
|
errorMessage = "数据验证失败,指定的任务Id并不存在,请刷新后重试!";
|
||||||
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
|
}
|
||||||
|
if (!StrUtil.equals(loginName, taskInstance.getAssignee())) {
|
||||||
|
errorMessage = "数据验证失败,历史任务的指派人与当前用户不匹配!";
|
||||||
|
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ResponseResult.success(instance);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证并获取流程的实时任务信息。
|
* 验证并获取流程的实时任务信息。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class FlowWorkOrderVo {
|
|||||||
private String businessKey;
|
private String businessKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程状态。
|
* 流程状态。参考FlowTaskStatus常量值对象。
|
||||||
*/
|
*/
|
||||||
private Integer flowStatus;
|
private Integer flowStatus;
|
||||||
|
|
||||||
|
|||||||
@@ -117,6 +117,10 @@ public class OnlineColumnServiceImpl extends BaseService<OnlineColumn, Long> imp
|
|||||||
public void refresh(SqlTableColumn sqlTableColumn, OnlineColumn onlineColumn) {
|
public void refresh(SqlTableColumn sqlTableColumn, OnlineColumn onlineColumn) {
|
||||||
this.evictTableCache(onlineColumn.getTableId());
|
this.evictTableCache(onlineColumn.getTableId());
|
||||||
BeanUtil.copyProperties(sqlTableColumn, onlineColumn, false);
|
BeanUtil.copyProperties(sqlTableColumn, onlineColumn, false);
|
||||||
|
String objectFieldName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, onlineColumn.getColumnName());
|
||||||
|
onlineColumn.setObjectFieldName(objectFieldName);
|
||||||
|
String objectFieldType = convertToJavaType(onlineColumn.getColumnType());
|
||||||
|
onlineColumn.setObjectFieldType(objectFieldType);
|
||||||
onlineColumnMapper.updateById(onlineColumn);
|
onlineColumnMapper.updateById(onlineColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>framework</artifactId>
|
||||||
|
<groupId>com.flow.demo</groupId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>apidoc-tools</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<name>apidoc-tools</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.flow.demo</groupId>
|
||||||
|
<artifactId>common-core</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.thoughtworks.qdox</groupId>
|
||||||
|
<artifactId>qdox</artifactId>
|
||||||
|
<version>${qdox.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.flow.demo.apidoc.tools;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.flow.demo.apidoc.tools.codeparser.ApiCodeConfig;
|
||||||
|
import com.flow.demo.apidoc.tools.codeparser.ApiCodeParser;
|
||||||
|
import com.flow.demo.apidoc.tools.export.ApiPostmanExporter;
|
||||||
|
import freemarker.template.TemplateException;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class ExportApiApp {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException, TemplateException {
|
||||||
|
// 在第一次导出时,需要打开export-api-config.json配置文件,
|
||||||
|
// 修改其中的工程根目录配置项(projectRootPath),其他配置保持不变即可。
|
||||||
|
InputStream in = ExportApiApp.class.getResourceAsStream("/export-api-config.json");
|
||||||
|
String jsonData = StreamUtils.copyToString(in, StandardCharsets.UTF_8);
|
||||||
|
ApiCodeConfig apiCodeConfig = JSON.parseObject(jsonData, ApiCodeConfig.class);
|
||||||
|
ApiCodeParser apiCodeParser = new ApiCodeParser(apiCodeConfig);
|
||||||
|
ApiCodeParser.ApiProject project = apiCodeParser.doParse();
|
||||||
|
ApiPostmanExporter exporter = new ApiPostmanExporter();
|
||||||
|
// 将下面的目录改为实际输出目录。
|
||||||
|
exporter.doGenerate(project, "/xxx/Desktop/1.json");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.flow.demo.apidoc.tools;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.flow.demo.apidoc.tools.codeparser.ApiCodeConfig;
|
||||||
|
import com.flow.demo.apidoc.tools.codeparser.ApiCodeParser;
|
||||||
|
import com.flow.demo.apidoc.tools.export.ApiDocExporter;
|
||||||
|
import freemarker.template.TemplateException;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class ExportDocApp {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException, TemplateException {
|
||||||
|
// 在第一次导出时,需要打开export-api-config.json配置文件,
|
||||||
|
// 修改其中的工程根目录配置项(projectRootPath),其他配置保持不变即可。
|
||||||
|
InputStream in = ExportDocApp.class.getResourceAsStream("/export-api-config.json");
|
||||||
|
String jsonData = StreamUtils.copyToString(in, StandardCharsets.UTF_8);
|
||||||
|
ApiCodeConfig apiCodeConfig = JSON.parseObject(jsonData, ApiCodeConfig.class);
|
||||||
|
ApiCodeParser apiCodeParser = new ApiCodeParser(apiCodeConfig);
|
||||||
|
ApiCodeParser.ApiProject project = apiCodeParser.doParse();
|
||||||
|
ApiDocExporter exporter = new ApiDocExporter();
|
||||||
|
// 将下面的目录改为实际输出目录。
|
||||||
|
exporter.doGenerate(project, "/xxx/Desktop/2.md");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.flow.demo.apidoc.tools.codeparser;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析项目中接口信息的配置对象。
|
||||||
|
*
|
||||||
|
* @author Jerry
|
||||||
|
* @date 2021-06-06
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ApiCodeConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目名称。
|
||||||
|
*/
|
||||||
|
private String projectName;
|
||||||
|
/**
|
||||||
|
* 项目的基础包名,如(com.demo.multi)。
|
||||||
|
*/
|
||||||
|
private String basePackage;
|
||||||
|
/**
|
||||||
|
* 项目在本地文件系统中的根目录。这里需要注意的是,Windows用户请务必使用反斜杠作为目录分隔符。
|
||||||
|
* 如:"e:/mypath/OrangeSingleDemo","/Users/xxx/OrangeSingleDemo"。
|
||||||
|
*/
|
||||||
|
private String projectRootPath;
|
||||||
|
/**
|
||||||
|
* 是否为微服务项目。
|
||||||
|
*/
|
||||||
|
private Boolean microService;
|
||||||
|
/**
|
||||||
|
* 服务配置列表。对于单体服务,至少也会有一个ServiceConfig对象。
|
||||||
|
*/
|
||||||
|
private List<ServiceConfig> serviceList;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ServiceConfig {
|
||||||
|
/**
|
||||||
|
* 服务名称。
|
||||||
|
*/
|
||||||
|
private String serviceName;
|
||||||
|
/**
|
||||||
|
* 服务中文显示名称。
|
||||||
|
*/
|
||||||
|
private String showName;
|
||||||
|
/**
|
||||||
|
* 服务所在目录,相对于工程目录的子目录。
|
||||||
|
*/
|
||||||
|
private String servicePath;
|
||||||
|
/**
|
||||||
|
* 仅用于微服务工程。通常为服务路由路径,如:/admin/coursepaper。服务内的接口,都会加上该路径前缀。
|
||||||
|
*/
|
||||||
|
private String serviceRequestPath;
|
||||||
|
/**
|
||||||
|
* 服务的端口号。
|
||||||
|
*/
|
||||||
|
private String port;
|
||||||
|
/**
|
||||||
|
* Api Controller信息列表。
|
||||||
|
*/
|
||||||
|
private List<ControllerInfo> controllerInfoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ControllerInfo {
|
||||||
|
/**
|
||||||
|
* Controller.java等接口文件的所在目录。该目录仅为相对于服务代码目录的子目录。
|
||||||
|
* 目录分隔符请务必使用反斜杠。如:"/com/orange/demo/app/controller"。
|
||||||
|
*/
|
||||||
|
private String path;
|
||||||
|
/**
|
||||||
|
* 如果一个服务内,存在多个Controller目录,将再次生成二级子目录,目录名为groupName。(可使用中文)
|
||||||
|
*/
|
||||||
|
private String groupName;
|
||||||
|
/**
|
||||||
|
* 在当前Controller目录下,需要忽略的Controller列表 (只写类名即可)。如:LoginController。
|
||||||
|
*/
|
||||||
|
private Set<String> skipControllers;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,672 @@
|
|||||||
|
package com.flow.demo.apidoc.tools.codeparser;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.flow.demo.common.core.object.Tuple2;
|
||||||
|
import com.flow.demo.apidoc.tools.exception.ApiCodeConfigParseException;
|
||||||
|
import com.thoughtworks.qdox.JavaProjectBuilder;
|
||||||
|
import com.thoughtworks.qdox.model.*;
|
||||||
|
import com.thoughtworks.qdox.model.impl.DefaultJavaParameterizedType;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析项目中的接口信息,以及关联的Model、Dto和Mapper,主要用于生成接口文档。
|
||||||
|
*
|
||||||
|
* @author Jerry
|
||||||
|
* @date 2021-06-06
|
||||||
|
*/
|
||||||
|
public class ApiCodeParser {
|
||||||
|
|
||||||
|
private static final String PATH_SEPERATOR = "/";
|
||||||
|
private static final String REQUEST_MAPPING = "RequestMapping";
|
||||||
|
private static final String FULL_REQUEST_MAPPING = "org.springframework.web.bind.annotation.RequestMapping";
|
||||||
|
private static final String GET_MAPPING = "GetMapping";
|
||||||
|
private static final String FULL_GET_MAPPING = "org.springframework.web.bind.annotation.GetMapping";
|
||||||
|
private static final String POST_MAPPING = "PostMapping";
|
||||||
|
private static final String FULL_POST_MAPPING = "org.springframework.web.bind.annotation.PostMapping";
|
||||||
|
private static final String VALUE_PROP = "value";
|
||||||
|
private static final String REQUIRED_PROP = "required";
|
||||||
|
private static final String DELETED_COLUMN = "DeletedFlagColumn";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 忽略微服务间标准调用接口的导出。
|
||||||
|
*/
|
||||||
|
private static final Set<String> IGNORED_API_METHOD_SET = new HashSet<>(8);
|
||||||
|
|
||||||
|
static {
|
||||||
|
IGNORED_API_METHOD_SET.add("listByIds");
|
||||||
|
IGNORED_API_METHOD_SET.add("getById");
|
||||||
|
IGNORED_API_METHOD_SET.add("existIds");
|
||||||
|
IGNORED_API_METHOD_SET.add("existId");
|
||||||
|
IGNORED_API_METHOD_SET.add("deleteById");
|
||||||
|
IGNORED_API_METHOD_SET.add("deleteBy");
|
||||||
|
IGNORED_API_METHOD_SET.add("listBy");
|
||||||
|
IGNORED_API_METHOD_SET.add("listMapBy");
|
||||||
|
IGNORED_API_METHOD_SET.add("listByNotInList");
|
||||||
|
IGNORED_API_METHOD_SET.add("getBy");
|
||||||
|
IGNORED_API_METHOD_SET.add("countBy");
|
||||||
|
IGNORED_API_METHOD_SET.add("aggregateBy");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础配置。
|
||||||
|
*/
|
||||||
|
private ApiCodeConfig config;
|
||||||
|
/**
|
||||||
|
* 工程对象。
|
||||||
|
*/
|
||||||
|
private ApiProject apiProject;
|
||||||
|
/**
|
||||||
|
* 项目中所有的解析后Java文件,key是Java对象的全名,如:com.flow.demo.xxxx.Student。
|
||||||
|
*/
|
||||||
|
private final Map<String, JavaClass> projectJavaClassMap = new HashMap<>(128);
|
||||||
|
/**
|
||||||
|
* 存储服务数据。key为配置的serviceName。
|
||||||
|
*/
|
||||||
|
private final Map<String, InternalServiceData> serviceDataMap = new HashMap<>(8);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数。
|
||||||
|
*
|
||||||
|
* @param config 配置对象。
|
||||||
|
*/
|
||||||
|
public ApiCodeParser(ApiCodeConfig config) {
|
||||||
|
this.config = config;
|
||||||
|
// 验证配置中的数据是否正确,出现错误直接抛出运行时异常。
|
||||||
|
this.verifyConfigData();
|
||||||
|
// 将配置文件中所有目录相关的参数,全部规格化处理,后续的使用中不用再做处理了。
|
||||||
|
this.normalizeConfigPath();
|
||||||
|
for (ApiCodeConfig.ServiceConfig serviceConfig : config.getServiceList()) {
|
||||||
|
InternalServiceData serviceData = new InternalServiceData();
|
||||||
|
// 仅有微服务项目,需要添加服务路由路径。
|
||||||
|
if (StrUtil.isNotBlank(serviceConfig.getServiceRequestPath())) {
|
||||||
|
String serviceRequestPath = "";
|
||||||
|
if (!serviceRequestPath.equals(PATH_SEPERATOR)) {
|
||||||
|
serviceRequestPath = normalizePath(serviceConfig.getServiceRequestPath());
|
||||||
|
}
|
||||||
|
serviceData.setServiceRequestPath(serviceRequestPath);
|
||||||
|
}
|
||||||
|
serviceDataMap.put(serviceConfig.getServiceName(), serviceData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行解析操作。
|
||||||
|
*
|
||||||
|
* @return 解析后的工程对象。
|
||||||
|
*/
|
||||||
|
public ApiProject doParse() throws IOException {
|
||||||
|
// 先把工程完整编译一遍,以便工程内的Java对象的引用信息更加完整。
|
||||||
|
this.parseProject();
|
||||||
|
// 开始逐级推演。
|
||||||
|
apiProject = new ApiProject();
|
||||||
|
apiProject.setProjectName(config.getProjectName());
|
||||||
|
apiProject.setMicroService(config.getMicroService());
|
||||||
|
apiProject.setServiceList(new LinkedList<>());
|
||||||
|
for (ApiCodeConfig.ServiceConfig serviceConfig : config.getServiceList()) {
|
||||||
|
ApiService apiService = this.parseService(serviceConfig);
|
||||||
|
apiProject.getServiceList().add(apiService);
|
||||||
|
}
|
||||||
|
return apiProject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseProject() throws IOException {
|
||||||
|
JavaProjectBuilder javaProjectBuilder = new JavaProjectBuilder();
|
||||||
|
javaProjectBuilder.setEncoding(StandardCharsets.UTF_8.name());
|
||||||
|
javaProjectBuilder.addSourceTree(new File(config.getProjectRootPath()));
|
||||||
|
// 全部导入,便于后续解析中使用和检索。
|
||||||
|
for (JavaClass javaClass : javaProjectBuilder.getClasses()) {
|
||||||
|
projectJavaClassMap.put(javaClass.getFullyQualifiedName(), javaClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApiService parseService(ApiCodeConfig.ServiceConfig serviceConfig) {
|
||||||
|
InternalServiceData serviceData = serviceDataMap.get(serviceConfig.getServiceName());
|
||||||
|
ApiService apiService = new ApiService();
|
||||||
|
apiService.setServiceName(serviceConfig.getServiceName());
|
||||||
|
apiService.setShowName(serviceConfig.getShowName());
|
||||||
|
apiService.setPort(serviceConfig.getPort());
|
||||||
|
List<ApiCodeConfig.ControllerInfo> controllerInfoList = serviceConfig.getControllerInfoList();
|
||||||
|
// 准备解析接口文件
|
||||||
|
for (ApiCodeConfig.ControllerInfo controllerInfo : controllerInfoList) {
|
||||||
|
JavaProjectBuilder javaControllerBuilder = new JavaProjectBuilder();
|
||||||
|
javaControllerBuilder.addSourceTree(new File(controllerInfo.getPath()));
|
||||||
|
for (JavaClass javaClass : javaControllerBuilder.getClasses()) {
|
||||||
|
if (controllerInfo.getSkipControllers() != null
|
||||||
|
&& controllerInfo.getSkipControllers().contains(javaClass.getName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ApiClass apiClass = this.parseApiClass(controllerInfo, javaClass.getFullyQualifiedName(), serviceData);
|
||||||
|
if (apiClass != null) {
|
||||||
|
// 如果配置中,为当前ControllerInfo添加了groupName属性,
|
||||||
|
// 所有的生成后接口都会位于serviceName/groupName子目录,否则,都直接位于当前服务的子目录。
|
||||||
|
if (StrUtil.isBlank(apiClass.getGroupName())) {
|
||||||
|
apiService.getDefaultGroupClassSet().add(apiClass);
|
||||||
|
} else {
|
||||||
|
Set<ApiClass> groupedClassList = apiService.getGroupedClassMap()
|
||||||
|
.computeIfAbsent(apiClass.getGroupName(), k -> new TreeSet<>());
|
||||||
|
groupedClassList.add(apiClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return apiService;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApiClass parseApiClass(
|
||||||
|
ApiCodeConfig.ControllerInfo controllerInfo,
|
||||||
|
String classFullname,
|
||||||
|
InternalServiceData serviceData) {
|
||||||
|
// 去包含工程全部Class的Map中,找到当前ControllerClass。
|
||||||
|
// 之所以这样做,主要是因为全工程分析controller文件,会包含更多更精确的对象关联信息。
|
||||||
|
JavaClass controllerClass = this.projectJavaClassMap.get(classFullname);
|
||||||
|
List<JavaAnnotation> classAnnotations = controllerClass.getAnnotations();
|
||||||
|
boolean hasControllerAnnotation = false;
|
||||||
|
String requestPath = "";
|
||||||
|
for (JavaAnnotation annotation : classAnnotations) {
|
||||||
|
String annotationName = annotation.getType().getValue();
|
||||||
|
if (this.isRequestMapping(annotationName) && annotation.getNamedParameter(VALUE_PROP) != null) {
|
||||||
|
requestPath = StrUtil.removeAll(
|
||||||
|
annotation.getNamedParameter(VALUE_PROP).toString(), "\"");
|
||||||
|
if (requestPath.equals(PATH_SEPERATOR) || StrUtil.isBlank(requestPath)) {
|
||||||
|
requestPath = "";
|
||||||
|
} else {
|
||||||
|
requestPath = normalizePath(requestPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isController(annotationName)) {
|
||||||
|
hasControllerAnnotation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasControllerAnnotation) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
requestPath = serviceData.getServiceRequestPath() + requestPath;
|
||||||
|
ApiClass apiClass = new ApiClass();
|
||||||
|
apiClass.setName(controllerClass.getName());
|
||||||
|
apiClass.setFullName(controllerClass.getFullyQualifiedName());
|
||||||
|
apiClass.setComment(controllerClass.getComment());
|
||||||
|
apiClass.setGroupName(controllerInfo.getGroupName());
|
||||||
|
apiClass.setRequestPath(requestPath);
|
||||||
|
List<ApiMethod> methodList = this.parseApiMethodList(apiClass, controllerClass);
|
||||||
|
apiClass.setMethodList(methodList);
|
||||||
|
return apiClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean needToIgnore(JavaMethod method) {
|
||||||
|
return !method.isPublic() || method.isStatic() || IGNORED_API_METHOD_SET.contains(method.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ApiMethod> parseApiMethodList(ApiClass apiClass, JavaClass javaClass) {
|
||||||
|
List<ApiMethod> apiMethodList = new LinkedList<>();
|
||||||
|
List<JavaMethod> methodList = javaClass.getMethods();
|
||||||
|
for (JavaMethod method : methodList) {
|
||||||
|
if (this.needToIgnore(method)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<JavaAnnotation> methodAnnotations = method.getAnnotations();
|
||||||
|
Tuple2<String, String> result = this.parseRequestPathAndHttpMethod(methodAnnotations);
|
||||||
|
String methodRequestPath = result.getFirst();
|
||||||
|
String httpMethod = result.getSecond();
|
||||||
|
if (StrUtil.isNotBlank(methodRequestPath)) {
|
||||||
|
ApiMethod apiMethod = new ApiMethod();
|
||||||
|
apiMethod.setName(method.getName());
|
||||||
|
apiMethod.setComment(method.getComment());
|
||||||
|
apiMethod.setHttpMethod(httpMethod);
|
||||||
|
methodRequestPath = StrUtil.removeAll(methodRequestPath, "\"");
|
||||||
|
methodRequestPath = apiClass.getRequestPath() + normalizePath(methodRequestPath);
|
||||||
|
apiMethod.setRequestPath(methodRequestPath);
|
||||||
|
apiMethod.setPathList(StrUtil.splitTrim(apiMethod.getRequestPath(), PATH_SEPERATOR));
|
||||||
|
if (apiMethod.getRequestPath().contains("/listDict")) {
|
||||||
|
apiMethod.setListDictUrl(true);
|
||||||
|
} else if (apiMethod.getRequestPath().endsWith("/list")
|
||||||
|
|| apiMethod.getRequestPath().endsWith("/listWithGroup")
|
||||||
|
|| apiMethod.getRequestPath().contains("/listNotIn")
|
||||||
|
|| apiMethod.getRequestPath().contains("/list")) {
|
||||||
|
apiMethod.setListUrl(true);
|
||||||
|
} else if (apiMethod.getRequestPath().contains("/doLogin")) {
|
||||||
|
apiMethod.setLoginUrl(true);
|
||||||
|
}
|
||||||
|
JavaClass returnClass = method.getReturns();
|
||||||
|
if (returnClass.isVoid()) {
|
||||||
|
apiMethod.setReturnString("void");
|
||||||
|
} else {
|
||||||
|
apiMethod.setReturnString(returnClass.getGenericValue());
|
||||||
|
}
|
||||||
|
apiMethodList.add(apiMethod);
|
||||||
|
List<ApiArgument> apiArgumentList = this.parseApiMethodArgumentList(method);
|
||||||
|
apiMethod.setArgumentList(apiArgumentList);
|
||||||
|
this.classifyArgumentList(apiMethod, apiArgumentList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return apiMethodList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void classifyArgumentList(ApiMethod apiMethod, List<ApiArgument> apiArgumentList) {
|
||||||
|
for (ApiArgument arg : apiArgumentList) {
|
||||||
|
if (arg.getAnnotationType() == ApiArgumentAnnotationType.REQUEST_PARAM) {
|
||||||
|
if (arg.uploadFileParam) {
|
||||||
|
apiMethod.getUploadParamArgumentList().add(arg);
|
||||||
|
} else {
|
||||||
|
apiMethod.getQueryParamArgumentList().add(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (arg.getAnnotationType() != ApiArgumentAnnotationType.REQUEST_PARAM) {
|
||||||
|
apiMethod.getJsonParamArgumentList().add(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tuple2<String, String> parseRequestPathAndHttpMethod(List<JavaAnnotation> methodAnnotations) {
|
||||||
|
for (JavaAnnotation annotation : methodAnnotations) {
|
||||||
|
String annotationName = annotation.getType().getValue();
|
||||||
|
if (GET_MAPPING.equals(annotationName) || FULL_GET_MAPPING.equals(annotationName)) {
|
||||||
|
String methodRequestPath = annotation.getNamedParameter(VALUE_PROP).toString();
|
||||||
|
String httpMethod = "GET";
|
||||||
|
return new Tuple2<>(methodRequestPath, httpMethod);
|
||||||
|
}
|
||||||
|
if (POST_MAPPING.equals(annotationName) || FULL_POST_MAPPING.equals(annotationName)) {
|
||||||
|
String methodRequestPath = annotation.getNamedParameter(VALUE_PROP).toString();
|
||||||
|
String httpMethod = "POST";
|
||||||
|
return new Tuple2<>(methodRequestPath, httpMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Tuple2<>(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ApiArgument> parseApiMethodArgumentList(JavaMethod javaMethod) {
|
||||||
|
List<ApiArgument> apiArgumentList = new LinkedList<>();
|
||||||
|
List<JavaParameter> parameterList = javaMethod.getParameters();
|
||||||
|
if (CollUtil.isEmpty(parameterList)) {
|
||||||
|
return apiArgumentList;
|
||||||
|
}
|
||||||
|
for (JavaParameter parameter : parameterList) {
|
||||||
|
String typeName = parameter.getType().getValue();
|
||||||
|
// 该类型的参数为Validator的验证结果对象,因此忽略。
|
||||||
|
if ("BindingResult".equals(typeName) || this.isServletArgument(typeName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ApiArgument apiArgument = this.parseApiMethodArgument(parameter);
|
||||||
|
apiArgumentList.add(apiArgument);
|
||||||
|
}
|
||||||
|
return apiArgumentList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseMethodArgmentComment(JavaParameter parameter) {
|
||||||
|
String comment = null;
|
||||||
|
JavaExecutable executable = parameter.getExecutable();
|
||||||
|
List<DocletTag> tags = executable.getTagsByName("param");
|
||||||
|
if (CollUtil.isNotEmpty(tags)) {
|
||||||
|
for (DocletTag tag : tags) {
|
||||||
|
if (tag.getValue().startsWith(parameter.getName())) {
|
||||||
|
comment = StrUtil.removePrefix(tag.getValue(), parameter.getName()).trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApiArgument parseApiMethodArgument(JavaParameter parameter) {
|
||||||
|
String typeName = parameter.getType().getValue();
|
||||||
|
ApiArgument apiArgument = new ApiArgument();
|
||||||
|
ApiArgumentAnnotation argumentAnnotation =
|
||||||
|
this.parseArgumentAnnotationTypeAndName(parameter.getAnnotations(), parameter.getName());
|
||||||
|
apiArgument.setAnnotationType(argumentAnnotation.getType());
|
||||||
|
apiArgument.setName(argumentAnnotation.getName());
|
||||||
|
apiArgument.setTypeName(typeName);
|
||||||
|
apiArgument.setFullTypeName(parameter.getFullyQualifiedName());
|
||||||
|
if (argumentAnnotation.getType() == ApiArgumentAnnotationType.REQUEST_PARAM) {
|
||||||
|
apiArgument.setRequired(argumentAnnotation.isRequired());
|
||||||
|
}
|
||||||
|
String comment = parseMethodArgmentComment(parameter);
|
||||||
|
apiArgument.setComment(comment);
|
||||||
|
// 文件上传字段,是必填参数。
|
||||||
|
if ("MultipartFile".equals(typeName)) {
|
||||||
|
apiArgument.setUploadFileParam(true);
|
||||||
|
apiArgument.setRequired(true);
|
||||||
|
return apiArgument;
|
||||||
|
}
|
||||||
|
// 对于内置类型,则无需继续处理了。所有和内置类型参数相关的处理,应该在之前完成。
|
||||||
|
if (this.verifyAndSetBuiltinParam(apiArgument, typeName)) {
|
||||||
|
return apiArgument;
|
||||||
|
}
|
||||||
|
// 判断是否为集合类型的参数。
|
||||||
|
if (this.isCollectionType(typeName)) {
|
||||||
|
apiArgument.setCollectionParam(true);
|
||||||
|
if (parameter.getType() instanceof DefaultJavaParameterizedType) {
|
||||||
|
DefaultJavaParameterizedType javaType = (DefaultJavaParameterizedType) parameter.getType();
|
||||||
|
JavaType genericType = javaType.getActualTypeArguments().get(0);
|
||||||
|
ApiModel apiModel = this.buildApiModelForArgument(genericType.getFullyQualifiedName());
|
||||||
|
apiArgument.setModelData(apiModel);
|
||||||
|
apiArgument.setFullTypeName(parameter.getGenericFullyQualifiedName());
|
||||||
|
apiArgument.setTypeName(parameter.getGenericValue());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ApiModel apiModel = this.buildApiModelForArgument(parameter.getFullyQualifiedName());
|
||||||
|
apiArgument.setModelData(apiModel);
|
||||||
|
}
|
||||||
|
return apiArgument;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean verifyAndSetBuiltinParam(ApiArgument apiArgument, String typeName) {
|
||||||
|
if ("MyOrderParam".equals(typeName)) {
|
||||||
|
apiArgument.setOrderParam(true);
|
||||||
|
} else if ("MyPageParam".equals(typeName)) {
|
||||||
|
apiArgument.setPageParam(true);
|
||||||
|
} else if ("MyGroupParam".equals(typeName)) {
|
||||||
|
apiArgument.setGroupParam(true);
|
||||||
|
} else if ("MyQueryParam".equals(typeName)) {
|
||||||
|
apiArgument.setQueryParam(true);
|
||||||
|
} else if ("MyAggregationParam".equals(typeName)) {
|
||||||
|
apiArgument.setAggregationParam(true);
|
||||||
|
}
|
||||||
|
return apiArgument.isOrderParam()
|
||||||
|
|| apiArgument.isPageParam()
|
||||||
|
|| apiArgument.isGroupParam()
|
||||||
|
|| apiArgument.isQueryParam()
|
||||||
|
|| apiArgument.isAggregationParam();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApiArgumentAnnotation parseArgumentAnnotationTypeAndName(
|
||||||
|
List<JavaAnnotation> annotationList, String defaultName) {
|
||||||
|
ApiArgumentAnnotation argumentAnnotation = new ApiArgumentAnnotation();
|
||||||
|
argumentAnnotation.setType(ApiArgumentAnnotationType.REQUEST_PARAM);
|
||||||
|
argumentAnnotation.setName(defaultName);
|
||||||
|
for (JavaAnnotation annotation : annotationList) {
|
||||||
|
String annotationName = annotation.getType().getValue();
|
||||||
|
if ("RequestBody".equals(annotationName)) {
|
||||||
|
argumentAnnotation.setType(ApiArgumentAnnotationType.REQUEST_BODY);
|
||||||
|
return argumentAnnotation;
|
||||||
|
} else if ("MyRequestBody".equals(annotationName)) {
|
||||||
|
String annotationValue = this.getArgumentNameFromAnnotationValue(annotation, VALUE_PROP);
|
||||||
|
argumentAnnotation.setType(ApiArgumentAnnotationType.MY_REQUEST_BODY);
|
||||||
|
argumentAnnotation.setName(annotationValue != null ? annotationValue : defaultName);
|
||||||
|
return argumentAnnotation;
|
||||||
|
} else if ("RequestParam".equals(annotationName)) {
|
||||||
|
String annotationValue = this.getArgumentNameFromAnnotationValue(annotation, VALUE_PROP);
|
||||||
|
argumentAnnotation.setType(ApiArgumentAnnotationType.REQUEST_PARAM);
|
||||||
|
argumentAnnotation.setName(annotationValue != null ? annotationValue : defaultName);
|
||||||
|
String requiredValue = this.getArgumentNameFromAnnotationValue(annotation, REQUIRED_PROP);
|
||||||
|
if (StrUtil.isNotBlank(requiredValue)) {
|
||||||
|
argumentAnnotation.setRequired(Boolean.parseBoolean(requiredValue));
|
||||||
|
}
|
||||||
|
return argumentAnnotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 缺省为@RequestParam
|
||||||
|
return argumentAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getArgumentNameFromAnnotationValue(JavaAnnotation annotation, String attribute) {
|
||||||
|
Object value = annotation.getNamedParameter(attribute);
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String paramAlias = value.toString();
|
||||||
|
if (StrUtil.isNotBlank(paramAlias)) {
|
||||||
|
paramAlias = StrUtil.removeAll(paramAlias, "\"");
|
||||||
|
}
|
||||||
|
return paramAlias;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApiModel buildApiModelForArgument(String fullJavaClassName) {
|
||||||
|
// 先从当前服务内的Model中找,如果参数是Model类型的对象,微服务和单体行为一致。
|
||||||
|
ApiModel apiModel = apiProject.getFullNameModelMap().get(fullJavaClassName);
|
||||||
|
if (apiModel != null) {
|
||||||
|
return apiModel;
|
||||||
|
}
|
||||||
|
// 判断工程全局对象映射中是否包括该对象类型,如果不包含,就直接返回了。
|
||||||
|
JavaClass modelClass = projectJavaClassMap.get(fullJavaClassName);
|
||||||
|
if (modelClass == null) {
|
||||||
|
return apiModel;
|
||||||
|
}
|
||||||
|
// 先行解析对象中的字段。
|
||||||
|
apiModel = parseModel(modelClass);
|
||||||
|
apiProject.getFullNameModelMap().put(fullJavaClassName, apiModel);
|
||||||
|
return apiModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApiModel parseModel(JavaClass javaClass) {
|
||||||
|
ApiModel apiModel = new ApiModel();
|
||||||
|
apiModel.setName(javaClass.getName());
|
||||||
|
apiModel.setFullName(javaClass.getFullyQualifiedName());
|
||||||
|
apiModel.setComment(javaClass.getComment());
|
||||||
|
apiModel.setFieldList(new LinkedList<>());
|
||||||
|
List<JavaField> fieldList = javaClass.getFields();
|
||||||
|
for (JavaField field : fieldList) {
|
||||||
|
if (field.isStatic()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ApiField apiField = new ApiField();
|
||||||
|
apiField.setName(field.getName());
|
||||||
|
apiField.setComment(field.getComment());
|
||||||
|
apiField.setTypeName(field.getType().getSimpleName());
|
||||||
|
apiModel.getFieldList().add(apiField);
|
||||||
|
}
|
||||||
|
return apiModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyConfigData() {
|
||||||
|
if (StrUtil.isBlank(config.getProjectName())) {
|
||||||
|
throw new ApiCodeConfigParseException("ProjectName field can't be EMPTY.");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(config.getBasePackage())) {
|
||||||
|
throw new ApiCodeConfigParseException("BasePackage field can't be EMPTY.");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(config.getProjectRootPath())) {
|
||||||
|
throw new ApiCodeConfigParseException("ProjectRootPath field can't be EMPTY.");
|
||||||
|
}
|
||||||
|
if (!FileUtil.exist(config.getProjectRootPath())) {
|
||||||
|
throw new ApiCodeConfigParseException(
|
||||||
|
"ProjectRootPath doesn't exist, please check ./resources/export-api-config.json as DEFAULT.");
|
||||||
|
}
|
||||||
|
if (config.getMicroService() == null) {
|
||||||
|
throw new ApiCodeConfigParseException("MicroService field can't be NULL.");
|
||||||
|
}
|
||||||
|
if (CollUtil.isEmpty(config.getServiceList())) {
|
||||||
|
throw new ApiCodeConfigParseException("ServiceList field can't be EMPTY.");
|
||||||
|
}
|
||||||
|
this.verifyServiceConfig(config.getServiceList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyServiceConfig(List<ApiCodeConfig.ServiceConfig> serviceConfigList) {
|
||||||
|
Set<String> serviceNameSet = new HashSet<>(8);
|
||||||
|
Set<String> servicePathSet = new HashSet<>(8);
|
||||||
|
for (ApiCodeConfig.ServiceConfig serviceConfig : serviceConfigList) {
|
||||||
|
if (StrUtil.isBlank(serviceConfig.getServiceName())) {
|
||||||
|
throw new ApiCodeConfigParseException("One of the ServiceName Field in Services List is NULL.");
|
||||||
|
}
|
||||||
|
String serviceName = serviceConfig.getServiceName();
|
||||||
|
if (StrUtil.isBlank(serviceConfig.getServicePath())) {
|
||||||
|
throw new ApiCodeConfigParseException(
|
||||||
|
"The ServicePath Field in Service [" + serviceName + "] is NULL.");
|
||||||
|
}
|
||||||
|
if (serviceNameSet.contains(serviceName)) {
|
||||||
|
throw new ApiCodeConfigParseException("The ServiceName [" + serviceName + "] is duplicated.");
|
||||||
|
}
|
||||||
|
serviceNameSet.add(serviceName);
|
||||||
|
if (servicePathSet.contains(serviceConfig.getServicePath())) {
|
||||||
|
throw new ApiCodeConfigParseException(
|
||||||
|
"The ServicePath [" + serviceConfig.getServicePath() + "] is duplicated.");
|
||||||
|
}
|
||||||
|
servicePathSet.add(serviceConfig.getServicePath());
|
||||||
|
if (StrUtil.isBlank(serviceConfig.getPort())) {
|
||||||
|
throw new ApiCodeConfigParseException(
|
||||||
|
"The Port Field in Service [" + serviceName + "] is NULL.");
|
||||||
|
}
|
||||||
|
this.verifyServiceControllerConfig(serviceConfig.getControllerInfoList(), serviceName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyServiceControllerConfig(
|
||||||
|
List<ApiCodeConfig.ControllerInfo> controllerInfoList, String serviceName) {
|
||||||
|
if (CollUtil.isEmpty(controllerInfoList)) {
|
||||||
|
throw new ApiCodeConfigParseException(
|
||||||
|
"The ControllerInfoList Field of Service [" + serviceName + "] is EMPTY");
|
||||||
|
}
|
||||||
|
for (ApiCodeConfig.ControllerInfo controllerInfo : controllerInfoList) {
|
||||||
|
if (StrUtil.isBlank(controllerInfo.getPath())) {
|
||||||
|
throw new ApiCodeConfigParseException(
|
||||||
|
"One of the ControllerInfo.Path Field of Service [" + serviceName + "] is EMPTY");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void normalizeConfigPath() {
|
||||||
|
config.setProjectRootPath(normalizePath(config.getProjectRootPath()));
|
||||||
|
for (ApiCodeConfig.ServiceConfig serviceConfig : config.getServiceList()) {
|
||||||
|
serviceConfig.setServicePath(config.getProjectRootPath() + normalizePath(serviceConfig.getServicePath()));
|
||||||
|
for (ApiCodeConfig.ControllerInfo controllerInfo : serviceConfig.getControllerInfoList()) {
|
||||||
|
controllerInfo.setPath(serviceConfig.getServicePath() + normalizePath(controllerInfo.getPath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizePath(String path) {
|
||||||
|
if (!path.startsWith(PATH_SEPERATOR)) {
|
||||||
|
path = PATH_SEPERATOR + path;
|
||||||
|
}
|
||||||
|
return StrUtil.removeSuffix(path, PATH_SEPERATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCollectionType(String typeName) {
|
||||||
|
return "List".equals(typeName) || "Set".equals(typeName) || "Collection".equals(typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isServletArgument(String typeName) {
|
||||||
|
return "HttpServletResponse".equals(typeName) || "HttpServletRequest".equals(typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isController(String annotationName) {
|
||||||
|
return "Controller".equals(annotationName)
|
||||||
|
|| "org.springframework.stereotype.Controller".equals(annotationName)
|
||||||
|
|| "RestController".equals(annotationName)
|
||||||
|
|| "org.springframework.web.bind.annotation.RestController".equals(annotationName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isRequiredColumn(String annotationName) {
|
||||||
|
return "NotNull".equals(annotationName)
|
||||||
|
|| "javax.validation.constraints.NotNull".equals(annotationName)
|
||||||
|
|| "NotBlank".equals(annotationName)
|
||||||
|
|| "javax.validation.constraints.NotBlank".equals(annotationName)
|
||||||
|
|| "NotEmpty".equals(annotationName)
|
||||||
|
|| "javax.validation.constraints.NotEmpty".equals(annotationName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isRequestMapping(String name) {
|
||||||
|
return REQUEST_MAPPING.equals(name) || FULL_REQUEST_MAPPING.equals(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ApiProject {
|
||||||
|
private String projectName;
|
||||||
|
private Boolean microService;
|
||||||
|
private List<ApiService> serviceList;
|
||||||
|
private Map<String, ApiModel> fullNameModelMap = new HashMap<>(32);
|
||||||
|
private Map<String, ApiModel> simpleNameModelMap = new HashMap<>(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ApiService {
|
||||||
|
private String serviceName;
|
||||||
|
private String showName;
|
||||||
|
private String port;
|
||||||
|
private Set<ApiClass> defaultGroupClassSet = new TreeSet<>();
|
||||||
|
private Map<String, Set<ApiClass>> groupedClassMap = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ApiClass implements Comparable<ApiClass> {
|
||||||
|
private String name;
|
||||||
|
private String fullName;
|
||||||
|
private String groupName;
|
||||||
|
private String comment;
|
||||||
|
private String requestPath;
|
||||||
|
private List<ApiMethod> methodList;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(ApiClass o) {
|
||||||
|
return this.name.compareTo(o.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ApiMethod {
|
||||||
|
private String name;
|
||||||
|
private String comment;
|
||||||
|
private String returnString;
|
||||||
|
private String requestPath;
|
||||||
|
private String httpMethod;
|
||||||
|
private boolean listDictUrl = false;
|
||||||
|
private boolean listUrl = false;
|
||||||
|
private boolean loginUrl = false;
|
||||||
|
private List<String> pathList = new LinkedList<>();
|
||||||
|
private List<ApiArgument> argumentList;
|
||||||
|
private List<ApiArgument> queryParamArgumentList = new LinkedList<>();
|
||||||
|
private List<ApiArgument> jsonParamArgumentList = new LinkedList<>();
|
||||||
|
private List<ApiArgument> uploadParamArgumentList = new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ApiArgument {
|
||||||
|
private String name;
|
||||||
|
private String typeName;
|
||||||
|
private String fullTypeName;
|
||||||
|
private String comment;
|
||||||
|
private Integer annotationType;
|
||||||
|
private boolean required = true;
|
||||||
|
private boolean uploadFileParam = false;
|
||||||
|
private boolean collectionParam = false;
|
||||||
|
private boolean orderParam = false;
|
||||||
|
private boolean pageParam = false;
|
||||||
|
private boolean groupParam = false;
|
||||||
|
private boolean queryParam = false;
|
||||||
|
private boolean aggregationParam = false;
|
||||||
|
private boolean jsonData = false;
|
||||||
|
private ApiModel modelData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ApiArgumentAnnotation {
|
||||||
|
private String name;
|
||||||
|
private Integer type;
|
||||||
|
private boolean required = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ApiModel {
|
||||||
|
private String name;
|
||||||
|
private String fullName;
|
||||||
|
private String comment;
|
||||||
|
private List<ApiField> fieldList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ApiField {
|
||||||
|
private String name;
|
||||||
|
private String comment;
|
||||||
|
private String typeName;
|
||||||
|
private boolean requiredColumn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class ApiArgumentAnnotationType {
|
||||||
|
public static final int REQUEST_PARAM = 0;
|
||||||
|
public static final int REQUEST_BODY = 1;
|
||||||
|
public static final int MY_REQUEST_BODY = 2;
|
||||||
|
|
||||||
|
private ApiArgumentAnnotationType() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
private static class InternalServiceData {
|
||||||
|
private String serviceRequestPath = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.flow.demo.apidoc.tools.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析接口信息配置对象中的异常。
|
||||||
|
*
|
||||||
|
* @author Jerry
|
||||||
|
* @date 2021-06-06
|
||||||
|
*/
|
||||||
|
public class ApiCodeConfigParseException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数。
|
||||||
|
*/
|
||||||
|
public ApiCodeConfigParseException() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数。
|
||||||
|
*
|
||||||
|
* @param msg 错误信息。
|
||||||
|
*/
|
||||||
|
public ApiCodeConfigParseException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.flow.demo.apidoc.tools.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析Mybatis XML Mapper中的异常。
|
||||||
|
*
|
||||||
|
* @author Jerry
|
||||||
|
* @date 2021-06-06
|
||||||
|
*/
|
||||||
|
public class MapperParseException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数。
|
||||||
|
*/
|
||||||
|
public MapperParseException() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数。
|
||||||
|
*
|
||||||
|
* @param msg 错误信息。
|
||||||
|
*/
|
||||||
|
public MapperParseException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package com.flow.demo.apidoc.tools.export;
|
||||||
|
|
||||||
|
import com.flow.demo.apidoc.tools.codeparser.ApiCodeParser;
|
||||||
|
import com.flow.demo.apidoc.tools.util.FreeMarkerUtils;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
import freemarker.template.TemplateException;
|
||||||
|
import freemarker.template.TemplateExceptionHandler;
|
||||||
|
import freemarker.template.TemplateModelException;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据代码解析后的工程对象数据,导出到Markdown格式的接口文档文件。
|
||||||
|
*
|
||||||
|
* @author Jerry
|
||||||
|
* @date 2021-06-06
|
||||||
|
*/
|
||||||
|
public class ApiDocExporter {
|
||||||
|
|
||||||
|
private final Configuration config;
|
||||||
|
|
||||||
|
public ApiDocExporter() throws TemplateModelException {
|
||||||
|
config = new Configuration(Configuration.VERSION_2_3_28);
|
||||||
|
config.setNumberFormat("0.####");
|
||||||
|
config.setClassicCompatible(true);
|
||||||
|
config.setAPIBuiltinEnabled(true);
|
||||||
|
config.setClassForTemplateLoading(ApiPostmanExporter.class, "/templates/");
|
||||||
|
config.setDefaultEncoding("UTF-8");
|
||||||
|
config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
|
||||||
|
config.setSharedVariable("freemarkerUtils", new FreeMarkerUtils());
|
||||||
|
config.unsetCacheStorage();
|
||||||
|
config.clearTemplateCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成Markdown格式的API接口文档。
|
||||||
|
*
|
||||||
|
* @param apiProject 解析后的工程对象。
|
||||||
|
* @param outputFile 生成后的、包含全路径的输出文件名。
|
||||||
|
* @throws IOException 文件操作异常。
|
||||||
|
* @throws TemplateException 模板实例化异常。
|
||||||
|
*/
|
||||||
|
public void doGenerate(ApiCodeParser.ApiProject apiProject, String outputFile) throws IOException, TemplateException {
|
||||||
|
Map<String, Object> paramMap = new HashMap<>(1);
|
||||||
|
paramMap.put("project", apiProject);
|
||||||
|
List<ApiCodeParser.ApiService> newServiceList = new LinkedList<>();
|
||||||
|
if (apiProject.getMicroService()) {
|
||||||
|
// 在微服务场景中,我们需要把upms服务放到最前面显示。
|
||||||
|
for (ApiCodeParser.ApiService apiService : apiProject.getServiceList()) {
|
||||||
|
if ("upms".equals(apiService.getServiceName())) {
|
||||||
|
newServiceList.add(apiService);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (ApiCodeParser.ApiService apiService : apiProject.getServiceList()) {
|
||||||
|
if (!"upms".equals(apiService.getServiceName())) {
|
||||||
|
newServiceList.add(apiService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ApiCodeParser.ApiService appService = apiProject.getServiceList().get(0);
|
||||||
|
ApiCodeParser.ApiService newUpmsService = new ApiCodeParser.ApiService();
|
||||||
|
newUpmsService.setDefaultGroupClassSet(appService.getGroupedClassMap().get("upms"));
|
||||||
|
newUpmsService.setServiceName("upms");
|
||||||
|
newUpmsService.setShowName("用户权限模块");
|
||||||
|
newServiceList.add(newUpmsService);
|
||||||
|
ApiCodeParser.ApiService newAppService = new ApiCodeParser.ApiService();
|
||||||
|
newAppService.setDefaultGroupClassSet(appService.getGroupedClassMap().get("app"));
|
||||||
|
newAppService.setServiceName("app");
|
||||||
|
newAppService.setShowName("业务应用模块");
|
||||||
|
newServiceList.add(newAppService);
|
||||||
|
}
|
||||||
|
apiProject.setServiceList(newServiceList);
|
||||||
|
FileUtils.forceMkdirParent(new File(outputFile));
|
||||||
|
config.getTemplate("./api-doc.md.ftl").process(paramMap, new FileWriter(outputFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.flow.demo.apidoc.tools.export;
|
||||||
|
|
||||||
|
import com.flow.demo.apidoc.tools.codeparser.ApiCodeParser;
|
||||||
|
import com.flow.demo.apidoc.tools.util.FreeMarkerUtils;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
import freemarker.template.TemplateException;
|
||||||
|
import freemarker.template.TemplateExceptionHandler;
|
||||||
|
import freemarker.template.TemplateModelException;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据代码解析后的工程对象数据,导出到Postman支持的JSON格式的文件。
|
||||||
|
*
|
||||||
|
* @author Jerry
|
||||||
|
* @date 2021-06-06
|
||||||
|
*/
|
||||||
|
public class ApiPostmanExporter {
|
||||||
|
|
||||||
|
private final Configuration config;
|
||||||
|
|
||||||
|
public ApiPostmanExporter() throws TemplateModelException {
|
||||||
|
config = new Configuration(Configuration.VERSION_2_3_28);
|
||||||
|
config.setNumberFormat("0.####");
|
||||||
|
config.setClassicCompatible(true);
|
||||||
|
config.setAPIBuiltinEnabled(true);
|
||||||
|
config.setClassForTemplateLoading(ApiPostmanExporter.class, "/templates/");
|
||||||
|
config.setDefaultEncoding("UTF-8");
|
||||||
|
config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
|
||||||
|
config.setSharedVariable("freemarkerUtils", new FreeMarkerUtils());
|
||||||
|
config.unsetCacheStorage();
|
||||||
|
config.clearTemplateCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成Postman支持的JSON文档。
|
||||||
|
* @param apiProject 解析后的工程对象。
|
||||||
|
* @param outputFile 生成后的、包含全路径的输出文件名。
|
||||||
|
* @throws IOException 文件操作异常。
|
||||||
|
* @throws TemplateException 模板实例化异常。
|
||||||
|
*/
|
||||||
|
public void doGenerate(ApiCodeParser.ApiProject apiProject, String outputFile) throws IOException, TemplateException {
|
||||||
|
Map<String, Object> paramMap = new HashMap<>(1);
|
||||||
|
paramMap.put("project", apiProject);
|
||||||
|
FileUtils.forceMkdirParent(new File(outputFile));
|
||||||
|
config.getTemplate("./postman_collection.json.ftl").process(paramMap, new FileWriter(outputFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.flow.demo.apidoc.tools.util;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅供Freemarker模板内部使用的Java工具函数。
|
||||||
|
*
|
||||||
|
* @author Jerry
|
||||||
|
* @date 2021-06-06
|
||||||
|
*/
|
||||||
|
public class FreeMarkerUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成GUID。
|
||||||
|
*
|
||||||
|
* @return 生成后的GUID。
|
||||||
|
*/
|
||||||
|
public static String generateGuid() {
|
||||||
|
return UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 私有构造函数,明确标识该常量类的作用。
|
||||||
|
*/
|
||||||
|
public FreeMarkerUtils() {
|
||||||
|
// FreeMarker的工具对象,Sonarqube建议给出空构造的注释。
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"projectName": "橙单在线表单",
|
||||||
|
"basePackage": "com.flow.demo",
|
||||||
|
"projectRootPath": "这里请使用当前工程的根目录,如:e:/xxx/OrangeDemo 或者 /Users/xxx/OrangeDemo",
|
||||||
|
"microService": "false",
|
||||||
|
"serviceList": [
|
||||||
|
{
|
||||||
|
"serviceName": "application-webadmin",
|
||||||
|
"showName": "后台管理服务",
|
||||||
|
"servicePath": "/application-webadmin",
|
||||||
|
"port": "8082",
|
||||||
|
"controllerInfoList": [
|
||||||
|
{
|
||||||
|
"path": "/src/main/java/com/flow/demo/webadmin/app/controller",
|
||||||
|
"groupName": "app"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/src/main/java/com/flow/demo/webadmin/upms/controller",
|
||||||
|
"groupName": "upms"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
## 用户登录
|
||||||
|
### 登录接口
|
||||||
|
#### 登录
|
||||||
|
- **URI:** /admin/upms/login/doLogin
|
||||||
|
- **Type:** GET
|
||||||
|
- **Content-Type:** multipart/form-data
|
||||||
|
- **Request-Headers:**
|
||||||
|
Name|Type|Description
|
||||||
|
--|--|--
|
||||||
|
Authorization|String|身份验证的Token
|
||||||
|
- **Request-Parameters:**
|
||||||
|
Parameter|Type|Required|Description
|
||||||
|
--|--|--|--
|
||||||
|
loginName|string|true|用户名
|
||||||
|
password|string|true|加密后的用户密码
|
||||||
|
|
||||||
|
#### 退出
|
||||||
|
- **URI:** /admin/upms/login/logout
|
||||||
|
- **Type:** POST
|
||||||
|
- **Content-Type:** application/json; chartset=utf-8
|
||||||
|
- **Request-Headers:**
|
||||||
|
Name|Type|Description
|
||||||
|
--|--|--
|
||||||
|
Authorization|String|身份验证的Token
|
||||||
|
|
||||||
|
#### 修改密码
|
||||||
|
- **URI:** /admin/upms/login/changePassword
|
||||||
|
- **Type:** POST
|
||||||
|
- **Content-Type:** application/json; chartset=utf-8
|
||||||
|
- **Request-Headers:**
|
||||||
|
Name|Type|Description
|
||||||
|
--|--|--
|
||||||
|
Authorization|String|身份验证的Token
|
||||||
|
- **Request-Parameters:**
|
||||||
|
Parameter|Type|Required|Description
|
||||||
|
--|--|--|--
|
||||||
|
oldPass|string|true|加密后的原用户密码
|
||||||
|
newPass|string|true|加密后的新用户密码
|
||||||
|
<#list project.serviceList as service>
|
||||||
|
|
||||||
|
## ${service.showName}
|
||||||
|
<#list service.defaultGroupClassSet as apiClass>
|
||||||
|
### ${apiClass.name}
|
||||||
|
<#list apiClass.methodList as apiMethod>
|
||||||
|
#### ${apiMethod.name}
|
||||||
|
- **URI:** ${apiMethod.requestPath}
|
||||||
|
- **Type:** ${apiMethod.httpMethod}
|
||||||
|
- **Content-Type:** <#if apiMethod.httpMethod == "GET" || apiMethod.queryParamArgumentList?size gt 0 || apiMethod.uploadParamArgumentList?size gt 0>multipart/form-data<#else>application/json; chartset=utf-8</#if>
|
||||||
|
- **Request-Headers:**
|
||||||
|
Name|Type|Description
|
||||||
|
--|--|--
|
||||||
|
Authorization|String|身份验证的Token
|
||||||
|
<#if apiMethod.queryParamArgumentList?size gt 0 || apiMethod.uploadParamArgumentList?size gt 0>
|
||||||
|
- **Request-Parameters:**
|
||||||
|
Parameter|Type|Required|Description
|
||||||
|
--|--|--|--
|
||||||
|
<#list apiMethod.queryParamArgumentList as apiArgument>
|
||||||
|
<#if apiArgument.modelData??>
|
||||||
|
<#list apiArgument.modelData.tableFieldList as apiField>
|
||||||
|
${apiField.name}|${apiField.typeName}|<#if apiMethod.listDictUrl>false<#else><#if apiField.requiredColumn>true<#else>false</#if></#if>|${apiField.comment}
|
||||||
|
</#list>
|
||||||
|
<#else>
|
||||||
|
${apiArgument.name}|${apiArgument.typeName}|<#if apiMethod.listDictUrl>false<#else><#if apiArgument.required>true<#else>false</#if></#if>|${apiArgument.comment}
|
||||||
|
</#if><#-- apiArgument.modelData?? -->
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
<#list apiMethod.uploadParamArgumentList as apiArgument>
|
||||||
|
${apiArgument.name}|File|true|${apiArgument.comment}
|
||||||
|
</#list>
|
||||||
|
<#if apiMethod.jsonParamArgumentList?size gt 0>
|
||||||
|
- **Request-Body:**
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
<#list apiMethod.jsonParamArgumentList as apiArgument>
|
||||||
|
<#if apiArgument.modelData??>
|
||||||
|
<#if apiArgument.collectionParam>
|
||||||
|
"${apiArgument.name}" : [
|
||||||
|
{
|
||||||
|
<#if apiMethod.listUrl>
|
||||||
|
<#list apiArgument.modelData.filteredFieldList as apiField>
|
||||||
|
"${apiField.name}" : "${apiField.typeName} | false | <#if apiField.name == "searchString">模糊搜索字符串。<#else>${apiField.comment}</#if>"<#if apiField_has_next>,</#if>
|
||||||
|
</#list>
|
||||||
|
<#else><#-- apiMethod.listUrl -->
|
||||||
|
<#list apiArgument.modelData.tableFieldList as apiField>
|
||||||
|
<#if !apiMethod.addUrl || !apiField.primaryKey>
|
||||||
|
"${apiField.name}" : "${apiField.typeName} | <#if apiField.requiredColumn>true<#else>false</#if> | ${apiField.comment}"<#if apiField_has_next>,</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if><#-- apiMethod.listUrl -->
|
||||||
|
}
|
||||||
|
]<#if apiArgument_has_next>,</#if>
|
||||||
|
<#else><#-- apiArgument.collectionParam -->
|
||||||
|
"${apiArgument.name}" : {
|
||||||
|
<#if apiMethod.listUrl>
|
||||||
|
<#list apiArgument.modelData.filteredFieldList as apiField>
|
||||||
|
"${apiField.name}" : "${apiField.typeName} | false | <#if apiField.name == "searchString">模糊搜索字符串。<#else>${apiField.comment}</#if>"<#if apiField_has_next>,</#if>
|
||||||
|
</#list>
|
||||||
|
<#else><#-- apiMethod.listUrl -->
|
||||||
|
<#list apiArgument.modelData.tableFieldList as apiField>
|
||||||
|
<#if !apiMethod.addUrl || !apiField.primaryKey>
|
||||||
|
"${apiField.name}" : "${apiField.typeName} | <#if apiField.requiredColumn>true<#else>false</#if> | ${apiField.comment}"<#if apiField_has_next>,</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</#if><#-- apiMethod.listUrl -->
|
||||||
|
}<#if apiArgument_has_next>,</#if>
|
||||||
|
</#if><#-- apiArgument.collectionParam -->
|
||||||
|
<#elseif apiArgument.orderParam>
|
||||||
|
"${apiArgument.name}" : [
|
||||||
|
{
|
||||||
|
"fieldName" : "String | false | 排序字段名",
|
||||||
|
"asc" : "Boolean | false | 是否升序"
|
||||||
|
}
|
||||||
|
]<#if apiArgument_has_next>,</#if>
|
||||||
|
<#elseif apiArgument.groupParam>
|
||||||
|
"${apiArgument.name}" : [
|
||||||
|
{
|
||||||
|
"fieldName" : "String | false | 分组字段名",
|
||||||
|
"aliasName" : "String | false | 分组字段别名",
|
||||||
|
"dateAggregateBy" : "String | false | 是否按照日期聚合,可选项(day|month|year)"
|
||||||
|
}
|
||||||
|
]<#if apiArgument_has_next>,</#if>
|
||||||
|
<#elseif apiArgument.pageParam>
|
||||||
|
"${apiArgument.name}" : {
|
||||||
|
"pageNum": "Integer | false | 分页页号",
|
||||||
|
"pageSize": "Integer | false | 每页数据量"
|
||||||
|
}<#if apiArgument_has_next>,</#if>
|
||||||
|
<#elseif apiArgument.queryParam || apiArgument.aggregationParam>
|
||||||
|
${apiArgument.name}" : {
|
||||||
|
|
||||||
|
}<#if apiArgument_has_next>,</#if>
|
||||||
|
<#else><#-- apiArgument.modelData?? -->
|
||||||
|
<#if apiArgument.collectionParam>
|
||||||
|
"${apiArgument.name}" : [ "${apiArgument.typeName} | ${apiArgument.required}<#if apiArgument.comment??> | ${apiArgument.comment}</#if>" ]<#if apiArgument_has_next>,</#if>
|
||||||
|
<#else>
|
||||||
|
"${apiArgument.name}" : "${apiArgument.typeName} | ${apiArgument.required}<#if apiArgument.comment??> | ${apiArgument.comment}</#if>"<#if apiArgument_has_next>,</#if>
|
||||||
|
</#if>
|
||||||
|
</#if><#-- apiArgument.modelData?? -->
|
||||||
|
</#list>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</#if>
|
||||||
|
</#list><#-- apiClass.methodList as apiMethod -->
|
||||||
|
</#list><#-- upmsClassList as apiClass -->
|
||||||
|
</#list>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<#import "postman_common.ftl" as Common>
|
||||||
|
{
|
||||||
|
"info": {
|
||||||
|
"_postman_id": "92b51dc5-3611-49ac-8d94-a0718dba5bf1",
|
||||||
|
"name": "${project.projectName}",
|
||||||
|
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||||
|
},
|
||||||
|
"item": [
|
||||||
|
<#list project.serviceList as service>
|
||||||
|
{
|
||||||
|
"name": "${service.serviceName}",
|
||||||
|
"item": [
|
||||||
|
<#if service.groupedClassMap?size gt 0>
|
||||||
|
<#list service.groupedClassMap?keys as groupName>
|
||||||
|
<#assign groupedClassList=service.groupedClassMap[groupName] />
|
||||||
|
{
|
||||||
|
"name": "${groupName}",
|
||||||
|
"item": [
|
||||||
|
<#list groupedClassList as apiClass>
|
||||||
|
{
|
||||||
|
<@Common.generateControllerRequest service apiClass 7/>
|
||||||
|
}<#if apiClass_has_next>,</#if>
|
||||||
|
</#list>
|
||||||
|
],
|
||||||
|
"protocolProfileBehavior": {},
|
||||||
|
"_postman_isSubFolder": true
|
||||||
|
}<#if groupName_has_next>,</#if>
|
||||||
|
</#list>
|
||||||
|
</#if>
|
||||||
|
<#list service.defaultGroupClassSet as apiClass>
|
||||||
|
{
|
||||||
|
<@Common.generateControllerRequest service apiClass 5/>
|
||||||
|
}<#if apiClass_has_next>,</#if>
|
||||||
|
</#list>
|
||||||
|
],
|
||||||
|
"protocolProfileBehavior": {},
|
||||||
|
"_postman_isSubFolder": true
|
||||||
|
}<#if service_has_next>,</#if>
|
||||||
|
</#list><#-- project.serviceList as service -->
|
||||||
|
],
|
||||||
|
"protocolProfileBehavior": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<#macro doIndent level><#if level != 0><#list 0..(level-1) as i> </#list></#if></#macro>
|
||||||
|
|
||||||
|
<#macro generateControllerRequest service apiClass indentLevel>
|
||||||
|
<@doIndent indentLevel/>"name": "${apiClass.name}",
|
||||||
|
<@doIndent indentLevel/>"item": [
|
||||||
|
<#list apiClass.methodList as apiMethod>
|
||||||
|
<@doIndent indentLevel/> {
|
||||||
|
<@doIndent indentLevel/> "name": "${apiMethod.name}",
|
||||||
|
<#if apiMethod.loginUrl>
|
||||||
|
<@doIndent indentLevel/> "event": [
|
||||||
|
<@doIndent indentLevel/> {
|
||||||
|
<@doIndent indentLevel/> "listen": "test",
|
||||||
|
<@doIndent indentLevel/> "script": {
|
||||||
|
<@doIndent indentLevel/> "id": "${freemarkerUtils.generateGuid()}",
|
||||||
|
<@doIndent indentLevel/> "type": "text/javascript",
|
||||||
|
<@doIndent indentLevel/> "exec": [
|
||||||
|
<@doIndent indentLevel/> "pm.test(\"登录操作\", function () {",
|
||||||
|
<@doIndent indentLevel/> " var jsonData = pm.response.json();",
|
||||||
|
<@doIndent indentLevel/> " var token = jsonData.data.tokenData;",
|
||||||
|
<@doIndent indentLevel/> " pm.environment.set(\"token\", token);",
|
||||||
|
<@doIndent indentLevel/> " console.log(\"login token \" + token);",
|
||||||
|
<@doIndent indentLevel/> "});",
|
||||||
|
<@doIndent indentLevel/> ""
|
||||||
|
<@doIndent indentLevel/> ]
|
||||||
|
<@doIndent indentLevel/> }
|
||||||
|
<@doIndent indentLevel/> },
|
||||||
|
<@doIndent indentLevel/> {
|
||||||
|
<@doIndent indentLevel/> "listen": "prerequest",
|
||||||
|
<@doIndent indentLevel/> "script": {
|
||||||
|
<@doIndent indentLevel/> "id": "${freemarkerUtils.generateGuid()}",
|
||||||
|
<@doIndent indentLevel/> "type": "text/javascript",
|
||||||
|
<@doIndent indentLevel/> "exec": [
|
||||||
|
<@doIndent indentLevel/> ""
|
||||||
|
<@doIndent indentLevel/> ]
|
||||||
|
<@doIndent indentLevel/> }
|
||||||
|
<@doIndent indentLevel/> }
|
||||||
|
<@doIndent indentLevel/> ],
|
||||||
|
</#if>
|
||||||
|
<@doIndent indentLevel/> "request": {
|
||||||
|
<@doIndent indentLevel/> "method": "${apiMethod.httpMethod}",
|
||||||
|
<#if apiMethod.loginUrl>
|
||||||
|
<@doIndent indentLevel/> "header": [],
|
||||||
|
<#else>
|
||||||
|
<@doIndent indentLevel/> "header": [
|
||||||
|
<@doIndent indentLevel/> {
|
||||||
|
<@doIndent indentLevel/> "key": "Authorization",
|
||||||
|
<@doIndent indentLevel/> "value": "{{token}}",
|
||||||
|
<@doIndent indentLevel/> "type": "text"
|
||||||
|
<@doIndent indentLevel/> }
|
||||||
|
<@doIndent indentLevel/> ],
|
||||||
|
</#if>
|
||||||
|
<@doIndent indentLevel/> "url": {
|
||||||
|
<@doIndent indentLevel/> "raw": "http://{{host}}:${service.port}/${apiMethod.requestPath}",
|
||||||
|
<@doIndent indentLevel/> "protocol": "http",
|
||||||
|
<@doIndent indentLevel/> "host": [
|
||||||
|
<@doIndent indentLevel/> "{{host}}"
|
||||||
|
<@doIndent indentLevel/> ],
|
||||||
|
<@doIndent indentLevel/> "port": "${service.port}",
|
||||||
|
<@doIndent indentLevel/> "path": [
|
||||||
|
<#list apiMethod.pathList as path>
|
||||||
|
<@doIndent indentLevel/> "${path}"<#if path_has_next>,</#if>
|
||||||
|
</#list>
|
||||||
|
<@doIndent indentLevel/> ]<#if apiMethod.queryParamArgumentList?size gt 0>,</#if>
|
||||||
|
<#if apiMethod.queryParamArgumentList?size gt 0>
|
||||||
|
<@doIndent indentLevel/> "query": [
|
||||||
|
<#list apiMethod.queryParamArgumentList as apiArgument>
|
||||||
|
<#if apiArgument.modelData??>
|
||||||
|
<#list apiArgument.modelData.tableFieldList as apiField>
|
||||||
|
<@doIndent indentLevel/> {
|
||||||
|
<@doIndent indentLevel/> "key": "${apiField.name}",
|
||||||
|
<@doIndent indentLevel/> "value": ""
|
||||||
|
<@doIndent indentLevel/> }<#if apiArgument_has_next || apiField_has_next>,</#if>
|
||||||
|
</#list>
|
||||||
|
<#else>
|
||||||
|
<@doIndent indentLevel/> {
|
||||||
|
<@doIndent indentLevel/> "key": "${apiArgument.name}",
|
||||||
|
<@doIndent indentLevel/> "value": ""
|
||||||
|
<@doIndent indentLevel/> }<#if apiArgument_has_next>,</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<@doIndent indentLevel/> ]
|
||||||
|
</#if>
|
||||||
|
<@doIndent indentLevel/> }<#if (apiMethod.httpMethod == "POST" && apiMethod.jsonParamArgumentList?size gt 0) || apiMethod.uploadParamArgumentList?size gt 0>,</#if>
|
||||||
|
<#if apiMethod.uploadParamArgumentList?size gt 0>
|
||||||
|
<@doIndent indentLevel/> "body": {
|
||||||
|
<@doIndent indentLevel/> "mode": "formdata",
|
||||||
|
<@doIndent indentLevel/> "formdata": [
|
||||||
|
<#list apiMethod.uploadParamArgumentList as apiArgument>
|
||||||
|
<@doIndent indentLevel/> {
|
||||||
|
<@doIndent indentLevel/> "key": "${apiArgument.name}",
|
||||||
|
<@doIndent indentLevel/> "type": "file",
|
||||||
|
<@doIndent indentLevel/> "src": []
|
||||||
|
<@doIndent indentLevel/> }<#if apiArgument_has_next>,</#if>
|
||||||
|
</#list>
|
||||||
|
<@doIndent indentLevel/> ]
|
||||||
|
<@doIndent indentLevel/> }<#if apiMethod.httpMethod == "POST" && apiMethod.jsonParamArgumentList?size gt 0>,</#if>
|
||||||
|
</#if><#-- apiMethod.uploadParamArgumentList?size gt 0 -->
|
||||||
|
<#if apiMethod.httpMethod == "POST" && apiMethod.jsonParamArgumentList?size gt 0>
|
||||||
|
<@doIndent indentLevel/> "body": {
|
||||||
|
<@doIndent indentLevel/> "mode": "raw",
|
||||||
|
<#if !apiMethod.loginUrl>
|
||||||
|
<@doIndent indentLevel/> "raw": "{\n<#list apiMethod.jsonParamArgumentList as apiArgument><#if apiArgument.modelData??><#if apiArgument.collectionParam>\t\"${apiArgument.name}\" : [\n\t\t{\n<#list apiArgument.modelData.fieldList as apiField><#if apiMethod.listUrl>\t\t\t\"${apiField.name}\" : \"\"<#if apiField_has_next>,</#if>\n<#else>\t\t\t\"${apiField.name}\" : \"<#if apiField.typeName == "Integer" || apiField.typeName == "Long">0</#if>\"<#if apiField_has_next>,</#if>\n</#if><#-- apiMethod.listUrl --></#list>\t\t}\n\t]<#if apiArgument_has_next>,</#if>\n<#else><#-- apiArgument.collectionParam -->\t\"${apiArgument.name}\" : {\n<#list apiArgument.modelData.fieldList as apiField><#if apiMethod.listUrl>\t\t\"${apiField.name}\" : \"\"<#if apiField_has_next>,</#if>\n<#else>\t\t\"${apiField.name}\" : \"<#if apiField.typeName == "Integer" || apiField.typeName == "Long">0</#if>\"<#if apiField_has_next>,</#if>\n</#if><#-- apiMethod.listUrl --></#list>\t}<#if apiArgument_has_next>,</#if>\n</#if><#-- apiArgument.collectionParam --><#elseif apiArgument.orderParam>\t\"${apiArgument.name}\" : [\n\t\t{\n\t\t\t\"fieldName\" : \"\",\n\t\t\t\"asc\" : \"true\"\n\t\t}\n\t]<#if apiArgument_has_next>,</#if>\n<#elseif apiArgument.groupParam>\t\"${apiArgument.name}\" : [\n\t\t{\n\t\t\t\"fieldName\" : \"\",\n\t\t\t\"aliasName\" : \"\",\n\t\t\t\"dateAggregateBy\" : \"\"\n\t\t}\n\t]<#if apiArgument_has_next>,</#if>\n<#elseif apiArgument.pageParam>\t\"${apiArgument.name}\" : {\n\t\t\"pageNum\": \"1\",\n\t\t\"pageSize\": \"10\"\n\t}<#if apiArgument_has_next>,</#if>\n<#elseif apiArgument.queryParam || apiArgument.aggregationParam>\t\"${apiArgument.name}\" : {\n\t}<#if apiArgument_has_next>,</#if>\n<#else><#if apiArgument.collectionParam>\t\"${apiArgument.name}\" : [ ]<#if apiArgument_has_next>,</#if>\n<#else>\t\"${apiArgument.name}\" : \"\"<#if apiArgument_has_next>,</#if>\n</#if></#if><#-- apiArgument.modelData?? --></#list><#-- apiMethod.jsonParamArgumentList?size gt 0 -->}\n",
|
||||||
|
<#else>
|
||||||
|
<@doIndent indentLevel/> "raw": "{\n \"loginName\":\"admin\",\n \"password\":\"IP3ccke3GhH45iGHB5qP9p7iZw6xUyj28Ju10rnBiPKOI35sc%2BjI7%2FdsjOkHWMfUwGYGfz8ik31HC2Ruk%2Fhkd9f6RPULTHj7VpFdNdde2P9M4mQQnFBAiPM7VT9iW3RyCtPlJexQ3nAiA09OqG%2F0sIf1kcyveSrulxembARDbDo%3D\"\n}",
|
||||||
|
</#if>
|
||||||
|
<@doIndent indentLevel/> "options": {
|
||||||
|
<@doIndent indentLevel/> "raw": {
|
||||||
|
<@doIndent indentLevel/> "language": "json"
|
||||||
|
<@doIndent indentLevel/> }
|
||||||
|
<@doIndent indentLevel/> }
|
||||||
|
<@doIndent indentLevel/> }
|
||||||
|
</#if>
|
||||||
|
<@doIndent indentLevel/> },
|
||||||
|
<@doIndent indentLevel/> "response": []
|
||||||
|
<@doIndent indentLevel/> }<#if apiMethod_has_next>,</#if>
|
||||||
|
</#list><#-- apiClass.methodList as apiMethod -->
|
||||||
|
<@doIndent indentLevel/>],
|
||||||
|
<@doIndent indentLevel/>"protocolProfileBehavior": {},
|
||||||
|
<@doIndent indentLevel/>"_postman_isSubFolder": true
|
||||||
|
</#macro>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>com.flow.demo</groupId>
|
||||||
|
<artifactId>DemoFlow</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>framework</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
<modules>
|
||||||
|
<module>apidoc-tools</module>
|
||||||
|
</modules>
|
||||||
|
</project>
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
<modules>
|
<modules>
|
||||||
<module>application-webadmin</module>
|
<module>application-webadmin</module>
|
||||||
<module>common</module>
|
<module>common</module>
|
||||||
|
<module>framework</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
@@ -15,10 +15,6 @@ export default class FlowOperationController {
|
|||||||
}
|
}
|
||||||
return sender.doUrl(url, 'post', params, axiosOption, httpOption);
|
return sender.doUrl(url, 'post', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
// 撤销工单
|
|
||||||
static cancelWorkOrder (sender, params, axiosOption, httpOption) {
|
|
||||||
return sender.doUrl('/admin/flow/flowOperation/cancelWorkOrder', 'post', params, axiosOption, httpOption);
|
|
||||||
}
|
|
||||||
// 提交用户任务数据
|
// 提交用户任务数据
|
||||||
static submitUserTask (sender, params, axiosOption, httpOption) {
|
static submitUserTask (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOnlineOperation/submitUserTask', 'post', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOnlineOperation/submitUserTask', 'post', params, axiosOption, httpOption);
|
||||||
@@ -35,6 +31,10 @@ export default class FlowOperationController {
|
|||||||
static listFlowEntryForm (sender, params, axiosOption, httpOption) {
|
static listFlowEntryForm (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOnlineOperation/listFlowEntryForm', 'get', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOnlineOperation/listFlowEntryForm', 'get', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
|
// 撤销工单
|
||||||
|
static cancelWorkOrder (sender, params, axiosOption, httpOption) {
|
||||||
|
return sender.doUrl('/admin/flow/flowOperation/cancelWorkOrder', 'post', params, axiosOption, httpOption);
|
||||||
|
}
|
||||||
// 多实例加签
|
// 多实例加签
|
||||||
static submitConsign (sender, params, axiosOption, httpOption) {
|
static submitConsign (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/submitConsign', 'post', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/submitConsign', 'post', params, axiosOption, httpOption);
|
||||||
@@ -51,47 +51,47 @@ export default class FlowOperationController {
|
|||||||
static startOnly (sender, params, axiosOption, httpOption) {
|
static startOnly (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/startOnly', 'post', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/startOnly', 'post', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
// 获得流程定义初始化用户任务信息 *
|
// 获得流程定义初始化用户任务信息
|
||||||
static viewInitialTaskInfo (sender, params, axiosOption, httpOption) {
|
static viewInitialTaskInfo (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/viewInitialTaskInfo', 'get', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/viewInitialTaskInfo', 'get', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
// 获取待办任务信息 *
|
// 获取待办任务信息
|
||||||
static viewRuntimeTaskInfo (sender, params, axiosOption, httpOption) {
|
static viewRuntimeTaskInfo (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/viewRuntimeTaskInfo', 'get', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/viewRuntimeTaskInfo', 'get', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
// 获取流程实例审批历史 *
|
// 获取流程实例审批历史
|
||||||
static listFlowTaskComment (sender, params, axiosOption, httpOption) {
|
static listFlowTaskComment (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/listFlowTaskComment', 'get', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/listFlowTaskComment', 'get', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
// 获取历史任务信息 *
|
// 获取历史任务信息
|
||||||
static viewInitialHistoricTaskInfo (sender, params, axiosOption, httpOption) {
|
static viewInitialHistoricTaskInfo (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/viewInitialHistoricTaskInfo', 'get', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/viewInitialHistoricTaskInfo', 'get', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
// 获取所有待办任务 *
|
// 获取所有待办任务
|
||||||
static listRuntimeTask (sender, params, axiosOption, httpOption) {
|
static listRuntimeTask (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/listRuntimeTask', 'post', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/listRuntimeTask', 'post', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
// 获得流程实例审批路径 *
|
// 获得流程实例审批路径
|
||||||
static viewHighlightFlowData (sender, params, axiosOption, httpOption) {
|
static viewHighlightFlowData (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/viewHighlightFlowData', 'get', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/viewHighlightFlowData', 'get', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
// 获得流程实例的配置XML *
|
// 获得流程实例的配置XML
|
||||||
static viewProcessBpmn (sender, params, axiosOption, httpOption) {
|
static viewProcessBpmn (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/viewProcessBpmn', 'get', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/viewProcessBpmn', 'get', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
// 获得所有历史流程实例 *
|
// 获得所有历史流程实例
|
||||||
static listAllHistoricProcessInstance (sender, params, axiosOption, httpOption) {
|
static listAllHistoricProcessInstance (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/listAllHistoricProcessInstance', 'post', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/listAllHistoricProcessInstance', 'post', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
// 获得当前用户历史流程实例 *
|
// 获得当前用户历史流程实例
|
||||||
static listHistoricProcessInstance (sender, params, axiosOption, httpOption) {
|
static listHistoricProcessInstance (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/listHistoricProcessInstance', 'post', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/listHistoricProcessInstance', 'post', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
// 终止流程 *
|
// 终止流程
|
||||||
static stopProcessInstance (sender, params, axiosOption, httpOption) {
|
static stopProcessInstance (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/stopProcessInstance', 'post', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/stopProcessInstance', 'post', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
// 删除流程实例 *
|
// 删除流程实例
|
||||||
static deleteProcessInstance (sender, params, axiosOption, httpOption) {
|
static deleteProcessInstance (sender, params, axiosOption, httpOption) {
|
||||||
return sender.doUrl('/admin/flow/flowOperation/deleteProcessInstance', 'post', params, axiosOption, httpOption);
|
return sender.doUrl('/admin/flow/flowOperation/deleteProcessInstance', 'post', params, axiosOption, httpOption);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,8 +136,12 @@ export function objectToQueryString (params) {
|
|||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return Object.keys(params).map((key) => {
|
return Object.keys(params).map((key) => {
|
||||||
|
if (params[key] !== undefined) {
|
||||||
return `${key}=${params[key]}`;
|
return `${key}=${params[key]}`;
|
||||||
}).join('&');
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}).filter(item => item != null).join('&');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ export default {
|
|||||||
},
|
},
|
||||||
isInit: false
|
isInit: false
|
||||||
},
|
},
|
||||||
pageListWidget: new TableWidget(this.loadOnlinePageData, this.loadOnlinePageVerify, false, false)
|
pageListWidget: new TableWidget(this.loadOnlinePageData, this.loadOnlinePageVerify, true, false)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -856,8 +856,8 @@ export default {
|
|||||||
tableName: relation.slaveTable.tableName,
|
tableName: relation.slaveTable.tableName,
|
||||||
tableId: relation.slaveTableId,
|
tableId: relation.slaveTableId,
|
||||||
relationType: relation.relationType,
|
relationType: relation.relationType,
|
||||||
masterColumnName: relation.masterColumn.columnName,
|
masterColumnName: (relation.masterColumn || {}).columnName || '未知字段',
|
||||||
slaveColumnName: relation.slaveColumn.columnName,
|
slaveColumnName: (relation.slaveColumn || {}).columnName || '未知字段',
|
||||||
cascadeDelete: relation.cascadeDelete,
|
cascadeDelete: relation.cascadeDelete,
|
||||||
leftJoin: relation.leftJoin,
|
leftJoin: relation.leftJoin,
|
||||||
tag: relation
|
tag: relation
|
||||||
|
|||||||