| @@ -5,7 +5,9 @@ import java.util.ArrayList; | |||||
| import java.util.List; | import java.util.List; | ||||
| import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||
| import lombok.Builder; | |||||
| import lombok.Data; | import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | |||||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | ||||
| /** | /** | ||||
| @@ -34,6 +36,14 @@ public class WxCpUser implements Serializable { | |||||
| private String telephone; | private String telephone; | ||||
| private String qrCode; | private String qrCode; | ||||
| private Boolean toInvite; | private Boolean toInvite; | ||||
| /** | |||||
| * 成员对外信息. | |||||
| */ | |||||
| private List<ExternalAttr> externalAttrs = new ArrayList<>(); | |||||
| public void addExternalAttr(ExternalAttr externalAttr) { | |||||
| this.externalAttrs.add(externalAttr); | |||||
| } | |||||
| public void addExtAttr(String name, String value) { | public void addExtAttr(String name, String value) { | ||||
| this.extAttrs.add(new Attr(name, value)); | this.extAttrs.add(new Attr(name, value)); | ||||
| @@ -54,4 +64,40 @@ public class WxCpUser implements Serializable { | |||||
| private String value; | private String value; | ||||
| } | } | ||||
| @Data | |||||
| @Builder | |||||
| @NoArgsConstructor | |||||
| @AllArgsConstructor | |||||
| public static class ExternalAttr { | |||||
| /** | |||||
| * 属性类型: 0-本文 1-网页 2-小程序. | |||||
| */ | |||||
| private int type; | |||||
| /** | |||||
| * 属性名称: 需要先确保在管理端有创建改属性,否则会忽略. | |||||
| */ | |||||
| private String name; | |||||
| /** | |||||
| * 文本属性内容,长度限制12个UTF8字符. | |||||
| */ | |||||
| private String value; | |||||
| /** | |||||
| * 网页的url,必须包含http或者https头. | |||||
| */ | |||||
| private String url; | |||||
| /** | |||||
| * 小程序的展示标题,长度限制12个UTF8字符. | |||||
| * 或者 网页的展示标题,长度限制12个UTF8字符 | |||||
| */ | |||||
| private String title; | |||||
| /** | |||||
| * 小程序appid,必须是有在本企业安装授权的小程序,否则会被忽略. | |||||
| */ | |||||
| private String appid; | |||||
| /** | |||||
| * 小程序的页面路径. | |||||
| */ | |||||
| private String pagePath; | |||||
| } | |||||
| } | } | ||||
| @@ -10,6 +10,9 @@ import me.chanjar.weixin.cp.bean.WxCpMessage; | |||||
| import me.chanjar.weixin.cp.bean.WxCpTag; | import me.chanjar.weixin.cp.bean.WxCpTag; | ||||
| import me.chanjar.weixin.cp.bean.WxCpUser; | import me.chanjar.weixin.cp.bean.WxCpUser; | ||||
| /** | |||||
| * @author Daniel Qian | |||||
| */ | |||||
| public class WxCpGsonBuilder { | public class WxCpGsonBuilder { | ||||
| public static final GsonBuilder INSTANCE = new GsonBuilder(); | public static final GsonBuilder INSTANCE = new GsonBuilder(); | ||||
| @@ -27,10 +27,11 @@ import me.chanjar.weixin.cp.bean.WxCpUser; | |||||
| * @author Daniel Qian | * @author Daniel Qian | ||||
| */ | */ | ||||
| public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSerializer<WxCpUser> { | public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSerializer<WxCpUser> { | ||||
| private static final String EXTERNAL_PROFILE = "external_profile"; | |||||
| private static final String EXTERNAL_ATTR = "external_attr"; | |||||
| @Override | @Override | ||||
| public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) | |||||
| throws JsonParseException { | |||||
| public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { | |||||
| JsonObject o = json.getAsJsonObject(); | JsonObject o = json.getAsJsonObject(); | ||||
| WxCpUser user = new WxCpUser(); | WxCpUser user = new WxCpUser(); | ||||
| @@ -71,6 +72,53 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri | |||||
| user.getExtAttrs().add(attr); | user.getExtAttrs().add(attr); | ||||
| } | } | ||||
| } | } | ||||
| if (GsonHelper.isNotNull(o.get(EXTERNAL_PROFILE))) { | |||||
| JsonArray attrJsonElements = o.get(EXTERNAL_PROFILE).getAsJsonObject().get(EXTERNAL_ATTR).getAsJsonArray(); | |||||
| for (JsonElement element : attrJsonElements) { | |||||
| final Integer type = GsonHelper.getInteger(element.getAsJsonObject(), "type"); | |||||
| final String name = GsonHelper.getString(element.getAsJsonObject(), "name"); | |||||
| switch (type) { | |||||
| case 0: { | |||||
| user.getExternalAttrs() | |||||
| .add(WxCpUser.ExternalAttr.builder() | |||||
| .type(type) | |||||
| .name(name) | |||||
| .value(GsonHelper.getString(element.getAsJsonObject().get("text").getAsJsonObject(), "value")) | |||||
| .build() | |||||
| ); | |||||
| break; | |||||
| } | |||||
| case 1: { | |||||
| final JsonObject web = element.getAsJsonObject().get("web").getAsJsonObject(); | |||||
| user.getExternalAttrs() | |||||
| .add(WxCpUser.ExternalAttr.builder() | |||||
| .type(type) | |||||
| .name(name) | |||||
| .url(GsonHelper.getString(web, "url")) | |||||
| .title(GsonHelper.getString(web, "title")) | |||||
| .build() | |||||
| ); | |||||
| break; | |||||
| } | |||||
| case 2: { | |||||
| final JsonObject miniprogram = element.getAsJsonObject().get("miniprogram").getAsJsonObject(); | |||||
| user.getExternalAttrs() | |||||
| .add(WxCpUser.ExternalAttr.builder() | |||||
| .type(type) | |||||
| .name(name) | |||||
| .appid(GsonHelper.getString(miniprogram, "appid")) | |||||
| .pagePath(GsonHelper.getString(miniprogram, "pagepath")) | |||||
| .title(GsonHelper.getString(miniprogram, "title")) | |||||
| .build() | |||||
| ); | |||||
| break; | |||||
| } | |||||
| default://ignored | |||||
| } | |||||
| } | |||||
| } | |||||
| return user; | return user; | ||||
| } | } | ||||
| @@ -145,6 +193,45 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri | |||||
| attrsJson.add("attrs", attrsJsonArray); | attrsJson.add("attrs", attrsJsonArray); | ||||
| o.add("extattr", attrsJson); | o.add("extattr", attrsJson); | ||||
| } | } | ||||
| if (user.getExternalAttrs().size() > 0) { | |||||
| JsonArray attrsJsonArray = new JsonArray(); | |||||
| for (WxCpUser.ExternalAttr attr : user.getExternalAttrs()) { | |||||
| JsonObject attrJson = new JsonObject(); | |||||
| attrJson.addProperty("type",attr.getType()); | |||||
| attrJson.addProperty("name", attr.getName()); | |||||
| switch (attr.getType()) { | |||||
| case 0: { | |||||
| JsonObject text = new JsonObject(); | |||||
| text.addProperty("value", attr.getValue()); | |||||
| attrJson.add("text", text); | |||||
| break; | |||||
| } | |||||
| case 1: { | |||||
| JsonObject web = new JsonObject(); | |||||
| web.addProperty("url", attr.getUrl()); | |||||
| web.addProperty("title", attr.getTitle()); | |||||
| attrJson.add("web", web); | |||||
| break; | |||||
| } | |||||
| case 2: { | |||||
| JsonObject miniprogram = new JsonObject(); | |||||
| miniprogram.addProperty("appid", attr.getAppid()); | |||||
| miniprogram.addProperty("pagepath", attr.getPagePath()); | |||||
| miniprogram.addProperty("title", attr.getTitle()); | |||||
| attrJson.add("miniprogram", miniprogram); | |||||
| break; | |||||
| } | |||||
| default://忽略 | |||||
| } | |||||
| attrsJsonArray.add(attrJson); | |||||
| } | |||||
| JsonObject attrsJson = new JsonObject(); | |||||
| attrsJson.add(EXTERNAL_ATTR, attrsJsonArray); | |||||
| o.add(EXTERNAL_PROFILE, attrsJson); | |||||
| } | |||||
| return o; | return o; | ||||
| } | } | ||||
| @@ -0,0 +1,124 @@ | |||||
| package me.chanjar.weixin.cp.util.json; | |||||
| import org.testng.annotations.*; | |||||
| import me.chanjar.weixin.cp.bean.WxCpUser; | |||||
| import static org.assertj.core.api.Assertions.assertThat; | |||||
| /** | |||||
| * <pre> | |||||
| * | |||||
| * Created by Binary Wang on 2018/9/16. | |||||
| * </pre> | |||||
| * | |||||
| * @author BinaryWang | |||||
| */ | |||||
| public class WxCpUserGsonAdapterTest { | |||||
| @Test | |||||
| public void testDeserialize() { | |||||
| final String userJson = "{\n" + | |||||
| " \"errcode\": 0,\n" + | |||||
| " \"errmsg\": \"ok\",\n" + | |||||
| " \"userid\": \"zhangsan\",\n" + | |||||
| " \"name\": \"李四\",\n" + | |||||
| " \"department\": [1, 2],\n" + | |||||
| " \"order\": [1, 2],\n" + | |||||
| " \"position\": \"后台工程师\",\n" + | |||||
| " \"mobile\": \"15913215421\",\n" + | |||||
| " \"gender\": \"1\",\n" + | |||||
| " \"email\": \"zhangsan@gzdev.com\",\n" + | |||||
| " \"isleader\": 1,\n" + | |||||
| " \"avatar\": \"http://wx.qlogo.cn/mmopen/ajNVdqHZLLA3WJ6DSZUfiakYe37PKnQhBIeOQBO4czqrnZDS79FH5Wm5m4X69TBicnHFlhiafvDwklOpZeXYQQ2icg/0\",\n" + | |||||
| " \"telephone\": \"020-123456\",\n" + | |||||
| " \"enable\": 1,\n" + | |||||
| " \"alias\": \"jackzhang\",\n" + | |||||
| " \"extattr\": {\n" + | |||||
| " \"attrs\": [{\n" + | |||||
| " \"name\": \"爱好\",\n" + | |||||
| " \"value\": \"旅游\"\n" + | |||||
| " }, {\n" + | |||||
| " \"name\": \"卡号\",\n" + | |||||
| " \"value\": \"1234567234\"\n" + | |||||
| " }]\n" + | |||||
| " },\n" + | |||||
| " \"status\": 1,\n" + | |||||
| " \"qr_code\": \"https://open.work.weixin.qq.com/wwopen/userQRCode?vcode=xxx\",\n" + | |||||
| " \"external_profile\": {\n" + | |||||
| " \"external_attr\": [{\n" + | |||||
| " \"type\": 0,\n" + | |||||
| " \"name\": \"文本名称\",\n" + | |||||
| " \"text\": {\n" + | |||||
| " \"value\": \"文本\"\n" + | |||||
| " }\n" + | |||||
| " },\n" + | |||||
| " {\n" + | |||||
| " \"type\": 1,\n" + | |||||
| " \"name\": \"网页名称\",\n" + | |||||
| " \"web\": {\n" + | |||||
| " \"url\": \"http://www.test.com\",\n" + | |||||
| " \"title\": \"标题\"\n" + | |||||
| " }\n" + | |||||
| " },\n" + | |||||
| " {\n" + | |||||
| " \"type\": 2,\n" + | |||||
| " \"name\": \"测试app\",\n" + | |||||
| " \"miniprogram\": {\n" + | |||||
| " \"appid\": \"wx8bd80126147df384\",\n" + | |||||
| " \"pagepath\": \"/index\",\n" + | |||||
| " \"title\": \"my miniprogram\"\n" + | |||||
| " }\n" + | |||||
| " }\n" + | |||||
| " ]\n" + | |||||
| " }\n" + | |||||
| "}"; | |||||
| final WxCpUser user = WxCpUser.fromJson(userJson); | |||||
| assertThat(user).isNotNull(); | |||||
| assertThat(user.getExternalAttrs()).isNotEmpty(); | |||||
| final WxCpUser.ExternalAttr externalAttr1 = user.getExternalAttrs().get(0); | |||||
| assertThat(externalAttr1.getType()).isEqualTo(0); | |||||
| assertThat(externalAttr1.getName()).isEqualTo("文本名称"); | |||||
| assertThat(externalAttr1.getValue()).isEqualTo("文本"); | |||||
| final WxCpUser.ExternalAttr externalAttr2 = user.getExternalAttrs().get(1); | |||||
| assertThat(externalAttr2.getType()).isEqualTo(1); | |||||
| assertThat(externalAttr2.getName()).isEqualTo("网页名称"); | |||||
| assertThat(externalAttr2.getUrl()).isEqualTo("http://www.test.com"); | |||||
| assertThat(externalAttr2.getTitle()).isEqualTo("标题"); | |||||
| final WxCpUser.ExternalAttr externalAttr3 = user.getExternalAttrs().get(2); | |||||
| assertThat(externalAttr3.getType()).isEqualTo(2); | |||||
| assertThat(externalAttr3.getName()).isEqualTo("测试app"); | |||||
| assertThat(externalAttr3.getAppid()).isEqualTo("wx8bd80126147df384"); | |||||
| assertThat(externalAttr3.getPagePath()).isEqualTo("/index"); | |||||
| assertThat(externalAttr3.getTitle()).isEqualTo("my miniprogram"); | |||||
| } | |||||
| @Test | |||||
| public void testSerialize() { | |||||
| WxCpUser user = new WxCpUser(); | |||||
| user.addExternalAttr(WxCpUser.ExternalAttr.builder() | |||||
| .type(0) | |||||
| .name("文本名称") | |||||
| .value("文本") | |||||
| .build()); | |||||
| user.addExternalAttr(WxCpUser.ExternalAttr.builder() | |||||
| .type(1) | |||||
| .name("网页名称") | |||||
| .url("http://www.test.com") | |||||
| .title("标题") | |||||
| .build()); | |||||
| user.addExternalAttr(WxCpUser.ExternalAttr.builder() | |||||
| .type(2) | |||||
| .name("测试app") | |||||
| .appid("wx8bd80126147df384") | |||||
| .pagePath("/index") | |||||
| .title("my miniprogram") | |||||
| .build()); | |||||
| assertThat(user.toJson()).isEqualTo("{\"external_profile\":{\"external_attr\":[{\"type\":0,\"name\":\"文本名称\",\"text\":{\"value\":\"文本\"}},{\"type\":1,\"name\":\"网页名称\",\"web\":{\"url\":\"http://www.test.com\",\"title\":\"标题\"}},{\"type\":2,\"name\":\"测试app\",\"miniprogram\":{\"appid\":\"wx8bd80126147df384\",\"pagepath\":\"/index\",\"title\":\"my miniprogram\"}}]}}"); | |||||
| } | |||||
| } | |||||