| @@ -61,6 +61,11 @@ | |||||
| <artifactId>joda-time</artifactId> | <artifactId>joda-time</artifactId> | ||||
| <scope>test</scope> | <scope>test</scope> | ||||
| </dependency> | </dependency> | ||||
| <dependency> | |||||
| <groupId>org.assertj</groupId> | |||||
| <artifactId>assertj-guava</artifactId> | |||||
| <scope>test</scope> | |||||
| </dependency> | |||||
| <dependency> | <dependency> | ||||
| <groupId>redis.clients</groupId> | <groupId>redis.clients</groupId> | ||||
| <artifactId>jedis</artifactId> | <artifactId>jedis</artifactId> | ||||
| @@ -1,8 +1,12 @@ | |||||
| package cn.binarywang.wx.miniapp.bean; | package cn.binarywang.wx.miniapp.bean; | ||||
| import cn.binarywang.wx.miniapp.builder.ImageBuilder; | import cn.binarywang.wx.miniapp.builder.ImageBuilder; | ||||
| import cn.binarywang.wx.miniapp.builder.LinkBuilder; | |||||
| import cn.binarywang.wx.miniapp.builder.TextBuilder; | import cn.binarywang.wx.miniapp.builder.TextBuilder; | ||||
| import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; | |||||
| import com.google.gson.GsonBuilder; | |||||
| import com.google.gson.annotations.SerializedName; | |||||
| import lombok.AllArgsConstructor; | |||||
| import lombok.Builder; | |||||
| import lombok.Data; | import lombok.Data; | ||||
| import java.io.Serializable; | import java.io.Serializable; | ||||
| @@ -16,13 +20,59 @@ import java.io.Serializable; | |||||
| public class WxMaKefuMessage implements Serializable { | public class WxMaKefuMessage implements Serializable { | ||||
| private static final long serialVersionUID = -9196732086954365246L; | private static final long serialVersionUID = -9196732086954365246L; | ||||
| @SerializedName("touser") | |||||
| private String toUser; | private String toUser; | ||||
| @SerializedName("msgtype") | |||||
| private String msgType; | private String msgType; | ||||
| private String content; | |||||
| private String mediaId; | |||||
| private String thumbMediaId; | |||||
| private String title; | |||||
| private String description; | |||||
| @SerializedName("text") | |||||
| private KfText text; | |||||
| @SerializedName("image") | |||||
| private KfImage image; | |||||
| @SerializedName("link") | |||||
| private KfLink link; | |||||
| @SerializedName("miniprogrampage") | |||||
| private KfMaPage maPage; | |||||
| @Data | |||||
| @AllArgsConstructor | |||||
| public static class KfText { | |||||
| private String content; | |||||
| } | |||||
| @Data | |||||
| @AllArgsConstructor | |||||
| public static class KfImage { | |||||
| @SerializedName("media_id") | |||||
| private String mediaId; | |||||
| } | |||||
| @Data | |||||
| @Builder | |||||
| public static class KfLink { | |||||
| private String title; | |||||
| private String description; | |||||
| private String url; | |||||
| @SerializedName("thumb_url") | |||||
| private String thumbUrl; | |||||
| } | |||||
| @Data | |||||
| @Builder | |||||
| public static class KfMaPage { | |||||
| private String title; | |||||
| @SerializedName("pagepath") | |||||
| private String pagePath; | |||||
| @SerializedName("thumb_media_id") | |||||
| private String thumbMediaId; | |||||
| } | |||||
| /** | /** | ||||
| * 获得文本消息builder. | * 获得文本消息builder. | ||||
| @@ -38,8 +88,15 @@ public class WxMaKefuMessage implements Serializable { | |||||
| return new ImageBuilder(); | return new ImageBuilder(); | ||||
| } | } | ||||
| /** | |||||
| * 获得图文链接消息builder. | |||||
| */ | |||||
| public static LinkBuilder newLinkBuilder() { | |||||
| return new LinkBuilder(); | |||||
| } | |||||
| public String toJson() { | public String toJson() { | ||||
| return WxMaGsonBuilder.create().toJson(this); | |||||
| return new GsonBuilder().create().toJson(this); | |||||
| } | } | ||||
| } | } | ||||
| @@ -31,8 +31,9 @@ public class WxMaWxcodeLimit extends AbstractWxMaQrcodeWrapper implements Serial | |||||
| return WxMaGsonBuilder.create().fromJson(json, WxMaWxcodeLimit.class); | return WxMaGsonBuilder.create().fromJson(json, WxMaWxcodeLimit.class); | ||||
| } | } | ||||
| @Override | |||||
| public String toString() { | public String toString() { | ||||
| return super.toString(); | return super.toString(); | ||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -4,6 +4,8 @@ import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
| import cn.binarywang.wx.miniapp.constant.WxMaConstants; | import cn.binarywang.wx.miniapp.constant.WxMaConstants; | ||||
| /** | /** | ||||
| * 图片消息builder. | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| */ | */ | ||||
| public final class ImageBuilder extends BaseBuilder<ImageBuilder> { | public final class ImageBuilder extends BaseBuilder<ImageBuilder> { | ||||
| @@ -21,7 +23,7 @@ public final class ImageBuilder extends BaseBuilder<ImageBuilder> { | |||||
| @Override | @Override | ||||
| public WxMaKefuMessage build() { | public WxMaKefuMessage build() { | ||||
| WxMaKefuMessage m = super.build(); | WxMaKefuMessage m = super.build(); | ||||
| m.setMediaId(this.mediaId); | |||||
| m.setImage(new WxMaKefuMessage.KfImage(this.mediaId)); | |||||
| return m; | return m; | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,52 @@ | |||||
| package cn.binarywang.wx.miniapp.builder; | |||||
| import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
| import cn.binarywang.wx.miniapp.constant.WxMaConstants; | |||||
| /** | |||||
| * 图文链接builder | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| public class LinkBuilder extends BaseBuilder<LinkBuilder> { | |||||
| private String title; | |||||
| private String description; | |||||
| private String url; | |||||
| private String thumbUrl; | |||||
| public LinkBuilder() { | |||||
| this.msgType = WxMaConstants.KefuMsgType.IMAGE; | |||||
| } | |||||
| public LinkBuilder title(String title) { | |||||
| this.title = title; | |||||
| return this; | |||||
| } | |||||
| public LinkBuilder description(String description) { | |||||
| this.description = description; | |||||
| return this; | |||||
| } | |||||
| public LinkBuilder url(String url) { | |||||
| this.url = url; | |||||
| return this; | |||||
| } | |||||
| public LinkBuilder thumbUrl(String thumbUrl) { | |||||
| this.thumbUrl = thumbUrl; | |||||
| return this; | |||||
| } | |||||
| @Override | |||||
| public WxMaKefuMessage build() { | |||||
| WxMaKefuMessage m = super.build(); | |||||
| m.setLink(WxMaKefuMessage.KfLink.builder().title(this.title) | |||||
| .description(this.description) | |||||
| .url(this.url) | |||||
| .thumbUrl(this.thumbUrl) | |||||
| .build() | |||||
| ); | |||||
| return m; | |||||
| } | |||||
| } | |||||
| @@ -4,6 +4,8 @@ import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
| import cn.binarywang.wx.miniapp.constant.WxMaConstants; | import cn.binarywang.wx.miniapp.constant.WxMaConstants; | ||||
| /** | /** | ||||
| * 文本消息builder. | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| */ | */ | ||||
| public final class TextBuilder extends BaseBuilder<TextBuilder> { | public final class TextBuilder extends BaseBuilder<TextBuilder> { | ||||
| @@ -21,7 +23,7 @@ public final class TextBuilder extends BaseBuilder<TextBuilder> { | |||||
| @Override | @Override | ||||
| public WxMaKefuMessage build() { | public WxMaKefuMessage build() { | ||||
| WxMaKefuMessage m = super.build(); | WxMaKefuMessage m = super.build(); | ||||
| m.setContent(this.content); | |||||
| m.setText(new WxMaKefuMessage.KfText(this.content)); | |||||
| return m; | return m; | ||||
| } | } | ||||
| } | } | ||||
| @@ -2,29 +2,29 @@ package cn.binarywang.wx.miniapp.constant; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 小程序常量 | |||||
| * 小程序常量. | |||||
| * </pre> | * </pre> | ||||
| * | * | ||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| */ | */ | ||||
| public class WxMaConstants { | public class WxMaConstants { | ||||
| /** | /** | ||||
| * 微信接口返回的参数errcode | |||||
| * 微信接口返回的参数errcode. | |||||
| */ | */ | ||||
| public static final String ERRCODE = "errcode"; | public static final String ERRCODE = "errcode"; | ||||
| /** | /** | ||||
| * 素材类型 | |||||
| * 素材类型. | |||||
| */ | */ | ||||
| public static class MediaType { | public static class MediaType { | ||||
| /** | /** | ||||
| * 图片 | |||||
| * 图片. | |||||
| */ | */ | ||||
| public static final String IMAGE = "image"; | public static final String IMAGE = "image"; | ||||
| } | } | ||||
| /** | /** | ||||
| * 消息格式 | |||||
| * 消息格式. | |||||
| */ | */ | ||||
| public static class MsgDataFormat { | public static class MsgDataFormat { | ||||
| public static final String XML = "XML"; | public static final String XML = "XML"; | ||||
| @@ -32,32 +32,40 @@ public class WxMaConstants { | |||||
| } | } | ||||
| /** | /** | ||||
| * 客服消息的消息类型 | |||||
| * 客服消息的消息类型. | |||||
| */ | */ | ||||
| public static class KefuMsgType { | public static class KefuMsgType { | ||||
| /** | /** | ||||
| * 文本消息 | |||||
| * 文本消息. | |||||
| */ | */ | ||||
| public static final String TEXT = "text"; | public static final String TEXT = "text"; | ||||
| /** | /** | ||||
| * 图片消息 | |||||
| * 图片消息. | |||||
| */ | */ | ||||
| public static final String IMAGE = "image"; | public static final String IMAGE = "image"; | ||||
| /** | |||||
| * 图文链接. | |||||
| */ | |||||
| public static final String LINK = "link"; | |||||
| /** | |||||
| * 小程序卡片消息. | |||||
| */ | |||||
| public static final String MA_PAGE = "miniprogrampage"; | |||||
| } | } | ||||
| public static final class ErrorCode { | public static final class ErrorCode { | ||||
| /** | /** | ||||
| * 40001 获取access_token时AppSecret错误,或者access_token无效 | |||||
| * 40001 获取access_token时AppSecret错误,或者access_token无效. | |||||
| */ | */ | ||||
| public static final int ERR_40001 = 40001; | public static final int ERR_40001 = 40001; | ||||
| /** | /** | ||||
| * 42001 access_token超时 | |||||
| * 42001 access_token超时. | |||||
| */ | */ | ||||
| public static final int ERR_42001 = 42001; | public static final int ERR_42001 = 42001; | ||||
| /** | /** | ||||
| * 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期) | |||||
| * 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期). | |||||
| */ | */ | ||||
| public static final int ERR_40014 = 40014; | public static final int ERR_40014 = 40014; | ||||
| } | } | ||||
| @@ -1,6 +1,5 @@ | |||||
| package cn.binarywang.wx.miniapp.util.json; | package cn.binarywang.wx.miniapp.util.json; | ||||
| import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
| import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; | import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; | ||||
| import com.google.gson.Gson; | import com.google.gson.Gson; | ||||
| import com.google.gson.GsonBuilder; | import com.google.gson.GsonBuilder; | ||||
| @@ -13,7 +12,6 @@ public class WxMaGsonBuilder { | |||||
| static { | static { | ||||
| INSTANCE.disableHtmlEscaping(); | INSTANCE.disableHtmlEscaping(); | ||||
| INSTANCE.registerTypeAdapter(WxMaKefuMessage.class, new WxMaKefuMessageGsonAdapter()); | |||||
| INSTANCE.registerTypeAdapter(WxMaTemplateMessage.class, new WxMaTemplateMessageGsonAdapter()); | INSTANCE.registerTypeAdapter(WxMaTemplateMessage.class, new WxMaTemplateMessageGsonAdapter()); | ||||
| } | } | ||||
| @@ -1,38 +0,0 @@ | |||||
| package cn.binarywang.wx.miniapp.util.json; | |||||
| import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||||
| import cn.binarywang.wx.miniapp.constant.WxMaConstants; | |||||
| import com.google.gson.JsonElement; | |||||
| import com.google.gson.JsonObject; | |||||
| import com.google.gson.JsonSerializationContext; | |||||
| import com.google.gson.JsonSerializer; | |||||
| import java.lang.reflect.Type; | |||||
| /** | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| public class WxMaKefuMessageGsonAdapter implements JsonSerializer<WxMaKefuMessage> { | |||||
| @Override | |||||
| public JsonElement serialize(WxMaKefuMessage message, Type typeOfSrc, JsonSerializationContext context) { | |||||
| JsonObject messageJson = new JsonObject(); | |||||
| messageJson.addProperty("touser", message.getToUser()); | |||||
| messageJson.addProperty("msgtype", message.getMsgType()); | |||||
| if (WxMaConstants.KefuMsgType.TEXT.equals(message.getMsgType())) { | |||||
| JsonObject text = new JsonObject(); | |||||
| text.addProperty("content", message.getContent()); | |||||
| messageJson.add("text", text); | |||||
| } | |||||
| if (WxMaConstants.KefuMsgType.IMAGE.equals(message.getMsgType())) { | |||||
| JsonObject image = new JsonObject(); | |||||
| image.addProperty("media_id", message.getMediaId()); | |||||
| messageJson.add("image", image); | |||||
| } | |||||
| return messageJson; | |||||
| } | |||||
| } | |||||
| @@ -7,16 +7,14 @@ import cn.binarywang.wx.miniapp.test.ApiTestModule; | |||||
| import cn.binarywang.wx.miniapp.test.TestConfig; | import cn.binarywang.wx.miniapp.test.TestConfig; | ||||
| import com.google.common.collect.Lists; | import com.google.common.collect.Lists; | ||||
| import com.google.inject.Inject; | import com.google.inject.Inject; | ||||
| import me.chanjar.weixin.common.api.WxConsts; | |||||
| import me.chanjar.weixin.common.exception.WxErrorException; | import me.chanjar.weixin.common.exception.WxErrorException; | ||||
| import org.testng.annotations.Guice; | |||||
| import org.testng.annotations.Test; | |||||
| import org.testng.annotations.*; | |||||
| import java.text.SimpleDateFormat; | import java.text.SimpleDateFormat; | ||||
| import java.util.Date; | import java.util.Date; | ||||
| /** | /** | ||||
| * 测试客服相关接口 | |||||
| * 测试消息相关接口 | |||||
| * | * | ||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| */ | */ | ||||
| @@ -25,26 +23,14 @@ import java.util.Date; | |||||
| public class WxMaMsgServiceImplTest { | public class WxMaMsgServiceImplTest { | ||||
| @Inject | @Inject | ||||
| protected WxMaService wxService; | |||||
| public void testSendKefuMpNewsMessage() throws WxErrorException { | |||||
| TestConfig configStorage = (TestConfig) this.wxService | |||||
| .getWxMaConfig(); | |||||
| WxMaKefuMessage message = new WxMaKefuMessage(); | |||||
| message.setMsgType(WxConsts.KefuMsgType.MPNEWS); | |||||
| message.setToUser(configStorage.getOpenid()); | |||||
| this.wxService.getMsgService().sendKefuMsg(message); | |||||
| } | |||||
| private WxMaService wxService; | |||||
| public void testSendKefuMessage() throws WxErrorException { | public void testSendKefuMessage() throws WxErrorException { | ||||
| TestConfig config = (TestConfig) this.wxService | |||||
| .getWxMaConfig(); | |||||
| WxMaKefuMessage message = new WxMaKefuMessage(); | |||||
| message.setMsgType(WxConsts.KefuMsgType.TEXT); | |||||
| message.setToUser(config.getOpenid()); | |||||
| message.setContent( | |||||
| "欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>"); | |||||
| TestConfig config = (TestConfig) this.wxService.getWxMaConfig(); | |||||
| WxMaKefuMessage message = WxMaKefuMessage.newTextBuilder() | |||||
| .toUser(config.getOpenid()) | |||||
| .content("欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>") | |||||
| .build(); | |||||
| this.wxService.getMsgService().sendKefuMsg(message); | this.wxService.getMsgService().sendKefuMsg(message); | ||||
| } | } | ||||
| @@ -1,8 +1,8 @@ | |||||
| package cn.binarywang.wx.miniapp.bean; | package cn.binarywang.wx.miniapp.bean; | ||||
| import me.chanjar.weixin.common.api.WxConsts; | |||||
| import org.testng.Assert; | |||||
| import org.testng.annotations.Test; | |||||
| import org.testng.annotations.*; | |||||
| import static org.assertj.core.api.Assertions.assertThat; | |||||
| /** | /** | ||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | * @author <a href="https://github.com/binarywang">Binary Wang</a> | ||||
| @@ -10,30 +10,35 @@ import org.testng.annotations.Test; | |||||
| @Test | @Test | ||||
| public class WxMaKefuMessageTest { | public class WxMaKefuMessageTest { | ||||
| public void testTextReply() { | |||||
| WxMaKefuMessage reply = new WxMaKefuMessage(); | |||||
| reply.setToUser("OPENID"); | |||||
| reply.setMsgType(WxConsts.KefuMsgType.TEXT); | |||||
| reply.setContent("sfsfdsdf"); | |||||
| Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); | |||||
| } | |||||
| public void testTextBuild() { | |||||
| WxMaKefuMessage reply = WxMaKefuMessage.newTextBuilder().toUser("OPENID").content("sfsfdsdf").build(); | |||||
| Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); | |||||
| public void testTextBuilder() { | |||||
| WxMaKefuMessage reply = WxMaKefuMessage.newTextBuilder() | |||||
| .toUser("OPENID") | |||||
| .content("sfsfdsdf") | |||||
| .build(); | |||||
| assertThat(reply.toJson()) | |||||
| .isEqualTo("{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); | |||||
| } | } | ||||
| public void testImageReply() { | |||||
| WxMaKefuMessage reply = new WxMaKefuMessage(); | |||||
| reply.setToUser("OPENID"); | |||||
| reply.setMsgType(WxConsts.KefuMsgType.IMAGE); | |||||
| reply.setMediaId("MEDIA_ID"); | |||||
| Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); | |||||
| public void testImageBuilder() { | |||||
| WxMaKefuMessage reply = WxMaKefuMessage.newImageBuilder() | |||||
| .toUser("OPENID") | |||||
| . mediaId("MEDIA_ID") | |||||
| .build(); | |||||
| assertThat(reply.toJson()) | |||||
| .isEqualTo( "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); | |||||
| } | } | ||||
| public void testImageBuild() { | |||||
| WxMaKefuMessage reply = WxMaKefuMessage.newImageBuilder().toUser("OPENID").mediaId("MEDIA_ID").build(); | |||||
| Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); | |||||
| public void testLinkBuilder() { | |||||
| WxMaKefuMessage reply = WxMaKefuMessage.newLinkBuilder() | |||||
| .toUser("OPENID") | |||||
| .url("url") | |||||
| .description("description") | |||||
| .title("title") | |||||
| .thumbUrl("thumbUrl") | |||||
| .build(); | |||||
| assertThat(reply.toJson()) | |||||
| .isEqualTo( "{\"touser\":\"OPENID\",\"msgtype\":\"image\"," + | |||||
| "\"link\":{\"title\":\"title\",\"description\":\"description\",\"url\":\"url\",\"thumb_url\":\"thumbUrl\"}}"); | |||||
| } | } | ||||