修改TMS用户同步只增量同步用户数据

This commit is contained in:
luojiaquan
2026-10-19 09:59:01 +08:00
parent a48b40c649
commit 92fc2f1ad0
6 changed files with 271 additions and 9 deletions
@@ -40,6 +40,9 @@ public class OrgSyncService
/** 写库人标记 */
public static final String SYNC_MARKER = "oracle-sync";
/** TMS 用户增量同步写库人标记 */
public static final String USER_SYNC_MARKER = "tms-user-sync";
/** 新用户默认密码(BCrypt,明文 123456) */
private static final String DEFAULT_PASSWORD =
"$2a$10$gAOzrNJaYLM2m85.9ykkLO0IPvQktxqee8RVpAu1e3.J0Ujiv4Z0G";
@@ -101,6 +104,194 @@ public class OrgSyncService
return result;
}
/**
* TMS 用户增量同步(按钮「TMS同步用户」)。
* 规则:
* 1) 不变动组织机构(sys_dept)、不同步角色/岗位(sys_role、sys_user_role、sys_user_post);
* 2) 只同步用户:已存在的用户一律保持不变,仅新增系统中不存在的用户;
* 3) 匹配优先级:先按工号(EMPLOYEE_CODE = sys_user.user_name)匹配,
* 再按姓名(EMPLOYEE_NAME = sys_user.nick_name)+ 所在机构匹配;
* 4) 新用户部门:按 TMS 部门名称匹配现有机构(优先“威狮国际”直属部门),
* 机构匹配不到的统一挂到根部门“威狮国际”(dept_id=200);
* 5) 新用户 user_id 自增、默认密码 123456、不分配角色。
*/
public Map<String, Object> syncUsersOnly()
{
long t0 = System.currentTimeMillis();
List<Map<String, Object>> deptRows = oracleOrgReader.readAllDept();
List<Map<String, Object>> empRows = oracleOrgReader.readAllEmployee();
// TMS 部门编码 -> 部门名称(TAB_DEPT 中 DEPT_NAME 即机构名)
Map<String, String> tmsDeptNameByCode = new HashMap<String, String>();
for (Map<String, Object> row : deptRows)
{
String code = clean(str(row, "DEPT_CODE"));
String name = clean(str(row, "DEPT_NAME"));
if (code != null && name != null && !tmsDeptNameByCode.containsKey(code))
{
tmsDeptNameByCode.put(code, name);
}
}
// 现有机构:部门名称 -> deptId(重名时优先“威狮国际”直属部门)
List<SysDept> bmsDepts = orgSyncWriter.readSyncDepts();
Map<String, Long> bmsDeptIdByName = new HashMap<String, Long>();
for (SysDept d : bmsDepts)
{
String name = clean(d.getDeptName());
if (name == null || d.getDeptId() == null)
{
continue;
}
Long exist = bmsDeptIdByName.get(name);
if (exist == null
|| (d.getParentId() != null && d.getParentId().longValue() == ROOT_DEPT_ID
&& exist.longValue() != ROOT_DEPT_ID))
{
bmsDeptIdByName.put(name, d.getDeptId());
}
}
// 现有用户匹配索引:工号(小写);姓名 + 机构
List<SysUser> bmsUsers = orgSyncWriter.readSyncUsers();
Map<String, SysUser> userByLoginName = new HashMap<String, SysUser>();
Map<String, SysUser> userByNameDept = new HashMap<String, SysUser>();
for (SysUser u : bmsUsers)
{
if (u == null || u.getUserId() == null)
{
continue;
}
if (clean(u.getUserName()) != null
&& !userByLoginName.containsKey(u.getUserName().trim().toLowerCase()))
{
userByLoginName.put(u.getUserName().trim().toLowerCase(), u);
}
if (clean(u.getNickName()) != null && u.getDeptId() != null)
{
String key = nameDeptKey(u.getDeptId(), u.getNickName());
if (!userByNameDept.containsKey(key))
{
userByNameDept.put(key, u);
}
}
}
List<SysUser> toInsert = new ArrayList<SysUser>();
Set<String> batchLoginNames = new HashSet<String>();
long matchedByCode = 0;
long matchedByName = 0;
long orgFallback = 0;
long skipped = 0;
for (Map<String, Object> row : empRows)
{
String code = clean(str(row, "EMPLOYEE_CODE"));
String name = clean(str(row, "EMPLOYEE_NAME"));
if (code == null && name == null)
{
skipped++;
continue;
}
if (code != null && BUILTIN_ADMIN.equalsIgnoreCase(code))
{
// 不动 BMS 内置超级管理员
skipped++;
continue;
}
// 按机构匹配部门:TMS DEPT_CODE -> TMS 部门名称 -> 现有 sys_dept;匹配不到挂威狮国际
Long targetDeptId = ROOT_DEPT_ID;
String deptCode = clean(str(row, "DEPT_CODE"));
if (deptCode != null)
{
String tmsDeptName = tmsDeptNameByCode.get(deptCode);
if (tmsDeptName != null)
{
Long matched = bmsDeptIdByName.get(tmsDeptName);
if (matched != null)
{
targetDeptId = matched;
}
}
}
boolean underRoot = targetDeptId == ROOT_DEPT_ID;
// 1) 优先工号匹配
if (code != null && userByLoginName.containsKey(code.toLowerCase()))
{
matchedByCode++;
continue;
}
// 2) 再按姓名 + 所在机构匹配
if (name != null && userByNameDept.containsKey(nameDeptKey(targetDeptId, name)))
{
matchedByName++;
continue;
}
// 3) 不存在 -> 新增(工号是登录账号,缺失无法建号)
if (code == null)
{
log.warn("TMS 用户同步跳过:姓名={} 缺少工号(EMPLOYEE_CODE),无法创建登录账号", name);
skipped++;
continue;
}
if (!batchLoginNames.add(code.toLowerCase()))
{
log.warn("TMS 用户同步跳过:工号 {}({}) 在 TMS 数据中重复", code, name);
skipped++;
continue;
}
if (underRoot)
{
orgFallback++;
}
SysUser u = new SysUser();
u.setDeptId(targetDeptId);
u.setUserName(code);
u.setNickName(name != null ? truncate(name, 30) : code);
u.setPassword(DEFAULT_PASSWORD);
u.setStatus("1".equals(clean(str(row, "BL_OPEN"))) ? "0" : "1");
u.setSex(mapSex(clean(str(row, "SEX"))));
u.setEmail(cleanEmail(str(row, "EMAIL")));
u.setPhonenumber(cleanPhone(str(row, "MOBILE_PHONE")));
u.setRemark(truncate(clean(str(row, "REMARK")), 500));
Object createDate = row.get("CREATE_DATE");
u.setCreateTime(createDate instanceof Date ? (Date) createDate : new Date());
u.setCreateBy(USER_SYNC_MARKER);
toInsert.add(u);
}
orgSyncWriter.insertNewUsers(toInsert);
long cost = System.currentTimeMillis() - t0;
String summary = String.format(
"TMS 用户同步完成:读取 TMS 员工 %d 人,已存在保持不变 %d 人(工号匹配 %d / 姓名+机构匹配 %d),新增 %d 人(其中机构未匹配挂“%s”%d 人),跳过 %d 条,耗时 %dms。新用户默认密码 123456,未分配角色。",
empRows.size(), matchedByCode + matchedByName, matchedByCode, matchedByName,
toInsert.size(), ROOT_DEPT_NAME, orgFallback, skipped, cost);
log.info(summary);
Map<String, Object> result = new LinkedHashMap<String, Object>();
result.put("total", empRows.size());
result.put("existCount", matchedByCode + matchedByName);
result.put("matchedByCode", matchedByCode);
result.put("matchedByName", matchedByName);
result.put("insertCount", toInsert.size());
result.put("orgFallbackCount", orgFallback);
result.put("skipCount", skipped);
result.put("costMs", cost);
result.put("summary", summary);
return result;
}
private static String nameDeptKey(Long deptId, String name)
{
return deptId + "|" + name.trim();
}
private List<SysDept> buildDepts(List<Map<String, Object>> rows)
{
List<SysDept> list = new ArrayList<>();
@@ -59,4 +59,26 @@ public class OrgSyncWriter
// 6. 超级管理员挂到根部门
writerMapper.updateUserDept(1L, adminDeptId);
}
/** TMS 用户增量同步:读取现有全部未删除部门 */
public List<SysDept> readSyncDepts()
{
return writerMapper.selectSyncDepts();
}
/** TMS 用户增量同步:读取现有全部未删除用户(仅匹配字段) */
public List<SysUser> readSyncUsers()
{
return writerMapper.selectSyncUsers();
}
/** TMS 用户增量同步:仅新增用户(user_id 自增,不触碰部门/角色/岗位),单事务 */
@Transactional(rollbackFor = Exception.class)
public void insertNewUsers(List<SysUser> users)
{
for (int i = 0; i < users.size(); i += USER_BATCH)
{
writerMapper.batchInsertUserAutoId(users.subList(i, Math.min(i + USER_BATCH, users.size())));
}
}
}
@@ -43,4 +43,13 @@ public interface SysOrgSyncWriterMapper
/** 将指定用户挂到根部门 */
int updateUserDept(@Param("userId") Long userId, @Param("deptId") Long deptId);
/** 查询全部未删除部门(TMS 用户增量同步:按部门名称匹配机构) */
List<SysDept> selectSyncDepts();
/** 查询全部未删除用户的匹配字段(TMS 用户增量同步:工号/姓名+机构匹配) */
List<SysUser> selectSyncUsers();
/** 批量新增用户(user_id 自增,不指定 ID,不写角色/岗位) */
int batchInsertUserAutoId(@Param("list") List<SysUser> list);
}
@@ -4,6 +4,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bms.system.orgsync.mapper.SysOrgSyncWriterMapper">
<!-- 全局未开启下划线转驼峰,TMS 用户增量同步查询使用显式映射 -->
<resultMap id="syncDeptResult" type="com.bms.common.core.domain.entity.SysDept">
<id property="deptId" column="dept_id"/>
<result property="parentId" column="parent_id"/>
<result property="deptName" column="dept_name"/>
<result property="status" column="status"/>
</resultMap>
<resultMap id="syncUserResult" type="com.bms.common.core.domain.entity.SysUser">
<id property="userId" column="user_id"/>
<result property="deptId" column="dept_id"/>
<result property="userName" column="user_name"/>
<result property="nickName" column="nick_name"/>
</resultMap>
<delete id="deleteAllRoleDept">
delete from sys_role_dept
</delete>
@@ -62,4 +77,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<update id="updateUserDept">
update sys_user set dept_id = #{deptId} where user_id = #{userId}
</update>
<select id="selectSyncDepts" resultMap="syncDeptResult">
select dept_id, parent_id, dept_name, status
from sys_dept
where del_flag = '0'
</select>
<select id="selectSyncUsers" resultMap="syncUserResult">
select user_id, dept_id, user_name, nick_name
from sys_user
where del_flag = '0'
</select>
<insert id="batchInsertUserAutoId" parameterType="java.util.List">
insert into sys_user(dept_id, user_name, nick_name, user_type, email, phonenumber, sex,
password, status, del_flag, create_by, create_time, remark)
values
<foreach collection="list" item="u" separator=",">
(#{u.deptId}, #{u.userName}, #{u.nickName}, '00', #{u.email}, #{u.phonenumber},
#{u.sex}, #{u.password}, #{u.status}, '0', #{u.createBy},
<choose><when test="u.createTime != null">#{u.createTime}</when><otherwise>sysdate()</otherwise></choose>,
#{u.remark})
</foreach>
</insert>
</mapper>