手把手教你如何微信公众号开发「建议收藏」

2022-09-25 10:50:28 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

最近的话,发现微信开发其实也有很多挺有意思的地方,比如最近很火的一款游戏“跳一跳”,也让我如此着迷。。但是,今天我所要讲的并不是对于小程序的开发,而是要说一下,关于微信开发的另外一个内容,那就是微信公众号。。

关于,什么是微信公众号,微信公众号怎么申请,这个我就不多说,这些基本的概念不在这里进行讲解,自己可以直接百度就可以找到很多的资源。而我主要讲解一下关于微信公众号开发中,一些比较重要和常见的知识点,所以,这个也并不是基础篇的文章哦~!好歹也要对微信公众号有一点了解才行。~!

一:实现外网域名访问本地服务项目

描述:我们在刚开始接触微信公众号开发的时候,我想,一般情况下,很多人都是没有服务器的,简单点说,就是没有服务器IP,或者是公网访问的域名。然而,要想能够实现微信公众能能够与我们后台代码进行交互,那么肯定就需要有一个公网能够访问的地址,那么这怎么办好呢?

解法一:很简单呀,直接去新浪云,阿里云,华为云,买一个服务器呗,而且是学生的话,还有优惠,多好。。但是,这个又比较繁琐,里面又有配置内容啥的,一堆(比如,tomcat,mysql,jdk等等)。那么,看看第二种方法。。。。(但是,请记住,这个是想做服务端开发必须会的,如果你连部署项目都不会,你觉得公司对你的感觉如何?多一个技能就是一个优势)

解法二:反向代理。。如果,你是第一次听说这个名词,那么就赶紧恶补一下,这个名词的含义。我简单点说,就是通过反向代理的模式,来代理你本地的ip,以便能够在公网地址能够访问到本地的项目。。具体,请看下面,如何进行~!~!

步骤:(1)下载ogrok客户端———也就是反向代理的客户端,当然还有很多类似的,我这里就使用这个而已。

这个可以通过该链接进行下载ogrok下载链接

(2)解压刚下载好的客户端文件到自己的一个目录下

(3)通过cmd命令,进入DOS,并且进入到刚刚解压的ogrok目录下

(4)执行 ngrok -config=ngrok.cfg -subdomain xxx 8080 //(xxx 是你自定义的域名前缀)

比如,我这里就是xxx就是用myjavttest

结果:

(5)这样的话,我们就可以通过上面的地址进行访问本地的项目了。(原来都是用的localhost:8080/login.jsp或者127.0.0.1:8080/login.jsp),当然,前提是本地有一个开启的项目,这样才可以,别本地都没有项目开启,就用公网去访问,你觉得,它能够访问么?所以,请别忘记这一点。

(二)微信公众号客户端与后台进行验证身份

首先,我们通过第一步,我们就能够得到一个以公网地址访问的一个IP(域名),那么既然要使得微信公众号能够与后台进行关联,那么肯定需要配置微信公众号的具体对应的服务器地址了。

步骤:(1)首先,进入微信公众号开发官网,并且进行登陆

(2)

(3)

(4)

OK,配置到这个的话,就简单的,将基本的配置进行设置好了。。那么,下面才是关键,进入真正的开发阶段。。

如果微信端,要与后台进行关联,那么当用户进行与后台交互的时候,后台就需要采取,身份验证,而这个是通过GET方式的请求,而只有通过的才可以进行后续的处理。所以,如何进行,那么就看下面的代码:这里讲解两种形式~~~~

第一种:(采取Servlet)

代码语言:javascript复制
@WebServlet(name = "ConnectWeChatServlet")
public class ConnectWeChatServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }

    /**
     * 进行验证是否身份匹配
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        System.out.println("" signature  "@" timestamp  "$" nonce  "^" echostr);
        PrintWriter out = response.getWriter();
        if(CheckConnectUtils.checkConncetWithWeChat(signature,timestamp,nonce)){
            out.print(echostr);
        }
    }

验证的代码:

代码语言:javascript复制
package com.hnu.scw.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
 * @author scw
 * @create 2018-01-17 9:28
 * @desc 检查微信和服务器是否链接成功
 **/
