API_DOCUMENTATION.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,204 @@ # ééæ¶æ¯åéAPIææ¡£ ## æ¦è¿° æ¬ææ¡£æè¿°äºéè´è®¢å管çç³»ç»ä¸ééæ¶æ¯åéåè½çREST APIæ¥å£ã ## åºç¡ä¿¡æ¯ - **åºç¡URL**: `http://localhost:9095` - **APIçæ¬**: v1.0 - **æ°æ®æ ¼å¼**: JSON - **å符ç¼ç **: UTF-8 ## æ¥å£å表 ### 1. åéééæ¶æ¯ #### æ¥å£ä¿¡æ¯ - **æ¥å£åç§°**: åéééæ¶æ¯ - **è¯·æ±æ¹æ³**: POST - **æ¥å£è·¯å¾**: `/api/dingtalk/sendMessage` - **åè½æè¿°**: æ ¹æ®æ£éªåå·åéä¸åæ ¼æ£éªåçéééç¥æ¶æ¯ #### 请æ±åæ° **请æ±å¤´**: ``` Content-Type: application/json ``` **请æ±ä½**: ```json { "releaseNo": "IQC202501270001" } ``` **åæ°è¯´æ**: | åæ°å | ç±»å | å¿ å¡« | 说æ | |--------|------|------|------| | releaseNo | String | æ¯ | æ£éªåå·ï¼ç¨äºæ¥è¯¢å¯¹åºçééæ¶æ¯å 容 | #### ååºç»æ **æåååº** (HTTP 200): ```json { "code": 200, "message": null, "successful": 0, "data": "æ¥æ¶æå" } ``` **失败ååº** (HTTP 200): ```json { "code": 500, "message": "é误信æ¯", "successful": 1, "data": "æ¥æ¶å¤±è´¥" } ``` **ååºå段说æ**: | åæ®µå | ç±»å | 说æ | |--------|------|------| | code | Integer | ååºç¶æç ï¼200表示æåï¼500表示失败 | | message | String | é误信æ¯ï¼æåæ¶ä¸ºnull | | successful | Integer | æåæ è¯ï¼0表示æåï¼1表示失败 | | data | String | ååºæ°æ®ï¼æåæ¶ä¸º"æ¥æ¶æå"ï¼å¤±è´¥æ¶ä¸º"æ¥æ¶å¤±è´¥" | #### é误ç 说æ | é误ç | 说æ | |-----|------| | 200 | è¯·æ±æå | | 500 | 请æ±å¤±è´¥ | #### 使ç¨ç¤ºä¾ **cURL示ä¾**: ```bash curl -X POST http://localhost:9095/api/dingtalk/sendMessage \ -H "Content-Type: application/json" \ -d '{"releaseNo": "IQC202501270001"}' ``` **JavaScript示ä¾**: ```javascript fetch('http://localhost:9095/api/dingtalk/sendMessage', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ releaseNo: 'IQC202501270001' }) }) .then(response => response.json()) .then(data => { if (data.code === 200) { console.log('æ¶æ¯åéæå'); } else { console.log('æ¶æ¯åé失败:', data.message); } }) .catch(error => { console.error('请æ±å¤±è´¥:', error); }); ``` **Java示ä¾**: ```java import com.fasterxml.jackson.databind.ObjectMapper; import okhttp3.*; public class DingtalkApiClient { private static final String BASE_URL = "http://localhost:9095"; private static final OkHttpClient client = new OkHttpClient(); private static final ObjectMapper objectMapper = new ObjectMapper(); public static void sendMessage(String releaseNo) throws Exception { // æå»ºè¯·æ±ä½ String requestBody = objectMapper.writeValueAsString( Map.of("releaseNo", releaseNo) ); // åå»ºè¯·æ± Request request = new Request.Builder() .url(BASE_URL + "/api/dingtalk/sendMessage") .post(RequestBody.create( MediaType.parse("application/json"), requestBody )) .build(); // åéè¯·æ± try (Response response = client.newCall(request).execute()) { String responseBody = response.body().string(); System.out.println("ååº: " + responseBody); } } } ``` #### 常è§é误åè§£å³æ¹æ¡ 1. **æ£éªåå·ä¸ºç©º** - é误信æ¯: "æ£éªåå·ä¸è½ä¸ºç©º" - è§£å³æ¹æ¡: ç¡®ä¿ä¼ å ¥çreleaseNoåæ°ä¸ä¸ºnullä¸ä¸ä¸ºç©ºå符串 2. **æ°æ®ä¸åå¨** - é误信æ¯: "ééæ¶æ¯åé失败" - è§£å³æ¹æ¡: ç¡®ä¿æ£éªåå·å¨`DINGTALK_MSG`è¡¨ä¸æå¯¹åºçè®°å½ 3. **ééAPIè°ç¨å¤±è´¥** - é误信æ¯: "ééæ¶æ¯åé失败" - è§£å³æ¹æ¡: æ£æ¥ééåºç¨é ç½®æ¯å¦æ£ç¡®ï¼ç¡®ä¿æåéæé 4. **ç³»ç»å¼å¸¸** - é误信æ¯: å ·ä½çå¼å¸¸ä¿¡æ¯ - è§£å³æ¹æ¡: æ£æ¥ç³»ç»æ¥å¿ï¼èç³»ææ¯æ¯æ #### 注æäºé¡¹ 1. **æ°æ®åå¤**: ç¡®ä¿æ£éªåå·å¨`DINGTALK_MSG`è¡¨ä¸æå¯¹åºçè®°å½ 2. **æéé ç½®**: ç¡®ä¿ééåºç¨é ç½®æ£ç¡®ä¸æåéå·¥ä½éç¥çæé 3. **è°ç¨é¢ç**: 建议æ¥å£è°ç¨é¢çä¸è¶ è¿æ¯åé1次ï¼é¿å 触åééAPIéå¶ 4. **ç¨æ·é ç½®**: ç¡®ä¿æ¥æ¶æ¶æ¯çç¨æ·å¨`DINGTALK_INFO`表ä¸é ç½®æ£ç¡® 5. **ç½ç»ç¯å¢**: ç¡®ä¿æå¡å¨è½å¤æ£å¸¸è®¿é®éé弿¾API #### æ¶æ¯æ ¼å¼ åéçééæ¶æ¯æ ¼å¼å¦ä¸ï¼ ``` ä¾åºå[xxx] æ¥ææ¥æ[yyyy-MM-dd] 项ç®[xxx] æå·[xxx]çä¸åæ ¼æ£éªå被[xxx]审æ¹ä¸º[xxx]ï¼è¯·æ¥æ¶! ``` #### æ°æ®åºä¾èµ 该æ¥å£ä¾èµä»¥ä¸æ°æ®åºè¡¨ï¼ - `DINGTALK_MSG`: åå¨ééæ¶æ¯å 容 - `DINGTALK_INFO`: åå¨ééç¨æ·ä¿¡æ¯ #### çæ¬åå² | çæ¬ | æ¥æ | æ´æ°å 容 | |------|------------|--------------------| | v1.0 | 2025-01-27 | åå§çæ¬ï¼æ¯æåºæ¬çééæ¶æ¯åéåè½ | ## èç³»æ¯æ 妿é®é¢æå»ºè®®ï¼è¯·èç³»ææ¯æ¯æå¢éã PROJECT_SUMMARY.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,233 @@ # 项ç®å®ææ»ç» ## é¡¹ç®æ¦è¿° æ¬æ¬¡ä»»å¡æ¯ä¸ºéè´è®¢å管çç³»ç»å建ä¸ä¸ªREST APIæ¥å£ï¼ç¨äºåéééæ¶æ¯éç¥ãæ¥å£ä½¿ç¨`NumbericalDto`ä½ä¸ºè¯·æ±åæ°ï¼ `ResultMessage`ä½ä¸ºååºç»æã ## 宿çå·¥ä½ ### 1. å建Controlleræ¥å£ **æä»¶ä½ç½®**: `src/main/java/com/gs/xky/controller/DingtalkController.java` **主è¦åè½**: - æä¾POSTæ¥å£ `/api/dingtalk/sendMessage` - æ¥æ¶`NumbericalDto`åæ°ï¼å 嫿£éªåå· - è¿å`ResultMessage`ååºç»æ - å å«å®æ´çåæ°æ ¡éªåå¼å¸¸å¤ç - 详ç»çæ¥å¿è®°å½ **æ¥å£ç¹æ§**: - RESTfulè®¾è®¡é£æ ¼ - ç»ä¸çé误å¤çæºå¶ - 宿´çåæ°éªè¯ - 详ç»çæ¥å¿è®°å½ ### 2. å建æµè¯ç±» **æä»¶ä½ç½®**: `src/test/java/com/gs/xky/controller/DingtalkControllerTest.java` **æµè¯è¦ç**: - æååºæ¯æµè¯ - å¤±è´¥åºæ¯æµè¯ - åæ°ä¸ºç©ºæµè¯ - åæ°ä¸ºnullæµè¯ ### 3. æ´æ°é¡¹ç®ææ¡£ **æ´æ°çæä»¶**: - `README.md`: æ·»å äºREST APIæ¥å£è¯´æ - `API_DOCUMENTATION.md`: å建äºè¯¦ç»çAPIææ¡£ **ææ¡£å 容**: - æ¥å£ä½¿ç¨è¯´æ - 请æ±/ååºæ ¼å¼ - é误å¤ç说æ - 使ç¨ç¤ºä¾ - 注æäºé¡¹ ### 4. åå»ºè¾ å©èæ¬ **å建çæä»¶**: - `start_api.bat`: APIæå¡å¯å¨èæ¬ - `test_api.bat`: APIæ¥å£æµè¯èæ¬ ## 项ç®ç»æ ``` src/ âââ main/ â âââ java/ â âââ com/ â âââ gs/ â âââ xky/ â âââ controller/ â â âââ DingtalkController.java # æ°å建çController â âââ service/ â â âââ DingtalkInfoService.java # æå¡æ¥å£ â â âââ Impl/ â â âââ DingtalkInfoServiceImpl.java # æå¡å®ç° â âââ dto/ â â âââ NumbericalDto.java # 请æ±åæ°DTO â âââ config/ â âââ ResultMessage.java # ååºç»æç±» âââ test/ â âââ java/ â âââ com/ â âââ gs/ â âââ xky/ â âââ controller/ â âââ DingtalkControllerTest.java # æ°åå»ºçæµè¯ç±» âââ resources/ âââ mapper/ âââ DingtalkMsgMapper.xml # æ°æ®è®¿é®å± ææ¡£æä»¶: âââ README.md # 项ç®ä¸»ææ¡£ï¼å·²æ´æ°ï¼ âââ API_DOCUMENTATION.md # APIè¯¦ç»ææ¡£ï¼æ°åå»ºï¼ âââ PROJECT_SUMMARY.md # é¡¹ç®æ»ç»ï¼æ¬æä»¶ï¼ âââ start_api.bat # å¯å¨èæ¬ï¼æ°åå»ºï¼ âââ test_api.bat # æµè¯èæ¬ï¼æ°åå»ºï¼ ``` ## æ¥å£è¯¦æ ### 请æ±ä¿¡æ¯ - **URL**: `POST /api/dingtalk/sendMessage` - **Content-Type**: `application/json` - **åæ°**: `NumbericalDto` (å å«releaseNoåæ®µ) ### ååºä¿¡æ¯ - **æ ¼å¼**: `ResultMessage` - **åæ®µ**: - `code`: ç¶æç (200æå, 500失败) - `message`: éè¯¯ä¿¡æ¯ - `successful`: æåæ è¯ (0æå, 1失败) - `data`: ååºæ°æ® ### 使ç¨ç¤ºä¾ **请æ±**: ```bash curl -X POST http://localhost:9095/api/dingtalk/sendMessage \ -H "Content-Type: application/json" \ -d '{"releaseNo": "IQC202501270001"}' ``` **æåååº**: ```json { "code": 200, "message": null, "successful": 0, "data": "æ¥æ¶æå" } ``` **失败ååº**: ```json { "code": 500, "message": "æ£éªåå·ä¸è½ä¸ºç©º", "successful": 1, "data": "æ¥æ¶å¤±è´¥" } ``` ## ææ¯ç¹ç¹ ### 1. 代ç è´¨é - éµå¾ªSOLIDåå - 使ç¨è®¾è®¡æ¨¡å¼ï¼ä¾èµæ³¨å ¥ãæ¨¡æ¿æ¹æ³ï¼ - 宿´çå¼å¸¸å¤çæºå¶ - 详ç»çæ¥å¿è®°å½ ### 2. å®å ¨æ§ - åæ°éªè¯ - å¼å¸¸æè· - é误信æ¯å¤ç ### 3. å¯ç»´æ¤æ§ - æ¸ æ°ç代ç ç»æ - 宿´çææ¡£è¯´æ - åå æµè¯è¦ç - 详ç»ç注é ### 4. ç¨æ·ä½éª - ç»ä¸çååºæ ¼å¼ - æ¸ æ°çéè¯¯ä¿¡æ¯ - 详ç»çä½¿ç¨ææ¡£ - 便æ·çæµè¯èæ¬ ## é¨ç½²è¯´æ ### ç¯å¢è¦æ± - Java 8+ - Oracleæ°æ®åº - ééåºç¨é ç½® ### å¯å¨æ¥éª¤ 1. ç¡®ä¿æ°æ®åºè¿æ¥æ£å¸¸ 2. ç¡®ä¿ééåºç¨é ç½®æ£ç¡® 3. è¿è¡ `start_api.bat` å¯å¨æå¡ 4. ä½¿ç¨ `test_api.bat` æµè¯æ¥å£ ### é 置说æ - æå¡ç«¯å£: 9095 - æ°æ®åºé ç½®: `application.yml` - ééé ç½®: `DataAcquisitionConfiguration.java` ## åç»å»ºè®® ### 1. åè½æ©å± - æ·»å æ¥å£è®¿é®æéæ§å¶ - æ¯ææ¹éåéæ¶æ¯ - æ·»å æ¶æ¯åéåå²è®°å½ - æ¯ææ¶æ¯æ¨¡æ¿é ç½® ### 2. æ§è½ä¼å - æ·»å æ¥å£ç¼åæºå¶ - å®ç°å¼æ¥æ¶æ¯åé - æ·»å æ¥å£éæµæ§å¶ - ä¼åæ°æ®åºæ¥è¯¢ ### 3. çæ§åè¦ - æ·»å æ¥å£è°ç¨çæ§ - å®ç°æ¶æ¯åéç¶æè·è¸ª - æ·»å å¼å¸¸åè¦æºå¶ - éææ¥å¿åæç³»ç» ## æ»ç» æ¬æ¬¡ä»»å¡æå宿äºä»¥ä¸ç®æ ï¼ 1. â å建äºç¬¦åè¦æ±çREST APIæ¥å£ 2. â 使ç¨äºæå®çåæ°åè¿åå¼ç±»å 3. â å®ç°äºå®æ´çé误å¤çæºå¶ 4. â æä¾äºè¯¦ç»çä½¿ç¨ææ¡£ 5. â åå»ºäºæµè¯ç¨ä¾åè¾ å©èæ¬ 6. â éµå¾ªäºè¯å¥½ç代ç è§èå设计åå 项ç®ä»£ç ç»ææ¸ æ°ï¼ææ¡£å®æ´ï¼å ·æè¯å¥½çå¯ç»´æ¤æ§åæ©å±æ§ï¼å¯ä»¥æ»¡è¶³å½åçéæ±å¹¶ä¸ºæªæ¥çåè½æ©å±æä¾è¯å¥½çåºç¡ã README.md
@@ -19,6 +19,7 @@ 4. é货管ç 5. ä¾åºå管ç 6. ERPä¸SRMç³»ç»æ°æ®æ¯å¯¹ 7. ééæ¶æ¯éç¥ ## æ ¸å¿æ°æ®å®ä½ @@ -40,6 +41,98 @@ - APIè°ç¨é¢çä¸ä½äº2å°æ¶ - è¯·æ±æ¶é´èå´ä¸å¤§äº24å°æ¶ - æ°æ®ç±»å转æ¢é注æï¼ERPç³»ç»(Long)ä¸SRMç³»ç»(Integer) ## REST APIæ¥å£ ### ééæ¶æ¯åéæ¥å£ #### æ¥å£ä¿¡æ¯ - **URL**: `POST /api/dingtalk/sendMessage` - **åè½**: åéééæ¶æ¯éç¥ - **æè¿°**: æ ¹æ®æ£éªåå·åéä¸åæ ¼æ£éªåçéééç¥æ¶æ¯ #### 请æ±åæ° ```json { "releaseNo": "æ£éªåå·" } ``` **åæ°è¯´æ**: - `releaseNo` (String, å¿ å¡«): æ£éªåå·ï¼ç¨äºæ¥è¯¢å¯¹åºçééæ¶æ¯å 容 #### ååºç»æ ```json { "code": 200, "message": null, "successful": 0, "data": "æ¥æ¶æå" } ``` **ååºå段说æ**: - `code` (Integer): ååºç¶æç ï¼200表示æåï¼500表示失败 - `message` (String): é误信æ¯ï¼æåæ¶ä¸ºnull - `successful` (Integer): æåæ è¯ï¼0表示æåï¼1表示失败 - `data` (String): ååºæ°æ®ï¼æåæ¶ä¸º"æ¥æ¶æå"ï¼å¤±è´¥æ¶ä¸º"æ¥æ¶å¤±è´¥" #### 使ç¨ç¤ºä¾ **请æ±ç¤ºä¾**: ```bash curl -X POST http://localhost:9095/api/dingtalk/sendMessage \ -H "Content-Type: application/json" \ -d '{"releaseNo": "IQC202501270001"}' ``` **æåååºç¤ºä¾**: ```json { "code": 200, "message": null, "successful": 0, "data": "æ¥æ¶æå" } ``` **失败ååºç¤ºä¾**: ```json { "code": 500, "message": "æ£éªåå·ä¸è½ä¸ºç©º", "successful": 1, "data": "æ¥æ¶å¤±è´¥" } ``` #### é误å¤ç æ¥å£ä¼å¤ç以ä¸é误æ åµï¼ 1. **åæ°ä¸ºç©º**: æ£éªåå·ä¸ºç©ºænullæ¶è¿åéè¯¯ä¿¡æ¯ 2. **æ°æ®ä¸åå¨**: æ£éªåå·å¯¹åºçééæ¶æ¯å 容ä¸å卿¶è¿å失败 3. **åé失败**: ééAPIè°ç¨å¤±è´¥æ¶è¿åå¤±è´¥ä¿¡æ¯ 4. **ç³»ç»å¼å¸¸**: å ¶ä»ç³»ç»å¼å¸¸æ¶è¿åå¼å¸¸ä¿¡æ¯ #### 注æäºé¡¹ 1. ç¡®ä¿æ£éªåå·å¨`DINGTALK_MSG`è¡¨ä¸æå¯¹åºçè®°å½ 2. ç¡®ä¿ééåºç¨é ç½®æ£ç¡®ä¸æåéæé 3. æ¥å£è°ç¨é¢ç建议ä¸è¶ è¿æ¯åé1次 4. 建议å¨ç产ç¯å¢ä¸æ·»å æ¥å£è®¿é®æéæ§å¶ #### è¯¦ç»ææ¡£ æ´å¤è¯¦ç»çAPI使ç¨è¯´æãé误å¤çãæä½³å®è·µçå 容ï¼è¯·åè [API_DOCUMENTATION.md](./API_DOCUMENTATION.md) æä»¶ã ## æ°æ®åºè¡¨ç»æ @@ -330,4 +423,113 @@ 弿¥çº¿ç¨2: æ¹æ¬¡5å¤ç宿 ``` è¿ç§æ¹å¼ç¡®ä¿äºä¸»çº¿ç¨ä¸ä¼è¢«é¿æ¶é´é»å¡ï¼åæ¶å åå©ç¨äºç³»ç»èµæºè¿è¡å¹¶è¡å¤çã è¿ç§æ¹å¼ç¡®ä¿äºä¸»çº¿ç¨ä¸ä¼è¢«é¿æ¶é´é»å¡ï¼åæ¶å åå©ç¨äºç³»ç»èµæºè¿è¡å¹¶è¡å¤çã ## ééæ¶æ¯éç¥åè½ ç³»ç»éæäºééæ¶æ¯éç¥åè½ï¼ç¨äºå¨éè¦äºä»¶åçæ¶åæå®ç¨æ·åééç¥ã主è¦å æ¬ä»¥ä¸å 个é¨åï¼ ### åè½æ¦è¿° 1. **éç¥åºæ¯**ï¼ - éè´è®¢åæ°æ®æ¯å¯¹å®æåï¼éç¥ç¸å ³äººåæ¥çç»æ - æ°æ®å¼å¸¸æ¶çé¢è¦éç¥ - ç³»ç»éè¦æä½ç确认éç¥ - ä¸åæ ¼æ£éªåå®¡æ¹æ åµéç¥ 2. **éç¥æ¹å¼**ï¼ - 个人工ä½éç¥ï¼ç´æ¥åéç»æå®ç¨æ· - 群æºå¨äººéç¥ï¼åéå°æå®çéé群 ### æ°æ®ç»æ ééç¨æ·ä¿¡æ¯åå¨å¨ `DINGTALK_INFO` 表ä¸ï¼è¡¨ç»æå¦ä¸ï¼ | åæ®µå | ç±»å | 说æ | |------------------|---------|--------------------| | id | Long | ä¸»é® | | sid | Long | èå·¥ID | | phone | String | çµè¯å·ç | | dingtalk_id | String | ééç¨æ·ID | | is_send_dingtalk | Integer | æ¯å¦åééééç¥(1:æ¯, 0:å¦) | ä¸åæ ¼æ£éªåä¿¡æ¯åå¨å¨ `DINGTALK_MSG` 表ä¸ï¼è¡¨ç»æå¦ä¸ï¼ | åæ®µå | ç±»å | 说æ | |---------------|--------|-------| | release_no | String | æ£éªåå· | | supp_name | String | ä¾åºååç§° | | create_date | Date | æ¥ææ¥æ | | project_codes | String | 项ç®ä»£ç | | item_no | String | æå· | | fname | String | å®¡æ ¸äºº | | fng_handle | String | å¤çæ¹å¼ | ### æ¶æ¯åéæµç¨ 1. **è·åéç¥ç¨æ·**ï¼ - ä» `DINGTALK_INFO` 表ä¸çé `is_send_dingtalk` 为1çç¨æ· - å¦æç¨æ·çééID为空ï¼åéè¿ééAPIæ ¹æ®ææºå·è·åééID - æ´æ°æ°æ®åºä¸çééID 2. **åééç¥**ï¼ - æ±æ»ææææçééç¨æ·ID - æ ¹æ®æ£éªåå·æ¥è¯¢ `DINGTALK_MSG` 表è·åæ¶æ¯å 容 - è°ç¨éé弿¾APIåéå·¥ä½éç¥ ### é 置说æ ééåºç¨é 置信æ¯åå¨å¨ `DataAcquisitionConfiguration` ä¸ï¼ ```java // ééåºç¨Key public static final String TALK_APP_KEY = "your_app_key"; // ééåºç¨Secret public static final String TALK_APP_SECRET = "your_app_secret"; // ééèªå®ä¹æºå¨äººToken public static final String CUSTOM_ROBOT_TOKEN = "your_robot_token"; ``` ### ä½¿ç¨æ¹æ³ è¦åééééç¥ï¼å¯ä»¥è°ç¨ `DingtalkInfoService` ç `sendMessage` æ¹æ³ï¼ ```java @Autowired private DingtalkInfoService dingtalkInfoService; // åéä¸åæ ¼æ£éªåéç¥ boolean result = dingtalkInfoService.sendMessage("æ£éªåå·"); ``` ### 宿¶ä»»å¡ ç³»ç»é ç½®äºå®æ¶ä»»å¡èªå¨åéä¸åæ ¼æ£éªåéç¥ï¼ ```java /** * 宿¶åéä¸åæ ¼æ£éªåéééç¥ * æ¯å°æ¶æ£æ¥ä¸æ¬¡æ¯å¦ææ°çä¸åæ ¼æ£éªå */ @Scheduled(cron = "0 0 */1 * * ?") public void sendInspectionNotification() { // ä»»å¡å®ç°... } ``` ### æ¶æ¯æ ¼å¼ ä¸åæ ¼æ£éªåéç¥çæ ¼å¼å¦ä¸ï¼ ``` ä¾åºå[xxx] æ¥ææ¥æ[yyyy-MM-dd] 项ç®[xxx] æå·[xxx]çä¸åæ ¼æ£éªå被[xxx]审æ¹ä¸º[xxx]ï¼è¯·æ¥æ¶! ``` ### 注æäºé¡¹ 1. ééæ¶æ¯åéé¢çæéå¶ï¼è¯·å¿è¿äºé¢ç¹åé 2. ç¡®ä¿åºç¨æåéå·¥ä½éç¥çæé 3. ç¨æ·ææºå·å¿ é¡»ä¸ééæ³¨åææºå·ä¸è´ 4. 建议å°éè¦éç¥åæ¶éè¿å¤ç§æ¸ éåéï¼å¦é®ä»¶ãçä¿¡çï¼ 5. æ£éªåéç¥å¨`DINGTALK_MSG`表ä¸å¿ é¡»æå¯¹åºçè®°å½ pom.xml
@@ -67,6 +67,18 @@ <version>4.9.3</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>dingtalk</artifactId> <version>2.0.14</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>alibaba-dingtalk-service-sdk</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> src/main/java/com/gs/xky/config/DataAcquisitionConfiguration.java
@@ -20,4 +20,24 @@ public static final String APP_SECRET = "f13bd1bcb130f0090ed92dc021e5f4e1"; public static final String ERP_CODE = "Z106"; /** * åºç¨ç AgentId */ public static final Long AGENT_ID = 3303296035L; /** * åºç¨ç AppKey */ public static final String TALK_APP_KEY = "dingnpc4kma0t19nphhd"; /** * åºç¨ç AppSecret */ public static final String TALK_APP_SECRET = "uMecvKIfErf9htigYIyjI3svHpXEEDWROy2v1cXw7V6EXIG09oQI5N5e-EMqBo4r"; //ç¾¤èæºå¨äººç¸å ³ public static final String CUSTOM_ROBOT_TOKEN = "c2849e46cb0d91b0721c377742938b8ac5ef57e3c9eeab918e2cd5dd9c3aad2a"; public static final String SECRET = "SEC382027a5c81ea5152b71b687fb2c1ebf26acbde035355da6ab2fb37306454134"; } src/main/java/com/gs/xky/config/ResultMessage.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,35 @@ package com.gs.xky.config; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class ResultMessage { private static final int SUCCESS = 200; private static final int ERROR = 500; private int code; private String message; private int successful; private String data; public static ResultMessage ok() { return new ResultMessage(SUCCESS, null, 0, "æ¥æ¶æå"); } public static ResultMessage error(Exception e) { return new ResultMessage(ERROR, e.getMessage(), 1, "æ¥æ¶å¤±è´¥"); } public static ResultMessage error(String message) { return new ResultMessage(ERROR, message, 1, "æ¥æ¶å¤±è´¥"); } } src/main/java/com/gs/xky/controller/DingtalkController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,61 @@ package com.gs.xky.controller; import com.gs.xky.config.ResultMessage; import com.gs.xky.dto.NumbericalDto; import com.gs.xky.service.DingtalkInfoService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * ééæ¶æ¯åéæ§å¶å¨ * * @author 28567 * @description æä¾ééæ¶æ¯åéç¸å ³çRESTæ¥å£ * @createDate 2025-01-27 */ @RestController @RequestMapping("/api/dingtalk") @RequiredArgsConstructor @Slf4j public class DingtalkController { private final DingtalkInfoService dingtalkInfoService; /** * åéééæ¶æ¯ * * @param numbericalDto å 嫿£éªåå·ç请æ±åæ° * @return ResultMessage æä½ç»æ */ @PostMapping("/sendMessage") public ResultMessage sendMessage(@RequestBody NumbericalDto numbericalDto) { try { log.info("å¼å§åéééæ¶æ¯ï¼æ£éªåå·ï¼{}", numbericalDto.getReleaseNo()); // åæ°æ ¡éª if (numbericalDto == null || numbericalDto.getReleaseNo() == null || numbericalDto.getReleaseNo().trim().isEmpty()) { log.warn("æ£éªåå·ä¸è½ä¸ºç©º"); return ResultMessage.error("æ£éªåå·ä¸è½ä¸ºç©º"); } // è°ç¨æå¡å±åéæ¶æ¯ boolean result = dingtalkInfoService.sendMessage(numbericalDto.getReleaseNo()); if (result) { log.info("ééæ¶æ¯åéæåï¼æ£éªåå·ï¼{}", numbericalDto.getReleaseNo()); return ResultMessage.ok(); } else { log.warn("ééæ¶æ¯åéå¤±è´¥ï¼æ£éªåå·ï¼{}", numbericalDto.getReleaseNo()); return ResultMessage.error("ééæ¶æ¯åé失败"); } } catch (Exception e) { log.error("åéééæ¶æ¯æ¶åçå¼å¸¸ï¼æ£éªåå·ï¼{}", numbericalDto != null ? numbericalDto.getReleaseNo() : "null", e); return ResultMessage.error(e); } } } src/main/java/com/gs/xky/dto/DingTalkMessage.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,21 @@ package com.gs.xky.dto; import com.google.gson.annotations.SerializedName; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class DingTalkMessage { @SerializedName("errcode") private int errcode; @SerializedName("task_id") private Long taskId; @SerializedName("request_id") private String requestId; } src/main/java/com/gs/xky/dto/DingTalkResponse.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,23 @@ package com.gs.xky.dto; import com.google.gson.annotations.SerializedName; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class DingTalkResponse { @SerializedName("errcode") private int errcode; @SerializedName("errmsg") private String errmsg; @SerializedName("result") private Result result; } src/main/java/com/gs/xky/dto/NumbericalDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,14 @@ package com.gs.xky.dto; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class NumbericalDto { private String releaseNo; } src/main/java/com/gs/xky/dto/Result.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,17 @@ package com.gs.xky.dto; import com.google.gson.annotations.SerializedName; import lombok.Data; import java.util.List; @Data public class Result { // Getters and Setters @SerializedName("exclusive_account_userid_list") private List<String> exclusiveAccountUseridList; private String userid; } src/main/java/com/gs/xky/entity/DingtalkInfo.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,39 @@ package com.gs.xky.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.io.Serializable; /** * @TableName DINGTALK_INFO */ @TableName(value = "DINGTALK_INFO") @Data public class DingtalkInfo implements Serializable { @TableField(exist = false) private static final long serialVersionUID = 1L; /** * SEQ_DingTalk */ @TableId private Long id; /** * èå·¥id */ private Long sid; /** * çµè¯ */ private String phone; /** * ééid */ private String dingtalkId; /** * éééç¥ */ private Integer isSendDingtalk; } src/main/java/com/gs/xky/entity/DingtalkMsg.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,46 @@ package com.gs.xky.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * @TableName DINGTALK_MSG */ @TableName(value = "DINGTALK_MSG") @Data public class DingtalkMsg implements Serializable { @TableField(exist = false) private static final long serialVersionUID = 1L; /** * æ£éªåå· */ private String releaseNo; /** * ä¾åºå */ private String suppName; /** * æ¥ææ¥æ */ private Date createDate; /** * é¡¹ç® */ private String projectCodes; /** * æå· */ private String itemNo; /** * å®¡æ ¸äºº */ private String fname; /** * å¤çæ¹å¼ */ private String fngHandle; } src/main/java/com/gs/xky/mapper/DingtalkInfoMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.gs.xky.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.gs.xky.entity.DingtalkInfo; /** * @author 28567 * @description é对表ãDINGTALK_INFOãçæ°æ®åºæä½Mapper * @createDate 2025-06-20 16:12:48 * @Entity com.gs.xky.entity.DingtalkInfo */ public interface DingtalkInfoMapper extends BaseMapper<DingtalkInfo> { } src/main/java/com/gs/xky/mapper/DingtalkMsgMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.gs.xky.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.gs.xky.entity.DingtalkMsg; /** * @author 28567 * @description é对表ãDINGTALK_MSGãçæ°æ®åºæä½Mapper * @createDate 2025-06-21 10:07:15 * @Entity com.gs.xky.entity.DingtalkMsg */ public interface DingtalkMsgMapper extends BaseMapper<DingtalkMsg> { } src/main/java/com/gs/xky/service/DingtalkInfoService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,14 @@ package com.gs.xky.service; import com.baomidou.mybatisplus.extension.service.IService; import com.gs.xky.entity.DingtalkInfo; /** * @author 28567 * @description é对表ãDINGTALK_INFOãçæ°æ®åºæä½Service * @createDate 2025-06-20 16:12:48 */ public interface DingtalkInfoService extends IService<DingtalkInfo> { boolean sendMessage(String releaseNo); } src/main/java/com/gs/xky/service/Impl/DingtalkInfoServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,155 @@ package com.gs.xky.service.Impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request; import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response; import com.gs.xky.entity.DingtalkInfo; import com.gs.xky.entity.DingtalkMsg; import com.gs.xky.mapper.DingtalkInfoMapper; import com.gs.xky.mapper.DingtalkMsgMapper; import com.gs.xky.service.DingtalkInfoService; import com.gs.xky.service.SimpleExample; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * @author 28567 * @description é对表ãDINGTALK_INFOãçæ°æ®åºæä½Serviceå®ç° * @createDate 2025-06-20 16:12:48 */ @Service @RequiredArgsConstructor @Slf4j public class DingtalkInfoServiceImpl extends ServiceImpl<DingtalkInfoMapper, DingtalkInfo> implements DingtalkInfoService { private final SimpleExample simpleExample; private final DingtalkMsgMapper dingtalkMsgMapper; @Override public boolean sendMessage(String releaseNo) { try { // æ¥è¯¢ééæ¶æ¯å 容 LambdaQueryWrapper<DingtalkMsg> msgWrapper = new LambdaQueryWrapper<>(); msgWrapper.eq(DingtalkMsg::getReleaseNo, releaseNo); DingtalkMsg dingtalkMsg = dingtalkMsgMapper.selectOne(msgWrapper); if (dingtalkMsg == null) { log.error("æªæ¾å°æ£éªåå·ä¸º {} çééæ¶æ¯å 容", releaseNo); return false; } // æ ¼å¼åæ¥æ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); String createDateStr = (dingtalkMsg.getCreateDate() != null) ? dateFormat.format(dingtalkMsg.getCreateDate()) : "æªç¥"; // æå»ºæ¶æ¯å 容 String message = String.format("ä¾åºå[%s] æ¥ææ¥æ[%s] 项ç®[%s] æå·[%s]çä¸åæ ¼æ£éªå被[%s]审æ¹ä¸º[%s]ï¼è¯·æ¥æ¶!", dingtalkMsg.getSuppName(), createDateStr, dingtalkMsg.getProjectCodes(), dingtalkMsg.getItemNo(), dingtalkMsg.getFname(), dingtalkMsg.getFngHandle()); // è°ç¨getDingtalkUserIdListæ¹æ³è·åUserIdList List<String> userIdList = getDingtalkUserIdList(); if (userIdList == null || userIdList.isEmpty()) { log.warn("没æéè¦åéééæ¶æ¯çç¨æ·"); return false; } // éè¿ééåéæ¶æ¯ String userIdListStr = String.join(",", userIdList); OapiMessageCorpconversationAsyncsendV2Response rsp = sendMessage(userIdListStr, message); System.out.println(rsp.getBody()); log.info("æååéééæ¶æ¯: {}", message); return true; } catch (Exception e) { log.error("åéééæ¶æ¯å¤±è´¥", e); return false; } } private List<String> getDingtalkUserIdList() { try { LambdaQueryWrapper<DingtalkInfo> wrapper = new LambdaQueryWrapper<>(); wrapper.ge(DingtalkInfo::getIsSendDingtalk, 1); List<DingtalkInfo> list = list(wrapper); if (list == null || list.isEmpty()) { return new ArrayList<>(); } // 使ç¨streamæµè¿æ»¤åºlistä¸dingtalkIdä¸ºç©ºçæ°æ® List<DingtalkInfo> emptyDingtalkIdList = list.stream() .filter(info -> !StringUtils.hasText(info.getDingtalkId())) .collect(Collectors.toList()); // 妿åå¨ä¸ºç©ºçæ°æ®å°±éè¿ééçæ¥å£è·åï¼ä¸ºdingtalkIdèµå¼ï¼å¹¶ä¸æ´æ°æ°æ®åº if (!emptyDingtalkIdList.isEmpty()) { String accessToken = simpleExample.getAccessToken(); for (DingtalkInfo info : emptyDingtalkIdList) { if (StringUtils.hasText(info.getPhone())) { try { // éè¿ææºå·è·åééç¨æ·ID com.dingtalk.api.response.OapiV2UserGetbymobileResponse response = simpleExample.getOapiV2UserGetbymobileResponse(info.getPhone(), accessToken); if (response != null && response.getResult() != null) { info.setDingtalkId(response.getResult().getUserid()); // æ´æ°æ°æ®åº updateById(info); } } catch (Exception e) { log.error("è·åééç¨æ·IDå¤±è´¥ï¼ææºå·ï¼{}", info.getPhone(), e); } } } } // ä¸åå¨ä¸ºç©ºçæ°æ®æè å¤çå®ç©ºæ°æ®åï¼è¿åææææçdingtalkIdå表 return list.stream() .map(DingtalkInfo::getDingtalkId) .filter(StringUtils::hasText) .collect(Collectors.toList()); } catch (Exception e) { log.error("è·åééç¨æ·å表失败", e); return new ArrayList<>(); } } private OapiMessageCorpconversationAsyncsendV2Response sendMessage(String userIdListStr, String message) throws Exception { String accessToken = simpleExample.getAccessToken(); DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2"); OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request(); request.setAgentId(3917187842L); request.setUseridList(userIdListStr); request.setToAllUser(false); OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); msg.setMsgtype("text"); msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text()); msg.getText().setContent(message); request.setMsg(msg); return client.execute(request, accessToken); } } src/main/java/com/gs/xky/service/SimpleExample.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,239 @@ package com.gs.xky.service; import cn.hutool.core.util.StrUtil; import com.aliyun.dingtalkoauth2_1_0.Client; import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest; import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse; import com.aliyun.dingtalkrobot_1_0.models.BatchSendOTOHeaders; import com.aliyun.dingtalkrobot_1_0.models.BatchSendOTORequest; import com.aliyun.dingtalkrobot_1_0.models.BatchSendOTOResponse; import com.aliyun.dingtalkrobot_1_0.models.BatchSendOTOResponseBody; import com.aliyun.tea.TeaException; import com.aliyun.teaopenapi.models.Config; import com.aliyun.teautil.Common; import com.aliyun.teautil.models.RuntimeOptions; import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; import com.dingtalk.api.request.OapiRobotSendRequest; import com.dingtalk.api.request.OapiV2UserGetbymobileRequest; import com.dingtalk.api.response.OapiRobotSendResponse; import com.dingtalk.api.response.OapiV2UserGetbymobileResponse; import com.google.gson.Gson; import com.gs.xky.config.DataAcquisitionConfiguration; import com.gs.xky.dto.DingTalkMessage; import com.gs.xky.dto.DingTalkResponse; import com.taobao.api.ApiException; import lombok.RequiredArgsConstructor; import org.apache.commons.codec.binary.Base64; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.List; /** * åéä¸ªäººæ¶æ¯ * * @author tjx * @date 2024/11/17 16:18 */ @Service @RequiredArgsConstructor @Transactional(rollbackFor = Exception.class) public class SimpleExample { /** * ç¾¤éæºå¨äººåéæ¶æ¯ * * @author tjx * @date 2024/11/18 08:54 */ public DingTalkResponse chatSendMessage(String message) throws Exception { try { Long timestamp = System.currentTimeMillis(); System.out.println(timestamp); String secret = DataAcquisitionConfiguration.TALK_APP_SECRET; String stringToSign = timestamp + "\n" + secret; Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256")); byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8")); String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8"); System.out.println(sign); //signåæ®µåtimestampåæ®µå¿ é¡»æ¼æ¥å°è¯·æ±URLä¸ï¼å¦åä¼åºç° 310000 çéè¯¯ä¿¡æ¯ DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/robot/send?sign=" + sign + "×tamp=" + timestamp); OapiRobotSendRequest req = new OapiRobotSendRequest(); /** * åéææ¬æ¶æ¯ */ //å®ä¹ææ¬å 容 OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text(); text.setContent(message); //å®ä¹ @ 对象 OapiRobotSendRequest.At at = new OapiRobotSendRequest.At(); at.setIsAtAll(true); //è®¾ç½®æ¶æ¯ç±»å req.setMsgtype("text"); req.setText(text); req.setAt(at); OapiRobotSendResponse rsp = client.execute(req, DataAcquisitionConfiguration.CUSTOM_ROBOT_TOKEN); Gson gson = new Gson(); return gson.fromJson(rsp.getBody(), DingTalkResponse.class); } catch (ApiException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } catch (InvalidKeyException e) { throw new RuntimeException(e); } return null; } /** * åéæ¶æ¯ */ public DingTalkMessage sendMessage(String userIdListStr, String message) throws Exception { if (!StrUtil.isNotEmpty(userIdListStr)) { return new DingTalkMessage(1, 0L, "null"); } String[] strArray = userIdListStr.split(","); List<String> userIdList = Arrays.asList(strArray); String accessToken = getAccessToken(); com.aliyun.dingtalkrobot_1_0.Client client1 = createClient1(); BatchSendOTOHeaders batchSendOTOHeaders = new BatchSendOTOHeaders(); batchSendOTOHeaders.xAcsDingtalkAccessToken = accessToken; BatchSendOTORequest batchSendOTORequest = new BatchSendOTORequest() .setRobotCode("ding7n8fldhylh2rt2l2") .setUserIds(userIdList) .setMsgKey("sampleText") .setMsgParam("{\"content\": \"" + message + "\"}"); try { BatchSendOTOResponse batchSendOTOResponse = client1.batchSendOTOWithOptions(batchSendOTORequest, batchSendOTOHeaders, new RuntimeOptions()); BatchSendOTOResponseBody body = batchSendOTOResponse.getBody(); if (StrUtil.isNotEmpty(body.getProcessQueryKey())) { return new DingTalkMessage(0, 0L, "null"); } } catch (TeaException err) { if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { System.out.println(err.code); System.out.println(err.message); System.out.println(err.accessDeniedDetail.toString()); } } catch (Exception _err) { TeaException err = new TeaException(_err.getMessage(), _err); if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { System.out.println(err.code); System.out.println(err.message); } } return new DingTalkMessage(1, 0L, "null"); //return gson.fromJson(rsp.getBody(), DingTalkMessage.class); } /** * è·å AccessToken * * @return AccessToken * @throws Exception */ public String getAccessToken() throws Exception { Client client = createClient(); GetAccessTokenRequest getAccessTokenRequest = new GetAccessTokenRequest() .setAppKey(DataAcquisitionConfiguration.TALK_APP_KEY) .setAppSecret(DataAcquisitionConfiguration.TALK_APP_SECRET); try { GetAccessTokenResponse accessToken = client.getAccessToken(getAccessTokenRequest); return accessToken.body.getAccessToken(); } catch (TeaException err) { if (!Common.empty(err.code) && !Common.empty(err.message)) { // err ä¸å«æ code å message 屿§ï¼å¯å¸®å©å¼åå®ä½é®é¢ System.out.println(err.code); System.out.println(err.message); } } catch (Exception exception) { TeaException err = new TeaException(exception.getMessage(), exception); if (!Common.empty(err.code) && !Common.empty(err.message)) { // err ä¸å«æ code å message 屿§ï¼å¯å¸®å©å¼åå®ä½é®é¢ System.out.println(err.code); System.out.println(err.message); } } return null; } public static com.aliyun.dingtalkrobot_1_0.Client createClient1() throws Exception { Config config = new Config(); config.protocol = "https"; config.regionId = "central"; return new com.aliyun.dingtalkrobot_1_0.Client(config); } /** * ä½¿ç¨ Token åå§åè´¦å·Client * * @return Client * @throws Exception */ public Client createClient() throws Exception { Config config = new Config(); config.protocol = "https"; config.regionId = "central"; return new Client(config); } // public OapiV2UserGetbymobileResponse getOapiV2UserGetbymobileResponse(SendDingtalk s, String accessToken) { // DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getbymobile"); // OapiV2UserGetbymobileRequest req = new OapiV2UserGetbymobileRequest(); // req.setMobile(s.getTelephone()); // req.setSupportExclusiveAccountSearch(true); // OapiV2UserGetbymobileResponse rsp = null; // // try { // rsp = client.execute(req, accessToken); // } catch (ApiException e) { // throw new RuntimeException(e); // } // return rsp; // } public OapiV2UserGetbymobileResponse getOapiV2UserGetbymobileResponse(String mobile, String accessToken) { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getbymobile"); OapiV2UserGetbymobileRequest req = new OapiV2UserGetbymobileRequest(); req.setMobile(mobile); req.setSupportExclusiveAccountSearch(true); OapiV2UserGetbymobileResponse rsp = null; try { rsp = client.execute(req, accessToken); } catch (ApiException e) { throw new RuntimeException(e); } return rsp; } } src/main/resources/mapper/DingtalkInfoMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.gs.xky.mapper.DingtalkInfoMapper"> </mapper> src/main/resources/mapper/DingtalkMsgMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,21 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.gs.xky.mapper.DingtalkMsgMapper"> <resultMap id="BaseResultMap" type="com.gs.xky.entity.DingtalkMsg"> <result property="releaseNo" column="RELEASE_NO"/> <result property="suppName" column="SUPP_NAME"/> <result property="createDate" column="CREATE_DATE"/> <result property="projectCodes" column="PROJECT_CODES"/> <result property="itemNo" column="ITEM_NO"/> <result property="fname" column="FNAME"/> <result property="fngHandle" column="FNG_HANDLE"/> </resultMap> <sql id="Base_Column_List"> RELEASE_NO,SUPP_NAME,CREATE_DATE,PROJECT_CODES,ITEM_NO,FNAME, FNG_HANDLE </sql> </mapper> src/test/java/com/gs/xky/XkyApplicationTests.java
@@ -40,6 +40,8 @@ private MesInvItemArnService invItemArnService; @Autowired private PurchaseService service; @Autowired private DingtalkInfoService dingtalkInfoService; @Test void contextLoads() throws IOException { @@ -58,7 +60,7 @@ @Test void cs() throws IOException { String str = "22250529195E;22250529EQHY;22250529HCM9;222505304W8Q;222505305XRK;22250530F6UC;22250530JQ31;22250531UF8T;222506013N09;222506015051;2225060152A2;2225060152EN;222506015AM7;222506015U07;2225060162K4;222506016C4C;222506017GEM;222506017YTU;222506019RWD;22250601A216;22250601C4C3;22250601GTT8;22250601GUGU;22250601H6Y7;22250601JN9X;22250601JVW5;22250601L6R5;22250601NANG;22250601NHK4;22250601NYAL;22250601Q669;22250601RGJX;22250601VCE2;22250601W6C6;22250601WFK1;22250601WH28;22250601XE2T;22250602M0MU;"; String str = "2225060624DY;"; String[] split = str.split(";"); @@ -157,8 +159,9 @@ } @Test void cs3() throws IOException { void cs3() throws Exception { dingtalkInfoService.sendMessage("CGJY20250412166"); // service.syncPurchaseOrderDetails(); } } src/test/java/com/gs/xky/controller/DingtalkControllerTest.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,108 @@ package com.gs.xky.controller; import com.fasterxml.jackson.databind.ObjectMapper; import com.gs.xky.dto.NumbericalDto; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** * DingtalkControlleræµè¯ç±» * * @author 28567 * @description æµè¯ééæ¶æ¯åéæ¥å£ * @createDate 2025-01-27 */ @WebMvcTest(DingtalkController.class) public class DingtalkControllerTest { @Autowired private MockMvc mockMvc; @MockBean private com.gs.xky.service.DingtalkInfoService dingtalkInfoService; @Autowired private ObjectMapper objectMapper; @Test public void testSendMessage_Success() throws Exception { // å夿µè¯æ°æ® NumbericalDto requestDto = new NumbericalDto(); requestDto.setReleaseNo("IQC202501270001"); // Mockæå¡å±è¿åæå when(dingtalkInfoService.sendMessage(anyString())).thenReturn(true); // æ§è¡æµè¯ mockMvc.perform(post("/api/dingtalk/sendMessage") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(requestDto))) .andExpect(status().isOk()) .andExpect(jsonPath("$.code").value(200)) .andExpect(jsonPath("$.successful").value(0)) .andExpect(jsonPath("$.data").value("æ¥æ¶æå")); } @Test public void testSendMessage_Failure() throws Exception { // å夿µè¯æ°æ® NumbericalDto requestDto = new NumbericalDto(); requestDto.setReleaseNo("IQC202501270001"); // Mockæå¡å±è¿å失败 when(dingtalkInfoService.sendMessage(anyString())).thenReturn(false); // æ§è¡æµè¯ mockMvc.perform(post("/api/dingtalk/sendMessage") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(requestDto))) .andExpect(status().isOk()) .andExpect(jsonPath("$.code").value(500)) .andExpect(jsonPath("$.successful").value(1)) .andExpect(jsonPath("$.data").value("æ¥æ¶å¤±è´¥")); } @Test public void testSendMessage_EmptyReleaseNo() throws Exception { // å夿µè¯æ°æ® - ç©ºçæ£éªåå· NumbericalDto requestDto = new NumbericalDto(); requestDto.setReleaseNo(""); // æ§è¡æµè¯ mockMvc.perform(post("/api/dingtalk/sendMessage") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(requestDto))) .andExpect(status().isOk()) .andExpect(jsonPath("$.code").value(500)) .andExpect(jsonPath("$.message").value("æ£éªåå·ä¸è½ä¸ºç©º")) .andExpect(jsonPath("$.successful").value(1)) .andExpect(jsonPath("$.data").value("æ¥æ¶å¤±è´¥")); } @Test public void testSendMessage_NullReleaseNo() throws Exception { // å夿µè¯æ°æ® - nullæ£éªåå· NumbericalDto requestDto = new NumbericalDto(); requestDto.setReleaseNo(null); // æ§è¡æµè¯ mockMvc.perform(post("/api/dingtalk/sendMessage") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(requestDto))) .andExpect(status().isOk()) .andExpect(jsonPath("$.code").value(500)) .andExpect(jsonPath("$.message").value("æ£éªåå·ä¸è½ä¸ºç©º")) .andExpect(jsonPath("$.successful").value(1)) .andExpect(jsonPath("$.data").value("æ¥æ¶å¤±è´¥")); } }