手把手教你如何微信公众号开发

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

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

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

描述:我们在刚开始接触微信公众号开发的时候,我想,一般情况下,很多人都是没有服务器的,简单点说,就是没有服务器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)

@WebServlet(name = "ConnectWeChatServlet")
public class ConnectWeChatServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}/*** 进行验证是否身份匹配* @param request* @param response* @throws ServletException* @throws IOException*/@Overrideprotected 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);}}

验证的代码:

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)

/*** @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 {}

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

消息的实体类:

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;}
}
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;}
}
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;}
}
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;}
}
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;}
}
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;}
}
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;}
}
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;}
}

消息封装工具类:

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);//调用转为图文的XMLreturn 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);}
}

交互主类:

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是一个全局的票据,调用任何的高级接口,都需要这个,所以这个非常非常的重要

具体代码:

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的URLprivate static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";//进行创建菜单的接口URLprivate static final String CREATE_MENU_URL ="https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";//菜单查询的接口URLprivate static final String QUERY_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN";//菜单删除的接口URLprivate 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;}

测试是否成功获取:

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,这个对于要想使用其他的微信接口,就必须要有这个进行验证*/@Testpublic void getAccssTokenTest(){AccessToken accessToken = WeiXinUtils.getAccessToken();System.out.println("token:" +accessToken.getToken());System.out.println("有效时间:" +accessToken.getExpireIn());}
}

(五)自定义菜单

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

步骤:

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

