package com.vci.starter.revision.service;
|
|
import com.vci.starter.revision.bo.TreeWrapperOptions;
|
import com.vci.starter.revision.model.*;
|
import com.vci.starter.revision.provider.*;
|
import com.vci.starter.web.annotation.Column;
|
import com.vci.starter.web.annotation.VciBtmType;
|
import com.vci.starter.web.annotation.VciColumnDefinition;
|
import com.vci.starter.web.constant.RevisionConstant;
|
import com.vci.starter.web.constant.RegExpConstant;
|
import com.vci.starter.web.enumpck.DataSecretEnum;
|
import com.vci.starter.web.enumpck.UserSecretEnum;
|
import com.vci.starter.web.exception.VciBaseException;
|
import com.vci.starter.web.model.BaseLinkModel;
|
import com.vci.starter.web.model.BaseModel;
|
import com.vci.starter.web.pagemodel.BaseResult;
|
import com.vci.starter.web.pagemodel.PageHelper;
|
import com.vci.starter.web.pagemodel.Tree;
|
import com.vci.starter.web.pagemodel.TreeQueryObject;
|
import com.vci.starter.web.service.VciSecretServiceI;
|
import com.vci.starter.web.util.BeanUtil;
|
import com.vci.starter.web.util.BeanUtilForVCI;
|
import com.vci.starter.web.util.VciBaseUtil;
|
import com.vci.starter.web.util.VciDateUtil;
|
import com.vci.starter.web.wrapper.VciQueryWrapperForDO;
|
import com.vci.starter.web.wrapper.VciQueryWrapperOption;
|
import org.apache.commons.lang3.StringUtils;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Component;
|
import org.springframework.util.CollectionUtils;
|
import java.lang.reflect.Field;
|
import java.util.*;
|
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.function.Function;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
import java.util.stream.Collectors;
|
|
/**
|
* 版本和对象模型的工具类
|
* @author weidy
|
* @date 2020/4/15
|
*/
|
@Component
|
public class RevisionModelUtil implements VciSecretServiceI {
|
|
/**
|
* 日志对象
|
*/
|
private Logger logger = LoggerFactory.getLogger(getClass());
|
|
/**
|
* 存储对象类的属性的注释
|
*/
|
public volatile static Map<String, Map<String,String>> modelColumnAnnotationMap = new ConcurrentHashMap<>();
|
|
/**
|
* 实体类和注解的映射,在springboot热加载的时候一定要清除
|
*/
|
public volatile static Map<String,VciBtmType> modelAnnotationMap = new ConcurrentHashMap<>();
|
|
/**
|
* 判断幂等性,使用redis
|
*/
|
public static boolean CHECK_IDEMPOTENCE = false;
|
|
/**
|
* 版本的数据操作层
|
*/
|
@Autowired(required = false)
|
private VciRevisionServiceI revisionMapper;
|
|
/**
|
* 版本的调用器
|
*/
|
@Autowired(required = false)
|
private CommonRevisionRuleProvider revisionRuleProvider;
|
|
/**
|
* 生命周期的调用器
|
*/
|
@Autowired(required = false)
|
private CommonLifeCycleProvider lifeCycleProvider;
|
|
/**
|
* 注释的调用接口
|
*/
|
@Autowired(required = false)
|
private CommonAnnotationProvider annotationProvider;
|
|
/**
|
* 是最新版本的值
|
*/
|
public static final String LAST_REV_VALUE = "1";
|
|
/**
|
* 不是最新版本的值
|
*/
|
public static final String UN_LAST_REV_VALUE = "0";
|
|
|
/**
|
* 在数据新增的时候封装属性(包括创建者和生命周期等),并且校验必输项,唯一项(其中唯一项对于时间无法判断),密级
|
* @param baseModel 基础数据对象
|
*/
|
public void wrapperForAdd(BaseModel baseModel){
|
wrapperForAddOrUpVersion(baseModel,false,false);
|
}
|
|
/**
|
* 批量添加数据
|
* @param baseModelCollection 数据对象集合
|
*/
|
public void wrapperForBatchAdd(Collection<? extends BaseModel> baseModelCollection ){
|
VciBaseUtil.alertCollectionNotNull("要新增的数据对象",baseModelCollection);
|
BaseModel fristModel = baseModelCollection.iterator().next();
|
VciBtmType vciBtmType = getBtmTypeAnnotation(fristModel);
|
if(vciBtmType == null){
|
throw new VciBaseException("实体对象上没有添加VciBtmType注解");
|
}
|
//有column注解的属性,有这个注解才需要校验必输项和唯一项
|
List<Field> hasColumnAnnoFields = filterHasColumnAnnoFields(VciBaseUtil.getAllFieldForObj(fristModel.getClass()));
|
//必输项
|
List<Field> checkNullFields = filterCheckNullFields(hasColumnAnnoFields);
|
//唯一项的,包含不区分大小写和区分大小写的
|
Map<Field/**要校验唯一项的属性**/, Boolean/**是否不区分大小写**/> checkUniqueFieldsMap = filterCheckUniqueFieldsHasUnCase(fristModel.getClass());
|
|
//唯一的属性的值
|
Map<String/**属性的名称**/,Set<Object>> unqiueFieldValueMap = new HashMap<>();
|
|
String creator = VciBaseUtil.getCurrentUserId();
|
Date currentDate= new Date();
|
String btmName = vciBtmType.name();
|
|
//获取默认的版本号,生命周期,密级
|
|
wrapperFristRevision(fristModel);
|
wrapperLifeCycle(fristModel);
|
boolean manageRevision = isManageRevision(vciBtmType);
|
boolean manageLifeCycle = isManageLifeCycle(vciBtmType);
|
boolean checkSecret = isCheckSecret(vciBtmType);
|
|
//遍历,实际也是每一个处理一次,只是版本和生命周期等不重复获取
|
baseModelCollection.stream().forEach(s -> {
|
VciBaseUtil.alertNotNull(s,"要添加的数据对象");
|
setBaseFieldValue(s,creator,currentDate,btmName);
|
//校验必输项
|
checkFieldsRequired(checkNullFields,s);
|
//先判断当前集合中唯一项是否有重复
|
if(!CollectionUtils.isEmpty(checkUniqueFieldsMap)){
|
checkUniqueFieldsMap.forEach( (field,unCase) ->{
|
checkUniqueValues(field,unCase,s,unqiueFieldValueMap,false);
|
});
|
}
|
|
//因为新增都一定是第一个版本和版次,所以如果没有设置的时候,全部用初始版本号
|
if(manageRevision){
|
if(StringUtils.isBlank(s.getNameOid())){
|
s.setNameOid(VciBaseUtil.getPk());
|
}
|
if(StringUtils.isBlank(s.getRevisionOid())){
|
s.setRevisionOid(VciBaseUtil.getPk());
|
}
|
s.setRevisionRule(fristModel.getRevisionRule());
|
s.setRevisionValue(fristModel.getRevisionValue());
|
s.setRevisionSeq(1);
|
s.setFirstR("1");
|
s.setLastR("1");
|
s.setVersionRule(fristModel.getVersionRule());
|
s.setVersionValue(fristModel.getVersionValue());
|
s.setVersionSeq(1);
|
s.setLastV("1");
|
s.setFirstV("1");
|
}
|
if(manageLifeCycle && StringUtils.isBlank(s.getLcStatus())){
|
s.setLcStatus(fristModel.getLcStatus());
|
}
|
if(checkSecret){
|
checkDataSecret(s);
|
}
|
});
|
}
|
|
/**
|
* 在数据修改的时候封装属性
|
* @param baseModel 基础数据对象
|
*/
|
public void wrapperForEdit(BaseModel baseModel){
|
VciBaseUtil.alertNotNull(baseModel,"要修改的数据对象",baseModel.getOid(),"数据的主键");
|
Date currentDate = new Date();
|
baseModel.setTs(currentDate);
|
baseModel.setLastModifier(VciBaseUtil.getCurrentUserId());
|
baseModel.setLastModifyTime(currentDate);
|
//
|
VciBtmType vciBtmType = getBtmTypeAnnotation(baseModel);
|
if(StringUtils.isBlank(baseModel.getBtmname()) && vciBtmType!=null){
|
baseModel.setBtmname(vciBtmType.name());
|
}
|
//获取包含了column注解的属性,因为不包含这个注解的时候是默认nullable为true,unique为false
|
List<Field> hasColumnAnnoFields = filterHasColumnAnnoFields(baseModel);
|
//判断是否有空的属性
|
checkFieldsRequired(filterCheckNullFields(hasColumnAnnoFields),baseModel);
|
Map<Field,Boolean> checkUniqueFields = filterCheckUniqueFieldsHasUnCase(hasColumnAnnoFields);
|
if(!CollectionUtils.isEmpty(checkUniqueFields)){
|
checkUniqueFields.forEach((field,unCase) ->{
|
checkUniqueValues(field,unCase,baseModel,new HashMap<>(),true);
|
});
|
}
|
//校验密级
|
checkDataSecret(baseModel);
|
//修改的时候版本号和生命周期不应该变化
|
}
|
|
/**
|
* 批量修改数据对象时封装属性,包括唯一项,必输项和基本属性设置
|
* @param baseModelCollection 数据对象集合
|
*/
|
public void wrapperForBatchEdit(List<? extends BaseModel> baseModelCollection){
|
VciBaseUtil.alertCollectionNotNull("要修改的数据对象",baseModelCollection);
|
BaseModel fristModel = baseModelCollection.iterator().next();
|
VciBtmType vciBtmType = getBtmTypeAnnotation(fristModel);
|
if(vciBtmType == null){
|
throw new VciBaseException("实体对象上没有添加VciBtmType注解");
|
}
|
//有column注解的属性,有这个注解才需要校验必输项和唯一项
|
List<Field> hasColumnAnnoFields = filterHasColumnAnnoFields(VciBaseUtil.getAllFieldForObj(fristModel.getClass()));
|
//必输项
|
List<Field> checkNullFields = filterCheckNullFields(hasColumnAnnoFields);
|
//唯一项的,包含不区分大小写和区分大小写的
|
Map<Field/**要校验唯一项的属性**/, Boolean/**是否不区分大小写**/> checkUniqueFieldsMap = filterCheckUniqueFieldsHasUnCase(fristModel.getClass());
|
|
//唯一的属性的值
|
Map<String/**属性的名称**/,Set<Object>> unqiueFieldValueMap = new HashMap<>();
|
|
String creator = VciBaseUtil.getCurrentUserId();
|
Date currentDate= new Date();
|
String btmName = vciBtmType.name();
|
|
boolean checkSecret = isCheckSecret(vciBtmType);
|
|
//遍历,实际也是每一个处理一次,只是版本和生命周期等不重复获取
|
baseModelCollection.stream().forEach(s -> {
|
VciBaseUtil.alertNotNull(s,"要添加的数据对象");
|
setBaseFieldValueEdit(s,creator,currentDate);
|
//校验必输项
|
checkFieldsRequired(checkNullFields,s);
|
//先判断当前集合中唯一项是否有重复
|
if(!CollectionUtils.isEmpty(checkUniqueFieldsMap)){
|
checkUniqueFieldsMap.forEach( (field,unCase) ->{
|
checkUniqueValues(field,unCase,s,unqiueFieldValueMap,true);
|
});
|
}
|
//修改的时候,版本和生命周期都不能修改,密级需要修改,所以需要再次校验
|
if(checkSecret){
|
checkDataSecret(s);
|
}
|
});
|
}
|
|
/**
|
* 升版本号
|
* @param baseModel 数据对象
|
*/
|
public void wrapperForUpRevision(BaseModel baseModel){
|
wrapperForAddOrUpVersion(baseModel,true,false);
|
}
|
|
/**
|
* 升版次
|
* @param baseModel 数据对象
|
*/
|
public void wrapperForUpVersion(BaseModel baseModel){
|
wrapperForAddOrUpVersion(baseModel,true,true);
|
}
|
|
/**
|
* 在修改的时候拷贝,防止前端没有传递默认的属性
|
* @param dto 数据传输对象
|
* @param baseModel 数据库中的数据对象
|
*/
|
public void copyFromDTO(Object dto,BaseModel baseModel){
|
VciBaseUtil.alertNotNull(dto,"数据传输对象",baseModel,"数据库中的数据对象");
|
//前端可能不会把默认的所有属性传递过来,所以先从数据库中的数据对象拷贝到临时的对象上
|
BaseModel tempModel = new BaseModel();
|
BeanUtil.convert(baseModel,tempModel);
|
BeanUtil.convert(dto,baseModel);
|
//BeanUtil.convert(tempModel,baseModel);
|
//不知道为啥,突然BeanUtil.convert(tempModel,baseModel);不好使了
|
BeanUtilForVCI.copyPropertiesIgnoreCase(tempModel,baseModel);
|
//为了防止前端没有传递默认的属性,所以得先拷贝到baseModel中,然后dto拷贝一次后,再把数据库中拷贝回来。
|
//但是因为id,name,description极大概率前端会传递,所以这里也设置一下
|
baseModel.setId(VciBaseUtil.getStringValueFromObject(VciBaseUtil.getValueFromField("id",dto)));
|
baseModel.setName(VciBaseUtil.getStringValueFromObject(VciBaseUtil.getValueFromField("name",dto)));
|
baseModel.setDescription(VciBaseUtil.getStringValueFromObject(VciBaseUtil.getValueFromField("description",dto)));
|
tempModel = null;
|
}
|
|
/**
|
* 从DTO上拷贝,忽略属性大小写
|
* @param dto DTO对象
|
* @param baseModel 目标对象
|
*/
|
public void copyFromDTOIgnore(Object dto,BaseModel baseModel){
|
VciBaseUtil.alertNotNull(dto,"数据传输对象",baseModel,"数据库中的数据对象");
|
//前端可能不会把默认的所有属性传递过来,所以先从数据库中的数据对象拷贝到临时的对象上
|
BaseModel tempModel = new BaseModel();
|
BeanUtilForVCI.copyPropertiesIgnoreCase(baseModel,tempModel);
|
BeanUtilForVCI.copyPropertiesIgnoreCase(dto,baseModel);
|
BeanUtilForVCI.copyPropertiesIgnoreCase(tempModel,baseModel);
|
//为了防止前端没有传递默认的属性,所以得先拷贝到baseModel中,然后dto拷贝一次后,再把数据库中拷贝回来。
|
//但是因为id,name,description极大概率前端会传递,所以这里也设置一下
|
baseModel.setId(VciBaseUtil.getStringValueFromObject(VciBaseUtil.getValueFromField("id",dto)));
|
baseModel.setName(VciBaseUtil.getStringValueFromObject(VciBaseUtil.getValueFromField("name",dto)));
|
baseModel.setDescription(VciBaseUtil.getStringValueFromObject(VciBaseUtil.getValueFromField("description",dto)));
|
tempModel = null;
|
}
|
|
/**
|
* 在数据新增的时候为链接类型封装属性
|
* @param linkModel 链接类型数据对象
|
*/
|
public void wrapperForAddLink(BaseLinkModel linkModel){
|
VciBaseUtil.alertNotNull(linkModel,"要新增的链接类型数据对象");
|
if(StringUtils.isBlank(linkModel.getOid())){
|
linkModel.setOid(VciBaseUtil.getPk());
|
}
|
linkModel.setCreator(VciBaseUtil.getCurrentUserId());
|
Date currentDate = new Date();
|
linkModel.setCreateTime(currentDate);
|
linkModel.setTs(currentDate);
|
linkModel.setLastModifier(linkModel.getCreator());
|
linkModel.setLastModifytime(currentDate);
|
}
|
|
/**
|
* 在新增数据的时候为链接类型封装属性
|
* @param linkModel 链接类型对象
|
* @param fromModel from端业务数据
|
* @param toModel to端业务数据
|
*/
|
public void wrapperForAddLink(BaseLinkModel linkModel,BaseModel fromModel,BaseModel toModel){
|
wrapperForAddLink(linkModel);
|
VciBaseUtil.alertNotNull(fromModel,"链接类型from端",toModel,"链接类型to端");
|
linkModel.setFoid(fromModel.getOid());
|
linkModel.setFbtmname(fromModel.getBtmname());
|
linkModel.setFnameoid(fromModel.getNameOid());
|
|
linkModel.setToid(toModel.getOid());
|
linkModel.setTbtmname(toModel.getBtmname());
|
linkModel.setTnameoid(toModel.getNameOid());
|
linkModel.setTrevisionoid(toModel.getRevisionOid());
|
}
|
|
/**
|
* 在数据修改的时候为链接类型封装属性
|
* @param linkModel 基础数据对象
|
*/
|
public void wrapperForEditLink(BaseLinkModel linkModel){
|
VciBaseUtil.alertNotNull(linkModel,"要修改的链接类型数据对象");
|
Date currentDate = new Date();
|
linkModel.setTs(currentDate);
|
linkModel.setLastModifier(VciBaseUtil.getCurrentUserId());
|
linkModel.setLastModifytime(currentDate);
|
}
|
|
/**
|
* 判断时间戳是否相同
|
* @param dtoTs 数据传输对象上的ts
|
* @param doTs 数据对象上的ts
|
* @return true表示相同
|
*/
|
public boolean checkTs(Date dtoTs,Date doTs){
|
if(dtoTs!=null && doTs!=null){
|
if(dtoTs.getTime() == doTs.getTime()){
|
return true;
|
}
|
String dtoTsString = VciDateUtil.date2Str(dtoTs,VciDateUtil.DateTimeMillFormat);
|
String doTsString = VciDateUtil.date2Str(doTs,VciDateUtil.DateTimeMillFormat);
|
if(dtoTsString.equalsIgnoreCase(doTsString)){
|
return true;
|
}else{
|
throw new VciBaseException("tsNotEqual");
|
}
|
}
|
return false;
|
}
|
|
/**
|
* 判断密级是否符合要求
|
* @param baseModel 数据对象
|
* @return true 表示符合要求
|
* @throws VciBaseException 不符合要求时会抛出异常
|
*/
|
public boolean checkDataSecret(BaseModel baseModel) throws VciBaseException{
|
VciBaseUtil.alertNotNull(baseModel,"要校验密级的数据对象");
|
//todo 登录还未启用,所以密级无法获取需要修改
|
// if(isCheckSecret(baseModel) && VciBaseUtil.getCurrentUserSecret()>0) {
|
// if (baseModel.getSecretGrade() == null ) {
|
// baseModel.setSecretGrade(DataSecretEnum.NONE.getValue());
|
// }
|
// Integer userSecret = VciBaseUtil.getCurrentUserSecret();
|
// if (!checkUserSecret(baseModel.getSecretGrade())) {
|
// throw new VciBaseException("当前用户的密级低于数据的密级,用户密级为" + UserSecretEnum.getSecretText(userSecret) + ",数据密级为" + DataSecretEnum.getSecretText(baseModel.getSecretGrade()));
|
// }
|
// }
|
return true;
|
}
|
|
/**
|
* 发布当前版本
|
* @param baseModel 要发布的数据对象
|
*/
|
public void saveRelease(BaseModel baseModel){
|
VciBaseUtil.alertNotNull(baseModel,"数据对象");
|
VciBtmType btmType = getBtmTypeAnnotation(baseModel);
|
if(isManageRevision(btmType)) {
|
//必须管理版本才会执行发布
|
VciBaseUtil.alertNotNull( baseModel.getOid(), "数据对象的主键", baseModel.getNameOid(), "对象的主键",baseModel.getRevisionOid(),"版本的主键");
|
ReleasedObjDO releasedObjDO = new ReleasedObjDO();
|
BeanUtil.convert(baseModel,releasedObjDO);
|
if(StringUtils.isBlank(releasedObjDO.getBtmName())){
|
releasedObjDO.setBtmName(btmType.name());
|
}
|
revisionMapper.saveReleased(releasedObjDO);
|
}
|
}
|
|
/**
|
* 数据新增的时候封装属性,可以升版本,可以升版次
|
* @param baseModel 数据对象
|
* @param upRevsion 升版号
|
* @param upVersion 升版次
|
*/
|
private void wrapperForAddOrUpVersion(BaseModel baseModel,boolean upRevsion,boolean upVersion){
|
VciBaseUtil.alertNotNull(baseModel,"数据对象");
|
//封装基本属性
|
setBaseFieldValue(baseModel);
|
//校验必输项和唯一项
|
List<Field> fields = VciBaseUtil.getAllFieldForObj(baseModel.getClass());
|
if(!CollectionUtils.isEmpty(fields)){
|
//获取包含了column注解的属性,因为不包含的默认nullable为true,unique为false
|
List<Field> hasColumnAnnoFields = fields.stream().filter(s->s.isAnnotationPresent(Column.class)).distinct().collect(Collectors.toList());
|
if(!CollectionUtils.isEmpty(hasColumnAnnoFields)){
|
//分离出需要判断是否为空的字段
|
List<Field> notNullFields = filterCheckNullFields(hasColumnAnnoFields);
|
//判断是否有空的属性
|
checkFieldsRequired(notNullFields,baseModel);
|
Map<Field,Boolean> checkUniqueFields = filterCheckUniqueFieldsHasUnCase(hasColumnAnnoFields);
|
if(!CollectionUtils.isEmpty(checkUniqueFields)){
|
checkUniqueFields.forEach((field,unCase) ->{
|
checkUniqueValues(field,unCase,baseModel,new HashMap<>(),false);
|
});
|
}
|
}
|
}
|
//校验密级
|
checkDataSecret(baseModel);
|
//处理生命周期
|
wrapperLifeCycle(baseModel);
|
//如果控制版本,会创建第一个版本
|
if(isManageRevision(baseModel)) {
|
if(!upVersion) {
|
if (StringUtils.isBlank(baseModel.getCopyFromVersion()) && !upRevsion) {
|
//说明是新增
|
wrapperFristRevision(baseModel);
|
} else {
|
//说明是升版号
|
wrapperRevisionModel(baseModel);
|
}
|
}else {
|
wrapperVersionModel(baseModel);
|
}
|
}
|
}
|
|
/**
|
*处理基本属性
|
* @param baseModel 数据对象
|
*/
|
public void setBaseFieldValue(BaseModel baseModel){
|
VciBaseUtil.alertNotNull(baseModel,"数据对象");
|
setBaseFieldValue(baseModel,null,null,null);
|
}
|
|
/**
|
* 处理基本属性
|
* @param currentUserId 当前用户
|
* @param currentDate 当前时间
|
* @param btmName 业务类型名称
|
* @param baseModel 数据对象
|
*/
|
public void setBaseFieldValue(BaseModel baseModel,String currentUserId,Date currentDate,String btmName){
|
if(StringUtils.isBlank(currentUserId)){
|
currentUserId = VciBaseUtil.getCurrentUserId();
|
}
|
if(currentDate == null){
|
currentDate = new Date();
|
}
|
if(StringUtils.isBlank(btmName)){
|
btmName = VciBaseUtil.getBtmTypeNameFromDO(baseModel.getClass());
|
}
|
//处理基本属性
|
if(StringUtils.isBlank(baseModel.getOid())){
|
baseModel.setOid(VciBaseUtil.getPk());
|
}
|
if(StringUtils.isBlank(baseModel.getCreator())) {
|
baseModel.setCreator(currentUserId);
|
}
|
baseModel.setCreateTime(currentDate);
|
baseModel.setTs(currentDate);
|
if(StringUtils.isBlank(baseModel.getLastModifier())) {
|
baseModel.setLastModifier(currentUserId);
|
}
|
baseModel.setLastModifyTime(currentDate);
|
if(StringUtils.isBlank(baseModel.getOwner())) {
|
baseModel.setOwner(baseModel.getCreator());
|
}
|
baseModel.setBtmname(btmName);
|
}
|
|
/**
|
* 编辑的时候处理基本属性
|
* @param baseModel 数据对象
|
* @param currentUserId 当前用户
|
* @param currentDate 当前时间
|
*/
|
public void setBaseFieldValueEdit(BaseModel baseModel,String currentUserId,Date currentDate){
|
if(StringUtils.isBlank(currentUserId)){
|
currentUserId = VciBaseUtil.getCurrentUserId();
|
}
|
if(currentDate == null){
|
currentDate = new Date();
|
}
|
baseModel.setTs(currentDate);
|
baseModel.setLastModifier(currentUserId);
|
baseModel.setLastModifyTime(currentDate);
|
}
|
|
|
|
/**
|
* 批量执行的时候,校验唯一项
|
* @param field 属性
|
* @param unCase 是否不区分大小写
|
* @param baseModel 数据对象
|
* @param unqiueFieldValueMap 存在的数据集合
|
* @param edit 是否为修改
|
*/
|
private void checkUniqueValues(Field field,Boolean unCase,BaseModel baseModel, Map<String/**属性的名称**/,Set<Object>> unqiueFieldValueMap ,boolean edit){
|
field.setAccessible(true);
|
String fieldName = field.getName();
|
Set<Object> fieldValueList ;
|
if(unqiueFieldValueMap.containsKey(fieldName)){
|
fieldValueList = unqiueFieldValueMap.get(fieldName);
|
}else{
|
fieldValueList = new HashSet<>();
|
}
|
Object fieldValue = null;
|
try {
|
fieldValue = field.get(baseModel);
|
} catch (IllegalAccessException e) {
|
if(logger.isDebugEnabled()){
|
logger.debug("获取属性的值出现了错误,{}",fieldName);
|
}
|
}
|
if(fieldValue!=null){
|
if(unCase !=null && unCase){
|
fieldValue = fieldValue.toString().toLowerCase();
|
}
|
if(fieldValueList.contains(fieldValue) || (unCase?checkFieldNotUniqueUnCase(field,baseModel,edit):checkFieldNotUnique(field,baseModel,edit))){
|
throw new VciBaseException("dataRepeat",new String[]{getColumnChineseText(field),fieldValue.toString()});
|
}else{
|
fieldValueList.add(fieldValue);
|
}
|
}
|
unqiueFieldValueMap.put(fieldName,fieldValueList);
|
}
|
|
|
|
|
|
/**
|
* 封装新的版本信息,会自动处理老的版本和最新版本的问题
|
* @param newModel 新版本的数据对象
|
* @throws VciBaseException 参数错误,无注解,服务配置不正确的时候会抛出异常
|
*/
|
public void wrapperRevisionModel(BaseModel newModel) throws VciBaseException{
|
setBtmName(newModel);
|
VciBaseUtil.alertNotNull(newModel.getCopyFromVersion(),"引用老版本的主键");
|
if (revisionMapper != null) {
|
RevisionInfo oldRevision = revisionMapper.selectByOid(newModel.getCopyFromVersion(),VciBaseUtil.getTableName(newModel.getBtmname()));
|
if(oldRevision == null || StringUtils.isBlank(oldRevision.getOid()) ){
|
throw new VciBaseException("老版本在数据库中不存在");
|
}
|
BaseModel oldModel = new BaseModel();
|
BeanUtil.convert(oldRevision,oldModel);
|
wrapperRevisionModel(oldModel,newModel);
|
}else{
|
throw new VciBaseException("没有初始化版本规则的数据操作层,请开发人员检查Maven是否引用");
|
}
|
}
|
|
/**
|
* 封装新的版次信息,会自动处理老的版次和最新版次问题
|
* @param newModel 新版次的数据对象
|
* @throws VciBaseException 参数错误,缺少注解,配置错误都会抛出这个异常
|
*/
|
public void wrapperVersionModel(BaseModel newModel) throws VciBaseException{
|
VciBaseUtil.alertNotNull(newModel,"新版次的数据对象",newModel.getCopyFromVersion(),"引用老版次的主键");
|
if (revisionMapper != null) {
|
RevisionInfo oldRevision = revisionMapper.selectByOid(newModel.getCopyFromVersion(),VciBaseUtil.getTableName(newModel.getBtmname()));
|
if(oldRevision == null || StringUtils.isBlank(oldRevision.getOid()) ){
|
throw new VciBaseException("老版次数据在数据库中不存在");
|
}
|
BaseModel oldModel = new BaseModel();
|
BeanUtil.convert(oldRevision,oldModel);
|
wrapperVersionModel(oldModel,newModel);
|
}else{
|
throw new VciBaseException("没有初始化版本规则的数据操作层,请开发人员检查Maven是否引用");
|
}
|
}
|
|
|
|
/**
|
* 获取数据对象中所有包含了column列的属性
|
* @param baseModel 数据对象
|
* @return 没有时会返回Null
|
*/
|
public List<Field> filterHasColumnAnnoFields(BaseModel baseModel){
|
List<Field> fields = VciBaseUtil.getAllFieldForObj(baseModel.getClass());
|
return filterHasColumnAnnoFields(fields);
|
}
|
|
/**
|
* 过滤包含了column的属性
|
* @param fields 所有的属性
|
* @return 符合条件的属性,不存在的时候会返回null
|
*/
|
public List<Field> filterHasColumnAnnoFields( List<Field> fields){
|
if(!CollectionUtils.isEmpty(fields)) {
|
return fields.stream().filter(s -> s.isAnnotationPresent(Column.class)).distinct().collect(Collectors.toList());
|
}else{
|
return null;
|
}
|
}
|
|
/**
|
* 过滤需要校验是否输入的属性
|
* @param fields 包含有column注解的属性
|
* @return 符合条件的属性,不存在的时候会返回null
|
*/
|
public List<Field> filterCheckNullFields(List<Field> fields){
|
if(!CollectionUtils.isEmpty(fields)){
|
return fields.stream().filter(s -> {
|
Column column = getColumnAnnotation(s);
|
//指定了不能为空,或者需要校验唯一的一定不能为空
|
return ((column != null && column.nullable()) == false) || ((column != null && column.unique()) == true);
|
}).collect(Collectors.toList());
|
}
|
return null;
|
}
|
|
/**
|
* 获取校验唯一项,包含 区分大小写唯一项的属性
|
* @param doClass 数据对象所属的类
|
* @return 属性映射,key是属性对象,value的值为true表示不区分大小写的方式校验唯一项
|
*/
|
public Map<Field/**要校验唯一项的属性**/, Boolean/**是否不区分大小写**/> filterCheckUniqueFieldsHasUnCase(Class<?> doClass){
|
List<Field> hasColumnAnnoFields = filterHasColumnAnnoFields(VciBaseUtil.getAllFieldForObj(doClass));
|
return filterCheckUniqueFieldsHasUnCase(hasColumnAnnoFields);
|
}
|
|
/**
|
* 获取校验唯一项,包含 区分大小写唯一项的属性
|
* @param hasColumnAnnoFields 数据对象所属的类
|
* @return 属性映射,key是属性对象,value的值为true表示不区分大小写的方式校验唯一项
|
*/
|
public Map<Field/**要校验唯一项的属性**/, Boolean/**是否不区分大小写**/> filterCheckUniqueFieldsHasUnCase(List<Field> hasColumnAnnoFields){
|
|
//唯一项的,包含不区分大小写和区分大小写的
|
Map<Field/**要校验唯一项的属性**/, Boolean/**是否不区分大小写**/> checkUniqueFieldsMap = new HashMap<>();
|
List<Field> checkUniqueFields = filterCheckUniqueFields(hasColumnAnnoFields);
|
if(!CollectionUtils.isEmpty(checkUniqueFields)){
|
checkUniqueFields.stream().forEach(s -> {
|
checkUniqueFieldsMap.put(s,false);
|
});
|
}
|
List<Field> checkUniqueUnCaseFields = filterCheckUniqueUnCaseFields(hasColumnAnnoFields);
|
if(!CollectionUtils.isEmpty(checkUniqueUnCaseFields)){
|
checkUniqueUnCaseFields.stream().forEach(s -> {
|
//这个是不区分大小写
|
checkUniqueFieldsMap.put(s,true);
|
});
|
}
|
return checkUniqueFieldsMap;
|
}
|
|
/**
|
* 获取需要校验唯一的属性
|
* @param fields 包含有column注解的属性
|
* @return 符合条件的属性,不存在的时候会返回null
|
*/
|
public List<Field> filterCheckUniqueFields(List<Field> fields){
|
if(!CollectionUtils.isEmpty(fields)){
|
return fields.stream().filter(s -> {
|
Column column = getColumnAnnotation(s);
|
return (column != null && column.unique()) == true;
|
}).collect(Collectors.toList());
|
}
|
return null;
|
}
|
|
/**
|
* 获取需要校验唯一的属性
|
* @param fields 包含有column注解的属性
|
* @return 符合条件的属性,不存在的时候会返回null
|
*/
|
public List<Field> filterCheckUniqueUnCaseFields(List<Field> fields){
|
if(!CollectionUtils.isEmpty(fields)){
|
return fields.stream().filter(s -> {
|
Column column = getColumnAnnotation(s);
|
return (column != null && column.unique() && column.unUniqueCase()) == true;
|
}).collect(Collectors.toList());
|
}
|
return null;
|
}
|
|
/**
|
* 校验属性的值是否唯一
|
* @param uniqueFields 需要校验唯一的属性值
|
* @param baseModel 数据对象
|
* @param editFlag 是否为修改数据,修改的时候需要排除当前数据
|
*/
|
public void checkFieldsUnique(List<Field> uniqueFields, BaseModel baseModel, boolean editFlag) {
|
if(!CollectionUtils.isEmpty(uniqueFields)){
|
List<Field> notUniqueFields = uniqueFields.stream().filter( s -> checkFieldNotUnique(s,baseModel,editFlag)).collect(Collectors.toList());
|
if(!CollectionUtils.isEmpty(notUniqueFields)){
|
//找对应的中文名称
|
List<String> notUniqueFieldChineseNames = new ArrayList<>();
|
notUniqueFields.stream().forEach( s -> {
|
//先从注释中上获取,但是怕的是之前没有注释,所以可能得从注解上获取
|
notUniqueFieldChineseNames.add(getColumnChineseText(s));
|
});
|
//按理说这个错误信息不应该出现的,所以不做多语
|
throw new VciBaseException("属性[" + notUniqueFieldChineseNames.stream().collect(Collectors.joining(",")) + "]对应的数据在系统中已经存在",notUniqueFieldChineseNames.toArray());
|
}
|
}
|
}
|
|
/**
|
* 校验属性的值是否唯一,不区分属性值的大小写
|
* @param uniqueFields 需要校验唯一的属性值
|
* @param baseModel 数据对象
|
* @param editFlag 是否为修改数据,修改的时候需要排除当前数据
|
*/
|
public void checkFieldsUnUniqueCase(List<Field> uniqueFields, BaseModel baseModel, boolean editFlag){
|
if(!CollectionUtils.isEmpty(uniqueFields)){
|
List<Field> notUniqueFields = uniqueFields.stream().filter( s -> checkFieldNotUniqueUnCase(s,baseModel,editFlag)).collect(Collectors.toList());
|
if(!CollectionUtils.isEmpty(notUniqueFields)){
|
//找对应的中文名称
|
List<String> notUniqueFieldChineseNames = new ArrayList<>();
|
notUniqueFields.stream().forEach( s -> {
|
//先从注释中上获取,但是怕的是之前没有注释,所以可能得从注解上获取
|
notUniqueFieldChineseNames.add(getColumnChineseText(s));
|
});
|
//按理说这个错误信息不应该出现的,所以不做多语
|
throw new VciBaseException("属性[" + notUniqueFieldChineseNames.stream().collect(Collectors.joining(",")) + "]对应的数据在系统中已经存在",notUniqueFieldChineseNames.toArray());
|
}
|
}
|
}
|
|
/**
|
* 检查属性是否唯一
|
* @param field 需要校验的属性对象
|
* @param baseModel 数据对象
|
* @param editFlag 是否为修改数据,修改的时候需要排除当前数据
|
* @return true表示不唯一,false唯一
|
*/
|
public boolean checkFieldNotUnique(Field field,BaseModel baseModel,boolean editFlag){
|
return checkFieldNotUnique(field,baseModel,editFlag,false);
|
}
|
|
/**
|
* 检查属性是否唯一,并且不区分大小写
|
* @param field 需要校验的属性对象
|
* @param baseModel 数据对象
|
* @param editFlag 是否为修改数据,修改的时候需要排除当前数据
|
* @return true表示不唯一,false唯一
|
*/
|
public boolean checkFieldNotUniqueUnCase(Field field,BaseModel baseModel,boolean editFlag){
|
return checkFieldNotUnique(field,baseModel,editFlag,true);
|
}
|
|
/**
|
* 检查属性是否唯一,可以设置不区分大小写
|
* @param field 需要校验的属性对象
|
* @param baseModel 数据对象
|
* @param editFlag 是否为修改数据,修改的时候需要排除当前数据
|
* @param unCase 不区分大小写
|
* @return true表示不唯一,false唯一
|
*/
|
private boolean checkFieldNotUnique(Field field,BaseModel baseModel,boolean editFlag,boolean unCase){
|
String btmType = VciBaseUtil.getBtmTypeNameFromDO(baseModel.getClass());
|
String className = baseModel.getClass().getName();
|
String columnName =VciBaseUtil.getCboAttrNameFromField(field,baseModel.getClass());
|
String tableName = VciBaseUtil.getTableName(btmType);
|
Object columnValue = null;
|
String oid = "";
|
if(editFlag){
|
oid = baseModel.getOid();
|
}
|
field.setAccessible(true);
|
try {
|
columnValue = field.get(baseModel);
|
} catch (IllegalAccessException e) {
|
String msg = "判断某个对象的属性是否重复时出现了错误";
|
if(logger.isErrorEnabled()) {
|
logger.error(msg + ",{}.{}", className, field.getName(), e);
|
}
|
throw new VciBaseException(msg + "{0},{1}",new String[]{className,field.getName()},e);
|
}
|
if(unCase && columnValue instanceof String){
|
//只有字符串才有大小写,日期和数字这些不支持
|
columnName = "lower(" + columnName + ")";
|
columnValue = columnValue.toString().toLowerCase();
|
}
|
int count;
|
if(editFlag){
|
count= revisionMapper.countByPropertiesNotIncludeSelf(columnName, columnValue, tableName, oid);
|
}else{
|
count = revisionMapper.countByProperties(columnName,columnValue,tableName);
|
}
|
if(count>0){
|
return true;
|
}
|
return false;
|
}
|
|
/**
|
* 判断数据是否为空
|
* @param notNullFields 需要判断的属性
|
* @param baseModel 数据对象
|
*/
|
public void checkFieldsRequired(List<Field> notNullFields, BaseModel baseModel) {
|
if(!CollectionUtils.isEmpty(notNullFields)){
|
String className = baseModel.getClass().getName();
|
List<Field> nullValueFields = notNullFields.stream().filter( s -> checkFieldValueNull(s,baseModel)).collect(Collectors.toList());
|
if(!CollectionUtils.isEmpty(nullValueFields)){
|
//找对应的中文名称
|
List<String> nullFieldChineseNames = new ArrayList<>();
|
nullValueFields.stream().forEach( s -> {
|
//先从注释中上获取,但是怕的是之前没有注释,所以可能得从注解上获取
|
nullFieldChineseNames.add(getColumnChineseText(s));
|
});
|
//按理说这个错误信息不应该出现的,所以不做多语
|
throw new VciBaseException("属性[" + nullFieldChineseNames.stream().collect(Collectors.joining(",")) + "]不能为空",nullFieldChineseNames.toArray());
|
}
|
}
|
}
|
|
/**
|
* 校验属性为空
|
* @param field 属性对象
|
* @param baseModel 数据对象
|
* @return true表示为空,false表示不为空
|
*/
|
public boolean checkFieldValueNull(Field field,BaseModel baseModel){
|
String className = baseModel.getClass().getName();
|
field.setAccessible(true);
|
try {
|
Object value = field.get(baseModel);
|
if(value == null || (value instanceof String) && StringUtils.isBlank((String)value)){
|
return true;
|
}
|
} catch (IllegalAccessException e) {
|
String msg = "判断某个对象的属性是否为空时出现了错误";
|
if(logger.isErrorEnabled()) {
|
logger.error(msg + ",{}.{}", className, field.getName(), e);
|
}
|
throw new VciBaseException(msg + "{0},{1}",new String[]{className,field.getName()},e);
|
}
|
return false;
|
}
|
|
/**
|
* 获取
|
* @param field 属性对象
|
* @return 中文名称,优先取注释,否则取注解,最后返回属性的英文名称
|
*/
|
public String getColumnChineseText(Field field){
|
String className = field.getDeclaringClass().getName();
|
if(modelColumnAnnotationMap.containsKey(className) && modelColumnAnnotationMap.get(className.toLowerCase()).containsKey(field.getName().toLowerCase())){
|
return modelColumnAnnotationMap.get(className.toLowerCase()).get(field.getName().toLowerCase());
|
}else{
|
Column column = getColumnAnnotation(field);
|
if(column!=null && StringUtils.isNotBlank(column.columnDefinition())){
|
return column.columnDefinition();
|
}else{
|
//看看columnDefinition注解
|
if(field.isAnnotationPresent(VciColumnDefinition.class)){
|
VciColumnDefinition columnDefinition = field.getDeclaredAnnotation(VciColumnDefinition.class);
|
if(columnDefinition == null){
|
columnDefinition = field.getAnnotation(VciColumnDefinition.class);
|
}
|
if(columnDefinition!=null) {
|
return columnDefinition.value();
|
}
|
}
|
}
|
return field.getName();
|
}
|
}
|
|
/**
|
* 获取数据对象上的列注解
|
* @param field 字段的属性对象
|
* @return 没有注解的时候返回空,否则返回对应的注解
|
*/
|
public Column getColumnAnnotation(Field field){
|
if(field.isAnnotationPresent(Column.class)) {
|
Column column = field.getDeclaredAnnotation(Column.class);
|
if (column == null) {
|
column = field.getAnnotation(Column.class);
|
}
|
return column;
|
}
|
return null;
|
}
|
|
|
|
/**
|
* 校验是否控制密级
|
* @param doObject 数据对象
|
* @return true需要校验密级
|
*/
|
public boolean isCheckSecret(BaseModel doObject){
|
VciBtmType btmType = getBtmTypeAnnotation(doObject);
|
return isCheckSecret(btmType);
|
}
|
|
/**
|
* 校验是否控制密级
|
* @param btmType 业务类型的注解
|
* @return true需要校验密级
|
*/
|
public boolean isCheckSecret(VciBtmType btmType){
|
if(btmType !=null && btmType.secretAble()){
|
return true;
|
}
|
return false;
|
}
|
|
|
/**
|
* 封装新的版本信息,会自动处理老的版本和最新版本的问题
|
* @param oldModel 老版本的数据对象
|
* @param newModel 新版本的数据对象
|
* @throws VciBaseException 参数错误,缺少注解,配置错误都会抛出这个异常
|
*/
|
public void wrapperRevisionModel(BaseModel oldModel, BaseModel newModel) throws VciBaseException {
|
VciBaseUtil.alertNotNull(oldModel,"老版本的数据对象",newModel,"新版本的数据对象");
|
VciBtmType btmType = getBtmTypeAnnotation(newModel);
|
if(btmType == null){
|
throw new VciBaseException("没有VciBtmType注解,无法判断是否控制版本");
|
}else {
|
if ( isManageRevision(btmType)) {
|
//升版的前提是有版本规则,并且如果是手动输入的时候,必须从前端输入值。
|
//1. 主键不能相同
|
if (StringUtils.isBlank(newModel.getOid()) || newModel.getOid().equalsIgnoreCase(oldModel.getOid())) {
|
newModel.setOid(VciBaseUtil.getPk());
|
}
|
//2.nameOid要相同
|
newModel.setNameOid(oldModel.getNameOid());
|
//2.1 revisionOid不相同
|
newModel.setRevisionOid(VciBaseUtil.getPk());
|
//查找最后一个版本的版本值
|
RevisionInfo lastRevision = null;
|
if (revisionMapper != null) {
|
lastRevision = revisionMapper.selectLastRevision(newModel.getNameOid(),VciBaseUtil.getTableName(btmType.name()));
|
} else {
|
//没有这个,那就直接用oldModel去获取版本号
|
lastRevision = new RevisionInfo();
|
BeanUtil.convert(oldModel, lastRevision);
|
}
|
newModel.setRevisionRule(lastRevision.getRevisionRule());
|
newModel.setVersionRule(lastRevision.getVersionRule());
|
//3.版本号
|
if(StringUtils.isBlank(newModel.getRevisionValue()) && !isInputRevision(newModel) && StringUtils.isBlank(lastRevision.getRevisionRule())){
|
//不处理
|
}else {
|
if (StringUtils.isBlank(newModel.getRevisionValue())) {
|
wrapperRevisionValue(newModel, btmType, lastRevision);
|
}
|
}
|
|
//如果有版次,那这个就是新版本的第一个版次
|
if (isManageVersion(btmType)) {
|
wrapperFristVersion(newModel);
|
}else{
|
//可能没有处理版次,但是必须要添加上
|
newModel.setFirstV("1");
|
newModel.setLastV("1");
|
}
|
//4.新的版本顺序
|
newModel.setRevisionSeq(lastRevision.getRevisionSeq() + 1);
|
newModel.setLastR("1");
|
newModel.setFirstR("0");
|
|
//5.修改老的版本的isLastR
|
saveOldModel(oldModel);
|
//而且可能oldModel不是最后的那个版本
|
}
|
//支持可以使用版本规则生成,也同时可以手动输入,所以当手动输入而值又没有的时候需要新生成
|
}
|
}
|
|
/**
|
* 封装新的版次信息,会自动处理老的版次和最新版次问题
|
* @param oldModel 老版次的数据对象
|
* @param newModel 新版次的数据对象
|
* @throws VciBaseException 参数错误,缺少注解,配置错误都会抛出这个异常
|
*/
|
public void wrapperVersionModel(BaseModel oldModel, BaseModel newModel) throws VciBaseException {
|
VciBaseUtil.alertNotNull(oldModel,"老版次的数据对象",newModel,"新版次的数据对象");
|
VciBtmType btmType = getBtmTypeAnnotation(newModel);
|
if(btmType == null){
|
throw new VciBaseException("没有VciBtmType注解,无法判断是否控制版次");
|
}else {
|
if (isManageVersion(btmType)) {
|
//才处理新的版次
|
//主键不能相同,nameoid和revisionoid必须相同
|
if (StringUtils.isBlank(newModel.getOid()) || newModel.getOid().equalsIgnoreCase(oldModel.getOid())) {
|
newModel.setOid(VciBaseUtil.getPk());
|
}
|
if(StringUtils.isBlank(newModel.getNameOid()) || !newModel.getNameOid().equalsIgnoreCase(oldModel.getNameOid())){
|
newModel.setNameOid(oldModel.getNameOid());
|
}
|
if(StringUtils.isBlank(newModel.getRevisionOid())
|
|| !newModel.getRevisionOid().equalsIgnoreCase(oldModel.getRevisionOid())){
|
newModel.setRevisionOid(oldModel.getRevisionOid());
|
}
|
//查询这个相同的版本下的最新版次
|
RevisionInfo lastRevision = null;
|
if (revisionMapper != null) {
|
lastRevision = revisionMapper.selectLastVersion(newModel.getNameOid(),newModel.getRevisionOid(),VciBaseUtil.getTableName(btmType.name()));
|
} else {
|
//没有这个,那就直接用oldModel去获取版本号
|
lastRevision = new RevisionInfo();
|
BeanUtil.convert(oldModel, lastRevision);
|
}
|
//版次号,就数字和字母两种
|
if(oldModel.getVersionValue().matches(RegExpConstant.LETTER)){
|
//说明是字母的
|
newModel.setVersionValue(String.valueOf((char)(oldModel.getVersionValue().toCharArray()[0] + 1)));
|
}else{
|
newModel.setVersionValue(String.valueOf(Integer.valueOf(oldModel.getVersionValue()) + 1));
|
}
|
newModel.setVersionSeq(lastRevision.getVersionSeq() + 1);
|
newModel.setVersionRule(oldModel.getVersionRule());
|
newModel.setLastV("1");
|
newModel.setFirstV("0");
|
//处理老版次
|
saveOldModelVersion(oldModel);
|
}
|
}
|
}
|
|
/**
|
* 处理业务类型的名称
|
* @param baseModel 数据对象
|
*/
|
private void setBtmName(BaseModel baseModel){
|
VciBaseUtil.alertNotNull(baseModel,"数据对象");
|
if(StringUtils.isBlank(baseModel.getBtmname())){
|
VciBtmType btmType = getBtmTypeAnnotation(baseModel);
|
if(btmType == null){
|
throw new VciBaseException("没有VciBtmType注解,无法判断业务类型");
|
}
|
baseModel.setBtmname(btmType.name());
|
}
|
}
|
|
/**
|
* 保存旧的版本,会自动把以前最新版本的哪条数据修改,同时会把老的这条版本修改
|
* @param oldModel 老版本的数据对象
|
*/
|
public void saveOldModel(BaseModel oldModel){
|
setBtmName(oldModel);
|
if (revisionMapper != null) {
|
revisionMapper.resetLastRevision(oldModel.getNameOid(),VciBaseUtil.getTableName(oldModel.getBtmname()));
|
revisionMapper.resetOldRevision(oldModel.getOid(),VciBaseUtil.getTableName(oldModel.getBtmname()));
|
}else{
|
throw new VciBaseException("没有初始化版本规则的数据操作层,请开发人员检查maven是否引用");
|
}
|
}
|
|
/**
|
* 保存旧的版次,会自动把以前最新版次的哪条数据修改,同时会把老的这条版次修改
|
* @param oldModel 老版次的数据对象
|
*/
|
public void saveOldModelVersion(BaseModel oldModel){
|
setBtmName(oldModel);
|
if (revisionMapper != null) {
|
revisionMapper.resetLastVersion(oldModel.getNameOid(),oldModel.getRevisionOid(),VciBaseUtil.getTableName(oldModel.getBtmname()));
|
revisionMapper.resetOldVersion(oldModel.getOid(),VciBaseUtil.getTableName(oldModel.getBtmname()));
|
}else{
|
throw new VciBaseException("没有初始化版本规则的数据操作层,请开发人员检查maven是否引用");
|
}
|
}
|
|
/**
|
* 封装版本的信息,支持第一个版本的第一个版次,和升版的情况
|
* @param newModel 新版本的数据,请先行设置版本规则的值在这个对象中
|
* @param btmType 对象的注解
|
* @param lastRevision 当前最新版本最新版次的对象,是第一个版本的第一个版本时传递null
|
*/
|
public void wrapperRevisionValue(BaseModel newModel,VciBtmType btmType,RevisionInfo lastRevision){
|
//没有版本号的时候必须使用编码规则来生成新的版本号
|
if (RevisionConstant.CHARACTER.equalsIgnoreCase(newModel.getRevisionRule())) {
|
//使用字母这个默认的字符,这个没有前缀,没有后缀,步长为1,没有跳跃字符
|
newRevisionForLetter(newModel, lastRevision, btmType != null ? btmType.revisionRulePrefix() : "", btmType != null ? btmType.revisionRuleSubfix() : "");
|
} else if (RevisionConstant.NUMBER.equalsIgnoreCase(newModel.getRevisionRule())) {
|
newRevisionForNumber(newModel,lastRevision,btmType != null ? btmType.revisionRulePrefix() : "", btmType != null ? btmType.revisionRuleSubfix() : "");
|
} else {
|
if (revisionRuleProvider != null) {
|
try {
|
BaseResult nextRevisionResult = revisionRuleProvider.getNextRevisionValue(newModel.getRevisionRule(), lastRevision==null?"":lastRevision.getRevisionValue());
|
if (nextRevisionResult.isSuccess()) {
|
newModel.setRevisionValue((String) nextRevisionResult.getObj());
|
} else {
|
throw new VciBaseException(nextRevisionResult.getMsg(), nextRevisionResult.getMsgObjs());
|
}
|
} catch (Throwable e) {
|
throw new VciBaseException("获取下一个版本号出现了错误,{0}", new String[]{newModel.getRevisionRule()}, e);
|
}
|
} else {
|
throw new VciBaseException("没有初始化版本规则的调用器,请开发人员检查feign");
|
}
|
}
|
}
|
|
/**
|
* 根据数字的规则封装新的版本
|
* @param baseModel 基础数据对象
|
* @param lastRevision 最后的版本对象
|
* @param prefix 前缀
|
* @param subfix 后缀
|
*/
|
private void newRevisionForNumber(BaseModel baseModel, RevisionInfo lastRevision,String prefix,String subfix) {
|
if(prefix==null){
|
prefix = "";
|
}
|
if(subfix == null){
|
subfix = "";
|
}
|
if(lastRevision == null) {
|
//说明是第一个版本
|
baseModel.setRevisionValue(prefix + "1" + subfix);
|
}else {
|
String ruleValue = replacePrefixAndSubfix(lastRevision, prefix, subfix);
|
if (ruleValue.matches(RegExpConstant.NUMBER)) {
|
//数字可以不停地加
|
ruleValue = String.valueOf(Integer.valueOf(ruleValue) + 1);
|
baseModel.setRevisionValue(prefix + ruleValue + subfix);
|
} else {
|
//最后一个版本可能是手动输入的,那就直接找一下最后一排数字,
|
if (ruleValue.matches(RegExpConstant.HAS_NUMBER)) {
|
String onlyNumber = getNumbers(ruleValue);
|
String nextNumber = String.valueOf(Integer.valueOf(onlyNumber) + 1);
|
if (ruleValue.startsWith(onlyNumber)) {
|
ruleValue = ruleValue.substring(onlyNumber.length());
|
baseModel.setRevisionValue(prefix + onlyNumber + ruleValue + subfix);
|
} else if (ruleValue.endsWith(onlyNumber)) {
|
ruleValue = ruleValue.substring(0, ruleValue.length() - onlyNumber.length() - 1);
|
baseModel.setRevisionValue(prefix + ruleValue + nextNumber + subfix);
|
} else {
|
baseModel.setRevisionValue(prefix + ruleValue.substring(0, ruleValue.lastIndexOf(onlyNumber)) + nextNumber + ruleValue.substring(ruleValue.lastIndexOf(onlyNumber) + 1) + subfix);
|
}
|
} else {
|
//一个数字都没有
|
baseModel.setRevisionValue(prefix + ruleValue + "1" + subfix);
|
}
|
}
|
}
|
}
|
|
/**
|
* 获取字符串中的数字部分
|
* @param content 字符串内容
|
* @return 数字的部分,最后的那部分
|
*/
|
private String getNumbers(String content) {
|
Pattern pattern = Pattern.compile("\\d+");
|
Matcher matcher = pattern.matcher(content);
|
while (matcher.find()) {
|
return matcher.group(matcher.groupCount()-1);
|
}
|
return "";
|
}
|
|
/**
|
* 替换前缀和后缀
|
* @param lastRevision 最后版本的对象
|
* @param prefix 前缀
|
* @param subfix 后缀
|
* @return 去除前缀和后缀的版本规则
|
*/
|
private String replacePrefixAndSubfix(RevisionInfo lastRevision,String prefix,String subfix){
|
String ruleValue = lastRevision.getRevisionValue();
|
if(prefix==null){
|
prefix = "";
|
}
|
if(subfix == null){
|
subfix = "";
|
}
|
if(StringUtils.isNotBlank(prefix) && ruleValue.startsWith(prefix)){
|
ruleValue = ruleValue.substring(prefix.length());
|
}
|
if(StringUtils.isNotBlank(subfix) && ruleValue.endsWith(subfix)){
|
ruleValue = ruleValue.substring(0,ruleValue.length()-subfix.length()-1);
|
}
|
return ruleValue;
|
}
|
|
/**
|
* 根据字母的规则封装新的版本
|
* @param baseModel 基础数据对象
|
* @param lastRevision 最后的版本对象
|
* @param prefix 前缀
|
* @param subfix 后缀
|
*/
|
private void newRevisionForLetter(BaseModel baseModel,RevisionInfo lastRevision,String prefix,String subfix){
|
if(prefix==null){
|
prefix = "";
|
}
|
if(subfix == null){
|
subfix = "";
|
}
|
if(lastRevision == null){
|
//说明是第一个版本
|
baseModel.setRevisionValue(prefix + "A" + subfix);
|
}else {
|
String ruleValue = replacePrefixAndSubfix(lastRevision, prefix, subfix);
|
if (ruleValue.matches(RegExpConstant.LETTER)) {
|
//从A到ZZ的形式
|
String lastLetter = ruleValue.substring(ruleValue.length() - 1);
|
if (lastLetter.equalsIgnoreCase("Z")) {
|
if (lastRevision.getRevisionValue().length() == 1) {
|
baseModel.setRevisionValue(prefix + "AA" + subfix);
|
} else {
|
lastLetter = ruleValue.substring(ruleValue.length() - 2, ruleValue.length() - 1);
|
lastLetter = String.valueOf((char) (lastLetter.toCharArray()[0] + 1));
|
baseModel.setRevisionValue(prefix + ruleValue.substring(0, ruleValue.length() - 2) + lastLetter + subfix);
|
}
|
} else {
|
lastLetter = String.valueOf((char) (lastLetter.toCharArray()[0] + 1));
|
baseModel.setRevisionValue(prefix + ruleValue.substring(0, ruleValue.length() - 1) + lastLetter + subfix);
|
}
|
} else {
|
//最后一个版本可能是手动输入的,如果我们之间存储A的话,可能会造成重复,最后一位是字母就在该字母上加1,最后一位不是字母,就原值上加A
|
String lastLetter = ruleValue.substring(ruleValue.length() - 1);
|
if (lastLetter.matches(RegExpConstant.LETTER)) {
|
lastLetter = String.valueOf((char) (lastLetter.toCharArray()[0] + 1));
|
baseModel.setRevisionValue(prefix + ruleValue.substring(0, ruleValue.length() - 1) + lastLetter + subfix);
|
} else {
|
baseModel.setRevisionValue(prefix + ruleValue + "A" + subfix);
|
}
|
}
|
}
|
}
|
|
/**
|
* 封装某个版本的第一个版次
|
* @param baseModel 数据对象
|
*/
|
public void wrapperFristVersion(BaseModel baseModel){
|
VciBaseUtil.alertNotNull(baseModel,"数据对象");
|
VciBtmType btmType = getBtmTypeAnnotation(baseModel);
|
if(isManageVersion(btmType)) {
|
//只支持从0,1,或者字母A开始
|
if (StringUtils.isBlank(baseModel.getVersionRule())) {
|
baseModel.setVersionRule(btmType.versionRule().getValue());
|
}
|
if (btmType.versionRule().equals(VciBtmType.VciBtmTypeVersionRule.INTSTART0)) {
|
baseModel.setVersionValue("0");
|
} else if (btmType.versionRule().equals(VciBtmType.VciBtmTypeVersionRule.INTSTART1)) {
|
baseModel.setVersionValue("1");
|
} else {
|
baseModel.setVersionValue("A");
|
}
|
}
|
baseModel.setVersionSeq(1);
|
baseModel.setFirstV("1");
|
baseModel.setLastV("1");
|
}
|
|
/**
|
* 封装第一个版本的第一个版次
|
* @param baseModel 新增的数据对象(第一个版本的第一个版次
|
*/
|
public void wrapperFristRevision(BaseModel baseModel){
|
VciBaseUtil.alertNotNull(baseModel,"数据对象");
|
//需要先判断是否控制版本
|
VciBtmType btmType = getBtmTypeAnnotation(baseModel);
|
if(isManageRevision(btmType)) {
|
if (StringUtils.isBlank(baseModel.getOid())) {
|
baseModel.setOid(VciBaseUtil.getPk());
|
}
|
//第一个版本的第一个版次
|
if (StringUtils.isBlank(baseModel.getNameOid())) {
|
baseModel.setNameOid(VciBaseUtil.getPk());
|
}
|
if (StringUtils.isBlank(baseModel.getRevisionOid())) {
|
baseModel.setRevisionOid(VciBaseUtil.getPk());
|
}
|
|
//第一个版本
|
if (btmType != null) {
|
baseModel.setRevisionRule(btmType.revisionRule());
|
baseModel.setVersionValue(btmType.versionRule().getValue());
|
} else {
|
throw new VciBaseException("没有VciBtmType注解,{0}");
|
}
|
//根据版本规则生成版本号
|
//3.版本号
|
//版本号为空,只能是手动后输入的时候,应该是错误
|
//其他情况下版本号为空都设置版本号
|
if (StringUtils.isBlank(baseModel.getRevisionValue() )&& isInputRevision(baseModel) && StringUtils.isBlank(baseModel.getRevisionRule())){
|
//不处理
|
}else {
|
if (StringUtils.isBlank(baseModel.getRevisionValue())) {
|
wrapperRevisionValue(baseModel, btmType, null);
|
}
|
}
|
//如果有版次,那这个就是新版本的第一个版次
|
if (StringUtils.isNotBlank(baseModel.getVersionRule()) && StringUtils.isBlank(baseModel.getVersionValue())) {
|
wrapperFristVersion(baseModel);
|
} else {
|
baseModel.setFirstV("1");
|
baseModel.setLastV("1");
|
}
|
//4.版本顺序
|
baseModel.setRevisionSeq(1);
|
baseModel.setFirstR("1");
|
baseModel.setLastR("1");
|
}
|
}
|
|
/**
|
* 封装生命周期
|
* @param baseModel 数据对象
|
*/
|
public void wrapperLifeCycle(BaseModel baseModel){
|
VciBaseUtil.alertNotNull(baseModel,"数据对象");
|
VciBtmType btmType = getBtmTypeAnnotation(baseModel);
|
if(StringUtils.isBlank(baseModel.getLcStatus()) &&isManageLifeCycle(btmType) ){
|
//开始的时候获取生命周期的初始状态
|
if(StringUtils.isNotBlank(btmType.startStatus())){
|
baseModel.setLcStatus(btmType.startStatus());
|
}else {
|
if (lifeCycleProvider != null) {
|
try {
|
BaseResult lifeCycleResult = lifeCycleProvider.getStartStatus(btmType.lifeCycle());
|
if (lifeCycleResult.isSuccess()) {
|
baseModel.setLcStatus((String) lifeCycleResult.getObj());
|
} else {
|
throw new VciBaseException(lifeCycleResult.getMsg(), lifeCycleResult.getMsgObjs());
|
}
|
} catch (Throwable e) {
|
throw new VciBaseException("调用【生命周期】服务获取初始状态时出错,{0}", new String[]{btmType.lifeCycle()}, e);
|
}
|
} else {
|
throw new VciBaseException("没有初始化生命周期的调用器,请开发人员检查feign");
|
}
|
}
|
}
|
}
|
|
|
|
/**
|
* 是否管理生命周期
|
* @param baseModel 数据对象
|
* @return true表示管理
|
*/
|
public boolean isManageLifeCycle(BaseModel baseModel){
|
VciBtmType btmType = getBtmTypeAnnotation(baseModel);
|
return isManageLifeCycle(btmType);
|
}
|
|
/**
|
* 是否管理生命周期
|
* @param btmType 业务类型注解
|
* @return true表示管理
|
*/
|
public boolean isManageLifeCycle(VciBtmType btmType){
|
if(btmType !=null && (StringUtils.isNotBlank(btmType.lifeCycle()) && !"defaultLC".equalsIgnoreCase(btmType.lifeCycle()))){
|
return true;
|
}else{
|
return false;
|
}
|
}
|
|
/**
|
* 是否管理版本
|
* @param baseModel 数据对象
|
* @return true 表示管理版本
|
*/
|
public boolean isManageRevision(BaseModel baseModel){
|
VciBtmType btmType = getBtmTypeAnnotation(baseModel);
|
return isManageRevision(btmType);
|
}
|
|
/**
|
* 是否管理版本
|
* @param btmType 业务类型的注解
|
* @return true 表示管理版本
|
*/
|
public boolean isManageRevision(VciBtmType btmType){
|
if(btmType !=null && (btmType.revisionRuleInput() || StringUtils.isNotBlank(btmType.revisionRule()))){
|
return true;
|
}
|
return false;
|
}
|
|
/**
|
* 是否管理版次,必须管理版本才可以管理版次
|
* @param baseModel 数据对象
|
* @return true 表示管理版本
|
*/
|
public boolean isManageVersion(BaseModel baseModel){
|
VciBtmType btmType = getBtmTypeAnnotation(baseModel);
|
return isManageVersion(btmType);
|
}
|
|
/**
|
* 是否管理版次,必须管理版本才可以管理版次
|
* @param btmType 业务类型的注解
|
* @return true 表示管理版本
|
*/
|
public boolean isManageVersion(VciBtmType btmType){
|
if(isManageRevision(btmType) && !btmType.versionRule().equals(VciBtmType.VciBtmTypeVersionRule.NONE)){
|
return true;
|
}
|
return false;
|
}
|
|
|
/**
|
* 是否可以手动输入版本号
|
* @param baseModel 基本数据对象
|
* @return true允许手动输入版本号
|
*/
|
public boolean isInputRevision(BaseModel baseModel) {
|
VciBtmType btmType = getBtmTypeAnnotation(baseModel);
|
return isInputRevision(btmType);
|
}
|
|
/**
|
* 是否可以手动输入版本号
|
* @param btmType 业务类型的注解
|
* @return true允许手动输入版本号
|
*/
|
public boolean isInputRevision(VciBtmType btmType) {
|
if(btmType !=null && btmType.revisionRuleInput()){
|
return true;
|
}
|
return false;
|
}
|
|
/**
|
* 获取数据对象上的注解
|
* @param baseModel 数据对象
|
* @return 不存在注解的时候会返回null
|
*/
|
public VciBtmType getBtmTypeAnnotation(BaseModel baseModel){
|
VciBaseUtil.alertNotNull(baseModel,"数据对象");
|
return getBtmTypeAnnotation(baseModel.getClass());
|
}
|
|
/**
|
* 获取DO对象上的注解
|
* @param doClass do对象的类
|
* @return 不存在注解的时候会返回null
|
*/
|
public VciBtmType getBtmTypeAnnotation(Class<?> doClass){
|
VciBaseUtil.alertNotNull(doClass,"要校验业务类型的类");
|
if(modelAnnotationMap.containsKey(doClass.getName())){
|
return modelAnnotationMap.get(doClass.getName());
|
}
|
if(doClass.isAnnotationPresent(VciBtmType.class)){
|
VciBtmType btmType = (VciBtmType)doClass.getAnnotation(VciBtmType.class);
|
if(btmType == null){
|
btmType = doClass.getDeclaredAnnotation(VciBtmType.class);
|
}
|
modelAnnotationMap.put(doClass.getName(),btmType);
|
return btmType;
|
}
|
return null;
|
}
|
|
/**
|
* 封装树形数据查询器.这个方法被废弃,改为 VciQueryWrapperForDO里的 parentQueryChild
|
* @param treeQueryObject 树形查询对象
|
* @param doClass 实体的类
|
* @param parentFieldName 上级属性的字段
|
* @return 查询封装器
|
*/
|
@Deprecated
|
public VciQueryWrapperForDO wrapperForTree(TreeQueryObject treeQueryObject,Class<?> doClass,String parentFieldName){
|
if(doClass == null){
|
throw new VciBaseException("数据对象所属的类不能为空,不能封装树形查询器");
|
}
|
if (treeQueryObject == null){
|
treeQueryObject = new TreeQueryObject();
|
}
|
VciQueryWrapperOption queryWrapperOption = new VciQueryWrapperOption();
|
if(treeQueryObject.isQueryAllRev()){
|
queryWrapperOption.setThisObjectQueryLastRevision(false);
|
queryWrapperOption.setThisObjectQueryRelease(false);
|
}
|
VciQueryWrapperForDO queryWrapper = new VciQueryWrapperForDO(treeQueryObject.getConditionMap(),doClass,new PageHelper(-1),true,queryWrapperOption);
|
if(StringUtils.isBlank(parentFieldName)){
|
return queryWrapper;
|
}
|
if(StringUtils.isNotBlank(treeQueryObject.getParentOid()) ){
|
//说明传递了上级的
|
if(treeQueryObject.isQueryAllLevel()){
|
//全部的层级都要查询,我们使用start with先查询出结果后,再匹配查询条件
|
queryWrapper.in(queryWrapper.getOidFieldName(), "select " + queryWrapper.getOidFieldName() + " from " + queryWrapper.getTableName()
|
+ " start with " + parentFieldName + " = '" + treeQueryObject.getParentOid().trim()
|
+ "' connect by prior " + queryWrapper.getOidFieldName() + " = " + parentFieldName );
|
}else {
|
queryWrapper.eq(parentFieldName, treeQueryObject.getParentOid());
|
}
|
}else{
|
if(treeQueryObject.isQueryAllLevel()){
|
//全部的层级都要查询,我们使用start with先查询出结果后,再匹配查询条件
|
queryWrapper.in(queryWrapper.getOidFieldName(), "select " + queryWrapper.getOidFieldName() + " from " + queryWrapper.getTableName() + " start with " + parentFieldName
|
+ " is null connect by prior " + queryWrapper.getOidFieldName() + " = " + parentFieldName );
|
}else{
|
queryWrapper.isNull(parentFieldName);
|
}
|
}
|
return queryWrapper;
|
}
|
|
/**
|
* 将数据对象转换为树形
|
* @param doList 数据对象
|
* @param wrapperOptions 封装的信息
|
* @return 树列表
|
*/
|
public <T,R> List<Tree> doList2Trees(List<T> doList, TreeWrapperOptions wrapperOptions, Function<T,R> f){
|
if(CollectionUtils.isEmpty(doList)){
|
return new ArrayList<>();
|
}
|
List<Tree> allTree = new ArrayList<Tree>();
|
List<Tree> children = new ArrayList<Tree>();
|
for (T doObject: doList) {
|
Tree tree =new Tree();
|
List<String> oidFieldNames = VciBaseUtil.str2List(wrapperOptions.getOidFieldName());
|
List<String> oidValues = new LinkedList<>();
|
oidFieldNames.stream().forEach( s->{
|
oidValues.add(VciBaseUtil.getStringValueFromObject(VciBaseUtil.getValueFromField(s,doObject)));
|
});
|
tree.setOid(oidValues.stream().collect(Collectors.joining(wrapperOptions.getOidValueSep())));
|
if(f !=null){
|
tree.setText((String)f.apply(doObject));
|
}else{
|
List<String> textFieldNames = VciBaseUtil.str2List(wrapperOptions.getTextFieldName());
|
List<String> textValues = new LinkedList<>();
|
textFieldNames.stream().forEach( s->{
|
textValues.add(VciBaseUtil.getStringValueFromObject(VciBaseUtil.getValueFromField(s,doObject)));
|
});
|
tree.setText(textValues.stream().collect(Collectors.joining(wrapperOptions.getTextValueSep())));
|
}
|
if(StringUtils.isNotBlank(wrapperOptions.getParentFieldName())){
|
tree.setParentId(VciBaseUtil.getStringValueFromObject(VciBaseUtil.getValueFromField(wrapperOptions.getParentFieldName(),doObject)));
|
}
|
if(wrapperOptions.isAllAttributes()) {
|
try {
|
tree.setAttributes(VciBaseUtil.objectToMapString(doObject));
|
} catch (Exception e) {
|
//这里不做处理
|
if (logger.isErrorEnabled()) {
|
logger.error("把对象转换为map时出现了错误,但是不影响树的展示,对业务可能有影响");
|
}
|
}
|
}
|
if(wrapperOptions.isMultipleSelect() || wrapperOptions.isShowCheckBox()){
|
tree.setShowCheckbox(true);
|
}
|
if(wrapperOptions.getParentOid() == null){
|
wrapperOptions.setParentOid("");
|
}
|
if(StringUtils.isBlank(tree.getParentId())
|
|| (StringUtils.isNotBlank(wrapperOptions.getParentOid()) && wrapperOptions.getParentOid().equalsIgnoreCase(tree.getParentId()))){
|
allTree.add(tree);
|
}else {
|
children.add(tree);
|
}
|
}
|
new Tree().findChild(allTree,children);
|
|
if(allTree.size()<=0){
|
allTree.addAll(children);
|
}
|
return allTree;
|
}
|
}
|