public class CheckConnectUtils {
    private static final String token = "wechat"; //这个就是微信公众号之前配置的token,必须保持一致
    /**
     * 判断是否链接匹配
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkConncetWithWeChat(String signature,String timestamp,String nonce){
        String[] arr = new String[]{token,timestamp,nonce};
        //排序
        Arrays.sort(arr);
        //生成字符串
        StringBuilder stringBuilder = new StringBuilder();
        for (String str:arr) {
            stringBuilder.append(str);
        }
        //进行SHA1加密
        String encodeString = passSha1Encode(stringBuilder.toString());
        if(signature.equals(encodeString)){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 字符串进行SHA1加密
     * @param str
     * @return
     */
    public static String passSha1Encode(String str){
        if(str == null || str.length() == 0){
            return null;
        }
        char hexDigits[] = {'0','1','2','3','4','5','6','7','8','9'
        ,'a','b','c','d','e','f'};
        try{
            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
            mdTemp.update(str.getBytes());
            byte[] md = mdTemp.digest();
            int j = md.length;
            char[] buf = new char[j*2];
            int k = 0;
            for(int i=0 ; i <j ; i  ){
                byte byte0 = md[i];
                buf[k  ] = hexDigits[byte0 >>>4 & 0xf];
                buf[k  ] = hexDigits[byte0 & 0xf];
            }
            return new String(buf);
        } catch (NoSuchAlgorithmException e) {
           return null;
        }
    }
}

第二种:(采取框架,比如SpringMVC Spring Hibernate)

代码语言:javascript复制
/**
 * @author scw
 * @create 2018-01-18 11:38
 * @desc 微信前端连接的主要控制类
 **/
@Controller
public class WeChatDogPrimaryController {
    /**
     * 进行微信用户验证,只能是Get方法
     * @param request
     * @param response
     */
    @RequestMapping(value = "/wechat" ,method = RequestMethod.GET)
    public void connectValidate(HttpServletRequest request , HttpServletResponse response) throws IOException {
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        System.out.println("" signature  "@" timestamp  "$" nonce  "^" echostr);
        PrintWriter out = response.getWriter();
        if(CheckConnectUtils.checkConncetWithWeChat(signature,timestamp,nonce)){
            out.print(echostr);
        }
    }


    /**
     * 客户端进行的消息处理
     * @param request
     * @param response
     */
    @RequestMapping(value = "/wechat" ,method = RequestMethod.POST)
    public void disposeClientMessage(HttpServletRequest request , HttpServletResponse response ) throws IOException {
      
    }

(三)微信客户端与后台进行消息交互(比如,文本,图片,视频,音频)

消息的实体类:

代码语言:javascript复制
package com.hnu.scw.model;

/**
 * @author scw
 * @create 2018-01-17 13:37
 * @desc 对于所有消息的基本父类
 **/
public class BaseMessage {
    private String ToUserName;
    private String FromUserName;
    private String CreateTime;
    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 String getCreateTime() {
        return CreateTime;
    }

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

    public String getMsgType() {
        return MsgType;
    }

    public void setMsgType(String msgType) {
        MsgType = msgType;
    }
}
代码语言:javascript复制
package com.hnu.scw.model;

/**
 * @author SCW
 * @create 2018-01-17 15:08
 * @desc 图片的基本类
 **/
public class ImageBase {
    private String MediaId;

    public String getMediaId() {
        return MediaId;
    }

    public void setMediaId(String mediaId) {
        MediaId = mediaId;
    }
}
代码语言:javascript复制
package com.hnu.scw.model;

/**
 * @author scw
 * @create 2018-01-17 15:09
 * @desc 图片消息
 **/
public class ImageMessage extends BaseMessage {
    private ImageBase Image ;

    public ImageBase getImageBase() {
        return Image;
    }

    public void setImageBase(ImageBase Image) {
        this.Image = Image;
    }
}
代码语言:javascript复制
package com.hnu.scw.model;

/**
 * @author Administrator
 * @create 2018-01-17 16:45
 * @desc 音乐类型的基本类
 **/
public class MusicBase {
    private String Title;
    private String Description;
    private String MusicUrl;
    private String HQMusicUrl;
    private String ThumbMediaId;

    public String getTitle() {
        return Title;
    }

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

    public String getDescription() {
        return Description;
    }

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

    public String getMusicUrl() {
        return MusicUrl;
    }