BaseButton:

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:

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:

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菜单定义:

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)调用接口,进行菜单的创建

 /*** 设置菜单的形式* @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)生成菜单

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 {/*** 创建菜单*/@Testpublic void creatMenuTest(){//获取到access_tokenAccessToken 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("创建失败");}}/*** 查询菜单*/@Testpublic void queryMenuTest(){//获取到access_tokenAccessToken accessToken = WeiXinUtils.getAccessToken();//调用菜单查询的方法,返回是的一个Json格式JSONObject jsonObject = WeiXinUtils.queryMenu(accessToken.getToken());System.out.println(jsonObject);}/*** 删除菜单*/@Testpublic void deleteMenuTest(){//获取到access_tokenAccessToken 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/47362.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信公众号开发教程

本教程为看微信公众号视频做的笔记&#xff0c;原视频链接&#xff1a;尚硅谷公众号开发&#xff0c;微信公众号开发实战_哔哩哔哩_bilibili 平台 微信公众号管理&#xff1a;公众号 (qq.com) 微信公众测试号平台&#xff1a;微信公众平台 (qq.com) 微信公众号开发文档&…

公众号推文制作及发布保姆级教程

在这个新媒体的时代&#xff0c;无论是我们刚步入大学&#xff0c;加入了部门&#xff0c;做一些宣传方面的工作&#xff0c;还是想在微信公众号平台发布一些自己的日常生活&#xff0c;写一些文章&#xff0c;甚至以后从事一些关于新媒体的工作……推文这个玩意儿确实越来越吃…

Python预测糖尿病

今天给大家讲解一个实战案例:如何根据现有数据预测糖尿病。在这个案例开始之前&#xff0c;希望大家回忆一下大学里讲过的线性回归的知识&#xff0c;这是数据挖掘里非常重要的一部分知识。当然&#xff0c;鉴于大家都学过&#xff0c;本篇就不再赘述。 一. 数据集介绍 diabe…

小组作业:糖尿病预测

提示&#xff1a;该Blog仅用于作业汇报展示&#xff0c;大佬请绕路 文章目录 一、作业介绍二、数据处理三、数据分析四、特征选择五、模型训练与评价六、模型优化七、与原模型进行对比八、作业总结 一、作业介绍 该项目依托于某医院处理好之后的体检数据&#xff0c;首先进行了…

python糖尿病数据挖掘

有人说21世纪&#xff0c;我们的生活越来越便捷&#xff0c;电子通讯越来越发达&#xff0c;美食越来越多。这一点也不假。但现代生活方式也有不利一面&#xff0c;工作越来越忙&#xff0c;身体锻炼越来越少&#xff0c;体重一天一天增加。有一种疾病叫做糖尿病&#xff0c;你…

数据挖掘——糖尿病预测

一、问题描述 糖尿病数据集是Sklearn 提供的数据集。它从442例糖尿病患者的资料中取10个特征&#xff1a;年龄、性别、体重、血压和6个血清测试量值&#xff0c;以及患者在一年后疾病发展的量化值&#xff08;标签&#xff09;。 二、实验目的 根据上述10个特征&#xff0c;预…

基于Python实现的糖尿病预测系统

资源下载地址&#xff1a;https://download.csdn.net/download/sheziqiong/86792308 资源下载地址&#xff1a;https://download.csdn.net/download/sheziqiong/86792308 基于Python设计的预测糖尿病 摘要和关键词 本次实验的主要内容是使用回归分析和聚类分析来预测某人患糖…

糖尿病预测

人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 https://www.captainai.net/shuai 一、糖尿病预测 1.1问题描述 糖尿病数据集是Sklearn 提供的数据集。它从442例糖尿病患者的资料中取10个特征&#xff1a;年龄…

使用 Python 机器学习的糖尿病预测模型

介绍 在本文中,我们将学习如何使用 Train Test Split 模型将数据集分为四个部分,开发预测模型,并通过用例分析预测和数据集。 用例——问题陈述 我们这篇文章的目标是预测患者是否患有糖尿病。我们所有的患者都是年轻女性,她们提供的数据(即怀孕次数、血糖水平和 BMI)…

FGF21 类似物 PF-05231023 改善糖尿病并发症

光感受器细胞中拥有大量的线粒体&#xff0c;以满足视网膜组织高代谢速率的需求。但是&#xff0c;在糖尿病人体内&#xff0c;高血糖引发的代谢异常会增加机体的氧化压力&#xff0c;从而加速视网膜的微血管病变。因此&#xff0c;增强光感受器细胞内的抗氧化通路可以阻止 DR …

保姆级人工智能学习成长路径

文章目录 0. 前言1. 第一阶段&#xff1a;编程语言学习2. 第二阶段&#xff1a;机器学习基本理论3. 第三阶段&#xff1a;深度学习理论与实战4. 第四阶段&#xff1a;细分领域深入学习5. 第五阶段&#xff1a;集大成者 0. 前言 最近有很多小伙伴想学习人工智能&#xff0c;其中…

图书馆小程序--Alpha迭代--第六周会议记录

1.小组介绍 组长&#xff1a;杨坤 小组成员&#xff1a;杨坤、何一鸣、韦灵雅、吴卿怡、许梦真、严影、林正远 2.流程图&#xff08;分模块&#xff09;&#xff1a; 3. 目前的小组分工&#xff1a; 许梦真&#xff1a;登录&#xff0c;验证用户信息。 1.制定数据库存储用…

【音视频架构演进:边缘计算与云原生】

在过去的一年中&#xff0c;我们可以看到多媒体特别是音视频技术的能力在严峻的挑战下&#xff0c;为各行各业带来了巨大的变化。疫情过后&#xff0c;又会有哪些多媒体新技术、新实践呈现在大众的视野当中&#xff1f;为行业的发展与应用带来哪些新的趋势与机会&#xff1f; 1…

跟一线高手深聊关于边缘计算的一切

这次我们把边缘计算“一线高手”都邀请到了上海&#xff0c;在全球边缘计算大会上海站上&#xff0c;关于边缘计算的一切&#xff0c;你好奇的、想了解的&#xff0c;都可以聊聊&#xff01; 1. 背景 今年三月份&#xff0c;十三届全国人大四次会议表决通过了关于国民经济和社会…

10月23日,相约全球边缘计算大会·上海站

全球边缘计算大会上海站&#xff0c;将于10月23日在上海召开。 本次大会&#xff0c;既有前沿技术研究分享&#xff0c;又有边缘计算落地实践、应用案例&#xff0c;是一次边缘计算领域的大型综合性会议。 早上设置了1个主会场&#xff0c;下午设置3个分会场&#xff0c;主要讨…

倒计时11天!全球边缘计算大会参会指南来啦!

全球边缘计算大会•上海站 参会指南 见证边缘的力量 10月23日&#xff08;周六&#xff09; 上海长宁区天山西路舜元会议中心&#xff08;靠近虹桥&#xff09; 目录 1.大会介绍 2.主办单位 3.峰会议程 4.交通指南 4.1 飞机 4.2 高铁 5.天气指南 6.签到&用餐指南 6.1 签到…

见证边缘的力量!全球边缘计算大会•上海站顺利召开!

2021年10月23日&#xff0c;以“见证边缘的力量”为主题的全球边缘计算大会在上海顺利召开&#xff01;本次大会由边缘计算社区主办&#xff0c;并得到了阿里云、亚马逊云科技、EMQ、PPIO、网宿科技、阿普奇、视美泰、九州云、谐云科技等企业联合支持&#xff0c;共同推动边缘计…

LiveVideoStackCon2021音视频技术大会北京站开幕在即,精彩抢鲜看

10.29-10.30&#xff0c;LiveVideoStackCon 2021音视频技术大会北京站将在北京丽亭华苑酒店举行。16个技术专题&#xff0c;67场技术分享&#xff0c;77位讲师&#xff0c;近500位多媒体生态技术代表将齐聚本届LiveVideoStackCon。本届大会主题为&#xff1a;新技术&#xff0c…

深度好文推荐:互联网厂商,究竟是如何看待5G的?

内容来源&#xff1a;2021年10月23日&#xff0c;由边缘计算社区主办的全球边缘计算大会上海站圆满落幕。会上&#xff0c;虎牙5G首席架构师林正显受邀发表了主题为《浅谈5G及边缘计算接入网络的治理》的演讲。经过整理后&#xff0c;分享给大家。 整理编辑&#xff1a;上海大学…

LiveVideoStack公众号2021年终盘点

在2021年伊始&#xff0c;我们翻译过Tsahi Levent-Levi关于今年WebRTC流行趋势的文章&#xff0c;文中提到2021年将是“还债”的一年&#xff0c;此前所进行的系统设计、软件架构或软件开发都将迎来最终结果&#xff1b;同时它也将是服务及传输质量不断优化的一年。在供给侧长期…