java微信开发API解析(六)
全局说明
* 详细说明请参考前两篇文章。
本文说明
* 本文主要是对前面学习的知识进行综合整合。
* 我们对需要的bean、工具类、xml、file进行必要的包装。
* 我们构建一个可以直接使用的Java微信应用。
* 文后包含该部分效果的测试微信公众号
* 文后包含构建好的源码供下载
bean的构建
-
public class Access_token,获取Access_token对应的bean。
private String access_token; private String expires_in;
-
public class BaseMsg,所有消息共有成员变量bean。
private String ToUserName; private String FromUserName; private long CreateTime; private String MsgType;
-
public class TextMsg extends BaseMsg,文本消息bean。
private String Content;
-
public class Group,分组所需要的成员变量bean。
private int id; private String name; private int count; private String openid; private String to_groupid; private String groupid;
工具类的构建
- public class AccessTokenUtils,该工具类前文已经详细说明过了,在此处没有改动。
- public class GlobalParamsUtils,该工具类存储了全局常量,包括APPID、SECERT、token等;以及微信服务器响应的消息类型(类型较多,可以直接查看源码,不再此处列出)。
-
public class GroupUtils ,包括对分组的各种操作。除了上一篇文章所说的对用户分组,还有一个保存用户信息的两个工具方法,如下
public class GroupUtils { private static final String TAG = "GroupUtils"; /* * 该方法测试将用户移动到指定分组 */ public static String updateGroup(String openid, String to_groupid) { ... } public static boolean existUser(String openid) { try { BufferedReader dr = new BufferedReader(new InputStreamReader( new FileInputStream(new File("user.txt")))); String line = dr.readLine(); while (line != null) { if (openid.equals(line)) return true; line = dr.readLine(); } dr.close(); return false; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } } public static boolean AddGroup(String openid) { try { File file = new File("user.txt"); if (!file.exists()) file.createNewFile(); BufferedWriter dw = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(file, true))); dw.write(openid); dw.newLine(); dw.flush(); dw.close(); return true; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } } @Test public void Test1() { AddGroup("asdas"); } }
public class MyHttpUtils,关于http的请求的简单封装。
- public class SHAUtils,对sha加密的抽取。
-
public class XmlUtils ,对xml处理的工具抽取,如下
package com.gist.utils; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.junit.Test; import com.gist.bean.TextMsg; import com.thoughtworks.xstream.XStream; /** * @author 高远</n> * 编写日期 2016-4-24下午2:28:07</n> * 邮箱 wgyscsf@163.com</n> * 博客 http://blog.csdn.net/wgyscsf</n> * TODO</n> */ public class XmlUtils { private static final String TAG = "XmlUtils"; /* * 解析用户发送过来的请求。将请求的xml全部封装到map里面 */ public static Map<String, String> handleXmlMsg(InputStream is) { Map<String, String> map = new HashMap<String, String>(); try { SAXReader saxReader=new SAXReader(); Document document = saxReader.read(is); Element root = document.getRootElement(); List<Element> elements = root.elements(); for (Element e : elements) { map.put(e.getName(), e.getText()); } elements = null; root = null; document = null; return map; } catch (DocumentException e) { e.printStackTrace(); } return null; } /** * TODO */ public static String str2Xml(TextMsg textMsg) { XStream xStream=new XStream(); xStream.alias("xml", TextMsg.class); String xmlStr = xStream.toXML(textMsg); return xmlStr; } @Test public void Test() { // 我们封装一个回复文本的信息. TextMsg textMsg = new TextMsg(); textMsg.setFromUserName("from"); textMsg.setToUserName("to"); textMsg.setMsgType(GlobalParamsUtils.MSGTYPE_TEXT); String content = "默认回复消息."; textMsg.setContent(content); textMsg.setCreateTime(System.currentTimeMillis()); System.out.println(str2Xml(textMsg)); } }
servlet的构建以及业务层service的构建
-
public class CoreServlet extends HttpServlet,该方法改动很小,其中的POST请求如下
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 特别注意,req.getInputStream()只能获取一次,并且只能读取一次。如果想要多次读取,需要另外想办法。 // 设置编码 req.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); CoreService coreService = new CoreService(); /* * 获取用户发送过来的消息 */ InputStream is = req.getInputStream(); String reqXml = coreService.handleRequest(is);// 接收处理过之后的xml /* * 给用户回复消息 */ PrintWriter writer = resp.getWriter(); writer.print(reqXml); writer.flush(); }
-
public class CoreService,业务核心类,如下
package com.gist.service; import java.io.InputStream; import java.util.Map; import com.gist.bean.TextMsg; import com.gist.utils.GlobalParamsUtils; import com.gist.utils.GroupUtils; import com.gist.utils.XmlUtils; /** * @author 高远</n> * 编写日期 2016-4-24下午2:10:32</n> * 邮箱 wgyscsf@163.com</n> * 博客 http://blog.csdn.net/wgyscsf</n> * TODO</n> */ public class CoreService { // private static final String TAG = "CoreService"; public String handleRequest(InputStream is) { boolean flag = false;// 设置一个标记,供下面分组用 // 用户发送过来消息是xml格式的。虽然消息类型繁多,但是格式基本固定(参看资料包中的“请求资料.txt”)。我们使用xstram对其进行xml解析。 Map<String, String> handleXmlMsg = XmlUtils.handleXmlMsg(is); /* * 我们查看资料包中的“请求资料.txt”可以发现,所有的请求都包括以下字段 * <ToUserName><![CDATA[toUser]]></ToUserName> * <FromUserName><![CDATA[fromUser]]></FromUserName> * <CreateTime>1348831860</CreateTime> * <MsgType><![CDATA[text]]></MsgType> * 特别的,对于关注和取消关注、自定义菜单,还有一个共有的字段“Event * ”,并且它们的“MsgType”内容全部都是“event”(需要仔细观察 * )。请参考GlobalParamsUtils中关于该部分参数的设置。 */ /* * 第一步,我们先获取所有事件共有的参数 */ String ToUserName = handleXmlMsg.get("ToUserName"); String FromUserName = handleXmlMsg.get("FromUserName"); String CreateTime = handleXmlMsg.get("CreateTime"); String MsgType = handleXmlMsg.get("MsgType"); // 我们封装一个回复文本的信息. TextMsg textMsg = new TextMsg(); textMsg.setFromUserName(ToUserName); textMsg.setToUserName(FromUserName); textMsg.setMsgType(GlobalParamsUtils.MSGTYPE_TEXT); String content = "默认回复消息.wgyscsf"; // 我们在这里测试一下用户自动分组(强制选择) boolean exist = GroupUtils.existUser(FromUserName); if (!exist) { String text = handleXmlMsg.get("Content"); if (text.equals("1")) { content = GroupUtils.updateGroup(FromUserName, "101"); GroupUtils.AddGroup(FromUserName); } else if (text.equals("2")) { content = GroupUtils.updateGroup(FromUserName, "102"); GroupUtils.AddGroup(FromUserName); } else { content = "请先选择分组(选择对应数字)<\n>:1、开发人员;2、普通用户"; } textMsg.setContent(content); textMsg.setCreateTime(System.currentTimeMillis()); String xmlStr = XmlUtils.str2Xml(textMsg); return xmlStr; } /* * 第二步,根据MsgType判断用户的请求类型。两大类:普通消息、事件推送 */ // 推送消息 if (MsgType.equals(GlobalParamsUtils.MSGTYPE_EVENT)) { // 这里面在细节判断是何种推送事件 String EVENT = handleXmlMsg.get("Event"); if (EVENT.equals(GlobalParamsUtils.EVENT_SUBSCRIBE)) { // 用户关注 content = "欢迎您的关注。"; } else if (EVENT.equals(GlobalParamsUtils.EVENT_UNSUBSCRIBE)) { // 取消关注 content = "取消关注。"; } else if (EVENT.equals(GlobalParamsUtils.EVENT_SCAN)) { // 扫描二维码 content = "扫描二维码。"; } else if (EVENT.equals(GlobalParamsUtils.EVENT_LOCATION)) { // 地理位置 content = "地理位置。"; } else if (EVENT.equals(GlobalParamsUtils.EVENT_CLICK)) { // click事件 content = "click事件。"; } else if (EVENT.equals(GlobalParamsUtils.EVENT_VIEW)) { // view事件 content = "view事件。"; } } else { // 普通消息 if (MsgType.equals(GlobalParamsUtils.MSGTYPE_TEXT)) { // 普通文本 content = "普通文本。"; } else if (MsgType.equals(GlobalParamsUtils.MSGTYPE_IMAGE)) { // 图片消息 content = "图片消息。"; } else if (MsgType.equals(GlobalParamsUtils.MSGTYPE_VOICE)) { // 语音消息 content = "语音消息。"; } else if (MsgType.equals(GlobalParamsUtils.MSGTYPE_VIDEO)) { // 视频消息 content = "视频消息。"; } else if (MsgType.equals(GlobalParamsUtils.MSGTYPE_SHORTVIDEO)) { // 小视频消息 content = "小视频消息。"; } else if (MsgType.equals(GlobalParamsUtils.MSGTYPE_LOCATION)) { // 地理位置消息 content = "地理位置消息。"; } else if (MsgType.equals(GlobalParamsUtils.MSGTYPE_LINK)) { // 链接消息 content = "链接消息。"; } } textMsg.setContent(content); textMsg.setCreateTime(System.currentTimeMillis()); String xmlStr = XmlUtils.str2Xml(textMsg); return xmlStr; } }
测试的微信号二维码(包含上述所说的效果)
这是平时写的一些技术文章的微信公众号,欢迎关注: