Ver código fonte

add: 微信公众号消息推送

请输入用户名 3 anos atrás
pai
commit
ec528c1b21
26 arquivos alterados com 1148 adições e 1 exclusões
  1. 22 0
      src/main/java/com/care/client/config/PlatformOfficialConfig.java
  2. 92 0
      src/main/java/com/care/client/controller/TestWxController.java
  3. 158 0
      src/main/java/com/care/client/controller/WxMsgController.java
  4. 25 0
      src/main/java/com/care/client/dto/MpTemplateMsgDTO.java
  5. 34 0
      src/main/java/com/care/client/dto/TemplateDataDTO.java
  6. 53 0
      src/main/java/com/care/client/dto/WxTemplateDTO.java
  7. 17 0
      src/main/java/com/care/client/dto/WxUniformTemplateDTO.java
  8. 8 0
      src/main/java/com/care/client/service/PassportService.java
  9. 11 0
      src/main/java/com/care/client/service/WxPassportService.java
  10. 2 0
      src/main/java/com/care/client/vo/MemberInitParams.java
  11. 31 0
      src/main/java/com/care/client/vo/WxAccessTokenVO.java
  12. 3 0
      src/main/java/com/care/common/cache/RedisKeyConstant.java
  13. 4 1
      src/main/java/com/care/common/entity/CareMemberInfo.java
  14. 68 0
      src/main/java/com/care/common/entity/CareOfficialMemberInfo.java
  15. 15 0
      src/main/java/com/care/common/mapper/CareOfficialMemberInfoMapper.java
  16. 4 0
      src/main/java/com/care/common/service/CareMemberInfoService.java
  17. 29 0
      src/main/java/com/care/common/service/CareOfficialMemberInfoService.java
  18. 31 0
      src/main/java/com/care/common/service/WxTemplateService.java
  19. 12 0
      src/main/java/com/care/common/service/impl/CareMemberInfoServiceImpl.java
  20. 50 0
      src/main/java/com/care/common/service/impl/CareOfficialMemberInfoServiceImpl.java
  21. 192 0
      src/main/java/com/care/common/service/impl/WxTemplateServiceImpl.java
  22. 53 0
      src/main/java/com/care/common/util/CheckoutUtil.java
  23. 11 0
      src/main/java/com/care/common/util/MessageUtil.java
  24. 26 0
      src/main/java/com/care/common/util/MyX509TrustManager.java
  25. 193 0
      src/main/java/com/care/common/util/WxTemplateUtil.java
  26. 4 0
      src/main/resources/application.properties

+ 22 - 0
src/main/java/com/care/client/config/PlatformOfficialConfig.java

@@ -0,0 +1,22 @@
+package com.care.client.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 描述:
+ *
+ * @autho:wenskys
+ * @create 2020/5/11 0:05
+ **/
+@Configuration
+public class PlatformOfficialConfig {
+
+    @Bean
+    @ConfigurationProperties(prefix = "wx.official")
+    public WxConfig officialConfig() {
+        return new WxConfig();
+    }
+
+}

+ 92 - 0
src/main/java/com/care/client/controller/TestWxController.java

@@ -0,0 +1,92 @@
+package com.care.client.controller;
+
+import com.care.common.service.WxTemplateService;
+import com.care.client.dto.TemplateDataDTO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+@Api(tags = "模板测试")
+@RestController
+@RequestMapping("/wxtemplate")
+@Slf4j
+public class TestWxController {
+
+    @Resource
+    private WxTemplateService wxTemplateService;
+
+    @ApiOperation(value = "模板测试", notes = "消息发送")
+    @GetMapping("send")
+    public void test(@RequestParam("openId") String openId, @RequestParam("templateId") String templateId) {
+
+
+//        WxAccessTokenVO wxda02870032b8f928 = WxTemplateUtil.getAccessToken("wxda02870032b8f928", "5984b6cf5dad4693eb60cbc494d9f385");
+//        System.out.println();
+
+//        WxConfig wxConfig = platformPinanbaoConfig.wxConfig();
+
+        // 获取accessToken
+//        WxAccessTokenVO wxAccessTokenVO = WxTemplateUtil.getAccessToken(wxConfig.getAppId(), wxConfig.getSecret());
+//        WxAccessTokenVO wxAccessTokenVO = WxTemplateUtil.getAccessToken("wxf393853ab94c853f", "f3fc21fee8de01d79ded7f799a4d2d4d");
+//        WxAccessTokenVO wxAccessTokenVO = new WxAccessTokenVO();
+//        wxAccessTokenVO.setAccessToken("50_hMKs4nHb0yvJwhfByWRc01Zq_ksQ34mfWHwHkymrT560MuDcW8DMuRTKTa5QjH06ZL-slBSGqKR42R7cPWsFoy6u7wlkpEDQgjG-Hv0YG9GA3FEZRMUsd-Zy0ePKCN06Ur2uNrzNPkdefA6tSEKjADAVHN");
+//        wxAccessTokenVO.setExpiresIn(7200);
+
+//        WxAccessTokenVO wxAccessTokenVO = new WxAccessTokenVO();
+//        if (redisUtil.hasKey(RedisKeyConstant.YUANSERVICE_ACCESSTOKEN + "y")) {
+//            wxAccessTokenVO.setAccessToken(ObjectUtils.toString(redisUtil.get(RedisKeyConstant.YUANSERVICE_ACCESSTOKEN)));
+//        } else {
+//            wxAccessTokenVO = WxTemplateUtil.getAccessToken("wxf393853ab94c853f", "f3fc21fee8de01d79ded7f799a4d2d4d");
+//            wxAccessTokenVO = WxTemplateUtil.getAccessToken("wxd735a330f9387639", "f0b4652c392b7cae457fe9d986115052");
+//            if (wxAccessTokenVO == null || StringUtils.isBlank(wxAccessTokenVO.getAccessToken())) {
+//                return;
+//            }
+//            redisUtil.set(RedisKeyConstant.YUANSERVICE_ACCESSTOKEN, wxAccessTokenVO.getAccessToken(),60 * 100);
+//        }
+//        WxTemplateUtil.getUserOpenIdList(wxAccessTokenVO.getAccessToken(), "oAIrY6RoG56fKOZZD6auXgdheV_Y");
+
+//        System.out.println("token: " + wxAccessTokenVO.getAccessToken());
+
+        // 消息模板对象
+//        WxTemplateDTO wxTemplateDTO = new WxTemplateDTO();
+        // 时间格式转换
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+        // 用户openIdopenid ->
+//        wxTemplateDTO.setTouser("oAIrY6RoG56fKOZZD6auXgdheV_Y");
+//        self
+//        wxTemplateDTO.setTouser("oAIrY6ci3o4O_HtGGKzVj495vV7M");
+//        wxTemplateDTO.setTouser("oAvJS6tYkZCwm6xC8m6uqW-UjBGc");
+        // 模板ID
+//        wxTemplateDTO.setTemplate_id("1M1kDRDW-kMSoOzmv9cP-SImD1kXWtezwyWe8euUJIc");
+//        wxTemplateDTO.setTemplate_id("S86r6mkzaKIv-m9HndhFgCmyCrrv9Uw87_5THakYCkQ");
+        // 跳转页面设置(仅限上线后的小程序,测试时可以忽略此属性)
+//        wxTemplateDTO.setPage("pages/index/index");
+
+        Map<String, TemplateDataDTO> data = new HashMap<>();
+        data.put("first", new TemplateDataDTO("您关联的与安宝设备上传一条安全事件", "#ff5200"));
+        data.put("keyword1", new TemplateDataDTO("跌倒报警", "#000000"));
+        data.put("keyword2", new TemplateDataDTO(simpleDateFormat.format(new Date()), "#000000"));
+        data.put("keyword3", new TemplateDataDTO("北京市丰台区金桥东街6号 顶秀金石家园1号楼1单元111室", "#000000"));
+        data.put("remark", new TemplateDataDTO("请尽快联系您的被监护人, 确认现场情况", "#ff5200"));
+        // 模板内容
+//        wxTemplateDTO.setData(data);
+
+        // 发送消息模板
+//        boolean flag = wxTemplateService.sendTemplateMsg("oyVYT6Ox9b88n_33lgKWRj5uFbUY", "S86r6mkzaKIv-m9HndhFgCmyCrrv9Uw87_5THakYCkQ", data);
+        boolean flag = wxTemplateService.sendTemplateMsg(openId, templateId, "wxda02870032b8f928", "/page/index/index", data);
+        log.info("发送消息模板: openId: " + openId + ", templateId: " + templateId + " 状态: " + flag);
+
+    }
+
+}

