微信公众号开发学习
1、Readme说明:微信公众号平台开发最好用PHP,但Java也是可以实现的,下面代码用Java语言演示了HttpURLConnection的使用,成为公众号开发者,接收微信公众号信息,响应文本消息,发布菜单,获取用户基本信息等操作。
下面会给出供参考的程序源代码。
2、XStream简单介绍:
(1)XStream可以将Java对象和xml文档之间相互转换,而且可以修改某个特定的属性和节点名称,而且也支持json的转换。
(2)Java到xml,用toXML()方法。
Xml到Java,用fromXML()方法。
(3)在没有任何设置默认情况下,Java到xml的映射,是Java成员名对应xml的元素名,Java类的全名对应xml根元素的名字。而实际中,往往是xml和java类都有了,需要相互转换,必须进行别名映射。
(4)别名配置包括三种情况:
①类别名,用alias(String name,Class type)
②类成员别名,用aliasField(String alias,Class definedIn, String fieldName)
③类成员作为属性别名,用aliasAttribute(Class definedIn, String attributeName, String alias),单独命名没有意义,还要通过useAttributeFor(Class definedIn, String fieldName)应用到某个类上。
3、下面是包及类的关系图:
4、源代码:
(1)action包
****action
********MainAction.java
********TestAction.java
①MainAction.java
package com.remoa.action; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.remoa.common.util.ConfigureUtil; import com.remoa.common.util.MessageUtil; import com.remoa.common.util.SignUtil; import com.remoa.domain.message.TextResponse; import com.remoa.domain.message.WeixinRequest; /** * 处理事务逻辑的主类(验证登录,接收消息及回复消息等) * @author Remoa * */ @WebServlet("/MainAction") public class MainAction extends HttpServlet { private static final long serialVersionUID = 1L; private static final String charset = ConfigureUtil.getValue("charset"); public MainAction() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("MainAction.doGet():start!"); response.setCharacterEncoding(charset); request.setCharacterEncoding(charset); //获取必要的参数,验证服务器地址的有效性 String token = request.getParameter("token");//密码 String signature = request.getParameter("signature");//微信加密签名 String timestamp = request.getParameter("timestamp");//时间戳 String nonce = request.getParameter("nonce");//随机数 String echostr = request.getParameter("echostr");//随机字符串 System.out.println(signature + " " + echostr); //调用登录工具类进行验证 boolean sign = SignUtil.validSign(signature, token, timestamp, nonce); ServletOutputStream outputStream = response.getOutputStream(); //验证成功则返回随机字符串内容,否则验证失败 if(sign){ outputStream.write(echostr.getBytes()); outputStream.flush(); }else{ outputStream.write("验证失败".getBytes()); outputStream.flush(); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("MainAction.doPost():start!"); request.setCharacterEncoding(charset); response.setCharacterEncoding(charset); ServletInputStream inputStream = request.getInputStream();//获取微信请求消息 WeixinRequest xinReq = MessageUtil.fromXmlToWeixinReq(inputStream);//将xml字符串转换为WeixinRequest对象 TextResponse textResponse = new TextResponse(); textResponse.setToUserName(xinReq.getFromUserName());//实现响应的开发者微信号 textResponse.setFromUserName(xinReq.getToUserName());//响应传达的接收方账号 textResponse.setCreateTime(System.currentTimeMillis());//返回系统当前时间 textResponse.setMsgType("text");//响应文本消息 textResponse.setContent("小编已收到您的消息");//回复的消息内容 String respStr = MessageUtil.toXmlFromResp(textResponse); response.getOutputStream().write(respStr.getBytes()); } }
package com.remoa.action; import java.io.IOException; import java.util.Scanner; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 此类用于测试连接成功后接收消息是否成功 * @author Remoa * */ @WebServlet("/TestAction") public class TestAction extends HttpServlet { private static final long serialVersionUID = 1L; public TestAction() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().append("Served at: ").append(request.getContextPath()); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletInputStream inputStream = request.getInputStream(); Scanner scanner = new Scanner(inputStream, "UTF-8"); while(scanner.hasNextLine()){ System.out.println(scanner.nextLine()); } scanner.close(); } }
****common
********util
************ConfigureUtil.java
************HttpUtil.java
************MessageUtil.java
************SignUtil.java
①ConfigureUtil.java
package com.remoa.common.util; import java.io.IOException; import java.io.InputStream; import java.util.Properties; /** * 获取配置信息工具类 * @author Remoa * */ public class ConfigureUtil { private static Properties pro; static{ InputStream is = ConfigureUtil.class.getClassLoader().getResourceAsStream("conf.properties");//通过类加载器返回作为输入流读取配置文件 pro = new Properties(); try { pro.load(is);//从输入流中读取属性列表 is.close(); } catch (IOException e) { e.printStackTrace(); System.out.println("发生了I/O异常错误"); } } /** * 从配置文件中获得属性值 * @param key 键 * @return value 返回键对应的值 */ public static String getValue(String key){ return pro.getProperty(key); } /** * 仅用于测试该配置信息工具类是否能获取到配置文件中的值 * @param args */ public static void main(String[] args){ String value = ConfigureUtil.getValue("charset"); System.out.println(value); } }
②HttpUtil.java
package com.remoa.common.util; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; import sun.net.www.protocol.http.HttpURLConnection; /** * Http连接工具类 * @author Remoa * */ public class HttpUtil { /** * 发送http请求 * @param url 请求地址 * @param method 请求方法 * @param param 请求参数 * @param charset 字符集 * @return 返回请求结果 */ public static String sendHttpReq(String url, String method, String param, String charset){ HttpURLConnection httpURLConnection = null;//生成请求连接到Http服务器 BufferedOutputStream bufferedOutputStream = null;// 缓冲输出流 BufferedReader bufferedReader = null;//读取字符输入流 URL urlObj; try { urlObj = new URL(url); httpURLConnection = (HttpURLConnection)urlObj.openConnection();//连接url所引用的远程对象 } catch (MalformedURLException e) { e.printStackTrace(); System.out.println("出现了使用未知协议错误"); } catch (IOException e) { e.printStackTrace(); System.out.println("出现了I/O异常错误"); } httpURLConnection.setDoInput(true);//读取指定url服务器的资源 if(param != null){ httpURLConnection.setDoOutput(true);//写入数据到指定url服务器 } httpURLConnection.setUseCaches(false);//不允许连接使用缓存 httpURLConnection.setReadTimeout(1000 * 60);//设置读超时,此处设置为1分钟,单位为毫秒 httpURLConnection.setConnectTimeout(1000 * 60);//设置建立连接超时,此处设置为1分钟,单位为毫秒 try { httpURLConnection.setRequestMethod(method); } catch (ProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("无法重置方法或者请求的方法对 HTTP 无效"); }//设置请求方法 try { if(param != null){ bufferedOutputStream = new BufferedOutputStream(httpURLConnection.getOutputStream()); bufferedOutputStream.write(param.getBytes()); bufferedOutputStream.flush(); bufferedOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); System.out.println("缓冲输出流出现了I/O异常错误"); } try { bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), charset)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("读取字符输入流出现了I/O异常错误"); } StringBuilder stringBuilder = new StringBuilder();//提供了与StringBuffer兼容的api,当字符缓冲区被单个线程所使用时,优先使用此类,因为其比StringBuffer要快 String line = null; //读取一个文本行操作 try { if((line = bufferedReader.readLine()) != null){ stringBuilder.append(line).append("\n"); } bufferedReader.close(); } catch (IOException e) { e.printStackTrace(); System.out.println("读取字符输入流出现了I/O异常错误"); } httpURLConnection.disconnect();//指示近期服务器不太可能有其他请求 return stringBuilder.toString(); } /** * 实现关闭流、关闭连接的功能 * @param reader 关闭字符读取流 * @param inputStream 关闭输入流 * @param outputStream 关闭输出流 * @param httpURLConnection 关闭http服务器连接 */ public static void closeAll(Reader reader, InputStream inputStream, OutputStream outputStream, HttpURLConnection httpURLConnection) { //关闭字符流 if(reader != null){ try { reader.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("发生I/O错误"); } } if(inputStream != null){ try { inputStream.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("发生I/O错误"); } } if(outputStream != null){ try { outputStream.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("发生I/O错误"); } } if(httpURLConnection != null){ httpURLConnection.disconnect(); } } /** * 实现上传素材的功能 * @param url 请求地址 * @param filePath 文件路径 * @param charset 字符编码方式 * @return String 表单地址 */ public static String upload(String url, String filePath, String charset) { HttpURLConnection httpURLConnection = null;//生成请求连接到Http服务器 BufferedOutputStream bufferedOutputStream = null;// 缓冲输出流 BufferedReader bufferedReader = null;//读取字符输入流 BufferedInputStream fileInput = null; URL urlObj; try { urlObj = new URL(url); httpURLConnection = (HttpURLConnection)urlObj.openConnection();//连接url所引用的远程对象 } catch (MalformedURLException e) { e.printStackTrace(); System.out.println("出现了使用未知协议错误"); } catch (IOException e) { e.printStackTrace(); System.out.println("出现了I/O异常错误"); } httpURLConnection.setDoInput(true);//允许读取指定url服务器的资源 httpURLConnection.setDoOutput(true);//允许写入数据到指定url服务器 httpURLConnection.setUseCaches(false);//不允许连接使用缓存 httpURLConnection.setReadTimeout(1000 * 60);//设置读超时,此处设置为1分钟,单位为毫秒 httpURLConnection.setConnectTimeout(1000 * 60);//设置建立连接超时,此处设置为1分钟,单位为毫秒 try { httpURLConnection.setRequestMethod("POST");//设置请求方法 } catch (ProtocolException e) { e.printStackTrace(); System.out.println("无法重置方法或者请求的方法对 HTTP 无效"); } String boundary = String.valueOf(System.currentTimeMillis()); httpURLConnection.addRequestProperty("Content-Type", "multipart/form-data:boundary=" + boundary);//设置请求头 StringBuilder headstr = new StringBuilder("----"); headstr.append(boundary).append("\r\n").append("Content-Disposition: form-data; name=\"file\"; filename=\"").append(filePath).append("\"").append("\r\n").append("Content-Type: application/octet-stream\r\n\r\n");//设置附件表单信息 try { bufferedOutputStream = new BufferedOutputStream(httpURLConnection.getOutputStream()); } catch (IOException e) { e.printStackTrace(); System.out.println("创建输出流时发生 I/O 错误"); } try { bufferedOutputStream.write(headstr.toString().getBytes());//写入表单信息 } catch (IOException e) { e.printStackTrace(); System.out.println("写入时发生I/O错误"); } try { bufferedOutputStream.flush(); } catch (IOException e) { e.printStackTrace(); System.out.println("刷新缓冲输出流时发生I/O错误"); } //写入附件 try { fileInput = new BufferedInputStream(new FileInputStream(filePath)); } catch (FileNotFoundException e) { e.printStackTrace(); System.out.println("没有找到文件"); } byte[] bytebuf = new byte[1024]; int len = 0; try { while((len = fileInput.read(bytebuf)) != -1){ bufferedOutputStream.write(bytebuf, 0, len); bufferedOutputStream.write(("\r\n--" + boundary + "--\r\n").getBytes(charset)); bufferedOutputStream.flush(); bufferedOutputStream.close(); fileInput.close(); } } catch (IOException e) { e.printStackTrace(); System.out.println("发生I/O异常"); } try { bufferedOutputStream.write(("\r\n--" + boundary + "--\r\n").getBytes(charset)); } catch (UnsupportedEncodingException e) { e.printStackTrace(); System.out.println("不支持该字符编码"); } catch (IOException e) { e.printStackTrace(); System.out.println("发生I/O异常"); } try { bufferedOutputStream.flush(); bufferedOutputStream.close(); fileInput.close(); } catch (IOException e) { e.printStackTrace(); System.out.println("发生I/O异常"); } StringBuilder stringBuilder = null; try { bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), charset)); String line = null; stringBuilder = new StringBuilder();//提供了与StringBuffer兼容的api,当字符缓冲区被单个线程所使用时,优先使用此类,因为其比StringBuffer要快 while((line = bufferedReader.readLine()) != null){ stringBuilder.append(line).append("\n"); } bufferedReader.close(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); System.out.println("不支持该字符编码"); } catch (IOException e) { e.printStackTrace(); System.out.println("发生I/O异常"); } httpURLConnection.disconnect(); return stringBuilder.toString(); } }
③MessageUtil.java
package com.remoa.common.util; import java.io.InputStream; import java.util.Scanner; import com.remoa.domain.message.TextResponse; import com.remoa.domain.message.WeixinRequest; import com.thoughtworks.xstream.XStream; /** * 消息处理工具类,包括接收消息及发送消息的处理 * @author Remoa * */ public class MessageUtil { public static final String charset = ConfigureUtil.getValue("charset"); /** * 将微信请求接收到的xml字符串转换为Java处理微信消息请求的类WeixinRequest对象 * @param in ServletInputStream输入流 * @return fromXML 返回WeixinRequest对象 */ public static WeixinRequest fromXmlToWeixinReq(InputStream in){ Scanner scan = new Scanner(in, charset);//从指定流中构造一个新的扫描器 StringBuffer str = new StringBuffer(); while(scan.hasNextLine()){ str.append(scan.nextLine()).append("\r\n"); } scan.close(); System.out.println(str.toString()); XStream xStream = new XStream(); xStream.alias("xml", WeixinRequest.class); WeixinRequest fromXML = (WeixinRequest)xStream.fromXML(str.toString()); System.out.println(fromXML); return fromXML; } /** * 将文本消息响应结果转换为xml字符串 * @param textResponse 文本消息响应对象 * @return toxml 返回xml字符串 */ public static String toXmlFromResp(TextResponse textResponse){ XStream xStream = new XStream(); xStream.alias("xml", TextResponse.class); String toXml = xStream.toXML(textResponse); System.out.println(toXml.toString()); return toXml; } }
④SignUtil.java
package com.remoa.common.util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; /** * 登录工具类 * @author Remoa * */ public class SignUtil { //开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带四个参数: /** * 判断登录的有效性 * @param signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 * @param token 密码 * @param timestamp 时间戳 * @param nonce 随机数 * @return boolean 返回判断值true或false */ public static boolean validSign(String signature, String token, String timestamp, String nonce){ String[] paramArr = new String[]{token, timestamp, nonce}; Arrays.sort(paramArr);//Arrays类用来操作数组(比如排序和搜索)的各种方法。sort对数组按数字升序进行排序。 StringBuilder sb = new StringBuilder(paramArr[0]); sb.append(paramArr[1]).append(paramArr[2]); String ciphertext = null; try { MessageDigest md = MessageDigest.getInstance("SHA-1");//为应用程序提供信息摘要算法的功能 byte[] digest = md.digest(sb.toString().getBytes()); ciphertext = byteToStr(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return ciphertext != null ? ciphertext.equals(signature.toUpperCase()) : false; } private static String byteToStr(byte[] byteArray) { String rst = ""; for (int i = 0; i < byteArray.length; i++) { rst += byteToHex(byteArray[i]); } return rst; } private static String byteToHex(byte b) { char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; char[] tempArr = new char[2]; tempArr[0] = Digit[(b >>> 4) & 0X0F]; tempArr[1] = Digit[b & 0X0F]; String s = new String(tempArr); return s; } }
(3)domain包
****domain
********AccessToken
************AccessToken.java
********menu
************Menu.java
************MyButton.java
********message
************BaseMessageResponse.java
************ErrorMessage.java
************ImageResponseMessage.java
************TextResponse.java
************WeixinRequest.java
********user
************UserInfo.java
①AccessToken.java
package com.remoa.domain.AccessToken; /** * 接口调用凭据获取类 * @author Remoa * */ public class AccessToken { private String access_token;//获取到的凭证 private long expires_in;//凭证有效时间(单位:秒) public String getAccess_token() { return access_token; } public void setAccess_token(String access_token) { this.access_token = access_token; } public long getExpires_in() { return expires_in; } public void setExpires_in(long expires_in) { this.expires_in = expires_in; } }
②Menu.java
package com.remoa.domain.menu; import java.util.ArrayList; import java.util.List; import com.alibaba.fastjson.JSON; /** * 菜单实体类 * @author Remoa * */ public class Menu { private List<MyButton> button = new ArrayList<MyButton>(); public List<MyButton> getButton() { return button; } public void setButton(List<MyButton> button) { this.button = button; } public void addButton(MyButton button){ this.getButton().add(button); } public static Menu getDefaultMenu(){ Menu menu = new Menu(); MyButton button1 = new MyButton(); button1.setName("五绝风采"); button1.setType("click"); button1.setKey("Superman"); MyButton button1_1 = new MyButton(); button1_1.setName("黄药师"); button1_1.setType("click"); button1_1.setKey("Doctor Huang"); MyButton button1_2 = new MyButton(); button1_2.setName("欧阳锋"); button1_2.setType("click"); button1_2.setKey("Feng Ouyang"); button1.addSub_button(button1_1); button1.addSub_button(button1_2); MyButton button2 = new MyButton(); button2.setName("百度一下"); button2.setType("view"); button2.setUrl("http://www.baidu.com"); menu.addButton(button1); menu.addButton(button2); return menu; } public static void main(String[] args){ Menu menu = Menu.getDefaultMenu(); System.out.println(JSON.toJSONString(menu, true)); } }
③MyButton.java
package com.remoa.domain.menu; import java.util.ArrayList; import java.util.List; /** * 菜单上的按钮实体类定义 * @author Remoa * */ public class MyButton { private List<MyButton> sub_button = new ArrayList<MyButton>();//二级菜单数组,个数应为1~5个 private String type;//菜单的响应动作类型 private String name;//菜单标题,不超过16个字节,子菜单不超过40个字节 private String key;//菜单KEY值,用于消息接口推送,不超过128字节,click等点击类型必须 private String url;//网页链接,用户点击菜单可打开链接,不超过1024字节,view类型必须 private String media_id;//调用新增永久素材接口返回的合法media_id,media_id类型和view_limited类型必须 public void addSub_button(MyButton button){ this.sub_button.add(button); } public List<MyButton> getSub_button() { return sub_button; } public void setSub_button(List<MyButton> sub_button) { this.sub_button = 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 String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getMedia_id() { return media_id; } public void setMedia_id(String media_id) { this.media_id = media_id; } @Override public String toString() { // TODO Auto-generated method stub return "Button [sub_button=" + sub_button + ",type=" + type + ",name=" + name + "]"; } }
④BaseMessageResponse.java
package com.remoa.domain.message; /** * 回复各类信息其所含参数构成的基础类 * @author Remoa * */ public class BaseMessageResponse { private String ToUserName;//开发者微信号 private String FromUserName;//发送方账号,一个openID private long 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 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.remoa.domain.message; /** * 出现错误时信息类 * @author Remoa * */ public class ErrorMessage { private long errcode;//错误码 private String errmsg;//错误信息 public long getErrcode() { return errcode; } public void setErrcode(long errcode) { this.errcode = errcode; } public String getErrmsg() { return errmsg; } public void setErrmsg(String errmsg) { this.errmsg = errmsg; } }
package com.remoa.domain.message; /** * 回复图片消息 * @author Remoa * */ public class ImageResponseMessage extends BaseMessageResponse{ private Image image = new Image(); public String getMediaId() { return image.getMediaId(); } public void setMediaId(String mediaId) { image.setMediaId(mediaId); } public Image getImage() { return image; } public void setImage(Image image) { this.image = image; } } /** * 图片类 * @author Remoa * */ class Image{ private String MediaId;//图片消息媒体id,可以调用多媒体文件下载接口拉取数据。 public String getMediaId() { return MediaId; } public void setMediaId(String mediaId) { MediaId = mediaId; } }
⑦TextResponse.java
package com.remoa.domain.message; /** * 回复文本消息 * @author Remoa * */ public class TextResponse extends BaseMessageResponse{ private String Content;//文本消息内容 public String getContent() { return Content; } public void setContent(String content) { Content = content; } }
package com.remoa.domain.message; /** * 处理公众号请求类 * @author Remoa * */ public class WeixinRequest { private String ToUserName;//接收方帐号(收到的OpenID) private String FromUserName;//开发者微信号 private long CreateTime;//消息创建时间 (整型) private String MsgType;//消息类型 private String Content;//回复文本消息特有,回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示) //用户未关注时,进行关注后的事件推送的特有参数 private String MsgId;//回复图片消息,通过素材管理接口上传多媒体文件,得到的id。 private String Event;//事件类型,subscribe private String EventKey;//事件KEY值,qrscene_为前缀,后面为二维码的参数值 private String Ticket;//二维码的ticket,可用来换取二维码图片 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(int createTime) { CreateTime = createTime; } public String getMsgType() { return MsgType; } public void setMsgType(String msgType) { MsgType = msgType; } public String getContent() { return Content; } public void setContent(String content) { Content = content; } public String getMsgId() { return MsgId; } public void setMsgId(String msgId) { MsgId = msgId; } public String getEvent() { return Event; } public void setEvent(String event) { Event = event; } public String getEventKey() { return EventKey; } public void setEventKey(String eventKey) { EventKey = eventKey; } public String getTicket() { return Ticket; } public void setTicket(String ticket) { Ticket = ticket; } @Override public String toString() { return "WeiXinReq [ToUserName=" + ToUserName + ", FromUserName=" + FromUserName + ", CreateTime=" + CreateTime + ", MsgType=" + MsgType + ", Content=" + Content + ", MsgId=" + MsgId + ", Event=" + Event + ", EventKey=" + EventKey + ", Ticket=" + Ticket + "]"; } }
⑨UserInfo.java
package com.remoa.domain.user; /* 获取用户基本信息(UnionID机制)在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID * (加密后的微信号,每个用户对每个公众号的OpenID是唯一的。对于不同公众号,同一用户的openid不同)。 * 公众号可通过本接口来根据OpenID获取用户基本信息,包括昵称、头像、性别、所在城市、语言和关注时间。 * @author Remoa * */ public class UserInfo { private int subscribe;//用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。 private String openid;//用户的标识,对当前公众号唯一 private int sex;//用户的性别,值为1时是男性,值为2时是女性,值为0时是未知 private String city;//用户所在城市 private String country;//用户所在国家 private String province;//用户所在省份 private String language;//用户的语言,简体中文为zh_CN private String headimgurl;//用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。 private String subscribe_time;//用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间 private String unionid;//只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。 private String remark;//公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注 private String groupid;//用户所在的分组ID public int getSubscribe() { return subscribe; } public void setSubscribe(int subscribe) { this.subscribe = subscribe; } public String getOpenid() { return openid; } public void setOpenid(String openid) { this.openid = openid; } public int getSex() { return sex; } public void setSex(int sex) { this.sex = sex; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getLanguage() { return language; } public void setLanguage(String language) { this.language = language; } public String getHeadimgurl() { return headimgurl; } public void setHeadimgurl(String headimgurl) { this.headimgurl = headimgurl; } public String getSubscribe_time() { return subscribe_time; } public void setSubscribe_time(String subscribe_time) { this.subscribe_time = subscribe_time; } public String getUnionid() { return unionid; } public void setUnionid(String unionid) { this.unionid = unionid; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public String getGroupid() { return groupid; } public void setGroupid(String groupid) { this.groupid = groupid; } }