一.获取通讯录密钥
获取方式:
登录企业微信—>管理工具—>通讯录同步助手—>开启“API接口同步” ; 开启后,即可看到通讯录密钥,也可设置通讯录API的权限:读取或者编辑通讯录。
获取通讯录密钥的目的:
通过企业ID(CorpId)和 通讯录密钥可以获取通讯录相关接口的使用凭证(AccessToken)。有了AccessToken,就可以使用通讯录相关接口了。
凭证的获取方式有两种(此处暂时存疑,以待勘误):
通讯录AccessToken:CorpId+通讯录密钥
其他AccessToken:CorpId+应用密钥
二、创建接口类
public interface QyApiService {
/**
* 企业微信全量同步部门
* @return
* @throws Exception
*/
AjaxJson synchronizationDepart() throws Exception;
/**
* 企业微信全量覆盖成员
* @return
* @throws Exception
*/
AjaxJson synchronizationUser() throws Exception;
/**
* 获取异步任务结果
* @return
* @throws Exception
*/
AjaxJson getQyWeixinResult(HttpServletRequest request) throws Exception;
}
三、创建实现类
@Service
public class QyApiServiceImpl implements QyApiService {
private static final Logger logger = Logger.getLogger(QyApiServiceImpl.class);
// 农担非正式员工企业微信ID
private static final String WECHAT_2_CORP_ID = "ww21f9457079dfbd4b";
// 农担非正式员工企业微信通讯录管理密钥
private static final String WECHAT_2_ADDRESSBOOKSECRET ="v3grboxbxFisxLaf6o4mZ4WzWiWtWq83ZoMy1Rur9AM";
private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36";
@Autowired
private SystemService systemService;
@Override
public AjaxJson synchronizationDepart() throws Exception {
//获取AccessToken
String accessTokenUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + WECHAT_2_CORP_ID + "&corpsecret="+WECHAT_2_ADDRESSBOOKSECRET;
String httpOrgCreateTestRtn = HttpClientUtil.doGet(accessTokenUrl, null);
JSONObject json = JSONObject.parseObject(httpOrgCreateTestRtn);
String accessToken = json.get("access_token").toString();
// 组装部门数据
List<Map<String, String>> exportData = new ArrayList<Map<String, String>>();
Map row = new LinkedHashMap<String, String>();
TSDepart tsDepart = systemService.getEntity(TSDepart.class, "402883d463ba0b070163ba4d8d8100b2");
row.put("1", tsDepart.getDepartname());
row.put("2", "1");
row.put("3", "0");
row.put("4", "0");
exportData.add(row);
List<Map<String, Object>> tsDepartList = systemService.findForJdbc("select * from t_s_depart d where d.orgtype='biz' and d.parentdepartid=? and d.org_type='9' and d.departname!='待占位' order by d.org_code asc", "402883d463ba0b070163ba4d8d8100b2");
for (Map<String, Object> tsDepartMap : tsDepartList) {
row = new LinkedHashMap<String, String>();
String orgCode = tsDepartMap.get("ORG_CODE").toString();
orgCode = orgCode.substring(2);
row.put("1", tsDepartMap.get("DEPARTNAME").toString());
row.put("2", orgCode);
row.put("3", "1");
row.put("4", "0");
exportData.add(row);
List<Map<String, Object>> tsDepartTwoList = systemService.findForJdbc("select * from t_s_depart d where d.orgtype='biz' and d.parentdepartid=? and d.org_type='11' and d.departname!='待占位' order by d.org_code asc", tsDepartMap.get("ID"));
for (Map<String, Object> tsDepartTwoMap : tsDepartTwoList) {
row = new LinkedHashMap<String, String>();
String orgCodeTwo = tsDepartTwoMap.get("ORG_CODE").toString();
orgCodeTwo = orgCodeTwo.substring(2);
row.put("1", tsDepartTwoMap.get("DEPARTNAME").toString());
row.put("2", orgCodeTwo);
row.put("3", orgCode);
row.put("4", "0");
exportData.add(row);
}
}
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put("1", "部门名称");
map.put("2", "部门ID");
map.put("3", "父部门ID");
map.put("4", "排序");
File file = createCSVFile(exportData, map, "D:/hnndFile");
// 上传临时素材文件到企业微信
String media_id = mediaUpload(accessToken,file);
// 企业微信全量覆盖部门
String replacepartyUrl = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceparty?access_token=" + accessToken;
Map<String, Object> replacepartyMap = new HashMap<>();
replacepartyMap.put("media_id", media_id);
Map<String, Object> replacepartyCallbackMap = new HashMap<>();
replacepartyCallbackMap.put("url", "");
replacepartyCallbackMap.put("token", "");
replacepartyCallbackMap.put("encodingaeskey", "");
replacepartyMap.put("callback", replacepartyCallbackMap);
String replacepartyJson = JSON.toJSONString(replacepartyMap);
JSONObject jsonObject = WeiXinUtil.httpRequest(replacepartyUrl, "POST", replacepartyJson);
logger.info("全量覆盖部门返回值:" + jsonObject.toString());
AjaxJson ajaxJson= new AjaxJson();
ajaxJson.setObj(jsonObject);
return ajaxJson;
}
@Override
public AjaxJson synchronizationUser() throws Exception{
AjaxJson ajaxJson= new AjaxJson();
//获取AccessToken
String accessTokenUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + WECHAT_2_CORP_ID + "&corpsecret="+WECHAT_2_ADDRESSBOOKSECRET;
String httpOrgCreateTestRtn = HttpClientUtil.doGet(accessTokenUrl, null);
JSONObject json = JSONObject.parseObject(httpOrgCreateTestRtn);
String accessToken = json.get("access_token").toString();
// 组装用户数据
List<Map<String, String>> exportData = new ArrayList<Map<String, String>>();
Map row = new LinkedHashMap<String, String>();
List<Map<String, Object>> tsUserList = systemService.findForJdbc("select distinct tsbu.id,tsbu.realname,tsbu.username,tsu.mobilephone,tsu.email,tsu.personal_mail,tsbu.departid,tsd.departname,substr(tsd.org_code,3) as org_code, tsbu.userkey,tsu.emp_sex,'' as isleader,0 as sortno,'' as nickname,tsu.family_address,tsu.family_mobile,tsu.job_position from t_s_base_user tsbu left join t_s_user tsu on tsu.id=tsbu.id left join t_s_org_role_user tsoru on tsoru.user_id=tsbu.id left join t_s_role tsr on tsr.id=tsoru.role_id left join t_s_depart tsd on tsd.id=tsbu.departid where tsr.rolecode in ('fgsqdjl','qdjl','fwzxfzr') and tsu.job_position='3' and tsbu.status=1");
for (Map<String, Object> tsUserMap : tsUserList) {
row = new LinkedHashMap<String, String>();
String orgCode ="";
String roleName="";
row.put("1", tsUserMap.get("REALNAME").toString());
row.put("2", tsUserMap.get("USERNAME").toString());
if(!StringUtil.isNotEmpty(tsUserMap.get("MOBILEPHONE"))){
logger.info(String.format("姓名:%s,用户名:%s,手机号码为空",tsUserMap.get("REALNAME").toString(),tsUserMap.get("USERNAME").toString()));
}
row.put("3", tsUserMap.get("MOBILEPHONE")==null?"":tsUserMap.get("MOBILEPHONE").toString());
row.put("4", tsUserMap.get("PERSONAL_MAIL")==null?"":tsUserMap.get("PERSONAL_MAIL").toString());
row.put("5", tsUserMap.get("EMAIL")==null?"":tsUserMap.get("EMAIL").toString());
List<Map<String, Object>> tsDepartList = systemService.findForJdbc("select tsoru.*,tsd.departname,tsd.org_code,tsr.rolename from t_s_org_role_user tsoru left join t_s_depart tsd on tsd.id=tsoru.org_id left join t_s_role tsr on tsr.id=tsoru.role_id where tsoru.user_id=? ", tsUserMap.get("ID"));
for (Map<String, Object> tsDepartMap : tsDepartList) {
orgCode = tsDepartMap.get("ORG_CODE").toString();
orgCode = orgCode.substring(2);
if(roleName.length()==0){
roleName=roleName+tsDepartMap.get("ROLENAME").toString();
}else{
roleName=roleName+";"+tsDepartMap.get("ROLENAME").toString();
}
}
row.put("6", orgCode);
row.put("7", roleName);
String sex=tsUserMap.get("EMP_SEX")==null?"":tsUserMap.get("EMP_SEX").toString();
if("2".equals(sex)){
sex="男";
}else if("3".equals(sex)){
sex="女";
}else {
sex="";
}
row.put("8", sex);
row.put("9", tsUserMap.get("ISLEADER")==null?"":tsUserMap.get("ISLEADER").toString());
row.put("10",tsUserMap.get("SORTNO")==null?"":tsUserMap.get("SORTNO").toString());
row.put("11", tsUserMap.get("NICKNAME")==null?"":tsUserMap.get("NICKNAME").toString());
row.put("12", tsUserMap.get("FAMILY_ADDRESS")==null?"":tsUserMap.get("FAMILY_ADDRESS").toString());
row.put("13", tsUserMap.get("FAMILY_MOBILE")==null?"":tsUserMap.get("FAMILY_MOBILE").toString());
String jobPosition=tsUserMap.get("JOB_POSITION")==null?"":tsUserMap.get("JOB_POSITION").toString();
if("3".equals(jobPosition)){
jobPosition="0";
}else {
jobPosition="1";
}
row.put("14", jobPosition);
row.put("15", "");
exportData.add(row);
}
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put("1", "姓名");
map.put("2", "帐号");
map.put("3", "手机号");
map.put("4", "邮箱");
map.put("5", "企业邮箱");
map.put("6", "所在部门");
map.put("7", "职位");
map.put("8", "性别");
map.put("9", "是否部门内领导");
map.put("10", "排序");
map.put("11", "别名");
map.put("12", "地址");
map.put("13", "座机");
map.put("14", "禁用");
map.put("15", "禁用项说明:(0-启用;1-禁用)");
logger.info(String.format("企业微信全量覆盖成员数量:%s",exportData.size()));
File file = createCSVFile(exportData, map, "D:/hnndFile");
// 上传临时素材文件到企业微信
String media_id = mediaUpload(accessToken,file);
// 企业微信全量覆盖成员
String replacepartyUrl = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser?access_token=" + accessToken;
Map<String, Object> replacepartyMap = new HashMap<>();
replacepartyMap.put("media_id", media_id);
replacepartyMap.put("to_invite", false);//是否发出邀请
Map<String, Object> replacepartyCallbackMap = new HashMap<>();
replacepartyCallbackMap.put("url", "");
replacepartyCallbackMap.put("token", "");
replacepartyCallbackMap.put("encodingaeskey", "");
replacepartyMap.put("callback", replacepartyCallbackMap);
String replacepartyJson = JSON.toJSONString(replacepartyMap);
JSONObject jsonObject = WeiXinUtil.httpRequest(replacepartyUrl, "POST", replacepartyJson);
logger.info("全量覆盖成员返回值:" + jsonObject.toString());
ajaxJson.setObj(jsonObject);
return ajaxJson;
}
/**
* 上传临时素材文件到企业微信
* @param accessToken
* @param file
* @return
* @throws IOException
*/
private String mediaUpload(String accessToken,File file) throws IOException {
String media_id = "";
String url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=" + accessToken + "&type=file";
String result = uploadMedia(url, file, null);
logger.info("上传临时素材返回值:" + result);
Map resultMap = (Map) JSON.parse(result);
if (resultMap.containsKey("errcode") && !"0".equals(resultMap.get("errcode").toString())) {
logger.info("上传临时素材failed:" + result);
} else {
media_id = resultMap.get("media_id").toString();
}
return media_id;
}
@Override
public AjaxJson getQyWeixinResult(HttpServletRequest request) throws Exception {
String jobid=request.getParameter("jobid");
//获取AccessToken
String accessTokenUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + WECHAT_2_CORP_ID + "&corpsecret="+WECHAT_2_ADDRESSBOOKSECRET;
String httpOrgCreateTestRtn = HttpClientUtil.doGet(accessTokenUrl, null);
JSONObject json = JSONObject.parseObject(httpOrgCreateTestRtn);
String accessToken = json.get("access_token").toString();
String getresultUrl = "https://qyapi.weixin.qq.com/cgi-bin/batch/getresult?access_token=" + accessToken + "&jobid="+jobid;
JSONObject jsonObject = WeiXinUtil.httpRequest(getresultUrl, "GET", null);
logger.info("获取异步任务结果:" + jsonObject.toString());
AjaxJson ajaxJson= new AjaxJson();
ajaxJson.setObj(jsonObject);
return ajaxJson;
}
/**
* 上传临时素材
*
* @param url 图片上传地址
* @param file 需要上传的文件
* @return ApiResult
* @throws IOException
*/
public String uploadMedia(String url, File file, String params) throws IOException {
URL urlGet = new URL(url);
HttpURLConnection conn = (HttpURLConnection) urlGet.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", DEFAULT_USER_AGENT);
conn.setRequestProperty("Charsert", "UTF-8");
// 定义数据分隔线
String BOUNDARY = "----WebKitFormBoundaryiDGnV9zdZA1eM1yL";
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
OutputStream out = new DataOutputStream(conn.getOutputStream());
// 定义最后数据分隔线
StringBuilder mediaData = new StringBuilder();
mediaData.append("--").append(BOUNDARY).append("\r\n");
mediaData.append("Content-Disposition: form-data;name=\"media\";filename=\"" + file.getName() + "\"\r\n");
mediaData.append("Content-Type:application/octet-stream\r\n\r\n");
byte[] mediaDatas = mediaData.toString().getBytes();
out.write(mediaDatas);
DataInputStream fs = new DataInputStream(new FileInputStream(file));
int bytes = 0;
byte[] bufferOut = new byte[1024];
while ((bytes = fs.read(bufferOut)) != -1) {
out.write(bufferOut, 0, bytes);
}
IOUtils.closeQuietly(fs);
// 多个文件时,二个文件之间加入这个
out.write("\r\n".getBytes());
if (StringUtils.isNotEmpty(params)) {
StringBuilder paramData = new StringBuilder();
paramData.append("--").append(BOUNDARY).append("\r\n");
paramData.append("Content-Disposition: form-data;name=\"description\";");
byte[] paramDatas = paramData.toString().getBytes();
out.write(paramDatas);
out.write(params.getBytes(Charsets.UTF_8));
}
byte[] end_data = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
out.write(end_data);
out.flush();
IOUtils.closeQuietly(out);
// 定义BufferedReader输入流来读取URL的响应
InputStream in = conn.getInputStream();
BufferedReader read = new BufferedReader(new InputStreamReader(in, Charsets.UTF_8));
String valueString = null;
StringBuffer bufferRes = null;
bufferRes = new StringBuffer();
while ((valueString = read.readLine()) != null) {
bufferRes.append(valueString);
}
IOUtils.closeQuietly(in);
// 关闭连接
if (conn != null) {
conn.disconnect();
}
return bufferRes.toString();
}
/**
* 导出为CVS文件
*
* @param exportData 需要导出的数据
* @param titleMap 与数据相对应的标题
* @param outPutPath 导出目录
*/
public static File createCSVFile(List<Map<String, String>> exportData, LinkedHashMap<String, String> titleMap, String outPutPath) {
File csvFile = null;
BufferedWriter csvFileOutputStream = null;
try {
File f = new File(outPutPath);
if (!f.exists()) {
f.mkdirs();
}
csvFile = File.createTempFile("temp", ".csv", new File(outPutPath));
// GB2312使正确读取分隔符","
csvFileOutputStream = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(csvFile), "UTF-8"),
1024);
// 写入文件头部标题
for (Iterator propertyIterator = titleMap.entrySet().iterator(); propertyIterator.hasNext(); ) {
java.util.Map.Entry propertyEntry = (java.util.Map.Entry) propertyIterator.next();
csvFileOutputStream.write("\"" + propertyEntry.getValue().toString() + "\"");
if (propertyIterator.hasNext()) {
csvFileOutputStream.write(",");
}
}
csvFileOutputStream.newLine();
// 写入文件内容
for (Iterator iterator = exportData.iterator(); iterator.hasNext(); ) {
Map row = (Map) iterator.next();
for (Iterator propertyIterator = titleMap.entrySet().iterator(); propertyIterator.hasNext(); ) {
java.util.Map.Entry propertyEntry = (java.util.Map.Entry) propertyIterator.next();
csvFileOutputStream.write("\""
+ row.get(propertyEntry.getKey().toString()).toString() + "\"");
if (propertyIterator.hasNext()) {
csvFileOutputStream.write(",");
}
}
if (iterator.hasNext()) {
csvFileOutputStream.newLine();
}
}
csvFileOutputStream.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
csvFileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return csvFile;
}
}