微信公众号开发学习
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());
}
}
②TestAction.java
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();
}
}
(2)common包
****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;
}
}
⑤ErrorMessage.java
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;
}
}
⑥ImageResponseMessage.java
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;
}
}
⑧WeixinRequest.java
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;
}
}