|
@@ -0,0 +1,241 @@
|
|
|
|
+package com.jpsoft.weixin.controller;
|
|
|
|
+
|
|
|
|
+import cn.hutool.core.date.DateTime;
|
|
|
|
+import cn.hutool.json.JSON;
|
|
|
|
+import cn.hutool.json.JSONObject;
|
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
|
+import com.jpsoft.weixin.config.WeixinConfig;
|
|
|
|
+import com.jpsoft.weixin.util.WeixinUtil;
|
|
|
|
+import io.swagger.annotations.Api;
|
|
|
|
+import io.swagger.annotations.ApiImplicitParam;
|
|
|
|
+import io.swagger.annotations.ApiImplicitParams;
|
|
|
|
+import io.swagger.annotations.ApiOperation;
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
|
+import org.apache.http.HttpEntity;
|
|
|
|
+import org.apache.http.HttpResponse;
|
|
|
|
+import org.apache.http.HttpStatus;
|
|
|
|
+import org.apache.http.client.methods.CloseableHttpResponse;
|
|
|
|
+import org.apache.http.client.methods.HttpGet;
|
|
|
|
+import org.apache.http.client.methods.HttpPost;
|
|
|
|
+import org.apache.http.client.utils.URIBuilder;
|
|
|
|
+import org.apache.http.entity.StringEntity;
|
|
|
|
+import org.apache.http.impl.client.CloseableHttpClient;
|
|
|
|
+import org.apache.http.impl.client.HttpClientBuilder;
|
|
|
|
+import org.apache.http.util.EntityUtils;
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
+import org.springframework.data.redis.core.ValueOperations;
|
|
|
|
+import org.springframework.stereotype.Controller;
|
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
|
+import org.xml.sax.Attributes;
|
|
|
|
+import org.xml.sax.SAXException;
|
|
|
|
+import org.xml.sax.helpers.DefaultHandler;
|
|
|
|
+
|
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
|
+import javax.xml.parsers.ParserConfigurationException;
|
|
|
|
+import javax.xml.parsers.SAXParser;
|
|
|
|
+import javax.xml.parsers.SAXParserFactory;
|
|
|
|
+import java.io.InputStream;
|
|
|
|
+import java.net.URLEncoder;
|
|
|
|
+import java.nio.charset.Charset;
|
|
|
|
+import java.util.Date;
|
|
|
|
+import java.util.HashMap;
|
|
|
|
+import java.util.Map;
|
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
|
+
|
|
|
|
+@Api(description = "微信中控")
|
|
|
|
+@Controller
|
|
|
|
+@Slf4j
|
|
|
|
+public class WeixinController {
|
|
|
|
+ @Autowired
|
|
|
|
+ private WeixinConfig weixinConfig;
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private ValueOperations<String,Object> valueOperations;
|
|
|
|
+
|
|
|
|
+ @ApiOperation(value="验证服务器地址的有效性")
|
|
|
|
+ @GetMapping("/")
|
|
|
|
+ @ResponseBody
|
|
|
|
+ public String index(@RequestParam(defaultValue = "") String signature,
|
|
|
|
+ @RequestParam(defaultValue = "") String timestamp,
|
|
|
|
+ @RequestParam(defaultValue = "") String nonce,
|
|
|
|
+ @RequestParam(defaultValue = "") String echostr){
|
|
|
|
+ log.warn("signature=" + signature);
|
|
|
|
+ log.warn("timestamp=" + timestamp);
|
|
|
|
+ log.warn("nonce=" + nonce);
|
|
|
|
+ log.warn("echostr=" + echostr);
|
|
|
|
+
|
|
|
|
+ if (WeixinUtil.checkSignature(weixinConfig.getToken(),signature,timestamp,nonce)){
|
|
|
|
+ return echostr;
|
|
|
|
+ }
|
|
|
|
+ else{
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @ApiOperation(value = "基础支持中获取普通access_token")
|
|
|
|
+ @GetMapping("/token")
|
|
|
|
+ @ResponseBody
|
|
|
|
+ public JSONObject getToken(@RequestParam(defaultValue = "client_credential") String grant_type,
|
|
|
|
+ @RequestParam(defaultValue = "") String appid,
|
|
|
|
+ @RequestParam(defaultValue = "") String secret){
|
|
|
|
+ String suffix = "_common_token";
|
|
|
|
+ JSONObject json = (JSONObject)valueOperations.get(appid + suffix);
|
|
|
|
+
|
|
|
|
+ if(json==null) {
|
|
|
|
+ StringBuilder urlBuilder = new StringBuilder();
|
|
|
|
+
|
|
|
|
+ urlBuilder.append(weixinConfig.getTokenUrl());
|
|
|
|
+
|
|
|
|
+ urlBuilder.append("?").append("grant_type=").append(grant_type);
|
|
|
|
+ urlBuilder.append("&").append("appid=").append(appid);
|
|
|
|
+ urlBuilder.append("&").append("secret=").append(secret);
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ HttpGet httpGet = new HttpGet(urlBuilder.toString());
|
|
|
|
+
|
|
|
|
+ CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
|
|
|
+
|
|
|
|
+ CloseableHttpResponse response = httpClient.execute(httpGet);
|
|
|
|
+
|
|
|
|
+ HttpEntity entity = response.getEntity();
|
|
|
|
+
|
|
|
|
+ String content = EntityUtils.toString(entity);
|
|
|
|
+
|
|
|
|
+ json = new JSONObject(content);
|
|
|
|
+
|
|
|
|
+ if(json.containsKey("expires_in")){
|
|
|
|
+ Long expiresSeconds = json.getLong("expires_in");
|
|
|
|
+ valueOperations.set(appid + suffix,json,expiresSeconds - 30, TimeUnit.SECONDS);
|
|
|
|
+ }
|
|
|
|
+ } catch (Exception ex) {
|
|
|
|
+ log.error(ex.getMessage(), ex);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return json;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @ApiOperation(value = "处理消息事件")
|
|
|
|
+ @PostMapping("/")
|
|
|
|
+ public void processEvent(HttpServletRequest request, HttpServletResponse response){
|
|
|
|
+
|
|
|
|
+ try{
|
|
|
|
+ Map<String,Object> dataMap = WeixinUtil.xmlToMap(request.getInputStream());
|
|
|
|
+
|
|
|
|
+ //{Ticket=gQEH8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyckZDekV1RHg5SFAxczNwYjF1MWIAAgTX10teAwQsAQAA, CreateTime=1582028776, EventKey=1457, Event=SCAN, ToUserName=gh_b6e865f48dea, FromUserName=op6Frsy4xuXYGqjaJ12Xv5Q-9NtU, MsgType=event}
|
|
|
|
+ log.warn(dataMap.toString());
|
|
|
|
+
|
|
|
|
+ response.setContentType("UTF-8");
|
|
|
|
+ response.setContentType("text/html; charset=UTF-8");
|
|
|
|
+ response.setCharacterEncoding("UTF-8");
|
|
|
|
+
|
|
|
|
+ String responseText = "success";
|
|
|
|
+
|
|
|
|
+ responseText = replyTextMessage(dataMap);
|
|
|
|
+
|
|
|
|
+ response.getWriter().print(responseText);
|
|
|
|
+ }
|
|
|
|
+ catch (Exception ex){
|
|
|
|
+ log.error(ex.getMessage(),ex);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String replyTextMessage(Map dataMap){
|
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
|
+
|
|
|
|
+ sb.append("<xml>");
|
|
|
|
+ sb.append("<ToUserName><![CDATA[" + dataMap.get("FromUserName") + "]]></ToUserName>");
|
|
|
|
+ sb.append("<FromUserName><![CDATA["+ dataMap.get("ToUserName") + "]]></FromUserName>");
|
|
|
|
+ sb.append("<CreateTime>" + DateTime.now().getTime() + "</CreateTime>");
|
|
|
|
+ sb.append("<MsgType><![CDATA[text]]></MsgType>");
|
|
|
|
+ sb.append("<Content><![CDATA[你好]]></Content>");
|
|
|
|
+ sb.append("</xml>");
|
|
|
|
+
|
|
|
|
+ return sb.toString();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @ResponseBody
|
|
|
|
+ @ApiOperation(value = "创建二维码")
|
|
|
|
+ @PostMapping("/qrcode/create")
|
|
|
|
+ @ApiImplicitParams({
|
|
|
|
+ @ApiImplicitParam(name="access_token", paramType="query", required=true, value="基础支持access_token"),
|
|
|
|
+ @ApiImplicitParam(name="expire_seconds", paramType="query", required=true, value="该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。"),
|
|
|
|
+ @ApiImplicitParam(name="action_name", paramType="query", required=true, value="二维码类型,QR_SCENE为临时的整型参数值,QR_STR_SCENE为临时的字符串参数值,QR_LIMIT_SCENE为永久的整型参数值,QR_LIMIT_STR_SCENE为永久的字符串参数值"),
|
|
|
|
+ @ApiImplicitParam(name="scene_id", paramType="query", value="场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000)"),
|
|
|
|
+ @ApiImplicitParam(name="scene_str", paramType="query", value="场景值ID(字符串形式的ID),字符串类型,长度限制为1到64")
|
|
|
|
+ })
|
|
|
|
+ public JSONObject createQrCode(@RequestParam(name = "access_token") String accessToken,
|
|
|
|
+ @RequestParam(name = "expire_seconds",defaultValue = "300") long expireSeconds,
|
|
|
|
+ @RequestParam(name = "action_name",defaultValue = "QR_SCENE") String actionName,
|
|
|
|
+ @RequestParam(name = "scene_id",required = false) String sceneId,
|
|
|
|
+ @RequestParam(name = "scene_str",required = false) String sceneStr){
|
|
|
|
+ JSONObject resultObj = new JSONObject();
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ StringBuilder urlBuilder = new StringBuilder();
|
|
|
|
+
|
|
|
|
+ urlBuilder.append(weixinConfig.getCreateQrCodeUrl())
|
|
|
|
+ .append("?access_token=")
|
|
|
|
+ .append(URLEncoder.encode(accessToken,"UTF-8"));
|
|
|
|
+
|
|
|
|
+ HttpPost httpPost = new HttpPost(urlBuilder.toString());
|
|
|
|
+
|
|
|
|
+ CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
|
|
|
+
|
|
|
|
+ JSONObject jsonObject = new JSONObject();
|
|
|
|
+ jsonObject.put("expire_seconds", expireSeconds);
|
|
|
|
+ jsonObject.put("action_name", actionName);
|
|
|
|
+
|
|
|
|
+ JSONObject actionInfo = new JSONObject();
|
|
|
|
+ JSONObject scene = new JSONObject();
|
|
|
|
+
|
|
|
|
+ if(StringUtils.isNotEmpty(sceneId)) {
|
|
|
|
+ scene.put("scene_id", sceneId);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(StringUtils.isNotEmpty(sceneStr)) {
|
|
|
|
+ scene.put("scene_str", sceneStr);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ actionInfo.put("scene",scene);
|
|
|
|
+
|
|
|
|
+ jsonObject.put("action_info", actionInfo);
|
|
|
|
+
|
|
|
|
+ StringEntity entity = new StringEntity(jsonObject.toString(), "utf-8");
|
|
|
|
+
|
|
|
|
+ entity.setContentEncoding("UTF-8");
|
|
|
|
+ entity.setContentType("application/json");//发送json数据需要设置contentType
|
|
|
|
+ httpPost.setEntity(entity);
|
|
|
|
+
|
|
|
|
+ HttpResponse res = httpClient.execute(httpPost);
|
|
|
|
+
|
|
|
|
+ if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
|
|
|
|
+ String content = EntityUtils.toString(res.getEntity());// 返回json格式:
|
|
|
|
+ JSONObject ret = new JSONObject(content);
|
|
|
|
+
|
|
|
|
+ if (ret.containsKey("errcode")) {
|
|
|
|
+ resultObj.put("result",false);
|
|
|
|
+ resultObj.put("message",ret.getStr("errmsg"));
|
|
|
|
+ resultObj.put("code",ret.getInt("errcode"));
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ String ticket = ret.getStr("ticket");
|
|
|
|
+ long expire_seconds = ret.getLong("expire_seconds");
|
|
|
|
+
|
|
|
|
+ resultObj.put("data", weixinConfig.getShowQrCodeUrl() + "?ticket=" + URLEncoder.encode(ticket, "UTF-8"));
|
|
|
|
+ resultObj.put("result", true);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ catch (Exception ex){
|
|
|
|
+ log.error(ex.getMessage(),ex);
|
|
|
|
+
|
|
|
|
+ resultObj.put("message",ex.getMessage());
|
|
|
|
+ resultObj.put("result",false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return resultObj;
|
|
|
|
+ }
|
|
|
|
+}
|