    public void setMusicUrl(String musicUrl) {
        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) {
        ThumbMediaId = thumbMediaId;
    }
}
代码语言:javascript复制
package com.hnu.scw.model;

/**
 * @author Administrator
 * @create 2018-01-17 16:46
 * @desc 用于包装音乐的实体
 **/
public class MusicMessage extends BaseMessage {
    private MusicBase Music;

    public MusicBase getMusic() {
        return Music;
    }

    public void setMusic(MusicBase music) {
        Music = music;
    }
}
代码语言:javascript复制
package com.hnu.scw.model;

/**
 * @author scw
 * @create 2018-01-17 10:03
 * @desc 文本消息的内容
 **/
public class MyTestMessage  extends BaseMessage{
    private String Content;
    private String  MsgId;

    public String getContent() {
        return Content;
    }

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

    public String getMsgId() {
        return MsgId;
    }

    public void setMsgId(String msgId) {
        MsgId = msgId;
    }
}
代码语言:javascript复制
package com.hnu.scw.model;

/**
 * @author scw
 * @create 2018-01-17 13:38
 * @desc 对于图文消息最内层结构的实体类
 **/
public class NewsBase {
    private String Title;
    private String Description;
    private String PicUrl;
    private String Url;

    public String getTitle() {
        return Title;
    }

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

    public String getDescription() {
        return Description;
    }

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

    public String getPicUrl() {
        return PicUrl;
    }

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

    public String getUrl() {
        return Url;
    }

    public void setUrl(String url) {
        Url = url;
    }
}
代码语言:javascript复制
package com.hnu.scw.model;

import java.util.List;

/**
 * @author scw
 * @create 2018-01-17 13:35
 * @desc 对于图文消息的实体类
 **/
public class NewsMessage extends BaseMessage{
    private int ArticleCount;
    private List<NewsBase> Articles;

    public int getArticleCount() {
        return ArticleCount;
    }

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

    public List<NewsBase> getArticles() {
        return Articles;
    }

    public void setArticles(List<NewsBase> articles) {
        Articles = articles;
    }
}

消息封装工具类:

代码语言:javascript复制
package com.hnu.scw.utils;
import com.hnu.scw.model.*;
import com.thoughtworks.xstream.XStream;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author scw
 * @create 2018-01-17 9:52
 * @desc 用户转换消息的格式
 **/
public class MessageUtils {
    /**
     * 定义多种消息类型
     */
    public static final String MESSAGE_TEXT = "text";
    public static final String MESSAGE_IMAGE = "image";
    public static final String MESSAGE_VOICE = "voice";
    public static final String MESSAGE_MUSIC = "music";
    public static final String MESSAGE_VIDEO = "video";
    public static final String MESSAGE_LINK = "link";
    public static final String MESSAGE_LOCATION = "location";
    public static final String MESSAGE_EVENT = "event";
    public static final String MESSAGE_SUBSCRIBE = "subscribe";
    public static final String MESSAGE_UNSUBSCRIBE = "unsubscribe";
    public static final String MESSAGE_CLICK = "CLICK";
    public static final String MESSAGE_VIEW = "VIEW";
    //扫码事件
    public static final String MESSAGE_SCANCODE = "scancode_push";

