工作流模块提交
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
package com.njcn.bpm.enums;
|
||||
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
|
||||
/**
|
||||
* BPM 通用常量
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class BpmConstants {
|
||||
|
||||
/**
|
||||
* 流程实例的变量 - 状态
|
||||
*
|
||||
* @see ProcessInstance#getProcessVariables()
|
||||
*/
|
||||
public static final String PROCESS_INSTANCE_VARIABLE_STATUS = "PROCESS_STATUS";
|
||||
/**
|
||||
* 流程实例的变量 - 发起用户选择的审批人 Map
|
||||
*
|
||||
* @see ProcessInstance#getProcessVariables()
|
||||
*/
|
||||
public static final String PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES = "PROCESS_START_USER_SELECT_ASSIGNEES";
|
||||
|
||||
/**
|
||||
* 任务的变量 - 状态
|
||||
*
|
||||
* @see org.flowable.task.api.Task#getTaskLocalVariables()
|
||||
*/
|
||||
public static final String TASK_VARIABLE_STATUS = "TASK_STATUS";
|
||||
/**
|
||||
* 任务的变量 - 理由
|
||||
*
|
||||
* 例如说:审批通过、不通过的理由
|
||||
*
|
||||
* @see org.flowable.task.api.Task#getTaskLocalVariables()
|
||||
*/
|
||||
public static final String TASK_VARIABLE_REASON = "TASK_REASON";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.njcn.bpm.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* BPM 模型的表单类型的枚举
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum BpmModelFormTypeEnum implements IntArrayValuable {
|
||||
|
||||
NORMAL(10, "流程表单"), // 对应 BpmFormDO
|
||||
CUSTOM(20, "业务表单") // 业务自己定义的表单,自己进行数据的存储
|
||||
;
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmModelFormTypeEnum::getType).toArray();
|
||||
|
||||
private final Integer type;
|
||||
private final String name;
|
||||
|
||||
@Override
|
||||
public int[] array() {
|
||||
return ARRAYS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.njcn.bpm.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 异常处理类
|
||||
* @author qijian
|
||||
* @version 1.0.0
|
||||
* @date 2022年11月11日 09:56
|
||||
*/
|
||||
@Getter
|
||||
public enum BpmResponseEnum {
|
||||
|
||||
/**
|
||||
* 过程监督异常响应码的范围:
|
||||
* A00550 ~ A00649
|
||||
*/
|
||||
BPM_COMMON_ERROR("A00568","工作流模块异常"),
|
||||
|
||||
BPM_XML_ERROR("A00568","流程标识格式不正确,需要以字母或下划线开头,后接任意字母、数字、中划线、下划线、句点!"),
|
||||
|
||||
BPM_MODEL_REPEAT("A00568","流程标识已存在"),
|
||||
|
||||
BPM_MODEL_NOT_EXIST("A00568","流程模型不存在"),
|
||||
|
||||
PROCESS_DEFINITION_NOT_EXISTS("A00568","流程定义不存在"),
|
||||
|
||||
FORM_NOT_EXISTS("A00568","动态表单不存在"),
|
||||
|
||||
MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG("A00568","部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置"),
|
||||
|
||||
BPM_START_EVENT_NOT_EXIST("A00568","起始事件不存在"),
|
||||
|
||||
MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS("A00568","部署流程失败,原因:BPMN 流程图中,用户任务的名字不存在"),
|
||||
|
||||
REPEAT_NAME_FORM("A00568","流程表单名称重复"),
|
||||
|
||||
REPEAT_CATEGORY_NAME_FORM("A00568","流程类型名称重复"),
|
||||
|
||||
;
|
||||
|
||||
private final String code;
|
||||
|
||||
private final String message;
|
||||
|
||||
BpmResponseEnum(String code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.njcn.bpm.enums;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* BPM 任务的候选人策略枚举
|
||||
*
|
||||
* 例如说:分配给指定人审批
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum BpmTaskCandidateStrategyEnum {
|
||||
|
||||
ROLE(10, "角色"),
|
||||
DEPT_MEMBER(20, "部门的成员"), // 包括负责人
|
||||
DEPT_LEADER(21, "部门的负责人"),
|
||||
POST(22, "岗位"),
|
||||
USER(30, "用户"),
|
||||
START_USER_SELECT(35, "发起人自选"), // 申请人自己,可在提交申请时选择此节点的审批人
|
||||
USER_GROUP(40, "用户组"),
|
||||
EXPRESSION(60, "流程表达式"), // 表达式 ExpressionManager
|
||||
;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final Integer strategy;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
public static BpmTaskCandidateStrategyEnum valueOf(Integer strategy) {
|
||||
return ArrayUtil.firstMatch(o -> o.getStrategy().equals(strategy), values());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.njcn.bpm.enums;
|
||||
|
||||
/**
|
||||
* BPMN XML 常量信息
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface BpmnModelConstants {
|
||||
|
||||
String BPMN_FILE_SUFFIX = ".bpmn";
|
||||
|
||||
/**
|
||||
* BPMN 中的命名空间
|
||||
*/
|
||||
String NAMESPACE = "http://flowable.org/bpmn";
|
||||
|
||||
/**
|
||||
* BPMN UserTask 的扩展属性,用于标记候选人策略
|
||||
*/
|
||||
String USER_TASK_CANDIDATE_STRATEGY = "candidateStrategy";
|
||||
/**
|
||||
* BPMN UserTask 的扩展属性,用于标记候选人参数
|
||||
*/
|
||||
String USER_TASK_CANDIDATE_PARAM = "candidateParam";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.njcn.bpm.enums;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 错误码对象
|
||||
*
|
||||
* 全局错误码,占用 [0, 999], 参见 {@link GlobalErrorCodeConstants}
|
||||
*
|
||||
* TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备
|
||||
*/
|
||||
@Data
|
||||
public class ErrorCode {
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private final Integer code;
|
||||
/**
|
||||
* 错误提示
|
||||
*/
|
||||
private final String msg;
|
||||
|
||||
public ErrorCode(Integer code, String message) {
|
||||
this.code = code;
|
||||
this.msg = message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.njcn.bpm.enums;
|
||||
|
||||
|
||||
/**
|
||||
* 全局错误码枚举
|
||||
* 0-999 系统异常编码保留
|
||||
*
|
||||
* 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
|
||||
* 虽然说,HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的
|
||||
* 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface GlobalErrorCodeConstants {
|
||||
|
||||
ErrorCode SUCCESS = new ErrorCode(0, "成功");
|
||||
|
||||
// ========== 客户端错误段 ==========
|
||||
|
||||
ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确");
|
||||
ErrorCode UNAUTHORIZED = new ErrorCode(401, "账号未登录");
|
||||
ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限");
|
||||
ErrorCode NOT_FOUND = new ErrorCode(404, "请求未找到");
|
||||
ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确");
|
||||
ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许
|
||||
ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试");
|
||||
|
||||
// ========== 服务端错误段 ==========
|
||||
|
||||
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
|
||||
ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未实现/未开启");
|
||||
ErrorCode ERROR_CONFIGURATION = new ErrorCode(502, "错误的配置项");
|
||||
|
||||
// ========== 自定义错误段 ==========
|
||||
ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
|
||||
ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作");
|
||||
|
||||
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.njcn.bpm.enums;
|
||||
|
||||
/**
|
||||
* 可生成 Int 数组的接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface IntArrayValuable {
|
||||
|
||||
/**
|
||||
* @return int 数组
|
||||
*/
|
||||
int[] array();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.njcn.bpm.pojo.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* BPM 流程 MetaInfo Response DTO
|
||||
* 主要用于 { Model#setMetaInfo(String)} 的存储
|
||||
*
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class BpmModelMetaInfoRespDTO {
|
||||
|
||||
/**
|
||||
* 流程图标
|
||||
*/
|
||||
private String icon;
|
||||
/**
|
||||
* 流程描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 表单类型
|
||||
*/
|
||||
private Integer formType;
|
||||
/**
|
||||
* 表单编号
|
||||
*/
|
||||
private String formId;
|
||||
/**
|
||||
* 自定义表单的提交路径,使用 Vue 的路由地址
|
||||
*/
|
||||
private String formCustomCreatePath;
|
||||
/**
|
||||
* 自定义表单的查看路径,使用 Vue 的路由地址
|
||||
*/
|
||||
private String formCustomViewPath;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.njcn.bpm.pojo.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.njcn.bpm.enums.ErrorCode;
|
||||
import com.njcn.bpm.enums.GlobalErrorCodeConstants;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import lombok.Data;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 通用返回
|
||||
*
|
||||
* @param <T> 数据泛型
|
||||
*/
|
||||
@Data
|
||||
public class CommonResult<T> implements Serializable {
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*
|
||||
* @see ErrorCode#getCode()
|
||||
*/
|
||||
private Integer code;
|
||||
/**
|
||||
* 返回数据
|
||||
*/
|
||||
private T data;
|
||||
/**
|
||||
* 错误提示,用户可阅读
|
||||
*
|
||||
* @see ErrorCode#getMsg() ()
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* 将传入的 result 对象,转换成另外一个泛型结果的对象
|
||||
*
|
||||
* 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。
|
||||
*
|
||||
* @param result 传入的 result 对象
|
||||
* @param <T> 返回的泛型
|
||||
* @return 新的 CommonResult 对象
|
||||
*/
|
||||
public static <T> CommonResult<T> error(CommonResult<?> result) {
|
||||
return error(result.getCode(), result.getMsg());
|
||||
}
|
||||
|
||||
public static <T> CommonResult<T> error(Integer code, String message) {
|
||||
Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code), "code 必须是错误的!");
|
||||
CommonResult<T> result = new CommonResult<>();
|
||||
result.code = code;
|
||||
result.msg = message;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> CommonResult<T> error( String message) {
|
||||
CommonResult<T> result = new CommonResult<>();
|
||||
result.msg = message;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> CommonResult<T> error(ErrorCode errorCode) {
|
||||
return error(errorCode.getCode(), errorCode.getMsg());
|
||||
}
|
||||
|
||||
public static <T> CommonResult<T> success(T data) {
|
||||
CommonResult<T> result = new CommonResult<>();
|
||||
result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
|
||||
result.data = data;
|
||||
result.msg = "";
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean isSuccess(Integer code) {
|
||||
return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode());
|
||||
}
|
||||
|
||||
@JsonIgnore // 避免 jackson 序列化
|
||||
public boolean isSuccess() {
|
||||
return isSuccess(code);
|
||||
}
|
||||
|
||||
@JsonIgnore // 避免 jackson 序列化
|
||||
public boolean isError() {
|
||||
return !isSuccess();
|
||||
}
|
||||
|
||||
// ========= 和 Exception 异常体系集成 =========
|
||||
|
||||
/**
|
||||
*/
|
||||
public void checkError() throws BusinessException {
|
||||
if (isSuccess()) {
|
||||
return;
|
||||
}
|
||||
// 业务异常
|
||||
throw new BusinessException(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果没有,则返回 {@link #data} 数据
|
||||
*/
|
||||
@JsonIgnore // 避免 jackson 序列化
|
||||
public T getCheckedData() {
|
||||
checkError();
|
||||
return data;
|
||||
}
|
||||
|
||||
public static <T> CommonResult<T> error(BusinessException serviceException) {
|
||||
return error( serviceException.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.njcn.bpm.pojo.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "分页结果")
|
||||
@Data
|
||||
public final class PageResult<T> implements Serializable {
|
||||
|
||||
private List<T> list;
|
||||
|
||||
private Long total;
|
||||
|
||||
public PageResult() {
|
||||
}
|
||||
|
||||
public PageResult(List<T> list, Long total) {
|
||||
this.list = list;
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public PageResult(Long total) {
|
||||
this.list = new ArrayList<>();
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public static <T> PageResult<T> empty() {
|
||||
return new PageResult<>(0L);
|
||||
}
|
||||
|
||||
public static <T> PageResult<T> empty(Long total) {
|
||||
return new PageResult<>(total);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.njcn.bpm.pojo.param;
|
||||
|
||||
import com.njcn.common.pojo.constant.PatternRegex;
|
||||
import com.njcn.web.constant.ValidMessage;
|
||||
import com.njcn.web.pojo.param.BaseParam;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.*;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* BPM 流程分类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class BpmCategoryParam implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* 分类名
|
||||
*/
|
||||
@ApiModelProperty("分类名")
|
||||
@NotNull(message = "分类名不能为空")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 分类标志
|
||||
*/
|
||||
@ApiModelProperty("分类标志")
|
||||
@NotNull(message = "分类标志不能为空")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 分类描述
|
||||
*/
|
||||
@ApiModelProperty("分类描述")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 分类状态
|
||||
*
|
||||
*/
|
||||
@ApiModelProperty("分类状态")
|
||||
private Integer status = 1;
|
||||
/**
|
||||
* 分类排序
|
||||
*/
|
||||
@ApiModelProperty("分类排序")
|
||||
private Integer sort = 100;
|
||||
|
||||
/**
|
||||
* 更新操作实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public static class BpmCategoryUpdateParam extends BpmCategoryParam {
|
||||
|
||||
/**
|
||||
* 表Id
|
||||
*/
|
||||
@ApiModelProperty("id")
|
||||
@NotBlank(message = ValidMessage.ID_NOT_BLANK)
|
||||
@Pattern(regexp = PatternRegex.SYSTEM_ID, message = ValidMessage.ID_FORMAT_ERROR)
|
||||
private String id;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public static class BpmCategoryQueryParam extends BaseParam {
|
||||
|
||||
/**
|
||||
* 表单名称
|
||||
*/
|
||||
@ApiModelProperty("分类名称")
|
||||
private String name;
|
||||
|
||||
|
||||
/**
|
||||
* 分类标志
|
||||
*/
|
||||
@ApiModelProperty("分类标志")
|
||||
private String code;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.njcn.bpm.pojo.param;
|
||||
|
||||
import com.njcn.common.pojo.constant.PatternRegex;
|
||||
import com.njcn.web.constant.ValidMessage;
|
||||
import com.njcn.web.pojo.param.BaseParam;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class BpmFormParam implements Serializable {
|
||||
|
||||
/**
|
||||
* 表单名
|
||||
*/
|
||||
@ApiModelProperty("表单名称")
|
||||
@NotNull(message = "表单名称不能为空")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@ApiModelProperty("表单状态")
|
||||
@NotNull(message = "表单状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 表单的配置
|
||||
*/
|
||||
@ApiModelProperty("表单的配置-JSON 字符串")
|
||||
@NotNull(message = "表单的配置不能为空")
|
||||
private String conf;
|
||||
|
||||
/**
|
||||
* 表单项的数组
|
||||
*
|
||||
*/
|
||||
@ApiModelProperty("表单项的数组-JSON 字符串的数组")
|
||||
@NotNull(message = "表单项的数组不能为空")
|
||||
private List<String> fields;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ApiModelProperty("备注")
|
||||
private String remark;
|
||||
|
||||
|
||||
/**
|
||||
* 更新操作实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public static class BpmFormUpdateParam extends BpmFormParam {
|
||||
|
||||
/**
|
||||
* 表Id
|
||||
*/
|
||||
@ApiModelProperty("id")
|
||||
@NotBlank(message = ValidMessage.ID_NOT_BLANK)
|
||||
@Pattern(regexp = PatternRegex.SYSTEM_ID, message = ValidMessage.ID_FORMAT_ERROR)
|
||||
private String id;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public static class BpmFormQueryParam extends BaseParam {
|
||||
|
||||
/**
|
||||
* 表单名称
|
||||
*/
|
||||
@ApiModelProperty("表单名称")
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.njcn.bpm.pojo.param;
|
||||
|
||||
import com.njcn.common.pojo.constant.PatternRegex;
|
||||
import com.njcn.web.constant.ValidMessage;
|
||||
import com.njcn.web.pojo.param.BaseParam;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hibernate.validator.constraints.URL;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
@Data
|
||||
public class BpmModelParam implements Serializable {
|
||||
|
||||
|
||||
@ApiModelProperty("流程标识")
|
||||
@NotNull(message = "流程标识不能为空")
|
||||
private String key;
|
||||
|
||||
@ApiModelProperty("流程名称")
|
||||
@NotNull(message = "流程名称不能为空")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty( "流程图标")
|
||||
private String icon;
|
||||
|
||||
@ApiModelProperty("流程分类")
|
||||
private String category;
|
||||
|
||||
@ApiModelProperty("BPMN XML")
|
||||
private String bpmnXml;
|
||||
|
||||
@ApiModelProperty("流程表单")
|
||||
private String formId;
|
||||
|
||||
@ApiModelProperty("流程描述")
|
||||
private String description;
|
||||
|
||||
private Integer formType = 10;
|
||||
|
||||
|
||||
private String formCustomCreatePath;
|
||||
|
||||
private String formCustomViewPath;
|
||||
|
||||
/**
|
||||
* 更新操作实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public static class BpmModelUpdateParam extends BpmModelParam {
|
||||
|
||||
/**
|
||||
* 表Id
|
||||
*/
|
||||
@ApiModelProperty("id")
|
||||
@NotBlank(message = ValidMessage.ID_NOT_BLANK)
|
||||
private String id;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public static class BpmModelQueryParam extends BaseParam {
|
||||
|
||||
@ApiModelProperty("流程标识")
|
||||
private String key;
|
||||
|
||||
@ApiModelProperty("流程名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("流程分类")
|
||||
private String category;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.njcn.bpm.pojo.param;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import com.njcn.common.pojo.constant.PatternRegex;
|
||||
import com.njcn.db.bo.BaseEntity;
|
||||
import com.njcn.web.constant.ValidMessage;
|
||||
import com.njcn.web.pojo.param.BaseParam;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* BPM 流程定义的拓信息
|
||||
* 主要解决 Flowable {@link org.flowable.engine.repository.ProcessDefinition} 不支持拓展字段,所以新建该表
|
||||
*/
|
||||
@Data
|
||||
public class BpmProcessDefinitionInfoParam extends BaseEntity implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* 流程定义的编号
|
||||
* <p>
|
||||
* 关联 ProcessDefinition 的 id 属性
|
||||
*/
|
||||
private String processDefinitionId;
|
||||
/**
|
||||
* 流程模型的编号
|
||||
* <p>
|
||||
* 关联 Model 的 id 属性
|
||||
*/
|
||||
private String modelId;
|
||||
|
||||
/**
|
||||
* 图标
|
||||
*/
|
||||
private String icon;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 表单类型
|
||||
*/
|
||||
private Integer formType;
|
||||
|
||||
/**
|
||||
* 动态表单编号
|
||||
*/
|
||||
private String formId;
|
||||
|
||||
/**
|
||||
* 表单的配置
|
||||
*/
|
||||
private String formConf;
|
||||
|
||||
/**
|
||||
* 表单项的数组
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<String> formFields;
|
||||
|
||||
|
||||
/**
|
||||
* 自定义表单的提交路径,使用 Vue 的路由地址
|
||||
*/
|
||||
private String formCustomCreatePath;
|
||||
|
||||
/**
|
||||
* 自定义表单的查看路径,使用 Vue 的路由地址
|
||||
*/
|
||||
private String formCustomViewPath;
|
||||
|
||||
/**
|
||||
* 更新操作实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public static class BpmProcessDefinitionInfoUpdateParam extends BpmProcessDefinitionInfoParam {
|
||||
|
||||
/**
|
||||
* 表Id
|
||||
*/
|
||||
@ApiModelProperty("id")
|
||||
@NotBlank(message = ValidMessage.ID_NOT_BLANK)
|
||||
@Pattern(regexp = PatternRegex.SYSTEM_ID, message = ValidMessage.ID_FORMAT_ERROR)
|
||||
private String id;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public static class BpmProcessDefinitionInfoQueryParam extends BaseParam {
|
||||
|
||||
@ApiModelProperty("标识-精准匹配")
|
||||
private String key;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.njcn.bpm.pojo.param;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Schema(description="分页参数")
|
||||
@Data
|
||||
public class PageParam implements Serializable {
|
||||
|
||||
private static final Integer PAGE_NO = 1;
|
||||
private static final Integer PAGE_SIZE = 10;
|
||||
|
||||
/**
|
||||
* 每页条数 - 不分页
|
||||
*
|
||||
* 例如说,导出接口,可以设置 {@link #pageSize} 为 -1 不分页,查询所有数据。
|
||||
*/
|
||||
public static final Integer PAGE_SIZE_NONE = -1;
|
||||
|
||||
@NotNull(message = "页码不能为空")
|
||||
@Min(value = 1, message = "页码最小值为 1")
|
||||
private Integer pageNo = PAGE_NO;
|
||||
|
||||
@NotNull(message = "每页条数不能为空")
|
||||
@Min(value = 1, message = "每页条数最小值为 1")
|
||||
@Max(value = 100, message = "每页条数最大值为 100")
|
||||
private Integer pageSize = PAGE_SIZE;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.njcn.bpm.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.njcn.db.bo.BaseEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* BPM 流程分类 DO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("bpm_category")
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BpmCategory extends BaseEntity implements Serializable {
|
||||
|
||||
/**
|
||||
* 分类编号
|
||||
*/
|
||||
@TableId
|
||||
private String id;
|
||||
/**
|
||||
* 分类名
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 分类标志
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 分类描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 分类状态
|
||||
*
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 分类排序
|
||||
*/
|
||||
private Integer sort;
|
||||
|
||||
/**
|
||||
* 状态:0-删除 1-正常
|
||||
*/
|
||||
private Integer state;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.njcn.bpm.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import com.njcn.db.bo.BaseEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* BPM 工作流的表单定义
|
||||
* 用于工作流的申请表单,需要动态配置的场景
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName(value = "bpm_form", autoResultMap = true)
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BpmForm extends BaseEntity implements Serializable {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private String id;
|
||||
/**
|
||||
* 表单名
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 表单的配置
|
||||
*/
|
||||
private String conf;
|
||||
/**
|
||||
* 表单项的数组
|
||||
*
|
||||
* 目前直接将 https://github.com/JakHuang/form-generator 生成的 JSON 串,直接保存
|
||||
* 定义:https://github.com/JakHuang/form-generator/issues/46
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<String> fields;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 状态:0-删除 1-正常
|
||||
*/
|
||||
private Integer state;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.njcn.bpm.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import com.njcn.db.bo.BaseEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* BPM 流程定义的拓信息
|
||||
* 主要解决 Flowable {@link org.flowable.engine.repository.ProcessDefinition} 不支持拓展字段,所以新建该表
|
||||
*
|
||||
*/
|
||||
@TableName(value = "bpm_process_definition_info", autoResultMap = true)
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BpmProcessDefinitionInfo extends BaseEntity implements Serializable {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private String id;
|
||||
/**
|
||||
* 流程定义的编号
|
||||
*
|
||||
* 关联 ProcessDefinition 的 id 属性
|
||||
*/
|
||||
private String processDefinitionId;
|
||||
/**
|
||||
* 流程模型的编号
|
||||
*
|
||||
* 关联 Model 的 id 属性
|
||||
*/
|
||||
private String modelId;
|
||||
|
||||
/**
|
||||
* 图标
|
||||
*/
|
||||
private String icon;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 表单类型
|
||||
*
|
||||
*/
|
||||
private Integer formType;
|
||||
|
||||
/**
|
||||
* 动态表单编号
|
||||
*
|
||||
*/
|
||||
private String formId;
|
||||
|
||||
/**
|
||||
* 表单的配置
|
||||
*
|
||||
*/
|
||||
private String formConf;
|
||||
|
||||
/**
|
||||
* 表单项的数组
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<String> formFields;
|
||||
|
||||
|
||||
/**
|
||||
* 自定义表单的提交路径,使用 Vue 的路由地址
|
||||
*/
|
||||
private String formCustomCreatePath;
|
||||
|
||||
/**
|
||||
* 自定义表单的查看路径,使用 Vue 的路由地址
|
||||
*/
|
||||
private String formCustomViewPath;
|
||||
|
||||
/**
|
||||
* 状态:0-删除 1-正常
|
||||
*/
|
||||
private Integer state;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.njcn.bpm.pojo.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.njcn.db.bo.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 流程表单
|
||||
* </p>
|
||||
*
|
||||
* @author hongawen
|
||||
* @since 2024-04-25
|
||||
*/
|
||||
@Data
|
||||
@TableName("wf_form")
|
||||
public class WFForm extends BaseEntity implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 流程表单id
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 表单名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 表单内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 表单描述
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 状态:0-删除 1-正常
|
||||
*/
|
||||
private Integer state;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.njcn.bpm.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* BPM 流程分类 DO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class BpmCategoryVO implements Serializable {
|
||||
|
||||
/**
|
||||
* 分类编号
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 分类名
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 分类标志
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 分类描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 分类状态
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 分类排序
|
||||
*/
|
||||
private Integer sort;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.njcn.bpm.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class BpmFormVO implements Serializable {
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String conf;
|
||||
|
||||
private List<String> fields;
|
||||
|
||||
private Integer status; // 参见 CommonStatusEnum 枚举
|
||||
|
||||
private String remark;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.njcn.bpm.pojo.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 流程模型 Response VO")
|
||||
@Data
|
||||
public class BpmModelRespVO {
|
||||
|
||||
private String id;
|
||||
|
||||
private String key;
|
||||
|
||||
private String name;
|
||||
|
||||
@Schema(description = "流程图标", example = "https://www.iocoder.cn/yudao.jpg")
|
||||
private String icon;
|
||||
|
||||
@Schema(description = "流程描述", example = "我是描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "流程分类编码", example = "1")
|
||||
private String category;
|
||||
@Schema(description = "流程分类名字", example = "请假")
|
||||
private String categoryName;
|
||||
|
||||
@Schema(description = "表单类型-参见 bpm_model_form_type 数据字典", example = "1")
|
||||
private Integer formType;
|
||||
|
||||
@Schema(description = "表单编号", example = "1024")
|
||||
private String formId; // 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空
|
||||
@Schema(description = "表单名字", example = "请假表单")
|
||||
private String formName;
|
||||
|
||||
@Schema(description = "自定义表单的提交路径", example = "/bpm/oa/leave/create")
|
||||
private String formCustomCreatePath; // 使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空
|
||||
@Schema(description = "自定义表单的查看路径", example = "/bpm/oa/leave/view")
|
||||
private String formCustomViewPath; // ,使用 Vue 的路由地址-在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM} 时,必须非空
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private String bpmnXml;
|
||||
|
||||
/**
|
||||
* 最新部署的流程定义
|
||||
*/
|
||||
private BpmProcessDefinitionInfoVO processDefinition;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.njcn.bpm.pojo.vo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import com.njcn.db.bo.BaseEntity;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* BPM 流程定义的拓信息
|
||||
* 主要解决 Flowable {@link org.flowable.engine.repository.ProcessDefinition} 不支持拓展字段,所以新建该表
|
||||
*
|
||||
*/
|
||||
@Data
|
||||
public class BpmProcessDefinitionInfoVO extends BaseEntity implements Serializable {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 流程定义的编号
|
||||
*
|
||||
* 关联 ProcessDefinition 的 id 属性
|
||||
*/
|
||||
private String processDefinitionId;
|
||||
/**
|
||||
* 流程模型的编号
|
||||
*
|
||||
* 关联 Model 的 id 属性
|
||||
*/
|
||||
private String modelId;
|
||||
|
||||
/**
|
||||
* 图标
|
||||
*/
|
||||
private String icon;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 表单类型
|
||||
*
|
||||
*/
|
||||
private Integer formType;
|
||||
|
||||
/**
|
||||
* 动态表单编号
|
||||
*
|
||||
*/
|
||||
private String formId;
|
||||
|
||||
/**
|
||||
* 表单的配置
|
||||
*
|
||||
*/
|
||||
private String formConf;
|
||||
|
||||
/**
|
||||
* 表单项的数组
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<String> formFields;
|
||||
|
||||
|
||||
/**
|
||||
* 自定义表单的提交路径,使用 Vue 的路由地址
|
||||
*/
|
||||
private String formCustomCreatePath;
|
||||
|
||||
/**
|
||||
* 自定义表单的查看路径,使用 Vue 的路由地址
|
||||
*/
|
||||
private String formCustomViewPath;
|
||||
|
||||
|
||||
private Integer version;
|
||||
|
||||
private String name;
|
||||
|
||||
private String key;
|
||||
|
||||
|
||||
@ApiModelProperty("流程分类")
|
||||
private String category;
|
||||
|
||||
@ApiModelProperty("流程分类名字")
|
||||
private String categoryName;
|
||||
|
||||
|
||||
@ApiModelProperty("表单名字")
|
||||
private String formName;
|
||||
|
||||
|
||||
private Integer suspensionState; // 参见 SuspensionState 枚举
|
||||
|
||||
@ApiModelProperty("部署时间")
|
||||
private LocalDateTime deploymentTime; // 需要从对应的 Deployment 读取,非必须返回
|
||||
|
||||
@ApiModelProperty("BPMN")
|
||||
private String bpmnXml; // 需要从对应的 BpmnModel 读取,非必须返回
|
||||
|
||||
@ApiModelProperty("发起用户需要选择审批人的任务数组")
|
||||
private List<BpmProcessDefinitionInfoVO.UserTask> startUserSelectTasks; // 需要从对应的 BpmnModel 读取,非必须返回
|
||||
|
||||
@Schema(description = "BPMN UserTask 用户任务")
|
||||
@Data
|
||||
public static class UserTask {
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.njcn.bpm.utils;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Bean 工具类
|
||||
*
|
||||
* 1. 默认使用 {@link BeanUtil} 作为实现类,虽然不同 bean 工具的性能有差别,但是对绝大多数同学的项目,不用在意这点性能
|
||||
* 2. 针对复杂的对象转换,可以搜参考 AuthConvert 实现,通过 mapstruct + default 配合实现
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class BeanUtils {
|
||||
|
||||
public static <T> T toBean(Object source, Class<T> targetClass) {
|
||||
return BeanUtil.toBean(source, targetClass);
|
||||
}
|
||||
|
||||
public static <T> T toBean(Object source, Class<T> targetClass, Consumer<T> peek) {
|
||||
T target = toBean(source, targetClass);
|
||||
if (target != null) {
|
||||
peek.accept(target);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
public static <S, T> List<T> toBean(List<S> source, Class<T> targetType) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
return CollectionUtils.convertList(source, s -> toBean(s, targetType));
|
||||
}
|
||||
|
||||
public static <S, T> List<T> toBean(List<S> source, Class<T> targetType, Consumer<T> peek) {
|
||||
List<T> list = toBean(source, targetType);
|
||||
if (list != null) {
|
||||
list.forEach(peek);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
//
|
||||
// public static <S, T> Page<T> toBean(Page<S> source, Class<T> targetType) {
|
||||
// return toBean(source, targetType, null);
|
||||
// }
|
||||
//
|
||||
// public static <S, T> Page<T> toBean(Page<S> source, Class<T> targetType, Consumer<T> peek) {
|
||||
// if (source == null) {
|
||||
// return null;
|
||||
// }
|
||||
// List<T> list = toBean(source.getRecords(), targetType);
|
||||
// if (peek != null) {
|
||||
// list.forEach(peek);
|
||||
// }
|
||||
// return new Page<>(list, source.getTotal());
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
package com.njcn.bpm.utils;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class CollectionUtils {
|
||||
|
||||
public static boolean containsAny(Object source, Object... targets) {
|
||||
return asList(targets).contains(source);
|
||||
}
|
||||
|
||||
public static boolean isAnyEmpty(Collection<?>... collections) {
|
||||
return Arrays.stream(collections).anyMatch(CollectionUtil::isEmpty);
|
||||
}
|
||||
|
||||
public static <T> boolean anyMatch(Collection<T> from, Predicate<T> predicate) {
|
||||
return from.stream().anyMatch(predicate);
|
||||
}
|
||||
|
||||
public static <T> List<T> filterList(Collection<T> from, Predicate<T> predicate) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return from.stream().filter(predicate).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <T, R> List<T> distinct(Collection<T> from, Function<T, R> keyMapper) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return distinct(from, keyMapper, (t1, t2) -> t1);
|
||||
}
|
||||
|
||||
public static <T, R> List<T> distinct(Collection<T> from, Function<T, R> keyMapper, BinaryOperator<T> cover) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return new ArrayList<>(convertMap(from, keyMapper, Function.identity(), cover).values());
|
||||
}
|
||||
|
||||
public static <T, U> List<U> convertList(T[] from, Function<T, U> func) {
|
||||
if (ArrayUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return convertList(Arrays.asList(from), func);
|
||||
}
|
||||
|
||||
public static <T, U> List<U> convertList(Collection<T> from, Function<T, U> func) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <T, U> List<U> convertList(Collection<T> from, Function<T, U> func, Predicate<T> filter) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <T, U> List<U> convertListByFlatMap(Collection<T> from,
|
||||
Function<T, ? extends Stream<? extends U>> func) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return from.stream().filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <T, U, R> List<R> convertListByFlatMap(Collection<T> from,
|
||||
Function<? super T, ? extends U> mapper,
|
||||
Function<U, ? extends Stream<? extends R>> func) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return from.stream().map(mapper).filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <K, V> List<V> mergeValuesFromMap(Map<K, List<V>> map) {
|
||||
return map.values()
|
||||
.stream()
|
||||
.flatMap(List::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static <T> Set<T> convertSet(Collection<T> from) {
|
||||
return convertSet(from, v -> v);
|
||||
}
|
||||
|
||||
public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func, Predicate<T> filter) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, T> convertMapByFilter(Collection<T> from, Predicate<T> filter, Function<T, K> keyFunc) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return from.stream().filter(filter).collect(Collectors.toMap(keyFunc, v -> v));
|
||||
}
|
||||
|
||||
public static <T, U> Set<U> convertSetByFlatMap(Collection<T> from,
|
||||
Function<T, ? extends Stream<? extends U>> func) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
return from.stream().filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static <T, U, R> Set<R> convertSetByFlatMap(Collection<T> from,
|
||||
Function<? super T, ? extends U> mapper,
|
||||
Function<U, ? extends Stream<? extends R>> func) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
return from.stream().map(mapper).filter(Objects::nonNull).flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return convertMap(from, keyFunc, Function.identity());
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc, Supplier<? extends Map<K, T>> supplier) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return supplier.get();
|
||||
}
|
||||
return convertMap(from, keyFunc, Function.identity(), supplier);
|
||||
}
|
||||
|
||||
public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return convertMap(from, keyFunc, valueFunc, (v1, v2) -> v1);
|
||||
}
|
||||
|
||||
public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc, BinaryOperator<V> mergeFunction) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return convertMap(from, keyFunc, valueFunc, mergeFunction, HashMap::new);
|
||||
}
|
||||
|
||||
public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc, Supplier<? extends Map<K, V>> supplier) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return supplier.get();
|
||||
}
|
||||
return convertMap(from, keyFunc, valueFunc, (v1, v2) -> v1, supplier);
|
||||
}
|
||||
|
||||
public static <T, K, V> Map<K, V> convertMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc, BinaryOperator<V> mergeFunction, Supplier<? extends Map<K, V>> supplier) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return from.stream().collect(Collectors.toMap(keyFunc, valueFunc, mergeFunction, supplier));
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, List<T>> convertMultiMap(Collection<T> from, Function<T, K> keyFunc) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return from.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(t -> t, Collectors.toList())));
|
||||
}
|
||||
|
||||
public static <T, K, V> Map<K, List<V>> convertMultiMap(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return from.stream()
|
||||
.collect(Collectors.groupingBy(keyFunc, Collectors.mapping(valueFunc, Collectors.toList())));
|
||||
}
|
||||
|
||||
// 暂时没想好名字,先以 2 结尾噶
|
||||
public static <T, K, V> Map<K, Set<V>> convertMultiMap2(Collection<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return from.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(valueFunc, Collectors.toSet())));
|
||||
}
|
||||
|
||||
public static <T, K> Map<K, T> convertImmutableMap(Collection<T> from, Function<T, K> keyFunc) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
ImmutableMap.Builder<K, T> builder = ImmutableMap.builder();
|
||||
from.forEach(item -> builder.put(keyFunc.apply(item), item));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对比老、新两个列表,找出新增、修改、删除的数据
|
||||
*
|
||||
* @param oldList 老列表
|
||||
* @param newList 新列表
|
||||
* @param sameFunc 对比函数,返回 true 表示相同,返回 false 表示不同
|
||||
* 注意,same 是通过每个元素的“标识”,判断它们是不是同一个数据
|
||||
* @return [新增列表、修改列表、删除列表]
|
||||
*/
|
||||
public static <T> List<List<T>> diffList(Collection<T> oldList, Collection<T> newList,
|
||||
BiFunction<T, T, Boolean> sameFunc) {
|
||||
List<T> createList = new LinkedList<>(newList); // 默认都认为是新增的,后续会进行移除
|
||||
List<T> updateList = new ArrayList<>();
|
||||
List<T> deleteList = new ArrayList<>();
|
||||
|
||||
// 通过以 oldList 为主遍历,找出 updateList 和 deleteList
|
||||
for (T oldObj : oldList) {
|
||||
// 1. 寻找是否有匹配的
|
||||
T foundObj = null;
|
||||
for (Iterator<T> iterator = createList.iterator(); iterator.hasNext(); ) {
|
||||
T newObj = iterator.next();
|
||||
// 1.1 不匹配,则直接跳过
|
||||
if (!sameFunc.apply(oldObj, newObj)) {
|
||||
continue;
|
||||
}
|
||||
// 1.2 匹配,则移除,并结束寻找
|
||||
iterator.remove();
|
||||
foundObj = newObj;
|
||||
break;
|
||||
}
|
||||
// 2. 匹配添加到 updateList;不匹配则添加到 deleteList 中
|
||||
if (foundObj != null) {
|
||||
updateList.add(foundObj);
|
||||
} else {
|
||||
deleteList.add(oldObj);
|
||||
}
|
||||
}
|
||||
return asList(createList, updateList, deleteList);
|
||||
}
|
||||
|
||||
public static boolean containsAny(Collection<?> source, Collection<?> candidates) {
|
||||
return org.springframework.util.CollectionUtils.containsAny(source, candidates);
|
||||
}
|
||||
|
||||
public static <T> T getFirst(List<T> from) {
|
||||
return !CollectionUtil.isEmpty(from) ? from.get(0) : null;
|
||||
}
|
||||
|
||||
public static <T> T findFirst(Collection<T> from, Predicate<T> predicate) {
|
||||
return findFirst(from, predicate, Function.identity());
|
||||
}
|
||||
|
||||
public static <T, U> U findFirst(Collection<T> from, Predicate<T> predicate, Function<T, U> func) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return null;
|
||||
}
|
||||
return from.stream().filter(predicate).findFirst().map(func).orElse(null);
|
||||
}
|
||||
|
||||
public static <T, V extends Comparable<? super V>> V getMaxValue(Collection<T> from, Function<T, V> valueFunc) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return null;
|
||||
}
|
||||
assert !from.isEmpty(); // 断言,避免告警
|
||||
T t = from.stream().max(Comparator.comparing(valueFunc)).get();
|
||||
return valueFunc.apply(t);
|
||||
}
|
||||
|
||||
public static <T, V extends Comparable<? super V>> V getMinValue(List<T> from, Function<T, V> valueFunc) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return null;
|
||||
}
|
||||
assert from.size() > 0; // 断言,避免告警
|
||||
T t = from.stream().min(Comparator.comparing(valueFunc)).get();
|
||||
return valueFunc.apply(t);
|
||||
}
|
||||
|
||||
public static <T, V extends Comparable<? super V>> V getSumValue(List<T> from, Function<T, V> valueFunc,
|
||||
BinaryOperator<V> accumulator) {
|
||||
return getSumValue(from, valueFunc, accumulator, null);
|
||||
}
|
||||
|
||||
public static <T, V extends Comparable<? super V>> V getSumValue(Collection<T> from, Function<T, V> valueFunc,
|
||||
BinaryOperator<V> accumulator, V defaultValue) {
|
||||
if (CollUtil.isEmpty(from)) {
|
||||
return defaultValue;
|
||||
}
|
||||
assert !from.isEmpty(); // 断言,避免告警
|
||||
return from.stream().map(valueFunc).filter(Objects::nonNull).reduce(accumulator).orElse(defaultValue);
|
||||
}
|
||||
|
||||
public static <T> void addIfNotNull(Collection<T> coll, T item) {
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
coll.add(item);
|
||||
}
|
||||
|
||||
public static <T> Collection<T> singleton(T obj) {
|
||||
return obj == null ? Collections.emptyList() : Collections.singleton(obj);
|
||||
}
|
||||
|
||||
public static <T> List<T> newArrayList(List<List<T>> list) {
|
||||
return list.stream().flatMap(Collection::stream).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
149
pqs-bpm/bpm-api/src/main/java/com/njcn/bpm/utils/DateUtils.java
Normal file
149
pqs-bpm/bpm-api/src/main/java/com/njcn/bpm/utils/DateUtils.java
Normal file
@@ -0,0 +1,149 @@
|
||||
package com.njcn.bpm.utils;
|
||||
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
|
||||
import java.time.*;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 时间工具类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class DateUtils {
|
||||
|
||||
/**
|
||||
* 时区 - 默认
|
||||
*/
|
||||
public static final String TIME_ZONE_DEFAULT = "GMT+8";
|
||||
|
||||
/**
|
||||
* 秒转换成毫秒
|
||||
*/
|
||||
public static final long SECOND_MILLIS = 1000;
|
||||
|
||||
public static final String FORMAT_YEAR_MONTH_DAY = "yyyy-MM-dd";
|
||||
|
||||
public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
/**
|
||||
* 将 LocalDateTime 转换成 Date
|
||||
*
|
||||
* @param date LocalDateTime
|
||||
* @return LocalDateTime
|
||||
*/
|
||||
public static Date of(LocalDateTime date) {
|
||||
if (date == null) {
|
||||
return null;
|
||||
}
|
||||
// 将此日期时间与时区相结合以创建 ZonedDateTime
|
||||
ZonedDateTime zonedDateTime = date.atZone(ZoneId.systemDefault());
|
||||
// 本地时间线 LocalDateTime 到即时时间线 Instant 时间戳
|
||||
Instant instant = zonedDateTime.toInstant();
|
||||
// UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
|
||||
return Date.from(instant);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Date 转换成 LocalDateTime
|
||||
*
|
||||
* @param date Date
|
||||
* @return LocalDateTime
|
||||
*/
|
||||
public static LocalDateTime of(Date date) {
|
||||
if (date == null) {
|
||||
return null;
|
||||
}
|
||||
// 转为时间戳
|
||||
Instant instant = date.toInstant();
|
||||
// UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
|
||||
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
public static Date addTime(Duration duration) {
|
||||
return new Date(System.currentTimeMillis() + duration.toMillis());
|
||||
}
|
||||
|
||||
public static boolean isExpired(LocalDateTime time) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return now.isAfter(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定时间
|
||||
*
|
||||
* @param year 年
|
||||
* @param mouth 月
|
||||
* @param day 日
|
||||
* @return 指定时间
|
||||
*/
|
||||
public static Date buildTime(int year, int mouth, int day) {
|
||||
return buildTime(year, mouth, day, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定时间
|
||||
*
|
||||
* @param year 年
|
||||
* @param mouth 月
|
||||
* @param day 日
|
||||
* @param hour 小时
|
||||
* @param minute 分钟
|
||||
* @param second 秒
|
||||
* @return 指定时间
|
||||
*/
|
||||
public static Date buildTime(int year, int mouth, int day,
|
||||
int hour, int minute, int second) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.YEAR, year);
|
||||
calendar.set(Calendar.MONTH, mouth - 1);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, day);
|
||||
calendar.set(Calendar.HOUR_OF_DAY, hour);
|
||||
calendar.set(Calendar.MINUTE, minute);
|
||||
calendar.set(Calendar.SECOND, second);
|
||||
calendar.set(Calendar.MILLISECOND, 0); // 一般情况下,都是 0 毫秒
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
public static Date max(Date a, Date b) {
|
||||
if (a == null) {
|
||||
return b;
|
||||
}
|
||||
if (b == null) {
|
||||
return a;
|
||||
}
|
||||
return a.compareTo(b) > 0 ? a : b;
|
||||
}
|
||||
|
||||
public static LocalDateTime max(LocalDateTime a, LocalDateTime b) {
|
||||
if (a == null) {
|
||||
return b;
|
||||
}
|
||||
if (b == null) {
|
||||
return a;
|
||||
}
|
||||
return a.isAfter(b) ? a : b;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否今天
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isToday(LocalDateTime date) {
|
||||
return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否昨天
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 是否
|
||||
*/
|
||||
public static boolean isYesterday(LocalDateTime date) {
|
||||
return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now().minusDays(1));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.njcn.bpm.utils;
|
||||
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 数字的工具类,补全 {@link NumberUtil} 的功能
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class NumberUtils {
|
||||
|
||||
public static Long parseLong(String str) {
|
||||
return StrUtil.isNotEmpty(str) ? Long.valueOf(str) : null;
|
||||
}
|
||||
|
||||
public static Integer parseInt(String str) {
|
||||
return StrUtil.isNotEmpty(str) ? Integer.valueOf(str) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过经纬度获取地球上两点之间的距离
|
||||
*
|
||||
* 参考 <<a href="https://gitee.com/dromara/hutool/blob/1caabb586b1f95aec66a21d039c5695df5e0f4c1/hutool-core/src/main/java/cn/hutool/core/util/DistanceUtil.java">DistanceUtil</a>> 实现,目前它已经被 hutool 删除
|
||||
*
|
||||
* @param lat1 经度1
|
||||
* @param lng1 纬度1
|
||||
* @param lat2 经度2
|
||||
* @param lng2 纬度2
|
||||
* @return 距离,单位:千米
|
||||
*/
|
||||
public static double getDistance(double lat1, double lng1, double lat2, double lng2) {
|
||||
double radLat1 = lat1 * Math.PI / 180.0;
|
||||
double radLat2 = lat2 * Math.PI / 180.0;
|
||||
double a = radLat1 - radLat2;
|
||||
double b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
|
||||
double distance = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
|
||||
+ Math.cos(radLat1) * Math.cos(radLat2)
|
||||
* Math.pow(Math.sin(b / 2), 2)));
|
||||
distance = distance * 6378.137;
|
||||
distance = Math.round(distance * 10000d) / 10000d;
|
||||
return distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供精确的乘法运算
|
||||
*
|
||||
* 和 hutool {@link NumberUtil#mul(BigDecimal...)} 的差别是,如果存在 null,则返回 null
|
||||
*
|
||||
* @param values 多个被乘值
|
||||
* @return 积
|
||||
*/
|
||||
public static BigDecimal mul(BigDecimal... values) {
|
||||
for (BigDecimal value : values) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return NumberUtil.mul(values);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.njcn.bpm.utils;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.njcn.bpm.enums.BpmResponseEnum;
|
||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
||||
import com.njcn.common.pojo.exception.BusinessException;
|
||||
import com.njcn.common.pojo.response.HttpResult;
|
||||
import com.njcn.common.utils.EnumUtils;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* @version 1.0.0
|
||||
* @date 2021年12月20日 10:03
|
||||
*/
|
||||
public class ProcessEnumUtil {
|
||||
|
||||
/**
|
||||
* 获取HarmonicResponseEnum实例
|
||||
*/
|
||||
public static BpmResponseEnum getHarmonicEnumResponseEnumByMessage(@NotNull Object value) {
|
||||
BpmResponseEnum harmonicResponseEnum;
|
||||
try {
|
||||
String message = value.toString();
|
||||
if(message.indexOf(StrUtil.C_COMMA)>0){
|
||||
value = message.substring(message.indexOf(StrUtil.C_COMMA)+1);
|
||||
}
|
||||
harmonicResponseEnum = EnumUtils.valueOf(BpmResponseEnum.class, value, BpmResponseEnum.class.getMethod(BusinessException.GET_MESSAGE_METHOD));
|
||||
return Objects.isNull(harmonicResponseEnum) ? BpmResponseEnum.BPM_COMMON_ERROR : harmonicResponseEnum;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new BusinessException(CommonResponseEnum.INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
public static Enum<?> getExceptionEnum(HttpResult<Object> result){
|
||||
//如果返回错误,且为内部错误,则直接抛出异常
|
||||
CommonResponseEnum commonResponseEnum = EnumUtils.getCommonResponseEnumByCode(result.getCode());
|
||||
if (commonResponseEnum == CommonResponseEnum.DEVICE_RESPONSE_ENUM) {
|
||||
return getHarmonicEnumResponseEnumByMessage(result.getMessage());
|
||||
}
|
||||
return commonResponseEnum;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.njcn.bpm.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 校验工具类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public class ValidationUtils {
|
||||
|
||||
private static final Pattern PATTERN_MOBILE = Pattern.compile("^(?:(?:\\+|00)86)?1(?:(?:3[\\d])|(?:4[0,1,4-9])|(?:5[0-3,5-9])|(?:6[2,5-7])|(?:7[0-8])|(?:8[\\d])|(?:9[0-3,5-9]))\\d{8}$");
|
||||
|
||||
private static final Pattern PATTERN_URL = Pattern.compile("^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]");
|
||||
|
||||
private static final Pattern PATTERN_XML_NCNAME = Pattern.compile("[a-zA-Z_][\\-_.0-9_a-zA-Z$]*");
|
||||
|
||||
public static boolean isMobile(String mobile) {
|
||||
return StringUtils.hasText(mobile)
|
||||
&& PATTERN_MOBILE.matcher(mobile).matches();
|
||||
}
|
||||
|
||||
public static boolean isURL(String url) {
|
||||
return StringUtils.hasText(url)
|
||||
&& PATTERN_URL.matcher(url).matches();
|
||||
}
|
||||
|
||||
public static boolean isXmlNCName(String str) {
|
||||
return StringUtils.hasText(str)
|
||||
&& PATTERN_XML_NCNAME.matcher(str).matches();
|
||||
}
|
||||
|
||||
public static void validate(Object object, Class<?>... groups) {
|
||||
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
Assert.notNull(validator);
|
||||
validate(validator, object, groups);
|
||||
}
|
||||
|
||||
public static void validate(Validator validator, Object object, Class<?>... groups) {
|
||||
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
|
||||
if (CollUtil.isNotEmpty(constraintViolations)) {
|
||||
throw new ConstraintViolationException(constraintViolations);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user