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

View File

@ -271,8 +271,8 @@
* 2015-05-07 * 2015-05-07
+**weixin4j-server**: 完成基本骨架 + **weixin4j-server**: 完成基本骨架
* 2015-05-08 * 2015-05-08
+**weixin4j-server**: 完成消息分发器、消息处理器、消息拦截器的骨架 + **weixin4j-server**: 完成消息分发器、消息处理器、消息拦截器的骨架

View File

@ -47,30 +47,15 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId> <artifactId>fastjson</artifactId>
<version>${fastjson.version}</version> <version>${fastjson.version}</version>
</dependency> </dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>${dom4j.version}</version>
</dependency>
<dependency> <dependency>
<groupId>redis.clients</groupId> <groupId>redis.clients</groupId>
<artifactId>jedis</artifactId> <artifactId>jedis</artifactId>
<version>${jedis.version}</version> <version>${jedis.version}</version>
</dependency> </dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons.codec.version}</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -7,7 +7,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts; import org.apache.http.Consts;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
@ -36,7 +35,9 @@ import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONException;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.util.ErrorUtil;
import com.foxinmy.weixin4j.util.MapUtil; import com.foxinmy.weixin4j.util.MapUtil;
import com.foxinmy.weixin4j.util.StringUtil;
import com.thoughtworks.xstream.mapper.CannotResolveClassException; import com.thoughtworks.xstream.mapper.CannotResolveClassException;
/** /**
@ -237,8 +238,9 @@ public class HttpRequest {
JsonResult jsonResult = response.getAsJsonResult(); JsonResult jsonResult = response.getAsJsonResult();
response.setJsonResult(true); response.setJsonResult(true);
if (jsonResult.getCode() != 0) { if (jsonResult.getCode() != 0) {
if (StringUtils.isBlank(jsonResult.getDesc())) { if (StringUtil.isBlank(jsonResult.getDesc())) {
jsonResult = response.getTextError(jsonResult.getCode()); jsonResult.setDesc(ErrorUtil.getText(Integer
.toString(jsonResult.getCode())));
} }
throw new WeixinException(Integer.toString(jsonResult.getCode()), throw new WeixinException(Integer.toString(jsonResult.getCode()),
jsonResult.getDesc()); jsonResult.getDesc());

View File

@ -1,14 +1,7 @@
package com.foxinmy.weixin4j.http; package com.foxinmy.weixin4j.http;
import java.io.IOException;
import java.io.InputStream; 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.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.TypeReference;
@ -67,65 +60,6 @@ public class Response {
return XmlStream.get(text, XmlResult.class); 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) { public void setText(String text) {
this.text = text; this.text = text;
} }

View File

@ -2,9 +2,8 @@ package com.foxinmy.weixin4j.http;
import java.io.Serializable; import java.io.Serializable;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.util.StringUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
/** /**
@ -53,7 +52,7 @@ public class XmlResult implements Serializable {
} }
public String getReturnMsg() { public String getReturnMsg() {
return StringUtils.isNotBlank(returnMsg) ? returnMsg : null; return StringUtil.isNotBlank(returnMsg) ? returnMsg : null;
} }
public void setReturnMsg(String returnMsg) { public void setReturnMsg(String returnMsg) {
@ -77,7 +76,7 @@ public class XmlResult implements Serializable {
} }
public String getErrCodeDes() { public String getErrCodeDes() {
return StringUtils.isNotBlank(errCodeDes) ? errCodeDes : null; return StringUtil.isNotBlank(errCodeDes) ? errCodeDes : null;
} }
public void setErrCodeDes(String errCodeDes) { public void setErrCodeDes(String errCodeDes) {

View File

@ -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;
}
}

View File

@ -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() + "]";
}
}

View File

@ -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() + "]";
}
}

View File

@ -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() + "]";
}
}

View File

@ -1,10 +0,0 @@
普通消息
-------
当普通微信用户向公众账号发消息时微信服务器将POST消息的XML数据包到开发者填写的URL上。
微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次
关于重试的消息排重推荐使用msgid排重。
假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。

View File

@ -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()
+ "]";
}
}

View File

@ -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() + "]";
}
}

View File

@ -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()
+ "]";
}
}

View File

@ -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();
}
}

View File

@ -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() + "]";
}
}

View File

@ -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() + "]";
}
}

View File

@ -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() + "]";
}
}

View File

@ -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() + "]";
}
}

View File

@ -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() + "]";
}
}

View File

@ -1,3 +0,0 @@
菜单事件消息
用户点击自定义菜单后微信会把点击事件推送给开发者请注意点击菜单弹出子菜单不会产生上报。请注意第3个到第8个的所有事件仅支持微信iPhone5.4.1以上版本和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。

View File

@ -22,6 +22,9 @@ public final class Consts {
public static final String TLS = "TLS"; public static final String TLS = "TLS";
public static final String X509 = "X.509"; public static final String X509 = "X.509";
public static final String AES = "AES"; 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_FILE = "file";
public static final String PROTOCOL_JAR = "jar"; public static final String PROTOCOL_JAR = "jar";

View File

@ -1,7 +1,5 @@
package com.foxinmy.weixin4j.token; package com.foxinmy.weixin4j.token;
import org.apache.commons.lang3.StringUtils;
import redis.clients.jedis.Jedis; import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig; 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.exception.WeixinException;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* 用REDIS保存TOKEN * 用REDIS保存TOKEN
@ -64,7 +63,7 @@ public class RedisTokenHolder implements TokenHolder {
jedis = jedisPool.getResource(); jedis = jedisPool.getResource();
String cacheKey = tokenCreator.getCacheKey(); String cacheKey = tokenCreator.getCacheKey();
String accessToken = jedis.get(cacheKey); String accessToken = jedis.get(cacheKey);
if (StringUtils.isBlank(accessToken)) { if (StringUtil.isBlank(accessToken)) {
token = tokenCreator.createToken(); token = tokenCreator.createToken();
jedis.setex(cacheKey, (int) token.getExpiresIn(), jedis.setex(cacheKey, (int) token.getExpiresIn(),
token.getAccessToken()); token.getAccessToken());

View File

@ -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;
}

View File

@ -8,7 +8,7 @@ import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.model.WeixinAccount;
/** /**
* 商户配置工具类 * 公众号配置
* *
* @className ConfigUtil * @className ConfigUtil
* @author jy * @author jy

View File

@ -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));
}
}

View File

@ -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"));
}
}

View File

@ -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);
}
}

View File

@ -7,7 +7,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts; import org.apache.http.Consts;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
@ -65,7 +64,7 @@ public class MapUtil {
try { try {
if (encoder && lowerCase) { if (encoder && lowerCase) {
for (Map.Entry<String, String> entry : set) { for (Map.Entry<String, String> entry : set) {
if (StringUtils.isBlank(entry.getValue())) { if (StringUtil.isBlank(entry.getValue())) {
continue; continue;
} }
sb.append(entry.getKey().toLowerCase()) sb.append(entry.getKey().toLowerCase())
@ -75,7 +74,7 @@ public class MapUtil {
} }
} else if (encoder) { } else if (encoder) {
for (Map.Entry<String, String> entry : set) { for (Map.Entry<String, String> entry : set) {
if (StringUtils.isBlank(entry.getValue())) { if (StringUtil.isBlank(entry.getValue())) {
continue; continue;
} }
sb.append(entry.getKey()) sb.append(entry.getKey())
@ -85,7 +84,7 @@ public class MapUtil {
} }
} else if (lowerCase) { } else if (lowerCase) {
for (Map.Entry<String, String> entry : set) { for (Map.Entry<String, String> entry : set) {
if (StringUtils.isBlank(entry.getValue())) { if (StringUtil.isBlank(entry.getValue())) {
continue; continue;
} }
sb.append(entry.getKey().toLowerCase()).append("=") sb.append(entry.getKey().toLowerCase()).append("=")
@ -93,7 +92,7 @@ public class MapUtil {
} }
} else { } else {
for (Map.Entry<String, String> entry : set) { for (Map.Entry<String, String> entry : set) {
if (StringUtils.isBlank(entry.getValue())) { if (StringUtil.isBlank(entry.getValue())) {
continue; continue;
} }
sb.append(entry.getKey()).append("=") sb.append(entry.getKey()).append("=")

View File

@ -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;
}
}

View File

@ -6,8 +6,6 @@ import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import org.apache.commons.lang3.StringUtils;
/** /**
* @title 反射工具类 * @title 反射工具类
* @description 提供对类,字段的反射调用 * @description 提供对类,字段的反射调用
@ -92,13 +90,13 @@ public class ReflectionUtil {
Method getterMethod = null; Method getterMethod = null;
String propertyNa = null; String propertyNa = null;
if (propertyName.contains(".")) { if (propertyName.contains(".")) {
propertyNa = StringUtils.substringBefore(propertyName, "."); propertyNa = StringUtil.substringBefore(propertyName, ".");
getterMethodName = "get" + StringUtils.capitalize(propertyNa); getterMethodName = "get" + StringUtil.capitalize(propertyNa);
getterMethod = object.getClass().getMethod(getterMethodName); getterMethod = object.getClass().getMethod(getterMethodName);
return invokeGetterMethod(getterMethod.invoke(object), return invokeGetterMethod(getterMethod.invoke(object),
StringUtils.substringAfter(propertyName, ".")); StringUtil.substringAfter(propertyName, "."));
} else { } else {
getterMethodName = "get" + StringUtils.capitalize(propertyName); getterMethodName = "get" + StringUtil.capitalize(propertyName);
getterMethod = object.getClass().getMethod(getterMethodName); getterMethod = object.getClass().getMethod(getterMethodName);
return getterMethod.invoke(object); return getterMethod.invoke(object);
} }
@ -140,7 +138,7 @@ public class ReflectionUtil {
*/ */
public static void invokeSetterMethod(Object object, String propertyName, public static void invokeSetterMethod(Object object, String propertyName,
Object propertyValue, Class<?> setterMethodClass) { Object propertyValue, Class<?> setterMethodClass) {
String setterMethodName = "set" + StringUtils.capitalize(propertyName); String setterMethodName = "set" + StringUtil.capitalize(propertyName);
try { try {
Method setterMethod = object.getClass().getMethod(setterMethodName, Method setterMethod = object.getClass().getMethod(setterMethodName,
setterMethodClass); setterMethodClass);

View File

@ -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();
}
}

View File

@ -4,8 +4,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; 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.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.converters.collections.MapConverter; import com.thoughtworks.xstream.converters.collections.MapConverter;
@ -50,7 +49,7 @@ public class Map2ObjectConverter extends MapConverter {
continue; continue;
} }
String value = entry.getValue().toString(); String value = entry.getValue().toString();
if (StringUtils.isBlank(value)) { if (StringUtil.isBlank(value)) {
continue; continue;
} }
ExtendedHierarchicalStreamWriterHelper.startNode(writer, entry ExtendedHierarchicalStreamWriterHelper.startNode(writer, entry

View File

@ -16,7 +16,7 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<configuration> <configuration>
<finalName>weixin4j-mp-${project.version}</finalName> <finalName>${project.name}-${project.version}</finalName>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
@ -42,11 +42,6 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>

View File

@ -7,8 +7,6 @@ import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
@ -19,6 +17,7 @@ import com.foxinmy.weixin4j.mp.payment.coupon.CouponDetail;
import com.foxinmy.weixin4j.mp.payment.coupon.CouponResult; import com.foxinmy.weixin4j.mp.payment.coupon.CouponResult;
import com.foxinmy.weixin4j.mp.payment.coupon.CouponStock; import com.foxinmy.weixin4j.mp.payment.coupon.CouponStock;
import com.foxinmy.weixin4j.util.RandomUtil; import com.foxinmy.weixin4j.util.RandomUtil;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* 代金券API * 代金券API
@ -66,7 +65,7 @@ public class CouponApi extends MpApi {
// openid记录数目前支持num=1 // openid记录数目前支持num=1
map.put("openid_count", "1"); map.put("openid_count", "1");
// 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限 // 操作员帐号, 默认为商户号 可在商户平台配置操作员对应的api权限
if (StringUtils.isBlank(opUserId)) { if (StringUtil.isBlank(opUserId)) {
opUserId = weixinAccount.getMchId(); opUserId = weixinAccount.getMchId();
} }
map.put("op_user_id", opUserId); map.put("op_user_id", opUserId);
@ -158,10 +157,10 @@ public class CouponApi extends MpApi {
map.put("appid", weixinAccount.getId()); map.put("appid", weixinAccount.getId());
map.put("mch_id", weixinAccount.getMchId()); map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16)); map.put("nonce_str", RandomUtil.generateString(16));
if (StringUtils.isNotBlank(weixinAccount.getDeviceInfo())) { if (StringUtil.isNotBlank(weixinAccount.getDeviceInfo())) {
map.put("device_info", weixinAccount.getDeviceInfo()); map.put("device_info", weixinAccount.getDeviceInfo());
} }
if (StringUtils.isNotBlank(weixinAccount.getSubMchId())) { if (StringUtil.isNotBlank(weixinAccount.getSubMchId())) {
map.put("sub_mch_id", weixinAccount.getSubMchId()); map.put("sub_mch_id", weixinAccount.getSubMchId());
} }
return map; return map;

View File

@ -6,7 +6,6 @@ import java.io.IOException;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.entity.mime.content.ByteArrayBody; import org.apache.http.entity.mime.content.ByteArrayBody;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
@ -21,6 +20,7 @@ import com.foxinmy.weixin4j.mp.model.CustomRecord;
import com.foxinmy.weixin4j.mp.model.KfAccount; import com.foxinmy.weixin4j.mp.model.KfAccount;
import com.foxinmy.weixin4j.mp.model.KfSession; import com.foxinmy.weixin4j.mp.model.KfSession;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.util.DigestUtil;
import com.foxinmy.weixin4j.util.IOUtil; import com.foxinmy.weixin4j.util.IOUtil;
/** /**
@ -136,7 +136,7 @@ public class CustomApi extends MpApi {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("kf_account", id); obj.put("kf_account", id);
obj.put("nickname", name); obj.put("nickname", name);
obj.put("password", DigestUtils.md5Hex(pwd)); obj.put("password", DigestUtil.MD5(pwd));
String custom_add_uri = getRequestUri("custom_add_uri"); String custom_add_uri = getRequestUri("custom_add_uri");
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
Response response = request.post( Response response = request.post(
@ -167,7 +167,7 @@ public class CustomApi extends MpApi {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("kf_account", id); obj.put("kf_account", id);
obj.put("nickname", name); obj.put("nickname", name);
obj.put("password", DigestUtils.md5Hex(pwd)); obj.put("password", DigestUtil.MD5(pwd));
String custom_update_uri = getRequestUri("custom_update_uri"); String custom_update_uri = getRequestUri("custom_update_uri");
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
Response response = request.post( Response response = request.post(

View File

@ -3,8 +3,6 @@ package com.foxinmy.weixin4j.mp.api;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
@ -17,6 +15,7 @@ import com.foxinmy.weixin4j.tuple.MpArticle;
import com.foxinmy.weixin4j.tuple.MpNews; import com.foxinmy.weixin4j.tuple.MpNews;
import com.foxinmy.weixin4j.tuple.Tuple; import com.foxinmy.weixin4j.tuple.Tuple;
import com.foxinmy.weixin4j.tuple.Video; import com.foxinmy.weixin4j.tuple.Video;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* 群发相关API * 群发相关API
@ -132,7 +131,7 @@ public class MassApi extends MpApi {
if (tuple instanceof MpNews) { if (tuple instanceof MpNews) {
MpNews _news = (MpNews) tuple; MpNews _news = (MpNews) tuple;
List<MpArticle> _articles = _news.getArticles(); List<MpArticle> _articles = _news.getArticles();
if (StringUtils.isBlank(_news.getMediaId()) if (StringUtil.isBlank(_news.getMediaId())
&& (_articles == null || _articles.isEmpty())) { && (_articles == null || _articles.isEmpty())) {
throw new WeixinException( throw new WeixinException(
"mass fail:mediaId or articles is required"); "mass fail:mediaId or articles is required");
@ -203,7 +202,7 @@ public class MassApi extends MpApi {
if (tuple instanceof MpNews) { if (tuple instanceof MpNews) {
MpNews _news = (MpNews) tuple; MpNews _news = (MpNews) tuple;
List<MpArticle> _articles = _news.getArticles(); List<MpArticle> _articles = _news.getArticles();
if (StringUtils.isBlank(_news.getMediaId()) if (StringUtil.isBlank(_news.getMediaId())
&& (_articles == null || _articles.isEmpty())) { && (_articles == null || _articles.isEmpty())) {
throw new WeixinException( throw new WeixinException(
"mass fail:mediaId or articles is required"); "mass fail:mediaId or articles is required");

View File

@ -9,7 +9,6 @@ import java.io.UnsupportedEncodingException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.mime.content.ByteArrayBody; import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.StringBody; import org.apache.http.entity.mime.content.StringBody;
@ -32,6 +31,7 @@ import com.foxinmy.weixin4j.type.MediaType;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.FileUtil; import com.foxinmy.weixin4j.util.FileUtil;
import com.foxinmy.weixin4j.util.IOUtil; import com.foxinmy.weixin4j.util.IOUtil;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* 素材相关API * 素材相关API
@ -65,7 +65,7 @@ public class MediaApi extends MpApi {
public String uploadMedia(File file, boolean isMaterial) public String uploadMedia(File file, boolean isMaterial)
throws WeixinException, IOException { throws WeixinException, IOException {
String mediaTypeKey = IOUtil.getExtension(file.getName()); String mediaTypeKey = IOUtil.getExtension(file.getName());
if (StringUtils.isBlank(mediaTypeKey)) { if (StringUtil.isBlank(mediaTypeKey)) {
mediaTypeKey = FileUtil.getFileType(file); mediaTypeKey = FileUtil.getFileType(file);
} }
MediaType mediaType = MediaType.getMediaType(mediaTypeKey); MediaType mediaType = MediaType.getMediaType(mediaTypeKey);

View File

@ -1,7 +1,5 @@
package com.foxinmy.weixin4j.mp.api; package com.foxinmy.weixin4j.mp.api;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.JsonResult;
@ -10,6 +8,7 @@ import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.message.NotifyMessage; import com.foxinmy.weixin4j.mp.message.NotifyMessage;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.tuple.NotifyTuple; import com.foxinmy.weixin4j.tuple.NotifyTuple;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* 客服消息API * 客服消息API
@ -70,7 +69,7 @@ public class NotifyApi extends MpApi {
obj.put("touser", notify.getTouser()); obj.put("touser", notify.getTouser());
obj.put("msgtype", msgtype); obj.put("msgtype", msgtype);
obj.put(msgtype, tuple); obj.put(msgtype, tuple);
if (StringUtils.isNotBlank(kfAccount)) { if (StringUtil.isNotBlank(kfAccount)) {
JSONObject kf = new JSONObject(); JSONObject kf = new JSONObject();
kf.put("kf_account", kfAccount); kf.put("kf_account", kfAccount);
obj.put("customservice", kf); obj.put("customservice", kf);

View File

@ -24,8 +24,6 @@ import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.TrustManagerFactory;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts; import org.apache.http.Consts;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@ -52,7 +50,9 @@ import com.foxinmy.weixin4j.mp.util.ExcelUtil;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.DateUtil; import com.foxinmy.weixin4j.util.DateUtil;
import com.foxinmy.weixin4j.util.DigestUtil;
import com.foxinmy.weixin4j.util.MapUtil; import com.foxinmy.weixin4j.util.MapUtil;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* V2支付API * V2支付API
@ -91,7 +91,7 @@ public class Pay2Api extends PayApi {
sb.append("&partner=").append(weixinAccount.getPartnerId()); sb.append("&partner=").append(weixinAccount.getPartnerId());
String part = sb.toString(); String part = sb.toString();
sb.append("&key=").append(weixinAccount.getPartnerKey()); sb.append("&key=").append(weixinAccount.getPartnerKey());
String sign = DigestUtils.md5Hex(sb.toString()).toUpperCase(); String sign = DigestUtil.MD5(sb.toString()).toUpperCase();
sb.delete(0, sb.length()); sb.delete(0, sb.length());
sb.append(part).append("&sign=").append(sign); sb.append(part).append("&sign=").append(sign);
@ -172,7 +172,7 @@ public class Pay2Api extends PayApi {
map.put("total_fee", DateUtil.formaFee2Fen(totalFee)); map.put("total_fee", DateUtil.formaFee2Fen(totalFee));
map.put("refund_fee", DateUtil.formaFee2Fen(refundFee)); map.put("refund_fee", DateUtil.formaFee2Fen(refundFee));
map.put(idQuery.getType().getName(), idQuery.getId()); map.put(idQuery.getType().getName(), idQuery.getId());
if (StringUtils.isBlank(opUserId)) { if (StringUtil.isBlank(opUserId)) {
opUserId = weixinAccount.getPartnerId(); opUserId = weixinAccount.getPartnerId();
} }
map.put("op_user_id", opUserId); map.put("op_user_id", opUserId);
@ -261,7 +261,7 @@ public class Pay2Api extends PayApi {
String outRefundNo, double totalFee, double refundFee, String outRefundNo, double totalFee, double refundFee,
String opUserId, String opUserPasswd) throws WeixinException { String opUserId, String opUserPasswd) throws WeixinException {
Map<String, String> mopara = new HashMap<String, String>(); Map<String, String> mopara = new HashMap<String, String>();
mopara.put("op_user_passwd", DigestUtils.md5Hex(opUserPasswd)); mopara.put("op_user_passwd", DigestUtil.MD5(opUserPasswd));
return refund(caFile, idQuery, outRefundNo, totalFee, refundFee, return refund(caFile, idQuery, outRefundNo, totalFee, refundFee,
opUserId, mopara); opUserId, mopara);
} }
@ -301,11 +301,11 @@ public class Pay2Api extends PayApi {
String opUserId, String opUserPasswd, String recvUserId, String opUserId, String opUserPasswd, String recvUserId,
String reccvUserName, RefundType refundType) throws WeixinException { String reccvUserName, RefundType refundType) throws WeixinException {
Map<String, String> mopara = new HashMap<String, String>(); Map<String, String> mopara = new HashMap<String, String>();
mopara.put("op_user_passwd", DigestUtils.md5Hex(opUserPasswd)); mopara.put("op_user_passwd", DigestUtil.MD5(opUserPasswd));
if (StringUtils.isNotBlank(recvUserId)) { if (StringUtil.isNotBlank(recvUserId)) {
mopara.put("recv_user_id", recvUserId); mopara.put("recv_user_id", recvUserId);
} }
if (StringUtils.isNotBlank(reccvUserName)) { if (StringUtil.isNotBlank(reccvUserName)) {
mopara.put("reccv_user_name", reccvUserName); mopara.put("reccv_user_name", reccvUserName);
} }
if (refundType != null) { if (refundType != null) {
@ -389,7 +389,7 @@ public class Pay2Api extends PayApi {
map.put("cft_signtype", "0"); map.put("cft_signtype", "0");
map.put("mchtype", Integer.toString(billType.getVal())); map.put("mchtype", Integer.toString(billType.getVal()));
map.put("key", weixinAccount.getPartnerKey()); map.put("key", weixinAccount.getPartnerKey());
String sign = DigestUtils.md5Hex(MapUtil String sign = DigestUtil.MD5(MapUtil
.toJoinString(map, false, false)); .toJoinString(map, false, false));
map.put("sign", sign.toLowerCase()); map.put("sign", sign.toLowerCase());
Response response = request.get(downloadbill_uri, map); Response response = request.get(downloadbill_uri, map);

View File

@ -18,7 +18,6 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts; import org.apache.http.Consts;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@ -45,6 +44,7 @@ import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.DateUtil; import com.foxinmy.weixin4j.util.DateUtil;
import com.foxinmy.weixin4j.util.RandomUtil; import com.foxinmy.weixin4j.util.RandomUtil;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* V3(商户平台版)支付API * V3(商户平台版)支付API
@ -134,7 +134,7 @@ public class Pay3Api extends PayApi {
map.put("out_refund_no", outRefundNo); map.put("out_refund_no", outRefundNo);
map.put("total_fee", DateUtil.formaFee2Fen(totalFee)); map.put("total_fee", DateUtil.formaFee2Fen(totalFee));
map.put("refund_fee", DateUtil.formaFee2Fen(refundFee)); map.put("refund_fee", DateUtil.formaFee2Fen(refundFee));
if (StringUtils.isBlank(opUserId)) { if (StringUtil.isBlank(opUserId)) {
opUserId = weixinAccount.getMchId(); opUserId = weixinAccount.getMchId();
} }
map.put("op_user_id", opUserId); map.put("op_user_id", opUserId);
@ -459,7 +459,7 @@ public class Pay3Api extends PayApi {
map.put("appid", weixinAccount.getId()); map.put("appid", weixinAccount.getId());
map.put("mch_id", weixinAccount.getMchId()); map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16)); map.put("nonce_str", RandomUtil.generateString(16));
if (StringUtils.isNotBlank(weixinAccount.getDeviceInfo())) { if (StringUtil.isNotBlank(weixinAccount.getDeviceInfo())) {
map.put("device_info", weixinAccount.getDeviceInfo()); map.put("device_info", weixinAccount.getDeviceInfo());
} }
if (idQuery != null) { if (idQuery != null) {

View File

@ -1,40 +0,0 @@
package com.foxinmy.weixin4j.mp.event;
import com.foxinmy.weixin4j.message.event.EventMessage;
import com.foxinmy.weixin4j.mp.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 客服关闭会话事件
*
* @className KfCloseEventMessage
* @author jy
* @date 2015年3月22日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/2/6c20f3e323bdf5986cfcb33cbd3b829a.html#.E4.BC.9A.E8.AF.9D.E7.8A.B6.E6.80.81.E9.80.9A.E7.9F.A5.E4.BA.8B.E4.BB.B6">会话状态通知事件</a>
*/
public class KfCloseEventMessage extends EventMessage {
private static final long serialVersionUID = 3644449346935205541L;
public KfCloseEventMessage() {
super(EventType.kf_close_session.name());
}
/**
* 客服账号
*/
@XStreamAlias("KfAccount")
private String kfAccount;
public String getKfAccount() {
return kfAccount;
}
@Override
public String toString() {
return "KfCloseEventMessage [kfAccount=" + kfAccount + ", ="
+ super.toString() + "]";
}
}

View File

@ -1,40 +0,0 @@
package com.foxinmy.weixin4j.mp.event;
import com.foxinmy.weixin4j.message.event.EventMessage;
import com.foxinmy.weixin4j.mp.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 客服接入会话事件
*
* @className KfCreateEventMessage
* @author jy
* @date 2015年3月22日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/2/6c20f3e323bdf5986cfcb33cbd3b829a.html#.E4.BC.9A.E8.AF.9D.E7.8A.B6.E6.80.81.E9.80.9A.E7.9F.A5.E4.BA.8B.E4.BB.B6">会话状态通知事件</a>
*/
public class KfCreateEventMessage extends EventMessage {
private static final long serialVersionUID = -8968189700999202108L;
public KfCreateEventMessage() {
super(EventType.kf_create_session.name());
}
/**
* 客服账号
*/
@XStreamAlias("KfAccount")
private String kfAccount;
public String getKfAccount() {
return kfAccount;
}
@Override
public String toString() {
return "KfCreateEventMessage [kfAccount=" + kfAccount + ", ="
+ super.toString() + "]";
}
}

View File

@ -1,48 +0,0 @@
package com.foxinmy.weixin4j.mp.event;
import com.foxinmy.weixin4j.message.event.EventMessage;
import com.foxinmy.weixin4j.mp.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 客服转接会话事件
*
* @className KfSwitchEventMessage
* @author jy
* @date 2015年3月22日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/2/6c20f3e323bdf5986cfcb33cbd3b829a.html#.E4.BC.9A.E8.AF.9D.E7.8A.B6.E6.80.81.E9.80.9A.E7.9F.A5.E4.BA.8B.E4.BB.B6">会话状态通知事件</a>
*/
public class KfSwitchEventMessage extends EventMessage {
private static final long serialVersionUID = 4319501074109623413L;
public KfSwitchEventMessage() {
super(EventType.kf_switch_session.name());
}
/**
* 来自的客服账号
*/
@XStreamAlias("FromKfAccount")
private String fromKfAccount;
/**
* 转移给客服账号
*/
@XStreamAlias("ToKfAccount")
private String toKfAccount;
public String getFromKfAccount() {
return fromKfAccount;
}
public String getToKfAccount() {
return toKfAccount;
}
@Override
public String toString() {
return "KfSwitchEventMessage [fromKfAccount=" + fromKfAccount
+ ", toKfAccount=" + toKfAccount + "]";
}
}

View File

@ -1,129 +0,0 @@
package com.foxinmy.weixin4j.mp.event;
import java.util.HashMap;
import java.util.Map;
import com.foxinmy.weixin4j.message.event.EventMessage;
import com.foxinmy.weixin4j.mp.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
/**
* 群发消息事件推送
*
* @className MassEventMessage
* @author jy
* @date 2014年4月27日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html#.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81.E7.BE.A4.E5.8F.91.E7.BB.93.E6.9E.9C">群发回调</a>
*/
public class MassEventMessage extends EventMessage {
private static final long serialVersionUID = -1660543255873723895L;
public MassEventMessage() {
super(EventType.masssendjobfinish.name());
}
/**
* 群发后的状态信息 send successsend failerr(num)
*/
@XStreamAlias("Status")
private String status;
/**
* group_id下粉丝数或者openid_list中的粉丝数
*/
@XStreamAlias("TotalCount")
private int totalCount;
/**
* 过滤过滤是指特定地区性别的过滤用户设置拒收的过滤用户接收已超4条的过滤准备发送的粉丝数原则上FilterCount =
* SentCount + ErrorCount
*/
@XStreamAlias("FilterCount")
private int filterCount;
/**
* 发送成功的粉丝数
*/
@XStreamAlias("SentCount")
private int sentCount;
/**
* 发送失败的粉丝数
*/
@XStreamAlias("ErrorCount")
private int errorCount;
@XStreamOmitField
private final static Map<String, String> statusMap;
static {
statusMap = new HashMap<String, String>();
statusMap.put("sendsuccess", "发送成功");
statusMap.put("send_success", "发送成功");
statusMap.put("success", "发送成功");
statusMap.put("send success", "发送成功");
statusMap.put("sendfail", "发送失败");
statusMap.put("send_fail", "发送失败");
statusMap.put("fail", "发送失败");
statusMap.put("send fail", "发送失败");
statusMap.put("err(10001)", "涉嫌广告");
statusMap.put("err(20001)", "涉嫌政治");
statusMap.put("err(20004)", "涉嫌社会");
statusMap.put("err(20006)", "涉嫌违法犯罪");
statusMap.put("err(20008)", "涉嫌欺诈");
statusMap.put("err(20013)", "涉嫌版权");
statusMap.put("err(22000)", "涉嫌互推(互相宣传)");
statusMap.put("err(21000)", "涉嫌其他");
}
public String getStatus() {
return status;
}
/**
* 发送状态描述</br> err(10001,涉嫌广告) err(20001,涉嫌政治) err(20004,涉嫌社会)</br>
* err(20002,涉嫌色情) err(20006,涉嫌违法犯罪) err(20008,涉嫌欺诈)</br> err(20013,涉嫌版权)
* err(22000,涉嫌互推(互相宣传) err(21000,涉嫌其他)
*
* @param status
* @return 中文描述
*/
public String getStatusDesc() {
return statusMap.get(status.toLowerCase());
}
/**
* 发送状态描述</br> err(10001,涉嫌广告) err(20001,涉嫌政治) err(20004,涉嫌社会)</br>
* err(20002,涉嫌色情) err(20006,涉嫌违法犯罪) err(20008,涉嫌欺诈)</br> err(20013,涉嫌版权)
* err(22000,涉嫌互推(互相宣传) err(21000,涉嫌其他)
*
* @param status
* @return 中文描述
*/
public static String getStatusDesc(String status) {
return statusMap.get(status.toLowerCase());
}
public int getTotalCount() {
return totalCount;
}
public int getFilterCount() {
return filterCount;
}
public int getSentCount() {
return sentCount;
}
public int getErrorCount() {
return errorCount;
}
@Override
public String toString() {
return "MassEventMessage [status=" + getStatusDesc() + ", totalCount="
+ totalCount + ", filterCount=" + filterCount + ", sentCount="
+ sentCount + ", errorCount=" + errorCount + ", "
+ super.toString() + "]";
}
}

View File

@ -1,57 +0,0 @@
package com.foxinmy.weixin4j.mp.event;
import com.foxinmy.weixin4j.message.event.EventMessage;
import com.foxinmy.weixin4j.mp.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 扫描二维码事件
*
* @className ScanEventMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/2/5baf56ce4947d35003b86a9805634b1e.html#.E6.89.AB.E6.8F.8F.E5.B8.A6.E5.8F.82.E6.95.B0.E4.BA.8C.E7.BB.B4.E7.A0.81.E4.BA.8B.E4.BB.B6">扫描二维码事件</a>
*/
public class ScanEventMessage extends EventMessage {
private static final long serialVersionUID = 8078674062833071562L;
public ScanEventMessage() {
super(EventType.scan.name());
}
public ScanEventMessage(String eventType) {
super(eventType);
}
/**
* 事件KEY值是一个32位无符号整数即创建二维码时的二维码scene_id
*/
@XStreamAlias("EventKey")
private String eventKey;
/**
* 二维码的ticket可用来换取二维码图片
*/
@XStreamAlias("Ticket")
private String ticket;
public String getEventKey() {
return eventKey;
}
public String getTicket() {
return ticket;
}
public String getParameter() {
return eventKey.replace("qrscene_", "");
}
@Override
public String toString() {
return "ScanEventMessage [eventKey=" + eventKey + ", ticket=" + ticket
+ ", " + super.toString() + "]";
}
}

View File

@ -1,27 +0,0 @@
package com.foxinmy.weixin4j.mp.event;
import com.foxinmy.weixin4j.type.EventType;
/**
* 关注/取消关注事件</br> <font color="red">包括直接关注与扫描关注</font>
*
* @className ScribeEventMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/2/5baf56ce4947d35003b86a9805634b1e.html#.E5.85.B3.E6.B3.A8.2F.E5.8F.96.E6.B6.88.E5.85.B3.E6.B3.A8.E4.BA.8B.E4.BB.B6">订阅号服务号的关注/取消关注事件</a>
*/
public class ScribeEventMessage extends ScanEventMessage {
private static final long serialVersionUID = -6846321620262204915L;
public ScribeEventMessage() {
super(EventType.subscribe.name());
}
@Override
public String toString() {
return "ScribeEventMessage [" + super.toString() + "]";
}
}

View File

@ -1,40 +0,0 @@
package com.foxinmy.weixin4j.mp.event;
import com.foxinmy.weixin4j.message.event.EventMessage;
import com.foxinmy.weixin4j.mp.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 模板消息事件推送(公众平台)
*
* @className TemplatesendjobfinishMessage
* @author jy
* @date 2014年9月19日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/17/304c1885ea66dbedf7dc170d84999a9d.html#.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">模板消息事件推送</a>
*/
public class TemplatesendjobfinishMessage extends EventMessage {
private static final long serialVersionUID = -2903359365988594012L;
public TemplatesendjobfinishMessage() {
super(EventType.templatesendjobfinish.name());
}
/**
* 推送状态 如failed: system failed
*/
@XStreamAlias("Status")
private String status;
public String getStatus() {
return status;
}
@Override
public String toString() {
return "TemplatesendjobfinishMessage [status=" + status + ", "
+ super.toString() + "]";
}
}

View File

@ -3,12 +3,11 @@ package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.model.Gender; import com.foxinmy.weixin4j.model.Gender;
import com.foxinmy.weixin4j.mp.type.FaceSize; import com.foxinmy.weixin4j.mp.type.FaceSize;
import com.foxinmy.weixin4j.mp.type.Lang; import com.foxinmy.weixin4j.mp.type.Lang;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* 用户对象 * 用户对象
@ -135,7 +134,7 @@ public class User implements Serializable {
} }
public String getHeadimgurl(FaceSize size) { public String getHeadimgurl(FaceSize size) {
if (StringUtils.isNotBlank(headimgurl)) { if (StringUtil.isNotBlank(headimgurl)) {
StringBuilder sb = new StringBuilder(headimgurl); StringBuilder sb = new StringBuilder(headimgurl);
return sb.replace(0, (headimgurl.length() - 1), size.getInt() + "") return sb.replace(0, (headimgurl.length() - 1), size.getInt() + "")
.toString(); .toString();

View File

@ -1,8 +1,7 @@
package com.foxinmy.weixin4j.mp.model; package com.foxinmy.weixin4j.mp.model;
import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* 微信公众平台信息 * 微信公众平台信息
@ -101,7 +100,7 @@ public class WeixinMpAccount extends WeixinAccount {
public int getVersion() { public int getVersion() {
if (version == 0) { if (version == 0) {
return StringUtils.isNotBlank(mchId) ? 3 : 2; return StringUtil.isNotBlank(mchId) ? 3 : 2;
} }
return version; return version;
} }

View File

@ -3,9 +3,6 @@ package com.foxinmy.weixin4j.mp.payment;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.PayException; import com.foxinmy.weixin4j.exception.PayException;
@ -24,8 +21,10 @@ import com.foxinmy.weixin4j.mp.type.SignType;
import com.foxinmy.weixin4j.mp.type.TradeType; import com.foxinmy.weixin4j.mp.type.TradeType;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.DateUtil; import com.foxinmy.weixin4j.util.DateUtil;
import com.foxinmy.weixin4j.util.DigestUtil;
import com.foxinmy.weixin4j.util.MapUtil; import com.foxinmy.weixin4j.util.MapUtil;
import com.foxinmy.weixin4j.util.RandomUtil; import com.foxinmy.weixin4j.util.RandomUtil;
import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.xml.XmlStream; import com.foxinmy.weixin4j.xml.XmlStream;
/** /**
@ -73,7 +72,7 @@ public class PayUtil {
*/ */
public static String createPayJsRequestJsonV2(PayPackageV2 payPackage, public static String createPayJsRequestJsonV2(PayPackageV2 payPackage,
WeixinMpAccount weixinAccount) { WeixinMpAccount weixinAccount) {
if (StringUtils.isBlank(payPackage.getPartner())) { if (StringUtil.isBlank(payPackage.getPartner())) {
payPackage.setPartner(weixinAccount.getPartnerId()); payPackage.setPartner(weixinAccount.getPartnerId());
} }
JsPayRequestV2 jsPayRequest = new JsPayRequestV2(weixinAccount, JsPayRequestV2 jsPayRequest = new JsPayRequestV2(weixinAccount,
@ -115,8 +114,7 @@ public class PayUtil {
* @return * @return
*/ */
public static String paysignSha(Object obj) { public static String paysignSha(Object obj) {
return DigestUtils return DigestUtil.SHA1(MapUtil.toJoinString(obj, false, true, null));
.sha1Hex(MapUtil.toJoinString(obj, false, true, null));
} }
/** /**
@ -132,8 +130,7 @@ public class PayUtil {
public static String paysignSha(Object obj, String paySignKey) { public static String paysignSha(Object obj, String paySignKey) {
Map<String, String> extra = new HashMap<String, String>(); Map<String, String> extra = new HashMap<String, String>();
extra.put("appKey", paySignKey); extra.put("appKey", paySignKey);
return DigestUtils.sha1Hex(MapUtil return DigestUtil.SHA1(MapUtil.toJoinString(obj, false, true, extra));
.toJoinString(obj, false, true, extra));
} }
/** /**
@ -154,7 +151,7 @@ public class PayUtil {
// stringSignTemp 进行 md5 运算 // stringSignTemp 进行 md5 运算
// 再将得到的 字符串所有字符转换为大写 ,得到 sign signValue // 再将得到的 字符串所有字符转换为大写 ,得到 sign signValue
sb.append("&key=").append(paySignKey); sb.append("&key=").append(paySignKey);
return DigestUtils.md5Hex(sb.toString()).toUpperCase(); return DigestUtil.SHA1(sb.toString()).toUpperCase();
} }
/** /**
@ -224,7 +221,7 @@ public class PayUtil {
*/ */
public static PrePay createPrePay(PayPackageV3 payPackage, String paySignKey) public static PrePay createPrePay(PayPackageV3 payPackage, String paySignKey)
throws PayException { throws PayException {
if (StringUtils.isBlank(payPackage.getSign())) { if (StringUtil.isBlank(payPackage.getSign())) {
payPackage.setSign(paysignMd5(payPackage, paySignKey)); payPackage.setSign(paysignMd5(payPackage, paySignKey));
} }
String payJsRequestXml = XmlStream.to(payPackage).replaceAll("__", "_"); String payJsRequestXml = XmlStream.to(payPackage).replaceAll("__", "_");

View File

@ -2,14 +2,13 @@ package com.foxinmy.weixin4j.mp.payment.coupon;
import java.util.Date; import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.mp.payment.v3.ApiResult; import com.foxinmy.weixin4j.mp.payment.v3.ApiResult;
import com.foxinmy.weixin4j.mp.type.CouponStatus; import com.foxinmy.weixin4j.mp.type.CouponStatus;
import com.foxinmy.weixin4j.mp.type.CouponStockType; import com.foxinmy.weixin4j.mp.type.CouponStockType;
import com.foxinmy.weixin4j.mp.type.CouponType; import com.foxinmy.weixin4j.mp.type.CouponType;
import com.foxinmy.weixin4j.util.DateUtil; import com.foxinmy.weixin4j.util.DateUtil;
import com.foxinmy.weixin4j.util.StringUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
/** /**
@ -315,7 +314,7 @@ public class CouponDetail extends ApiResult {
@JSONField(deserialize = false, serialize = false) @JSONField(deserialize = false, serialize = false)
public Date getFormatUseTime() { public Date getFormatUseTime() {
return StringUtils.isNotBlank(useTime) ? DateUtil return StringUtil.isNotBlank(useTime) ? DateUtil
.parse2yyyyMMddHHmmss(useTime) : null; .parse2yyyyMMddHHmmss(useTime) : null;
} }

View File

@ -2,10 +2,9 @@ package com.foxinmy.weixin4j.mp.payment.v2;
import java.io.Serializable; import java.io.Serializable;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.mp.type.SignType; import com.foxinmy.weixin4j.mp.type.SignType;
import com.foxinmy.weixin4j.util.StringUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
/** /**
@ -68,7 +67,7 @@ public class ApiResult implements Serializable {
} }
public String getRetMsg() { public String getRetMsg() {
return StringUtils.isNotBlank(retMsg) ? retMsg : null; return StringUtil.isNotBlank(retMsg) ? retMsg : null;
} }
public void setRetMsg(String retMsg) { public void setRetMsg(String retMsg) {

View File

@ -2,11 +2,10 @@ package com.foxinmy.weixin4j.mp.payment.v2;
import java.beans.Transient; import java.beans.Transient;
import org.apache.commons.codec.digest.DigestUtils;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.mp.model.WeixinMpAccount; import com.foxinmy.weixin4j.mp.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.payment.PayRequest; import com.foxinmy.weixin4j.mp.payment.PayRequest;
import com.foxinmy.weixin4j.util.DigestUtil;
import com.foxinmy.weixin4j.util.MapUtil; import com.foxinmy.weixin4j.util.MapUtil;
/** /**
@ -48,7 +47,7 @@ public class JsPayRequestV2 extends PayRequest {
// 再将得到的 字符串所有字符转换为大写 ,得到 sign signValue // 再将得到的 字符串所有字符转换为大写 ,得到 sign signValue
sb.append("&key=").append(partnerKey); sb.append("&key=").append(partnerKey);
// c---> & d----> // c---> & d---->
String sign = DigestUtils.md5Hex(sb.toString()).toUpperCase(); String sign = DigestUtil.MD5(sb.toString()).toUpperCase();
sb.delete(0, sb.length()); sb.delete(0, sb.length());
// c.对传入参数中所有键值对的 value 进行 urlencode 转码后重新拼接成字符串 string2 // c.对传入参数中所有键值对的 value 进行 urlencode 转码后重新拼接成字符串 string2
sb.append(MapUtil.toJoinString(payPackage, true, false, null)) sb.append(MapUtil.toJoinString(payPackage, true, false, null))

View File

@ -1,10 +1,9 @@
package com.foxinmy.weixin4j.mp.payment.v2; package com.foxinmy.weixin4j.mp.payment.v2;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.mp.type.RefundChannel; import com.foxinmy.weixin4j.mp.type.RefundChannel;
import com.foxinmy.weixin4j.mp.type.RefundStatus; import com.foxinmy.weixin4j.mp.type.RefundStatus;
import com.foxinmy.weixin4j.util.StringUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
/** /**
@ -123,11 +122,11 @@ public class RefundDetail extends ApiResult {
} }
public String getRecvUserId() { public String getRecvUserId() {
return StringUtils.isNotBlank(recvUserId) ? recvUserId : null; return StringUtil.isNotBlank(recvUserId) ? recvUserId : null;
} }
public String getReccvUserName() { public String getReccvUserName() {
return StringUtils.isNotBlank(reccvUserName) ? reccvUserName : null; return StringUtil.isNotBlank(reccvUserName) ? reccvUserName : null;
} }
@Override @Override

View File

@ -2,9 +2,8 @@ package com.foxinmy.weixin4j.mp.payment.v2;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.util.StringUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamOmitField; import com.thoughtworks.xstream.annotations.XStreamOmitField;
@ -52,7 +51,7 @@ public class RefundRecord extends ApiResult {
} }
public String getOutTradeNo() { public String getOutTradeNo() {
return StringUtils.isNotBlank(outTradeNo) ? outTradeNo : null; return StringUtil.isNotBlank(outTradeNo) ? outTradeNo : null;
} }
public int getCount() { public int getCount() {

View File

@ -1,9 +1,8 @@
package com.foxinmy.weixin4j.mp.payment.v3; package com.foxinmy.weixin4j.mp.payment.v3;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.http.XmlResult; import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.util.StringUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
/** /**
@ -83,7 +82,7 @@ public class ApiResult extends XmlResult {
} }
public String getSubMchId() { public String getSubMchId() {
return StringUtils.isNotBlank(subMchId) ? subMchId : null; return StringUtil.isNotBlank(subMchId) ? subMchId : null;
} }
public void setSubMchId(String subMchId) { public void setSubMchId(String subMchId) {

View File

@ -2,13 +2,12 @@ package com.foxinmy.weixin4j.mp.payment.v3;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.mp.payment.coupon.CouponInfo; import com.foxinmy.weixin4j.mp.payment.coupon.CouponInfo;
import com.foxinmy.weixin4j.mp.type.CurrencyType; import com.foxinmy.weixin4j.mp.type.CurrencyType;
import com.foxinmy.weixin4j.mp.type.RefundChannel; import com.foxinmy.weixin4j.mp.type.RefundChannel;
import com.foxinmy.weixin4j.mp.type.RefundStatus; import com.foxinmy.weixin4j.mp.type.RefundStatus;
import com.foxinmy.weixin4j.util.StringUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAlias;
/** /**
@ -140,7 +139,7 @@ public class RefundDetail extends ApiResult {
@JSONField(deserialize = false, serialize = false) @JSONField(deserialize = false, serialize = false)
public RefundChannel getFormatRefundChannel() { public RefundChannel getFormatRefundChannel() {
if (StringUtils.isNotBlank(refundChannel)) { if (StringUtil.isNotBlank(refundChannel)) {
return RefundChannel.valueOf(refundChannel.toUpperCase()); return RefundChannel.valueOf(refundChannel.toUpperCase());
} }
return null; return null;
@ -170,7 +169,7 @@ public class RefundDetail extends ApiResult {
@JSONField(deserialize = false, serialize = false) @JSONField(deserialize = false, serialize = false)
public RefundStatus getFormatRefundStatus() { public RefundStatus getFormatRefundStatus() {
if (StringUtils.isNotBlank(refundStatus)) { if (StringUtil.isNotBlank(refundStatus)) {
return RefundStatus.valueOf(refundStatus); return RefundStatus.valueOf(refundStatus);
} }
return null; return null;

View File

@ -1,3 +0,0 @@
模拟微信公众平台登陆
(模拟登录|启用开发者模式|修改服务器配置|修改回调地址|启用服务器配置....more)

View File

@ -1,666 +0,0 @@
package com.foxinmy.weixin4j.mp.spider;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.util.IOUtil;
import com.foxinmy.weixin4j.util.RandomUtil;
/**
* 模拟微信公众平台登陆
*
* <p>
* (模拟登录|启用开发者模式|修改服务器配置|修改回调地址|启用服务器配置....more)
* </p>
*
* @className WeixinExecutor
* @author jy
* @date 2014年8月15日
* @since JDK 1.7
* @see
*/
public class WeixinExecutor {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final static Map<String, String> accountMap = new HashMap<String, String>() {
private static final long serialVersionUID = 1L;
{
put("名称", "name");
put("头像", "avatar");
put("登录邮箱", "loginEmail");
put("原始ID", "originalId");
put("微信号", "weixinNo");
put("类型", "accountType");
put("认证情况", "weixinVerify");
put("主体信息", "bodyInfo");
put("介绍", "introduce");
put("所在地址", "address");
put("二维码", "qrcodeUrl");
}
};
private AbstractHttpClient client;
private HttpHost host;
private JSONObject weixin;
// 服务器响应地址
private String pushurl;
// oauth授权回调地址
private String backurl;
// 服务器校验token
private String token;
// 公众号用户名
private String uname;
// 公众号密码
private String pwd;
// 登录时验证码(如果有)
private String imgcode;
// 当要求输入验证码时,cookie需带上
private String sig;
public WeixinExecutor(String backurl, String pushurl, String token,
String uname, String pwd, String imgcode, String sig) {
this.backurl = backurl;
this.pushurl = pushurl;
this.token = token;
this.uname = uname;
this.pwd = pwd;
this.imgcode = StringUtils.isBlank(imgcode) ? "" : imgcode;
this.sig = sig;
weixin = new JSONObject();
weixin.put("host", "mp.weixin.qq.com");
weixin.put("base", "https://mp.weixin.qq.com");
weixin.put("auth", "https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN");
weixin.put(
"call",
"https://mp.weixin.qq.com/advanced/callbackprofile?t=ajax-response&token=%s&lang=zh_CN");
weixin.put("start",
"https://mp.weixin.qq.com/misc/skeyform?form=advancedswitchform");
weixin.put("back",
"https://mp.weixin.qq.com/merchant/myservice?action=set_oauth_domain&f=json");
weixin.put("verifycode",
"https://mp.weixin.qq.com/cgi-bin/verifycode?username=" + uname
+ "&r=%s");
weixin.put("bedeveloper",
"https://mp.weixin.qq.com/advanced/advanced?action=agreement");
List<BasicHeader> headers = new ArrayList<BasicHeader>();
headers.add(new BasicHeader("Origin", weixin.getString("base")));
headers.add(new BasicHeader("Connection", "keep-alive"));
headers.add(new BasicHeader(
"User-Agent",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36"));
client = new DefaultHttpClient();
client.getParams().setParameter(ClientPNames.COOKIE_POLICY,
CookiePolicy.BROWSER_COMPATIBILITY);
client.getParams().setBooleanParameter(
"http.protocol.single-cookie-header", true);
client.getParams().setParameter(ClientPNames.DEFAULT_HEADERS, headers);
host = new HttpHost(weixin.getString("host"), -1, "https");
}
public JSONObject process() {
// 1.登陆微信公众号
step1_login();
int code = weixin.getIntValue("code");
if (code == 0) {
// 2.收集相关信息
step2_collect();
code = weixin.getIntValue("code");
// 3.填写服务器配置
// 3-1.未初始化账号
// 3-2.已配置账号
if (code == 0) {
step3_setting();
}
code = weixin.getIntValue("code");
// 4.修改网页授权地址
if (code == 0) {
step4_back();
}
// 5.创建底部菜单 (调用封装好的API)
// 5-1.订阅号
// 5-2.服务号
// 6.完成
}
return weixin;
}
/**
* step1:登录操作
*/
private void step1_login() {
HttpPost method = new HttpPost(weixin.getString("auth"));
try {
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("username", uname));
parameters.add(new BasicNameValuePair("pwd", DigestUtils.md5Hex(pwd
.getBytes(Consts.UTF_8))));
parameters.add(new BasicNameValuePair("f", "json"));
parameters.add(new BasicNameValuePair("imgcode", imgcode));
if (!StringUtils.isBlank(imgcode)) {
method.addHeader("Cookie", "sig=" + sig);
}
method.setEntity(new UrlEncodedFormEntity(parameters, Consts.UTF_8));
method.addHeader("Referer", weixin.getString("base"));
HttpResponse response = client.execute(host, method);
HttpEntity entity = response.getEntity();
Document root = Jsoup.parse(entity.getContent(),
Consts.UTF_8.name(), weixin.getString("base"));
StatusLine line = response.getStatusLine();
logger.info("step1_login--->status={},body=\n{}", line,
root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
JSONObject body = JSON.parseObject(root.body().text());
String msg = "";
int code = 0;
switch (body.getIntValue("ret")
+ body.getJSONObject("base_resp").getIntValue("ret")) {
case -1:
msg = "系统错误,请稍候再试。";
code = -1;
break;
case -2:
msg = "帐号或密码错误。";
code = 100;
break;
case -23:
msg = "您输入的帐号或者密码不正确,请重新输入。";
code = 101;
break;
case -21:
msg = "不存在该帐户。";
code = 102;
break;
case -7:
msg = "您目前处于访问受限状态。";
code = 103;
break;
case -8:
msg = "请输入图中的验证码";
code = 104;
break;
case -27:
msg = "您输入的验证码不正确,请重新输入";
code = 105;
break;
case -26:
msg = "该公众会议号已经过期,无法再登录使用。";
code = 106;
break;
case 0:
msg = "成功登录,正在跳转...";
break;
case -25:
msg = "海外帐号请在公众平台海外版登录,<a href=\"http://admin.wechat.com/\">点击登录</a>";
code = 107;
break;
default:
msg = "未知错误";
code = 108;
break;
}
if (code == 0) {
weixin.put(
"urlToken",
getQueryMap(body.getString("redirect_url")).get(
"token"));
weixin.put("indexUrl", String.format("%s%s",
weixin.getString("base"),
body.getString("redirect_url")));
weixin.put("step", "1");
} else {
if (code == 104 || code == 105) {
// 下载验证码
HttpGet get = new HttpGet(String.format(
weixin.getString("verifycode"),
System.currentTimeMillis()));
get.setHeaders(method.getAllHeaders());
response = client.execute(host, get);
StringBuffer base64 = new StringBuffer();
base64.append("data:")
.append(response.getFirstHeader("Content-Type")
.getValue()).append(";base64,");
base64.append(new String(
Base64.encodeBase64(IOUtil.toByteArray(response
.getEntity().getContent())),
Consts.UTF_8));
weixin.put("verifydata", base64.toString());
List<Cookie> cookieList = client.getCookieStore()
.getCookies();
for (Cookie cookie : cookieList) {
if (cookie.getName().equals("sig")) {
weixin.put("sig", cookie.getValue());
break;
}
}
}
weixin.put("code", code);
weixin.put("msg", msg);
}
} else {
weixin.put("code", "-3");
weixin.put("msg", "网络异常,请稍后重试!");
}
} catch (Exception e) {
weixin.put("code", "-2");
weixin.put("msg", "服务器繁忙,请稍后重试!");
weixin.put("exception", e.getMessage());
logger.error("step1_login catch error", e);
} finally {
if (weixin.getIntValue("code") != 0) {
client.getConnectionManager().shutdown();
}
}
}
/**
* step2:收集信息
*/
private void step2_collect() {
String url = weixin.getString("indexUrl");
HttpGet method = new HttpGet(url);
try {
method.addHeader("Referer", weixin.getString("base"));
HttpResponse response = client.execute(host, method);
HttpEntity entity = response.getEntity();
Document root = Jsoup.parse(entity.getContent(),
Consts.UTF_8.name(), weixin.getString("base"));
StatusLine line = response.getStatusLine();
logger.info("step2_setting--->status={},body=\n{}", line,
root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
Element ele = root.getElementById("menuBar")
.getElementsByTag("dl").last();
url = ele.getElementsByTag("a").last().absUrl("href");
weixin.put("developerUrl", url);
method.addHeader("Referer", url);
url = ele.previousElementSibling().getElementsByTag("a")
.first().absUrl("href");
weixin.put("settingUrl", url);
method.setURI(URI.create(url));
response = client.execute(host, method);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(), Consts.UTF_8.name(),
weixin.getString("base"));
line = response.getStatusLine();
weixin.put("step", "2-1");
// 公众号配置页面
if (line.getStatusCode() == HttpStatus.SC_OK) {
Elements eles = root.getElementById("settingArea")
.getElementsByTag("li");
String key, value;
for (Element element : eles) {
key = element.getElementsByTag("h4").first().text();
ele = element.getElementsByClass("meta_content")
.first();
if (ele.children().isEmpty()) {
value = ele.text();
} else {
if (ele.child(0).tagName().equalsIgnoreCase("a")) {
value = ele.child(0).absUrl("href");
} else if (ele.child(0).tagName()
.equalsIgnoreCase("img")) {
value = ele.child(0).absUrl("src");
} else {
value = ele.text();
}
}
weixin.put(accountMap.get(key), value);
}
weixin.put("isVerify", weixin.getString("weixinVerify")
.contains("微信认证"));
weixin.put("isService", weixin.getString("accountType")
.contains("服务号"));
weixin.put("isSubscribe", weixin.getString("accountType")
.contains("订阅号"));
value = weixin.getString("qrcodeUrl");
method.setURI(URI.create(value));
response = client.execute(host, method);
weixin.put("qrcodeData", IOUtil.toByteArray(response
.getEntity().getContent()));
weixin.put("step", "2-2");
// 开发者页面
method.addHeader("Referer", url);
method.setURI(URI.create(weixin.getString("developerUrl")));
response = client.execute(host, method);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(),
Consts.UTF_8.name(), weixin.getString("base"));
line = response.getStatusLine();
if (line.getStatusCode() == HttpStatus.SC_OK) {
// 还没有成为开发者 2014.10-06 jy.hu
// 触发成为开发者动作
ele = root.getElementById("js_toBeDeveloper");
if (ele != null && ele.hasText()) {
HttpPost post = new HttpPost(URI.create(weixin
.getString("bedeveloper")));
post.addHeader("Referer", url);
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("token",
weixin.getString("urlToken")));
parameters.add(new BasicNameValuePair("f", "json"));
parameters.add(new BasicNameValuePair("ajax", "1"));
parameters.add(new BasicNameValuePair("lang",
"zh_CN"));
parameters.add(new BasicNameValuePair("random",
System.currentTimeMillis() + ""));
post.setEntity(new UrlEncodedFormEntity(parameters,
Consts.UTF_8));
response = client.execute(host, post);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(),
Consts.UTF_8.name(),
weixin.getString("base"));
line = response.getStatusLine();
logger.info(
"step2_bedeveloper--->status={},body=\n{}",
line, root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
JSONObject body = JSON.parseObject(root.body()
.text());
if (body.getIntValue("ret") == 0) {
method.addHeader("Referer", url);
method.setURI(URI.create(weixin
.getString("developerUrl")));
response = client.execute(host, method);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(),
Consts.UTF_8.name(),
weixin.getString("base"));
} else {
weixin.put("code", "-100");
weixin.put("msg", "成为开发者失败!");
return;
}
}
}
// 初始化状态
// 配置未启用状态
// 配置已启用状态
eles = root.getElementsByClass("developer_info_opr");
if (eles != null && eles.hasText()) {
weixin.put("developerModifyUrl", eles.first()
.children().first().absUrl("href"));
weixin.put("status",
eles.text().contains("启用") ? "READY"
: "RUNNING");
} else {
weixin.put("status", "INIT");
}
// appid&appsecret
if (weixin.getBooleanValue("isService")
|| (weixin.getBooleanValue("isSubscribe") && weixin
.getBooleanValue("isVerify"))) {
eles = root
.getElementsByClass("developer_info_item")
.first().children().last()
.getElementsByClass("frm_controls");
weixin.put("appId", eles.first().text());
weixin.put("appSecret",
eles.last().text().replace("重置", "").trim());
}
weixin.put("step", "2-3");
}
} else {
weixin.put("code", "-3");
weixin.put("msg", "网络异常,请稍后重试!");
}
} else {
weixin.put("code", "-3");
weixin.put("msg", "网络异常,请稍后重试!");
}
} catch (Exception e) {
weixin.put("code", "-2");
weixin.put("msg", "服务器繁忙,请稍后重试!");
weixin.put("exception", e.getMessage());
logger.error("step2_collect catch error", e);
} finally {
if (weixin.getIntValue("code") != 0) {
client.getConnectionManager().shutdown();
}
}
}
/**
* step3:填写配置
*/
private void step3_setting() {
HttpPost method = new HttpPost(String.format(weixin.getString("call"),
weixin.getString("urlToken")));
try {
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("url", pushurl));
parameters.add(new BasicNameValuePair("callback_token", token));
// EncodingAESKey | 消息加解密方式(明文0,兼容1,安全2)
parameters.add(new BasicNameValuePair("encoding_aeskey", RandomUtil
.generateString(43)));
parameters
.add(new BasicNameValuePair("callback_encrypt_mode", "0"));
parameters.add(new BasicNameValuePair("operation_seq", RandomUtil
.generateStringByNumberChar(9)));
method.setEntity(new UrlEncodedFormEntity(parameters, Consts.UTF_8));
method.addHeader("Referer", weixin.getString("developerModifyUrl"));
HttpResponse response = client.execute(host, method);
HttpEntity entity = response.getEntity();
Document root = Jsoup.parse(entity.getContent(),
Consts.UTF_8.name(), weixin.getString("base"));
StatusLine line = response.getStatusLine();
logger.info("step3_setting--->status={},body=\n{}", line,
root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
JSONObject body = JSON.parseObject(root.body().text());
String msg = "";
int code = 0;
switch (body.getIntValue("ret")
+ body.getJSONObject("base_resp").getIntValue("ret")) {
case -201:
msg = "无效的URL";
code = 200;
break;
case -202:
msg = "无效的Token";
code = 201;
break;
case -203:
msg = "操作频率太快,请休息一下。";
code = 202;
break;
case -204:
msg = "请先在设置页面完善当前帐号信息";
code = 203;
break;
case -205:
msg = "该URL可能存在安全风险请检查";
code = 207;
break;
case -301:
msg = "请求URL超时";
code = 204;
break;
case -302:
msg = "服务器没有正确响应Token验证请稍后重试";
code = 205;
break;
case -104:
msg = "参数错误,请重新填写。";
code = 206;
break;
case 0:
msg = "配置成功..";
break;
default:
msg = "未知错误";
code = 108;
break;
}
if (code == 0) {
// 触发启用按钮
if (!weixin.getString("status").equals("RUNNING")) {
parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("token", weixin
.getString("urlToken")));
parameters.add(new BasicNameValuePair("f", "json"));
parameters.add(new BasicNameValuePair("ajax", "1"));
parameters.add(new BasicNameValuePair("flag", "1"));
parameters.add(new BasicNameValuePair("type", "2"));
parameters.add(new BasicNameValuePair("lang", "zh_CN"));
parameters.add(new BasicNameValuePair("random", System
.currentTimeMillis() + ""));
method.setEntity(new UrlEncodedFormEntity(parameters,
Consts.UTF_8));
method.setURI(URI.create(weixin.getString("start")));
response = client.execute(host, method);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(),
Consts.UTF_8.name(), weixin.getString("base"));
line = response.getStatusLine();
logger.info("step3_setting--->status={},body=\n{}",
line, root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
body = JSON.parseObject(root.body().text());
if (body.getIntValue("ret")
+ body.getJSONObject("base_resp")
.getIntValue("ret") != 0) {
weixin.put("code", 300);
weixin.put("msg", "启用开发者模式失败,请稍后再试!");
}
}
}
weixin.put("step", "3");
} else {
weixin.put("code", code);
weixin.put("msg", msg);
}
} else {
weixin.put("code", "-3");
weixin.put("msg", "网络异常,请稍后重试!");
}
} catch (Exception e) {
weixin.put("code", "-2");
weixin.put("msg", "服务器繁忙,请稍后重试!");
weixin.put("exception", e.getMessage());
logger.error("step3_setting catch error", e);
} finally {
if (weixin.getIntValue("code") != 0) {
client.getConnectionManager().shutdown();
}
}
}
/**
* step4:修改回调
*/
private void step4_back() {
try {
if (weixin.getBooleanValue("isVerify")) {
HttpPost method = new HttpPost(weixin.getString("back"));
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("domain", backurl));
parameters.add(new BasicNameValuePair("token", weixin
.getString("urlToken")));
parameters.add(new BasicNameValuePair("f", "json"));
parameters.add(new BasicNameValuePair("ajax", "1"));
parameters.add(new BasicNameValuePair("flag", "1"));
parameters.add(new BasicNameValuePair("lang", "zh_CN"));
parameters.add(new BasicNameValuePair("random", System
.currentTimeMillis() + ""));
method.setEntity(new UrlEncodedFormEntity(parameters,
Consts.UTF_8));
method.addHeader("Referer", weixin.getString("developerUrl"));
HttpResponse response = client.execute(host, method);
HttpEntity entity = response.getEntity();
Document root = Jsoup.parse(entity.getContent(),
Consts.UTF_8.name(), weixin.getString("base"));
StatusLine line = response.getStatusLine();
logger.info("step4_back--->status={},body=\n{}", line,
root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
JSONObject body = JSON.parseObject(root.body().text());
if (body.getIntValue("ret")
+ body.getJSONObject("base_resp")
.getIntValue("ret") != 0) {
weixin.put("code", "400");
weixin.put("msg", "修改授权回调地址失败!");
}
weixin.put("step", "4");
}
} else {
logger.info("公众号尚未认证,放弃本次修改授权回调地址操作。{}", weixin);
}
} catch (Exception e) {
weixin.put("code", "-2");
weixin.put("msg", "服务器繁忙,请稍后重试!");
weixin.put("exception", e.getMessage());
logger.error("step4_back catch error", e);
} finally {
client.getConnectionManager().shutdown();
}
}
private Map<String, String> getQueryMap(String query) {
String[] params = query.split("&");
Map<String, String> map = new HashMap<String, String>();
for (String param : params) {
String name = param.split("=")[0];
String value = param.split("=")[1];
map.put(name, value);
}
return map;
}
}

View File

@ -1,55 +0,0 @@
package com.foxinmy.weixin4j.mp.type;
/**
* 公众号事件类型
*
* @className EventType
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see
*/
public enum EventType {
/**
* 二维码扫描事件
*
* @see com.foxinmy.weixin4j.mp.event.ScanEventMessage
*/
scan,
/**
* 群发消息事件
*
* @see com.foxinmy.weixin4j.mp.event.MassEventMessage
*/
masssendjobfinish,
/**
* 模板消息事件
*
* @see com.foxinmy.weixin4j.mp.event.TemplatesendjobfinishMessage
*/
templatesendjobfinish,
/**
* 客服接入会话事件
*
* @see com.foxinmy.weixin4j.mp.event.KfCreateEventMessage
*/
kf_create_session,
/**
* 客服关闭会话事件
*
* @see com.foxinmy.weixin4j.mp.event.KfCloseEventMessage
*/
kf_close_session,
/**
* 客服转接会话事件
*
* @see com.foxinmy.weixin4j.mp.event.KfSwitchEventMessage
*/
kf_switch_session,
/**
* 异步任务完成事件
*
* @see com.foxinmy.weixin4j.mp.event.BatchjobresultMessage
*/
batch_job_result;
}

View File

@ -11,7 +11,6 @@ import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont; import org.apache.poi.hssf.usermodel.HSSFFont;
@ -32,6 +31,7 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* excel工具类 * excel工具类
@ -55,7 +55,7 @@ public class ExcelUtil {
*/ */
public static String[][] read(File file) throws Exception { public static String[][] read(File file) throws Exception {
String fileExt = getExtension(file.getName()); String fileExt = getExtension(file.getName());
if (StringUtils.isNotBlank(fileExt)) { if (StringUtil.isNotBlank(fileExt)) {
if (fileExt.toLowerCase().equals("xls")) {// 2003 if (fileExt.toLowerCase().equals("xls")) {// 2003
BufferedInputStream in = new BufferedInputStream( BufferedInputStream in = new BufferedInputStream(
new FileInputStream(file)); new FileInputStream(file));
@ -75,7 +75,7 @@ public class ExcelUtil {
public static String[][] read4Special(File file, String fileName, public static String[][] read4Special(File file, String fileName,
int columnSize) throws Exception { int columnSize) throws Exception {
String fileExt = getExtension(fileName); String fileExt = getExtension(fileName);
if (StringUtils.isNotBlank(fileExt)) { if (StringUtil.isNotBlank(fileExt)) {
if (fileExt.toLowerCase().equals("xls")) {// 2003 if (fileExt.toLowerCase().equals("xls")) {// 2003
BufferedInputStream in = new BufferedInputStream( BufferedInputStream in = new BufferedInputStream(
new FileInputStream(file)); new FileInputStream(file));

View File

@ -0,0 +1,323 @@
package com.foxinmy.weixin4j.mp.util;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.PayException;
import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.model.Consts;
import com.foxinmy.weixin4j.mp.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.payment.JsPayNotify;
import com.foxinmy.weixin4j.mp.payment.PayPackage;
import com.foxinmy.weixin4j.mp.payment.PayUtil;
import com.foxinmy.weixin4j.mp.payment.conver.CouponConverter;
import com.foxinmy.weixin4j.mp.payment.v2.NativePayNotifyV2;
import com.foxinmy.weixin4j.mp.payment.v2.NativePayResponseV2;
import com.foxinmy.weixin4j.mp.payment.v2.PayFeedback;
import com.foxinmy.weixin4j.mp.payment.v2.PayPackageV2;
import com.foxinmy.weixin4j.mp.payment.v2.PayWarn;
import com.foxinmy.weixin4j.mp.payment.v3.NativePayNotifyV3;
import com.foxinmy.weixin4j.mp.payment.v3.NativePayResponseV3;
import com.foxinmy.weixin4j.mp.payment.v3.PayPackageV3;
import com.foxinmy.weixin4j.mp.type.TradeType;
import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.xml.XmlStream;
/**
* 支付示例
*
* @className PayDemo
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see
*/
public final class PayDemo {
private final Logger log = LoggerFactory.getLogger(getClass());
/**
* JSAPI支付
*
* @return
*/
public JSONObject jsPay() {
JSONObject obj = new JSONObject();
WeixinMpAccount weixinAccount = JSON.parseObject(
ConfigUtil.getValue("account"), WeixinMpAccount.class);
// V3 支付
PayPackage payPackage = new PayPackageV3(weixinAccount, "用户openid",
"商品描述", "系统内部订单号", 1d, "IP地址", TradeType.JSAPI);
// V2 支付
payPackage = new PayPackageV2("商品描述", weixinAccount.getPartnerId(),
"系统内部订单号", 1d, "回调地址", "IP地址");
payPackage.setAttach("ID");
String jspay = null;
try {
jspay = PayUtil.createPayJsRequestJson(payPackage, weixinAccount);
} catch (PayException e) {
log.error("create jspay error,{}", weixinAccount, e);
}
if (StringUtil.isBlank(jspay)) {
obj.put("code", "-2");
obj.put("msg", "创建支付链接失败!");
return obj;
}
obj.put("code", "0");
obj.put("jspay", jspay);
/*
* 编辑收货地址 SnsToken token = (SnsToken) getSession("AccessToken");
* obj.put("editaddress", PayUtil.createAddressRequestJson(
* wx.getAppId(), getFullLoction(), token.getAccess_token()));
*/
log.info("js pay....{}", obj);
return obj;
}
/**
* JSAPI(V2)支付成功(前端)时的回调通知<br>
* &ltxml&gt</br> &ltOpenId&gt&lt![CDATA[111222]]&gt&lt/OpenId&gt</br>
* &ltAppId&gt&lt![CDATA[wwwwb4f85f3a797777]]&gt&lt/AppId&gt</br>
* &ltIsSubscribe&gt1&lt/IsSubscribe&gt</br>
* &ltTimeStamp&gt1369743511&lt/TimeStamp&gt</br>
* &ltNonceStr&gt&lt![CDATA[jALldRTHAFd5Tgs5]]&gt&lt/NonceStr&gt</br>
* &ltAppSignature>&lt![CDATA[bafe07f060f22dcda0bfdb4b5ff756f973aecffa]]&gt
* &lt/AppSignature&gt</br>
* &ltSignMethod>&lt![CDATA[sha1]]&gt&lt/SignMethod&gt</br> &lt/xml&gt</br>
* 参与签名的字段为: appidappkeytimestampnoncestropenidissubscribe
*
* @param 订单信息
* @param inputStream
* 用户信息
*
* @see com.foxinmy.weixin4j.mp.payment.JsPayNotify
* @return success或其他
*/
public String jsNotifyV2(InputStream inputStream) {
Map<String, String> objMap = new HashMap<String, String>();
/*
* 收集url中携带的参数 /pay/notify/back?attach=8&bank_billno=201410293351060&
* bank_type=2032&discount=0&fee_type=1&input_charset=UTF-8&
* notify_id=9fKbVf_qg6y-
* wSjtSMV0PLXeEn2oGfTM1s9dWSvR2B9U6iFQRTzmjrMWKUxvh9mpBLvnh8aqFbC_OFk1pTvFnFUO00Lln4fh
* & out_trade_no=D14102900031&partner=1221928801&product_fee=1&
* sign=B9D6E772C271C9B86B8436FC9F5DFC1A&
* sign_type=MD5&time_end=20141029183707&
* total_fee=1&trade_mode=1&trade_state=0&
* transaction_id=1221928801201410296039230054&transport_fee=0
*/
log.info("jspay_notify_orderinfo,{}", objMap);
JsPayNotify payNotify = XmlStream.get(inputStream, JsPayNotify.class);
log.info("jspay_notify_userinfo,{}", payNotify);
WeixinMpAccount weixinAccount = JSON.parseObject(
ConfigUtil.getValue("account"), WeixinMpAccount.class);
// 验证财付通签名
String sign = objMap.get("sign");
objMap.remove("sign");
String _sign = PayUtil
.paysignMd5(objMap, weixinAccount.getPartnerKey());
log.info("财付通签名----->sign={},vaild_sign={}", sign, _sign);
if (!sign.equals(_sign)) {
return "fail";
}
objMap.clear();
// 验证微信签名
sign = payNotify.getPaySign();
payNotify.setPaySign(null);
payNotify.setSignType(null);
String vaild_sign = PayUtil.paysignSha(payNotify,
weixinAccount.getPaySignKey());
log.info("微信签名----->sign={},vaild_sign={}", sign, vaild_sign);
if (!sign.equals(vaild_sign)) {
return "fail";
}
// 处理业务逻辑
return "success";
}
/**
* JSAPI(V3)支付成功(前端)时的回调通知
*
*
* @param inputStream
* 订单回调
* @return &ltxml&gt<br>
* &ltreturn_code&gtSUCCESS/FAIL&lt/return_code&gt<br>
* &ltreturn_msg&gt如非空,为错误 原因签名失败参数格式校验错误&lt/return_msg&gt<br>
* &lt/xml&gt
* @throws DocumentException
* @see <a
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7">支付结果通知</a>
*/
public String jsNotifyV3(InputStream inputStream) {
String orderXml = "从inputStream中读取订单信息";
com.foxinmy.weixin4j.mp.payment.v3.Order order = CouponConverter
.fromXML(orderXml,
com.foxinmy.weixin4j.mp.payment.v3.Order.class);
log.info("jsapi_notify_order_info:", order);
String sign = order.getSign();
order.setSign(null);
WeixinMpAccount weixinAccount = JSON.parseObject(
ConfigUtil.getValue("account"), WeixinMpAccount.class);
String valid_sign = PayUtil.paysignMd5(order,
weixinAccount.getPaySignKey());
// 如果订单中存在代金券的情况并不适用
log.info("微信签名----->sign={},vaild_sign={}", sign, valid_sign);
if (!sign.equals(valid_sign)) {
return XmlStream.to(new XmlResult(Consts.FAIL, "签名错误"));
}
// 处理业务逻辑
return XmlStream.to(new XmlResult(Consts.SUCCESS, ""));
}
/**
* V2.x版本Native支付时POST数据<br>
* &ltxml&gt</br> &ltOpenId&gt&lt![CDATA[111222]]&gt&lt/OpenId&gt</br>
* &ltAppId&gt&lt![CDATA[wwwwb4f85f3a797777]]&gt&lt/AppId&gt</br>
* &ltIsSubscribe&gt1&lt/IsSubscribe&gt</br>
* &ltProductId&gt[CDATA[000000]]&lt/ProductId&gt</br>
* &ltTimeStamp&gt1369743511&lt/TimeStamp&gt</br>
* &ltNonceStr&gt&lt![CDATA[jALldRTHAFd5Tgs5]]&gt&lt/NonceStr&gt</br>
* &ltAppSignature>&lt![CDATA[bafe07f060f22dcda0bfdb4b5ff756f973aecffa]]&gt
* &lt/AppSignature&gt</br>
* &ltSignMethod>&lt![CDATA[sha1]]&gt&lt/SignMethod&gt</br> &lt/xml&gt</br>
* 参与签名的字段为: appidappkeytimestampnoncestropenidissubscribeproductId
*
* @param inputStream
*
* @return 必须返回一个带有Package信息的xml字符串
*/
public String nativeNotifyV2(InputStream inputStream) {
// V2.x版本
NativePayNotifyV2 payNotify = XmlStream.get(inputStream,
NativePayNotifyV2.class);
log.info("native_pay_notify,{}", payNotify);
WeixinMpAccount weixinAccount = JSON.parseObject(
ConfigUtil.getValue("account"), WeixinMpAccount.class);
String sign = payNotify.getPaySign();
payNotify.setPaySign(null);
payNotify.setSignType(null);
// 验证微信签名
String vaild_sign = PayUtil.paysignSha(payNotify,
weixinAccount.getPaySignKey());
log.info("微信签名----->sign={},vaild_sign={}", sign, vaild_sign);
if (!sign.equals(vaild_sign)) {
return "fail";
}
// 构造订单信息
PayPackageV2 payPackage = new PayPackageV2("商品描述",
weixinAccount.getPartnerId(), "系统内部订单号", 1d, "回调地址", "IP地址");
NativePayResponseV2 payResponse = new NativePayResponseV2(
weixinAccount, payPackage);
return XmlStream.to(payResponse);
}
/**
* V3.x版本native回调<br>
* &ltxml&gt</br> &ltopenid&gt&lt![CDATA[111222]]&gt&lt/openid&gt</br>
* &ltappid&gt&lt![CDATA[wwwwb4f85f3a797777]]&gt&lt/appid&gt</br>
* &ltmch_id&gt&lt![CDATA[1100022]]&gt&lt/mch_id&gt</br>
* &ltis_subscribe&gt1&lt/is_subscribe&gt</br>
* &ltproduct_id&gt[CDATA[000000]]&lt/product_id&gt</br>
* &ltnonce_str&gt&lt![CDATA[jALldRTHAFd5Tgs5]]&gt&lt/nonce_str&gt</br>
* &ltsign>&lt![CDATA[bafe07f060f22dcda0bfdb4b5ff756f973aecffa]]&gt
* &lt/sign&gt</br> &lt/xml&gt</br>
*
* @return
* @throws PayException
*/
public String nativeNotifyV3(InputStream inputStream) throws PayException {
NativePayNotifyV3 payNotify = XmlStream.get(inputStream,
NativePayNotifyV3.class);
String sign = payNotify.getSign();
payNotify.setSign(null);
WeixinMpAccount weixinAccount = JSON.parseObject(
ConfigUtil.getValue("account"), WeixinMpAccount.class);
String valid_sign = PayUtil.paysignMd5(payNotify,
weixinAccount.getPaySignKey());
log.info("微信签名----->sign={},vaild_sign={}", sign, valid_sign);
// 生成Package
PayPackageV3 payPackage = new PayPackageV3(weixinAccount, "用户openid",
"商品描述", "系统内部订单号", 1d, "IP地址", TradeType.NATIVE);
payPackage.setProductId(payNotify.getProductId());
if (!sign.equals(valid_sign)) {
// 校验失败
NativePayResponseV3 payReponse = new NativePayResponseV3("签名失败",
null);
payReponse.setSign(PayUtil.paysignMd5(payReponse,
weixinAccount.getPaySignKey()));
return XmlStream.to(payReponse);
}
// 成功返回
NativePayResponseV3 payReponse = new NativePayResponseV3(payPackage,
weixinAccount.getPaySignKey());
payReponse.setSign(PayUtil.paysignMd5(payReponse,
weixinAccount.getPaySignKey()));
return XmlStream.to(payReponse);
}
/**
* 告警通知 需要成功返回 success </br> &ltxml&gt</br>
* &ltAppId&gt&lt![CDATA[wxf8b4f85f3a794e77]]&gt&lt/AppId&gt</br>
* &ltErrorType&gt1001&lt/ErrorType&gt</br>
* &ltDescription&gt&lt![CDATA[错误描述]]>&lt/Description&gt</br>
* &ltAlarmContent&gt&lt![CDATA[错误详情]]>&lt/AlarmContent&gt</br>
* &ltTimeStamp&gt1393860740&lt/TimeStamp&gt</br>
* &ltAppSignature&gt&lt![CDATA[签名方式跟JsPayRequest中的paySign一样]]&gt&lt/
* AppSignature&gt</br>
* &ltSignMethod&gt&lt![CDATA[sha1]]&gt&lt/SignMethod&gt</br>
* &lt/xml&gt</br>
* 参与签名字段:alarmcontentappidappkeydescriptionerrortypetimestamp
*
* @param inputStream
* xml数据
* @see com.foxinmy.weixin4j.mp.payment.v2.PayWarn
* @return
*/
public String warning(InputStream inputStream) {
PayWarn payWarn = XmlStream.get(inputStream, PayWarn.class);
log.info("pay_warning,{}", payWarn);
WeixinMpAccount weixinAccount = JSON.parseObject(
ConfigUtil.getValue("account"), WeixinMpAccount.class);
String sign = payWarn.getPaySign();
payWarn.setPaySign(null);
payWarn.setSignType(null);
// 验证微信签名
String vaild_sign = PayUtil.paysignSha(payWarn,
weixinAccount.getPaySignKey());
log.info("微信签名----->sign={},vaild_sign={}", sign, vaild_sign);
return "success";
}
/**
* 用户维权
*
* @param inputStream
* @see com.foxinmy.weixin4j.mp.payment.v2.PayFeedback
* @return
*/
public String feedback(InputStream inputStream) {
PayFeedback feedback = XmlStream.get(inputStream, PayFeedback.class);
log.info("pay_feedback_info:{}", feedback);
WeixinMpAccount weixinAccount = JSON.parseObject(
ConfigUtil.getValue("account"), WeixinMpAccount.class);
// 验证微信签名
Map<String, String> obj = new HashMap<String, String>();
obj.put("openid", feedback.getOpenId());
obj.put("appid", feedback.getAppId());
obj.put("timestamp", feedback.getTimeStamp());
obj.put("appkey", weixinAccount.getPaySignKey());
String sign = PayUtil.paysignSha(obj);
log.info("微信签名----->sign={},vaild_sign={}", sign, feedback.getPaySign());
return "success";
}
}

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.test.msg; package com.foxinmy.weixin4j.mp.test;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -16,7 +16,6 @@ import com.foxinmy.weixin4j.mp.api.CustomApi;
import com.foxinmy.weixin4j.mp.model.CustomRecord; import com.foxinmy.weixin4j.mp.model.CustomRecord;
import com.foxinmy.weixin4j.mp.model.KfAccount; import com.foxinmy.weixin4j.mp.model.KfAccount;
import com.foxinmy.weixin4j.mp.model.KfSession; import com.foxinmy.weixin4j.mp.model.KfSession;
import com.foxinmy.weixin4j.mp.test.TokenTest;
/** /**
* 客服消息测试 * 客服消息测试

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.test.msg; package com.foxinmy.weixin4j.mp.test;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -13,8 +13,6 @@ import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.mp.api.MassApi; import com.foxinmy.weixin4j.mp.api.MassApi;
import com.foxinmy.weixin4j.mp.api.MediaApi; import com.foxinmy.weixin4j.mp.api.MediaApi;
import com.foxinmy.weixin4j.mp.event.MassEventMessage;
import com.foxinmy.weixin4j.mp.test.TokenTest;
import com.foxinmy.weixin4j.tuple.Image; import com.foxinmy.weixin4j.tuple.Image;
import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.tuple.MpArticle;
import com.foxinmy.weixin4j.tuple.Text; import com.foxinmy.weixin4j.tuple.Text;
@ -30,7 +28,7 @@ import com.foxinmy.weixin4j.type.MediaType;
* @since JDK 1.7 * @since JDK 1.7
* @see * @see
*/ */
public class MassMsgTest extends TokenTest { public class MassTest extends TokenTest {
private MassApi massApi; private MassApi massApi;
private MediaApi mediaApi; private MediaApi mediaApi;
@ -107,7 +105,6 @@ public class MassMsgTest extends TokenTest {
public void getMassNews() throws WeixinException { public void getMassNews() throws WeixinException {
String status = massApi.getMassNews("82358"); String status = massApi.getMassNews("82358");
System.out.println(status); System.out.println(status);
System.out.println(MassEventMessage.getStatusDesc(status));
Assert.assertNotNull(status); Assert.assertNotNull(status);
} }
} }

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.test.msg; package com.foxinmy.weixin4j.mp.test;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -12,7 +12,6 @@ import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.mp.api.MediaApi; import com.foxinmy.weixin4j.mp.api.MediaApi;
import com.foxinmy.weixin4j.mp.api.NotifyApi; import com.foxinmy.weixin4j.mp.api.NotifyApi;
import com.foxinmy.weixin4j.mp.message.NotifyMessage; import com.foxinmy.weixin4j.mp.message.NotifyMessage;
import com.foxinmy.weixin4j.mp.test.TokenTest;
import com.foxinmy.weixin4j.tuple.Image; import com.foxinmy.weixin4j.tuple.Image;
import com.foxinmy.weixin4j.tuple.Music; import com.foxinmy.weixin4j.tuple.Music;
import com.foxinmy.weixin4j.tuple.News; import com.foxinmy.weixin4j.tuple.News;
@ -30,7 +29,7 @@ import com.foxinmy.weixin4j.type.MediaType;
* @since JDK 1.7 * @since JDK 1.7
* @see * @see
*/ */
public class NotifyMsgTest extends TokenTest { public class NotifyTest extends TokenTest {
private NotifyApi notifyApi; private NotifyApi notifyApi;
private MediaApi mediaApi; private MediaApi mediaApi;

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.test.msg; package com.foxinmy.weixin4j.mp.test;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
@ -8,10 +8,9 @@ import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.mp.api.TmplApi; import com.foxinmy.weixin4j.mp.api.TmplApi;
import com.foxinmy.weixin4j.mp.message.TemplateMessage; import com.foxinmy.weixin4j.mp.message.TemplateMessage;
import com.foxinmy.weixin4j.mp.test.TokenTest;
import com.foxinmy.weixin4j.mp.type.IndustryType; import com.foxinmy.weixin4j.mp.type.IndustryType;
public class TemplateMsgTest extends TokenTest { public class TemplateTest extends TokenTest {
private TmplApi tmplApi; private TmplApi tmplApi;
@Before @Before

View File

@ -1,11 +1,5 @@
package com.foxinmy.weixin4j.mp.test; package com.foxinmy.weixin4j.mp.test;
import java.net.URL;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -36,19 +30,4 @@ public class TokenTest {
public void test() throws WeixinException { public void test() throws WeixinException {
Assert.assertNotNull(tokenHolder.getToken()); Assert.assertNotNull(tokenHolder.getToken());
} }
public static void main(String[] args) throws Exception {
String wikiUrl = "http://qydev.weixin.qq.com/wiki/index.php?title=%E5%85%A8%E5%B1%80%E8%BF%94%E5%9B%9E%E7%A0%81%E8%AF%B4%E6%98%8E";
// wikiUrl =
// "http://mp.weixin.qq.com/wiki/17/fa4e1434e57290788bde25603fa2fcbd.html";
Document doc = Jsoup.parse(new URL(wikiUrl), 5000);
Elements errors = doc.getElementsByTag("tr");
String node = "<error><code>%s</code><text>%s</text></error>";
StringBuilder xml = new StringBuilder();
for (Element error : errors) {
xml.append(String.format(node, error.child(0).text(), error
.child(1).text()));
}
System.err.println(xml);
}
} }

View File

@ -1,64 +0,0 @@
package com.foxinmy.weixin4j.mp.test.msg;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
public class AesMsgTest extends MessagePush {
StringBuilder xmlSb = new StringBuilder();
@Test
public void testValidate() throws WeixinException, IOException {
String para = "?signature=0d2366aedb4f3531cfa4297c1e4ea7eece2311d9&echostr=2143641595566077626&timestamp=1415951914&nonce=165976363";
xmlSb.delete(0, xmlSb.length());
String response = get(para);
Assert.assertEquals("2143641595566077626", response);
}
@Test
public void testType1() throws WeixinException, IOException {
String para = "?signature=6dd806a20a314723e78bc58742a1b98a7adfd151&timestamp=1415979366&nonce=1865915590";
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[gh_248c6f91d64f]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[oyFLst1bqtuTcxK-ojF8hOGtLQao]]></FromUserName>");
xmlSb.append("<CreateTime>1415979365</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[CLICK]]></Event>");
xmlSb.append("<EventKey><![CDATA[CHECKIN]]></EventKey>");
xmlSb.append("</xml>");
String response = push(para, xmlSb.toString());
Assert.assertNotNull(response);
}
@Test
public void testType2() throws WeixinException, IOException {
String para = "?signature=ad05f836772d1cbba1ff2edb7be4b9c9fb3a43d5&timestamp=1415980001&nonce=1803216865&encrypt_type=raw&msg_signature=c0d38e9ca00548f7142627ec2908a4fe8481025e";
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[gh_248c6f91d64f]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[oyFLst1bqtuTcxK-ojF8hOGtLQao]]></FromUserName>");
xmlSb.append("<CreateTime>1415980001</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[CLICK]]></Event>");
xmlSb.append("<EventKey><![CDATA[CHECKIN]]></EventKey>");
xmlSb.append("</xml>");
String response = push(para, xmlSb.toString());
Assert.assertNotNull(response);
}
@Test
public void testType3() throws WeixinException, IOException {
String para = "?signature=ad05f836772d1cbba1ff2edb7be4b9c9fb3a43d5&timestamp=1415980001&nonce=1803216865&encrypt_type=aes&msg_signature=c0d38e9ca00548f7142627ec2908a4fe8481025e";
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[gh_248c6f91d64f]]></ToUserName>");
xmlSb.append("<Encrypt><![CDATA[R6VQIWDR14XgSRLm25zc7V/WJYqK15gsUiMh0u/5GTMZME6jGtHkyfVN079ZPL065b+ZDq3TnoFKKtjtZlzcodY6Fm8+EujvtbTdVMMFSwdo8AwqVViAn09+DDfqPaNvbHUSiYsL3qlxArs1MH6APRUHFo7MU/piY1x2stJc8+kv28xtF+K8Aou0RuPO7PeQ18Zu/GkLnYNiI1E7UG31UYfOgVKcRjeE0PXa18iF5LBS8G/ce/l+/pH/DJWUBw5uXaqSOlo21tctlgLXu3bYUUkIu8tT49QwhHvRZILtO9icoyCNuTA7iTcHIdlAe1bD1S0ncmopIQCGmoU2/AXC2CCi6trONf3EPNKKKfDeQYHadnVZOg6kTX2cnYmHZLviYeLzjCKFSqSNkimoSKQ/Dcutpsq1D82NCwiExUZW4oo=]]></Encrypt>");
xmlSb.append("</xml>");
String response = push(para, xmlSb.toString());
Assert.assertNotNull(response);
}
}

View File

@ -1,179 +0,0 @@
package com.foxinmy.weixin4j.mp.test.msg;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
/**
* 接收事件消息格式测试
*
* @author jy.hu
* @date 2014年3月24日
* @since JDK 1.7
*/
public class EventMsgTest extends MessagePush {
private StringBuilder xmlSb = new StringBuilder();
/***************** event message *********************/
@Test
public void scribe() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[subscribe]]></Event>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void scan() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[SCAN]]></Event>");
xmlSb.append("<EventKey><![CDATA[SCENE_VALUE]]></EventKey>");
xmlSb.append("<Ticket><![CDATA[TICKET]]></Ticket>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void scan_scribe() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml><ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[subscribe]]></Event>");
xmlSb.append("<EventKey><![CDATA[qrscene_123123]]></EventKey>");
xmlSb.append("<Ticket><![CDATA[TICKET]]></Ticket>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void location() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[fromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[LOCATION]]></Event>");
xmlSb.append("<Latitude>23.137466</Latitude>");
xmlSb.append("<Longitude>113.352425</Longitude>");
xmlSb.append("<Precision>119.385040</Precision>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void menu_click() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[CLICK]]></Event>");
xmlSb.append("<EventKey><![CDATA[EVENTKEY]]></EventKey>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void menu_link() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[VIEW]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void menu_scan() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[scancode_waitmsg]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("<ScanCodeInfo><ScanType><![CDATA[qrcode]]></ScanType>");
xmlSb.append("<ScanResult><![CDATA[1]]></ScanResult>");
xmlSb.append("</ScanCodeInfo>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void menu_photo() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[pic_weixin]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("<SendPicsInfo><Count>1</Count>");
xmlSb.append("<PicList><item><PicMd5Sum><![CDATA[1b5f7c23b5bf75682a53e7b6d163e185]]></PicMd5Sum>");
xmlSb.append("</item></PicList></SendPicsInfo>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void menu_location() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[location_select]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("<SendLocationInfo><Location_X><![CDATA[23]]></Location_X>");
xmlSb.append("<Location_Y><![CDATA[113]]></Location_Y>");
xmlSb.append("<Scale><![CDATA[15]]></Scale>");
xmlSb.append("<Label><![CDATA[ 广州市海珠区客村艺苑路 106号]]></Label>");
xmlSb.append("<Poiname><![CDATA[]]></Poiname></SendLocationInfo>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
}

View File

@ -1,144 +0,0 @@
package com.foxinmy.weixin4j.mp.test.msg;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
/**
* 接受一般消息格式测试
*
* @author jy.hu
* @date 2014年3月24日
* @since JDK 1.7
*/
public class InMsgTest extends MessagePush {
private StringBuilder xmlSb = new StringBuilder();
/***************** common message *********************/
@Test
public void text() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[fromUser]]></FromUserName>");
xmlSb.append("<CreateTime>1348831860</CreateTime>");
xmlSb.append("<MsgType><![CDATA[text]]></MsgType>");
xmlSb.append("<Content><![CDATA[this is a test]]></Content>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void image() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[image]]></MsgType>");
xmlSb.append("<PicUrl><![CDATA[this is a url]]></PicUrl>");
xmlSb.append("<MediaId><![CDATA[media_id]]></MediaId>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void voice() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[voice]]></MsgType>");
xmlSb.append("<MediaId><![CDATA[media_id]]></MediaId>");
xmlSb.append("<Format><![CDATA[Format]]></Format>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void re_voice() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[voice]]></MsgType>");
xmlSb.append("<MediaId><![CDATA[media_id]]></MediaId>");
xmlSb.append("<Format><![CDATA[Format]]></Format>");
xmlSb.append("<Recognition><![CDATA[腾讯微信团队]]></Recognition>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void video() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[video]]></MsgType>");
xmlSb.append("<MediaId><![CDATA[media_id]]></MediaId>");
xmlSb.append("<ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void location() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[location]]></MsgType>");
xmlSb.append("<Location_X>23.134521</Location_X>");
xmlSb.append("<Location_Y>113.358803</Location_Y>");
xmlSb.append("<Scale>20</Scale>");
xmlSb.append("<Label><![CDATA[位置信息]]></Label>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void link() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[link]]></MsgType>");
xmlSb.append("<Title><![CDATA[公众平台官网链接]]></Title>");
xmlSb.append("<Description><![CDATA[公众平台官网链接]]></Description>");
xmlSb.append("<Url><![CDATA[url]]></Url>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
}

View File

@ -1,68 +0,0 @@
package com.foxinmy.weixin4j.mp.test.msg;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import com.foxinmy.weixin4j.exception.WeixinException;
public class MessagePush {
private final String server = "http://localhost:8080";
private final HttpClient httpClient;
private final HttpPost httpPost;
private final HttpGet httpGet;
public MessagePush() {
httpClient = new DefaultHttpClient();
httpPost = new HttpPost();
httpPost.setURI(URI.create(server));
httpGet = new HttpGet();
httpGet.setURI(URI.create(server));
}
public String get(String para) throws WeixinException, IOException {
httpGet.setURI(URI.create(server + para));
HttpResponse httpResponse = httpClient.execute(httpGet);
return entity(httpResponse);
}
public String push(String xml) throws WeixinException, IOException {
return push("", xml);
}
public String push(String para, String xml) throws WeixinException,
IOException {
httpPost.setURI(URI.create(server + para));
httpPost.setEntity(new StringEntity(xml, StandardCharsets.UTF_8));
HttpResponse httpResponse = httpClient.execute(httpPost);
return entity(httpResponse);
}
private String entity(HttpResponse httpResponse) throws WeixinException,
IOException {
StatusLine statusLine = httpResponse.getStatusLine();
int status = statusLine.getStatusCode();
if (status != HttpStatus.SC_OK) {
throw new WeixinException(Integer.toString(status), "request fail");
}
if (status == HttpStatus.SC_MOVED_PERMANENTLY
|| status == HttpStatus.SC_MOVED_TEMPORARILY) {
throw new WeixinException(Integer.toString(status), "uri moved");
}
return EntityUtils.toString(httpResponse.getEntity(),
StandardCharsets.UTF_8);
}
}

View File

@ -10,7 +10,6 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.mime.content.ByteArrayBody; import org.apache.http.entity.mime.content.ByteArrayBody;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
@ -30,6 +29,7 @@ import com.foxinmy.weixin4j.type.MediaType;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.FileUtil; import com.foxinmy.weixin4j.util.FileUtil;
import com.foxinmy.weixin4j.util.IOUtil; import com.foxinmy.weixin4j.util.IOUtil;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* 媒体相关API * 媒体相关API
@ -62,7 +62,7 @@ public class MediaApi extends QyApi {
*/ */
public String uploadMedia(File file) throws WeixinException, IOException { public String uploadMedia(File file) throws WeixinException, IOException {
String mediaTypeKey = IOUtil.getExtension(file.getName()); String mediaTypeKey = IOUtil.getExtension(file.getName());
if (StringUtils.isBlank(mediaTypeKey)) { if (StringUtil.isBlank(mediaTypeKey)) {
mediaTypeKey = FileUtil.getFileType(file); mediaTypeKey = FileUtil.getFileType(file);
} }
MediaType mediaType = MediaType.getMediaType(mediaTypeKey); MediaType mediaType = MediaType.getMediaType(mediaTypeKey);
@ -237,7 +237,7 @@ public class MediaApi extends QyApi {
return true; return true;
} }
}); });
writer.write(StringUtils.join(column.values(), ",")); writer.write(StringUtil.join(column.values(), ','));
writer.write("\r\n"); writer.write("\r\n");
} }
String mediaId = uploadMedia(batchName, String mediaId = uploadMedia(batchName,

View File

@ -3,8 +3,6 @@ package com.foxinmy.weixin4j.qy.api;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
@ -16,6 +14,7 @@ import com.foxinmy.weixin4j.qy.model.User;
import com.foxinmy.weixin4j.qy.type.InviteType; import com.foxinmy.weixin4j.qy.type.InviteType;
import com.foxinmy.weixin4j.qy.type.UserStatus; import com.foxinmy.weixin4j.qy.type.UserStatus;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* 成员API * 成员API
@ -282,7 +281,7 @@ public class UserApi extends QyApi {
throws WeixinException { throws WeixinException {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("userid", userId); obj.put("userid", userId);
if (StringUtils.isBlank(tips)) { if (StringUtil.isBlank(tips)) {
obj.put("invite_tips", tips); obj.put("invite_tips", tips);
} }
String invite_user_uri = getRequestUri("invite_user_uri"); String invite_user_uri = getRequestUri("invite_user_uri");

View File

@ -1,100 +0,0 @@
package com.foxinmy.weixin4j.qy.event;
import java.io.Serializable;
import com.foxinmy.weixin4j.message.event.EventMessage;
import com.foxinmy.weixin4j.qy.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 异步任务事件完成通知
*
* @className BatchjobresultMessage
* @author jy
* @date 2015年3月31日
* @since JDK 1.7
* @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.82.E6.AD.A5.E4.BB.BB.E5.8A.A1.E5.AE.8C.E6.88.90.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">异步任务事件完成通知</a>
*/
public class BatchjobresultMessage extends EventMessage {
private static final long serialVersionUID = 8014540441322209657L;
public BatchjobresultMessage() {
super(EventType.batch_job_result.name());
}
/**
* 任务信息
*/
@XStreamAlias("BatchJob")
private BatchJob batchJob;
public BatchJob getBatchJob() {
return batchJob;
}
/**
* 任务信息
*
* @className BatchJob
* @author jy
* @date 2015年4月1日
* @since JDK 1.7
* @see
*/
public static class BatchJob implements Serializable {
private static final long serialVersionUID = -7520032656787156391L;
/**
* 异步任务id最大长度为64字符
*/
@XStreamAlias("JobId")
private String jobId;
/**
* 操作类型字符串目前分别有 1. sync_user(增量更新成员) 2. replace_user(全量覆盖成员) 3.
* invite_user(邀请成员关注) 4. replace_party(全量覆盖部门)
*
* @see com.foxinmy.weixin4j.qy.type.BatchType
*/
@XStreamAlias("JobType")
private String jobType;
/**
* 返回码
*/
@XStreamAlias("ErrCode")
private String ErrCode;
/**
* 对返回码的文本描述内容
*/
@XStreamAlias("ErrMsg")
private String errMsg;
public String getJobId() {
return jobId;
}
public String getJobType() {
return jobType;
}
public String getErrCode() {
return ErrCode;
}
public String getErrMsg() {
return errMsg;
}
@Override
public String toString() {
return "[jobId=" + jobId + ", jobType=" + jobType + ", ErrCode="
+ ErrCode + ", errMsg=" + errMsg + "]";
}
}
@Override
public String toString() {
return "BatchjobresultMessage [batchJob=" + batchJob + ", "
+ super.toString() + "]";
}
}

View File

@ -1,41 +0,0 @@
package com.foxinmy.weixin4j.qy.event;
import com.foxinmy.weixin4j.message.event.EventMessage;
import com.foxinmy.weixin4j.qy.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 用户进入应用的事件推送(企业号)本事件只有在应用的回调模式中打开上报开关时上报
*
* @className EnterAgentEventMessage
* @author jy
* @date 2014年12月28日
* @since JDK 1.7
* @see <a href=
* "http://qydev.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6#.E7.94.A8.E6.88.B7.E8.BF.9B.E5.85.A5.E5.BA.94.E7.94.A8.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81"
* >用户进入应用的事件推送</a>
*/
public class EnterAgentEventMessage extends EventMessage {
private static final long serialVersionUID = 7675732524832500820L;
public EnterAgentEventMessage() {
super(EventType.enter_agent.name());
}
/**
* 事件KEY值与自定义菜单接口中KEY值对应
*/
@XStreamAlias("EventKey")
private String eventKey;
public String getEventKey() {
return eventKey;
}
@Override
public String toString() {
return "EnterAgentEventMessage [eventKey=" + eventKey + ", "
+ super.toString() + "]";
}
}

View File

@ -1,28 +0,0 @@
package com.foxinmy.weixin4j.qy.event;
import com.foxinmy.weixin4j.message.event.EventMessage;
import com.foxinmy.weixin4j.type.EventType;
/**
* 关注/取消关注事件</br> <font color="red">包括直接关注与扫描关注</font>
*
* @className ScribeEventMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @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.88.90.E5.91.98.E5.85.B3.E6.B3.A8.2F.E5.8F.96.E6.B6.88.E5.85.B3.E6.B3.A8.E4.BA.8B.E4.BB.B6">成员关注/取消关注事件</a>
*/
public class ScribeEventMessage extends EventMessage {
private static final long serialVersionUID = -6846321620262204915L;
public ScribeEventMessage() {
super(EventType.subscribe.name());
}
@Override
public String toString() {
return "ScribeEventMessage [" + super.toString() + "]";
}
}

View File

@ -3,10 +3,9 @@ package com.foxinmy.weixin4j.qy.message;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.tuple.NotifyTuple; import com.foxinmy.weixin4j.tuple.NotifyTuple;
import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* 发送消息对象 * 发送消息对象
@ -29,7 +28,7 @@ public class NotifyMessage implements Serializable {
private static final long serialVersionUID = 1219589414293000383L; private static final long serialVersionUID = 1219589414293000383L;
private static final String SEPARATOR = "|"; private static final char SEPARATOR = '|';
/** /**
* UserID列表消息接收者多个接收者用|分隔特殊情况指定为@all则向关注该企业应用的全部成员发送 * UserID列表消息接收者多个接收者用|分隔特殊情况指定为@all则向关注该企业应用的全部成员发送
@ -65,13 +64,13 @@ public class NotifyMessage implements Serializable {
public NotifyMessage(List<String> tousers, List<String> topartys, public NotifyMessage(List<String> tousers, List<String> topartys,
List<String> totags, NotifyTuple tuple, int agentid, boolean isSafe) { List<String> totags, NotifyTuple tuple, int agentid, boolean isSafe) {
if (tousers != null && !tousers.isEmpty()) { if (tousers != null && !tousers.isEmpty()) {
this.touser = StringUtils.join(tousers, SEPARATOR); this.touser = StringUtil.join(tousers, SEPARATOR);
} }
if (topartys != null && !topartys.isEmpty()) { if (topartys != null && !topartys.isEmpty()) {
this.toparty = StringUtils.join(topartys, SEPARATOR); this.toparty = StringUtil.join(topartys, SEPARATOR);
} }
if (totags != null && !totags.isEmpty()) { if (totags != null && !totags.isEmpty()) {
this.totag = StringUtils.join(totags, SEPARATOR); this.totag = StringUtil.join(totags, SEPARATOR);
} }
this.agentid = agentid; this.agentid = agentid;
this.safe = isSafe ? 1 : 0; this.safe = isSafe ? 1 : 0;
@ -88,7 +87,7 @@ public class NotifyMessage implements Serializable {
public void setTouser(List<String> tousers) { public void setTouser(List<String> tousers) {
if (tousers != null && !tousers.isEmpty()) { if (tousers != null && !tousers.isEmpty()) {
this.touser = StringUtils.join(tousers, SEPARATOR); this.touser = StringUtil.join(tousers, SEPARATOR);
} }
} }
@ -102,7 +101,7 @@ public class NotifyMessage implements Serializable {
public void setToparty(List<String> topartys) { public void setToparty(List<String> topartys) {
if (topartys != null && !topartys.isEmpty()) { if (topartys != null && !topartys.isEmpty()) {
this.toparty = StringUtils.join(topartys, SEPARATOR); this.toparty = StringUtil.join(topartys, SEPARATOR);
} }
} }
@ -116,7 +115,7 @@ public class NotifyMessage implements Serializable {
public void setTotag(List<String> totags) { public void setTotag(List<String> totags) {
if (totags != null && !totags.isEmpty()) { if (totags != null && !totags.isEmpty()) {
this.totag = StringUtils.join(totags, SEPARATOR); this.totag = StringUtil.join(totags, SEPARATOR);
} }
} }

View File

@ -4,7 +4,7 @@ import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang3.StringUtils; import com.foxinmy.weixin4j.util.StringUtil;
/** /**
* id参数集 * id参数集
@ -19,6 +19,8 @@ public class IdParameter implements Serializable {
private static final long serialVersionUID = -2689758682205591133L; private static final long serialVersionUID = -2689758682205591133L;
private static final char SEPARATOR = '|';
private Map<String, String> parameterMap; private Map<String, String> parameterMap;
public IdParameter() { public IdParameter() {
@ -32,7 +34,7 @@ public class IdParameter implements Serializable {
* @return * @return
*/ */
public IdParameter putUseIds(String... userIds) { public IdParameter putUseIds(String... userIds) {
parameterMap.put("touser", StringUtils.join(userIds, '|')); parameterMap.put("touser", StringUtil.join(userIds, SEPARATOR));
return this; return this;
} }
@ -43,7 +45,7 @@ public class IdParameter implements Serializable {
* @return * @return
*/ */
public IdParameter putUseIds(int... partyIds) { public IdParameter putUseIds(int... partyIds) {
parameterMap.put("toparty", StringUtils.join(partyIds, '|')); parameterMap.put("toparty", StringUtil.join(partyIds, SEPARATOR));
return this; return this;
} }
@ -54,7 +56,7 @@ public class IdParameter implements Serializable {
* @return * @return
*/ */
public IdParameter putTagIds(int... tagIds) { public IdParameter putTagIds(int... tagIds) {
parameterMap.put("totag", StringUtils.join(tagIds, '|')); parameterMap.put("totag", StringUtil.join(tagIds, SEPARATOR));
return this; return this;
} }

View File

@ -1,25 +0,0 @@
package com.foxinmy.weixin4j.qy.type;
/**
* 企业号事件类型
*
* @className EventType
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see
*/
public enum EventType {
/**
* 进入企业号应用事件
*
* @see com.foxinmy.weixin4j.qy.event.EnterAgentEventMessage
*/
enter_agent,
/**
* 异步任务完成事件
*
* @see com.foxinmy.weixin4j.msg.event.BatchjobresultMessage
*/
batch_job_result;
}

View File

@ -1,64 +0,0 @@
package com.foxinmy.weixin4j.qy.test;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
public class AesMsgTest extends MessagePush {
StringBuilder xmlSb = new StringBuilder();
@Test
public void testValidate() throws WeixinException, IOException {
String para = "?msg_signature=33f680b72cfd87a6f8f4d751575bcc31266853a9&timestamp=1416488666&nonce=1358224345&echostr=WZu9tT6KDuyhgOZ1aT%2FIoPNaUkA%2FsfVR%2F%2BDua5q84Kvhs6Fc1%2F6f2510%2BUuMByessdQWsoeak0lSIpaYOIlHrw%3D%3D";
xmlSb.delete(0, xmlSb.length());
String response = get(para);
Assert.assertEquals("2143641595566077626", response);
}
@Test
public void testType1() throws WeixinException, IOException {
String para = "?signature=6dd806a20a314723e78bc58742a1b98a7adfd151&timestamp=1415979366&nonce=1865915590";
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[gh_248c6f91d64f]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[oyFLst1bqtuTcxK-ojF8hOGtLQao]]></FromUserName>");
xmlSb.append("<CreateTime>1415979365</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[CLICK]]></Event>");
xmlSb.append("<EventKey><![CDATA[CHECKIN]]></EventKey>");
xmlSb.append("</xml>");
String response = push(para, xmlSb.toString());
Assert.assertNotNull(response);
}
@Test
public void testType2() throws WeixinException, IOException {
String para = "?signature=ad05f836772d1cbba1ff2edb7be4b9c9fb3a43d5&timestamp=1415980001&nonce=1803216865&encrypt_type=raw&msg_signature=c0d38e9ca00548f7142627ec2908a4fe8481025e";
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[gh_248c6f91d64f]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[oyFLst1bqtuTcxK-ojF8hOGtLQao]]></FromUserName>");
xmlSb.append("<CreateTime>1415980001</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[CLICK]]></Event>");
xmlSb.append("<EventKey><![CDATA[CHECKIN]]></EventKey>");
xmlSb.append("</xml>");
String response = push(para, xmlSb.toString());
Assert.assertNotNull(response);
}
@Test
public void testType3() throws WeixinException, IOException {
String para = "?signature=ad05f836772d1cbba1ff2edb7be4b9c9fb3a43d5&timestamp=1415980001&nonce=1803216865&encrypt_type=aes&msg_signature=c0d38e9ca00548f7142627ec2908a4fe8481025e";
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[gh_248c6f91d64f]]></ToUserName>");
xmlSb.append("<Encrypt><![CDATA[R6VQIWDR14XgSRLm25zc7V/WJYqK15gsUiMh0u/5GTMZME6jGtHkyfVN079ZPL065b+ZDq3TnoFKKtjtZlzcodY6Fm8+EujvtbTdVMMFSwdo8AwqVViAn09+DDfqPaNvbHUSiYsL3qlxArs1MH6APRUHFo7MU/piY1x2stJc8+kv28xtF+K8Aou0RuPO7PeQ18Zu/GkLnYNiI1E7UG31UYfOgVKcRjeE0PXa18iF5LBS8G/ce/l+/pH/DJWUBw5uXaqSOlo21tctlgLXu3bYUUkIu8tT49QwhHvRZILtO9icoyCNuTA7iTcHIdlAe1bD1S0ncmopIQCGmoU2/AXC2CCi6trONf3EPNKKKfDeQYHadnVZOg6kTX2cnYmHZLviYeLzjCKFSqSNkimoSKQ/Dcutpsq1D82NCwiExUZW4oo=]]></Encrypt>");
xmlSb.append("</xml>");
String response = push(para, xmlSb.toString());
Assert.assertNotNull(response);
}
}

View File

@ -1,68 +0,0 @@
package com.foxinmy.weixin4j.qy.test;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import com.foxinmy.weixin4j.exception.WeixinException;
public class MessagePush {
private final String server = "http://localhost:8090";
private final HttpClient httpClient;
private final HttpPost httpPost;
private final HttpGet httpGet;
public MessagePush() {
httpClient = new DefaultHttpClient();
httpPost = new HttpPost();
httpPost.setURI(URI.create(server));
httpGet = new HttpGet();
httpGet.setURI(URI.create(server));
}
public String get(String para) throws WeixinException, IOException {
httpGet.setURI(URI.create(server + para));
HttpResponse httpResponse = httpClient.execute(httpGet);
return entity(httpResponse);
}
public String push(String xml) throws WeixinException, IOException {
return push("", xml);
}
public String push(String para, String xml) throws WeixinException,
IOException {
httpPost.setURI(URI.create(server + para));
httpPost.setEntity(new StringEntity(xml, StandardCharsets.UTF_8));
HttpResponse httpResponse = httpClient.execute(httpPost);
return entity(httpResponse);
}
private String entity(HttpResponse httpResponse) throws WeixinException,
IOException {
StatusLine statusLine = httpResponse.getStatusLine();
int status = statusLine.getStatusCode();
if (status != HttpStatus.SC_OK) {
throw new WeixinException(Integer.toString(status), "request fail");
}
if (status == HttpStatus.SC_MOVED_PERMANENTLY
|| status == HttpStatus.SC_MOVED_TEMPORARILY) {
throw new WeixinException(Integer.toString(status), "uri moved");
}
return EntityUtils.toString(httpResponse.getEntity(),
StandardCharsets.UTF_8);
}
}

View File

@ -130,7 +130,7 @@ public final class WeixinServerBootstrap {
new WeixinServerInitializer(aesToken, new WeixinServerInitializer(aesToken,
messageDispatcher)); messageDispatcher));
Channel ch = b.bind(serverPort).sync().channel(); Channel ch = b.bind(serverPort).sync().channel();
System.err.println("weixin server startup OK:" + serverPort); System.err.println("weixin4j server startup OK:" + serverPort);
ch.closeFuture().sync(); ch.closeFuture().sync();
} catch (WeixinException e) { } catch (WeixinException e) {
throw e; throw e;

View File

@ -16,32 +16,28 @@ public class EncryptMessageHandler extends DefaultHandler {
private String encryptContent; private String encryptContent;
private String currentQName;
@Override @Override
public void startDocument() throws SAXException { public void startDocument() throws SAXException {
encryptContent = null; encryptContent = null;
currentQName = null;
} }
@Override @Override
public void startElement(String uri, String localName, String qName, public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException { Attributes attributes) throws SAXException {
this.currentQName = qName; if (qName.equalsIgnoreCase("encrypt")) {
return;
}
} }
@Override @Override
public void endElement(String uri, String localName, String qName) public void endElement(String uri, String localName, String qName)
throws SAXException { throws SAXException {
this.currentQName = null;
} }
@Override @Override
public void characters(char[] ch, int start, int length) public void characters(char[] ch, int start, int length)
throws SAXException { throws SAXException {
if (currentQName.equalsIgnoreCase("encrypt")) {
this.encryptContent = new String(ch, start, length); this.encryptContent = new String(ch, start, length);
}
} }
public String getEncryptContent() { public String getEncryptContent() {

View File

@ -25,9 +25,9 @@ import com.foxinmy.weixin4j.startup.WeixinServerBootstrap;
*/ */
public class MessageServerStarup { public class MessageServerStarup {
final String appid = "公众号appid"; final String appid = "wx0d1d598c0c03c999";
final String token = "开发者token"; final String token = "carsonliu13450438112";
final String aesKey = "aes加密密钥"; final String aesKey = "vlrw8zK2UDSV7Hbmkl8ThzSBmdC11Lw95Um9b2dg3w1";
/** /**
* 明文模式 * 明文模式