    /**
     * XML格式转为map格式
     * @param request
     * @return
     */
    public static Map<String , String> xmlToMap(HttpServletRequest request){
        Map<String ,String> map = new HashMap<String , String>();
        try {
            InputStream inputStream =null;
            inputStream = request.getInputStream();
            SAXReader reader = new SAXReader();
            Document doc = reader.read(inputStream);
            Element rootElement = doc.getRootElement();
            List<Element> elements = rootElement.elements();
            for (Element el:elements) {
                map.put(el.getName() , el.getText());
            }
            inputStream.close();
            return map ;
        } catch (Exception e) {
            e.printStackTrace();
            return null ;
        }
    }
    /**
     * 文本消息对象转为xml格式
     * @param myTestMessage
     * @return
     */
    public static String textMessage2Xml(MyTestMessage myTestMessage){
        XStream xStream = new XStream();
        xStream.alias("xml" , myTestMessage.getClass());
        return xStream.toXML(myTestMessage);
    }
    /**
     * 将图文消息对象转化为图文格式的XML
     * @return
     */
    public static String newsMessage2XML(NewsMessage newsMessage){
        XStream xStream = new XStream();
        //将需要修改的一些标签进行替换
        xStream.alias("xml" , newsMessage.getClass());
        xStream.alias("item" , new NewsBase().getClass());
        return xStream.toXML(newsMessage);
    }
    /**
     * 设置需要返回的图文信息
     * @param fromUserName
     * @param toUserName
     * @return
     */
    public static String initNewSMessage(String fromUserName , String toUserName ){
        String message = null;
        List<NewsBase> newList = new ArrayList<NewsBase>();
        NewsMessage newsMessage = new NewsMessage();
        NewsBase  newsBase = new NewsBase();
        newsBase.setTitle("我是图文消息");
        newsBase.setDescription("测试测试测试测试测试测试测试测试测试");
    newsBase.setPicUrl("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=677717294,4155848424&fm=27&gp=0.jpg")
        newsBase.setUrl("www.baidu.com");
        //添加图文消息的内容
        newList.add(newsBase);

        //注意接受消息和发送消息的顺序要反过来,因为现在是从服务器进行发送了,而客户端是接收端了
        newsMessage.setFromUserName(toUserName);
        newsMessage.setToUserName(fromUserName);
        newsMessage.setCreateTime(String.valueOf(System.currentTimeMillis()));
        newsMessage.setMsgType("news");
        newsMessage.setArticleCount(newList.size());
        newsMessage.setArticles(newList);
        //调用转为图文的XML
        return MessageUtils.newsMessage2XML(newsMessage);
    }
    /**
     * 设置需要返回的文本信息
     * @param fromUserName
     * @param toUserName
     * @param content
     * @return
     */
    public static String initText(String fromUserName , String toUserName , String content){
        MyTestMessage text = new MyTestMessage();
        //注意接受消息和发送消息的顺序要烦过来
        text.setFromUserName(toUserName);
        text.setToUserName(fromUserName);
        text.setMsgType(MessageUtils.MESSAGE_TEXT);
        long time = System.currentTimeMillis();
        text.setCreateTime(String.valueOf(time));
        text.setContent(content);
        return MessageUtils.textMessage2Xml(text);
    }
    /**
     * 设置订阅时,返回菜单的内容
     * @return
     */
    public static String menuText(){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("菜单1:回复数字1,有惊喜n");
        stringBuilder.append("菜单2:回复数字2,有惊喜n");
        stringBuilder.append("菜单3:回复数字3,有惊喜n");
        stringBuilder.append("菜单4:回复数字3,有惊喜n");
        stringBuilder.append("菜单5:回复数字3,有惊喜n");
        stringBuilder.append("菜单6:回复数字未知的东东,也还有有惊喜哦n");
        return stringBuilder.toString();
    }
    /**
     * 回复关键字"1"的时候的内容
     * @return
     */
    public static String inputNumber1(){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("我是惊喜111,哈哈,惊喜不惊喜!");
        return stringBuilder.toString();
    }
    /**
     * 回复关键字"2"的时候的内容
     * @return
     */
    public static String inputNumber2(){
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("我是惊喜2222,哈哈,惊喜不惊喜!");
        return stringBuilder.toString();
    }
    /**
     * 返回图片消息(对于视频和音频都是一样的方式,只需要更改类型即可,即将Image修改为video,voice)
     * @param fromUserName
     * @param toUserName
     * @return
     */
    public static String initImageMessage(String fromUserName , String toUserName ){
        ImageBase imageBase = new ImageBase();
        //这个media_Id是在之前执行过上传图片返回得到的信息
        imageBase.setMediaId("HK17wQmCupESK4B9u14PqI4w3gtteXhUtGgriJW6G5c8O-Y0OsjGbYfQYhGDbYDx");
        ImageMessage imageMessage = new ImageMessage();
        imageMessage.setFromUserName(toUserName);
        imageMessage.setToUserName(fromUserName);
        imageMessage.setMsgType(MessageUtils.MESSAGE_IMAGE);
        long time = System.currentTimeMillis();
        imageMessage.setCreateTime(String.valueOf(time));
        imageMessage.setImageBase(imageBase);
        return imageMessage2XML(imageMessage);
    }
    /**
     * 将图片消息对象转化为图片格式的XML
     * @return
     */
    public static String imageMessage2XML(ImageMessage imageMessage){
        XStream xStream = new XStream();
        //将需要修改的一些标签进行替换
        xStream.alias("xml" , imageMessage.getClass());
        xStream.alias("Image" , new ImageBase().getClass());
        return xStream.toXML(imageMessage);
    }
    /**
     * 将音乐消息对象转化为图片格式的XML
     * @return
     */
    public static String musicMessage2XML(MusicMessage musicMessage){
        XStream xStream = new XStream();
        //将需要修改的一些标签进行替换
        xStream.alias("xml" , musicMessage.getClass());
        xStream.alias("Music" , new MusicBase().getClass());
        return xStream.toXML(musicMessage);
    }
    /**
     * 返回音乐消息
     * @param fromUserName
     * @param toUserName
     * @return
     */
    public static String initMusicMessage(String fromUserName , String toUserName ){
        MusicBase musicBase = new MusicBase();
        //这个ThumbMediaId是在之前执行过上传缩略图返回得到的信息(这个和上传图片的方法是一样的,都是调用pictureUtils中的上传方法)
        musicBase.setThumbMediaId("vJOi5E4_U91onQnsayPdkzxted6ZctEAEzcoLd3BJ8a00gJLuhEmTckF6S2XkS5R");
        musicBase.setTitle("来一首音乐");
        musicBase.setDescription("静静的听首歌吧!");
        //设置高质量音质的歌曲路径,可以和一般音质音乐的路径一样
        musicBase.setHQMusicUrl("http://myjava.ngrok.xiaomiqiu.cn/resource/mymusic.mp3");
        //设置音乐的路径
        musicBase.setMusicUrl("http://myjava.ngrok.xiaomiqiu.cn/resource/mymusic.mp3");
        MusicMessage musicMessage = new MusicMessage();
        musicMessage.setFromUserName(toUserName);
        musicMessage.setToUserName(fromUserName);
        //设置类型为音乐
        musicMessage.setMsgType(MessageUtils.MESSAGE_MUSIC);
        long time = System.currentTimeMillis();
        musicMessage.setCreateTime(String.valueOf(time));
        musicMessage.setMusic(musicBase);
        return musicMessage2XML(musicMessage);
    }
}

交互主类:

代码语言:javascript复制
package com.hnu.scw.controller;
import com.hnu.scw.utils.CheckConnectUtils;
import com.hnu.scw.utils.MessageUtils;
import com.hnu.scw.utils.WeiXinUserInfoUtiols;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
/**
 * @author scw
 * @create 2018-01-18 11:38
 * @desc 微信前端连接的主要控制类
 **/
@Controller
public class WeChatDogPrimaryController {
    /**
     * 进行微信用户验证,只能是Get方法
     * @param request
     * @param response
     */
    @RequestMapping(value = "/wechat" ,method = RequestMethod.GET)
    public void connectValidate(HttpServletRequest request , HttpServletResponse response) throws IOException {
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        System.out.println("" signature  "@" timestamp  "$" nonce  "^" echostr);
        PrintWriter out = response.getWriter();
        if(CheckConnectUtils.checkConncetWithWeChat(signature,timestamp,nonce)){
            out.print(echostr);
        }
    }
    /**
     * 客户端进行的消息处理
     * @param request
     * @param response
     */
    @RequestMapping(value = "/wechat" ,method = RequestMethod.POST)
    public void disposeClientMessage(HttpServletRequest request , HttpServletResponse response ) throws IOException {
        backTestFunction(request , response );
    }
    /**
     * 文字回复功能开发
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    public void backTestFunction(HttpServletRequest request , HttpServletResponse response ) throws IOException {
        //防止进行post提交和响应的消息乱码
        request.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "text/html;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        try{
            //将发送过来的消息XML形式转为map内容
            Map<String , String> map = MessageUtils.xmlToMap(request);
            String fromUserName = map.get("FromUserName");
            String toUserName = map.get("ToUserName");
            String msgType = map.get("MsgType");
            String content = map.get("Content");
            String message = null ;
            if(MessageUtils.MESSAGE_TEXT.equals(msgType)){
                //进行关键字回复功能
                if("1".equals(content)){
                    message = MessageUtils.initText(fromUserName,toUserName,MessageUtils.inputNumber1());
                }else if("2".equals(content)){
                    message = MessageUtils.initText(fromUserName,toUserName,MessageUtils.inputNumber2());
                }
                else if("3".equals(content)){
                    //客户端输入“3”,返回一条图文消息
                    message = MessageUtils.initNewSMessage(fromUserName,toUserName);
                }else if("4".equals(content)){
                    //客户端输入“4”,返回一条图片消息
                    message = MessageUtils.initImageMessage(fromUserName,toUserName);
                }else if("5".equals(content)){
                    //客户端输入“5”,返回一首音乐消息
                    message = MessageUtils.initMusicMessage(fromUserName,toUserName);
                }else if("6".equals(content)){
                    //测试是否能够获取用户的信息
                    message = MessageUtils.initText(fromUserName,toUserName, WeiXinUserInfoUtiols.getUserInfo(fromUserName));
                }else if(content.startsWith("翻译")){
                    //客户端输入“以翻译开头”,返回对应的翻译信息
                    /*String translateResult = TranslationUtils.translate(content.substring(2,content.length()));
                    message = MessageUtils.initText(fromUserName,toUserName , translateResult);*/
                }else {
                    message = MessageUtils.initText(fromUserName,toUserName,"你发送的消息是:"   content);
                }
            }else if(MessageUtils.MESSAGE_EVENT.equals(msgType)){
                String eventType = map.get("Event");
                //完成订阅时候返回的内容
                if(MessageUtils.MESSAGE_SUBSCRIBE .equals(eventType)){
                    message = MessageUtils.initText(fromUserName,toUserName , MessageUtils.menuText());
                }else if(MessageUtils.MESSAGE_CLICK .equals(eventType)){
                    //进行的是click按钮的点击事件(这里就推送一下主菜单内容)
                    message = MessageUtils.initText(fromUserName,toUserName , MessageUtils.menuText());
                }else if(MessageUtils.MESSAGE_VIEW .equals(eventType)){
                    //进行的是view按钮的点击事件(这里就推送一下主菜单内容)
                    String viewUrl = map.get("EventKey");
                    message = MessageUtils.initText(fromUserName,toUserName , viewUrl);
                }else if(MessageUtils.MESSAGE_SCANCODE .equals(eventType)) {
                    //进行的是扫码事件
                    String key = map.get("EventKey");
                    message = MessageUtils.initText(fromUserName,toUserName , key);
                }
            }else if(MessageUtils.MESSAGE_LOCATION .equals(msgType)) {
                //进行的是地理位置信息
                String label = map.get("Label");
                message = MessageUtils.initText(fromUserName,toUserName , label);
            }
            //打印输出的xml格式内容,方便进行调试
            System.out.println(message);
            out.print(message);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            out.close();
        }
    }
}

