Java微信公众号开发之接入与消息回复

访问令牌实体类

package com.tdzh.weixin.Entity;

/**
 * className:AccessToken
 * Package:com.tdzh.util
 * Description:访问令牌实体类
 *
 * @date:2019/7/22 17:30
 * @author:malin
 */
public class AccessToken {

    //令牌字符串
    private String accessToken;
	
	//过期时间
    private Long expiresIn;

    private AccessToken() {
    }

    public AccessToken(String accessToken, String expiresIn) {
        this.accessToken = accessToken;
        //设置过期时间,创建后的一个小时59分钟内,防止在必要时刻,调用接口失败
        this.expiresIn = System.currentTimeMillis() + Integer.parseInt(expiresIn) - 60;
    }

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public long getExpiresIn() {
        return expiresIn;
    }

    public void setExpiresIn(long expiresIn) {
        this.expiresIn = expiresIn;
    }

    //判断当前访问令牌是否过期
    public boolean isExpired(){
        return System.currentTimeMillis() > expiresIn;
    }
}


开发所需工具类


package com.tdzh.weixin.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tdzh.weixin.Entity.AccessToken;
import com.tdzh.weixin.Entity.resp.*;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * className:WxUtil
 * Package:com.tdzh.util
 * Description:微信工具类,主要用来获取访问令牌,对实体类进行XMl转换
 *
 * @date:2019/7/22 15:23
 * @author:malin
 */
@Component
public class WxUtil {

    //token,用作生成签名,须于微信公众号端一致
    @Value("${WeChat.token}")
    private String token;

    //第三方用户唯一凭证
    @Value("${WeChat.appID}")
    private String appID;

    //第三方用户唯一凭证密钥,即appsecret
    @Value("${WeChat.appsecret}")
    private String appsecret;

    //访问令牌实体
    private AccessToken accessToken;

    //对所有xml节点的转换都增加CDATA标记
    private static XStream xstream = new XStream(new XppDriver() {
        public HierarchicalStreamWriter createWriter(Writer out) {
            return new PrettyPrintWriter(out) {
                // 对所有xml节点的转换都增加CDATA标记
                boolean cdata = true;

                @SuppressWarnings("unchecked")
                public void startNode(String name, Class clazz) {
                    super.startNode(name, clazz);
                }
                protected void writeText(QuickWriter writer, String text) {
                    if (cdata) {
                        writer.write("<![CDATA[");
                        writer.write(text);
                        writer.write("]]>");
                    } else {
                        writer.write(text);
                    }
                }
            };
        }
    });

    /**
     * 微信接入校验,仅接入时使用
     * @param signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
     * @param timestamp 时间戳
     * @param nonce 随机数
     * @return
     */
    public boolean WxAccess(String signature,String timestamp,String nonce){

        //1)将token、timestamp、nonce三个参数进行字典序排序
        String[] args = {token,timestamp,nonce};

        Arrays.sort(args);

        //2)将三个参数字符串拼接成一个字符串进行sha1加密
        String str = args[0] + args[1] + args[2];

        //加密字符串
        String sha1 = getSha1(str);

        //3)开发者获得加密后的字符串可与signature对比,true则标识该请求来源于微信
        return sha1.equals(signature);
    }

