README.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,124 @@ # ééæ¶æ¯æ¨éç³»ç» ## é¡¹ç®æ¦è¿° è¿æ¯ä¸ä¸ªåºäº Spring Boot çééæ¶æ¯æ¨éç³»ç»ï¼å为 `dingtalk`ã该系ç»éè¿éé弿¾å¹³å° API å®ç°äºå®æ¶æ¶æ¯æ¨éãç¨æ·ç®¡çã以åè®¾å¤æ°æ®æéçåè½ã ## æ ¸å¿ææ¯æ - **æ¡æ¶**: Spring Boot 2.6.13 - **è¯è¨**: Java 1.8 - **æ°æ®åº**: Oracleï¼ä½¿ç¨ Druid è¿æ¥æ± - **æä¹ å±**: MyBatis-Plus - **éééæ**: éé弿¾å¹³å° SDK - **å·¥å ·åº**: Lombok, Gson, OkHttp3, Fastjson, Hutool, Apache POI - **å 管ç**: Maven ## é¡¹ç®æ¶æ ``` src/ âââ main/ â âââ java/com/gs/dingtalk/ â â âââ DingtalkApplication.java # Spring Boot å¯å¨ç±» â â âââ config/ â â â âââ DataAcquisitionConfiguration.java # ééåºç¨é ç½®ï¼AppKeyãAppSecretçï¼ â â â âââ ResultMessage.java # ç»ä¸ååºæ¶æ¯æ ¼å¼ â â â âââ URLEncoder.java # URLç¼ç å·¥å ·ç±» â â âââ controller/ â â â âââ KMController.java # æ¶æ¯åéæ§å¶å± â â âââ dto/ â â â âââ ApiResponseCode.java # APIååºç â â â âââ DingTalkMessage.java # ééæ¶æ¯ DTO â â â âââ DingTalkResponse.java # ééååº DTO â â â âââ Result.java # ç»ä¸è¿åç»æ â â âââ entity/ â â â âââ MesQaDingtalk.java # è´¨éæ£æµééæ¶æ¯å®ä½ â â â âââ SendDingtalk.java # ééç¨æ·å®ä½ â â â âââ SendMessage.java # æ¶æ¯åéå®ä½ â â âââ mapper/ â â â âââ MesQaDingtalkMapper.java # è´¨éæ£æµééæ¶æ¯æ°æ®è®¿é®å± â â â âââ SendDingtalkMapper.java # ééç¨æ·æ°æ®è®¿é®å± â â â âââ SendMessageMapper.java # æ¶æ¯åéæ°æ®è®¿é®å± â â âââ service/ â â â âââ MesQaDingtalkService.java # è´¨éæ£æµééæå¡æ¥å£ â â â âââ SendDingtalkService.java # ééæå¡æ¥å£ â â â âââ SendMessageService.java # æ¶æ¯æå¡æ¥å£ â â â âââ SimpleExample.java # ééæ¶æ¯åéå®ç° â â â âââ impl/ â â â âââ MesQaDingtalkServiceImpl.java # è´¨éæ£æµééæå¡å®ç° â â â âââ SendDingtalkServiceImpl.java # ééæå¡å®ç° â â â âââ SendMessageServiceImpl.java # æ¶æ¯æå¡å®ç° â â âââ task/ â â âââ ScheduledTasks.java # 宿¶ä»»å¡ â âââ resources/ â âââ application.yml # åºç¨é ç½®æä»¶ â âââ mapper/ # MyBatis XML æ å°æä»¶ âââ test/ âââ java/com/gs/dingtalk/DeviceReceivingApplicationTests.java # æµè¯ç±» ``` ## æ°æ®åºé ç½® - **æ°æ®åº**: Oracle - **URL**: jdbc:oracle:thin:@172.16.0.219:1521/orcl - **ç¨æ·å**: yc_dev - **å¯ç **: ycdev - **è¿æ¥æ± **: Druidï¼åå§è¿æ¥æ°5ï¼æå¤§è¿æ¥æ°20 ## ééé ç½® å¨ `config/DataAcquisitionConfiguration.java` ä¸é ç½®ï¼ - **AppKey**: ééåºç¨ç AppKey - **AppSecret**: ééåºç¨ç AppSecret - **CorpId**: ééä¼ä¸ CorpId - **æºå¨äººToken**: ééç¾¤èæºå¨äºº Token - **æºå¨äººSecret**: ééç¾¤èæºå¨äºº Secret ## 主è¦åè½æ¨¡å ### 1. ç¨æ·ç®¡ç - `getDingTalkUserId()`: éè¿ææºå·è·åééç¨æ·IDå¹¶ä¿åå°æ°æ®åº - 使ç¨éé `OapiV2UserGetbymobileResponse` API å®ç° ### 2. æ¶æ¯æ¨é - `chatSendMessage()`: åééç¾¤èæºå¨äººåéæ¶æ¯ - `sendDingTalkFiveMinute()`, `sendDingTalkFifteenMinute()`, `sendDingTalkthirtyMinute()`: 宿¶åç¹å®ç¨æ·åéæ¶æ¯ ### 3. 宿¶ä»»å¡ - `ScheduledTasks.java`: å®ä¹äºä¸ä¸ªå®æ¶ä»»å¡ - æ¯2åéæ§è¡ä¸æ¬¡5åéæéæ£æ¥ - æ¯3åéæ§è¡ä¸æ¬¡15åéæéæ£æ¥ - æ¯4åéæ§è¡ä¸æ¬¡30åéæéæ£æ¥ ### 4. è´¨éæ£æµ - `MesQaDingtalkServiceImpl`: å¤çè´¨éæ£æµç¸å ³çééæ¶æ¯æ¨é ### 5. æéæ§å¶ - éè¿ `SendDingtalk` å®ä½ä¸ç `purview` åæ®µæ§å¶ç¨æ·æ¶æ¯æ¥æ¶æé - æ ¹æ® `procNo`ï¼å·¥åºç¼å·ï¼å¹é ç¨æ·æé ## æå»ºä¸è¿è¡ ### æå»º ```bash mvn clean package ``` ### è¿è¡ ```bash java -jar dingtalk.jar ``` æå¨ IDE ä¸è¿è¡ `DingtalkApplication.java` ç `main` æ¹æ³ ### ç«¯å£ - æå¡å¨ç«¯å£: 9096 ## å¼åçº¦å® - ä½¿ç¨ Lombok 注解ç®å代ç - ä½¿ç¨ MyBatis-Plus è¿è¡æ°æ®åºæä½ - 使ç¨ç»ä¸çååºæ ¼å¼ `ResultMessage` - é ç½®æä»¶ä½¿ç¨ YAML æ ¼å¼ - 宿¶ä»»å¡ä½¿ç¨ Spring ç `@Scheduled` 注解 src/main/java/com/gs/dingtalk/dto/QaMsgDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,13 @@ package com.gs.dingtalk.dto; import lombok.Data; @Data public class QaMsgDto { private String lineName; private String workshopName; private String qaType; private String billNo; } src/main/java/com/gs/dingtalk/entity/MesQaDingtalk.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,65 @@ package com.gs.dingtalk.entity; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import lombok.Data; /** * * @TableName MES_QA_DINGTALK */ @TableName(value ="MES_QA_DINGTALK") @Data @KeySequence(value = "SEQ_SEND", dbType = DbType.ORACLE) public class MesQaDingtalk implements Serializable { /** * */ private Long id; /** * 线ä½ç¼ç */ private String lineNo; /** * 线ä½åç§° */ private String lineName; /** * 车é´id */ private Long departmentid; /** * 车é´åç§° */ private String departmentname; /** * æ£éªç±»å */ private String qaType; /** * ç¨æ·çééid */ private String userId; /** * ç¨æ·ä¸æ */ private String userName; /** * çµè¯ */ private String telephone; @TableField(exist = false) private static final long serialVersionUID = 1L; } src/main/java/com/gs/dingtalk/entity/QaSj.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,57 @@ package com.gs.dingtalk.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import lombok.Data; /** * * @TableName QA_SJ */ @TableName(value ="QA_SJ") @Data public class QaSj implements Serializable { /** * æ£éªåå· */ private String billNo; /** * ç©æç¼ç */ private String itemNo; /** * ç©æåç§° */ private String itemName; /** * çº¿ä½ */ private String lineName; /** * è½¦é´ */ private String workshopName; /** * æäº¤æ è¯ */ private Long fsubmit; /** * å·¥åå· */ private String daa001; /** * æ£éªç»æ */ private String jyjg; @TableField(exist = false) private static final long serialVersionUID = 1L; } src/main/java/com/gs/dingtalk/entity/SendDingtalk.java
@@ -41,6 +41,12 @@ */ private Integer fiveMinuteReminder; //Fifteen_MINUTE_REMINDER /** * åäºåé该æéç人 0è¡¨ç¤ºä¸æé 1 表示æé */ private Integer FifteenMinuteReminder; /** * ä¸ååé该æéç人 0è¡¨ç¤ºä¸æé 1 表示æé */ src/main/java/com/gs/dingtalk/mapper/MesQaDingtalkMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.gs.dingtalk.mapper; import com.gs.dingtalk.entity.MesQaDingtalk; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** * @author Administrator * @description é对表ãMES_QA_DINGTALKãçæ°æ®åºæä½Mapper * @createDate 2025-12-03 18:53:07 * @Entity com.gs.dingtalk.entity.MesQaDingtalk */ public interface MesQaDingtalkMapper extends BaseMapper<MesQaDingtalk> { } src/main/java/com/gs/dingtalk/mapper/QaSjMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ package com.gs.dingtalk.mapper; import com.gs.dingtalk.entity.QaSj; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** * @author Administrator * @description é对表ãQA_SJãçæ°æ®åºæä½Mapper * @createDate 2025-12-03 19:48:50 * @Entity com.gs.dingtalk.entity.QaSj */ public interface QaSjMapper extends BaseMapper<QaSj> { } src/main/java/com/gs/dingtalk/service/MesQaDingtalkService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,16 @@ package com.gs.dingtalk.service; import com.gs.dingtalk.dto.QaMsgDto; import com.gs.dingtalk.entity.MesQaDingtalk; import com.baomidou.mybatisplus.extension.service.IService; /** * @author Administrator * @description é对表ãMES_QA_DINGTALKãçæ°æ®åºæä½Service * @createDate 2025-12-03 18:53:07 */ public interface MesQaDingtalkService extends IService<MesQaDingtalk> { void sendQaMsgSJ(QaMsgDto dto); } src/main/java/com/gs/dingtalk/service/QaSjService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,13 @@ package com.gs.dingtalk.service; import com.gs.dingtalk.entity.QaSj; import com.baomidou.mybatisplus.extension.service.IService; /** * @author Administrator * @description é对表ãQA_SJãçæ°æ®åºæä½Service * @createDate 2025-12-03 19:48:50 */ public interface QaSjService extends IService<QaSj> { } src/main/java/com/gs/dingtalk/service/SendDingtalkService.java
@@ -10,6 +10,8 @@ void sendDingTalkFiveMinute() throws Exception; void sendDingTalkFifteenMinute() throws Exception; void sendDingTalkthirtyMinute() throws Exception; void chatSendMessage() throws Exception; src/main/java/com/gs/dingtalk/service/SimpleExample.java
@@ -222,4 +222,19 @@ } 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/java/com/gs/dingtalk/service/impl/MesQaDingtalkServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,158 @@ package com.gs.dingtalk.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.gs.dingtalk.dto.DingTalkMessage; import com.gs.dingtalk.dto.QaMsgDto; import com.gs.dingtalk.entity.MesQaDingtalk; import com.gs.dingtalk.entity.QaSj; import com.gs.dingtalk.service.MesQaDingtalkService; import com.gs.dingtalk.mapper.MesQaDingtalkMapper; import com.gs.dingtalk.service.QaSjService; import com.gs.dingtalk.service.SimpleExample; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; /** * @author Administrator * @description é对表ãMES_QA_DINGTALKãçæ°æ®åºæä½Serviceå®ç° * @createDate 2025-12-03 18:53:07 */ @Service @RequiredArgsConstructor @Transactional(rollbackFor = Exception.class) public class MesQaDingtalkServiceImpl extends ServiceImpl<MesQaDingtalkMapper, MesQaDingtalk> implements MesQaDingtalkService { private final SimpleExample simpleExample; private final QaSjService qaSjService; @Override public void sendQaMsgSJ(QaMsgDto dto) { LambdaQueryWrapper<MesQaDingtalk> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(MesQaDingtalk::getLineName, dto.getLineName()) .eq(MesQaDingtalk::getDepartmentname, dto.getWorkshopName()) .eq(MesQaDingtalk::getQaType, dto.getQaType()); //è·åå°ç¨æ·idï¼å½ç¨æ·æ²¡æidæ¶éæ°è·åå¹¶æ´æ°MesQaDingtalk表 List<MesQaDingtalk> list = list(wrapper); if (list.isEmpty()) { // å¦ææ²¡ææ¾å°å¯¹åºçç¨æ·ï¼ç´æ¥è¿å return; } LambdaQueryWrapper<QaSj> qaSjQueryWrapper = new LambdaQueryWrapper<>(); qaSjQueryWrapper.eq(QaSj::getBillNo, dto.getBillNo()); QaSj qaSj = qaSjService.getOne(qaSjQueryWrapper, false); if (qaSj == null) { // å¦ææ²¡ææ¾å°å¯¹åºçæ£éªä¿¡æ¯ï¼ç´æ¥è¿å return; } String message = String.format("é¦ä»¶[æ£éªåå·:%s, ç©æç¼ç :%s, ç©æåç§°:%s, 车é´:%s, 线ä½:%s, å·¥åå·:%s, æ£éªç»æ:%s]ï¼è¯·è¿è¡åç»æä½", qaSj.getBillNo(), qaSj.getItemNo(), qaSj.getItemName(), qaSj.getWorkshopName(), qaSj.getLineName(), qaSj.getDaa001(), qaSj.getJyjg()); // æList<MesQaDingtalk>ä¸çuserId使ç¨,æ¼æ¥èµ·æ¥åæuserIdListè¿ä¸ªåé List<String> sidList = list.stream() .map(MesQaDingtalk::getTelephone) .collect(Collectors.toList()); List<String> userIdList = getDingtalkUserIdListByPhones(sidList); if (userIdList == null || userIdList.isEmpty()) { log.warn("æ²¡æææçééç¨æ·ID"); return; } String userIdListStr = String.join(",", userIdList); DingTalkMessage dingTalkMessage = null; try { dingTalkMessage = simpleExample.sendMessage(userIdListStr, message); } catch (Exception e) { throw new RuntimeException("åéééæ¶æ¯å¤±è´¥", e); } if (dingTalkMessage != null && dingTalkMessage.getErrcode() == 0) { System.out.println("åéæå"); } else { System.out.println("åé失败"); } } private List<String> getDingtalkUserIdListByPhones(List<String> phoneList) { try { if (phoneList == null || phoneList.isEmpty()) { return new ArrayList<>(); } // å»é phoneList = phoneList.stream().distinct().collect(Collectors.toList()); // æ ¹æ®sidæ¥è¯¢DingtalkInfo List<MesQaDingtalk> list = baseMapper.selectList( new LambdaQueryWrapper<MesQaDingtalk>().in(MesQaDingtalk::getTelephone, phoneList) ); if (list == null || list.isEmpty()) { return new ArrayList<>(); } // 使ç¨streamæµè¿æ»¤åºlistä¸dingtalkIdä¸ºç©ºçæ°æ® List<MesQaDingtalk> emptyDingtalkIdList = list.stream() .filter(info -> !StringUtils.hasText(info.getUserId())) .collect(Collectors.toList()); // 妿åå¨ä¸ºç©ºçæ°æ®å°±éè¿ééçæ¥å£è·åï¼ä¸ºdingtalkIdèµå¼ï¼å¹¶ä¸æ´æ°æ°æ®åº if (!emptyDingtalkIdList.isEmpty()) { String accessToken = simpleExample.getAccessToken(); for (MesQaDingtalk info : emptyDingtalkIdList) { if (StringUtils.hasText(info.getTelephone())) { try { // éè¿ææºå·è·åééç¨æ·ID com.dingtalk.api.response.OapiV2UserGetbymobileResponse response = simpleExample.getOapiV2UserGetbymobileResponse(info.getTelephone(), accessToken); if (response != null && response.getResult() != null) { info.setUserId(response.getResult().getUserid()); // æ´æ°æ°æ®åº updateById(info); } } catch (Exception e) { log.error("è·åééç¨æ·IDå¤±è´¥ï¼ææºå·ï¼" + info.getTelephone()); } } } } // ä¸åå¨ä¸ºç©ºçæ°æ®æè å¤çå®ç©ºæ°æ®åï¼è¿åææææçdingtalkIdå表 return list.stream() .map(MesQaDingtalk::getUserId) .filter(StringUtils::hasText) .distinct() .collect(Collectors.toList()); } catch (Exception e) { log.error("è·åééç¨æ·å表失败", e); return new ArrayList<>(); } } } src/main/java/com/gs/dingtalk/service/impl/QaSjServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,22 @@ package com.gs.dingtalk.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.gs.dingtalk.entity.QaSj; import com.gs.dingtalk.service.QaSjService; import com.gs.dingtalk.mapper.QaSjMapper; import org.springframework.stereotype.Service; /** * @author Administrator * @description é对表ãQA_SJãçæ°æ®åºæä½Serviceå®ç° * @createDate 2025-12-03 19:48:50 */ @Service public class QaSjServiceImpl extends ServiceImpl<QaSjMapper, QaSj> implements QaSjService{ } src/main/java/com/gs/dingtalk/service/impl/SendDingtalkServiceImpl.java
@@ -83,6 +83,16 @@ } @Override public void sendDingTalkFifteenMinute() throws Exception { LambdaQueryWrapper<SendDingtalk> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(SendDingtalk::getFifteenMinuteReminder, 1); List<SendDingtalk> list = list(wrapper); getMessage(list, 15); } @Override public void sendDingTalkthirtyMinute() throws Exception { LambdaQueryWrapper<SendDingtalk> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(SendDingtalk::getThirtyMinuteReminder, 1); src/main/java/com/gs/dingtalk/task/ScheduledTasks.java
@@ -34,6 +34,16 @@ } @Scheduled(cron = "0 0/3 * * * ?") public void sendDingTalkFifteenMinute() { try { sendDingtalkService.sendDingTalkFifteenMinute(); log.info("宿¶ä»»å¡ sendDingTalkFifteenMinute æ§è¡æå"); } catch (Exception e) { log.error("宿¶ä»»å¡ sendDingTalkFifteenMinute æ§è¡å¤±è´¥: ", e); } } @Scheduled(cron = "0 0/4 * * * ?") public void sendDingTalkThirtyMinute() { try { sendDingtalkService.sendDingTalkthirtyMinute(); src/main/resources/application.yml
@@ -5,7 +5,7 @@ datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: oracle.jdbc.OracleDriver url: jdbc:oracle:thin:@192.168.0.100:1521/orcl url: jdbc:oracle:thin:@172.16.0.219:1521/orcl username: yc_dev password: ycdev druid: src/main/resources/mapper/MesQaDingtalkMapper.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.dingtalk.mapper.MesQaDingtalkMapper"> </mapper> src/main/resources/mapper/QaSjMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,22 @@ <?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.dingtalk.mapper.QaSjMapper"> <resultMap id="BaseResultMap" type="com.gs.dingtalk.entity.QaSj"> <result property="billNo" column="BILL_NO" /> <result property="itemNo" column="ITEM_NO" /> <result property="itemName" column="ITEM_NAME" /> <result property="lineName" column="LINE_NAME" /> <result property="workshopName" column="WORKSHOP_NAME" /> <result property="fsubmit" column="FSUBMIT" /> <result property="daa001" column="DAA001" /> <result property="jyjg" column="JYJG" /> </resultMap> <sql id="Base_Column_List"> BILL_NO,ITEM_NO,ITEM_NAME,LINE_NAME,WORKSHOP_NAME,FSUBMIT, DAA001,JYJG </sql> </mapper> src/test/java/com/gs/dingtalk/MesQaDingtalkServiceTest.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,36 @@ package com.gs.dingtalk; import com.gs.dingtalk.dto.QaMsgDto; import com.gs.dingtalk.entity.MesQaDingtalk; import com.gs.dingtalk.entity.QaSj; import com.gs.dingtalk.service.MesQaDingtalkService; import com.gs.dingtalk.service.QaSjService; import com.gs.dingtalk.service.SimpleExample; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; @SpringBootTest class MesQaDingtalkServiceTest { @Autowired private MesQaDingtalkService mesQaDingtalkService; @Test void testSendQaMsgSJ() throws Exception { // å夿µè¯æ°æ® QaMsgDto dto = new QaMsgDto(); dto.setLineName("注å¡3å·æº"); dto.setWorkshopName("注å¡è½¦é´"); dto.setQaType("é¦ä»¶é¦æ£å®æ"); dto.setBillNo("SJ202509150022"); mesQaDingtalkService.sendQaMsgSJ(dto); } }