天天看點

微信公衆号 擷取 token、使用者資訊、xml map轉換、伺服器回調簽名校驗、自定義消息回複、模闆消息微信公衆号工具類

微信公衆号工具類

package com.xxx.service.attendance.provider.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xxx.service.attendance.provider.persistence.entity.CheckLog;
import com.xxxx.standard.service.spring.redis.tool.RedisUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.annotation.PostConstruct;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Component
public class WxUtils {
    private static Logger logger = LoggerFactory.getLogger(WxUtils.class);


    public static final String WX_TOKEN_KEY = "WX_TOKEN_KEY";

    public static final String WX_MESSAGE_PREFIX = "WX_MESSAGE_PREFIX:%s";

    @Value("${wx.miniprogram.appId}")
    private String miniProgramAppId;
    @Value("${wx.miniprogram.path}")
    private String miniProgramPath;

    @Value("${wx.official.account.template}")
    private String officialAccountTemplateId;


    public static String WX_CHECK_NOTIC_TEMPLATEID = null;
    public static String WX_CHECK_NOTIC_MINIPROGRAM_APP_ID = null;
    public static String WX_CHECK_NOTIC_MINIPROGRAM_PATH = null;


    public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    public static final SimpleDateFormat sdf1 = new SimpleDateFormat("HH:mm:ss");

    @PostConstruct
    public void init(){
        WX_CHECK_NOTIC_TEMPLATEID = this.officialAccountTemplateId;
        WX_CHECK_NOTIC_MINIPROGRAM_APP_ID = this.miniProgramAppId;
        WX_CHECK_NOTIC_MINIPROGRAM_PATH = this.miniProgramPath;
    }


    /**
     * 擷取token
     * @param appId
     * @param secret
     * @return
     */
    public static String getToken(String appId,String secret){
        String token = RedisUtils.get(WX_TOKEN_KEY);
        if(token == null){
            String str = HttpUtils.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret="+secret);
            JSONObject jsonObject = JSON.parseObject(str);
            token = jsonObject.get("access_token") == null?null:(String)jsonObject.get("access_token");
            Integer expiresIn = jsonObject.get("expires_in") == null?null:(Integer)jsonObject.get("expires_in");
            if(token != null){
                RedisUtils.set(WX_TOKEN_KEY,token,(expiresIn-100)*1000);
            }
        }
        return token;
    }

    /**
     * 擷取使用者資訊
     * @param accessToken
     * @param openId
     * @return
     */
    public static JSONObject getUserInfo(String accessToken,String openId){
        String str = HttpUtils.get("https://api.weixin.qq.com/cgi-bin/user/info?access_token="+accessToken+"&openid="+openId+"&);
        return JSON.parseObject(str);
    }


    /**
     * xml轉map
     * @param strXml
     * @return
     * @throws Exception
     */
    public static Map<String, String> xmlToMap(String strXml) throws Exception {
        Map<String, String> data = new HashMap<String, String>();
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
        InputStream stream = new ByteArrayInputStream(strXml.getBytes("UTF-8"));
        org.w3c.dom.Document doc = documentBuilder.parse(stream);
        doc.getDocumentElement().normalize();
        NodeList nodeList = doc.getDocumentElement().getChildNodes();
        for (int idx=0; idx<nodeList.getLength(); ++idx) {
            Node node = nodeList.item(idx);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                data.put(element.getNodeName(), element.getTextContent());
            }
        }
        try {
            stream.close();
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
        return data;
    }


    /**
     * map轉xml
     * @param data
     * @return
     * @throws Exception
     */
    public static String mapToXml(Map<String, String> data) throws Exception {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
        org.w3c.dom.Document document = documentBuilder.newDocument();
        org.w3c.dom.Element root = document.createElement("xml");
        document.appendChild(root);
        for (String key: data.keySet()) {
            String value = data.get(key);
            if (value == null) {
                value = "";
            }
            value = value.trim();
            org.w3c.dom.Element filed = document.createElement(key);
            filed.appendChild(document.createTextNode(value));
            root.appendChild(filed);
        }
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        DOMSource source = new DOMSource(document);
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        StringWriter writer = new StringWriter();
        StreamResult result = new StreamResult(writer);
        transformer.transform(source, result);
        String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
        try {
            writer.close();
        }

        catch (Exception ex) {

            ex.printStackTrace();

        }
        return output;
    }


    /**
     * 微信伺服器回調  驗證簽名
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce,String token) {
        String[] arr = new String[] { token, timestamp, nonce };
        Arrays.sort(arr);
        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 = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        content = null;
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }
    /**
     * 将位元組數組轉換為十六進制字元串
     *
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }
    /**
     * 将位元組轉換為十六進制字元串
     *
     * @param mByte
     * @return
     */
    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];
        String s = new String(tempArr);
        return s;
    }

    /**
     * 客戶賬号回複消息
     * @param token
     * @param map
     * @return
     */
    public static boolean customSend(String token,Map map){
        String url  = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="+token;
        String param = JSON.toJSONString(map);
        String str = HttpUtils.postJson(url,param);
        JSONObject jsonObject = JSON.parseObject(str);
        int errcode = jsonObject.get("errcode") == null?-1:(int)jsonObject.get("errcode");
        if(errcode != 0){
            System.err.println("param:"+param+"  \nresult:"+str);
        }
        return errcode == 0;
    }


    /**
     * 發送模闆消息
     * @param accessToken
     * @param openId
     * @param checkLog
     * @return
     */
    public static boolean sendLogNotic(String accessToken, String openId, CheckLog checkLog){
        Map map = new HashMap<>();
        map.put("touser",openId);
        map.put("template_id",WX_CHECK_NOTIC_TEMPLATEID);
        //map.put("url","http://www.baidu.com");
        map.put("topcolor","#FF0000");


        Map miniprogram = new HashMap<>();
        miniprogram.put("appid",WX_CHECK_NOTIC_MINIPROGRAM_APP_ID);
        miniprogram.put("pagepath",WX_CHECK_NOTIC_MINIPROGRAM_PATH);
        map.put("miniprogram",miniprogram);

        Map data = new HashMap<>();

        Map first = new HashMap<>();
        first.put("value","您好,"+checkLog.getStudentName()+"在學校考勤了");
        first.put("color","#173177");
        data.put("first",first);

        Map keyword1 = new HashMap<>();
        keyword1.put("value",checkLog.getStudentName());
        keyword1.put("color","#173177");
        data.put("keyword1",keyword1);

        Map keyword2 = new HashMap<>();
        keyword2.put("value",sdf.format(checkLog.getDayTime())+" "+sdf1.format(checkLog.getHourTime()));
        keyword2.put("color","#173177");
        data.put("keyword2",keyword2);

        Map remark = new HashMap<>();
        remark.put("value","點選檢視詳情");
        remark.put("color","#173177");
        data.put("remark",remark);

        map.put("data",data);
        String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+accessToken;
        String paramStr = JSON.toJSONString(map);
        String str = HttpUtils.postJson(url,paramStr);
        JSONObject result = JSON.parseObject(str);
        if(result.get("errcode") != null && (Integer)result.get("errcode")  == 0){
            return true;
        }
        logger.error("sendLogNotic-url:{}",url);
        logger.error("sendLogNotic-paramStr:{}",paramStr);
        logger.error("sendLogNotic-str:{}",str);
        return false;
    }
}