微信公众号开发者原生态的servlet
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 微信公眾號開發者原生態的servlet?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
如果想要成功成為微信公眾號開發者,那么首先就是要服務器與微信公眾號接入
查詢公眾號開發文檔: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數據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結合了開發者填寫的token參數和請求中的timestamp參數、nonce參數。String signature = request.getParameter("signature");// 時間戳String timestamp = request.getParameter("timestamp");// 隨機數String nonce = request.getParameter("nonce");// 隨機字符串String echostr = request.getParameter("echostr");List<String> params = new ArrayList<String>();params.add(Token);params.add(timestamp);params.add(nonce);// 1. 將token、timestamp、nonce三個參數進行字典排序Collections.sort(params, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareTo(o2);}});// 2. 將三個參數拼接成一個字符串進行SHA1進行加密String temp = SHA1Utils.encode(params.get(0) + params.get(1)+ params.get(2));// 3. 加密后的字符串與signature比較,標識該請求是來自微信if (temp.equals(signature)) {// 原樣返回echostr參數內容,則接入成功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);// 把密文轉換成十六進制的字符串形式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);}} }此時如果微信公眾號后臺的URL、秘鑰、token等填寫無誤,用微信公眾號調試接口:https://mp.weixin.qq.com/debug?token=233128916&lang=zh_CN進行測試服務器是否已經接入,會返回json數據狀態為200 OK那么恭喜你已經成功接入開發者模式
二、實現公眾號被動回復消息
可以回復文本、圖片、語音、圖文等等眾多多謀體文件。創建這些文件消息實體。發送與回復消息都是通過Xml格式進行傳輸
創建一個消息實體基類,供它的子類繼承,不論是文本還是圖片都有4個共有的屬性,ToUserName、FromUserName、CreateTime、MsgType,分別是接收方、來自方、會話創建時間、會話類型。
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 {/*** 圖片的臨時文件Id*/private String MediaId;public String getMediaId() {return MediaId;}public void setMediaId(String mediaId) {MediaId = mediaId;}}我還實現了很多的類型,圖文消息實體就不附加上來了
下面就是消息回復所用到的工具類啦,Message消息處理工具類(最重要的工具類)
實現圖片回復的功能,因為圖片不是在微信后臺的,所以必要我們提供的服務器來進行預上傳到公眾號的臨時素材庫中(失效是三天吧)。公眾號的API中提供的接口中要求必須有一個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;/*** 上傳圖片到臨時素材庫類* @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);// 設置請求頭信息con.setRequestProperty("Connection", "Keep-Alive");con.setRequestProperty("Charset", "UTF-8");// 設置邊界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();// 結尾部分byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定義最后數據分隔線out.write(foot);out.flush();out.close();StringBuffer buffer = new StringBuffer();BufferedReader reader = null;String result = null;try {// 定義BufferedReader輸入流來讀取URL的響應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;}}三、實現查詢天氣的功能
根據天氣的接口,來定義查詢出來的天氣實體類。進行查詢天氣并且處理我們場景實用的信息
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";/*** 獲取天氣的結果* @param location 地點* @return 該地點的天氣信息*/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();// 百度天氣返回的內容String result = "";result = HttpUtils.get(url, Constants.CHARSET);// 去解析查詢回來的json字符串String message = handleResult(result);// 如果返回的不是Json那么還需要進行處理....return message;}/*** 處理查詢出來的天氣結果* @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();} }最后編寫我們最核心的大腦系統servlet,編寫JoinChatServlet中doPost()方法,接入公眾號是get請求,粉絲與公眾號之間進行消息回復是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數據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結合了開發者填寫的token參數和請求中的timestamp參數、nonce參數。String signature = request.getParameter("signature");// 時間戳String timestamp = request.getParameter("timestamp");// 隨機數String nonce = request.getParameter("nonce");// 隨機字符串String echostr = request.getParameter("echostr");List<String> params = new ArrayList<String>();params.add(Token);params.add(timestamp);params.add(nonce);// 1. 將token、timestamp、nonce三個參數進行字典排序Collections.sort(params, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareTo(o2);}});// 2. 將三個參數拼接成一個字符串進行SHA1進行加密String temp = SHA1Utils.encode(params.get(0) + params.get(1)+ params.get(2));// 3. 加密后的字符串與signature比較,標識該請求是來自微信if (temp.equals(signature)) {// 原樣返回echostr參數內容,則接入成功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");// 判斷是否是微信接入激活驗證,只有首次接入驗證時才會收到echostr參數,此時需要把它直接返回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;} }當然了還有一個常用類HttpUtils工具類,進行各種接口的調用。但凡遇見Constant.CHARSET全部改成UTF-8就行啦。
總結
以上是生活随笔為你收集整理的微信公众号开发者原生态的servlet的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CIO40知识星球—天道勤酬
- 下一篇: ChatGPT学习研究总结