+ 158 - 0
src/main/java/com/care/client/controller/WxMsgController.java

@@ -0,0 +1,158 @@
+//package com.care.client.controller;
+//
+//import cn.hutool.core.util.XmlUtil;
+//import cn.hutool.json.JSONObject;
+//import com.care.common.entity.CareOfficialMemberInfo;
+//import com.care.common.service.CareOfficialMemberInfoService;
+//import com.care.common.service.WxTemplateService;
+//import com.care.common.util.CheckoutUtil;
+//import com.care.common.util.MessageUtil;
+//import com.care.client.vo.WxAccessTokenVO;
+//import com.care.common.util.WxTemplateUtil;
+//import lombok.extern.slf4j.Slf4j;
+//import org.apache.commons.lang3.ObjectUtils;
+//import org.springframework.stereotype.Controller;
+//import org.springframework.web.bind.annotation.RequestMapping;
+//import org.springframework.web.bind.annotation.RequestMethod;
+//import org.springframework.web.bind.annotation.ResponseBody;
+//import org.w3c.dom.Document;
+//import org.w3c.dom.Element;
+//
+//import javax.annotation.Resource;
+//import javax.servlet.http.HttpServletRequest;
+//import javax.servlet.http.HttpServletResponse;
+//import java.io.IOException;
+//import java.io.PrintWriter;
+//import java.util.Date;
+//import java.util.Map;
+//
+//@Controller
+//@RequestMapping("/wxmsg")
+//@Slf4j
+//public class WxMsgController {
+//
+//    @Resource
+//    private CareOfficialMemberInfoService careOfficialMemberInfoService;
+//
+////    @Resource
+////    private CareMemberInfoService careMemberInfoService;
+//
+//    @Resource
+//    private WxTemplateService wxService;
+//
+//    /**
+//     * 微信消息接收和token验证
+//     * @param request
+//     * @param response
+//     * @throws IOException
+//     */
+//        @RequestMapping(value="/checkToken",method= RequestMethod.GET)
+//    public void weChat(HttpServletRequest request, HttpServletResponse response) throws IOException {
+//        boolean isGet = request.getMethod().toLowerCase().equals("get");
+//        if (isGet) {
+//            // 微信加密签名
+//            String signature = request.getParameter("signature");
+//            // 时间戳
+//            String timestamp = request.getParameter("timestamp");
+//            // 随机数
+//            String nonce = request.getParameter("nonce");
+//            // 随机字符串
+//            String echostr = request.getParameter("echostr");
+//            // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
+//            if (signature != null && CheckoutUtil.checkSignature(signature, timestamp, nonce)) {
+//                try {
+//                    boolean flag = CheckoutUtil.checkSignature(signature, timestamp, nonce);
+//                    System.out.println(flag);
+//                    PrintWriter print = response.getWriter();
+//                    print.write(echostr);
+//                    System.out.println(echostr);
+//                    print.flush();
+//                    print.close();
+//                } catch (IOException e) {
+//                    e.printStackTrace();
+//                }
+//            }
+//        }
+//    }
+//
+//    @RequestMapping(value="/checkToken",method=RequestMethod.POST)
+//    @ResponseBody
+//    public String  responseEvent(HttpServletRequest req, HttpServletResponse resp)throws IOException {
+//        req.setCharacterEncoding("UTF-8");
+//        resp.setCharacterEncoding("UTF-8");
+//        String message = "success";
+//        try {
+//            WxAccessTokenVO wxAccessTokenVO = wxService.processAccessToken();
+//            if (wxAccessTokenVO == null) {
+//                return "failure";
+//            }
+//            // 读取输入流
+//            Document document = XmlUtil.readXML(req.getInputStream());
+//            // 得到xml根元素
+//            Element element = document.getDocumentElement();
+//            //把微信返回的xml信息转义成map
+//            Map<String, Object> map = XmlUtil.xmlToMap(element);
+//            System.out.println("微信接收到的消息为:"+map.toString());
+//            String fromUserName = ObjectUtils.toString(map.get("FromUserName"));//消息来源用户标识
+//            String msgType = ObjectUtils.toString(map.get("MsgType"));//消息类型(event或者text)
+//            String eventType = ObjectUtils.toString(map.get("Event"));//事件类型
+////            String nickName = getUserNickName(fromUserName);
+//            if(MessageUtil.MSGTYPE_EVENT.equals(msgType)){//如果为事件类型
+//                if(MessageUtil.SUBSCIBE_EVENT.equals(eventType)){//处理订阅事件
+//                    JSONObject parseUnionObject = WxTemplateUtil.parseWxOpenIdBySubscribe(wxAccessTokenVO.getAccessToken(), fromUserName);
+////                    parseUnionObject.set("unionid", "oyVYT6Ox9b88n_33lgKWRj5uFbUY");
+//                    if (parseUnionObject != null && parseUnionObject.containsKey("unionid")) {
+//                        CareOfficialMemberInfo careOfficialMemberInfo = new CareOfficialMemberInfo();
+//                        careOfficialMemberInfo.setNickname(parseUnionObject.getStr("nickname"));
+//                        careOfficialMemberInfo.setOpenId(fromUserName);
+//                        careOfficialMemberInfo.setProfile(parseUnionObject.getStr("headimgurl"));
+//                        careOfficialMemberInfo.setUnionId(parseUnionObject.getStr("unionid"));
+//                        careOfficialMemberInfo.setSubscribeStatus(1);
+//                        careOfficialMemberInfo.setCreateTime(new Date());
+//                        boolean subscribed = careOfficialMemberInfoService.subscribe(careOfficialMemberInfo);
+//                        if (subscribed) {
+//                            return "success";
+//                        } else {
+//                            return "failure";
+//                        }
+//                    }
+//                } else if (MessageUtil.UNSUBSCIBE_EVENT.equals(eventType)) {//处理取消订阅事件
+//                    System.out.println("事件类型为:"+eventType);
+//                    JSONObject parseUnionObject = WxTemplateUtil.parseWxOpenIdBySubscribe(wxAccessTokenVO.getAccessToken(), fromUserName);
+//                    if (parseUnionObject != null && parseUnionObject.containsKey("unionid")) {
+//                        boolean updated = careOfficialMemberInfoService.cancelSubscribe(parseUnionObject.getStr("unionid"));
+//                        if (updated) {
+//                            return "success";
+//                        } else {
+//                            return "failure";
+//                        }
+//                    }
+////                    message = MessageUtil.unsubscribe(toUserName, fromUserName);
+//                }
+//            }else {
+////                //微信消息分为事件推送消息和普通消息,非事件即为普通消息类型
+////                switch (msgType) {
+////                    case "text":{//文本消息
+////                        String content = map.get("Content");//用户发的消息内容
+////                        content = "您发的消息内容是:"+content+",如需帮助,请联系";
+////                        message = MessageUtil.replyMsg(toUserName, fromUserName,content,"text");
+////                        break;
+////                    }
+////                    case "image":{//图片消息
+////                        String content = "您发的消息内容是图片,如需帮助,请联系";
+////                        message = MessageUtil.replyMsg(toUserName, fromUserName,content,"text");
+////                        break;
+////                    }
+////                    default:{//其他类型的普通消息
+////                        break;
+////                    }
+////                }
+//            }
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
+//        System.out.println("关注微信公众号自动回复的消息内容为:" + message);
+//        return message;
+//    }
+//
+//}

