big update:去除被动消息实体、commons包、dom4j包

This commit is contained in:
jinyu
2015-05-12 23:27:39 +08:00
parent 165f4b3bb8
commit 3d0c3e2c9c
84 changed files with 836 additions and 3287 deletions
@@ -7,7 +7,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
@@ -36,7 +35,9 @@ import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSONException;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.util.ErrorUtil;
import com.foxinmy.weixin4j.util.MapUtil;
import com.foxinmy.weixin4j.util.StringUtil;
import com.thoughtworks.xstream.mapper.CannotResolveClassException;
/**
@@ -237,8 +238,9 @@ public class HttpRequest {
JsonResult jsonResult = response.getAsJsonResult();
response.setJsonResult(true);
if (jsonResult.getCode() != 0) {
if (StringUtils.isBlank(jsonResult.getDesc())) {
jsonResult = response.getTextError(jsonResult.getCode());
if (StringUtil.isBlank(jsonResult.getDesc())) {
jsonResult.setDesc(ErrorUtil.getText(Integer
.toString(jsonResult.getCode())));
}
throw new WeixinException(Integer.toString(jsonResult.getCode()),
jsonResult.getDesc());
@@ -1,14 +1,7 @@
package com.foxinmy.weixin4j.http;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
@@ -67,65 +60,6 @@ public class Response {
return XmlStream.get(text, XmlResult.class);
}
/**
* <a href=
* "http://mp.weixin.qq.com/wiki/17/fa4e1434e57290788bde25603fa2fcbd.html"
* >全局返回码</a> {"errcode":45009,"errmsg":"api freq out of limit"}
*
* @return
* @throws DocumentException
*/
public JsonResult getTextError(int code) {
JsonResult result = new JsonResult();
result.setCode(code);
SAXReader reader = new SAXReader();
Document doc = null;
InputStream is = null;
try {
is = Response.class.getResourceAsStream("error.xml");
doc = reader.read(is);
Node node = doc.getRootElement().selectSingleNode(
String.format("error/code[text()=%d]", code));
if (node != null) {
node = node.getParent();
String desc = null;
Node _node = node.selectSingleNode("desc");
if (_node != null) {
desc = _node.getStringValue();
}
String text = null;
_node = node.selectSingleNode("text");
if (_node != null) {
text = _node.getStringValue();
}
if (StringUtils.isBlank(desc) && StringUtils.isNotBlank(text)) {
desc = text;
}
if (StringUtils.isBlank(text) && StringUtils.isNotBlank(desc)) {
text = desc;
}
result.setDesc(desc);
result.setText(text);
} else {
result.setDesc("unknown error");
result.setText("未知错误");
}
} catch (DocumentException e) {
result.setDesc("unknown error");
result.setText("未知错误");
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
;
}
}
}
return result;
}
public void setText(String text) {
this.text = text;
}
@@ -2,9 +2,8 @@ package com.foxinmy.weixin4j.http;
import java.io.Serializable;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.util.StringUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
@@ -53,7 +52,7 @@ public class XmlResult implements Serializable {
}
public String getReturnMsg() {
return StringUtils.isNotBlank(returnMsg) ? returnMsg : null;
return StringUtil.isNotBlank(returnMsg) ? returnMsg : null;
}
public void setReturnMsg(String returnMsg) {
@@ -77,7 +76,7 @@ public class XmlResult implements Serializable {
}
public String getErrCodeDes() {
return StringUtils.isNotBlank(errCodeDes) ? errCodeDes : null;
return StringUtil.isNotBlank(errCodeDes) ? errCodeDes : null;
}
public void setErrCodeDes(String errCodeDes) {
@@ -1,140 +0,0 @@
package com.foxinmy.weixin4j.message;
import java.io.Serializable;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 消息基类
*
* @className BaseMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
*/
public class BaseMessage implements Serializable {
private static final long serialVersionUID = 7761192742840031607L;
/**
* 开发者微信号
*/
@XStreamAlias("ToUserName")
private String toUserName;
/**
* 发送方账号 即用户的openid
*/
@XStreamAlias("FromUserName")
private String fromUserName;
/**
* 消息创建时间 系统毫秒数
*/
@XStreamAlias("CreateTime")
private long createTime = System.currentTimeMillis();
/**
* 消息类型
*
* @see com.foxinmy.weixin4j.type.MessageType
*/
@XStreamAlias("MsgType")
private String msgType;
/**
* 消息ID 可用于排重
*/
@XStreamAlias("MsgId")
private long msgId;
/**
* 企业号独有的应用ID
*/
@XStreamAlias("AgentID")
private String agentId;
public BaseMessage() {
}
public BaseMessage(String msgType) {
this.msgType = msgType;
}
public BaseMessage(String toUserName, String fromUserName) {
this(null, toUserName, fromUserName);
}
public BaseMessage(String msgType, String toUserName, String fromUserName) {
this.msgType = msgType;
this.toUserName = toUserName;
this.fromUserName = fromUserName;
}
public String getToUserName() {
return toUserName;
}
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
public String getFromUserName() {
return fromUserName;
}
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}
public long getCreateTime() {
return createTime;
}
public void setCreateTime(long createTime) {
this.createTime = createTime;
}
public String getMsgType() {
return msgType;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
public long getMsgId() {
return msgId;
}
public String getAgentId() {
return agentId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((agentId == null) ? 0 : agentId.hashCode());
result = prime * result + (int) (createTime ^ (createTime >>> 32));
result = prime * result
+ ((fromUserName == null) ? 0 : fromUserName.hashCode());
result = prime * result + (int) (msgId ^ (msgId >>> 32));
result = prime * result + ((msgType == null) ? 0 : msgType.hashCode());
result = prime * result
+ ((toUserName == null) ? 0 : toUserName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof BaseMessage) {
return ((BaseMessage) obj).getMsgId() == msgId
&& ((BaseMessage) obj).getCreateTime() == createTime;
}
return false;
}
@Override
public String toString() {
return "toUserName=" + toUserName + ", fromUserName=" + fromUserName
+ ", createTime=" + createTime + ", msgType=" + msgType
+ ", msgId=" + msgId + ", agentId=" + agentId;
}
}
@@ -1,50 +0,0 @@
package com.foxinmy.weixin4j.message;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 图片消息
*
* @className ImageMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html#.E5.9B.BE.E7.89.87.E6.B6.88.E6.81.AF">订阅号、服务号的图片消息</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#image.E6.B6.88.E6.81.AF">企业号的图片消息</a>
*/
public class ImageMessage extends BaseMessage {
private static final long serialVersionUID = 8430800898756567016L;
public ImageMessage() {
super(MessageType.image.name());
}
/**
* 图片链接
*/
@XStreamAlias("PicUrl")
private String picUrl;
/**
* 图片消息媒体id,可以调用多媒体文件下载接口拉取数据。
*/
@XStreamAlias("MediaId")
private String mediaId;
public String getPicUrl() {
return picUrl;
}
public String getMediaId() {
return mediaId;
}
@Override
public String toString() {
return "ImageMessage [picUrl=" + picUrl + ", mediaId=" + mediaId + ", "
+ super.toString() + "]";
}
}
@@ -1,57 +0,0 @@
package com.foxinmy.weixin4j.message;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 链接消息
*
* @className LinkMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html#.E9.93.BE.E6.8E.A5.E6.B6.88.E6.81.AF">订阅号、服务号的链接消息</a>
*/
public class LinkMessage extends BaseMessage {
private static final long serialVersionUID = 754952745115497030L;
public LinkMessage() {
super(MessageType.link.name());
}
/**
* 消息标题
*/
@XStreamAlias("Title")
private String title;
/**
* 消息描述
*/
@XStreamAlias("Description")
private String description;
/**
* 消息链接
*/
@XStreamAlias("Url")
private String url;
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
public String getUrl() {
return url;
}
@Override
public String toString() {
return "LinkMessage [title=" + title + ", description=" + description
+ ", url=" + url + ", " + super.toString() + "]";
}
}
@@ -1,68 +0,0 @@
package com.foxinmy.weixin4j.message;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 地理位置消息
*
* @className LocationMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html#.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E6.B6.88.E6.81.AF">订阅号、服务号的地理位置消息</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#location.E6.B6.88.E6.81.AF">企业号的地理位置消息</a>
*/
public class LocationMessage extends BaseMessage {
private static final long serialVersionUID = 2866021596599237334L;
public LocationMessage() {
super(MessageType.location.name());
}
/**
* 地理位置维度
*/
@XStreamAlias("Location_X")
private double x;
/**
* 地理位置经度
*/
@XStreamAlias("Location_Y")
private double y;
/**
* 地图缩放大小
*/
@XStreamAlias("Scale")
private double scale;
/**
* 地理位置信息
*/
@XStreamAlias("Label")
private String label;
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getScale() {
return scale;
}
public String getLabel() {
return label;
}
@Override
public String toString() {
return "LocationMessage [x=" + x + ", y=" + y + ", scale=" + scale
+ ", label=" + label + ", " + super.toString() + "]";
}
}
@@ -1,10 +0,0 @@
普通消息
-------
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次
关于重试的消息排重,推荐使用msgid排重。
假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。
@@ -1,41 +0,0 @@
package com.foxinmy.weixin4j.message;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 文本消息
*
* @className TextMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html#.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">订阅号、服务号的文本消息</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#text.E6.B6.88.E6.81.AF">企业号的文本消息</a>
*/
public class TextMessage extends BaseMessage {
private static final long serialVersionUID = -7018053906644190260L;
public TextMessage() {
super(MessageType.text.name());
}
/**
* 消息内容
*/
@XStreamAlias("Content")
private String content;
public String getContent() {
return content;
}
@Override
public String toString() {
return "TextMessage [content=" + content + ", " + super.toString()
+ "]";
}
}
@@ -1,50 +0,0 @@
package com.foxinmy.weixin4j.message;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 视频消息
*
* @className VideoMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html#.E8.A7.86.E9.A2.91.E6.B6.88.E6.81.AF">订阅号、服务号的视频消息</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#video.E6.B6.88.E6.81.AF">企业号的视频消息</a>
*/
public class VideoMessage extends BaseMessage {
private static final long serialVersionUID = -1013075358679078381L;
public VideoMessage() {
super(MessageType.video.name());
}
/**
* 视频消息媒体id,可以调用多媒体文件下载接口拉取数据。
*/
@XStreamAlias("MediaId")
private String mediaId;
/**
* 视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
*/
@XStreamAlias("ThumbMediaId")
private String thumbMediaId;
public String getMediaId() {
return mediaId;
}
public String getThumbMediaId() {
return thumbMediaId;
}
@Override
public String toString() {
return "VideoMessage [mediaId=" + mediaId + ", thumbMediaId="
+ thumbMediaId + ", " + super.toString() + "]";
}
}
@@ -1,63 +0,0 @@
package com.foxinmy.weixin4j.message;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 语音消息
* <p>
* 开通语音识别功能,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,赋值到Recongnition字段.
* </p>
*
* @className VoiceMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/10/79502792eef98d6e0c6e1739da387346.html#.E8.AF.AD.E9.9F.B3.E6.B6.88.E6.81.AF">订阅号、服务号的语音消息</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#voice.E6.B6.88.E6.81.AF">企业号的语音消息</a>
*/
public class VoiceMessage extends BaseMessage {
private static final long serialVersionUID = -7988380977182214003L;
public VoiceMessage() {
super(MessageType.voice.name());
}
/**
* 语音消息媒体id,可以调用多媒体文件下载接口拉取数据。
*/
@XStreamAlias("MediaId")
private String mediaId;
/**
* 语音格式,如amrspeex等
*/
@XStreamAlias("Format")
private String format;
/**
* 语音识别结果,UTF8编码
*/
@XStreamAlias("Recognition")
private String recognition;
public String getRecognition() {
return recognition;
}
public String getMediaId() {
return mediaId;
}
public String getFormat() {
return format;
}
@Override
public String toString() {
return "VoiceMessage [mediaId=" + mediaId + ", format=" + format
+ ", recognition=" + recognition + ", " + super.toString()
+ "]";
}
}
@@ -1,44 +0,0 @@
package com.foxinmy.weixin4j.message.event;
import com.foxinmy.weixin4j.message.BaseMessage;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 事件消息基类
*
* @className EventMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/9/981d772286d10d153a3dc4286c1ee5b5.html">订阅号、服务号的事件推送</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6">企业号的事件消息</a>
*/
public class EventMessage extends BaseMessage {
private static final long serialVersionUID = 7703667223814088865L;
public EventMessage(String eventType) {
super(MessageType.event.name());
this.eventType = eventType;
}
/**
* 事件类型
*
* @see com.foxinmy.weixin4j.type.EventType
*/
@XStreamAlias("Event")
private String eventType;
public String getEventType() {
return eventType;
}
@Override
public String toString() {
return "eventType=" + eventType + ", " + super.toString();
}
}
@@ -1,59 +0,0 @@
package com.foxinmy.weixin4j.message.event;
import com.foxinmy.weixin4j.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 上报地理位置事件
*
* @className LocationEventMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/2/5baf56ce4947d35003b86a9805634b1e.html#.E4.B8.8A.E6.8A.A5.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E4.BA.8B.E4.BB.B6">订阅号、服务号的上报地理位置事件</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E4.B8.8A.E6.8A.A5.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E4.BA.8B.E4.BB.B6">企业号的上报地理位置事件</a>
*/
public class LocationEventMessage extends EventMessage {
private static final long serialVersionUID = -2030716800669824861L;
public LocationEventMessage() {
super(EventType.location.name());
}
/**
* 地理位置纬度
*/
@XStreamAlias("Latitude")
private String latitude;
/**
* 地理位置经度
*/
@XStreamAlias("Longitude")
private String longitude;
/**
* 地理位置精度
*/
@XStreamAlias("Precision")
private String precision;
public String getLatitude() {
return latitude;
}
public String getLongitude() {
return longitude;
}
public String getPrecision() {
return precision;
}
@Override
public String toString() {
return "LocationEventMessage [latitude=" + latitude + ", longitude="
+ longitude + ", precision=" + precision + ", "
+ super.toString() + "]";
}
}
@@ -1,45 +0,0 @@
package com.foxinmy.weixin4j.message.event;
import com.foxinmy.weixin4j.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 自定义菜单事件(view|click)
*
* @className MenuEventMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/9/981d772286d10d153a3dc4286c1ee5b5.html#.E7.82.B9.E5.87.BB.E8.8F.9C.E5.8D.95.E6.8B.89.E5.8F.96.E6.B6.88.E6.81.AF.E6.97.B6.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">订阅号、服务号的菜单事件</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E4.B8.8A.E6.8A.A5.E8.8F.9C.E5.8D.95.E4.BA.8B.E4.BB.B6">企业号的菜单事件</a>
*/
public class MenuEventMessage extends EventMessage {
private static final long serialVersionUID = -1049672447995366063L;
public MenuEventMessage() {
super(EventType.click.name());
}
public MenuEventMessage(EventType eventType) {
super(eventType.name());
}
/**
* 事件KEY值,与自定义菜单接口中KEY值对应
*/
@XStreamAlias("EventKey")
private String eventKey;
public String getEventKey() {
return eventKey;
}
@Override
public String toString() {
return "MenuEventMessage [eventKey=" + eventKey + ", "
+ super.toString() + "]";
}
}
@@ -1,108 +0,0 @@
package com.foxinmy.weixin4j.message.event;
import java.io.Serializable;
import com.foxinmy.weixin4j.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 弹出地理位置选择器的事件推送
*
* @className MenuLocationEventMessage
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/9/981d772286d10d153a3dc4286c1ee5b5.html#location_select.EF.BC.9A.E5.BC.B9.E5.87.BA.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E9.80.89.E6.8B.A9.E5.99.A8.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">订阅号、服务号的弹出地理位置选择事件推送</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E5.BC.B9.E5.87.BA.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E9.80.89.E6.8B.A9.E5.99.A8.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">企业号的弹出地理位置选择事件推送</a>
*/
public class MenuLocationEventMessage extends MenuEventMessage {
private static final long serialVersionUID = 145223888272819563L;
public MenuLocationEventMessage() {
super(EventType.location_select);
}
/**
* 发送的位置消息
*/
@XStreamAlias("SendLocationInfo")
private LocationInfo locationInfo;
public LocationInfo getLocationInfo() {
return locationInfo;
}
/**
* 地理位置信息
* @className LocationInfo
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
public static class LocationInfo implements Serializable {
private static final long serialVersionUID = 4904181780216819965L;
/**
* 地理位置维度
*/
@XStreamAlias("Location_X")
private double x;
/**
* 地理位置经度
*/
@XStreamAlias("Location_Y")
private double y;
/**
* 地图缩放大小
*/
@XStreamAlias("Scale")
private double scale;
/**
* 地理位置信息
*/
@XStreamAlias("Label")
private String label;
/**
* 朋友圈POI的名字,可能为空
*/
@XStreamAlias("Poiname")
private String poiname;
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getScale() {
return scale;
}
public String getLabel() {
return label;
}
public String getPoiname() {
return poiname;
}
@Override
public String toString() {
return "LocationInfo [x=" + x + ", y=" + y + ", scale=" + scale
+ ", label=" + label + ", poiname=" + poiname + "]";
}
}
@Override
public String toString() {
return "MenuLocationEventMessage [locationInfo=" + locationInfo + ", "
+ super.toString() + "]";
}
}
@@ -1,103 +0,0 @@
package com.foxinmy.weixin4j.message.event;
import java.io.Serializable;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 弹出拍照或者相册发图的事件推送(pic_sysphoto|pic_photo_or_album|pic_weixin)
*
* @className MenuPhotoEventMessage
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/9/981d772286d10d153a3dc4286c1ee5b5.html#pic_sysphoto.EF.BC.9A.E5.BC.B9.E5.87.BA.E7.B3.BB.E7.BB.9F.E6.8B.8D.E7.85.A7.E5.8F.91.E5.9B.BE.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">订阅号、服务号的系统发图的事件推送</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E5.BC.B9.E5.87.BA.E7.B3.BB.E7.BB.9F.E6.8B.8D.E7.85.A7.E5.8F.91.E5.9B.BE.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">企业号的系统发图的事件推送</a>
*/
public class MenuPhotoEventMessage extends MenuEventMessage {
private static final long serialVersionUID = 3142350663022709730L;
/**
* 发送的图片信息
*/
@XStreamAlias("SendPicsInfo")
private PictureInfo pictureInfo;
public PictureInfo getPictureInfo() {
return pictureInfo;
}
/**
* 图片信息
*
* @className PictureInfo
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
public static class PictureInfo implements Serializable {
private static final long serialVersionUID = -3361375879168233258L;
/**
* 发送的图片数量
*/
@XStreamAlias("Count")
private int count;
/**
* 图片列表
*/
@XStreamAlias("PicList")
private List<PictureItem> items;
public int getCount() {
return count;
}
public List<PictureItem> getItems() {
return items;
}
@Override
public String toString() {
return "PictureInfo [count=" + count + ", items=" + items + "]";
}
}
/**
* 图片
*
* @className PictureItem
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
@XStreamAlias("item")
public static class PictureItem implements Serializable {
private static final long serialVersionUID = -7636697449096645590L;
/**
* 图片的MD5值,开发者若需要,可用于验证接收到图片
*/
@XStreamAlias("PicMd5Sum")
private String md5;
@Override
public String toString() {
return "PictureItem [md5=" + md5 + "]";
}
}
@Override
public String toString() {
return "MenuPhotoEventMessage [pictureInfo=" + pictureInfo + ", "
+ super.toString() + "]";
}
}
@@ -1,75 +0,0 @@
package com.foxinmy.weixin4j.message.event;
import java.io.Serializable;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 扫码推事件(scancode_push|scancode_waitmsg)
*
* @className MenuScanEventMessage
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/9/981d772286d10d153a3dc4286c1ee5b5.html#scancode_push.EF.BC.9A.E6.89.AB.E7.A0.81.E6.8E.A8.E4.BA.8B.E4.BB.B6.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">订阅号、服务号的扫码推事件</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E6.89.AB.E7.A0.81.E6.8E.A8.E4.BA.8B.E4.BB.B6.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">企业号的的扫码推事件</a>
*/
public class MenuScanEventMessage extends MenuEventMessage {
private static final long serialVersionUID = 3142350663022709730L;
/**
* 扫描信息
*/
@XStreamAlias("ScanCodeInfo")
private ScanInfo scanInfo;
public ScanInfo getScanInfo() {
return scanInfo;
}
/**
* 扫描信息
*
* @className ScanInfo
* @author jy
* @date 2015年3月29日
* @since JDK 1.7
* @see
*/
public static class ScanInfo implements Serializable {
private static final long serialVersionUID = 2237570238164900421L;
/**
* 扫描类型,一般是qrcode
*/
@XStreamAlias("ScanType")
private String type;
/**
* 扫描结果,即二维码对应的字符串信息
*/
@XStreamAlias("ScanResult")
private String result;
public String getType() {
return type;
}
public String getResult() {
return result;
}
@Override
public String toString() {
return "ScanInfo [type=" + type + ", result=" + result + "]";
}
}
@Override
public String toString() {
return "MenuScanEventMessage [scanInfo=" + scanInfo + ", "
+ super.toString() + "]";
}
}
@@ -1,3 +0,0 @@
菜单事件消息
用户点击自定义菜单后,微信会把点击事件推送给开发者,请注意,点击菜单弹出子菜单,不会产生上报。请注意,第3个到第8个的所有事件,仅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。
@@ -22,6 +22,9 @@ public final class Consts {
public static final String TLS = "TLS";
public static final String X509 = "X.509";
public static final String AES = "AES";
public static final String MD5 = "MD5";
public static final String SHA = "SHA";
public static final String SHA1 = "SHA-1";
public static final String PROTOCOL_FILE = "file";
public static final String PROTOCOL_JAR = "jar";
@@ -1,7 +1,5 @@
package com.foxinmy.weixin4j.token;
import org.apache.commons.lang3.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@@ -9,6 +7,7 @@ import redis.clients.jedis.exceptions.JedisException;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.util.StringUtil;
/**
* 用REDIS保存TOKEN
@@ -64,7 +63,7 @@ public class RedisTokenHolder implements TokenHolder {
jedis = jedisPool.getResource();
String cacheKey = tokenCreator.getCacheKey();
String accessToken = jedis.get(cacheKey);
if (StringUtils.isBlank(accessToken)) {
if (StringUtil.isBlank(accessToken)) {
token = tokenCreator.createToken();
jedis.setex(cacheKey, (int) token.getExpiresIn(),
token.getAccessToken());
@@ -1,77 +0,0 @@
package com.foxinmy.weixin4j.type;
/**
* 事件类型
*
* @className EventType
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see
*/
public enum EventType {
/**
* 关注事件
*
*/
subscribe,
/**
* 取消关注事件
*
*/
unsubscribe,
/**
* 上报地理位置事件
*
* @see com.foxinmy.weixin4j.msg.event.LocationEventMessage
*/
location,
/**
* 菜单扫描事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage
*/
scancode_push,
/**
* 菜单点击关键字事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage
*/
view,
/**
* 菜单点击链接事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage
*/
click,
/**
* 菜单扫描并调出等待界面事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage
*/
scancode_waitmsg,
/**
* 菜单弹出拍照事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage
*/
pic_sysphoto,
/**
* 菜单弹出发图事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage
*/
pic_photo_or_album,
/**
* 菜单弹出发图事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage
*/
pic_weixin,
/**
* 菜单发送地理位置事件
*
* @see com.foxinmy.weixin4j.msg.event.menu.MenuLocationEventMessage
*/
location_select;
}
@@ -8,7 +8,7 @@ import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.model.WeixinAccount;
/**
* 商户配置工具类
* 公众号配置
*
* @className ConfigUtil
* @author jy
@@ -0,0 +1,62 @@
package com.foxinmy.weixin4j.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import com.foxinmy.weixin4j.model.Consts;
/**
* 签名工具类
*
* @className DigestUtil
* @author jy
* @date 2015年5月6日
* @since JDK 1.7
* @see
*/
public final class DigestUtil {
private static MessageDigest getDigest(final String algorithm) {
try {
return MessageDigest.getInstance(algorithm);
} catch (final NoSuchAlgorithmException e) {
throw new IllegalArgumentException(e);
}
}
/**
* SHA1签名
*
* @param content
* 待签名字符串
* @return 签名后的字符串
*/
public static String SHA1(String content) {
byte[] data = StringUtil.getBytesUtf8(content);
return HexUtil.encodeHexString(getDigest(Consts.SHA1).digest(data));
}
/**
* SHA签名
*
* @param content
* 待签名字符串
* @return 签名后的字符串
*/
public static String SHA(String content) {
byte[] data = StringUtil.getBytesUtf8(content);
return HexUtil.encodeHexString(getDigest(Consts.SHA).digest(data));
}
/**
* MD5签名
*
* @param content
* 待签名字符串
* @return 签名后的字符串
*/
public static String MD5(String content) {
byte[] data = StringUtil.getBytesUtf8(content);
return HexUtil.encodeHexString(getDigest(Consts.MD5).digest(data));
}
}
@@ -0,0 +1,107 @@
package com.foxinmy.weixin4j.util;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
import com.foxinmy.weixin4j.http.Response;
/**
* 接口调用错误获取
*
* @className ErrorUtil
* @author jy
* @date 2015年5月12日
* @since JDK 1.7
* @see
*/
public final class ErrorUtil {
private static byte[] errorXmlByteArray;
private final static Map<String, String> errorCacheMap;
static {
errorCacheMap = new HashMap<String, String>();
try {
errorXmlByteArray = IOUtil.toByteArray(Response.class
.getResourceAsStream("error.xml"));
} catch (IOException e) {
;
}
}
private static class ErrorTextHandler extends DefaultHandler {
private final String code;
public ErrorTextHandler(String code) {
this.code = code;
}
private String text;
private boolean codeElement;
private boolean textElement;
private boolean findElement;
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
codeElement = qName.equalsIgnoreCase("code");
textElement = qName.equalsIgnoreCase("text");
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
String _text = new String(ch, start, length);
if (codeElement && _text.equalsIgnoreCase(code)) {
findElement = true;
} else if (textElement && findElement) {
text = _text;
throw new SAXException("ENOUGH");
}
}
public String getText() {
return StringUtil.isBlank(text) ? "未知错误" : text;
}
}
public static String getText(String code) throws RuntimeException {
String text = errorCacheMap.get(code);
if (StringUtil.isBlank(text)) {
ErrorTextHandler textHandler = new ErrorTextHandler(code);
try {
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.setContentHandler(textHandler);
xmlReader.parse(new InputSource(new ByteArrayInputStream(
errorXmlByteArray)));
text = textHandler.getText();
errorCacheMap.put(code, text);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (SAXException e) {
text = textHandler.getText();
errorCacheMap.put(code, text);
}
}
return text;
}
public static void main(String[] args) {
System.out.println(getText("40001"));
System.out.println(getText("40001"));
System.out.println(getText("1234"));
}
}
@@ -0,0 +1,34 @@
package com.foxinmy.weixin4j.util;
public final class HexUtil {
/**
* Used to build output as Hex
*/
private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
/**
* Used to build output as Hex
*/
private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
private static char[] encodeHex(final byte[] data, final char[] toDigits) {
final int l = data.length;
final char[] out = new char[l << 1];
// two characters form the hex value.
for (int i = 0, j = 0; i < l; i++) {
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
out[j++] = toDigits[0x0F & data[i]];
}
return out;
}
public static String encodeHexString(final byte[] data) {
return new String(encodeHex(data, true));
}
public static char[] encodeHex(final byte[] data, final boolean toLowerCase) {
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
}
@@ -7,7 +7,6 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import com.alibaba.fastjson.JSON;
@@ -65,7 +64,7 @@ public class MapUtil {
try {
if (encoder && lowerCase) {
for (Map.Entry<String, String> entry : set) {
if (StringUtils.isBlank(entry.getValue())) {
if (StringUtil.isBlank(entry.getValue())) {
continue;
}
sb.append(entry.getKey().toLowerCase())
@@ -75,7 +74,7 @@ public class MapUtil {
}
} else if (encoder) {
for (Map.Entry<String, String> entry : set) {
if (StringUtils.isBlank(entry.getValue())) {
if (StringUtil.isBlank(entry.getValue())) {
continue;
}
sb.append(entry.getKey())
@@ -85,7 +84,7 @@ public class MapUtil {
}
} else if (lowerCase) {
for (Map.Entry<String, String> entry : set) {
if (StringUtils.isBlank(entry.getValue())) {
if (StringUtil.isBlank(entry.getValue())) {
continue;
}
sb.append(entry.getKey().toLowerCase()).append("=")
@@ -93,7 +92,7 @@ public class MapUtil {
}
} else {
for (Map.Entry<String, String> entry : set) {
if (StringUtils.isBlank(entry.getValue())) {
if (StringUtil.isBlank(entry.getValue())) {
continue;
}
sb.append(entry.getKey()).append("=")
@@ -1,158 +0,0 @@
package com.foxinmy.weixin4j.util;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Consts;
/**
* 消息工具类
*
* @className MessageUtil
* @author jy
* @date 2014年10月31日
* @since JDK 1.7
* @see
*/
public class MessageUtil {
/**
* 验证微信签名
*
* @param signature
* 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数
* @return 开发者通过检验signature对请求进行相关校验。若确认此次GET请求来自微信服务器
* 请原样返回echostr参数内容,则接入生效 成为开发者成功,否则接入失败
* @see <a
* href="http://mp.weixin.qq.com/wiki/0/61c3a8b9d50ac74f18bdf2e54ddfc4e0.html">接入指南</a>
*/
public static String signature(String... para) {
Arrays.sort(para);
StringBuilder sb = new StringBuilder();
for (String str : para) {
sb.append(str);
}
return DigestUtils.sha1Hex(sb.toString());
}
/**
* 对xml消息加密
*
* @param appId 应用ID
* @param encodingAesKey
* 加密密钥
* @param xmlContent
* 原始消息体
* @return aes加密后的消息体
* @throws WeixinException
*/
public static String aesEncrypt(String appId, String encodingAesKey,
String xmlContent) throws WeixinException {
byte[] randomBytes = RandomUtil.generateString(16).getBytes(
org.apache.http.Consts.UTF_8);
byte[] xmlBytes = xmlContent.getBytes(org.apache.http.Consts.UTF_8);
int xmlLength = xmlBytes.length;
byte[] orderBytes = new byte[4];
orderBytes[3] = (byte) (xmlLength & 0xFF);
orderBytes[2] = (byte) (xmlLength >> 8 & 0xFF);
orderBytes[1] = (byte) (xmlLength >> 16 & 0xFF);
orderBytes[0] = (byte) (xmlLength >> 24 & 0xFF);
byte[] appidBytes = appId.getBytes(org.apache.http.Consts.UTF_8);
int byteLength = randomBytes.length + xmlLength + orderBytes.length
+ appidBytes.length;
// ... + pad: 使用自定义的填充方式对明文进行补位填充
byte[] padBytes = PKCS7Encoder.encode(byteLength);
// random + endian + xml + appid + pad 获得最终的字节流
byte[] unencrypted = new byte[byteLength + padBytes.length];
byteLength = 0;
// src:源数组;srcPos:源数组要复制的起始位置;dest:目的数组;destPos:目的数组放置的起始位置;length:复制的长度
System.arraycopy(randomBytes, 0, unencrypted, byteLength,
randomBytes.length);
byteLength += randomBytes.length;
System.arraycopy(orderBytes, 0, unencrypted, byteLength,
orderBytes.length);
byteLength += orderBytes.length;
System.arraycopy(xmlBytes, 0, unencrypted, byteLength, xmlBytes.length);
byteLength += xmlBytes.length;
System.arraycopy(appidBytes, 0, unencrypted, byteLength,
appidBytes.length);
byteLength += appidBytes.length;
System.arraycopy(padBytes, 0, unencrypted, byteLength, padBytes.length);
try {
byte[] aesKey = Base64.decodeBase64(encodingAesKey + "=");
// 设置加密模式为AES的CBC模式
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(aesKey, Consts.AES);
IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
// 加密
byte[] encrypted = cipher.doFinal(unencrypted);
// 使用BASE64对加密后的字符串进行编码
return Base64.encodeBase64String(encrypted);
} catch (Exception e) {
throw new WeixinException("-40006", "AES加密失败:" + e.getMessage());
}
}
/**
* 对AES消息解密
*
* @param appId
* @param encodingAesKey
* aes加密的密钥
* @param encryptContent
* 加密的消息体
* @return 解密后的字符
* @throws WeixinException
*/
public static String aesDecrypt(String appId, String encodingAesKey,
String encryptContent) throws WeixinException {
byte[] aesKey = Base64.decodeBase64(encodingAesKey + "=");
byte[] original;
try {
// 设置解密模式为AES的CBC模式
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key_spec = new SecretKeySpec(aesKey, Consts.AES);
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey,
0, 16));
cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
// 使用BASE64对密文进行解码
byte[] encrypted = Base64.decodeBase64(encryptContent);
// 解密
original = cipher.doFinal(encrypted);
} catch (Exception e) {
throw new WeixinException("-40007", "AES解密失败:" + e.getMessage());
}
String xmlContent, fromAppId;
try {
// 去除补位字符
byte[] bytes = PKCS7Encoder.decode(original);
// 获取表示xml长度的字节数组
byte[] lengthByte = Arrays.copyOfRange(bytes, 16, 20);
// 获取xml消息主体的长度(byte[]2int)
// http://my.oschina.net/u/169390/blog/97495
int xmlLength = lengthByte[3] & 0xff | (lengthByte[2] & 0xff) << 8
| (lengthByte[1] & 0xff) << 16
| (lengthByte[0] & 0xff) << 24;
xmlContent = new String(Arrays.copyOfRange(bytes, 20,
20 + xmlLength), org.apache.http.Consts.UTF_8);
fromAppId = new String(Arrays.copyOfRange(bytes, 20 + xmlLength,
bytes.length), org.apache.http.Consts.UTF_8);
} catch (Exception e) {
throw new WeixinException("-40008", "公众平台发送的xml不合法:"
+ e.getMessage());
}
// 校验appId是否一致
if (!fromAppId.trim().equals(appId)) {
throw new WeixinException("-40005", "校验AppID失败");
}
return xmlContent;
}
}
@@ -6,8 +6,6 @@ import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.apache.commons.lang3.StringUtils;
/**
* @title 反射工具类
* @description 提供对类,字段的反射调用
@@ -92,13 +90,13 @@ public class ReflectionUtil {
Method getterMethod = null;
String propertyNa = null;
if (propertyName.contains(".")) {
propertyNa = StringUtils.substringBefore(propertyName, ".");
getterMethodName = "get" + StringUtils.capitalize(propertyNa);
propertyNa = StringUtil.substringBefore(propertyName, ".");
getterMethodName = "get" + StringUtil.capitalize(propertyNa);
getterMethod = object.getClass().getMethod(getterMethodName);
return invokeGetterMethod(getterMethod.invoke(object),
StringUtils.substringAfter(propertyName, "."));
StringUtil.substringAfter(propertyName, "."));
} else {
getterMethodName = "get" + StringUtils.capitalize(propertyName);
getterMethodName = "get" + StringUtil.capitalize(propertyName);
getterMethod = object.getClass().getMethod(getterMethodName);
return getterMethod.invoke(object);
}
@@ -140,7 +138,7 @@ public class ReflectionUtil {
*/
public static void invokeSetterMethod(Object object, String propertyName,
Object propertyValue, Class<?> setterMethodClass) {
String setterMethodName = "set" + StringUtils.capitalize(propertyName);
String setterMethodName = "set" + StringUtil.capitalize(propertyName);
try {
Method setterMethod = object.getClass().getMethod(setterMethodName,
setterMethodClass);
@@ -0,0 +1,193 @@
package com.foxinmy.weixin4j.util;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Objects;
import com.foxinmy.weixin4j.model.Consts;
public final class StringUtil {
public static final String EMPTY = "";
public static final int INDEX_NOT_FOUND = -1;
private static byte[] getBytes(final String content, final Charset charset) {
if (content == null) {
return null;
}
return content.getBytes(charset);
}
private static String newString(final byte[] bytes, final Charset charset) {
return bytes == null ? null : new String(bytes, charset);
}
public static byte[] getBytesUtf8(final String content) {
return getBytes(content, Consts.UTF_8);
}
public static String newStringUtf8(final byte[] bytes) {
return newString(bytes, Consts.UTF_8);
}
public static boolean isEmpty(final CharSequence cs) {
return cs == null || cs.length() == 0;
}
public static boolean isBlank(final CharSequence cs) {
int strLen;
if (cs == null || (strLen = cs.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (Character.isWhitespace(cs.charAt(i)) == false) {
return false;
}
}
return true;
}
public static boolean isNotBlank(final CharSequence cs) {
return !isBlank(cs);
}
public static String capitalize(final String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return str;
}
char firstChar = str.charAt(0);
if (Character.isTitleCase(firstChar)) {
// already capitalized
return str;
}
return new StringBuilder(strLen)
.append(Character.toTitleCase(firstChar))
.append(str.substring(1)).toString();
}
public static String substringBefore(final String str,
final String separator) {
if (isEmpty(str) || separator == null) {
return str;
}
if (separator.isEmpty()) {
return EMPTY;
}
final int pos = str.indexOf(separator);
if (pos == INDEX_NOT_FOUND) {
return str;
}
return str.substring(0, pos);
}
public static String substringAfter(final String str, final String separator) {
if (isEmpty(str)) {
return str;
}
if (separator == null) {
return EMPTY;
}
final int pos = str.indexOf(separator);
if (pos == INDEX_NOT_FOUND) {
return EMPTY;
}
return str.substring(pos + separator.length());
}
public static String join(final Object[] array, final char separator) {
if (array == null) {
return null;
}
return join(array, separator, 0, array.length);
}
public static String join(final Object[] array, final char separator,
final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final StringBuilder buf = new StringBuilder(noOfItems * 16);
for (int i = startIndex; i < endIndex; i++) {
if (i > startIndex) {
buf.append(separator);
}
if (array[i] != null) {
buf.append(array[i]);
}
}
return buf.toString();
}
public static String join(final Iterable<?> iterable, final char separator) {
if (iterable == null) {
return null;
}
return join(iterable.iterator(), separator);
}
public static String join(final Iterator<?> iterator, final char separator) {
// handle null, zero and one elements before building a buffer
if (iterator == null) {
return null;
}
if (!iterator.hasNext()) {
return EMPTY;
}
final Object first = iterator.next();
if (!iterator.hasNext()) {
String result = Objects.toString(first);
return result;
}
// two or more elements
final StringBuilder buf = new StringBuilder(256); // Java default is 16,
// probably too
// small
if (first != null) {
buf.append(first);
}
while (iterator.hasNext()) {
buf.append(separator);
final Object obj = iterator.next();
if (obj != null) {
buf.append(obj);
}
}
return buf.toString();
}
public static String join(final int[] array, final char separator) {
if (array == null) {
return null;
}
return join(array, separator, 0, array.length);
}
public static String join(final int[] array, final char separator,
final int startIndex, final int endIndex) {
if (array == null) {
return null;
}
final int noOfItems = endIndex - startIndex;
if (noOfItems <= 0) {
return EMPTY;
}
final StringBuilder buf = new StringBuilder(noOfItems * 16);
for (int i = startIndex; i < endIndex; i++) {
if (i > startIndex) {
buf.append(separator);
}
buf.append(array[i]);
}
return buf.toString();
}
}
@@ -4,8 +4,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.util.StringUtil;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.converters.collections.MapConverter;
@@ -50,7 +49,7 @@ public class Map2ObjectConverter extends MapConverter {
continue;
}
String value = entry.getValue().toString();
if (StringUtils.isBlank(value)) {
if (StringUtil.isBlank(value)) {
continue;
}
ExtendedHierarchicalStreamWriterHelper.startNode(writer, entry