Files
qualifications-management-s…/src/main/java/cn/wepact/dfm/training/service/SyncUserInfoService.java
2026-06-08 16:34:31 +08:00

481 lines
21 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package cn.wepact.dfm.training.service;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import cn.wepact.dfm.training.dto.SyncRequest;
import cn.wepact.dfm.training.dto.entity.SyncTaskLog;
import cn.wepact.dfm.training.dto.entity.SyncUserInfoLog;
import cn.wepact.dfm.training.dto.entity.TUser;
import cn.wepact.dfm.training.mapper.SyncUserInfoLogMapper;
import cn.wepact.dfm.training.mapper.TUserMapper;
import cn.wepact.dfm.training.util.HttpClientUtil;
import com.alibaba.fastjson.JSON;
// 修改 import 语句
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// 删除这两行
// import com.itextpdf.text.log.Logger;
// import com.itextpdf.text.log.LoggerFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class SyncUserInfoService {
private static final Logger logger = LoggerFactory.getLogger(SyncUserInfoService.class);
@Autowired
private SyncUserInfoLogMapper syncUserInfoMapper;
@Autowired
private TUserMapper userMapper;
@Value("${api.All_API_USER_URL}")
private String All_API_USER_URL;
@Value("${api.Incr_API_USER_URL}")
private String Incr_API_USER_URL;
@Value("${api.getAPITokenUrl}")
private String getAPITokenUrl;
@Transactional(rollbackOn = Exception.class)
public ResponseEntity<String> syncUserInfos(SyncRequest syncRequest) {
try {
// 执行同步逻辑
// 如果成功
int offset =syncRequest.getOffset();
int limit = syncRequest.getLimit();
String searchStartTime = syncRequest.getSearchStartTime();
String searchEndTime = syncRequest.getSearchEndTime();
String syncType = syncRequest.getSyncType();
int duration = syncRequest.getDuration();
if ("full".equalsIgnoreCase(syncType)) {
// 全量同步,使用请求中传入的时间区间
fullSync(offset, limit, searchStartTime, searchEndTime);
} else if ("incremental".equalsIgnoreCase(syncType)) {
// 增量同步,通常使用最后一次同步的时间戳
incrementalSync(offset, limit,duration);
}else {
throw new IllegalArgumentException("Invalid syncType: " + syncType);
}
return ResponseEntity.ok("同步用户成功");
} catch (Exception e) {
// 如果发生异常
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("同步用户失败: " + e.getMessage());
}
}
private void fullSync(int offset, int limit, String searchStartTime, String searchEndTime) {
while (true) {
// 请求数据
Map<String, Object> requestParams = new HashMap<>();
requestParams.put("offset", offset);
requestParams.put("limit", limit);
requestParams.put("searchStartTime", searchStartTime);
requestParams.put("searchEndTime", searchEndTime);
// 调用API获取数据
String response = callApi(All_API_USER_URL, requestParams);
// 如果返回数据为空,则结束同步
if (response == null || response.isEmpty()) {
break;
}
try {
// 将返回的数据解析为 JSONObject
JSONObject responseJson = new JSONObject(response);
// 检查返回的 "data" 是否为空
if (responseJson.containsKey("data") && responseJson.getJSONArray("data").size() == 0) {
System.out.println("Data is empty, exiting the loop.");
break; // 如果 "data" 为空,跳出循环
}
// 在这里处理 "data" 非空的情况
// 你可以继续进行数据处理
// ...
} catch (JSONException e) {
// 如果 JSON 解析出错,打印异常并跳出循环
System.err.println("Error parsing JSON response: " + e.getMessage());
break;
}
// 解析返回数据并保存到数据库
saveSyncUserData(offset, limit, requestParams, response);
// 更新offset值进行下一次同步
offset += limit;
}
}
private void incrementalSync(int offset, int limit,int duration) {
// 获取上次同步的时间点,通常从数据库中获取
String lastSyncTime = getLastSyncTimeFromDatabase();
// 增量同步,使用上次同步的时间点作为查询的起始时间
String searchStartTime = lastSyncTime;
String searchEndTime = getCurrentTime();
// 请求数据
while (true) {
Map<String, Object> requestParams = new HashMap<>();
requestParams.put("offset", offset);
requestParams.put("limit", limit);
requestParams.put("searchStartTime", searchStartTime);
requestParams.put("searchEndTime", searchEndTime);
requestParams.put("duration", duration);
// 调用API获取数据
String response = callApi(Incr_API_USER_URL, requestParams);
// 如果返回数据为空,则结束同步
if (response == null || response.isEmpty()) {
break;
}
try {
// 将返回的数据解析为 JSONObject
JSONObject responseJson = new JSONObject(response);
// 检查返回的 "data" 是否为空
if (responseJson.containsKey("data") && responseJson.getJSONArray("data").size() == 0) {
System.out.println("Data is empty, exiting the loop.");
break; // 如果 "data" 为空,跳出循环
}
// 在这里处理 "data" 非空的情况
// 你可以继续进行数据处理
// ...
} catch (JSONException e) {
// 如果 JSON 解析出错,打印异常并跳出循环
System.err.println("Error parsing JSON response: " + e.getMessage());
break;
}
// 解析返回数据并保存到数据库
saveSyncUserData(offset, limit, requestParams, response);
// 更新offset值进行下一次同步
offset += limit;
}
// 增量同步后,更新最后同步时间
updateLastSyncTimeToDatabase(getCurrentTime());
}
private void saveSyncUserData(int offset, int limit, Map<String, Object> params, String responseData) {
// 检查入参
if (responseData == null || responseData.isEmpty()) {
logger.error("响应数据为空");
return;
}
JSONObject responseJson = null;
JSONArray dataArray = null;
try {
responseJson = new JSONObject(responseData);
// 检查data字段是否存在且不为空
if (!responseJson.containsKey("data")) {
logger.error("响应数据中没有data字段");
return;
}
dataArray = responseJson.getJSONArray("data");
if (dataArray == null || dataArray.size() == 0) {
logger.info("没有需要同步的数据");
return;
}
// 第一遍收集所有用户名批量查询用户ID替代 N+1 逐条查询)
List<String> usernames = new ArrayList<>(dataArray.size());
for (int i = 0; i < dataArray.size(); i++) {
JSONObject dataObject = dataArray.getJSONObject(i);
if (dataObject == null) continue;
String u = getStringValue(dataObject, "username");
if (!u.isEmpty()) {
usernames.add(u);
}
}
Map<String, Long> userIdCache = new HashMap<>();
if (!usernames.isEmpty()) {
List<TUser> tUsers = userMapper.batchFindUserIdByUsernames(usernames);
for (TUser tUser : tUsers) {
if (tUser.getUserNo() != null) {
userIdCache.put(tUser.getUserNo(), tUser.getId());
}
}
}
for (int i = 0; i < dataArray.size(); i++) {
JSONObject dataObject = dataArray.getJSONObject(i);
if (dataObject == null) {
logger.warn("第{}条数据为空,跳过处理", i);
continue;
}
// 获取用户名,进行空值检查
String username = getStringValue(dataObject, "username");
if (username == null || username.trim().isEmpty()) {
logger.warn("用户名为空,跳过处理第{}条数据", i);
continue;
}
// 从批量查询的缓存中获取系统内部的user_id
Long userId = userIdCache.get(username);
if (userId == null) {
logger.warn("未找到用户: {}", username);
continue;
}
// 后续代码保持不变
SyncUserInfoLog userInfo = new SyncUserInfoLog();
// 填充 SyncTaskLog 对象的字段
userInfo.setSyncTime(new Timestamp(System.currentTimeMillis()));
userInfo.setOffset(offset);
userInfo.setSyncLimit(limit);
userInfo.setSearchStartTime(parseTimestamp((String) params.get("searchStartTime")));
userInfo.setSearchEndTime(parseTimestamp((String) params.get("searchEndTime")));
userInfo.setStatus(1); // 假设同步成功
userInfo.setId(getStringValue(dataObject, "id"));
userInfo.setUserId(getStringValue(dataObject, "userId"));
userInfo.setUsername(getStringValue(dataObject, "username"));
userInfo.setFullname(getStringValue(dataObject, "fullname"));
userInfo.setGender(getIntValue(dataObject, "gender"));
userInfo.setIdNo(getStringValue(dataObject, "idNo"));
userInfo.setBirthday(getDateValue(dataObject, "birthday"));
userInfo.setDeptId(getStringValue(dataObject, "deptId"));
userInfo.setDeptName(getStringValue(dataObject, "deptName"));
userInfo.setPositionId(getStringValue(dataObject, "positionId"));
userInfo.setPositionName(getStringValue(dataObject, "positionName"));
userInfo.setGradeId(getStringValue(dataObject, "gradeId"));
userInfo.setGradeName(getStringValue(dataObject, "gradeName"));
userInfo.setManagerId(getStringValue(dataObject, "managerId"));
userInfo.setManagerFullname(getStringValue(dataObject, "managerFullname"));
userInfo.setDeptManagerId(getStringValue(dataObject, "deptManagerId"));
userInfo.setDeptManagerFullname(getStringValue(dataObject, "deptManagerFullname"));
userInfo.setMobile(getStringValue(dataObject, "mobile"));
userInfo.setEmail(getStringValue(dataObject, "email"));
userInfo.setUserNo(getStringValue(dataObject, "userNo"));
userInfo.setHireDate(getDateValue(dataObject, "hireDate"));
userInfo.setExpiredTime(getDateValue(dataObject, "expiredTime"));
userInfo.setAreaCode(getStringValue(dataObject, "areaCode"));
userInfo.setUserStatus(getIntValue(dataObject, "userStatus"));
userInfo.setAvatarUrl(getStringValue(dataObject, "avatarUrl"));
userInfo.setAdmin(getIntValue(dataObject, "admin"));
userInfo.setDeleted(getIntValue(dataObject, "deleted"));
userInfo.setThirdUserId(getStringValue(dataObject, "thirdUserId"));
userInfo.setCreateTime(getDateValue(dataObject, "createTime"));
userInfo.setUpdateTime(getDateValue(dataObject, "updateTime"));
userInfo.setUserType(getIntValue(dataObject, "userType"));
// 额外存储API响应的原始数据和错误信息
userInfo.setResponseData(responseData);
userInfo.setErrorMessage(optString(dataObject, "errorMessage", ""));
// Check if the user already exists in the database
try {
SyncUserInfoLog existingUser = syncUserInfoMapper.getUserInfoByUserId(userInfo.getUserId());
if (existingUser == null) {
// New user, insert into database
try {
syncUserInfoMapper.insertUserInfo(userInfo);
logger.info("Successfully inserted new user: {}", userInfo.getUserId());
} catch (DataAccessException e) {
logger.error("Failed to insert new user: {}, error: {}", userInfo.getUserId(), e.getMessage());
userInfo.setStatus(0); // 设置同步状态为失败
userInfo.setErrorMessage(e.getMessage());
syncUserInfoMapper.insertUserInfo(userInfo); // 保存失败记录
continue; // 继续处理下一条记录
}
} else {
// Existing user, update the user info
try {
syncUserInfoMapper.updateUserInfo(userInfo);
logger.info("Successfully updated user: {}", userInfo.getUserId());
} catch (DataAccessException e) {
logger.error("Failed to update user: {}, error: {}", userInfo.getUserId(), e.getMessage());
userInfo.setStatus(0); // 设置同步状态为失败
userInfo.setErrorMessage(e.getMessage());
syncUserInfoMapper.updateUserInfo(userInfo); // 保存失败记录
continue; // 继续处理下一条记录
}
}
} catch (Exception e) {
logger.error("Error processing user: {}, error: {}", userInfo.getUserId(), e.getMessage());
continue; // 继续处理下一条记录
}
}
} catch (Exception e) {
logger.error("同步数据处理失败:", e);
throw e; // 抛出异常,跳出循环
}
}
public String getLastSyncTimeFromDatabase() {
String formattedLastSyncTime = null;
try {
// 调用Mapper方法获取时间
Date lastSyncTime = syncUserInfoMapper.getLastSyncTime();
// Check if lastSyncTime is not null
if (lastSyncTime != null) {
// Format the date to a readable string (e.g., "yyyy-MM-dd HH:mm:ss")
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
formattedLastSyncTime = dateFormat.format(lastSyncTime);
} else {
formattedLastSyncTime = "No sync time recorded.";
}
} catch (Exception e) {
e.printStackTrace();
formattedLastSyncTime = "Error retrieving last sync time.";
}
return formattedLastSyncTime;
}
private String getCurrentTime() {
// 获取当前时间,用作增量同步结束的时间
// 创建日期格式化对象
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 获取当前系统时间
Date now = new Date();
// 格式化当前时间并返回字符串
return dateFormat.format(now);
}
private void updateLastSyncTimeToDatabase(String lastSyncTime) {
// 更新最后同步时间到数据库
try {
// 将字符串转换为 Date 对象
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = dateFormat.parse(lastSyncTime);
// 调用 Mapper 方法更新最后同步时间
syncUserInfoMapper.updateLastSyncTime(date);
System.out.println("最后同步时间已更新: " + lastSyncTime);
} catch (ParseException e) {
e.printStackTrace();
System.err.println("时间格式错误: " + lastSyncTime);
} catch (Exception e) {
e.printStackTrace();
System.err.println("更新数据库时发生错误");
}
}
// 调用接口
private String callApi(String apiUrl, Map<String, Object> params) {
// 假设 accessToken 是从某个地方获取的比如从配置文件、Session 或者前端传递
String accessToken = getAccessToken(); // 你可以根据自己的需求获取 token
// 调用 HttpClientUtil 的 doPost 方法
String response = HttpClientUtil.doPost(apiUrl, params, accessToken);
// 如果需要,你可以进一步处理响应结果
if (response != null && !response.isEmpty()) {
// 处理响应数据,比如解析 JSON 或者记录日志
return response;
} else {
// 错误处理
System.out.println("API 请求失败,未收到响应");
return null;
}
}
// 假设这是获取 accessToken 的方法,根据需要修改
private String getAccessToken() {
String apiUrl =getAPITokenUrl;
String accessToken = null;
try (CloseableHttpClient client = HttpClients.createDefault()) {
HttpGet getRequest = new HttpGet(apiUrl);
// 执行请求
HttpResponse response = client.execute(getRequest);
// 获取响应内容
String responseString = EntityUtils.toString(response.getEntity());
// 解析响应 JSON
com.alibaba.fastjson.JSONObject responseObject = JSON.parseObject(responseString);
accessToken = responseObject.getString("accessToken"); // 假设返回的是 {"accessToken": "your-token"}
} catch (Exception e) {
System.out.println("获取 accessToken 失败: " + e.getMessage());
}
return accessToken;
}
public static void main(String[] args) {
// String token = getAccessToken();
// System.out.println("Access Token: " + token);
}
// 辅助方法:转换字符串为时间戳
private Timestamp parseTimestamp(String value) {
try {
return value != null && !value.isEmpty() ? Timestamp.valueOf(value) : null;
} catch (IllegalArgumentException e) {
// logger.error("时间转换失败: " + value, e);
return null;
}
}
private Date getDateValue(JSONObject json, String key) {
String value = getStringValue(json, key);
try {
return value != null && !value.isEmpty() ? Timestamp.valueOf(value) : null;
} catch (IllegalArgumentException e) {
return null; // Invalid date format, return null
}
}
// 获取 Long 值,若为空则返回 null
private Long getLongValue(JSONObject json, String key) {
return json.containsKey(key) && json.get(key) != null ? json.getLong(key) : null;
}
// 获取 String 值,若为空则返回空字符串
private String getStringValue(JSONObject json, String key) {
return json.containsKey(key) && json.get(key) != null ? json.getStr(key) : "";
}
// 获取 Integer 值,若为空则返回 0
private Integer getIntValue(JSONObject json, String key) {
if (json != null && json.containsKey(key) && json.get(key) != null) {
Object value = json.get(key);
if (value instanceof Integer) {
return (Integer) value; // 如果值是 Integer直接返回
} else {
try {
return Integer.parseInt(value.toString()); // 如果是其他类型,转换为 Integer
} catch (NumberFormatException e) {
return 0; // 转换失败,返回 0
}
}
}
return 0; // 如果 json 为 null或者 key 不存在,或者值是 JSONObject.NULL返回 0
}
// 获取 BigDecimal 值,若为空则返回 null
private BigDecimal getBigDecimalValue(JSONObject json, String key) {
return json.containsKey(key) && json.get(key) != null ? json.getBigDecimal(key) : null;
}
// 实现类似于 org.json.JSONObject 的 optString 方法
public String optString(JSONObject json, String key, String defaultValue) {
return json.containsKey(key) && json.get(key) != null ? json.getStr(key) : defaultValue;
}
}