(四)获取Access_Token

Access_Token是一个全局的票据,调用任何的高级接口,都需要这个,所以这个非常非常的重要

具体代码:

代码语言:javascript复制
package com.hnu.scw.utils;
import com.hnu.scw.menu.BaseButton;
import com.hnu.scw.menu.ClickButton;
import com.hnu.scw.menu.CustomeMenu;
import com.hnu.scw.menu.ViewButton;
import com.hnu.scw.model.AccessToken;
import com.hnu.scw.projectconst.ProjectConst;
import net.sf.json.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;

import javax.servlet.ServletContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

/**
 * @author scw
 * @create 2018-01-17 14:13
 * @desc 用户获取access_token,众号调用各接口时都需使用access_token
 **/
public class WeiXinUtils {
    /**
     * 微信公众号的APPID和Appsecret,这个是每个微信公众号都唯一的,以后配置不同的公众号配置这里即可
     */
    private static final String APPID = "自己公众号对应的内容";
    private static final String APPSECRET = "自己公众号对应的内容";
    //获取access_token的URL
    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

    //进行创建菜单的接口URL
    private static final String CREATE_MENU_URL ="https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";

    //菜单查询的接口URL
    private static final String QUERY_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN";

    //菜单删除的接口URL
    private static final String DELETE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";

