企业MediaApi新增批量上传成员、部门接口

This commit is contained in:
jinyu 2015-04-04 11:56:17 +08:00
parent ab587d5f0a
commit 7d8c8dda47
20 changed files with 440 additions and 56 deletions

View File

@ -221,3 +221,9 @@
+ **weixin4j-qy**: 新增[BatchApi](./weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/BatchApi.java)批量异步执行任务接口 + **weixin4j-qy**: 新增[BatchApi](./weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/BatchApi.java)批量异步执行任务接口
+ **weixin4j-qy**: <font color="red">DepartApi命名为[PartyApi](./weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/PartyApi.java)</font> + **weixin4j-qy**: <font color="red">DepartApi命名为[PartyApi](./weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/PartyApi.java)</font>
* 2015-04-04
+ **weixin4j-qy**: [MediaApi](./weixin4j-qy/weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java)新增批量上传成员和部门接口
<font color="red">released 1.3</font>

View File

@ -71,11 +71,9 @@ netty的代码没有放到maven中心仓库,也没什么意义,因为最终需
接下来 接下来
------ ------
* 公众号服务应用 * 公众号第三方服务应用
* 企业号第三方应用 * 企业号第三方应用 & 企业号登陆授权
* 企业号登陆授权
* 微信小店 * 微信小店

View File

@ -42,7 +42,7 @@ public abstract class BaseApi {
protected abstract ResourceBundle getWeixinBundle(); protected abstract ResourceBundle getWeixinBundle();
protected String getRequestUri(String key) { protected String getRequestUri(String key) {
String url = getWeixinBundle().getString(key); String url = getConfigValue(key);
Pattern p = Pattern.compile("(\\{[^\\}]*\\})"); Pattern p = Pattern.compile("(\\{[^\\}]*\\})");
Matcher m = p.matcher(url); Matcher m = p.matcher(url);
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
@ -55,4 +55,8 @@ public abstract class BaseApi {
m.appendTail(sb); m.appendTail(sb);
return sb.toString(); return sb.toString();
} }
protected String getConfigValue(String key) {
return getWeixinBundle().getString(key);
}
} }

View File