    /**
     * sha1 加密
     * @param str 被加密字符串
     * @return  加密字符串
     */
    public String getSha1(String str){

        try {
            // 获取一个加密对象
            MessageDigest md = MessageDigest.getInstance("sha1");

            // 数据加密
            byte[] digest = md.digest(str.getBytes());
            char[] chars = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};

            //对字符串进行加密处理
            StringBuffer sb = new StringBuffer();
            for(byte b : digest){
                sb.append(chars[b>>4 & 15]);
                sb.append(chars[b & 15]);
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;

    }

    /**
     * 创建访问令牌,令牌过期时间为创建后的2小时
     */
    public void createAccessToken(){
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET".replace("APPID",appID).replace("APPSECRET",appsecret);
        //本人编写参考HttpClient工具类
        Map<String, Object> stringObjectMap = HttpClientUtil.doGet(url);
        //System.out.println(stringObjectMap.toString());
        String content = (String) stringObjectMap.get("content");
        JSONObject jsonObject = JSON.parseObject(content);
        String access_token = (String) jsonObject.get("access_token");
        String expires_in = jsonObject.get("expires_in").toString();
        accessToken = new AccessToken(access_token,expires_in);
    }

    /**
     * 获取访问令牌
     * @return accessToken 访问令牌
     */
    public String getAccessToken(){
    	//判断访问令牌是否存在或者过期,如若不存在或已过期,重新生成访问令牌
        if (null == accessToken || accessToken.isExpired()) {
            createAccessToken();
        }
        return accessToken.getAccessToken();
    }

    /**
     * 解析微信发来的request请求
     * @param request
     * @return
     */
    public Map<String,Object> parseXml(HttpServletRequest request){
        Map<String,Object> resultMap = new HashMap<String,Object>();

        // 从request中取得输入流
        InputStream inputStream = null;
        try {
            inputStream = request.getInputStream();
            // 读取输入流
            SAXReader reader = new SAXReader();
            Document document = reader.read(inputStream);
            // 得到xml根元素
            Element root = document.getRootElement();
            // 得到根元素的所有子节点
            List<Element> elementList = root.elements();
            // 遍历所有子节点
            for (Element e : elementList){
                resultMap.put(e.getName(), e.getText());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            try {
                if(null != inputStream){
                    inputStream.close();
                    inputStream = null;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultMap;
    }

    /**
     * 响应文本消息对象转换成xml
     * @param textMessageResp 文本消息对象
     * @return
     */
    public String textMessageToXml(TextMessageResp textMessageResp){
        xstream.alias("xml",textMessageResp.getClass());
        return xstream.toXML(textMessageResp);
    }

    /**
     * 响应图片消息对象转换成xml
     * @param imageMessageResp
     * @return
     */
    public String imageMessageToXml(ImageMessageResp imageMessageResp) {
        xstream.alias("xml",imageMessageResp.getClass());
        return xstream.toXML(imageMessageResp);
    }

    /**
     * 响应语音消息对象转换成xml
     * @param voiceMessageResp
     * @return
     */
    public String voiceMessageToXml(VoiceMessageResp voiceMessageResp) {
        xstream.alias("xml",voiceMessageResp.getClass());
        return xstream.toXML(voiceMessageResp);
    }

    /**
     * 响应语音消息对象转换成xml
     * @param videoMessageResp
     * @return
     */
    public String videoMessageToXml(VideoMessageResp videoMessageResp) {
        xstream.alias("xml",videoMessageResp.getClass());
        return xstream.toXML(videoMessageResp);
    }

    /**
     * 响应音乐消息对象转换成xml
     * @param musicMessageResp
     * @return
     */
    public String musicMessageToXml(MusicMessageResp musicMessageResp) {
        xstream.alias("xml",musicMessageResp.getClass());
        return xstream.toXML(musicMessageResp);
    }

    /**
     * 响应图文消息对象转换成xml
     * @param articleMessageResp
     * @return
     */
    public String articleMessageToXml(ArticleMessageResp articleMessageResp) {
        xstream.alias("xml",articleMessageResp.getClass());
        return xstream.toXML(articleMessageResp);
    }

}

微信公众号接入及被动回复图文消息(controller)

package com.tdzh.weixin.controller;

import com.tdzh.weixin.Entity.*;
import com.tdzh.weixin.Entity.resp.*;
import com.tdzh.weixin.util.WxUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * className:CheckController
 * Package:com.tdzh.weixin.controller
 * Description:1、微信接入校验 2、微信相关信息被动回复
 *
 * @date:2019/7/26 17:03
 * @author:malin
 */
@RestController
@RequestMapping("/check")
public class CheckController {

    @Autowired
    private WxUtil wxUtil;

	/**
     * 微信接入校验
     * @param request
     */
    @GetMapping("/weChat"public String checkGetRequestFromWeChat(HttpServletRequest request){
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        System.out.println("校验中...");
        boolean flag = wxUtil.WxAccess(signature, timestamp, nonce);
        if(flag){
            System.out.println("校验成功...");
            return echostr;
        }else{
        	System.out.println("校验失败...");
            return null;
        }
    }

    /**
     * 被动回复消息事件处理
     * @param request
     */
    @PostMapping("/weChat")
    public String weChatMessageReceive(HttpServletRequest request){
        //解析微信端发送来的xml包,并获得相应的map
        Map<String, Object> stringObjectMap = wxUtil.parseXml(request);
        //输出,后期删除
        //System.out.println(stringObjectMap);
        //返回xml数据包
        String returnMessage = null;
        //基础数据准备
        String msgType = (String) stringObjectMap.get("MsgType");
        switch (msgType){
            case "text" :
                TextMessageResp textMessageResp = new TextMessageResp(stringObjectMap,"hello ,boy");
                returnMessage = wxUtil.textMessageToXml(textMessageResp);
                break;
            case "image" :
                //此处的mediaId为通过素材管理中的接口上传多媒体文件,得到的id。
                Image image = new Image(mediaId);
                ImageMessageResp imageMessageResp = new ImageMessageResp(stringObjectMap,image);
                returnMessage = wxUtil.imageMessageToXml(imageMessageResp);
                break;
            case "voice" :
                //此处的mediaId为通过素材管理中的接口上传多媒体文件,得到的id。
                Voice voice = new Voice(mediaId);
                VoiceMessageResp voiceMessageResp = new VoiceMessageResp(stringObjectMap, voice);
                returnMessage = wxUtil.voiceMessageToXml(voiceMessageResp);
                break;
            case "video" :
                //此处的mediaId为通过素材管理中的接口上传多媒体文件,得到的id。
                Video video = new Video(mediaId,"下雨了","雨下的很大");
                VideoMessageResp videoMessageResp = new VideoMessageResp(stringObjectMap, video);
                returnMessage = wxUtil.videoMessageToXml(videoMessageResp);
                break;
            case "music" :
            	//此处本人未测试成功,但返回格式正确
                Music music = new Music("安河桥","这是一首很棒的民谣","https://music.163.com/outchain/player?type=2&id=566521546&auto=1&height=66","https://music.163.com/outchain/player?type=2&id=566521546&auto=1&height=66","hkbuYI2WOLNLBCwtsOO3KlP6Vaxcc8OMQ1H4pfPzsIk11SgL5wozM72kfkCLFMlw");
                MusicMessageResp musicMessageResp = new MusicMessageResp(stringObjectMap,music);
                returnMessage = wxUtil.musicMessageToXml(musicMessageResp);
                break;
            case "news":
                Item item = new Item("文章1","这是一篇测试文章","http://pic25.nipic.com/20121112/9252150_150552938000_2.jpg","https://www.baidu.com/");
                Articles articles = new Articles(item);
                ArticleMessageResp articleMessageResp = new ArticleMessageResp(stringObjectMap,1,articles);
                returnMessage = wxUtil.articleMessageToXml(articleMessageResp);
                break;
        }
        //System.out.println(returnMessage);
        return returnMessage;
    }

}

controller中使用到的实体类

BaseMessageResp 基础信息响应对象

package com.tdzh.weixin.Entity.resp;

import java.util.Date;
import java.util.Map;

/**
 * className:BaseMessageResp
 * Package:com.tdzh.weixin.Entity.resp
 * Description:基础信息返回对象
 *
 * @date:2019/7/29 8:26
 * @author:malin
 */
public class BaseMessageResp {

    //接收方帐号(收到的OpenID)
    private String ToUserName;

    //开发者微信号
    private String FromUserName;

    //消息创建时间 (整型)
    private Long CreateTime;

    //消息类型,文本为text,图片为img,语音为voice,视频为video,小视频为shortvideo,地理位置为location,链接为link
    private String MsgType;

    public String getToUserName() {
        return ToUserName;
    }

    public void setToUserName(String toUserName) {
        ToUserName = toUserName;
    }

    public String getFromUserName() {
        return FromUserName;
    }

    public void setFromUserName(String fromUserName) {
        FromUserName = fromUserName;
    }

    public Long getCreateTime() {
        return CreateTime;
    }

    public void setCreateTime(Long createTime) {
        CreateTime = createTime;
    }

    public String getMsgType() {
        return MsgType;
    }

    public void setMsgType(String msgType) {
        MsgType = msgType;
    }

    public BaseMessageResp(Map<String,Object> requestMap){
        this.MsgType = (String) requestMap.get("MsgType");
        this.FromUserName = (String) requestMap.get("ToUserName");
        this.ToUserName = (String) requestMap.get("FromUserName");
        this.CreateTime = new Date().getTime();
    }
}

TextMessageResp 文本消息响应

package com.tdzh.weixin.Entity.resp;

import java.util.Map;

/**
 * className:TextMessageResp
 * Package:com.tdzh.weixin.Entity.resp
 * Description:文字信息返回对象
 *
 * @date:2019/7/31 11:13
 * @author:malin
 */
public class TextMessageResp extends BaseMessageResp{

    //文本消息内容
    private String Content;

    public String getContent() {
        return Content;
    }

    public void setContent(String content) {
        Content = content;
    }

    public TextMessageResp(Map<String, Object> requestMap, String content) {
        super(requestMap);
        this.Content = content;
    }
}

ImageMessageResp 图片消息响应

package com.tdzh.weixin.Entity.resp;

import com.tdzh.weixin.Entity.Image;

import java.util.Map;

/**
 * className:ImageMessageResp
 * Package:com.tdzh.weixin.Entity.resp
 * Description:图片信息返回对象
 *
 * @date:2019/7/29 8:28
 * @author:malin
 */

public class ImageMessageResp extends BaseMessageResp {

    private Image Image;

    public Image getImage() {
        return Image;
    }

    public void setImage(Image image) {
        this.Image = image;
    }

    public ImageMessageResp(Map<String, Object> requestMap, Image image) {
        super(requestMap);
        this.Image = image;
    }

}

Image 图片

package com.tdzh.weixin.Entity;

/**
 * className:Image
 * Package:com.tdzh.weixin.Entity
 * Description:图片实体类
 *
 * @date:2019/7/29 8:29
 * @author:malin
 */
public class Image {

    //通过素材管理中的接口上传多媒体文件,得到的id。
    private String MediaId;

    public String getMediaId() {
        return MediaId;
    }

    public void setMediaId(String mediaId) {
        MediaId = mediaId;
    }

    public Image(String mediaId) {
        MediaId = mediaId;
    }
}

VoiceMessageResp 语音消息响应

package com.tdzh.weixin.Entity.resp;


import com.tdzh.weixin.Entity.Voice;

import java.util.Map;

/**
 * className:VoiceMessageResp
 * Package:com.tdzh.weixin.Entity.resp
 * Description:语音信息返回对象
 *
 * @date:2019/7/29 10:11
 * @author:malin
 */
public class VoiceMessageResp extends BaseMessageResp{

    private Voice Voice;

    public VoiceMessageResp(Map<String, Object> requestMap, Voice voice) {
        super(requestMap);
        this.Voice = voice;
    }

    public com.tdzh.weixin.Entity.Voice getVoice() {
        return Voice;
    }

    public void setVoice(com.tdzh.weixin.Entity.Voice voice) {
        Voice = voice;
    }
}

Voice 语音

package com.tdzh.weixin.Entity;

/**
 * className:Voice
 * Package:com.tdzh.weixin.Entity
 * Description:语音实体类
 *
 * @date:2019/7/27 18:07
 * @author:malin
 */
public class Voice {

    //通过素材管理中的接口上传多媒体文件,得到的id
    private String MediaId;

    public String getMediaId() {
        return MediaId;
    }

    public void setMediaId(String mediaId) {
        MediaId = mediaId;
    }

    public Voice(String mediaId) {
        MediaId = mediaId;
    }
}

VideoMessageResp 视频消息响应

package com.tdzh.weixin.Entity.resp;

import com.tdzh.weixin.Entity.Video;

import java.util.Map;

/**
 * className:VideoMessageResp
 * Package:com.tdzh.weixin.Entity.resp
 * Description:视频信息返回对象
 *
 * @date:2019/7/29 10:48
 * @author:malin
 */
public class VideoMessageResp extends BaseMessageResp {

    private Video Video;

    public VideoMessageResp(Map<String, Object> requestMap, Video Video) {
        super(requestMap);
        this.Video = Video;
    }

    public Video getVideo() {
        return Video;
    }

    public void setVideo(Video Video) {
        this.Video = Video;
    }
}

Video 视频

package com.tdzh.weixin.Entity;

/**
 * className:Video
 * Package:com.tdzh.weixin.Entity
 * Description:视频实体类
 *
 * @date:2019/7/29 10:45
 * @author:malin
 */
public class Video {

    private String MediaId;

    private String Title;

    private String Description;

    public Video(){

    }

    public Video(String mediaId, String title, String description) {
        this.MediaId = mediaId;
        this.Title = title;
        this.Description = description;
    }

    public String getMediaId() {
        return MediaId;
    }

    public void setMediaId(String mediaId) {
        MediaId = mediaId;
    }

    public String getTitle() {
        return Title;
    }


    public void setTitle(String title) {
        Title = title;
    }

    public String getDescription() {
        return Description;
    }

    public void setDescription(String description) {
        Description = description;
    }
}

MusicMessageResp 音乐消息响应

package com.tdzh.weixin.Entity.resp;

import com.tdzh.weixin.Entity.Music;

import java.util.Map;

/**
 * className:MusicMessageResp
 * Package:com.tdzh.weixin.Entity.resp
 * Description:音乐信息返回对象
 *
 * @date:2019/7/29 11:13
 * @author:malin
 */
public class MusicMessageResp extends BaseMessageResp{

    private Music Music;

    public MusicMessageResp(Map<String, Object> requestMap,Music Music) {
        super(requestMap);
        this.Music = Music;
    }

    public Music getMusic() {
        return Music;
    }

    public void setMusic(Music music) {
        this.Music = music;
    }
}

Music 音乐

package com.tdzh.weixin.Entity;

/**
 * className:Music
 * Package:com.tdzh.weixin.Entity
 * Description:音乐实体类
 *
 * @date:2019/7/29 10:57
 * @author:malin
 */
public class Music {

    //音乐标题
    private String Title;

    //音乐描述
    private String Description;

    //音乐链接
    private String MusicURL;

    //高质量音乐链接,WIFI环境优先使用该链接播放音乐
    private String HQMusicUrl;

    //缩略图的媒体id,通过素材管理中的接口上传多媒体文件,得到的id
    private String ThumbMediaId;

    public Music(String title, String description, String musicURL, String HQMusicUrl, String thumbMediaId) {
        Title = title;
        Description = description;
        MusicURL = musicURL;
        this.HQMusicUrl = HQMusicUrl;
        ThumbMediaId = thumbMediaId;
    }

    public String getTitle() {
        return Title;
    }

    public void setTitle(String title) {
        this.Title = title;
    }

    public String getDescription() {
        return Description;
    }

    public void setDescription(String description) {
        this.Description = description;
    }

    public String getMusicURL() {
        return MusicURL;
    }

    public void setMusicURL(String musicURL) {
        this.MusicURL = musicURL;
    }

    public String getHQMusicUrl() {
        return HQMusicUrl;
    }

    public void setHQMusicUrl(String HQMusicUrl) {
        this.HQMusicUrl = HQMusicUrl;
    }

    public String getThumbMediaId() {
        return ThumbMediaId;
    }

    public void setThumbMediaId(String thumbMediaId) {
        this.ThumbMediaId = thumbMediaId;
    }
}

ArticleMessageResp 图文消息响应

package com.tdzh.weixin.Entity.resp;

import com.tdzh.weixin.Entity.Articles;

import java.util.Map;

/**
 * className:ArticleMessageResp
 * Package:com.tdzh.weixin.Entity.resp
 * Description:图文信息返回对象
 *
 * @date:2019/7/29 11:35
 * @author:malin
 */
public class ArticleMessageResp extends BaseMessageResp{

    private Integer ArticleCount;

    private Articles Articles;

    public ArticleMessageResp(Map<String, Object> requestMap, Integer ArticleCount , Articles Articles) {
        super(requestMap);
        this.ArticleCount = ArticleCount;
        this.Articles = Articles;
    }

    public Integer getArticleCount() {
        return ArticleCount;
    }

    public void setArticleCount(Integer articleCount) {
        ArticleCount = articleCount;
    }

    public com.tdzh.weixin.Entity.Articles getArticles() {
        return Articles;
    }

    public void setArticles(com.tdzh.weixin.Entity.Articles articles) {
        Articles = articles;
    }
}

Articles 图文消息列表

package com.tdzh.weixin.Entity;

/**
 * className:Articles
 * Package:com.tdzh.weixin.Entity
 * Description:文章实体类
 *
 * @date:2019/7/29 11:29
 * @author:malin
 */
public class Articles {

    private Item item;

    public Articles(Item item) {
        this.item = item;
    }

    public Item getItem() {
        return item;
    }

    public void setItem(Item item) {
        this.item = item;
    }
}

Item 单个图文

package com.tdzh.weixin.Entity;

/**
 * className:Item
 * Package:com.tdzh.weixin.Entity
 * Description:文章子实体类
 *
 * @date:2019/7/29 11:30
 * @author:malin
 */
public class Item {

    private String Title;

    private String Description;

    private String PicUrl;

    private String Url;

    public Item(String title, String description, String picUrl, String url) {
        this.Title = title;
        this.Description = description;
        this.PicUrl = picUrl;
        this.Url = url;
    }

    public String getTitle() {
        return Title;
    }

    public void setTitle(String title) {
        this.Title = title;
    }

    public String getDescription() {
        return Description;
    }

    public void setDescription(String description) {
        this.Description = description;
    }

    public String getPicUrl() {
        return PicUrl;
    }

    public void setPicUrl(String picUrl) {
        this.PicUrl = picUrl;
    }

    public String getUrl() {
        return Url;
    }

    public void setUrl(String url) {
        this.Url = url;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值