+ 25 - 0
src/main/java/com/care/client/dto/MpTemplateMsgDTO.java

@@ -0,0 +1,25 @@
+package com.care.client.dto;
+
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+public class MpTemplateMsgDTO {
+
+    /** 公众号appid,要求与小程序有绑定且同主体 */
+    private String appid;
+
+    /** 公众号模板id */
+    private String template_id;
+
+    /** 公众号模板消息所要跳转的url */
+    private String url;
+
+    /** 公众号模板消息所要跳转的小程序,小程序的必须与公众号具有绑定关系 */
+    private Map<String, String> miniprogram;
+
+    /** 模板内容,不填则下发空模板(必填) */
+    private Map<String, TemplateDataDTO> data;
+
+}

+ 34 - 0
src/main/java/com/care/client/dto/TemplateDataDTO.java

@@ -0,0 +1,34 @@
+package com.care.client.dto;
+
+/**
+ * 消息模板内容,字体大小,颜色可配置
+ */
+public class TemplateDataDTO {
+
+    /** 模板内容字体的颜色,不填默认黑色.*/
+    private String color;
+
+    /** 模板需要放大的关键词,不填则默认无放大.*/
+    private String value;
+
+    public String getColor() {
+        return color;
+    }
+
+    public void setColor(String color) {
+        this.color = color;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public TemplateDataDTO(String value, String color) {
+        this.value = value;
+        this.color = color;
+    }
+}

+ 53 - 0
src/main/java/com/care/client/dto/WxTemplateDTO.java

@@ -0,0 +1,53 @@
+package com.care.client.dto;
+
+import java.util.Map;
+
+/**
+ * 消息模板基本属性封装,参数命名风格需参照微信参数定义
+ */
+public class WxTemplateDTO {
+
+    /** 模板消息ID(必填).*/
+    private String template_id;
+
+    /** 接收者(用户)的 openid(必填).*/
+    private String touser;
+
+    /** 点击模板卡片后的跳转页面.*/
+    private String page;
+
+    /** 模板内容,不填则下发空模板(必填).*/
+    private Map<String, TemplateDataDTO> data;
+
+    public String getTemplate_id() {
+        return template_id;
+    }
+
+    public void setTemplate_id(String template_id) {
+        this.template_id = template_id;
+    }
+
+    public String getTouser() {
+        return touser;
+    }
+
+    public void setTouser(String touser) {
+        this.touser = touser;
+    }
+
+    public String getPage() {
+        return page;
+    }
+
+    public void setPage(String page) {
+        this.page = page;
+    }
+
+    public Map<String, TemplateDataDTO> getData() {
+        return data;
+    }
+
+    public void setData(Map<String, TemplateDataDTO> data) {
+        this.data = data;
+    }
+}

+ 17 - 0
src/main/java/com/care/client/dto/WxUniformTemplateDTO.java

@@ -0,0 +1,17 @@
+package com.care.client.dto;
+
+import lombok.Data;
+
+/**
+ * 消息模板基本属性封装,参数命名风格需参照微信参数定义
+ */
+@Data
+public class WxUniformTemplateDTO {
+
+    /** 接收者(用户)的 openid(必填).*/
+    private String touser;
+
+    /** 公众号配置 */
+    private MpTemplateMsgDTO mp_template_msg;
+
+}

+ 8 - 0
src/main/java/com/care/client/service/PassportService.java

@@ -83,6 +83,7 @@ public class PassportService extends AbstractPassportService {
          if (StringUtils.isEmpty(openId)){
              return  Result.error();
          }
+         String unionId = params.getUnionid();
          //判断是否注册过了
          CareMemberInfo careMemberInfoDb = careMemberInfoService.detailByOpenid(openId);
          if(careMemberInfoDb != null) {
@@ -104,6 +105,7 @@ public class PassportService extends AbstractPassportService {
              CareMemberInfo careMemberInfo = new CareMemberInfo();
              careMemberInfo.setPhone(phone);
              careMemberInfo.setOpenId(openId);
+             careMemberInfo.setUnionId(unionId);
 
              //前端主动获取传给后台,下面不用了
 //             String accessToken= wxPassportService.accessToken();
@@ -128,6 +130,12 @@ public class PassportService extends AbstractPassportService {
                  return Result.error();
              }
          } else { //已经注册了
+             if (StringUtils.isNotBlank(openId) && StringUtils.isNotBlank(unionId)) {
+                 boolean updated = careMemberInfoService.modifyUnionId(openId, openId);
+                 if (!updated) {
+                     log.error("修改用户平台唯一标识出现错误, openId: " + openId + "; unionId: " + unionId);
+                 }
+             }
              return cache(params);
          }
      }

+ 11 - 0
src/main/java/com/care/client/service/WxPassportService.java

@@ -11,6 +11,7 @@ import com.care.common.entity.CareMemberInfo;
 import com.care.common.service.CareMemberInfoService;
 import com.care.common.util.HttpUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -37,9 +38,18 @@ public class WxPassportService extends AbstractPassportService {
         log.warn("-----jsonObject:[{}]", jsonObject);
 
         String openid = jsonObject.getStr("openid");
+        String unionid = jsonObject.getStr("unionid");
         //判断是否注册过了
         CareMemberInfo careMemberInfo = careMemberInfoService.detailByOpenid(openid);
         if(careMemberInfo != null) {
+            if (StringUtils.isNotBlank(openid) && StringUtils.isNotBlank(unionid)) {
+                boolean updated = careMemberInfoService.modifyUnionId(openid, unionid);
+                if (!updated) {
+                    log.error("修改用户平台唯一标识出现错误, openId: " + openid + "; unionId: " + unionid);
+                }
+            } else {
+                log.error("未获取到用户" + careMemberInfo.getNickname() + " 的平台唯一标识, openId: " + openid);
+            }
             return careMemberInfo;
         } else { //没有注册,走第二步
             String sessionKey = jsonObject.getStr("session_key");
@@ -48,6 +58,7 @@ public class WxPassportService extends AbstractPassportService {
             MemberInitParams memberInitParams = new MemberInitParams();
             memberInitParams.setLoginType("wx");
             memberInitParams.setOpenid(openid);
+            memberInitParams.setUnionid(unionid);
             memberInitParams.setSessionKey(sessionKey);
             redisUtil.hset(RedisKeyConstant.PINANBAO_WX_LOGIN_INFO, params.getCode(), memberInitParams, RedisKeyConstant.PINANBAO_WX_LOGIN_INFO_TIME);
             return null;

+ 2 - 0
src/main/java/com/care/client/vo/MemberInitParams.java

@@ -15,6 +15,8 @@ public class MemberInitParams implements Serializable {
     private String code;
     @ApiModelProperty(name = "openid", value = "平台标识")
     private String openid;
+    @ApiModelProperty(name = "unionid", value = "用户唯一标识")
+    private String unionid;
     @ApiModelProperty(name = "sessionKey", value = "session_key")
     private String sessionKey;
 

+ 31 - 0
src/main/java/com/care/client/vo/WxAccessTokenVO.java

@@ -0,0 +1,31 @@
+package com.care.client.vo;
+
+import java.io.Serializable;
+
+/**
+ * 获取微信accessToken接口信息,参数封装
+ */
+public class WxAccessTokenVO implements Serializable {
+
+    /** 获取到的凭证.*/
+    private String accessToken;
+
+    /** 凭证有效时间,单位:秒.*/
+    private Integer expiresIn;
+
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    public Integer getExpiresIn() {
+        return expiresIn;
+    }
+
+    public void setExpiresIn(Integer expiresIn) {
+        this.expiresIn = expiresIn;
+    }
+}

+ 3 - 0
src/main/java/com/care/common/cache/RedisKeyConstant.java

@@ -65,4 +65,7 @@ public class RedisKeyConstant {
     //设备Mqtt心跳信息 5m
     public static final String MQTT_DEV_HEARBEAT_INFO = "MQTT:HEARBEAT";
     public static final int MQTT_DEV_HEARBEAT_INFO_TIME = 60 * 5;
+
+    // 与安服务平台 -> 小程序, 请求TOKEN, 100m
+    public static final String YUANSERVICE_ACCESSTOKEN = "YUANSERVICE:ACCESSTOKEN";
 }

+ 4 - 1
src/main/java/com/care/common/entity/CareMemberInfo.java

@@ -31,11 +31,14 @@ public class CareMemberInfo implements Serializable {
     @TableId(value = "ID", type = IdType.AUTO)
     private Long id;
 
-
     @ApiModelProperty("openId")
     @TableField("OPEN_ID")
     private String openId;
 
+    @ApiModelProperty("unionId")
+    @TableField("UNION_ID")
+    private String unionId;
+
 
     @ApiModelProperty("姓名")
     @TableField("NAME")

+ 68 - 0
src/main/java/com/care/common/entity/CareOfficialMemberInfo.java

@@ -0,0 +1,68 @@
+//package com.care.common.entity;
+//
+//import com.baomidou.mybatisplus.annotation.IdType;
+//import com.baomidou.mybatisplus.annotation.TableField;
+//import com.baomidou.mybatisplus.annotation.TableId;
+//import com.baomidou.mybatisplus.annotation.TableName;
+//import io.swagger.annotations.ApiModel;
+//import io.swagger.annotations.ApiModelProperty;
+//import lombok.Data;
+//import lombok.EqualsAndHashCode;
+//import lombok.experimental.Accessors;
+//
+//import java.io.Serializable;
+//import java.util.Date;
+//
+///**
+// * 微信公众号成员关联表(CareOfficialMemberInfo)实体类
+// *
+// * @author lyao
+// * @since 2021-11-14 11:07:14
+// */
+//
+//@Data
+//@EqualsAndHashCode(callSuper = false)
+//@Accessors(chain = true)
+//@TableName("care_official_member_info")
+//@ApiModel(value = "频安宝公众号用户信息", description = "")
+//public class CareOfficialMemberInfo implements Serializable {
+//
+//    private static final long serialVersionUID = 806178869535928668L;
+//
+//    @TableId(value = "ID", type = IdType.AUTO)
+//    private Long id;
+//
+//    @ApiModelProperty("openId")
+//    @TableField("OPEN_ID")
+//    private String openId;
+//
+//    @ApiModelProperty("unionId")
+//    @TableField("UNION_ID")
+//    private String unionId;
+//
+//
+//    @ApiModelProperty("昵称")
+//    @TableField("NICKNAME")
+//    private String nickname;
+//
+//
+//    @ApiModelProperty("头像")
+//    @TableField("PROFILE")
+//    private String profile;
+//
+//
+//    @ApiModelProperty("关注状态")
+//    @TableField(" SUBSCRIBE_STATUS")
+//    private Integer subscribeStatus;
+//
+//
+//    @ApiModelProperty("createTime")
+//    @TableField("CREATE_TIME")
+//    private Date createTime;
+//
+//
+//    @ApiModelProperty("modifyTime")
+//    @TableField("MODIFY_TIME")
+//    private Date modifyTime;
+//
+//}

+ 15 - 0
src/main/java/com/care/common/mapper/CareOfficialMemberInfoMapper.java

@@ -0,0 +1,15 @@
+//package com.care.common.mapper;
+//
+//import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+//import com.care.common.entity.CareOfficialMemberInfo;
+//
+//
+///**
+// * 微信公众号成员关联表(CareOfficialMemberInfo)表数据库访问层
+// *
+// * @author makejava
+// * @since 2021-06-02 21:43:38
+// */
+//public interface CareOfficialMemberInfoMapper extends BaseMapper<CareOfficialMemberInfo> {
+//
+//}

+ 4 - 0
src/main/java/com/care/common/service/CareMemberInfoService.java

@@ -13,4 +13,8 @@ public interface CareMemberInfoService extends IService<CareMemberInfo> {
     CareMemberInfo detailByOpenid(String openId);
 
     CareMemberInfo detailByPhone(String phone);
+
+    boolean modifyUnionId(Long id, String unionId);
+
+    boolean modifyUnionId(String openId, String unionId);
 }

+ 29 - 0
src/main/java/com/care/common/service/CareOfficialMemberInfoService.java

@@ -0,0 +1,29 @@
+//package com.care.common.service;
+//
+//import com.baomidou.mybatisplus.extension.service.IService;
+//import com.care.common.entity.CareOfficialMemberInfo;
+//
+//public interface CareOfficialMemberInfoService extends IService<CareOfficialMemberInfo> {
+//
+//    /**
+//     * 通过唯一标识获取关联
+//     * @param unionId
+//     * @return
+//     */
+//    CareOfficialMemberInfo findByUnionId(String unionId);
+//
+//    /**
+//     * 处理关注
+//     * @param careOfficialMemberInfo
+//     * @return
+//     */
+//    boolean subscribe(CareOfficialMemberInfo careOfficialMemberInfo);
+//
+//    /**
+//     * 取消关注
+//     * @param unionId
+//     * @return
+//     */
+//    boolean cancelSubscribe(String unionId);
+//
+//}

+ 31 - 0
src/main/java/com/care/common/service/WxTemplateService.java

@@ -0,0 +1,31 @@
+package com.care.common.service;
+
+import com.care.client.dto.TemplateDataDTO;
+import com.care.client.vo.WxAccessTokenVO;
+
+import java.util.Map;
+
+public interface WxTemplateService {
+
+    WxAccessTokenVO processAccessToken();
+
+    /**
+     * 发送模板消息
+     * @param openId 小程序OPENID
+     * @param templateId 公众号模板ID
+     * @param dataMap 数据内容
+     */
+    boolean sendTemplateMsg(String openId, String templateId, Map<String, TemplateDataDTO> dataMap);
+
+    /**
+     * 发送模板消息
+     * @param openId 小程序OPENID
+     * @param templateId 公众号模板ID
+     * @param miniprogramAppid 小程序APPID
+     * @param miniprogramPage 小程序链接地址
+     * @param dataMap 数据内容
+     * @return
+     */
+    boolean sendTemplateMsg(String openId, String templateId, String miniprogramAppid, String miniprogramPage, Map<String, TemplateDataDTO> dataMap);
+
+}

+ 12 - 0
src/main/java/com/care/common/service/impl/CareMemberInfoServiceImpl.java

@@ -1,6 +1,7 @@
 package com.care.common.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.care.common.entity.CareMemberInfo;
 import com.care.common.mapper.CareMemberInfoMapper;
@@ -29,4 +30,15 @@ public class CareMemberInfoServiceImpl extends ServiceImpl<CareMemberInfoMapper,
         queryWrapper.lambda().eq(CareMemberInfo::getPhone,phone);
         return this.getOne(queryWrapper);
     }
+
+    @Override
+    public boolean modifyUnionId(Long id, String unionId) {
+        return update(new UpdateWrapper<CareMemberInfo>().lambda().eq(CareMemberInfo::getId, id).set(CareMemberInfo::getUnionId, unionId));
+    }
+
+    @Override
+    public boolean modifyUnionId(String openId, String unionId) {
+        return update(new UpdateWrapper<CareMemberInfo>().lambda().eq(CareMemberInfo::getOpenId, openId).set(CareMemberInfo::getUnionId, unionId));
+    }
+
 }

+ 50 - 0
src/main/java/com/care/common/service/impl/CareOfficialMemberInfoServiceImpl.java

@@ -0,0 +1,50 @@
+//package com.care.common.service.impl;
+//
+//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+//import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+//import com.care.common.entity.CareMemberInfo;
+//import com.care.common.entity.CareOfficialMemberInfo;
+//import com.care.common.mapper.CareMemberInfoMapper;
+//import com.care.common.mapper.CareOfficialMemberInfoMapper;
+//import com.care.common.service.CareMemberInfoService;
+//import com.care.common.service.CareOfficialMemberInfoService;
+//import org.springframework.stereotype.Service;
+//
+///**
+// * 微信公众号成员关联表(CareOfficialMemberInfo)表服务实现类
+// *
+// * @author makejava
+// * @since 2021-06-02 21:43:38
+// */
+//@Service
+//public class CareOfficialMemberInfoServiceImpl extends ServiceImpl<CareOfficialMemberInfoMapper, CareOfficialMemberInfo> implements CareOfficialMemberInfoService {
+//
+//    @Override
+//    public CareOfficialMemberInfo findByUnionId(String unionId) {
+//        return this.getOne(new QueryWrapper<CareOfficialMemberInfo>().lambda().eq(CareOfficialMemberInfo::getUnionId, unionId));
+//    }
+//
+//    @Override
+//    public boolean subscribe(CareOfficialMemberInfo careOfficialMemberInfo) {
+//        CareOfficialMemberInfo dbCareOfficialMemberInfo = this.getOne(new QueryWrapper<CareOfficialMemberInfo>().lambda().eq(CareOfficialMemberInfo::getUnionId, careOfficialMemberInfo.getUnionId()));
+//        if (dbCareOfficialMemberInfo == null) {
+//            return this.save(careOfficialMemberInfo);
+//        } else {
+//            if (dbCareOfficialMemberInfo.getSubscribeStatus() == null || dbCareOfficialMemberInfo.getSubscribeStatus() == 0) {
+//                dbCareOfficialMemberInfo.setSubscribeStatus(1);
+//            }
+//            return this.updateById(dbCareOfficialMemberInfo);
+//        }
+//    }
+//
+//    @Override
+//    public boolean cancelSubscribe(String unionId) {
+//        CareOfficialMemberInfo dbCareOfficialMemberInfo = this.getOne(new QueryWrapper<CareOfficialMemberInfo>().lambda().eq(CareOfficialMemberInfo::getUnionId, unionId));
+//        if (dbCareOfficialMemberInfo == null) {
+//            return Boolean.TRUE;
+//        } else {
+//            return this.removeById(dbCareOfficialMemberInfo.getId());
+//        }
+//    }
+//
+//}

+ 192 - 0
src/main/java/com/care/common/service/impl/WxTemplateServiceImpl.java

@@ -0,0 +1,192 @@
+package com.care.common.service.impl;
+
+import cn.hutool.json.JSONObject;
+import com.care.client.config.PlatformOfficialConfig;
+import com.care.client.config.PlatformPinanbaoConfig;
+import com.care.client.config.WxConfig;
+import com.care.client.dto.MpTemplateMsgDTO;
+import com.care.client.dto.TemplateDataDTO;
+import com.care.client.dto.WxUniformTemplateDTO;
+import com.care.client.vo.WxAccessTokenVO;
+import com.care.common.cache.RedisKeyConstant;
+import com.care.common.cache.RedisUtil;
+import com.care.common.service.WxTemplateService;
+import com.care.common.util.*;
+import com.google.common.collect.Maps;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+@Service
+@Slf4j
+public class WxTemplateServiceImpl implements WxTemplateService {
+
+    @Resource
+    private RedisUtil redisUtil;
+
+    @Resource
+    private PlatformPinanbaoConfig platformPinanbaoConfig;
+
+    @Resource
+    private PlatformOfficialConfig platformOfficialConfig;
+
+//    @Resource
+//    private CareOfficialMemberInfoService careOfficialMemberInfoService;
+
+    private Lock lock = new ReentrantLock();
+
+    @Override
+    public WxAccessTokenVO processAccessToken() {
+        WxAccessTokenVO wxAccessTokenVO = new WxAccessTokenVO();
+        WxConfig wxConfig = platformPinanbaoConfig.wxConfig();
+        if (StringUtils.isBlank(wxConfig.getAppId()) || StringUtils.isBlank(wxConfig.getSecret())) {
+            log.error("缺少必要参数");
+            return null;
+        }
+        try {
+            //得到对象锁
+            lock.lock();
+            if (redisUtil.hasKey(RedisKeyConstant.YUANSERVICE_ACCESSTOKEN + "text")) {
+                wxAccessTokenVO.setAccessToken(ObjectUtils.toString(redisUtil.get(RedisKeyConstant.YUANSERVICE_ACCESSTOKEN + "text")));
+            } else {
+                wxAccessTokenVO = WxTemplateUtil.getAccessToken(wxConfig.getAppId(), wxConfig.getSecret());
+                if (wxAccessTokenVO == null || StringUtils.isBlank(wxAccessTokenVO.getAccessToken())) {
+                    log.error("未获取到AccessToekn");
+                    return null;
+                }
+                redisUtil.set(RedisKeyConstant.YUANSERVICE_ACCESSTOKEN + "text", wxAccessTokenVO.getAccessToken(),60 * 100);
+            }
+        } catch (Exception e) {
+            log.error("获取AccessToken出现错误", e);
+        } finally {
+            //释放锁
+            lock.unlock();
+        }
+        return wxAccessTokenVO;
+    }
+
+    @Override
+    public boolean sendTemplateMsg(String openId, String templateId, Map<String, TemplateDataDTO> dataMap) {
+        if (StringUtils.isBlank(openId)) {
+            throw new IllegalArgumentException("参数 openId 为空");
+        }
+        if (StringUtils.isBlank(templateId)) {
+            throw new IllegalArgumentException("参数 templateId 为空");
+        }
+        if (dataMap == null) {
+            dataMap = Maps.newHashMap();
+        }
+        WxAccessTokenVO wxAccessTokenVO = processAccessToken();
+        if (wxAccessTokenVO == null) {
+            throw new RuntimeException("获取AccessToken出错");
+        }
+//        CareOfficialMemberInfo byUnionId = careOfficialMemberInfoService.findByUnionId(unionId);
+//        if (byUnionId == null) {
+//            throw new RuntimeException("用户 unionId: " + unionId + " 未找到相应公众号关注信息");
+//        }
+        WxUniformTemplateDTO wxUniformTemplateDTO = new WxUniformTemplateDTO();
+        wxUniformTemplateDTO.setTouser(openId);
+
+        WxConfig wxConfig = platformOfficialConfig.officialConfig();
+
+        MpTemplateMsgDTO mpTemplateMsgDTO = new MpTemplateMsgDTO();
+        mpTemplateMsgDTO.setAppid(wxConfig.getAppId());
+        mpTemplateMsgDTO.setTemplate_id(templateId);
+        mpTemplateMsgDTO.setData(dataMap);
+        wxUniformTemplateDTO.setMp_template_msg(mpTemplateMsgDTO);
+
+        // 发送消息模板
+        JSONObject jsonObject = WxTemplateUtil.sendTemplateMsg(wxUniformTemplateDTO, wxAccessTokenVO.getAccessToken());
+        if (jsonObject != null && "0".equals(jsonObject.getStr("errcode"))) {
+            return Boolean.TRUE;
+        }
+        return Boolean.FALSE;
+    }
+
+    @Override
+    public boolean sendTemplateMsg(String openId, String templateId, String miniprogramAppid, String miniprogramPage, Map<String, TemplateDataDTO> dataMap) {
+        if (StringUtils.isBlank(openId)) {
+            throw new IllegalArgumentException("参数 openId 为空");
+        }
+        if (StringUtils.isBlank(templateId)) {
+            throw new IllegalArgumentException("参数 templateId 为空");
+        }
+        if (StringUtils.isBlank(miniprogramAppid)) {
+            throw new IllegalArgumentException("参数 miniprogramAppid 为空");
+        }
+        if (StringUtils.isBlank(miniprogramPage)) {
+            throw new IllegalArgumentException("参数 miniprogramPage 为空");
+        }
+        if (dataMap == null) {
+            dataMap = Maps.newHashMap();
+        }
+        WxAccessTokenVO wxAccessTokenVO = processAccessToken();
+        if (wxAccessTokenVO == null) {
+            throw new RuntimeException("获取AccessToken出错");
+        }
+//        CareOfficialMemberInfo byUnionId = careOfficialMemberInfoService.findByUnionId(unionId);
+//        if (byUnionId == null) {
+//            throw new RuntimeException("用户 unionId: " + unionId + " 未找到相应公众号关注信息");
+//        }
+        WxUniformTemplateDTO wxUniformTemplateDTO = new WxUniformTemplateDTO();
+        wxUniformTemplateDTO.setTouser(openId);
+
+        WxConfig wxConfig = platformOfficialConfig.officialConfig();
+        MpTemplateMsgDTO mpTemplateMsgDTO = new MpTemplateMsgDTO();
+        mpTemplateMsgDTO.setAppid(wxConfig.getAppId());
+        mpTemplateMsgDTO.setTemplate_id(templateId);
+        mpTemplateMsgDTO.setData(dataMap);
+
+        Map<String, String> miniprogramMap = Maps.newHashMap();
+        miniprogramMap.put("appid", miniprogramAppid);
+        miniprogramMap.put("page", miniprogramPage);
+        mpTemplateMsgDTO.setMiniprogram(miniprogramMap);
+
+        wxUniformTemplateDTO.setMp_template_msg(mpTemplateMsgDTO);
+
+        // 发送消息模板
+        JSONObject jsonObject = WxTemplateUtil.sendTemplateMsg(wxUniformTemplateDTO, wxAccessTokenVO.getAccessToken());
+        if (jsonObject != null && "0".equals(jsonObject.getStr("errcode"))) {
+            return Boolean.TRUE;
+        }
+        return Boolean.FALSE;
+    }
+
+//    @Override
+//    public boolean sendTemplateMsg(String unionId, String templateId, Map<String, TemplateDataDTO> dataMap) {
+//        if (StringUtils.isBlank(unionId)) {
+//            throw new IllegalArgumentException("参数 unionId 为空");
+//        }
+//        if (StringUtils.isBlank(templateId)) {
+//            throw new IllegalArgumentException("参数 templateId 为空");
+//        }
+//        if (dataMap == null) {
+//            dataMap = Maps.newHashMap();
+//        }
+//        WxAccessTokenVO wxAccessTokenVO = processAccessToken();
+//        if (wxAccessTokenVO == null) {
+//            throw new RuntimeException("获取AccessToken出错");
+//        }
+//        CareOfficialMemberInfo byUnionId = careOfficialMemberInfoService.findByUnionId(unionId);
+//        if (byUnionId == null) {
+//            throw new RuntimeException("用户 unionId: " + unionId + " 未找到相应公众号关注信息");
+//        }
+//        WxTemplateDTO wxTemplateDTO = new WxTemplateDTO();
+//        wxTemplateDTO.setTouser(byUnionId.getOpenId());
+//        wxTemplateDTO.setTemplate_id(templateId);
+//        wxTemplateDTO.setData(dataMap);
+//        // 发送消息模板
+//        JSONObject jsonObject = WxTemplateUtil.sendTemplateMsg(wxTemplateDTO, wxAccessTokenVO.getAccessToken());
+//        if (jsonObject != null && "0".equals(jsonObject.getStr("errcode"))) {
+//            return Boolean.TRUE;
+//        }
+//        return Boolean.FALSE;
+//    }
+
+}

+ 53 - 0
src/main/java/com/care/common/util/CheckoutUtil.java

@@ -0,0 +1,53 @@
+//package com.care.common.util;
+//
+//import java.security.MessageDigest;
+//import java.security.NoSuchAlgorithmException;
+//import java.util.Arrays;
+//import java.util.Formatter;
+//
+//public class CheckoutUtil {
+//
+//    // 与测试账号接口配置信息中的Token要一致
+//    private static String token = "yuanbaotoken";
+//
+//    /**
+//     * 验证签名
+//     * @param signature
+//     * @param timestamp
+//     * @param nonce
+//     * @return
+//     */
+//    public static boolean checkSignature(String signature, String timestamp, String nonce) {
+//        String[] arr = new String[] { token, timestamp, nonce };
+//        Arrays.sort(arr);// 将token、timestamp、nonce三个参数进行字典序排序
+//        StringBuilder content = new StringBuilder();
+//        for (int i = 0; i < arr.length; i++) {
+//            content.append(arr[i]);
+//        }
+//        MessageDigest md = null;
+//        String tmpStr = null;
+//
+//        try {
+//            md = MessageDigest.getInstance("SHA-1");
+//            // 将三个参数字符串拼接成一个字符串进行sha1加密
+//            byte[] digest = md.digest(content.toString().getBytes());
+//            tmpStr = byteToHex(digest );
+//        } catch (NoSuchAlgorithmException e) {
+//            e.printStackTrace();
+//        }
+//        // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
+//        return tmpStr != null ? tmpStr.equals(signature) : false;
+//    }
+//
+//    //十六进制字节数组转为字符串
+//    private static String byteToHex(final byte[] hash) {
+//        Formatter formatter = new Formatter();
+//        for (byte b : hash) {
+//            formatter.format("%02x", b);
+//        }
+//        String result = formatter.toString();
+//        formatter.close();
+//        return result;
+//    }
+//
+//}

+ 11 - 0
src/main/java/com/care/common/util/MessageUtil.java

@@ -0,0 +1,11 @@
+//package com.care.common.util;
+//
+//public interface MessageUtil {
+//
+//    String MSGTYPE_EVENT = "event";
+//
+//    String SUBSCIBE_EVENT = "subscribe";
+//
+//    String UNSUBSCIBE_EVENT = "unsubscribe";
+//
+//}

+ 26 - 0
src/main/java/com/care/common/util/MyX509TrustManager.java

@@ -0,0 +1,26 @@
+package com.care.common.util;
+
+import javax.net.ssl.X509TrustManager;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+/**
+ * 证书验证
+ */
+public class MyX509TrustManager implements X509TrustManager {
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+
+    }
+
+    @Override
+    public X509Certificate[] getAcceptedIssuers() {
+        return new X509Certificate[0];
+    }
+}

+ 193 - 0
src/main/java/com/care/common/util/WxTemplateUtil.java

@@ -0,0 +1,193 @@
+package com.care.common.util;
+
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.care.client.dto.WxTemplateDTO;
+import com.care.client.dto.WxUniformTemplateDTO;
+import com.care.client.vo.WxAccessTokenVO;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.ConnectException;
+import java.net.URL;
+import java.security.SecureRandom;
+
+/**
+ * 微信接口访问工具封装
+ */
+public class WxTemplateUtil {
+
+    /**
+     * 获取access_token的接口地址(GET) 限200(次/天)
+     */
+    public final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
+
+    /**
+     * 发送模板消息(POST)
+     */
+//    public final static String SEND_TEMPLATE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
+
+    /**
+     * 发送模板消息(POST)
+     */
+    public final static String SEND_TEMPLATE_URL = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN";
+
+    /**
+     * 获取微信用户数据
+     */
+    private final static String SEND_USER_OPENID_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
+
+    /**
+     * 接口描述:请求工具
+     * @params [requestUrl, requestMethod, outputStr]
+     * @return net.sf.json.JSONObject
+     */
+    public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
+        JSONObject jsonObject = null;
+        StringBuffer buffer = new StringBuffer();
+        try {
+            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
+            TrustManager[] tm = {new MyX509TrustManager()};
+            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
+            sslContext.init(null, tm, new SecureRandom());
+            // 从上述SSLContext对象中得到SSLSocketFactory对象
+            SSLSocketFactory ssf = sslContext.getSocketFactory();
+
+            URL url = new URL(requestUrl);
+            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
+            httpUrlConn.setSSLSocketFactory(ssf);
+
+            httpUrlConn.setDoOutput(true);
+            httpUrlConn.setDoInput(true);
+            httpUrlConn.setUseCaches(false);
+            // 设置请求方式(GET/POST)
+            httpUrlConn.setRequestMethod(requestMethod);
+
+            if(RequestMethod.GET.equals(requestMethod)){
+                httpUrlConn.connect();
+            }
+
+            // 当有数据需要提交时
+            if(null != outputStr) {
+                OutputStream outputStream = httpUrlConn.getOutputStream();
+                // 注意编码格式,防止中文乱码
+                outputStream.write(outputStr.getBytes("UTF-8"));
+                outputStream.close();
+            }
+
+            // 将返回的输入流转换成字符串
+            InputStream inputStream = httpUrlConn.getInputStream();
+            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
+            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
+
+            String str = null;
+            while ((str = bufferedReader.readLine()) != null) {
+                buffer.append(str);
+            }
+            bufferedReader.close();
+            inputStreamReader.close();
+            // 释放资源
+            inputStream.close();
+            inputStream = null;
+            httpUrlConn.disconnect();
+            jsonObject = JSONUtil.parseObj(buffer.toString());
+        } catch (ConnectException ce) {
+            System.out.println("Weixin server connection timed out.");
+        } catch (Exception e) {
+            System.out.println("https request error:{}" + e);
+        }
+        return jsonObject;
+    }
+
+    /**
+     * 接口描述:获取access_token
+     * @params [appId, appSecret]
+     * @return com.gzschool.prismtestcms.model.vo.WxAccessTokenVO
+     */
+    public static WxAccessTokenVO getAccessToken(String appId, String appSecret) {
+
+        WxAccessTokenVO wxAccessTokenVO = null;
+
+        String requestUrl = ACCESS_TOKEN_URL.replace("APPID", appId).replace("APPSECRET", appSecret);
+        JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
+        // 如果请求成功
+        if (null != jsonObject) {
+            try {
+                wxAccessTokenVO = new WxAccessTokenVO();
+                wxAccessTokenVO.setAccessToken(jsonObject.getStr("access_token"));
+                wxAccessTokenVO.setExpiresIn(jsonObject.getInt("expires_in"));
+                if (StringUtils.isBlank(wxAccessTokenVO.getAccessToken())) {
+                    return null;
+                }
+            } catch (Exception e) {
+                wxAccessTokenVO = null;
+                // 获取token失败
+                System.out.println("获取token失败");
+            }
+        }
+        return wxAccessTokenVO;
+    }
+
+    /**
+     * 解析公众号订阅/取消时用户信息
+     * @param accessToken
+     * @param openId
+     * @return
+     */
+    public static JSONObject parseWxOpenIdBySubscribe(String accessToken, String openId) {
+        if (StringUtils.isBlank(accessToken) || StringUtils.isBlank(openId)) {
+            return null;
+        }
+        String requestUrl = SEND_USER_OPENID_URL.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
+        return httpRequest(requestUrl, "GET", null);
+    }
+
+    /**
+     * 接口描述:消息模板发送
+     * @params [wxTemplateDTO, accessToken]
+     * @return net.sf.json.JSONObject
+     */
+    public static JSONObject sendTemplateMsg(WxTemplateDTO wxTemplateDTO, String accessToken) {
+
+        String url = SEND_TEMPLATE_URL.replace("ACCESS_TOKEN", accessToken);
+        // 将模板数据对象转换成json字符串
+        String wxTemplate = JSONUtil.toJsonStr(wxTemplateDTO);
+        //发送请求
+        JSONObject result = httpRequest(url, "POST", wxTemplate);
+
+        if (result != null) {
+            return result;
+        } else{
+            return null;
+        }
+    }
+
+    /**
+     * 接口描述:消息模板发送
+     * @params [wxTemplateDTO, accessToken]
+     * @return net.sf.json.JSONObject
+     */
+    public static JSONObject sendTemplateMsg(WxUniformTemplateDTO wxUniformTemplateDTO, String accessToken) {
+        String url = SEND_TEMPLATE_URL.replace("ACCESS_TOKEN", accessToken);
+        // 将模板数据对象转换成json字符串
+        String wxTemplate = JSONUtil.toJsonStr(wxUniformTemplateDTO);
+        //发送请求
+        JSONObject result = httpRequest(url, "POST", wxTemplate);
+        if (result != null) {
+            return result;
+        } else{
+            return null;
+        }
+    }
+
+
+
+}

+ 4 - 0
src/main/resources/application.properties

@@ -59,6 +59,10 @@ wx.pinanbao.infoUrl=https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}
 wx.pinanbao.appid=wxda02870032b8f928
 wx.pinanbao.secret=5984b6cf5dad4693eb60cbc494d9f385
 
+# 微信公众号配置
+wx.official.appid=wxf393853ab94c853f
+wx.official.secret=f3fc21fee8de01d79ded7f799a4d2d4d
+
 #频安守护 小程序
 wx.pinanshouhu.codeUrl=https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code
 wx.pinanshouhu.tokenUrl=https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}