|
@@ -1,10 +1,13 @@
|
|
|
package com.jpsoft.smart.modules.wechat.controller;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.jpsoft.smart.config.WxConfig;
|
|
|
import com.jpsoft.smart.modules.base.entity.InformationInfo;
|
|
|
import com.jpsoft.smart.modules.base.entity.OwnerInfo;
|
|
|
+import com.jpsoft.smart.modules.base.entity.WarningPusher;
|
|
|
import com.jpsoft.smart.modules.base.service.InformationInfoService;
|
|
|
import com.jpsoft.smart.modules.base.service.OwnerInfoService;
|
|
|
+import com.jpsoft.smart.modules.base.service.WarningPusherService;
|
|
|
import com.jpsoft.smart.modules.common.dto.MessageResult;
|
|
|
import com.jpsoft.smart.modules.common.service.impl.RedisServiceImpl;
|
|
|
import com.jpsoft.smart.modules.common.utils.ApiUtil;
|
|
@@ -16,17 +19,36 @@ import com.jpsoft.smart.modules.common.utils.WeixinUtil;
|
|
|
import com.jpsoft.smart.modules.pay.properties.WxPayProperties;
|
|
|
import com.jpsoft.smart.modules.wechat.entity.AccessControl;
|
|
|
import com.jpsoft.smart.modules.wechat.entity.AccessToken;
|
|
|
+import com.jpsoft.smart.modules.wechat.entity.ReplyMessage;
|
|
|
import com.jpsoft.smart.modules.wechat.service.IAccessControlService;
|
|
|
+import com.jpsoft.smart.modules.wechat.service.ReplyMessageService;
|
|
|
import com.jpsoft.smart.modules.wechat.vo.*;
|
|
|
+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.HttpResponse;
|
|
|
+import org.apache.http.HttpStatus;
|
|
|
+import org.apache.http.client.methods.HttpPost;
|
|
|
+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.BeanUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.redis.core.ValueOperations;
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
+import java.io.BufferedReader;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStreamReader;
|
|
|
+import java.net.URLEncoder;
|
|
|
import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* @author 墨鱼_mo
|
|
@@ -42,6 +64,18 @@ public class WxController {
|
|
|
@Autowired
|
|
|
private ApiUtil apiUtil;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private WxConfig wxConfig;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private WarningPusherService warningPusherService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ReplyMessageService replyMessageService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ValueOperations<String,Object> valueOperations;
|
|
|
+
|
|
|
@Autowired
|
|
|
private RedisServiceImpl redisService;
|
|
|
|
|
@@ -631,4 +665,243 @@ public class WxController {
|
|
|
return new MessageResult(result, message, data, code);
|
|
|
}
|
|
|
|
|
|
+ @ApiOperation(value="验证服务器地址的有效性")
|
|
|
+ @GetMapping("/get")
|
|
|
+ @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(wxConfig.getToken(),signature,timestamp,nonce)){
|
|
|
+ return echostr;
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ return "index";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @ResponseBody
|
|
|
+ @ApiOperation(value = "创建二维码")
|
|
|
+ @PostMapping("/qrcode/create")
|
|
|
+ @ApiImplicitParams({
|
|
|
+ @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 cn.hutool.json.JSONObject createQrcode(@RequestParam(name = "expire_seconds",defaultValue = "300") long expireSeconds,
|
|
|
+ @RequestParam(name = "action_name",defaultValue = "QR_STR_SCENE") String actionName,
|
|
|
+ @RequestParam(name = "scene_id",required = false) String sceneId,
|
|
|
+ @RequestParam(name = "scene_str",required = false) String sceneStr){
|
|
|
+ cn.hutool.json.JSONObject resultObj = new cn.hutool.json.JSONObject();
|
|
|
+
|
|
|
+ try {
|
|
|
+ StringBuilder urlBuilder = new StringBuilder();
|
|
|
+ AccessToken accessToken = WeixinUtil.getAccessToken(wxConfig.getAppId(),wxConfig.getAppSecret());
|
|
|
+
|
|
|
+ urlBuilder.append(wxConfig.getCreateQrCodeUrl())
|
|
|
+ .append("?access_token=")
|
|
|
+ .append(URLEncoder.encode(accessToken.getToken(),"UTF-8"));
|
|
|
+
|
|
|
+ cn.hutool.json.JSONObject jsonObject = new cn.hutool.json.JSONObject();
|
|
|
+ jsonObject.put("expire_seconds", expireSeconds);
|
|
|
+ jsonObject.put("action_name", actionName);
|
|
|
+
|
|
|
+ cn.hutool.json.JSONObject actionInfo = new cn.hutool.json.JSONObject();
|
|
|
+ cn.hutool.json.JSONObject scene = new cn.hutool.json.JSONObject();
|
|
|
+
|
|
|
+ StringBuilder keyBuilder = new StringBuilder();
|
|
|
+
|
|
|
+ keyBuilder.append(accessToken);
|
|
|
+
|
|
|
+ if(StringUtils.isNotEmpty(sceneId)) {
|
|
|
+ scene.put("scene_id", sceneId);
|
|
|
+ keyBuilder.append(sceneId);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(StringUtils.isNotEmpty(sceneStr)) {
|
|
|
+ scene.put("scene_str", sceneStr);
|
|
|
+ keyBuilder.append(sceneStr);
|
|
|
+ }
|
|
|
+
|
|
|
+ String qrcodeUrl = (String)valueOperations.get("QRCODE_" + keyBuilder.toString());
|
|
|
+
|
|
|
+ if (StringUtils.isNotEmpty(qrcodeUrl)){
|
|
|
+ resultObj.put("data",qrcodeUrl);
|
|
|
+ resultObj.put("result", true);
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ actionInfo.put("scene",scene);
|
|
|
+
|
|
|
+ jsonObject.put("action_info", actionInfo);
|
|
|
+
|
|
|
+ StringEntity entity = new StringEntity(jsonObject.toString(), "utf-8");
|
|
|
+
|
|
|
+ entity.setContentType("application/json");//发送json数据需要设置contentType
|
|
|
+
|
|
|
+ HttpPost httpPost = new HttpPost(urlBuilder.toString());
|
|
|
+ CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
|
|
+
|
|
|
+ httpPost.setEntity(entity);
|
|
|
+
|
|
|
+ HttpResponse res = httpClient.execute(httpPost);
|
|
|
+
|
|
|
+ if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
|
|
|
+ String content = EntityUtils.toString(res.getEntity());// 返回json格式:
|
|
|
+ cn.hutool.json.JSONObject ret = new cn.hutool.json.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");
|
|
|
+
|
|
|
+ qrcodeUrl = wxConfig.getShowQrCodeUrl() + "?ticket=" + URLEncoder.encode(ticket, "UTF-8");
|
|
|
+
|
|
|
+ valueOperations.set("QRCODE_" + keyBuilder, qrcodeUrl, expire_seconds - 5, TimeUnit.SECONDS);
|
|
|
+
|
|
|
+ resultObj.put("data", qrcodeUrl);
|
|
|
+ resultObj.put("result", true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ resultObj.put("result", false);
|
|
|
+ resultObj.put("message", "weixin服务器未正常返回!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex){
|
|
|
+ log.error(ex.getMessage(),ex);
|
|
|
+
|
|
|
+ resultObj.put("message",ex.getMessage());
|
|
|
+ resultObj.put("result",false);
|
|
|
+ }
|
|
|
+
|
|
|
+ return resultObj;
|
|
|
+ }
|
|
|
+
|
|
|
+ @ApiOperation(value = "处理消息事件")
|
|
|
+ @PostMapping("/get")
|
|
|
+ public void processEvent(HttpServletRequest request, HttpServletResponse response){
|
|
|
+ try{
|
|
|
+ log.warn("收到post请求");
|
|
|
+
|
|
|
+ cn.hutool.json.JSONObject requestJson = null;
|
|
|
+
|
|
|
+ if("json".equals(wxConfig.getContentType())){
|
|
|
+ String jsonStr = new BufferedReader(new InputStreamReader(request.getInputStream()))
|
|
|
+ .lines().parallel().collect(Collectors.joining(System.lineSeparator()));
|
|
|
+
|
|
|
+ requestJson = new cn.hutool.json.JSONObject(jsonStr);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ requestJson = WeixinUtil.xmlToJson(request.getInputStream());
|
|
|
+ }
|
|
|
+
|
|
|
+ log.warn(requestJson.toString());
|
|
|
+
|
|
|
+ response.setContentType("UTF-8");
|
|
|
+ response.setContentType("text/html; charset=UTF-8");
|
|
|
+ response.setCharacterEncoding("UTF-8");
|
|
|
+
|
|
|
+ String event = requestJson.getStr("Event");
|
|
|
+ String eventKey = requestJson.getStr("EventKey");
|
|
|
+
|
|
|
+ /*
|
|
|
+ 正常扫码是:"EventKey":"7000,2142006";
|
|
|
+ 当未关注时,扫码是"EventKey":"qrscene_7000,2142006"
|
|
|
+ */
|
|
|
+ if(StringUtils.isNotEmpty(eventKey) && eventKey.indexOf("_")!=-1){
|
|
|
+ String[] arr = eventKey.split("_");
|
|
|
+
|
|
|
+ if(arr.length>0){
|
|
|
+ eventKey = arr[1];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //微信公众号编号
|
|
|
+ String wechatId = requestJson.getStr("ToUserName");
|
|
|
+ //扫码用户openID
|
|
|
+ String openId = requestJson.getStr("FromUserName");
|
|
|
+
|
|
|
+
|
|
|
+ boolean processed = false;
|
|
|
+
|
|
|
+ if (StringUtils.isNotEmpty(eventKey) && eventKey.indexOf(",")!=-1) {
|
|
|
+ String[] keys = eventKey.split(",");
|
|
|
+ String eventCode = keys[0];
|
|
|
+ String id = keys[1];
|
|
|
+
|
|
|
+ ReplyMessage replyMessage = replyMessageService.findByEvent(eventCode);
|
|
|
+
|
|
|
+ if (replyMessage != null) {
|
|
|
+ WarningPusher warningPusher = warningPusherService.get(id);
|
|
|
+ if (warningPusher == null){
|
|
|
+ WeixinUtil.replyTextMessage(response, wechatId, openId,"绑定信息不存在,请联系管理员");
|
|
|
+ }
|
|
|
+ else if (StringUtils.isNotBlank(warningPusher.getOpenId())){
|
|
|
+ WeixinUtil.replyTextMessage(response, wechatId, openId,"此二维码已被绑定,请联系管理员");
|
|
|
+ }else {
|
|
|
+ warningPusher.setOpenId(openId);
|
|
|
+ warningPusher.setUpdateTime(new Date());
|
|
|
+ warningPusherService.update(warningPusher);
|
|
|
+ WeixinUtil.replyTextMessage(response, wechatId, openId,replyMessage.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ processed = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //开发者在5秒内未回复任何内容
|
|
|
+// for (EventCallback callback : callbackList) {
|
|
|
+// if (StringUtils.isNotEmpty(eventKey) && eventKey.startsWith(callback.getCode())) {
|
|
|
+// callback.process(wechatId, openId, eventKey);
|
|
|
+//
|
|
|
+// WeixinUtil.replyTextMessage(response, wechatId, openId, callback.getMessage());
|
|
|
+//
|
|
|
+// processed = true;
|
|
|
+// break;
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+ if(!processed) {
|
|
|
+ String responseText = "success";
|
|
|
+
|
|
|
+ if("subscribe".equals(event)){
|
|
|
+ /* ReplyMessage replyMessage = replyMessageService.findByEvent(wechatId,event);
|
|
|
+
|
|
|
+ if(replyMessage!=null) {
|
|
|
+ WeixinUtil.replyTextMessage(response, wechatId, openId, replyMessage.getMessage());
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ log.warn(openId + ",事件:" + event + "未设置自动回复!");
|
|
|
+ response.getWriter().print(responseText);
|
|
|
+ }*/
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ response.getWriter().print(responseText);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception ex){
|
|
|
+ log.error(ex.getMessage(),ex);
|
|
|
+
|
|
|
+ try {
|
|
|
+ response.getWriter().print("fail");
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|