This commit is contained in:
2026-06-08 16:34:41 +08:00
8 changed files with 243 additions and 118 deletions

View File

@@ -4,6 +4,8 @@ import cn.wepact.dfm.training.dto.SyncRequest;
import cn.wepact.dfm.training.dto.TaskScoreSummary;
import cn.wepact.dfm.training.service.SyncTaskService;
import cn.wepact.dfm.training.service.SyncUserInfoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -17,6 +19,8 @@ import java.util.List;
@RequestMapping("sync")
public class SyncController {
private static final Logger log = LoggerFactory.getLogger(SyncController.class);
@Autowired
private SyncTaskService taskSyncService;
@Autowired
@@ -24,21 +28,31 @@ public class SyncController {
@PostMapping("/syncTasks")
public ResponseEntity<String> syncTasks(@RequestBody SyncRequest syncRequest) {
// 调用 syncTasks 方法并传入请求数据
taskSyncService.syncTasks(syncRequest);
// 返回成功响应
return ResponseEntity.ok("同步任务完成");
log.info("【同步任务】请求参数 - syncType={}, offset={}, limit={}, duration={}, searchStartTime={}, searchEndTime={}",
syncRequest.getSyncType(), syncRequest.getOffset(), syncRequest.getLimit(),
syncRequest.getDuration(), syncRequest.getSearchStartTime(), syncRequest.getSearchEndTime());
try {
taskSyncService.syncTasks(syncRequest);
log.info("同步任务完成");
return ResponseEntity.ok("同步任务完成");
} catch (Exception e) {
log.error("【同步任务】失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("同步任务失败: " + e.getMessage());
}
}
@PostMapping("/syncUsers")
public ResponseEntity<String> syncUsers(@RequestBody SyncRequest syncRequest) {
// 调用 syncTasks 方法并传入请求数据
syncUserInfoService.syncUserInfos(syncRequest);
// 返回成功响应
return ResponseEntity.ok("同步任务完成");
log.info("【同步用户】请求参数 - syncType={}, offset={}, limit={}, duration={}, searchStartTime={}, searchEndTime={}",
syncRequest.getSyncType(), syncRequest.getOffset(), syncRequest.getLimit(),
syncRequest.getDuration(), syncRequest.getSearchStartTime(), syncRequest.getSearchEndTime());
try {
syncUserInfoService.syncUserInfos(syncRequest);
log.info("同步用户】完成");
return ResponseEntity.ok("同步任务完成");
} catch (Exception e) {
log.error("【同步用户】失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("同步任务失败: " + e.getMessage());
}
}
// /**
@@ -57,76 +71,87 @@ public class SyncController {
*/
@PostMapping("/process-scores")
public ResponseEntity<String> processTaskScores() {
log.info("【处理分数】开始");
try {
List<TaskScoreSummary> taskScoreSummaries = taskSyncService.getTaskScoreSummary();
log.info("【处理分数】获取到 {} 条分数汇总", taskScoreSummaries.size());
taskSyncService.processTaskScores(taskScoreSummaries);
log.info("【处理分数】完成");
return ResponseEntity.ok("任务分数处理成功");
} catch (Exception e) {
log.error("【处理分数】失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("任务分数处理失败: " + e.getMessage());
}
}
// 定时任务方法:每天某个时间点执行任务
// @Scheduled(cron = "0 0 0 * * ?") // 每天0点执行可以根据需求修改 cron 表达式
@Scheduled(cron = "0 */10 * * * ?") // 每5分钟执行一次
// 定时任务方法:每10分钟执行一次
@Scheduled(cron = "0 */10 * * * ?")
@PostMapping("/executeTasks")
@Transactional(rollbackOn = Exception.class)
public void executeTasks() {
log.info("【定时任务】开始执行 - 同步用户->同步任务->处理分数");
try {
// 第一个任务:同步用户
syncUsers();
// 第二个任务:同步任务
syncTasks();
// 第三个任务:处理任务分数
processTaskScores();
log.info("【定时任务】同步用户完成");
} catch (Exception e) {
// 任务执行失败时的异常处理
System.err.println("定时任务执行失败:" + e.getMessage());
log.error("【定时任务】同步用户异常,继续执行后续任务", e);
}
}
// 同步用户信息
try {
syncTasks();
log.info("【定时任务】同步任务完成");
} catch (Exception e) {
log.error("【定时任务】同步任务异常,继续执行后续任务", e);
}
try {
processScores();
log.info("【定时任务】处理分数完成");
} catch (Exception e) {
log.error("【定时任务】处理分数异常", e);
}
log.info("【定时任务】全部执行完毕");
}
private void syncUsers() throws Exception {
try {
SyncRequest syncRequest = new SyncRequest();
syncRequest.setDuration(0);
syncRequest.setSyncType("incremental");
syncRequest.setOffset(0);
syncRequest.setLimit(20);
SyncRequest syncRequest = new SyncRequest();
syncRequest.setDuration(0);
syncRequest.setSyncType("incremental");
syncRequest.setOffset(0);
syncRequest.setLimit(20);
ResponseEntity<String> response = syncUserInfoService.syncUserInfos(syncRequest);
if (!response.getStatusCode().equals(HttpStatus.OK)) {
throw new Exception("同步用户失败: " + response.getBody());
}
} catch (Exception e) {
System.err.println("同步用户失败: " + e.getMessage());
throw new Exception("同步用户执行异常: " + e.getMessage());
log.info("【定时-同步用户】请求参数: {}", syncRequest);
ResponseEntity<String> response = syncUserInfoService.syncUserInfos(syncRequest);
log.info("【定时-同步用户】响应: {}", response.getBody());
if (!response.getStatusCode().equals(HttpStatus.OK)) {
throw new Exception("同步用户失败: " + response.getBody());
}
}
// 同步任务
private void syncTasks() throws Exception {
try {
SyncRequest syncRequest = new SyncRequest();
syncRequest.setDuration(0);
syncRequest.setSyncType("incremental");
syncRequest.setOffset(0);
syncRequest.setLimit(20);
ResponseEntity<String> response = taskSyncService.syncTasks(syncRequest);
SyncRequest syncRequest = new SyncRequest();
syncRequest.setDuration(0);
syncRequest.setSyncType("incremental");
syncRequest.setOffset(0);
syncRequest.setLimit(20);
if (!response.getStatusCode().equals(HttpStatus.OK)) {
throw new Exception("同步任务失败: " + response.getBody());
}
} catch (Exception e) {
System.err.println("同步任务失败: " + e.getMessage());
throw new Exception("同步任务执行异常: " + e.getMessage());
log.info("【定时-同步任务】请求参数: {}", syncRequest);
ResponseEntity<String> response = taskSyncService.syncTasks(syncRequest);
log.info("【定时-同步任务】响应: {}", response.getBody());
if (!response.getStatusCode().equals(HttpStatus.OK)) {
throw new Exception("同步任务失败: " + response.getBody());
}
}
private void processScores() throws Exception {
log.info("【定时-处理分数】开始");
List<TaskScoreSummary> summaries = taskSyncService.getTaskScoreSummary();
log.info("【定时-处理分数】获取到 {} 条汇总", summaries.size());
taskSyncService.processTaskScores(summaries);
log.info("【定时-处理分数】完成");
}
}

View File

@@ -9,6 +9,8 @@ import cn.wepact.dfm.training.dto.entity.TOrg;
import cn.wepact.dfm.training.dto.entity.TUser;
import cn.wepact.dfm.training.service.UserService;
import cn.wepact.dfm.training.utils.EmailUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -19,51 +21,60 @@ import java.util.List;
@RestController
@RequestMapping("users")
public class UserController extends BaseController{
private static final Logger log = LoggerFactory.getLogger(UserController.class);
@Autowired
private UserService userService;
// 登录
@PostMapping("/login")
public GeneralRespBean<TUser> login(@RequestBody TUser loginRequest) {
log.info("【登录】用户: {}", loginRequest.getUsername());
GeneralRespBean<TUser> respBean = new GeneralRespBean();
TUser user = userService.loginAndGetUser(loginRequest);
String jsonString=null;
if (user != null) {
respBean.setData(user);
respBean.setMsg(Constant.SUCCESS_MSG);
respBean.setCode(Constant.SUCCESS_CODE);
log.info("【登录】用户: {} 登录成功", loginRequest.getUsername());
} else {
respBean.setData(null);
respBean.setMsg("登录失败,账号密码错误,或单位选择有误!");
respBean.setCode(Constant.ERROR_CODE);
log.warn("【登录】用户: {} 登录失败", loginRequest.getUsername());
}
return respBean;
}
// 注册
@PostMapping("/register")
public GeneralRespBean<String> register(@RequestBody TUser registerRequest) {
log.info("【注册】用户: {}", registerRequest.getUsername());
GeneralRespBean<String> respBean = new GeneralRespBean();
Boolean result = userService.register(registerRequest);
if (result) {
respBean.setMsg(Constant.SUCCESS_MSG);
respBean.setCode(Constant.SUCCESS_CODE);
log.info("【注册】用户: {} 注册成功", registerRequest.getUsername());
} else {
respBean.setMsg("注册失败,账号已经存在!");
respBean.setCode(Constant.ERROR_CODE);
log.warn("【注册】用户: {} 注册失败,账号已存在", registerRequest.getUsername());
}
return respBean;
}
@GetMapping("/getDeptList")
public GeneralRespBean<List<TOrg>> getDeptList() {
log.info("【获取部门列表】开始");
GeneralRespBean<List<TOrg>> respBean = new GeneralRespBean();
List<TOrg> tOrgList = userService.getDeptList();
respBean.setData(tOrgList);
respBean.setMsg(Constant.SUCCESS_MSG);
respBean.setCode(Constant.SUCCESS_CODE);
log.info("【获取部门列表】共 {} 条", tOrgList.size());
return respBean;
}
@@ -72,8 +83,9 @@ public class UserController extends BaseController{
*/
@PostMapping(value = "/captcha")
public GeneralRespBean<Boolean> captchacode(HttpSession session) throws Exception {
GeneralRespBean<Boolean> respBean = new GeneralRespBean<>();
TUser user = getUserInfo();
log.info("【验证码】用户: {} 请求发送验证码至邮箱: {}", user.getUsername(), user.getEmail());
GeneralRespBean<Boolean> respBean = new GeneralRespBean<>();
String randomCode = userService.generateRandomCode();
session.setAttribute("randomCode", randomCode);
session.setAttribute("codeTime",System.currentTimeMillis());
@@ -85,6 +97,7 @@ public class UserController extends BaseController{
EmailUtil.sendMail(email);
respBean.setMsg("验证码发送成功!");
respBean.setCode("200");
log.info("【验证码】用户: {} 验证码发送成功", user.getUsername());
return respBean;
}
@@ -98,20 +111,26 @@ public class UserController extends BaseController{
GeneralRespBean<Boolean> respBean = new GeneralRespBean<>();
TUser user = getUserInfo();
tUser.setUserNo(user.getUserNo());
log.info("【修改密码】用户: {} 请求修改密码", user.getUsername());
// 获得验证码对象
Object cko = session.getAttribute("randomCode");
if (cko == null) {
log.warn("【修改密码】用户: {} 验证码已失效(空)", user.getUsername());
return respBean.processErrorMsg("验证码已失效,请重新获取!");
}
String captcha = cko.toString();
// 判断验证码输入是否正确
if (StringUtils.isEmpty(tUser.getRandomCode()) || captcha == null || !(tUser.getRandomCode().equalsIgnoreCase(captcha))) {
log.warn("【修改密码】用户: {} 验证码错误", user.getUsername());
return respBean.processErrorMsg("验证码错误,请重新输入!");
} else {
Long codeTime = Long.valueOf(session.getAttribute("codeTime") + "");
if ((System.currentTimeMillis() - codeTime) / 1000 / 60 > 4) {
log.warn("【修改密码】用户: {} 验证码已超时", user.getUsername());
return respBean.processErrorMsg("验证码已失效,请重新获取!");
}
log.info("【修改密码】用户: {} 验证码校验通过,执行修改", user.getUsername());
return userService.updatePwd(tUser);
}
}
@@ -119,16 +138,19 @@ public class UserController extends BaseController{
// 取消预览
@PostMapping("/cancelPreview")
public GeneralRespBean<Boolean> cancelPreview() {
GeneralRespBean<Boolean> respBean = new GeneralRespBean();
TUser user = getUserInfo();
log.info("【取消预览】用户: {} 请求取消预览", user.getUsername());
GeneralRespBean<Boolean> respBean = new GeneralRespBean();
Boolean result = userService.cancelPreview(user);
respBean.setData(result);
if (result) {
respBean.setMsg(Constant.SUCCESS_MSG);
respBean.setCode(Constant.SUCCESS_CODE);
log.info("【取消预览】用户: {} 取消成功", user.getUsername());
} else {
respBean.setMsg("取消预览失败");
respBean.setCode(Constant.ERROR_CODE);
log.warn("【取消预览】用户: {} 取消失败", user.getUsername());
}
return respBean;

View File

@@ -9,8 +9,8 @@ import cn.wepact.dfm.training.dto.entity.*;
import cn.wepact.dfm.training.mapper.*;
import cn.wepact.dfm.training.util.HttpClientUtil;
import com.alibaba.fastjson.JSON;
import com.itextpdf.text.log.Logger;
import com.itextpdf.text.log.LoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
@@ -107,9 +107,14 @@ public class SyncTaskService {
// 将返回的数据解析为 JSONObject
JSONObject responseJson = new JSONObject(response);
// 响应中没有data字段如权限错误终止同步
if (!responseJson.containsKey("data")) {
logger.error("全量同步响应中不存在data字段终止同步 - offset: {}, 响应: {}", offset, response);
break;
}
// 检查返回的 "data" 是否为空
if (responseJson.containsKey("data") && responseJson.getJSONArray("data").size() == 0) {
System.out.println("Data is empty, exiting the loop.");
if (responseJson.getJSONArray("data").size() == 0) {
logger.info("全量同步完成,没有更多数据 - offset: {}", offset);
break; // 如果 "data" 为空,跳出循环
}
@@ -119,7 +124,7 @@ public class SyncTaskService {
} catch (JSONException e) {
// 如果 JSON 解析出错,打印异常并跳出循环
System.err.println("Error parsing JSON response: " + e.getMessage());
logger.error("全量同步JSON解析失败 - offset: {}, 错误: {}", offset, e.getMessage());
break;
}
// 解析返回数据并保存到数据库
@@ -165,9 +170,14 @@ public class SyncTaskService {
// 将返回的数据解析为 JSONObject
JSONObject responseJson = new JSONObject(response);
// 响应中没有data字段如权限错误终止同步
if (!responseJson.containsKey("data")) {
logger.error("增量同步响应中不存在data字段终止同步 - offset: {}, 响应: {}", offset, response);
break;
}
// 检查返回的 "data" 是否为空
if (responseJson.containsKey("data") && responseJson.getJSONArray("data").size() == 0) {
System.out.println("Data is empty, exiting the loop.");
if (responseJson.getJSONArray("data").size() == 0) {
logger.info("增量同步完成,没有更多数据 - offset: {}", offset);
break; // 如果 "data" 为空,跳出循环
}
@@ -177,7 +187,7 @@ public class SyncTaskService {
} catch (JSONException e) {
// 如果 JSON 解析出错,打印异常并跳出循环
System.err.println("Error parsing JSON response: " + e.getMessage());
logger.error("增量同步JSON解析失败 - offset: {}, 错误: {}", offset, e.getMessage());
break;
}
// 解析返回数据并保存到数据库

View File

@@ -82,6 +82,9 @@ public class SyncUserInfoService {
}
}
private void fullSync(int offset, int limit, String searchStartTime, String searchEndTime) {
int consecutiveFailures = 0;
final int MAX_FAILURES = 3; // 最大连续失败次数
while (true) {
// 请求数据
Map<String, Object> requestParams = new HashMap<>();
@@ -95,28 +98,47 @@ public class SyncUserInfoService {
// 如果返回数据为空,则结束同步
if (response == null || response.isEmpty()) {
break;
consecutiveFailures++;
logger.warn("全量同步API返回空响应 - offset: {}, 连续失败次数: {}", offset, consecutiveFailures);
if (consecutiveFailures >= MAX_FAILURES) {
logger.error("全量同步连续失败 {} 次,终止同步", MAX_FAILURES);
break;
}
// 短暂等待后重试
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
continue;
}
// 重置失败计数器
consecutiveFailures = 0;
try {
// 将返回的数据解析为 JSONObject
JSONObject responseJson = new JSONObject(response);
// 响应中没有data字段如权限错误终止同步
if (!responseJson.containsKey("data")) {
logger.error("全量同步响应中不存在data字段终止同步 - offset: {}, 响应: {}", offset, response);
break;
}
// 检查返回的 "data" 是否为空
if (responseJson.containsKey("data") && responseJson.getJSONArray("data").size() == 0) {
System.out.println("Data is empty, exiting the loop.");
if (responseJson.getJSONArray("data").size() == 0) {
logger.info("全量同步完成,没有更多数据 - offset: {}", offset);
break; // 如果 "data" 为空,跳出循环
}
// 在这里处理 "data" 非空的情况
// 你可以继续进行数据处理
// ...
} catch (JSONException e) {
// 如果 JSON 解析出错,打印异常并跳出循环
System.err.println("Error parsing JSON response: " + e.getMessage());
logger.error("全量同步JSON解析失败 - offset: {}, 错误: {}", offset, e.getMessage());
break;
}
// 解析返回数据并保存到数据库
saveSyncUserData(offset, limit, requestParams, response);
@@ -134,6 +156,9 @@ public class SyncUserInfoService {
// 增量同步,使用上次同步的时间点作为查询的起始时间
String searchStartTime = lastSyncTime;
String searchEndTime = getCurrentTime();
int consecutiveFailures = 0;
final int MAX_FAILURES = 3; // 最大连续失败次数
// 请求数据
while (true) {
@@ -147,26 +172,44 @@ public class SyncUserInfoService {
String response = callApi(Incr_API_USER_URL, requestParams);
// 如果返回数据为空,则结束同步
if (response == null || response.isEmpty()) {
break;
consecutiveFailures++;
logger.warn("增量同步API返回空响应 - offset: {}, 连续失败次数: {}", offset, consecutiveFailures);
if (consecutiveFailures >= MAX_FAILURES) {
logger.error("增量同步连续失败 {} 次,终止同步", MAX_FAILURES);
break;
}
// 短暂等待后重试
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
continue;
}
// 重置失败计数器
consecutiveFailures = 0;
try {
// 将返回的数据解析为 JSONObject
JSONObject responseJson = new JSONObject(response);
// 响应中没有data字段如权限错误终止同步
if (!responseJson.containsKey("data")) {
logger.error("增量同步响应中不存在data字段终止同步 - offset: {}, 响应: {}", offset, response);
break;
}
// 检查返回的 "data" 是否为空
if (responseJson.containsKey("data") && responseJson.getJSONArray("data").size() == 0) {
System.out.println("Data is empty, exiting the loop.");
if (responseJson.getJSONArray("data").size() == 0) {
logger.info("增量同步完成,没有更多数据 - offset: {}", offset);
break; // 如果 "data" 为空,跳出循环
}
// 在这里处理 "data" 非空的情况
// 你可以继续进行数据处理
// ...
} catch (JSONException e) {
// 如果 JSON 解析出错,打印异常并跳出循环
System.err.println("Error parsing JSON response: " + e.getMessage());
logger.error("增量同步JSON解析失败 - offset: {}, 错误: {}", offset, e.getMessage());
break;
}
// 解析返回数据并保存到数据库
@@ -182,7 +225,7 @@ public class SyncUserInfoService {
private void saveSyncUserData(int offset, int limit, Map<String, Object> params, String responseData) {
// 检查入参
if (responseData == null || responseData.isEmpty()) {
logger.error("响应数据为空");
logger.error("响应数据为空 - offset: {}, limit: {}", offset, limit);
return;
}
@@ -192,7 +235,8 @@ public class SyncUserInfoService {
responseJson = new JSONObject(responseData);
// 检查data字段是否存在且不为空
if (!responseJson.containsKey("data")) {
logger.error("响应数据中没有data字段");
// 记录完整响应内容用于排查问题
logger.error("响应数据中没有data字段 - offset: {}, limit: {}, 完整响应: {}", offset, limit, responseData);
return;
}
@@ -380,19 +424,33 @@ public class SyncUserInfoService {
}
// 调用接口
private String callApi(String apiUrl, Map<String, Object> params) {
// 假设 accessToken 是从某个地方获取的比如从配置文件、Session 或者前端传递
String accessToken = getAccessToken(); // 你可以根据自己的需求获取 token
// 获取 accessToken
String accessToken = getAccessToken();
// 检查Token有效性
if (accessToken == null || accessToken.isEmpty()) {
logger.error("获取AccessToken失败无法调用API: {}", apiUrl);
return null;
}
// 调用 HttpClientUtil 的 doPost 方法
String response = HttpClientUtil.doPost(apiUrl, params, accessToken);
// 如果需要,你可以进一步处理响应结果
if (response != null && !response.isEmpty()) {
// 处理响应数据,比如解析 JSON 或者记录日志
return response;
// 记录响应日志用于调试
logger.debug("API请求成功 - URL: {}, 参数: {}, 响应长度: {} 字符", apiUrl, params, response.length());
// 检查响应是否为有效JSON
if (response.trim().startsWith("{")) {
return response;
} else {
logger.error("API响应不是有效的JSON格式 - URL: {}, 响应: {}", apiUrl, response);
return null;
}
} else {
// 错误处理
System.out.println("API 请求失败,未收到响应");
logger.error("API请求失败未收到响应 - URL: {}, 参数: {}", apiUrl, params);
return null;
}
}

View File

@@ -31,12 +31,17 @@ public class HttpClientUtil {
post.setEntity(entity);
try (CloseableHttpResponse response = client.execute(post)) {
int statusCode = response.getStatusLine().getStatusCode();
result = EntityUtils.toString(response.getEntity(), "UTF-8");
// Log response for debugging
log.debug("POST Response from {}: {}", pathUrl, result);
// 记录状态码和响应长度
if (statusCode >= 400) {
log.warn("POST request returned error status - URL: {}, Status: {}, Response: {}", pathUrl, statusCode, result);
} else {
log.debug("POST Response from {} - Status: {}, Length: {} chars", pathUrl, statusCode, result != null ? result.length() : 0);
}
}
} catch (Exception e) {
e.printStackTrace();
log.error("POST request failed - URL: {}, Data: {}, Error: {}", pathUrl, dataMap, e.getMessage(), e);
}
return result;
@@ -56,7 +61,8 @@ public class HttpClientUtil {
urlBuilder.deleteCharAt(urlBuilder.length() - 1);
}
HttpGet get = new HttpGet(urlBuilder.toString());
String finalUrl = urlBuilder.toString();
HttpGet get = new HttpGet(finalUrl);
get.setHeader("Content-Type", "application/json;charset=utf-8");
if (accessToken != null && !accessToken.isEmpty()) {
@@ -64,12 +70,17 @@ public class HttpClientUtil {
}
try (CloseableHttpResponse response = client.execute(get)) {
int statusCode = response.getStatusLine().getStatusCode();
result = EntityUtils.toString(response.getEntity(), "UTF-8");
// Log response for debugging
log.debug("GET Response from {}: {}", pathUrl, result);
// 记录状态码和响应长度
if (statusCode >= 400) {
log.warn("GET request returned error status - URL: {}, Status: {}, Response: {}", finalUrl, statusCode, result);
} else {
log.debug("GET Response from {} - Status: {}, Length: {} chars", finalUrl, statusCode, result != null ? result.length() : 0);
}
}
} catch (Exception e) {
e.printStackTrace();
log.error("GET request failed - URL: {}, Parameters: {}, Error: {}", pathUrl, dataMap, e.getMessage(), e);
}
return result;