    /**
     * Get请求,方便到一个url接口来获取结果
     * @param url
     * @return
     */
    public static JSONObject doGetStr(String url){
        DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(url);
        JSONObject jsonObject = null;
        try{
            HttpResponse response = defaultHttpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if(entity != null){
                String result = EntityUtils.toString(entity, "UTF-8");
                jsonObject = JSONObject.fromObject(result);
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * 带参数的post请求,方便到一个url接口来获取结果
     * @param url
     * @param outStr
     * @return
     */
    public static JSONObject doPostStr(String url , String outStr)  {
        DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        JSONObject jsonObject = null;
        try {
            httpPost.setEntity(new StringEntity(outStr , "UTF-8"));
            HttpResponse response = defaultHttpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            if(entity != null){
                String result = EntityUtils.toString(entity, "UTF-8");
                jsonObject = JSONObject.fromObject(result);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * 获取access_token
     * @return
     */
    public static AccessToken getAccessToken(){
        AccessToken accessToken = new AccessToken();
        String url = ACCESS_TOKEN_URL.replace("APPID" ,APPID).replace("APPSECRET",APPSECRET);
        JSONObject jsonObject = doGetStr(url);
        if(jsonObject !=null){
            accessToken.setToken(jsonObject.getString("access_token"));
            accessToken.setExpireIn(jsonObject.getLong("expires_in"));
        }
        return accessToken;
    }

测试是否成功获取:

代码语言:javascript复制
package com.hnu.scw.test;
import com.hnu.scw.model.AccessToken;
import com.hnu.scw.utils.WeiXinAccessTokenKeepAlive;
import com.hnu.scw.utils.WeiXinUtils;
import org.junit.Test;
/**
 * @author scw
 * @create 2018-01-18 15:21
 * @desc 用于对Access_token内容相关的测试
 **/
public class AccessTokenTest {
    /**
     * 获取到Access_Token,这个对于要想使用其他的微信接口,就必须要有这个进行验证
     */
    @Test
    public void getAccssTokenTest(){
        AccessToken accessToken = WeiXinUtils.getAccessToken();
        System.out.println("token:"  accessToken.getToken());
        System.out.println("有效时间:"  accessToken.getExpireIn());
    }
}

(五)自定义菜单

下面的代码,就接着(四)中的类写就可以了,因为都属于微信开发的工具类

步骤:

(1)创建菜单按钮的实体对象类

BaseButton:

代码语言:javascript复制
package com.hnu.scw.menu;
/**
 * @author scw
 * @create 2018-01-17 17:20
 * @desc 最基础的Button
 **/
public class BaseButton {
    private String type;
    private String name;
    //子按钮(也可以理解为二级菜单)
    private BaseButton[] sub_button;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BaseButton[] getSub_button() {
        return sub_button;
    }

    public void setSub_button(BaseButton[] sub_button) {
        this.sub_button = sub_button;
    }
}

clickButton:

代码语言:javascript复制
package com.hnu.scw.menu;
/**
 * @author Administrator
 * @create 2018-01-17 17:21
 * @desc Click类型的Button实体
 **/
public class ClickButton extends BaseButton {
    private String key;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }
}

viewButton:

代码语言:javascript复制
package com.hnu.scw.menu;
/**
 * @author scw
 * @create 2018-01-17 17:22
 * @desc 类型是View的按钮实体
 **/
public class ViewButton extends BaseButton{
    private String url;

    public String getUrl() {
        return url;
    }

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

CustomerMenu菜单定义:

代码语言:javascript复制
package com.hnu.scw.menu;
/**
 * @author scw
 * @create 2018-01-17 17:23
 * @desc 自定义菜单的实体
 **/
public class CustomeMenu {
    //对菜单按钮进行封装
    private BaseButton[] button;

    public BaseButton[] getButton() {
        return button;
    }

    public void setButton(BaseButton[] button) {
        this.button = button;
    }
}

(2)调用接口,进行菜单的创建

代码语言:javascript复制
 /**
     * 设置菜单的形式
     * @return
     */
    public static CustomeMenu initMenu(){
        CustomeMenu customeMenu = new CustomeMenu();
        ClickButton clickButton = new ClickButton();
        clickButton.setName("click菜单");
        clickButton.setType("click");
        clickButton.setKey("01");

        ViewButton viewButton = new ViewButton();
        viewButton.setName("view菜单");
        viewButton.setType("view");
        viewButton.setUrl("需要访问的地址");

        ClickButton clickButton2 = new ClickButton();
        clickButton2.setName("扫码事件的click菜单");
        clickButton2.setType("scancode_push");
        clickButton2.setKey("02");

        ClickButton clickButton3 = new ClickButton();
        clickButton3.setName("地理位置的click菜单");
        clickButton3.setType("location_select");
        clickButton3.setKey("03");

        BaseButton baseButton = new BaseButton();
        baseButton.setName("菜单");
        //将clickButton2,clickButton3作为一个子菜单中的按钮
        baseButton.setSub_button(new BaseButton[]{clickButton2,clickButton3});
        //把按钮分别放入到菜单中
        customeMenu.setButton(new BaseButton[]{clickButton,viewButton,baseButton});

        return customeMenu;
    }

    /**
     * 创建自定义菜单
     * @param token
     * @param menu
     * @return
     */
    public static int createMenu(String token , String menu){
        int result = 0;
        String url = CREATE_MENU_URL.replace("ACCESS_TOKEN" ,token);
        JSONObject jsonObject = doPostStr(url, menu);
        if(jsonObject != null){
            //接受返回回来的参数,如果是0,就是创建成功
            result = jsonObject.getInt("errcode");
        }
        return result;
    }

    /**
     * 对菜单进行查询
     * @param token
     * @return
     */
    public static JSONObject queryMenu(String token){
        String url = QUERY_MENU_URL.replace("ACCESS_TOKEN" ,token);
        JSONObject jsonObject = doGetStr(url);
        return jsonObject;
    }

    /**
     * 对菜单进行删除
     * @param token
     * @return
     */
    public static JSONObject deleteMenu(String token){
        String url = DELETE_MENU_URL.replace("ACCESS_TOKEN" ,token);
        JSONObject jsonObject = doGetStr(url);
        return jsonObject;
    }

(3)生成菜单

代码语言:javascript复制
package com.hnu.scw.test;
import com.hnu.scw.model.AccessToken;
import com.hnu.scw.utils.WeiXinUtils;
import net.sf.json.JSONObject;
import org.junit.Test;
/**
 * @author scw
 * @create 2018-01-18 15:21
 * @desc 菜单相关的测试
 **/
public class MenuTest {
    /**
     * 创建菜单
     */
    @Test
    public void creatMenuTest(){
        //获取到access_token
        AccessToken accessToken = WeiXinUtils.getAccessToken();
        //获取到自定义菜单的格式(JSONObject将对象转为json,然后再需要转为字符串型)
        String menu = JSONObject.fromObject(WeiXinUtils.initMenu()).toString();
        //调用创建菜单
        int result = WeiXinUtils.createMenu(accessToken.getToken(), menu);
        if(result == 0){
            //如果调用方法之后,返回的是0,那么就表示创建成功。
            System.out.println("创建成功");
        }else{
            System.out.println("创建失败");
        }
    }
    /**
     * 查询菜单
     */
    @Test
    public void queryMenuTest(){
        //获取到access_token
        AccessToken accessToken = WeiXinUtils.getAccessToken();
        //调用菜单查询的方法,返回是的一个Json格式
        JSONObject jsonObject = WeiXinUtils.queryMenu(accessToken.getToken());
        System.out.println(jsonObject);
    }
    /**
     * 删除菜单
     */
    @Test
    public void deleteMenuTest(){
        //获取到access_token
        AccessToken accessToken = WeiXinUtils.getAccessToken();
        //调用菜单查询的方法,返回是的一个Json格式
        JSONObject jsonObject = WeiXinUtils.deleteMenu(accessToken.getToken());
        if(jsonObject.getInt("errcode") == 0){
            //返回0,表示的是删除成功
            System.out.println("删除成功");
        }else{
            System.out.println("删除失败");
        }

    }
}

上面就是一些基本的微信公众号的交互了,刚刚接触可能不是很熟,慢慢的就了解了之后,其实也很简单的,当然,对于其中的一些高级接口的使用,可以看看我其他的文章,都有提到。。如果有问题,不明白的地方,欢迎进行交流和留言~!另外,推荐了比较好的学习资源,就是慕课网,这里面对于比较基础的微信公众号开发还是讲解的比较好,再结合我的文章,肯定是没有任何问题的。。。。

Github的地址:

https:https://github.com/qq496616246/WeChatCode.git

git地址:git@github.com:qq496616246/WeChatCode.git

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/171591.html原文链接:https://javaforall.cn

0 人点赞