当前位置: 首页 > 后端技术 > Java

如何在gitlab完成提交PR、合并PR等操作后用钉钉自定义机器人进行消息推送

时间:2023-04-02 10:07:44 Java

如何在gitlab完成提交PR、合并PR等后使用钉钉自定义机器人推送消息.)钉钉机器人将这些信息实时推送到钉钉群。虽然钉钉也为gitlab设置了官方的机器人,但是可能不能很好的满足我们的需求,或者gitlab发送的请求不符合钉钉机器人要求的格式。这时候就需要一个类似中转站的东西来满足我们的要求——接收gitlab发过来的请求,转换成钉钉机器人可以正常接收的格式,然后根据这些数据构造一个新的请求来调用我们的钉钉机器人实现了我们需要的功能。本文基于Portal编写。流程图:如果我们直接运行项目,会发现当我们人为模拟gitlab发送请求时,会收到如下响应:{"errcode":310000,"errmsg":"signnotmatch"}错误信息提示:signaturedoesnotmatchMatching,查阅钉钉官方文档后会发现,如果我们使用“signature”方式设置机器人的安全性,如果请求的URL没有按照设置的serect进行处理,这样会发生错误。钉钉机器人安全设置根据上面给出的钉钉官方文档中的内容,我们可以编写如下函数来处理url:publicStringencode(Stringsecret)throwsException{//获取时间戳Longtimestamp=System.currentTimeMillis();//将时间戳和密钥拼接成一个字符串,中间加一个换行符StringstringToSign=timestamp+"\n"+secret;//声明一个Mac对象,用于操作字符串Macmac=Mac.getInstance("HmacSHA256");//初始化,设置Mac对象操作的字符串为UTF-8类型,加密方式为SHA256mac.init(newSecretKeySpec(secret.getBytes("UTF-8"),"HmacSHA256"));//将字符串转换成byte[]signData=mac.doFinal(stringToSign.getBytes("UTF-8"));//新建一个Base64编码对象Base64.Encoderencoder=Base64.getEncoder();//将上述字符串用Base64加密然后URL编码Stringsign=URLEncoder.encode(newString(encoder.encodeToString(signData)),"UTF-8");Stringresult="×tamp="+timestamp+"&sign="+sign;返回结果;}之后我们只需要从C层获取serect然后传给这个函数使用关于serect:我们在gitlab上设置好serect后,gitlab会把它添加到request的header中,让我们获取下图中的X-Gitlab-Token。之后我们就可以根据gitlab发来的请求修改C级对接的url就可以正常使用这个项目了。在C层匹配对应的url后获取request中的json、X-Gitlab-Event、X-Gitlab-Token,调用对应的M层函数。@RestController@RequestMapping("/oapi.dingtalk.com/robot/send")@Slf4jpublicclassGitLabController{@AutowiredprivateGitLabNotifyServicegitLabNotifyService;@PostMapping(consumes=MediaType.APPLICATION_JSON_VALUE)publicResponseVopushHook(@RequestBodyStringjson,@RequestHeader(name="X-Gitlab-Event")Stringevent,@RequestHeader(name="X-Gitlab-Token")Stringsecret)throwsIOException{System.out.println("触发推送");gitLabNotifyService.handleEventData(json、事件、秘密);返回ResponseUtil.ok();}字符串秘密;@OverridepublicvoidhandleEventData(Stringjson,StringeventName,Stringsecret)抛出IOException{System.out.println("json:"+json);System.out.println("事件名称:"+eventName);//保存秘密this.secret=secret;//根据哈希表返回X-Gitlab-Event对应的beanNameStringhandleBeanName=EventMapper.getHandleBeanName(事件名称);//根据beanName获取对应的服务EventServiceeventService=(EventService)applicationContextProvider.getBean(handleBeanName);eventService.handleEvent(json);}applicationContextProvider实现了ApplicationContextAware接口来设置context实例,然后我们可以根据context实例的getBean方法获取对应的service。@ComponentpublicclassApplicationContextProviderimplementsApplicationContextAware{/***上下文对象实例*/privateApplicationContextapplicationContext;@OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{this.applicationContext=applicationContext;}/***获取applicationContextapplicationContext*/(){returnapplicationContext;}/***通过名称获取Bean。*/publicObjectgetBean(Stringname){returngetApplicationContext().getBean(name);}}之后我们以pushService为例:@OverridepublicvoidhandleEvent(Stringjson)throwsIOException{//根据json数据设置gitLabPushRequestGitLabPushRequestgitLabPushRequest=covertJson(json);字符串文本=“-事件:”+gitLabPushRequest.getObjectKind()+“\n”+“-项目:”+gitLabPushRequest。getProject().getName()+"\n“+”-作者:“+gitLabPushRequest.getUserName()+”\n“+”-分支:“+gitLabPushRequest.getRef()+”\n“+”-total_commits:“+gitLabPushRequest.getTotalCommitsCount()+”\n";//设置根据gitLabPushRequest推送给钉钉的MarkDownMessagedingPushService.pushMarkDownMessage(newMarkDownMessage(MessageTypeConstant.MARKDOWN_TYPE,newMarkDownMessage.MarkDown(gitLabPushRequest.getObjectKind(),text)));}MarkDownMessage为钉钉官方钉钉机器人可以识别的几种数据格式之一,下面给出对应的钉钉官方文档访问自定义机器人的dingPushService:publicvoidpushMarkDownMessage(MarkDownMessagemarkDownMessage){如果(!SUCCESSS_CODE.equals(response.getErrcode())){thrownewUnknownException("error");}}之后我们需要调用dingTalkApi下的pushMarkDownMessage函数dingTalkApi:publicDingResponsepushMarkDownMessage(MarkDownMessagemarkDownMessage){...//根据sercret修改dingTalkUrldingTalkUrl=dingServiceTalkUrl+this.encode(gitLabNotifygetDingSecret());httpClientResponse=httpClientWrapper.postReturnHttpResponse(Collections.singletonMap("Content-Type","application/json"),dingTalkUrl,JsonUtil.serializeToJson(markDownMessage,true));returnCommonHttpUtils.handleResponseHttpResponse(NewDingResponse>(){...}这会调用httpClientWrapper.postReturnHttpResponse重构请求并向钉钉机器人发起请求,钉钉机器人收到请求后可以根据请求推送信息。publicHttpClientResponsepostReturnHttpResponse(MapheaderMap,Stringurl,StringbodyStr)抛出IOException{HttpPosthttpPost=getHttpPost(headerMap,url,bodyStr);返回convert2HttpClientResponse(httpClient.execute(httpPost));}privateHttpPostgetHttpPost(MapheaderMap,Stringurl,StringbodyStr){HttpPostthttpPost=url);if(headerMap!=null){headerMap.forEach(httpPost::addHeader);}httpPost.setEntity(newStringEntity(bodyStr,"UTF-8"));返回httpPost;}