一、IDEA构建springboot应用脚手架
引入springboot-coloud-star等基础依赖
基础技能相信学java都会。
二、企业微信自建应用与后台服务实现交互
- 已需要下载PC版企业微信,并且注册自己的企业,主要为了获取企业ID等与企业微信服务打通,登录企业管理后台企业微信
- 选择自建应用,新建自己的应用,如下,我自建一个小应用就叫【文心一言】
3.点击我的企业,获取企业scorpId
4.设置应用与自己的后台应用的消息接口API
该接口API就是企业微信自建应用与我后台交互的关键,具体实现步骤如下:
- 在springboot项目的配置文件中配置当前企业微信的企业sCorpID、sToken、sEncodingAESKey,后两项可以通过API接收消息界面动态随机获取,也可以自己生成。
- 关键代码,按照企业微信自建应用消息的开发文档,必须实现两个请求方式为GET和POST的相同接口URL的接口:
- GET请求:
@GetMapping("/checkURL")
public String validEntWeChatURL(HttpServletRequest request) {
logger.info("AiManagerController validEntWeChatURL validEntWeChatURL={}", request);
String sReplyEchoStr = null;
//微信加签
String sMsg_signature = request.getParameter("msg_signature");
//解析url
String sTimestamp = request.getParameter("timestamp");
String SNonce = request.getParameter("nonce");
String SEchostr = request.getParameter("echostr");
try {
sReplyEchoStr = cryptUtil.getCrypt().VerifyURL(sMsg_signature, sTimestamp, SNonce, SEchostr);
} catch (AesException e) {
logger.error("AiManagerController validEntWeChatURL err={}", e);
}
logger.info("AiManagerController validEntWeChatURL sReplyEchoStr={},微信验签成功!", sReplyEchoStr);
return sReplyEchoStr;
}
POST请求:
/**
* 接收企业微信的消息
*
* @param request
* @return
*/
@PostMapping("/checkURL")
public String getEntWXMsg(HttpServletRequest request, HttpServletResponse response) {
String respMsg = "";
//微信加签
String sMsg_signature = request.getParameter("msg_signature");
//解析url
String sTimestamp = request.getParameter("timestamp");
String SNonce = request.getParameter("nonce");
try {
ServletInputStream inputStream = request.getInputStream();
String sReqData = IoUtils.toString(inputStream, "UTF-8");
String sReplyEchoStr = cryptUtil.getCrypt().DecryptMsg(sMsg_signature, sTimestamp, SNonce, sReqData);
//解析xml数据
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
StringReader sr = new StringReader(sReplyEchoStr);
InputSource is = new InputSource(sr);
Document document = db.parse(is);
Element root = document.getDocumentElement();
NodeList nodelist1 = root.getElementsByTagName("Content");
String content = nodelist1.item(0).getTextContent();
//获取成员UserID
NodeList nodelist2 = root.getElementsByTagName("FromUserName");
String fromUserName = nodelist2.item(0).getTextContent();
//返回的消息内容
// logger.info("AiManagerController getEntWXMsg Content:{}", content);
String baiduRespMsg = baiduAPIUtil.call_ERNIEBot(content, fromUserName);
// logger.info("AiManagerController call_ERNIE_Bot baiduRespMsg:{}", baiduRespMsg);
//回复的消息
EntWXResp resp = new EntWXResp();
resp.setFromUserName(cryptUtil.getWxProperties().getSCorpID());
resp.setToUserName(fromUserName);
resp.setContent(baiduRespMsg);
resp.setMsgType("text");
resp.setCreateTime(DateUtil.date().toStringDefaultTimeZone());
//拼装被动消息返回体
//生成xml 字符串
String xmlMsg = "<xml>\n" +
" <ToUserName><![CDATA[" + resp.getToUserName() + "]]></ToUserName>\n" +
" <FromUserName><![CDATA[" + resp.getFromUserName() + "]]></FromUserName> \n" +
" <CreateTime>" + resp.getCreateTime() + "</CreateTime>\n" +
" <MsgType><![CDATA[" + resp.getMsgType() + "]]></MsgType>\n" +
" <Content><![CDATA[" + resp.getContent() + "]]></Content>\n" +
"</xml>\n";
// logger.info("AiManagerController call_ERNIE_Bot xmlMsg =:{}", xmlMsg);
//加密返回
respMsg = cryptUtil.getCrypt().EncryptMsg(xmlMsg, sTimestamp, SNonce);
logger.info("AiManagerController cryptUtil.EncryptMsg respMsg ={}", respMsg);
} catch (AesException e) {
logger.error("AiManagerController getEntWXMsg err={}", e);
} catch (ParserConfigurationException e) {
logger.error("AiManagerController getEntWXMsg err={}", e);
} catch (IOException e) {
logger.error("AiManagerController getEntWXMsg err={}", e);
} catch (SAXException e) {
logger.error("AiManagerController getEntWXMsg err={}", e);
}
return respMsg;
}
三、集成百度文心一言应用API
- 登录,自建模型应用,获取AK,SK.百度智能云千帆大模型平台
https://console.bce.baidu.com/qianfan/ais/console/applicationConsole/application
在服务配置文件application.yml配置好该参数:
##百度文心千帆AI接口配置
baidu:
client_id: j3tpU0KhE3Iwewewew
client_secret: PLSEAb8yXTzGasewewewewnDA7wew
grant_type: client_credentials
- 按照百度接口文档,开发相应API实现,调用API,zhiqian buxyo huoqu TOKEN
/** * 获取百度云应用 的access_token * * @return */ public BaiduApiResp getBaiDuAccessToken() { //设置百度缓存的 key String reinsCacheToken = String.format(ACCEESS_TOKEN_KEY, CLIENT_ID); if (redisService.hasKey(reinsCacheToken)) { BaiduApiResp cacheObject = redisService.getCacheObject(reinsCacheToken); logger.info("BaiduAPIUtil getBaiDuAccessToken ={}", cacheObject); return cacheObject; } BaiduApiResp resp = new BaiduApiResp(); HashMap<String, Object> paramMap = new HashMap<>(); paramMap.put("client_id", CLIENT_ID); paramMap.put("client_secret", CLIENT_SECRET); paramMap.put("grant_type", GRANT_TYPE); String returnMsg = HttpUtil.post(BAIDU_URL, paramMap); JSONObject respons = JSONUtil.parseObj(returnMsg); if (!StrUtil.isEmptyIfStr(respons.getStr("error"))) { logger.error("BaiduAPIUtil getBaiDuAccessToken err={},error_description={}", respons.getStr("error"), respons.getStr("error_description")); return resp; } //获取token String access_token = respons.getStr("access_token"); resp.setAccess_token(access_token); //获取有效期 Integer expires_in = respons.getInt("expires_in"); resp.setExpires_in(expires_in); //当如缓存,过期再取 redisService.setCacheObject(reinsCacheToken, resp, Long.valueOf(expires_in), TimeUnit.SECONDS); return resp; }
/** * ERNIE-Bot是百度自行研发的大语言模型, * 覆盖海量中文数据,具有更强的对话问答、内容创作生成等能力。 * * @return */ public String call_ERNIEBot(String askStr, String userId) { logger.info("BaiduAPIUtil call_ERNIEBot askStr={},userId={}", askStr, userId); // 添加请求头信息 Map<String, String> heads = new HashMap<>(); heads.put("Content-Type", "application/json"); Map<String, String> urlParmMap = new HashMap<>(); urlParmMap.put("access_token", getBaiDuAccessToken().getAccess_token()); String realUrl = ERNIE_BOT_URL + URLUtil.buildQuery(urlParmMap, CharsetUtil.CHARSET_UTF_8); //创建json对象作为requestBody MessageVo message = new MessageVo(); message.setRole("user"); message.setContent(askStr); List<MessageVo> messages = new ArrayList<>(); messages.add(message); JSONObject jsonObject = new JSONObject(); jsonObject.set("messages", messages.toArray()); jsonObject.set("stream", Boolean.TRUE); //用户id jsonObject.set("user_id", userId); System.out.println(JSONUtil.toJsonStr(jsonObject)); HttpResponse returnMsg = HttpRequest.post(realUrl).headerMap(heads, false) .body(String.valueOf(jsonObject)) .execute(); String result = StrUtil.EMPTY; JSONObject response = JSONUtil.parseObj(returnMsg); String status = response.getStr("status"); if ("200".equals(status)) { byte[] bytes = returnMsg.body().getBytes(); result = new String(bytes); String[] split = result.split("\n"); StringBuffer buffer = new StringBuffer(); for (String s : split) { if(s.contains("data")){ String subStr = s.substring(s.indexOf("{")-1); JSONObject entries = JSONUtil.parseObj(subStr); buffer.append(entries.getStr("result")); } } logger.info("BaiduAPIUtil call_ERNIEBot result={}", buffer); return buffer.toString(); } return result; }
四、最终实现效果:
注意点:
- 企业微信设置API接收必须要是企业申请的域名URL,所以测试成本有点高,适合企业开发。
- 其次,微信对接口响应有要求,对接百度的接口必须在1s内有响应,否则企业微信后台会丢弃该次请求。这会导致我们向企业微信发送消息不会有回应。之后在5s内,企业微信会幂等性的重试3次,所以我在实际业务中,调用边度文心一言的接口中加了缓存处理,保持5s内企业微信调用我们后台获取消息一定会有内容响应。