JkApiServiceImpl.java 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. package com.takai.system.service.impl;
  2. import com.alibaba.fastjson2.JSON;
  3. import com.alibaba.fastjson2.JSONArray;
  4. import com.alibaba.fastjson2.JSONObject;
  5. import com.auth0.jwt.JWTCreator;
  6. import com.auth0.jwt.algorithms.Algorithm;
  7. import com.takai.common.enums.UserTypeEnum;
  8. import com.takai.common.utils.DateUtils;
  9. import com.takai.common.utils.SecurityUtils;
  10. import com.takai.common.utils.StringUtils;
  11. import com.takai.system.domain.SysProject;
  12. import com.takai.system.domain.SysProjectStaff;
  13. import com.takai.system.domain.vo.Member;
  14. import com.takai.system.domain.vo.ProjectWebApiBo;
  15. import com.takai.system.service.*;
  16. import com.takai.common.annotation.DataSource;
  17. import com.takai.common.config.JkConfig;
  18. import com.takai.common.core.domain.entity.SysDept;
  19. import com.takai.common.core.domain.entity.SysUser;
  20. import com.takai.common.core.redis.RedisCache;
  21. import com.takai.common.enums.DataSourceType;
  22. import com.takai.system.domain.SysPost;
  23. import lombok.extern.slf4j.Slf4j;
  24. import okhttp3.*;
  25. import org.slf4j.Logger;
  26. import org.slf4j.LoggerFactory;
  27. import org.springframework.beans.factory.annotation.Autowired;
  28. import org.springframework.data.redis.core.RedisTemplate;
  29. import org.springframework.stereotype.Service;
  30. import java.io.IOException;
  31. import java.util.*;
  32. import java.util.concurrent.TimeUnit;
  33. import com.auth0.jwt.JWT;
  34. /**
  35. * 高井 业务层处理
  36. *
  37. * @author takai
  38. */
  39. @Slf4j
  40. @Service
  41. @DataSource(DataSourceType.MASTER)
  42. public class JkApiServiceImpl implements IJkApiService {
  43. private static final Logger logger = LoggerFactory.getLogger(JkApiServiceImpl.class);
  44. @Autowired
  45. private ISysUserService sysUserService;
  46. @Autowired
  47. private ISysDeptService sysDeptService;
  48. @Autowired
  49. private ISysPostService sysPostService;
  50. @Autowired
  51. private RedisCache redisCache;
  52. @Autowired
  53. public RedisTemplate redisTemplate;
  54. @Autowired
  55. JkConfig jkConfig;
  56. @Autowired
  57. private ISysProjectService projectService;
  58. @Autowired
  59. private ISysProjectStaffService projectStaffService;
  60. public static final String BEARER = "Bearer";
  61. public static final String PARAM_ST = "startTime";
  62. public static final String PARAM_PAGE = "page";
  63. public static final String PARAM_SIZE = "size";
  64. public static final String PARAM_GRANT_TYPE = "grant_type";
  65. public static final String PARAM_CLIENT_ID = "client_id";
  66. public static final String PARAM_CLIENT_SECRET = "client_secret";
  67. public static final String PARAM_CODE = "code";
  68. public static final String PARAM_REDIRECT_URI = "redirect_uri";
  69. public static final String PARAM_ACCESS_TOKEN = "access_token";
  70. public static final String PARAM_IDS = "ids";
  71. public static final String PARAM_ERRORS = "errors";
  72. public static final int DEFAULT_SIZE = 100;
  73. public static final String CODE_SUCCESS = "0";
  74. public static final String DATA = "data";
  75. public static final String TOTAL = "total";
  76. public static final String LIST = "list";
  77. public static final String INTERFACE_USER = "用户";
  78. public static final String GRANT_TYPE_AC = "authorization_code";
  79. public static final int BEFORE_DAYS = 7;
  80. private static final MediaType JSON_UTF8 = MediaType.get("application/json; charset=utf-8");
  81. private static final OkHttpClient client = new OkHttpClient();
  82. public static final String HXG_PROJECT_AND_STAFF = "用户";
  83. public static final String HJL_PROJECT_AND_STAFF = "用户";
  84. public static final String HXG = "f47ac10b58cc4372a5670e06f141669d";
  85. public static final String HJL = "a34851c530ee0d07d1154beb47bb93dd";
  86. /**
  87. * 通过建科接口获取建科用户信息
  88. */
  89. @Override
  90. public List<SysUser> getJkUsers() throws IOException {
  91. List<SysUser> userList = new ArrayList<>();
  92. List<JSONObject> dataList = getApiData(jkConfig.getIamUserUrl(),INTERFACE_USER);
  93. for(JSONObject jsonObject : dataList) {
  94. List<SysUser> users = buildSysUserList(jsonObject.getJSONArray(LIST));
  95. //保存用户到用户表
  96. sysUserService.batchUser(users);
  97. userList.addAll(users);
  98. }
  99. return userList;
  100. }
  101. private List<SysUser> buildSysUserList(JSONArray jsonArray) {
  102. List<SysUser> userList = new ArrayList<>();
  103. for(int i = 0; i < jsonArray.size(); i++) {
  104. SysUser sysUser = new SysUser();
  105. JSONObject json = jsonArray.getJSONObject(i);
  106. sysUser.setUserId(json.getString("app_account__id"));
  107. sysUser.setUserName(json.getString("app_account__account_no"));
  108. sysUser.setNickName(json.getString("app_account__account_name"));
  109. //建科用户状态,启用:1,停用:0,删除:-1
  110. String status = json.getString("app_account__status");
  111. status = status.equals("1") ? "0" : "1";
  112. sysUser.setStatus(status);
  113. sysUser.setPhonenumber(json.getString("idt_user__mobile"));
  114. sysUser.setWorkNo(json.getString("idt_user__work_no"));
  115. sysUser.setEmail(json.getString("idt_user__email"));
  116. sysUser.setUserType(UserTypeEnum.JK_USER.getCode());//建科用户
  117. sysUser.setPassword(SecurityUtils.encryptPassword(jkConfig.getJkPsw()));
  118. JSONArray orgs = json.getJSONArray("orgs");
  119. if(orgs.size() > 0) {
  120. sysUser.setDeptId(orgs.getJSONObject(0).getLong("idt_org__id"));
  121. }
  122. userList.add(sysUser);
  123. }
  124. return userList;
  125. }
  126. /**
  127. * 通过建科接口获取建科部门信息
  128. */
  129. @Override
  130. public List<SysDept> getJkDepts() throws IOException {
  131. List<SysDept> deptList = new ArrayList<>();
  132. List<JSONObject> dataList = getApiData(jkConfig.getIamDeptUrl(),"部门");
  133. for(JSONObject jsonObject : dataList) {
  134. List<SysDept> depts = buildSysDeptList(jsonObject.getJSONArray(LIST));
  135. //保存用户到用户表
  136. sysDeptService.batchDept(depts);
  137. deptList.addAll(depts);
  138. }
  139. return deptList;
  140. }
  141. private List<SysDept> buildSysDeptList(JSONArray jsonArray) {
  142. List<SysDept> deptList = new ArrayList<>();
  143. for(int i = 0; i < jsonArray.size(); i++) {
  144. SysDept sysDept = new SysDept();
  145. JSONObject json = jsonArray.getJSONObject(i);
  146. sysDept.setDeptId(json.getString("idt_org__id"));
  147. sysDept.setDeptName(json.getString("idt_org__name"));
  148. sysDept.setParentId(json.getString("idt_org__parent_id"));
  149. sysDept.setAncestors(json.getString("idt_org__org_path").substring(1).replaceAll("/",","));
  150. //部门状态,启用:1,停用:0
  151. String status = json.getString("idt_org__status");
  152. status = status.equals("1") ? "0" : "1";
  153. sysDept.setStatus(status);
  154. deptList.add(sysDept);
  155. }
  156. return deptList;
  157. }
  158. /**
  159. * 通过建科接口获取建科岗位信息
  160. */
  161. @Override
  162. public List<SysPost> getJkPosts() throws IOException {
  163. List<SysPost> postList = new ArrayList<>();
  164. List<JSONObject> dataList = getApiData(jkConfig.getIamPostUrl(),"岗位");
  165. for(JSONObject jsonObject : dataList) {
  166. List<SysPost> posts = buildSysPostList(jsonObject.getJSONArray(LIST));
  167. //保存用户到用户表
  168. sysPostService.batchPost(posts);
  169. postList.addAll(posts);
  170. }
  171. return postList;
  172. }
  173. private List<SysPost> buildSysPostList(JSONArray jsonArray) {
  174. List<SysPost> postList = new ArrayList<>();
  175. for(int i = 0; i < jsonArray.size(); i++) {
  176. SysPost sysPost = new SysPost();
  177. JSONObject json = jsonArray.getJSONObject(i);
  178. sysPost.setPostCode(json.getString("idt_job__code"));
  179. sysPost.setPostName(json.getString("idt_job__name"));
  180. //部门状态,启用:1,停用:0
  181. String status = json.getString("idt_job__status");
  182. status = status.equals("1") ? "0" : "1";
  183. sysPost.setStatus(status);
  184. postList.add(sysPost);
  185. }
  186. return postList;
  187. }
  188. @Override
  189. public void getHxgProjectAndStaff() throws IOException {
  190. JSONArray dataList = getProjectApiData(jkConfig.getHxgProjectAndStaff(),HXG_PROJECT_AND_STAFF);
  191. buildAndSaveSysProjectAndStaff(dataList,HXG);
  192. }
  193. @Override
  194. public void getHjlProjectAndStaff() throws IOException {
  195. JSONArray dataList = getProjectApiData(jkConfig.getHjlProjectAndStaff(),HJL_PROJECT_AND_STAFF);
  196. buildAndSaveSysProjectAndStaff(dataList,HJL);
  197. }
  198. private void buildAndSaveSysProjectAndStaff(JSONArray jsonArray,String sourceFrom) {
  199. try {
  200. // ========== 核心解析:JSON数组 → List<Project> ==========
  201. List<ProjectWebApiBo> projectList = JSON.parseArray(String.valueOf(jsonArray), ProjectWebApiBo.class);
  202. int projectNum = 0;
  203. int projectStaffNum = 0;
  204. // 遍历解析结果,验证数据
  205. for (ProjectWebApiBo project : projectList) {
  206. SysProject sysProject = new SysProject();
  207. sysProject.setProjectPid(project.getProCode());
  208. sysProject.setProjectName(project.getProName());
  209. sysProject.setSourceFrom(sourceFrom);
  210. SysProject dbProject = projectService.selectSysProjectByProjectPid(project.getProCode());
  211. if(null == dbProject) {
  212. projectService.insertSysProject(sysProject);
  213. projectNum++;
  214. }
  215. for (Member member : project.getMemberList()) {
  216. SysProjectStaff sysProjectStaff = new SysProjectStaff();
  217. SysUser sysUser = sysUserService.selectUserByUserName(member.getAccountNo());
  218. if(sysUser != null) {
  219. sysProjectStaff.setProjectPid(project.getProCode());
  220. sysProjectStaff.setProjectName(project.getProName());
  221. sysProjectStaff.setUserId(null != sysUser ? sysUser.getUserId() : null);
  222. sysProjectStaff.setRoleId(null != sysUser ? sysUser.getRoleId() : null);
  223. SysProjectStaff dbStaff = projectStaffService.selectSysProjectStaff(sysProjectStaff);
  224. if(null == dbStaff) {
  225. projectStaffService.insertSysProjectStaff(sysProjectStaff);
  226. projectStaffNum++;
  227. }
  228. }
  229. }
  230. }
  231. if(sourceFrom.equals(HJL)){
  232. logger.info("项目同步任务同步慧监理项目数据"+projectNum+"条");
  233. logger.info("项目同步任务同步慧监理项目成员数据"+projectStaffNum+"条");
  234. } else {
  235. logger.info("项目同步任务同步慧项管项目数据"+projectNum+"条");
  236. logger.info("项目同步任务同步慧项管项目成员数据"+projectStaffNum+"条");
  237. }
  238. } catch (Exception e) {
  239. System.err.println("FastJSON2 解析失败:" + e.getMessage());
  240. e.printStackTrace();
  241. }
  242. }
  243. public List<JSONObject> getApiData(String url,String objectName) throws IOException {
  244. List<JSONObject> objectList = new ArrayList<>();
  245. int page = 1;
  246. int total = 1;
  247. logger.info("获取建科"+objectName+"请求url:" + url);
  248. while(total >= page){
  249. Request request = buildRequest(url,page);
  250. // 执行请求并获取响应
  251. // OkHttpClient client = buildOkHttpClient();
  252. try {
  253. Response response = client.newCall(request).execute();
  254. String responseBody = response.body().string();
  255. logger.info("获取建科"+objectName+"返回:" + responseBody);
  256. if (!response.isSuccessful()) {
  257. throw new IOException("获取建科"+objectName+"信息失败 " + responseBody);
  258. }
  259. JSONObject jsonObject =JSON.parseObject(responseBody);
  260. logger.info("获取建科"+objectName+"返回信息:" + jsonObject.toJSONString());
  261. //“0”为成功其余均为失败
  262. String code = jsonObject.getString("code");
  263. if (CODE_SUCCESS.equals(code)) {
  264. JSONObject dataObject = jsonObject.getJSONObject(DATA);
  265. //如果是用户接口,调用回调函数
  266. if(INTERFACE_USER.equals(objectName)) {
  267. doUserCallback(dataObject);
  268. }
  269. objectList.add(dataObject);
  270. total = dataObject.getInteger(TOTAL);
  271. page++;
  272. continue;
  273. } else {
  274. }
  275. } catch (IOException e) {
  276. throw new IOException("获取建科用"+objectName+"信息失败 ", e);
  277. }
  278. }
  279. return objectList;
  280. }
  281. public JSONArray getProjectApiData(String url,String objectName) throws IOException {
  282. JSONArray jsonArray = new JSONArray();
  283. logger.info("获取建科"+objectName+"请求url:" + url);
  284. Request request = buildPostRequest(url);
  285. try {
  286. OkHttpClient okHttpClient = buildOkHttpClient();
  287. Response response = okHttpClient.newCall(request).execute();
  288. String responseBody = response.body().string();
  289. logger.info("获取建科项目"+objectName+"返回:" + responseBody);
  290. if (!response.isSuccessful()) {
  291. throw new IOException("获取建科项目"+objectName+"信息失败 " + responseBody);
  292. }
  293. JSONObject jsonObject =JSON.parseObject(responseBody);
  294. logger.info("获取建科项目"+objectName+"返回信息:" + jsonObject.toJSONString());
  295. //“0”为成功其余均为失败
  296. String code = jsonObject.getString("code");
  297. if (code == null) {
  298. code = jsonObject.getString("statusCode");
  299. }
  300. if (CODE_SUCCESS.equals(code) ||"200".equals(code)) {
  301. jsonArray = jsonObject.getJSONArray(DATA);
  302. }
  303. } catch (IOException e) {
  304. throw new IOException("获取建科用项目"+objectName+"信息失败 ", e);
  305. }
  306. return jsonArray;
  307. }
  308. private boolean doUserCallback(JSONObject dataObject) {
  309. String ids = "";
  310. JSONArray jsonArray = dataObject.getJSONArray(LIST);
  311. for(int i = 0; i < jsonArray.size(); i++) {
  312. SysUser sysUser = new SysUser();
  313. JSONObject json = jsonArray.getJSONObject(i);
  314. if(!"".equals(ids)) {
  315. ids += ",";
  316. }
  317. ids += json.getString("request_log__id");
  318. }
  319. Request request = buildCallbackRequest(ids);
  320. int i = 0;
  321. while(i < 3) {//重试3次
  322. try {
  323. if(i > 0) {
  324. Thread.sleep(i*1000);
  325. }
  326. // OkHttpClient client = buildOkHttpClient();
  327. Response response = client.newCall(request).execute();
  328. String responseBody = response.body().string();
  329. logger.info("回调建科用户接口返回:" + responseBody);
  330. if (!response.isSuccessful()) {
  331. logger.error("回调建科用户接口失败 " + responseBody);
  332. i++;
  333. continue;
  334. }
  335. JSONObject jsonObject =JSON.parseObject(responseBody);
  336. //“0”为成功其余均为失败
  337. String code = jsonObject.getString("code");
  338. if (CODE_SUCCESS.equals(code)) {
  339. return true;
  340. }
  341. } catch (Exception e) {
  342. logger.error("回调建科用户接口息失败 ", e);
  343. i++;
  344. }
  345. }
  346. return false;
  347. }
  348. public Map<String, Object> getJkToken(String code, String redirectUrl) throws IOException {
  349. String token = "";
  350. JSONObject userJson = null;
  351. try {
  352. Request request = buildTokenRequest(code, redirectUrl);
  353. Response response = client.newCall(request).execute();
  354. String responseBody = response.body().string();
  355. logger.info("获取建科token返回信息:{}", responseBody);
  356. if (!response.isSuccessful()) {
  357. throw new IOException("获取建科token信息失败 " + responseBody);
  358. }
  359. JSONObject jsonObject = JSON.parseObject(responseBody);
  360. token = jsonObject.getString("access_token");
  361. if (!StringUtils.isEmpty(token)) {
  362. // token 换取用户信息
  363. Request pReq = buildProfileRequest(token);
  364. Response pResp = client.newCall(pReq).execute();
  365. String pRespBody = pResp.body().string();
  366. if (!pResp.isSuccessful()) {
  367. throw new IOException("token换取建科用户信息失败 " + pRespBody);
  368. }
  369. userJson = JSON.parseObject(pRespBody);
  370. logger.info("获取建科用户返回信息:{}", userJson.toJSONString());
  371. }
  372. } catch (IOException e) {
  373. logger.error("获取建科token失败,code:{}", code, e);
  374. throw new IOException("获取建科token信息失败 ", e);
  375. }
  376. if (userJson == null) {
  377. return null;
  378. }
  379. JSONObject attrs = userJson.getJSONObject("attributes");
  380. Map<String, Object> map = new HashMap<>();
  381. map.put("userId", attrs.getString("account_no"));
  382. map.put("nickName", attrs.getString("account_no"));
  383. map.put("token", token);
  384. return map;
  385. }
  386. private String createJkToken() {
  387. JWTCreator.Builder builder = JWT.create().withIssuer(jkConfig.getIamAppid());
  388. String sign = builder.withIssuedAt(new Date()).withJWTId(UUID.randomUUID().toString()).sign(Algorithm.HMAC256(jkConfig.getIamAppsecret()));
  389. String token = String.join(" ", BEARER, sign);
  390. return token;
  391. }
  392. private Request buildRequest(String url,int page) {
  393. Map<String, Object> requestBodyMap = new HashMap<>();
  394. requestBodyMap.put(PARAM_ST, getStartTimeBeforeDays(BEFORE_DAYS));
  395. requestBodyMap.put(PARAM_PAGE, page);
  396. requestBodyMap.put(PARAM_SIZE, DEFAULT_SIZE);
  397. // 将 Map 转换为 JSON 字符串
  398. String requestBodyJson = JSON.toJSONString(requestBodyMap);
  399. // 构建请求体
  400. RequestBody body = RequestBody.create(JSON_UTF8,requestBodyJson);
  401. Request request = new Request.Builder()
  402. .addHeader("accept", "*/*")
  403. .addHeader("Authorization", createJkToken())
  404. .addHeader("Content-Type", "application/json")
  405. .post(body)
  406. .url(url).build();
  407. logger.info("请求head:{}", request.headers().toString());
  408. logger.info("请求body:{}", requestBodyJson);
  409. return request;
  410. }
  411. private Request buildPostRequest(String url) {
  412. Map<String, Object> requestBodyMap = new HashMap<>();
  413. requestBodyMap.put("projectCode", "");
  414. // 将 Map 转换为 JSON 字符串
  415. String requestBodyJson = JSON.toJSONString(requestBodyMap);
  416. // 构建请求体
  417. RequestBody body = RequestBody.create(JSON_UTF8,requestBodyJson);
  418. Request request = new Request.Builder()
  419. .addHeader("accept", "*/*")
  420. .addHeader("Content-Type", "application/json")
  421. .post(body)
  422. .url(url).build();
  423. logger.info("请求head:{}", request.headers().toString());
  424. logger.info("请求body:{}", requestBodyJson);
  425. return request;
  426. }
  427. private Request buildTokenRequest(String code, String redirectUrl) {
  428. String completeUrl = jkConfig.getIamTokenUrl() + "?" +PARAM_GRANT_TYPE + "=" + GRANT_TYPE_AC
  429. + "&" +PARAM_CLIENT_ID + "=" + jkConfig.getIamClientID()
  430. + "&" +PARAM_CLIENT_SECRET + "=" + jkConfig.getIamClientSecret()
  431. + "&" +PARAM_CODE + "=" + code
  432. + "&" +PARAM_REDIRECT_URI + "=" + redirectUrl;
  433. // 构建请求体
  434. RequestBody body = RequestBody.create(JSON_UTF8,"");
  435. Request request = new Request.Builder()
  436. .addHeader("accept", "*/*")
  437. .addHeader("Content-Type", "application/json")
  438. .post(body)
  439. .url(completeUrl).build();
  440. logger.info("code换取token接口请求head:{}", request.headers().toString());
  441. logger.info("code换取token接口请求url:{}", completeUrl);
  442. return request;
  443. }
  444. private Request buildCallbackRequest(String ids) {
  445. Map<String, Object> requestBodyMap = new HashMap<>();
  446. requestBodyMap.put(PARAM_IDS, ids);
  447. requestBodyMap.put(PARAM_ERRORS, new ArrayList<>());
  448. // 将 Map 转换为 JSON 字符串
  449. String requestBodyJson = JSON.toJSONString(requestBodyMap);
  450. // 构建请求体
  451. RequestBody body = RequestBody.create(JSON_UTF8,requestBodyJson);
  452. Request request = new Request.Builder()
  453. .addHeader("accept", "*/*")
  454. .addHeader("Authorization", createJkToken())
  455. .addHeader("Content-Type", "application/json")
  456. .post(body)
  457. .url(jkConfig.getIamCallbackUrl()).build();
  458. logger.info("回调接口请求head:{}", request.headers().toString());
  459. logger.info("回调接口请求body:{}", requestBodyJson);
  460. return request;
  461. }
  462. private Request buildProfileRequest(String token) {
  463. // 构建带参数的 URL
  464. HttpUrl.Builder urlBuilder = HttpUrl.parse(jkConfig.getIamProfileUrl()).newBuilder();
  465. urlBuilder.addQueryParameter(PARAM_ACCESS_TOKEN, token);
  466. String url = urlBuilder.build().toString();
  467. Request request = new Request.Builder()
  468. .url(url)
  469. .get()
  470. .build();
  471. logger.info("token获取用户信息请求url", url);
  472. return request;
  473. }
  474. private String getStartTimeBeforeDays(int days) {
  475. //7天内数据
  476. return String.valueOf(DateUtils.getTimeBeforeDays(days));
  477. }
  478. private boolean isJsonObject(String data) {
  479. try {
  480. JSON.parseObject(data);
  481. return true;
  482. } catch (Exception e) {
  483. return false;
  484. }
  485. }
  486. private OkHttpClient buildOkHttpClient() {
  487. return new OkHttpClient.Builder()
  488. .connectTimeout(60, TimeUnit.SECONDS)
  489. .writeTimeout(50, TimeUnit.SECONDS)
  490. .readTimeout(60, TimeUnit.MINUTES)
  491. .build();
  492. }
  493. }