@ -196,32 +196,22 @@ public class HttpRequest {
EntityUtils.consume(httpEntity); EntityUtils.consume(httpEntity);
Header contentType = httpResponse Header contentType = httpResponse
.getFirstHeader(HttpHeaders.CONTENT_TYPE); .getFirstHeader(HttpHeaders.CONTENT_TYPE);
Header disposition = httpResponse
.getFirstHeader("Content-disposition");
System.err.println(response.getAsString()); System.err.println(response.getAsString());
// error with html // json
if (contentType.getValue().contains( if (contentType.getValue().contains(
ContentType.TEXT_HTML.getMimeType())) { ContentType.APPLICATION_JSON.getMimeType())
// response.setText(new String(data, "gbk")); || (disposition != null && disposition.getValue().indexOf(
try { ".json") > 0)) {
checkJson(response);
return response;
} catch (JSONException e) {
;
}
try {
checkXml(response);
return response;
} catch (CannotResolveClassException ex) {
;
}
throw new WeixinException(response.getAsString());
} else if (contentType.getValue().contains(
ContentType.APPLICATION_JSON.getMimeType())) {
checkJson(response); checkJson(response);
} else if (contentType.getValue().contains( } else if (contentType.getValue().contains(
ContentType.TEXT_XML.getMimeType())) { ContentType.TEXT_XML.getMimeType())) {
checkXml(response); checkXml(response);
} else if (contentType.getValue().contains( } else if (contentType.getValue().contains(
ContentType.TEXT_PLAIN.getMimeType())) { ContentType.TEXT_PLAIN.getMimeType())
|| contentType.getValue().contains(
ContentType.TEXT_HTML.getMimeType())) {
try { try {
checkJson(response); checkJson(response);
return response; return response;

View File

@ -19,6 +19,7 @@ import com.foxinmy.weixin4j.mp.payment.v3.MPPaymentResult;
import com.foxinmy.weixin4j.mp.payment.v3.Redpacket; import com.foxinmy.weixin4j.mp.payment.v3.Redpacket;
import com.foxinmy.weixin4j.mp.payment.v3.RedpacketSendResult; import com.foxinmy.weixin4j.mp.payment.v3.RedpacketSendResult;
import com.foxinmy.weixin4j.util.RandomUtil; import com.foxinmy.weixin4j.util.RandomUtil;
import com.foxinmy.weixin4j.xml.XmlStream;
/** /**
* 现金API * 现金API
@ -135,7 +136,11 @@ public class CashApi extends MpApi {
} }
} }
} }
return response.getAsObject(new TypeReference<MPPaymentResult>() { String text = response.getAsString()
}); .replaceFirst("<mch_appid>", "<appid>")
.replaceFirst("</mch_appid>", "</appid>")
.replaceFirst("<mchid>", "<mch_id>")
.replaceFirst("</mchid>", "</mch_id>");
return XmlStream.get(text, MPPaymentResult.class);
} }
} }

View File

@ -26,7 +26,7 @@
<!--for further documentation --> <!--for further documentation -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/tmp/weixin/log/weixin.mp.%d{yyyy-MM-dd}.log <fileNamePattern>/tmp/weixin/log/mp/weixin.mp.%d{yyyy-MM-dd}.log
</fileNamePattern> </fileNamePattern>
<maxHistory>30</maxHistory> <maxHistory>30</maxHistory>
</rollingPolicy> </rollingPolicy>

View File

@ -130,3 +130,7 @@ weixin4j-qy
+ **weixin4j-qy-api**: 新增[BatchApi](./weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/BatchApi.java)批量异步执行任务接口 + **weixin4j-qy-api**: 新增[BatchApi](./weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/BatchApi.java)批量异步执行任务接口
+ **weixin4j-qy-api**: <font color="red">DepartApi命名为[PartyApi](./weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/PartyApi.java)</font> + **weixin4j-qy-api**: <font color="red">DepartApi命名为[PartyApi](./weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/PartyApi.java)</font>
* 2015-04-04
+ **weixin4j-qy-api**: [MediaApi](./weixin4j-qy-api/src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java)新增批量上传成员和部门接口

View File

@ -99,3 +99,7 @@ weixin.properties说明
+ 新增[BatchApi](./src/main/java/com/foxinmy/weixin4j/qy/api/BatchApi.java)批量异步执行任务接口 + 新增[BatchApi](./src/main/java/com/foxinmy/weixin4j/qy/api/BatchApi.java)批量异步执行任务接口
+ <font color="red">DepartApi命名为[PartyApi](./src/main/java/com/foxinmy/weixin4j/qy/api/PartyApi.java)</font> + <font color="red">DepartApi命名为[PartyApi](./src/main/java/com/foxinmy/weixin4j/qy/api/PartyApi.java)</font>
* 2015-04-04
+ [MediaApi](./src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java)新增批量上传成员和部门接口

View File

@ -1,15 +1,23 @@
package com.foxinmy.weixin4j.qy; package com.foxinmy.weixin4j.qy;
import java.io.File;
import java.io.IOException;
import java.util.List; import java.util.List;
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;
import com.foxinmy.weixin4j.model.Button;
import com.foxinmy.weixin4j.qy.api.AgentApi; import com.foxinmy.weixin4j.qy.api.AgentApi;
import com.foxinmy.weixin4j.qy.api.BatchApi; import com.foxinmy.weixin4j.qy.api.BatchApi;
import com.foxinmy.weixin4j.qy.api.HelperApi; import com.foxinmy.weixin4j.qy.api.HelperApi;
import com.foxinmy.weixin4j.qy.api.MediaApi;
import com.foxinmy.weixin4j.qy.api.MenuApi;
import com.foxinmy.weixin4j.qy.api.NotifyApi;
import com.foxinmy.weixin4j.qy.api.PartyApi; import com.foxinmy.weixin4j.qy.api.PartyApi;
import com.foxinmy.weixin4j.qy.api.TagApi; import com.foxinmy.weixin4j.qy.api.TagApi;
import com.foxinmy.weixin4j.qy.api.UserApi; import com.foxinmy.weixin4j.qy.api.UserApi;
import com.foxinmy.weixin4j.qy.message.NotifyMessage;
import com.foxinmy.weixin4j.qy.model.AgentInfo; import com.foxinmy.weixin4j.qy.model.AgentInfo;
import com.foxinmy.weixin4j.qy.model.AgentSetter; import com.foxinmy.weixin4j.qy.model.AgentSetter;
import com.foxinmy.weixin4j.qy.model.BatchResult; import com.foxinmy.weixin4j.qy.model.BatchResult;
@ -24,6 +32,7 @@ import com.foxinmy.weixin4j.token.FileTokenHolder;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.token.WeixinTokenCreator; import com.foxinmy.weixin4j.token.WeixinTokenCreator;
import com.foxinmy.weixin4j.type.AccountType; import com.foxinmy.weixin4j.type.AccountType;
import com.foxinmy.weixin4j.type.MediaType;
/** /**
* 微信企业号接口实现 * 微信企业号接口实现
@ -35,6 +44,9 @@ import com.foxinmy.weixin4j.type.AccountType;
* @see <a href="http://qydev.weixin.qq.com/wiki/index.php">api文档</a> * @see <a href="http://qydev.weixin.qq.com/wiki/index.php">api文档</a>
*/ */
public class WeixinProxy { public class WeixinProxy {
private final MediaApi mediaApi;
private final MenuApi menuApi;
private final NotifyApi notifyApi;
private final PartyApi partyApi; private final PartyApi partyApi;
private final UserApi userApi; private final UserApi userApi;
private final TagApi tagApi; private final TagApi tagApi;
@ -72,6 +84,186 @@ public class WeixinProxy {
this.helperApi = new HelperApi(tokenHolder); this.helperApi = new HelperApi(tokenHolder);
this.agentApi = new AgentApi(tokenHolder); this.agentApi = new AgentApi(tokenHolder);
this.batchApi = new BatchApi(tokenHolder); this.batchApi = new BatchApi(tokenHolder);
this.notifyApi = new NotifyApi(tokenHolder);
this.menuApi = new MenuApi(tokenHolder);
this.mediaApi = new MediaApi(tokenHolder);
}
/**
* 发送消息(需要管理员对应用有使用权限对收件人tousertopartytotag有查看权限否则本次调用失败)
* <p>
* 1 发送人员列表存在错误的userid执行发送开发者需注意返回结果说明</br>
* 2发送人员不在通讯录权限范围内不执行发送任务返回首个出错的userid</br>
* 3发送人员不在应用可见范围内不执行发送任务返回首个出错的userid</br>
* </p>
*
* @param notify
* 客服消息对象
* @return
* 如果对应用或收件人部门标签任何一个无权限则本次发送失败如果收件人部门或标签不存在发送仍然执行但返回无效的部分</br>
* { "errcode": 0, "errmsg": "ok", "invaliduser": "UserID1",
* "invalidparty":"PartyID1", "invalidtag":"TagID1" }
* @throws WeixinException
* @see com.foxinmy.weixin4j.qy.api.NotifyApi
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E">发送接口说明</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E6%B6%88%E6%81%AF%E7%B1%BB%E5%9E%8B%E5%8F%8A%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F">发送格式说明</a>
* @see com.foxinmy.weixin4j.msg.model.Text
* @see com.foxinmy.weixin4j.msg.model.Image
* @see com.foxinmy.weixin4j.msg.model.Voice
* @see com.foxinmy.weixin4j.msg.model.Video
* @see com.foxinmy.weixin4j.msg.model.File
* @see com.foxinmy.weixin4j.msg.model.News
* @see com.foxinmy.weixin4j.msg.model.MpNews
* @see com.foxinmy.weixin4j.qy.message.NotifyMessage
*/
public JSONObject sendNotify(NotifyMessage notify) throws WeixinException {
return notifyApi.sendNotify(notify);
}
/**
* 自定义菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式)
*
* @param btnList
* 菜单列表
* @param agentid
* 应用ID
* @throws WeixinException
* @see com.foxinmy.weixin4j.qy.api.MenuApi
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%88%9B%E5%BB%BA%E5%BA%94%E7%94%A8%E8%8F%9C%E5%8D%95">创建自定义菜单</a>
* @see com.foxinmy.weixin4j.model.Button
*/
public JsonResult createMenu(List<Button> btnList, int agentid)
throws WeixinException {
return menuApi.createMenu(btnList, agentid);
}
/**
* 查询菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式)
*
* @param agentid
* 应用ID
* @return 菜单集合
* @throws WeixinException
* @see com.foxinmy.weixin4j.qy.api.MenuApi
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E8%8F%9C%E5%8D%95%E5%88%97%E8%A1%A8">查询菜单</a>
* @see com.foxinmy.weixin4j.model.Button
*/
public List<Button> getMenu(int agentid) throws WeixinException {
return menuApi.getMenu(agentid);
}
/**
* 删除菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式)
*
* @param agentid
* 应用ID
* @throws WeixinException
* @see com.foxinmy.weixin4j.qy.api.MenuApi
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%88%A0%E9%99%A4%E8%8F%9C%E5%8D%95">删除菜单</a>
* @return 处理结果
*/
public JsonResult deleteMenu(int agentid) throws WeixinException {
return menuApi.deleteMenu(agentid);
}
/**
* 上传媒体文件
*
* @param file
* 媒体对象
* @return 上传到微信服务器返回的媒体标识
* @see com.foxinmy.weixin4j.qy.api.MediaApi
* @see {@link com.foxinmy.weixin4j.qy.WeixinProxy.MediaApi#uploadMedia(File, MediaType)}
* @throws WeixinException
* @throws IOException
*/
public String uploadMedia(File file) throws WeixinException, IOException {
return mediaApi.uploadMedia(file);
}
/**
* 上传媒体文件
*
* @param file
* 文件对象
* @param mediaType
* 媒体类型
* @return 上传到微信服务器返回的媒体标识
* @throws WeixinException
* @throws IOException
* @see com.foxinmy.weixin4j.qy.api.MediaApi
* @see com.foxinmy.weixin4j.type.MediaType
* @see {@link com.foxinmy.weixin4j.qy.WeixinProxy#uploadMedia(String, byte[],String)}
*/
public String uploadMedia(File file, MediaType mediaType)
throws WeixinException, IOException {
return mediaApi.uploadMedia(file, mediaType);
}
/**
* 上传媒体文件(完全公开所有管理员均可调用media_id可以共享)
* <p>
* 正常情况下返回{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789},
* 否则抛出异常.
* </p>
*
* @param bytes
* 媒体数据包
* @param mediaType
* 媒体类型
* @return 上传到微信服务器返回的媒体标识
* @see com.foxinmy.weixin4j.qy.api.MediaApi
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">上传媒体文件说明</a>
* @throws WeixinException
*/
public String uploadMedia(String fileName, byte[] bytes, String mediaType)
throws WeixinException {
return mediaApi.uploadMedia(fileName, bytes, mediaType);
}
/**
* 下载媒体文件(完全公开所有管理员均可调用media_id可以共享)
*
* @param mediaId
* 媒体ID
* @return 二进制数据包
* @see com.foxinmy.weixin4j.qy.api.MediaApi
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">获取媒体说明</a>
* @throws WeixinException
*/
public byte[] downloadMedia(String mediaId) throws WeixinException {
return mediaApi.downloadMedia(mediaId);
}
/**
* 下载媒体文件(完全公开所有管理员均可调用media_id可以共享)
* <p>
* 正常情况下返回表头如Content-Type: image/jpeg,否则抛出异常.
* </p>
*
* @param mediaId
* 存储在微信服务器上的媒体标识
* @param extension
* 媒体后缀名
* @return 写入硬盘后的文件对象
* @throws WeixinException
* @throws IOException
* @see com.foxinmy.weixin4j.qy.api.MediaApi
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">获取媒体说明</a>
* @see com.foxinmy.weixin4j.type.MediaType
* @see {@link com.foxinmy.weixin4j.WeixinProxy.MediaApi#downloadMedia(String)}
*/
public File downloadMedia(String mediaId, String extension)
throws WeixinException {
return mediaApi.downloadMedia(mediaId, extension);
} }
/** /**
@ -137,6 +329,24 @@ public class WeixinProxy {
return partyApi.deleteParty(partyId); return partyApi.deleteParty(partyId);
} }
/**
* 批量上传部门
*
* @param parties
* 部门列表
* @see com.foxinmy.weixin4j.qy.api.MediaApi
* @see com.foxinmy.weixin4j.qy.api.BatchApi
* @see {@link com.foxinmy.weixin4j.qy.WeixinProxy#replaceparty(String,Callback)}
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1%E6%8E%A5%E5%8F%A3#.E9.80.9A.E8.AE.AF.E5.BD.95.E6.9B.B4.E6.96.B0">批量任务</a>
* @return 上传后的mediaId
* @throws WeixinException
*/
public String batchUploadParties(List<Party> parties)
throws WeixinException {
return mediaApi.batchUploadParties(parties);
}
/** /**
* 创建成员 * 创建成员
* *
@ -522,6 +732,25 @@ public class WeixinProxy {
throws WeixinException { throws WeixinException {
return batchApi.replaceuser(mediaId, callback); return batchApi.replaceuser(mediaId, callback);
} }
/**
* 批量上传成员
*
* @param users
* 成员列表
* @see com.foxinmy.weixin4j.qy.api.MediaApi
* @see com.foxinmy.weixin4j.qy.api.BatchApi
* @see {@link com.foxinmy.weixin4j.qy.WeixinProxy#syncuser(String,Callback)}
* @see {@link com.foxinmy.weixin4j.qy.WeixinProxy#replaceuser(String,Callback)}
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1%E6%8E%A5%E5%8F%A3#.E9.80.9A.E8.AE.AF.E5.BD.95.E6.9B.B4.E6.96.B0">批量任务</a>
* @return 上传后的mediaId
* @throws WeixinException
*/
public String batchUploadUsers(List<User> users) throws WeixinException {
return mediaApi.batchUploadUsers(users);
}
/** /**
* 批量覆盖部门,本接口以partyid为键全量覆盖企业号通讯录组织架构任务完成后企业号通讯录组织架构与提交的文件完全保持一致 * 批量覆盖部门,本接口以partyid为键全量覆盖企业号通讯录组织架构任务完成后企业号通讯录组织架构与提交的文件完全保持一致
* <p> * <p>

View File

@ -63,6 +63,7 @@ public class BatchApi extends QyApi {
/** /**
* 批量更新成员,本接口以userid为主键增量更新企业号通讯录成员 * 批量更新成员,本接口以userid为主键增量更新企业号通讯录成员
*
* <p> * <p>
* 1.模板中的部门需填写部门ID多个部门用分号分隔部门ID必须为数字</br> * 1.模板中的部门需填写部门ID多个部门用分号分隔部门ID必须为数字</br>
* 2.文件中存在通讯录中也存在的成员更新成员在文件中指定的字段值 </br> 3.文件中存在通讯录中不存在的成员执行添加操作</br> * 2.文件中存在通讯录中也存在的成员更新成员在文件中指定的字段值 </br> 3.文件中存在通讯录中不存在的成员执行添加操作</br>
@ -70,10 +71,11 @@ public class BatchApi extends QyApi {
* </p> * </p>
* *
* @param mediaId * @param mediaId
* 带user信息的cvs文件上传后的media_id TODO * 带user信息的cvs文件上传后的media_id
* @param callback * @param callback
* 接收任务执行结果的回调地址等信息 * 接收任务执行结果的回调地址等信息
* @return 异步任务id最大长度为64字符 * @return 异步任务id最大长度为64字符
* @see {@link com.foxinmy.weixin4j.qy.api.UserApi#batchUploadUsers(List)}
* @see com.foxinmy.weixin4j.qy.model.Callback * @see com.foxinmy.weixin4j.qy.model.Callback
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1%E6%8E%A5%E5%8F%A3#.E5.A2.9E.E9.87.8F.E6.9B.B4.E6.96.B0.E6.88.90.E5.91.98">批量更新成员</a> * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1%E6%8E%A5%E5%8F%A3#.E5.A2.9E.E9.87.8F.E6.9B.B4.E6.96.B0.E6.88.90.E5.91.98">批量更新成员</a>
@ -111,6 +113,7 @@ public class BatchApi extends QyApi {
* @param callback * @param callback
* 接收任务执行结果的回调地址等信息 * 接收任务执行结果的回调地址等信息
* @return 异步任务id最大长度为64字符 * @return 异步任务id最大长度为64字符
* @see {@link com.foxinmy.weixin4j.qy.api.UserApi#batchUploadUsers(List)}
* @see com.foxinmy.weixin4j.qy.model.Callback * @see com.foxinmy.weixin4j.qy.model.Callback
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1%E6%8E%A5%E5%8F%A3#.E5.85.A8.E9.87.8F.E8.A6.86.E7.9B.96.E6.88.90.E5.91.98">批量覆盖成员</a> * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1%E6%8E%A5%E5%8F%A3#.E5.85.A8.E9.87.8F.E8.A6.86.E7.9B.96.E6.88.90.E5.91.98">批量覆盖成员</a>

View File

@ -5,14 +5,26 @@ import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.StringWriter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils; 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.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.PartParameter; import com.foxinmy.weixin4j.http.PartParameter;
import com.foxinmy.weixin4j.http.Response; import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Consts;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.qy.model.Callback;
import com.foxinmy.weixin4j.qy.model.Party;
import com.foxinmy.weixin4j.qy.model.User;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.type.MediaType; import com.foxinmy.weixin4j.type.MediaType;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
@ -137,8 +149,8 @@ public class MediaApi extends QyApi {
os = new FileOutputStream(file); os = new FileOutputStream(file);
os.write(datas); os.write(datas);
} else { } else {
throw new WeixinException(String.format( throw new WeixinException(String.format("create file fail:%s",
"create file fail:%s", file.getAbsolutePath())); file.getAbsolutePath()));
} }
} catch (IOException e) { } catch (IOException e) {
throw new WeixinException(e.getMessage()); throw new WeixinException(e.getMessage());
@ -171,4 +183,70 @@ public class MediaApi extends QyApi {
token.getAccessToken(), mediaId)); token.getAccessToken(), mediaId));
return response.getBody(); return response.getBody();
} }
/**
* 批量上传成员
*
* @param users
* 成员列表
* @see {@link com.foxinmy.weixin4j.qy.api.BatchApi#syncuser(String,Callback)}
* @see {@link com.foxinmy.weixin4j.qy.api.BatchApi#replaceuser(String,Callback)}
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1%E6%8E%A5%E5%8F%A3#.E9.80.9A.E8.AE.AF.E5.BD.95.E6.9B.B4.E6.96.B0">批量任务</a>
* @return 上传后的mediaId
* @throws WeixinException
*/
public String batchUploadUsers(List<User> users) throws WeixinException {
return batchUpload("batch_syncuser.cvs", users);
}
/**
* 批量上传部门
*
* @param parties
* 部门列表
* @see {@link com.foxinmy.weixin4j.qy.api.BatchApi#replaceparty(String,Callback)}
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1%E6%8E%A5%E5%8F%A3#.E9.80.9A.E8.AE.AF.E5.BD.95.E6.9B.B4.E6.96.B0">批量任务</a>
* @return 上传后的mediaId
* @throws WeixinException
*/
public String batchUploadParties(List<Party> parties)
throws WeixinException {
return batchUpload("batch_replaceparty.cvs", parties);
}
private <T> String batchUpload(String batchName, List<T> models)
throws WeixinException {
JSONObject csvObj = JSON.parseObject(getConfigValue(batchName));
JSONArray columns = csvObj.getJSONArray("column");
StringWriter writer = new StringWriter();
writer.write(csvObj.getString("header"));
final Map<String, Object> column = new LinkedHashMap<String, Object>();
for (Object col : columns) {
column.put(col.toString(), "");
}
writer.write("\r\n");
for (T model : models) {
JSON.toJSONString(model, new PropertyFilter() {
@Override
public boolean apply(Object object, String name, Object value) {
if (column.containsKey(name)) {
column.put(name, value);
}
return true;
}
});
writer.write(StringUtils.join(column.values(), ","));
writer.write("\r\n");
}
String mediaId = uploadMedia(batchName,
writer.toString().getBytes(Consts.UTF_8), MediaType.file.name());
try {
writer.close();
} catch (IOException e) {
;
}
return mediaId;
}
} }

View File

@ -32,6 +32,9 @@ public class MenuApi extends QyApi {
* 自定义菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式) * 自定义菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式)
* *
* @param btnList * @param btnList
* 菜单列表
* @param agentid
* 应用ID
* @throws WeixinException * @throws WeixinException
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%88%9B%E5%BB%BA%E5%BA%94%E7%94%A8%E8%8F%9C%E5%8D%95">创建自定义菜单</a> * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%88%9B%E5%BB%BA%E5%BA%94%E7%94%A8%E8%8F%9C%E5%8D%95">创建自定义菜单</a>
@ -53,6 +56,8 @@ public class MenuApi extends QyApi {
/** /**
* 查询菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式) * 查询菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式)
* *
* @param agentid
* 应用ID
* @return 菜单集合 * @return 菜单集合
* @throws WeixinException * @throws WeixinException
* @see <a * @see <a
@ -73,6 +78,8 @@ public class MenuApi extends QyApi {
/** /**
* 删除菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式) * 删除菜单(管理员须拥有应用的管理权限 并且应用必须设置在回调模式)
* *
* @param agentid
* 应用ID
* @throws WeixinException * @throws WeixinException
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%88%A0%E9%99%A4%E8%8F%9C%E5%8D%95">删除菜单</a> * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%88%A0%E9%99%A4%E8%8F%9C%E5%8D%95">删除菜单</a>

View File

@ -251,7 +251,7 @@ public class UserApi extends QyApi {
* 成员ID * 成员ID
* @param tips * @param tips
* 推送到微信上的提示语只有认证号可以使用当使用微信推送时该字段默认为请关注XXX企业号邮件邀请时该字段无效 * 推送到微信上的提示语只有认证号可以使用当使用微信推送时该字段默认为请关注XXX企业号邮件邀请时该字段无效
* @return 调用结果 * @return 邀请类型
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E9.82.80.E8.AF.B7.E6.88.90.E5.91.98.E5.85.B3.E6.B3.A8">邀请成员关注说明</a> * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E9.82.80.E8.AF.B7.E6.88.90.E5.91.98.E5.85.B3.E6.B3.A8">邀请成员关注说明</a>
* @throws WeixinException * @throws WeixinException

View File

@ -69,9 +69,11 @@ agent_set_uri={api_base_url}/agent/set?access_token=%s
batch_inviteuser_uri={api_base_url}/batch/inviteuser?access_token=%s batch_inviteuser_uri={api_base_url}/batch/inviteuser?access_token=%s
# \u6279\u91cf\u66f4\u65b0\u6210\u5458 # \u6279\u91cf\u66f4\u65b0\u6210\u5458
batch_syncuser_uri={api_base_url}/batch/syncuser?access_token=%s batch_syncuser_uri={api_base_url}/batch/syncuser?access_token=%s
batch_syncuser.cvs={"header":"\u59d3\u540d,\u8d26\u53f7,\u5fae\u4fe1\u53f7,\u624b\u673a\u53f7,\u90ae\u7bb1,\u6240\u5728\u90e8\u95e8,\u804c\u4f4d","column":["name","userid","weixinid","mobile","email","department","position"]}
# \u6279\u91cf\u8986\u76d6\u6210\u5458 # \u6279\u91cf\u8986\u76d6\u6210\u5458
batch_replaceuser_uri={api_base_url}/batch/replaceuser?access_token=%s batch_replaceuser_uri={api_base_url}/batch/replaceuser?access_token=%s
# \u6279\u91cf\u8986\u76d6\u90e8\u95e8 # \u6279\u91cf\u8986\u76d6\u90e8\u95e8
batch_replaceparty_uri={api_base_url}/batch/replaceparty?access_token=%s batch_replaceparty_uri={api_base_url}/batch/replaceparty?access_token=%s
batch_replaceparty.cvs={"header":"\u90e8\u95e8\u540d\u79f0,\u90e8\u95e8ID,\u7236\u90e8\u95e8ID,\u6392\u5e8f","column":["name","id","parentid","order"]}
# \u83b7\u53d6\u5f02\u6b65\u4efb\u52a1\u6267\u884c\u7ed3\u679c # \u83b7\u53d6\u5f02\u6b65\u4efb\u52a1\u6267\u884c\u7ed3\u679c
batch_getresult_uri={api_base_url}/batch/getresult?access_token=%s&jobid=%s batch_getresult_uri={api_base_url}/batch/getresult?access_token=%s&jobid=%s

View File

@ -51,7 +51,7 @@ public class BatchResult extends JsonResult {
} }
public BatchType getType() { public BatchType getType() {
return BatchType.valueOf(type); return BatchType.valueOf(type.toUpperCase());
} }
public void setType(String type) { public void setType(String type) {
@ -92,7 +92,7 @@ public class BatchResult extends JsonResult {
@Override @Override
public String toString() { public String toString() {
return "BatchResult [status=" + status + ", type=" + type + ", total=" return "BatchResult [status=" + getStatus() + ", type=" + getType() + ", total="
+ total + ", percentage=" + percentage + ", remaintime=" + total + ", percentage=" + percentage + ", remaintime="
+ remaintime + ", result=" + result + "]"; + remaintime + ", result=" + result + "]";
} }

View File

@ -37,10 +37,11 @@ public class Party implements Serializable {
} }
public Party(String name) { public Party(String name) {
this(name, 1, 1); this(0, name, 1, 1);
} }
public Party(String name, int parentid, int order) { public Party(int id, String name, int parentid, int order) {
this.id = id;
this.name = name; this.name = name;
this.parentid = parentid; this.parentid = parentid;
this.order = order; this.order = order;
@ -80,7 +81,7 @@ public class Party implements Serializable {
@Override @Override
public String toString() { public String toString() {
return "Party [id=" + id + ", name=" + name + ", parentid=" return "Party [id=" + id + ", name=" + name + ", parentid=" + parentid
+ parentid + ", order=" + order + "]"; + ", order=" + order + "]";
} }
} }

View File

@ -66,6 +66,10 @@ public class User implements Serializable {
* 关注状态: 1=已关注2=已冻结4=未关注 * 关注状态: 1=已关注2=已冻结4=未关注
*/ */
private int status; private int status;
/**
* 启用/禁用成员1表示启用成员0表示禁用成员
*/
private int enable;
/** /**
* 非必须 扩展属性扩展属性需要在WEB管理端创建后才生效否则忽略未知属性的赋值 * 非必须 扩展属性扩展属性需要在WEB管理端创建后才生效否则忽略未知属性的赋值
*/ */
@ -152,7 +156,7 @@ public class User implements Serializable {
} }
@JSONField(serialize = false) @JSONField(serialize = false)
public Gender getEnumGender() { public Gender getFormatGender() {
if (gender == 0) { if (gender == 0) {
return Gender.male; return Gender.male;
} else if (gender == 1) { } else if (gender == 1) {
@ -199,8 +203,8 @@ public class User implements Serializable {
this.avatar = avatar; this.avatar = avatar;
} }
@JSONField(serialize = false) @JSONField(serialize = false, deserialize = false)
public UserStatus getStatus() { public UserStatus getFormatStatus() {
for (UserStatus userStatus : UserStatus.values()) { for (UserStatus userStatus : UserStatus.values()) {
if (userStatus.getVal() == status) { if (userStatus.getVal() == status) {
return userStatus; return userStatus;
@ -213,6 +217,19 @@ public class User implements Serializable {
this.status = status; this.status = status;
} }
public int getEnable() {
return enable;
}
@JSONField(serialize = false, deserialize = false)
public boolean getFormatEnable() {
return enable == 1;
}
public void setEnable(int enable) {
this.enable = enable;
}
public List<NameValue> getExtattr() { public List<NameValue> getExtattr() {
return extattr; return extattr;
} }
@ -237,8 +254,9 @@ public class User implements Serializable {
public String toString() { public String toString() {
return "User [userid=" + userid + ", name=" + name + ", department=" return "User [userid=" + userid + ", name=" + name + ", department="
+ department + ", position=" + position + ", mobile=" + mobile + department + ", position=" + position + ", mobile=" + mobile
+ ", gender=" + gender + ", tel=" + tel + ", email=" + email + ", gender=" + getFormatGender() + ", tel=" + tel + ", email="
+ ", weixinid=" + weixinid + ", avatar=" + avatar + ", status=" + email + ", weixinid=" + weixinid + ", avatar=" + avatar
+ status + ", extattr=" + extattr + "]"; + ", status=" + getFormatStatus() + ", enable="
+ getFormatEnable() + ", extattr=" + extattr + "]";
} }
} }

View File

@ -1,12 +1,16 @@
package com.foxinmy.weixin4j.qy.test; package com.foxinmy.weixin4j.qy.test;
import java.util.Arrays;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.qy.api.BatchApi; import com.foxinmy.weixin4j.qy.api.BatchApi;
import com.foxinmy.weixin4j.qy.api.MediaApi;
import com.foxinmy.weixin4j.qy.model.BatchResult; import com.foxinmy.weixin4j.qy.model.BatchResult;
import com.foxinmy.weixin4j.qy.model.Callback; import com.foxinmy.weixin4j.qy.model.Callback;
import com.foxinmy.weixin4j.qy.model.Party;
/** /**
* 异步任务测试 * 异步任务测试
@ -19,21 +23,39 @@ import com.foxinmy.weixin4j.qy.model.Callback;
*/ */
public class BatchTest extends TokenTest { public class BatchTest extends TokenTest {
public BatchApi batchApi; public BatchApi batchApi;
public MediaApi mediaApi;
@Before @Before
public void init() { public void init() {
this.batchApi = new BatchApi(tokenHolder); this.batchApi = new BatchApi(tokenHolder);
this.mediaApi = new MediaApi(tokenHolder);
}
@Test
public void syncuser() throws WeixinException {
String jobId = batchApi
.syncuser(
"1QFmZ8LE9dFxPPx8EH5Kfm3cqGXB0OuXY432ZpsfwMFTJjEDt7QI4GZB1UhYGOSYr",
new Callback("http://182.254.188.133:8090",
"gp2eGT5mIpngr",
"BRYfV4zPFUJb3v3MySNBg1ERKE3vyyMRoScu76vFySv"));
System.err.println(jobId);
} }
@Test @Test
public void replaceparty() throws WeixinException { public void replaceparty() throws WeixinException {
String jobId = batchApi.replaceparty("mediaId", new Callback("url", "token", "aesKey")); String mediaId = mediaApi.batchUploadParties(Arrays.asList(new Party(5,
"部门1", 1, 1), new Party(6, "部门2", 1, 1)));
String jobId = batchApi.replaceparty(mediaId, new Callback(
"http://182.254.188.133:8090", "gp2eGT5mIpngr",
"BRYfV4zPFUJb3v3MySNBg1ERKE3vyyMRoScu76vFySv"));
System.err.println(jobId); System.err.println(jobId);
} }
@Test @Test
public void getresult() throws WeixinException { public void getresult() throws WeixinException {
BatchResult result = batchApi.getresult("jobId"); BatchResult result = batchApi
.getresult("PVucPBfEapLnvQZ1ru2Vdw3Dbl-jXs3AEQdS24cqmI0");
System.err.println(result); System.err.println(result);
} }
} }

View File

@ -1,5 +1,6 @@
package com.foxinmy.weixin4j.qy.test; package com.foxinmy.weixin4j.qy.test;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.junit.Assert; import org.junit.Assert;
@ -8,14 +9,15 @@ import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult; import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.qy.api.MediaApi;
import com.foxinmy.weixin4j.qy.api.UserApi; import com.foxinmy.weixin4j.qy.api.UserApi;
import com.foxinmy.weixin4j.qy.model.User; import com.foxinmy.weixin4j.qy.model.User;
import com.foxinmy.weixin4j.qy.type.UserStatus; import com.foxinmy.weixin4j.qy.type.UserStatus;
/** /**
* 部门API测试 * 用户API测试
* *
* @className DepartTest * @className UserTest
* @author jy * @author jy
* @date 2014年11月18日 * @date 2014年11月18日
* @since JDK 1.7 * @since JDK 1.7
@ -23,10 +25,12 @@ import com.foxinmy.weixin4j.qy.type.UserStatus;
*/ */
public class UserTest extends TokenTest { public class UserTest extends TokenTest {
public UserApi userApi; public UserApi userApi;
public MediaApi mediaApi;
@Before @Before
public void init() { public void init() {
this.userApi = new UserApi(tokenHolder); this.userApi = new UserApi(tokenHolder);
this.mediaApi = new MediaApi(tokenHolder);
} }
@Test @Test
@ -39,6 +43,15 @@ public class UserTest extends TokenTest {
Assert.assertEquals("created", result.getDesc()); Assert.assertEquals("created", result.getDesc());
} }
@Test
public void batchUpload() throws WeixinException {
User user = new User("u001", "jack");
user.setMobile("13500000000");
user.setDepartment(1);
String mediaId = mediaApi.batchUploadUsers(Arrays.asList(user));
System.err.println(mediaId);
}
@Test @Test
public void update() throws WeixinException { public void update() throws WeixinException {
User user = new User("u001", "ted"); User user = new User("u001", "ted");

View File

@ -26,7 +26,7 @@
<!--for further documentation --> <!--for further documentation -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/tmp/weixin/log/weixin.qy.%d{yyyy-MM-dd}.log <fileNamePattern>/tmp/weixin/log/qy/weixin.qy.%d{yyyy-MM-dd}.log
</fileNamePattern> </fileNamePattern>
<maxHistory>30</maxHistory> <maxHistory>30</maxHistory>
</rollingPolicy> </rollingPolicy>