Merge remote-tracking branch 'base-version/main' into dev

This commit is contained in:
chenbowen
2025-10-17 17:45:33 +08:00
106 changed files with 4200 additions and 1377 deletions

View File

@@ -55,6 +55,15 @@ public class DeptController {
return success(true);
}
@PostMapping("init-codes")
@Operation(summary = "初始化部门编码", description = "按照层级自动为全部部门重新生成编码")
@PreAuthorize("@ss.hasPermission('system:dept:init-code')")
@TenantIgnore
public CommonResult<Boolean> initializeDeptCodes() {
deptService.initializeDeptCodes();
return success(true);
}
@DeleteMapping("delete")
@Operation(summary = "删除部门")
@Parameter(name = "id", description = "编号", required = true, example = "1024")

View File

@@ -19,7 +19,7 @@ public class DeptSaveReqVO {
@Schema(description = "部门编号", example = "1024")
private Long id;
@Schema(description = "部门编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "DEPT_001")
@Schema(description = "部门编码", example = "ZT001001")
@Size(max = 50, message = "部门编码长度不能超过 50 个字符")
private String code;

View File

@@ -2,6 +2,7 @@ package com.zt.plat.module.system.controller.admin.sync;
import com.zt.plat.framework.common.biz.system.oauth2.OAuth2TokenCommonApi;
import com.zt.plat.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
import com.zt.plat.framework.common.util.security.CryptoSignatureUtils;
import com.zt.plat.framework.security.core.LoginUser;
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
import com.zt.plat.framework.tenant.core.aop.TenantIgnore;
@@ -558,7 +559,7 @@ public class SyncController {
syncLogService.logDecryptResult(logId, bimRequestId, bodyJson, authUser, true);
// 签名验证
boolean signatureValid = SyncVerifyUtil.verifySignature(map, "MD5");
boolean signatureValid = CryptoSignatureUtils.verifySignature(map, CryptoSignatureUtils.SIGNATURE_TYPE_MD5);
syncLogService.logSignatureVerifyResult(logId, signatureValid);
if (!signatureValid) {
throw exception(SYNC_SIGNATURE_VERIFY_FAILED);
@@ -608,8 +609,8 @@ public class SyncController {
String bodyJson;
String jsonString = JSON.toJSONString(object);
try {
bodyJson = SyncVerifyUtil.encrypt(jsonString, encryptKey, "AES");
} catch (Exception e) {
bodyJson = CryptoSignatureUtils.encrypt(jsonString, encryptKey, CryptoSignatureUtils.ENCRYPT_TYPE_AES);
} catch (IllegalArgumentException | IllegalStateException e) {
throw exception(SYNC_DECRYPT_TYPE);
}
return bodyJson;

View File

@@ -5,6 +5,7 @@ import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.zt.plat.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import com.zt.plat.module.system.dal.dataobject.dept.DeptDO;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
@@ -88,6 +89,20 @@ public interface DeptMapper extends BaseMapperX<DeptDO> {
);
}
/**
* 查询指定父部门下编码最大的子部门
*
* @param parentId 父部门ID
* @return 编码最大的子部门
*/
default DeptDO selectLastChildByCode(Long parentId) {
return selectOne(new LambdaQueryWrapper<DeptDO>()
.eq(DeptDO::getParentId, parentId)
.isNotNull(DeptDO::getCode)
.orderByDesc(DeptDO::getCode)
.last("LIMIT 1"));
}
/**
* 根据部门编码查询部门
*

View File

@@ -152,4 +152,9 @@ public interface DeptService {
* @return 公司列表
*/
List<DeptDO> getAllCompanyList();
/**
* 按照新的编码规则初始化全部部门编码
*/
void initializeDeptCodes();
}

View File

@@ -8,6 +8,7 @@ import com.zt.plat.framework.common.enums.CommonStatusEnum;
import com.zt.plat.framework.common.pojo.CompanyDeptInfo;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.framework.datapermission.core.annotation.DataPermission;
import com.zt.plat.framework.tenant.core.aop.TenantIgnore;
import com.zt.plat.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import com.zt.plat.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
import com.zt.plat.module.system.dal.dataobject.dept.DeptDO;
@@ -21,9 +22,11 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -47,6 +50,13 @@ public class DeptServiceImpl implements DeptService {
@Resource
private UserDeptMapper userDeptMapper;
private static final String ROOT_CODE_PREFIX = "ZT";
private static final int CODE_SEGMENT_LENGTH = 3;
private static final int MAX_SEQUENCE = 999;
private static final Comparator<DeptDO> DEPT_COMPARATOR = Comparator
.comparing(DeptDO::getSort, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(DeptDO::getId, Comparator.nullsLast(Comparator.naturalOrder()));
@Override
@CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST,
allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存
@@ -60,8 +70,10 @@ public class DeptServiceImpl implements DeptService {
validateParentDept(null, createReqVO.getParentId());
// 校验部门名的唯一性
validateDeptNameUnique(null, createReqVO.getParentId(), createReqVO.getName());
// 校验部门编码的唯一性
validateDeptCodeUnique(null, createReqVO.getCode());
// 生成并校验部门编码
String generatedCode = generateDeptCode(createReqVO.getParentId());
createReqVO.setCode(generatedCode);
validateDeptCodeUnique(null, generatedCode);
// 插入部门
DeptDO dept = BeanUtils.toBean(createReqVO, DeptDO.class);
@@ -82,15 +94,29 @@ public class DeptServiceImpl implements DeptService {
updateReqVO.setParentId(DeptDO.PARENT_ID_ROOT);
}
// 校验自己存在
validateDeptExists(updateReqVO.getId());
DeptDO originalDept = getRequiredDept(updateReqVO.getId());
// 校验父部门的有效性
validateParentDept(updateReqVO.getId(), updateReqVO.getParentId());
// 校验部门名的唯一性
validateDeptNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());
// 如果上级发生变化,需要重新生成编码并同步子级
Long newParentId = normalizeParentId(updateReqVO.getParentId());
Long oldParentId = normalizeParentId(originalDept.getParentId());
boolean parentChanged = !Objects.equals(newParentId, oldParentId);
if (parentChanged) {
String newCode = generateDeptCode(updateReqVO.getParentId());
updateReqVO.setCode(newCode);
} else {
updateReqVO.setCode(originalDept.getCode());
}
// 更新部门
DeptDO updateObj = BeanUtils.toBean(updateReqVO, DeptDO.class);
deptMapper.updateById(updateObj);
if (parentChanged) {
refreshChildCodesRecursively(updateObj.getId(), updateReqVO.getCode());
}
}
@Override
@@ -112,10 +138,18 @@ public class DeptServiceImpl implements DeptService {
if (id == null) {
return;
}
getRequiredDept(id);
}
private DeptDO getRequiredDept(Long id) {
if (id == null) {
throw exception(DEPT_NOT_FOUND);
}
DeptDO dept = deptMapper.selectById(id);
if (dept == null) {
throw exception(DEPT_NOT_FOUND);
}
return dept;
}
@VisibleForTesting
@@ -186,6 +220,98 @@ public class DeptServiceImpl implements DeptService {
}
}
private String generateDeptCode(Long parentId) {
Long effectiveParentId = normalizeParentId(parentId);
String prefix = ROOT_CODE_PREFIX;
if (!DeptDO.PARENT_ID_ROOT.equals(effectiveParentId)) {
DeptDO parentDept = deptMapper.selectById(effectiveParentId);
if (parentDept == null) {
throw exception(DEPT_PARENT_NOT_EXITS);
}
if (StrUtil.isBlank(parentDept.getCode())) {
throw exception(DEPT_PARENT_CODE_NOT_INITIALIZED);
}
prefix = parentDept.getCode();
}
int nextSequence = determineNextSequence(effectiveParentId, prefix);
assertSequenceRange(nextSequence);
return prefix + formatSequence(nextSequence);
}
private int determineNextSequence(Long parentId, String prefix) {
DeptDO lastChild = deptMapper.selectLastChildByCode(parentId);
Integer sequence = parseSequence(lastChild != null ? lastChild.getCode() : null, prefix);
if (sequence != null) {
return sequence + 1;
}
return deptMapper.selectListByParentId(parentId, null).stream()
.map(DeptDO::getCode)
.map(code -> parseSequence(code, prefix))
.filter(Objects::nonNull)
.max(Integer::compareTo)
.map(val -> val + 1)
.orElse(1);
}
private Integer parseSequence(String code, String prefix) {
if (StrUtil.isBlank(code) || StrUtil.isBlank(prefix) || !code.startsWith(prefix)) {
return null;
}
String suffix = code.substring(prefix.length());
if (suffix.length() != CODE_SEGMENT_LENGTH || !StrUtil.isNumeric(suffix)) {
return null;
}
return Integer.parseInt(suffix);
}
private void refreshChildCodesRecursively(Long parentId, String parentCode) {
rebuildCodes(parentId, parentCode, id -> deptMapper.selectListByParentId(id, null));
}
private void rebuildCodes(Long parentId, String parentCode, Function<Long, List<DeptDO>> childrenSupplier) {
List<DeptDO> children = sortChildren(childrenSupplier.apply(parentId));
if (CollUtil.isEmpty(children)) {
return;
}
int sequence = 1;
for (DeptDO child : children) {
assertSequenceRange(sequence);
String childCode = parentCode + formatSequence(sequence++);
updateDeptCode(child.getId(), childCode);
rebuildCodes(child.getId(), childCode, childrenSupplier);
}
}
private List<DeptDO> sortChildren(List<DeptDO> children) {
if (CollUtil.isEmpty(children)) {
return Collections.emptyList();
}
children.sort(DEPT_COMPARATOR);
return children;
}
private void assertSequenceRange(int sequence) {
if (sequence > MAX_SEQUENCE) {
throw exception(DEPT_CODE_OUT_OF_RANGE);
}
}
private String formatSequence(int sequence) {
return StrUtil.padPre(String.valueOf(sequence), CODE_SEGMENT_LENGTH, '0');
}
private Long normalizeParentId(Long parentId) {
return parentId == null ? DeptDO.PARENT_ID_ROOT : parentId;
}
private void updateDeptCode(Long deptId, String code) {
DeptDO update = new DeptDO();
update.setId(deptId);
update.setCode(code);
deptMapper.updateById(update);
}
@Override
public DeptDO getDept(Long id) {
return deptMapper.selectById(id);
@@ -465,4 +591,27 @@ public class DeptServiceImpl implements DeptService {
return deptMapper.selectAllCompanyList(CommonStatusEnum.ENABLE.getStatus());
}
@Override
@TenantIgnore
@Transactional(rollbackFor = Exception.class)
public void initializeDeptCodes() {
List<DeptDO> allDepts = deptMapper.selectList();
if (CollUtil.isEmpty(allDepts)) {
return;
}
Map<Long, List<DeptDO>> childrenMap = allDepts.stream()
.collect(Collectors.groupingBy(dept -> normalizeParentId(dept.getParentId())));
Function<Long, List<DeptDO>> childrenSupplier = id -> new ArrayList<>(childrenMap.getOrDefault(id, Collections.emptyList()));
List<DeptDO> rootDepts = sortChildren(childrenSupplier.apply(DeptDO.PARENT_ID_ROOT));
int sequence = 1;
for (DeptDO root : rootDepts) {
assertSequenceRange(sequence);
String code = ROOT_CODE_PREFIX + formatSequence(sequence++);
updateDeptCode(root.getId(), code);
rebuildCodes(root.getId(), code, childrenSupplier);
}
}
}

View File

@@ -37,6 +37,7 @@ public interface EbanOAuth2Service {
private String mobile;
private String deptName;
private String uid;
private String displayName;
private String rawUserInfoJson;
private EbanOAuth2ServiceImpl.EbanTokenInfo tokenInfo; // 添加Token信息
@@ -70,6 +71,9 @@ public interface EbanOAuth2Service {
public String getUid() { return uid; }
public void setUid(String uid) { this.uid = uid; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String displayName) { this.displayName = displayName; }
public String getRawUserInfoJson() { return rawUserInfoJson; }
public void setRawUserInfoJson(String rawUserInfoJson) { this.rawUserInfoJson = rawUserInfoJson; }

View File

@@ -77,15 +77,16 @@ public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
}
String uid = userInfo.getUid();
if (StrUtil.isBlank(uid)) {
String displayName = StrUtil.trim(StrUtil.blankToDefault(userInfo.getDisplayName(), userInfo.getUsername()));
if (StrUtil.isBlank(displayName)) {
log.error("E办OAuth2用户信息缺少displayName与loginName无法匹配账号: {}", JSONUtil.toJsonStr(userInfo));
throw exception(AUTH_LOGIN_EBAN_TOKEN_INVALID);
}
Long userId = parseUid(uid);
AdminUserDO user = userService.getUser(userId);
AdminUserDO user = userService.getUserByUsername(displayName);
if (user == null) {
createLoginLog(null, uid, LoginLogTypeEnum.LOGIN_SOCIAL, LoginResultEnum.BAD_CREDENTIALS);
createLoginLog(null, displayName, LoginLogTypeEnum.LOGIN_SOCIAL, LoginResultEnum.BAD_CREDENTIALS);
log.warn("E办OAuth2用户displayName未在系统中找到对应账号: {}", displayName);
throw exception(AUTH_LOGIN_EBAN_USER_NOT_SYNC);
}
@@ -105,13 +106,13 @@ public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
tokenInfo.getAccessToken(),
tokenInfo.getRefreshToken(),
tokenInfo.getExpiresIn(),
uid,
userInfo.getUid(),
userInfoJson
);
log.info("成功保存E办tokenuserId={}, uid={}", user.getId(), uid);
log.info("成功保存E办tokenuserId={}, uid={}, displayName={}", user.getId(), userInfo.getUid(), displayName);
}
} catch (Exception e) {
log.error("保存E办token失败userId={}, uid={}", user.getId(), uid, e);
log.error("保存E办token失败userId={}, uid={}, displayName={}", user.getId(), userInfo.getUid(), displayName, e);
}
return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL);
@@ -132,21 +133,16 @@ public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
if (StrUtil.isBlank(userInfo.getUid()) && StrUtil.isNotBlank(tokenInfo.getUid())) {
userInfo.setUid(tokenInfo.getUid());
}
return userInfo;
}
private Long parseUid(String uid) {
try {
return Long.parseLong(uid);
} catch (NumberFormatException ex) {
log.warn("E办uid无法解析: {}", uid);
throw exception(AUTH_LOGIN_EBAN_USER_NOT_SYNC);
if (StrUtil.isBlank(userInfo.getDisplayName()) && StrUtil.isNotBlank(tokenInfo.getDisplayName())) {
userInfo.setDisplayName(StrUtil.trim(tokenInfo.getDisplayName()));
}
return userInfo;
}
private String buildBasicUserInfoJson(EbanUserInfo userInfo) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("uid", userInfo.getUid());
jsonObject.put("displayName", userInfo.getDisplayName());
jsonObject.put("loginName", userInfo.getUsername());
jsonObject.put("realName", userInfo.getRealName());
jsonObject.put("email", userInfo.getEmail());
@@ -164,6 +160,7 @@ public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
private Integer expiresIn;
private String uid;
private String createDate;
private String displayName;
// 构造函数和getter/setter方法
public EbanTokenInfo() {}
@@ -190,6 +187,9 @@ public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
public String getCreateDate() { return createDate; }
public void setCreateDate(String createDate) { this.createDate = createDate; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String displayName) { this.displayName = displayName; }
}
/**
@@ -231,10 +231,13 @@ public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
Integer expiresIn = jsonResponse.getInt("expires_in");
String uid = jsonResponse.getStr("uid");
String createDate = jsonResponse.getStr("createDate");
String displayName = jsonResponse.getStr("displayName");
log.info("成功获取E办access_tokenuid={}, expires_in={}", uid, expiresIn);
log.info("成功获取E办access_tokenuid={}, displayName={}, expires_in={}", uid, displayName, expiresIn);
return new EbanTokenInfo(accessToken, refreshToken, expiresIn, uid, createDate);
EbanTokenInfo tokenInfo = new EbanTokenInfo(accessToken, refreshToken, expiresIn, uid, createDate);
tokenInfo.setDisplayName(displayName);
return tokenInfo;
}
/**
@@ -277,6 +280,7 @@ public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
userInfo.setMobile(userJson.getStr("mobile"));
userInfo.setDeptName(userJson.getStr("deptName"));
userInfo.setUid(userJson.getStr("uid"));
userInfo.setDisplayName(resolveDisplayName(userJson));
userInfo.setRawUserInfoJson(userJson.toString());
if (StrUtil.isBlank(userInfo.getRealName()) && userJson.containsKey("spRoleList")) {
@@ -296,6 +300,23 @@ public class EbanOAuth2ServiceImpl implements EbanOAuth2Service {
return userInfo;
}
private String resolveDisplayName(JSONObject userJson) {
String displayName = userJson.getStr("displayName");
if (StrUtil.isBlank(displayName)) {
displayName = userJson.getStr("display_name");
}
if (StrUtil.isBlank(displayName)) {
displayName = userJson.getStr("displayname");
}
if (StrUtil.isBlank(displayName)) {
displayName = userJson.getStr("loginName");
}
if (StrUtil.isBlank(displayName)) {
displayName = userJson.getStr("realName");
}
return StrUtil.trim(displayName);
}
private JSONObject parseResponseBody(String body, String action) {
try {

View File

@@ -1,22 +1,9 @@
package com.zt.plat.module.system.util.sync;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.DES;
import com.zt.plat.framework.common.util.security.CryptoSignatureUtils;
import com.zt.plat.module.system.enums.common.SexEnum;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.system.enums.ErrorCodeConstants.AUTH_LOGIN_BAD_CREDENTIALS;
import static com.zt.plat.module.system.enums.ErrorCodeConstants.SYNC_DECRYPT_TYPE;
/**
@@ -25,105 +12,13 @@ import static com.zt.plat.module.system.enums.ErrorCodeConstants.SYNC_DECRYPT_TY
public class SyncVerifyUtil {
public static String decrypt(String ciphertext, String key, String type) {
if ("AES".equalsIgnoreCase(type)) {
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));
byte[] result = cipher.doFinal(Base64.getDecoder().decode(ciphertext.getBytes()));
return new String(result, StandardCharsets.UTF_8);
} catch (Exception e) {
throw exception(SYNC_DECRYPT_TYPE);
}
} else if ("DES".equalsIgnoreCase(type)) {
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
byte[] desKey = new byte[8];
System.arraycopy(keyBytes, 0, desKey, 0, Math.min(keyBytes.length, desKey.length));
DES des = SecureUtil.des(desKey);
byte[] encryptedBytes = Base64.getDecoder().decode(ciphertext);
return new String(des.decrypt(encryptedBytes), StandardCharsets.UTF_8);
} else {
try {
return CryptoSignatureUtils.decrypt(ciphertext, key, type);
} catch (IllegalArgumentException | IllegalStateException ex) {
throw exception(SYNC_DECRYPT_TYPE);
}
}
/**
* 生成与原始代码兼容的密钥
*/
private static SecretKeySpec getSecretKey(String password) {
try {
KeyGenerator kg = KeyGenerator.getInstance("AES");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(password.getBytes());
kg.init(128, random);
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), "AES");
} catch (NoSuchAlgorithmException ex) {
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
}
}
/**
* 对称加密Base64 格式输出)
* @param plaintext 明文内容
* @param key 密钥
* @param type 加密类型,支持 AES、DES
* @return 密文Base64 格式)
*/
public static String encrypt(String plaintext, String key, String type) {
if ("AES".equalsIgnoreCase(type)) {
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
byte[] byteContent = plaintext.getBytes(StandardCharsets.UTF_8);
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));
byte[] result = cipher.doFinal(byteContent);
return Base64.getEncoder().encodeToString(result);
} catch (Exception e) {
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
}
} else if ("DES".equalsIgnoreCase(type)) {
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
byte[] desKey = new byte[8];
System.arraycopy(keyBytes, 0, desKey, 0, Math.min(keyBytes.length, desKey.length));
DES des = SecureUtil.des(desKey);
byte[] encrypted = des.encrypt(plaintext.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted);
} else {
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
}
}
public static boolean verifySignature(Map<String, Object> reqMap, String type) {
// 排序并拼接参数,忽略 signature 字段
Map<String, Object> sortedMap = new TreeMap<>(reqMap);
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, Object> entry : sortedMap.entrySet()) {
String key = entry.getKey();
if ("signature".equals(key) || entry.getValue() == null) {
continue;
}
sb.append(key).append("=").append(entry.getValue()).append("&");
}
if (!sb.isEmpty()) {
sb.deleteCharAt(sb.length() - 1);
}
// 取出请求中的 signature
String provided = (String) reqMap.get("signature");
if (provided == null) {
return false;
}
// 计算签名
String computed;
if ("MD5".equalsIgnoreCase(type)) {
computed = SecureUtil.md5(sb.toString());
} else if ("SHA256".equalsIgnoreCase(type)) {
computed = SecureUtil.sha256(sb.toString());
} else {
throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
}
return provided.equalsIgnoreCase(computed);
}
/**
* e 办性别编码转换为内部性别编码
* 外部:女=0男=1

View File

@@ -35,6 +35,18 @@ public class DeptServiceImplTest extends BaseDbUnitTest {
@Resource
private DeptMapper deptMapper;
private Long createDept(Long parentId, String name, int sort) {
DeptSaveReqVO reqVO = new DeptSaveReqVO();
reqVO.setParentId(parentId);
reqVO.setName(name);
reqVO.setSort(sort);
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setDeptSource(1);
reqVO.setIsCompany(false);
reqVO.setIsGroup(false);
return deptService.createDept(reqVO);
}
@Test
public void testCreateDept() {
// 准备参数
@@ -42,6 +54,7 @@ public class DeptServiceImplTest extends BaseDbUnitTest {
o.setId(null); // 防止 id 被设置
o.setParentId(DeptDO.PARENT_ID_ROOT);
o.setStatus(randomCommonStatus());
o.setCode(null);
}).setDeptSource(1);
// 调用
@@ -50,13 +63,35 @@ public class DeptServiceImplTest extends BaseDbUnitTest {
assertNotNull(deptId);
// 校验记录的属性是否正确
DeptDO deptDO = deptMapper.selectById(deptId);
assertPojoEquals(reqVO, deptDO, "id");
assertPojoEquals(reqVO, deptDO, "id", "code");
assertEquals("ZT001", deptDO.getCode());
}
@Test
public void testCreateDept_childCodeGeneration() {
Long parentId = createDept(DeptDO.PARENT_ID_ROOT, "总部", 1);
DeptDO parentDept = deptMapper.selectById(parentId);
DeptSaveReqVO childReq = new DeptSaveReqVO();
childReq.setParentId(parentId);
childReq.setName("事业部");
childReq.setSort(1);
childReq.setStatus(CommonStatusEnum.ENABLE.getStatus());
childReq.setDeptSource(1);
Long childId = deptService.createDept(childReq);
DeptDO childDept = deptMapper.selectById(childId);
assertEquals(parentDept.getCode() + "001", childDept.getCode());
}
@Test
public void testUpdateDept() {
// mock 数据
DeptDO dbDeptDO = randomPojo(DeptDO.class, o -> o.setStatus(randomCommonStatus())).setDeptSource(null);
DeptDO dbDeptDO = randomPojo(DeptDO.class, o -> {
o.setStatus(randomCommonStatus());
o.setParentId(DeptDO.PARENT_ID_ROOT);
}).setDeptSource(null);
dbDeptDO.setCode("ZT001");
deptMapper.insert(dbDeptDO);// @Sql: 先插入出一条存在的数据
// 准备参数
DeptSaveReqVO reqVO = randomPojo(DeptSaveReqVO.class, o -> {
@@ -65,12 +100,38 @@ public class DeptServiceImplTest extends BaseDbUnitTest {
o.setId(dbDeptDO.getId());
o.setStatus(randomCommonStatus());
}).setDeptSource(1);
reqVO.setCode(dbDeptDO.getCode());
// 调用
deptService.updateDept(reqVO);
// 校验是否更新正确
DeptDO deptDO = deptMapper.selectById(reqVO.getId()); // 获取最新的
assertPojoEquals(reqVO, deptDO);
assertPojoEquals(reqVO, deptDO, "code");
assertEquals("ZT001", deptDO.getCode());
}
@Test
public void testUpdateDept_parentChangedRebuildsCodes() {
Long parentAId = createDept(DeptDO.PARENT_ID_ROOT, "A公司", 1);
Long parentBId = createDept(DeptDO.PARENT_ID_ROOT, "B公司", 2);
Long childId = createDept(parentAId, "子部门", 1);
Long grandChildId = createDept(childId, "子部门-一组", 1);
DeptDO parentB = deptMapper.selectById(parentBId);
DeptSaveReqVO updateReq = new DeptSaveReqVO();
updateReq.setId(childId);
updateReq.setName("子部门");
updateReq.setParentId(parentBId);
updateReq.setSort(1);
updateReq.setStatus(CommonStatusEnum.ENABLE.getStatus());
updateReq.setDeptSource(1);
deptService.updateDept(updateReq);
DeptDO updatedChild = deptMapper.selectById(childId);
DeptDO updatedGrandChild = deptMapper.selectById(grandChildId);
assertEquals(parentB.getCode() + "001", updatedChild.getCode());
assertEquals(updatedChild.getCode() + "001", updatedGrandChild.getCode());
}
@Test
@@ -293,4 +354,44 @@ public class DeptServiceImplTest extends BaseDbUnitTest {
assertServiceException(() -> deptService.validateDeptList(ids), DEPT_NOT_ENABLE, deptDO.getName());
}
@Test
public void testInitializeDeptCodes() {
DeptDO root1 = randomPojo(DeptDO.class, o -> {
o.setParentId(DeptDO.PARENT_ID_ROOT);
o.setSort(1);
o.setCode(null);
}).setDeptSource(null);
deptMapper.insert(root1);
DeptDO root2 = randomPojo(DeptDO.class, o -> {
o.setParentId(DeptDO.PARENT_ID_ROOT);
o.setSort(2);
o.setCode(null);
}).setDeptSource(null);
deptMapper.insert(root2);
DeptDO child1 = randomPojo(DeptDO.class, o -> {
o.setParentId(root1.getId());
o.setSort(1);
o.setCode(null);
}).setDeptSource(null);
deptMapper.insert(child1);
DeptDO child2 = randomPojo(DeptDO.class, o -> {
o.setParentId(root1.getId());
o.setSort(2);
o.setCode(null);
}).setDeptSource(null);
deptMapper.insert(child2);
deptService.initializeDeptCodes();
DeptDO updatedRoot1 = deptMapper.selectById(root1.getId());
DeptDO updatedRoot2 = deptMapper.selectById(root2.getId());
DeptDO updatedChild1 = deptMapper.selectById(child1.getId());
DeptDO updatedChild2 = deptMapper.selectById(child2.getId());
assertEquals("ZT001", updatedRoot1.getCode());
assertEquals("ZT002", updatedRoot2.getCode());
assertEquals("ZT001001", updatedChild1.getCode());
assertEquals("ZT001002", updatedChild2.getCode());
}
}