| @@ -61,6 +61,11 @@ | |||
| <artifactId>joda-time</artifactId> | |||
| <scope>test</scope> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.assertj</groupId> | |||
| <artifactId>assertj-guava</artifactId> | |||
| <scope>test</scope> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>redis.clients</groupId> | |||
| <artifactId>jedis</artifactId> | |||
| @@ -1,8 +1,12 @@ | |||
| package cn.binarywang.wx.miniapp.bean; | |||
| 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.util.json.WxMaGsonBuilder; | |||
| import com.google.gson.GsonBuilder; | |||
| import com.google.gson.annotations.SerializedName; | |||
| import lombok.AllArgsConstructor; | |||
| import lombok.Builder; | |||
| import lombok.Data; | |||
| import java.io.Serializable; | |||
| @@ -16,13 +20,59 @@ import java.io.Serializable; | |||
| public class WxMaKefuMessage implements Serializable { | |||
| private static final long serialVersionUID = -9196732086954365246L; | |||
| @SerializedName("touser") | |||
| private String toUser; | |||
| @SerializedName("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. | |||
| @@ -38,8 +88,15 @@ public class WxMaKefuMessage implements Serializable { | |||
| return new ImageBuilder(); | |||
| } | |||
| /** | |||
| * 获得图文链接消息builder. | |||
| */ | |||
| public static LinkBuilder newLinkBuilder() { | |||
| return new LinkBuilder(); | |||
| } | |||
| 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); | |||
| } | |||
| @Override | |||
| public String toString() { | |||
| return super.toString(); | |||
| } | |||
| } | |||
| } | |||
| @@ -4,6 +4,8 @@ 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 final class ImageBuilder extends BaseBuilder<ImageBuilder> { | |||
| @@ -21,7 +23,7 @@ public final class ImageBuilder extends BaseBuilder<ImageBuilder> { | |||
| @Override | |||
| public WxMaKefuMessage build() { | |||
| WxMaKefuMessage m = super.build(); | |||
| m.setMediaId(this.mediaId); | |||
| m.setImage(new WxMaKefuMessage.KfImage(this.mediaId)); | |||
| 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; | |||
| /** | |||
| * 文本消息builder. | |||
| * | |||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
| */ | |||
| public final class TextBuilder extends BaseBuilder<TextBuilder> { | |||
| @@ -21,7 +23,7 @@ public final class TextBuilder extends BaseBuilder<TextBuilder> { | |||
| @Override | |||
| public WxMaKefuMessage build() { | |||
| WxMaKefuMessage m = super.build(); | |||
| m.setContent(this.content); | |||
| m.setText(new WxMaKefuMessage.KfText(this.content)); | |||
| return m; | |||
| } | |||
| } | |||
| @@ -2,29 +2,29 @@ package cn.binarywang.wx.miniapp.constant; | |||
| /** | |||
| * <pre> | |||
| * 小程序常量 | |||
| * 小程序常量. | |||
| * </pre> | |||
| * | |||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
| */ | |||
| public class WxMaConstants { | |||
| /** | |||
| * 微信接口返回的参数errcode | |||
| * 微信接口返回的参数errcode. | |||
| */ | |||
| public static final String ERRCODE = "errcode"; | |||
| /** | |||
| * 素材类型 | |||
| * 素材类型. | |||
| */ | |||
| public static class MediaType { | |||
| /** | |||
| * 图片 | |||
| * 图片. | |||
| */ | |||
| public static final String IMAGE = "image"; | |||
| } | |||
| /** | |||
| * 消息格式 | |||
| * 消息格式. | |||
| */ | |||
| public static class MsgDataFormat { | |||
| public static final String XML = "XML"; | |||
| @@ -32,32 +32,40 @@ public class WxMaConstants { | |||
| } | |||
| /** | |||
| * 客服消息的消息类型 | |||
| * 客服消息的消息类型. | |||
| */ | |||
| public static class KefuMsgType { | |||
| /** | |||
| * 文本消息 | |||
| * 文本消息. | |||
| */ | |||
| public static final String TEXT = "text"; | |||
| /** | |||
| * 图片消息 | |||
| * 图片消息. | |||
| */ | |||
| public static final String IMAGE = "image"; | |||
| /** | |||
| * 图文链接. | |||
| */ | |||
| public static final String LINK = "link"; | |||
| /** | |||
| * 小程序卡片消息. | |||
| */ | |||
| public static final String MA_PAGE = "miniprogrampage"; | |||
| } | |||
| public static final class ErrorCode { | |||
| /** | |||
| * 40001 获取access_token时AppSecret错误,或者access_token无效 | |||
| * 40001 获取access_token时AppSecret错误,或者access_token无效. | |||
| */ | |||
| public static final int ERR_40001 = 40001; | |||
| /** | |||
| * 42001 access_token超时 | |||
| * 42001 access_token超时. | |||
| */ | |||
| public static final int ERR_42001 = 42001; | |||
| /** | |||
| * 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期) | |||
| * 40014 不合法的access_token,请开发者认真比对access_token的有效性(如是否过期). | |||
| */ | |||
| public static final int ERR_40014 = 40014; | |||
| } | |||
| @@ -1,6 +1,5 @@ | |||
| package cn.binarywang.wx.miniapp.util.json; | |||
| import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage; | |||
| import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; | |||
| import com.google.gson.Gson; | |||
| import com.google.gson.GsonBuilder; | |||
| @@ -13,7 +12,6 @@ public class WxMaGsonBuilder { | |||
| static { | |||
| INSTANCE.disableHtmlEscaping(); | |||
| INSTANCE.registerTypeAdapter(WxMaKefuMessage.class, new WxMaKefuMessageGsonAdapter()); | |||
| 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 com.google.common.collect.Lists; | |||
| import com.google.inject.Inject; | |||
| import me.chanjar.weixin.common.api.WxConsts; | |||
| 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.util.Date; | |||
| /** | |||
| * 测试客服相关接口 | |||
| * 测试消息相关接口 | |||
| * | |||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||
| */ | |||
| @@ -25,26 +23,14 @@ import java.util.Date; | |||
| public class WxMaMsgServiceImplTest { | |||
| @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 { | |||
| 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); | |||
| } | |||
| @@ -1,8 +1,8 @@ | |||
| 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> | |||
| @@ -10,30 +10,35 @@ import org.testng.annotations.Test; | |||
| @Test | |||
| 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\"}}"); | |||
| } | |||