微信公众号开发者原生态的servlet
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 微信公眾號開發(fā)者原生態(tài)的servlet?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
如果想要成功成為微信公眾號開發(fā)者,那么首先就是要服務(wù)器與微信公眾號接入
查詢公眾號開發(fā)文檔:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319
值得注意的是上述接入公眾號是servlet的doGet( )請求 ,直接上代碼
編寫JoinChatServlet.java文件的get請求方法:
package com.eastrobot.robotdev.wechat;import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.eastrobot.robotdev.Constants; import com.eastrobot.robotdev.util.HttpUtils; import com.eastrobot.robotdev.wechat.entity.AccessToken; import com.eastrobot.robotdev.wechat.util.SHA1Utils;/*** 接入微信公眾號平臺* * @author han.sun* */ public class JoinChatServlet extends HttpServlet {private static final long serialVersionUID = 1L;private static Logger log = LoggerFactory.getLogger(JoinChatServlet.class);// private static ReceiveXmlUtils receiveXmlUtils;// 微信上填寫的Token數(shù)據(jù)private static String Token = "sunhan";public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding(Constants.CHARSET);response.setCharacterEncoding(Constants.CHARSET);log.debug("GEt請求成功");// 微信加密簽名,signature結(jié)合了開發(fā)者填寫的token參數(shù)和請求中的timestamp參數(shù)、nonce參數(shù)。String signature = request.getParameter("signature");// 時(shí)間戳String timestamp = request.getParameter("timestamp");// 隨機(jī)數(shù)String nonce = request.getParameter("nonce");// 隨機(jī)字符串String echostr = request.getParameter("echostr");List<String> params = new ArrayList<String>();params.add(Token);params.add(timestamp);params.add(nonce);// 1. 將token、timestamp、nonce三個(gè)參數(shù)進(jìn)行字典排序Collections.sort(params, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareTo(o2);}});// 2. 將三個(gè)參數(shù)拼接成一個(gè)字符串進(jìn)行SHA1進(jìn)行加密String temp = SHA1Utils.encode(params.get(0) + params.get(1)+ params.get(2));// 3. 加密后的字符串與signature比較,標(biāo)識該請求是來自微信if (temp.equals(signature)) {// 原樣返回echostr參數(shù)內(nèi)容,則接入成功response.getWriter().write(echostr);log.debug("echostr傳回微信后臺成功...");} else {log.debug("echostr傳回微信后臺失敗...");}} }SHA1Utils.java
package com.eastrobot.robotdev.wechat.util;import java.security.MessageDigest;/*** SHA1算法* @author han.sun**/ public class SHA1Utils {private SHA1Utils() {}private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };public static String getFormattedText(byte[] bytes) {int len = bytes.length;StringBuffer buffer = new StringBuffer(len * 2);// 把密文轉(zhuǎn)換成十六進(jìn)制的字符串形式for (int i = 0; i < bytes.length; i++) {buffer.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);buffer.append(HEX_DIGITS[bytes[i] & 0x0f]);}return buffer.toString();}public static String encode(String str){if (str==null) {return null;}try {MessageDigest messageDigest = MessageDigest.getInstance("SHA1");messageDigest.update(str.getBytes());return getFormattedText(messageDigest.digest());} catch (Exception e) {throw new RuntimeException(e);}} }此時(shí)如果微信公眾號后臺的URL、秘鑰、token等填寫無誤,用微信公眾號調(diào)試接口:https://mp.weixin.qq.com/debug?token=233128916&lang=zh_CN進(jìn)行測試服務(wù)器是否已經(jīng)接入,會返回json數(shù)據(jù)狀態(tài)為200 OK那么恭喜你已經(jīng)成功接入開發(fā)者模式
二、實(shí)現(xiàn)公眾號被動(dòng)回復(fù)消息
可以回復(fù)文本、圖片、語音、圖文等等眾多多謀體文件。創(chuàng)建這些文件消息實(shí)體。發(fā)送與回復(fù)消息都是通過Xml格式進(jìn)行傳輸
創(chuàng)建一個(gè)消息實(shí)體基類,供它的子類繼承,不論是文本還是圖片都有4個(gè)共有的屬性,ToUserName、FromUserName、CreateTime、MsgType,分別是接收方、來自方、會話創(chuàng)建時(shí)間、會話類型。
BaseMessage.java
package com.eastrobot.robotdev.wechat.entity;import java.io.Serializable;import com.thoughtworks.xstream.annotations.XStreamAlias;/*** 請求消息基類* @author han.sun**/ public class BaseMessage implements Serializable{private static final long serialVersionUID = 1L;@XStreamAlias("ToUserName")public String ToUserName;@XStreamAlias("FromUserName")public String FromUserName;@XStreamAlias("CreateTime")public Long CreateTime;@XStreamAlias("MsgType")public 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;}}文本消息類
package com.eastrobot.robotdev.wechat.entity;/*** 文本消息類* @author han.sun**/ public class TextMessage extends BaseMessage {private static final long serialVersionUID = 1L;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.eastrobot.robotdev.wechat.entity;import com.thoughtworks.xstream.annotations.XStreamAlias;/*** 圖片消息類* @author han.sun**/ @XStreamAlias("xml") public class ImageMessage extends BaseMessage {private static final long serialVersionUID = 1L;@XStreamAlias("Image")private Image Image;public Image getImage() {return Image;}public void setImage(Image image) {Image = image;}}ImageMessage的圖片消息類下的子屬性Image類
package com.eastrobot.robotdev.wechat.entity;/*** 圖片消息類的Image* @author han.sun**/ public class Image {/*** 圖片的臨時(shí)文件Id*/private String MediaId;public String getMediaId() {return MediaId;}public void setMediaId(String mediaId) {MediaId = mediaId;}}我還實(shí)現(xiàn)了很多的類型,圖文消息實(shí)體就不附加上來了
下面就是消息回復(fù)所用到的工具類啦,Message消息處理工具類(最重要的工具類)
實(shí)現(xiàn)圖片回復(fù)的功能,因?yàn)閳D片不是在微信后臺的,所以必要我們提供的服務(wù)器來進(jìn)行預(yù)上傳到公眾號的臨時(shí)素材庫中(失效是三天吧)。公眾號的API中提供的接口中要求必須有一個(gè)MediaId,這就是此類的作用
package com.eastrobot.robotdev.wechat.util;import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException;import net.sf.json.JSONObject;import com.eastrobot.robotdev.Constants; import com.eastrobot.robotdev.util.HttpUtils; import com.eastrobot.robotdev.wechat.entity.AccessToken;/*** 上傳圖片到臨時(shí)素材庫類* @author han.sun**/ public class WechatUtils {private static final String APPID = "wx7eea4228e2073fb8";private static final String APPSECRET = "13f608d28a4d2cefedb790fa321766fb";private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";private static final String UPLOAD_URL = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";private WechatUtils(){}/*** doGet形式的HttpClient請求* @param url 接口地址* @return 返回Json對象*/public static JSONObject doGetStr(String url) {JSONObject jsonObject = null;String result = HttpUtils.get(url, Constants.CHARSET);jsonObject = JSONObject.fromObject(result);return jsonObject;}/*** 獲取AccessToken* @return AccessToken* @author han.sun*/public static AccessToken getAccessToken() {AccessToken token = new AccessToken();String url = ACCESS_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET", APPSECRET);JSONObject jsonObject = doGetStr(url);if (jsonObject != null) {token.setToken(jsonObject.getString("access_token"));token.setExpiresIn(jsonObject.getInt("expires_in"));}return token;}/*** 上傳本地文件到微信獲取mediaId* @param filePath 文件路徑* @param accessToken 令牌* @param type 消息類型* @return 返回mediaId*/public static String upload(String filePath, String accessToken, String type)throws IOException, NoSuchAlgorithmException,NoSuchProviderException, KeyManagementException {System.out.println("filePath:" + filePath);File file = new File(filePath);if (!file.exists() || !file.isFile()) {throw new IOException("文件不存在");}String url = UPLOAD_URL.replace("ACCESS_TOKEN", accessToken).replace("TYPE", type);URL urlObj = new URL(url);// 連接HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();con.setRequestMethod("POST");con.setDoInput(true);con.setDoOutput(true);con.setUseCaches(false);// 設(shè)置請求頭信息con.setRequestProperty("Connection", "Keep-Alive");con.setRequestProperty("Charset", "UTF-8");// 設(shè)置邊界String BOUNDARY = "----------" + System.currentTimeMillis();con.setRequestProperty("Content-Type", "multipart/form-data; boundary="+ BOUNDARY);StringBuilder sb = new StringBuilder();sb.append("--");sb.append(BOUNDARY);sb.append("\r\n");sb.append("Content-Disposition: form-data;name=\"file\";filename=\""+ file.getName() + "\"\r\n");sb.append("Content-Type:application/octet-stream\r\n\r\n");byte[] head = sb.toString().getBytes("utf-8");// 獲得輸出流OutputStream out = new DataOutputStream(con.getOutputStream());// 輸出表頭out.write(head);// 文件正文部分// 把文件已流文件的方式 推入到url中DataInputStream in = new DataInputStream(new FileInputStream(file));int bytes = 0;byte[] bufferOut = new byte[1024];while ((bytes = in.read(bufferOut)) != -1) {out.write(bufferOut, 0, bytes);}in.close();// 結(jié)尾部分byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定義最后數(shù)據(jù)分隔線out.write(foot);out.flush();out.close();StringBuffer buffer = new StringBuffer();BufferedReader reader = null;String result = null;try {// 定義BufferedReader輸入流來讀取URL的響應(yīng)reader = new BufferedReader(new InputStreamReader(con.getInputStream()));String line = null;while ((line = reader.readLine()) != null) {buffer.append(line);}if (result == null) {result = buffer.toString();}} catch (IOException e) {e.printStackTrace();} finally {if (reader != null) {reader.close();}}JSONObject jsonObj = JSONObject.fromObject(result);System.out.println(jsonObj);String typeName = "media_id";if (!"image".equals(type)) {typeName = type + "_media_id";}String mediaId = jsonObj.getString(typeName);return mediaId;}}三、實(shí)現(xiàn)查詢天氣的功能
根據(jù)天氣的接口,來定義查詢出來的天氣實(shí)體類。進(jìn)行查詢天氣并且處理我們場景實(shí)用的信息
package com.eastrobot.robotdev.wechat.weather;import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.List;import org.slf4j.Logger; import org.slf4j.LoggerFactory;import com.eastrobot.robotdev.Constants; import com.eastrobot.robotdev.util.HttpUtils; import com.google.gson.Gson;/*** 拼接查詢天氣接口所需的URL,查詢天氣* @author han.sun**/ public class BaiduWeather {public static final Logger log = LoggerFactory.getLogger(BaiduWeather.class);private static final String API = "http://api.map.baidu.com/telematics/v3/weather?";private static final String AK = "81218080E79C9685b35e757566d8cbe5";private static final String OUTPUT = "json";/*** 獲取天氣的結(jié)果* @param location 地點(diǎn)* @return 該地點(diǎn)的天氣信息*/public static String getResult(String location) {try {URLEncoder.encode(location, Constants.CHARSET);} catch (UnsupportedEncodingException e) {e.printStackTrace();}// 拼接urlStringBuffer sb = new StringBuffer();sb.append("location=");sb.append(location);sb.append("&output=");sb.append(OUTPUT);sb.append("&ak=");sb.append(AK);String url = API + sb.toString();// 百度天氣返回的內(nèi)容String result = "";result = HttpUtils.get(url, Constants.CHARSET);// 去解析查詢回來的json字符串String message = handleResult(result);// 如果返回的不是Json那么還需要進(jìn)行處理....return message;}/*** 處理查詢出來的天氣結(jié)果* @param result 原始的Json字符串* @return 真正返回給用戶的字符串*/private static String handleResult(String result){Gson gson = new Gson();Status status = gson.fromJson(result, Status.class);List<Results> list = status.getResults();StringBuffer buffer = new StringBuffer();for (int i = 0; i < list.size(); i++) {Results results = list.get(i);List<Weather> weather_data = results.getWeather_data();for (int j = 0; j < weather_data.size(); j++) {Weather weather = weather_data.get(j);String date = weather.getDate();String weath= weather.getWeather();String temperature = weather.getTemperature();buffer.append(date+" ");buffer.append(weath+" ");buffer.append(temperature+" ");buffer.append("\n");}}return buffer.toString();} }最后編寫我們最核心的大腦系統(tǒng)servlet,編寫JoinChatServlet中doPost()方法,接入公眾號是get請求,粉絲與公眾號之間進(jìn)行消息回復(fù)是Post請求
最終的servlet程序代碼:
package com.eastrobot.robotdev.wechat;import java.io.IOException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Random;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import org.dom4j.DocumentException; import org.slf4j.Logger; import org.slf4j.LoggerFactory;import com.eastrobot.robotdev.Constants; import com.eastrobot.robotdev.util.HttpUtils; import com.eastrobot.robotdev.wechat.entity.AccessToken; import com.eastrobot.robotdev.wechat.util.MessageUtils; import com.eastrobot.robotdev.wechat.util.SHA1Utils; import com.eastrobot.robotdev.wechat.util.WechatUtils;/*** 接入微信公眾號平臺* * @author han.sun* */ public class JoinChatServlet extends HttpServlet {private static final long serialVersionUID = 1L;private static Logger log = LoggerFactory.getLogger(JoinChatServlet.class);// private static ReceiveXmlUtils receiveXmlUtils;// 微信上填寫的Token數(shù)據(jù)private static String Token = "sunhan";public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding(Constants.CHARSET);response.setCharacterEncoding(Constants.CHARSET);log.debug("GEt請求成功");// 微信加密簽名,signature結(jié)合了開發(fā)者填寫的token參數(shù)和請求中的timestamp參數(shù)、nonce參數(shù)。String signature = request.getParameter("signature");// 時(shí)間戳String timestamp = request.getParameter("timestamp");// 隨機(jī)數(shù)String nonce = request.getParameter("nonce");// 隨機(jī)字符串String echostr = request.getParameter("echostr");List<String> params = new ArrayList<String>();params.add(Token);params.add(timestamp);params.add(nonce);// 1. 將token、timestamp、nonce三個(gè)參數(shù)進(jìn)行字典排序Collections.sort(params, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareTo(o2);}});// 2. 將三個(gè)參數(shù)拼接成一個(gè)字符串進(jìn)行SHA1進(jìn)行加密String temp = SHA1Utils.encode(params.get(0) + params.get(1)+ params.get(2));// 3. 加密后的字符串與signature比較,標(biāo)識該請求是來自微信if (temp.equals(signature)) {// 原樣返回echostr參數(shù)內(nèi)容,則接入成功response.getWriter().write(echostr);log.debug("echostr傳回微信后臺成功...");} else {log.debug("echostr傳回微信后臺失敗...");}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding(Constants.CHARSET);response.setCharacterEncoding(Constants.CHARSET);PrintWriter out = response.getWriter();String result = null;Map<String, String> map = null;try {map = MessageUtils.xmlToMap(request);} catch (DocumentException e1) {e1.printStackTrace();}String toUserName = map.get("ToUserName");String fromUserName = map.get("FromUserName");String msgType = map.get("MsgType");String content = map.get("Content");String echostr = request.getParameter("echostr");// 判斷是否是微信接入激活驗(yàn)證,只有首次接入驗(yàn)證時(shí)才會收到echostr參數(shù),此時(shí)需要把它直接返回if (echostr != null && echostr.length() > 1) {result = echostr;} else {// 判斷請求是是否是文本類型 textif (MessageUtils.MESSAGE_TEXT.equals(msgType)) {if ("文藝".equals(content)) {result = imageProcess(toUserName, fromUserName);// String mediaId =// "7u19uWKlh-Nfpm8dAEpkhgxr0u5y0H5hxARQKsqtv3FjcMOV9dtFGxpYU4RvaV4t";// result = MessageUtils.initImageMessage(mediaId,// toUserName,fromUserName);} else if ("圖文".equals(content)) {result = MessageUtils.initArticlesMessage(toUserName,fromUserName);} else {String api = "http://ctr.demo.xiaoi.com/robot/ask.action?";try {URLEncoder.encode(content, Constants.CHARSET);} catch (UnsupportedEncodingException e) {e.printStackTrace();}// 拼接urlStringBuffer bf = new StringBuffer();bf.append("question=");bf.append(content);bf.append("&paltform=weixin");String url = api + bf.toString();String message = HttpUtils.get(url, Constants.CHARSET);message = message.substring(message.indexOf("<Content>") + 9,message.indexOf("</Content>"));result = MessageUtils.initTextMessage(message, toUserName,fromUserName);}}}out.write(result);out.close();}private String imageProcess(String toUserName, String fromUserName) {String message = null;AccessToken token = WechatUtils.getAccessToken();String mediaId = null;Random ran = new Random();int i = ran.nextInt(28);String filePath = "/app/ibot-odin-robot-8005/webapps/robot-dev/image/0" + (i+1) + ".jpg";try {mediaId = WechatUtils.upload(filePath, token.getToken(),MessageUtils.MESSAGE_IMAGE);// mediaId =// "7u19uWKlh-Nfpm8dAEpkhgxr0u5y0H5hxARQKsqtv3FjcMOV9dtFGxpYU4RvaV4t";} catch (Exception e) {e.printStackTrace();}message = MessageUtils.initImageMessage(mediaId, toUserName,fromUserName);return message;} }當(dāng)然了還有一個(gè)常用類HttpUtils工具類,進(jìn)行各種接口的調(diào)用。但凡遇見Constant.CHARSET全部改成UTF-8就行啦。
總結(jié)
以上是生活随笔為你收集整理的微信公众号开发者原生态的servlet的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CIO40知识星球—天道勤酬
- 下一篇: ChatGPT学习研究总结