feat:模块名称调整
This commit is contained in:
27
springboot-platform/pom.xml
Normal file
27
springboot-platform/pom.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.0.18</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-platform</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<artifactId>springboot-util</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.tiesheng.platform;
|
||||
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@ComponentScan({
|
||||
"com.tiesheng.platform.**.*",
|
||||
})
|
||||
public class PlatformAutoConfigurer {
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
package com.tiesheng.platform.config.ding;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.tiesheng.platform.config.ding.bean.*;
|
||||
import com.tiesheng.util.TimedCacheHelper;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "platform.ding")
|
||||
public class PlatformDingConfig {
|
||||
|
||||
private static final String CACHE_ACCESS_TOKEN = "cache_ding_access_token_";
|
||||
private static final String CACHE_JSAPI_TICKET = "cache_ding_jsapi_ticket_";
|
||||
|
||||
private Map<String, DingConfigBean> configs = MapUtil.newHashMap();
|
||||
private DingConfigBean global;
|
||||
|
||||
/**
|
||||
* 获取一个DingConfigBean
|
||||
*
|
||||
* @param service
|
||||
* @return
|
||||
*/
|
||||
public DingConfigBean getConfigBean(String service) {
|
||||
DingConfigBean bean = configs.get(service);
|
||||
if (bean == null) {
|
||||
bean = global;
|
||||
}
|
||||
if (bean == null) {
|
||||
throw new ApiException("该服务未配置钉钉授权");
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 逻辑方法
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* 获取accessToken
|
||||
*
|
||||
* @return accessToken
|
||||
* @see <a href="https://open.dingtalk.com/document/orgapp-server/obtain-orgapp-token" />
|
||||
*/
|
||||
private String getAccessToken(String service) {
|
||||
DingConfigBean dingConfigBean = getConfigBean(service);
|
||||
String accessToken = TimedCacheHelper.getTimedCache().get(CACHE_ACCESS_TOKEN + dingConfigBean.getAppKey(), false);
|
||||
if (!StrUtil.isEmpty(accessToken)) {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
// 重新获取新的token
|
||||
Map<String, Object> query = new HashMap<>(10);
|
||||
query.put("appkey", dingConfigBean.getAppKey());
|
||||
query.put("appsecret", dingConfigBean.getAppSecret());
|
||||
String response = HttpUtil.get("https://oapi.dingtalk.com/gettoken", query);
|
||||
JSONObject respJson = JSONUtil.parseObj(response);
|
||||
accessToken = respJson.getStr("access_token");
|
||||
TimedCacheHelper.getTimedCache().put(CACHE_ACCESS_TOKEN + dingConfigBean.getAppKey(), accessToken, respJson.getLong("expires_in"));
|
||||
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取jsapi_ticket
|
||||
*
|
||||
* @return ticket
|
||||
* @see <a href="https://open.dingtalk.com/document/isvapp-server/obtain-jsapi_ticket" />
|
||||
*/
|
||||
private String getJsapiTicket(String service) {
|
||||
DingConfigBean dingConfigBean = getConfigBean(service);
|
||||
String jsapiTicket = TimedCacheHelper.getTimedCache().get(CACHE_JSAPI_TICKET + dingConfigBean.getAppKey(), false);
|
||||
if (StrUtil.isEmpty(jsapiTicket)) {
|
||||
String response = HttpUtil.get("https://oapi.dingtalk.com/get_jsapi_ticket?access_token=" + getAccessToken(service));
|
||||
LogFactory.get().info("getJsapiTicket: " + response);
|
||||
JSONObject respJson = JSONUtil.parseObj(response);
|
||||
if (!Objects.equals(respJson.getStr("errcode"), "0")) {
|
||||
throw new ApiException(respJson.getStr("errmsg"));
|
||||
}
|
||||
jsapiTicket = respJson.getStr("ticket");
|
||||
TimedCacheHelper.getTimedCache().put(CACHE_JSAPI_TICKET + dingConfigBean.getAppKey(), jsapiTicket, respJson.getLong("expires_in"));
|
||||
}
|
||||
return jsapiTicket;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成jssdk配置
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public DingJsapiSignature createJsapiSignature(String service, String url) {
|
||||
DingConfigBean dingConfigBean = getConfigBean(service);
|
||||
if (StrUtil.contains(url, "#")) {
|
||||
url = StrUtil.sub(url, 0, StrUtil.indexOf(url, '#'));
|
||||
}
|
||||
return DingJsapiSignature.create(dingConfigBean.getCorpId(), dingConfigBean.getAgentId(), url, getJsapiTicket(service));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 通过code获取userId
|
||||
*
|
||||
* @param service
|
||||
* @param code
|
||||
* @return
|
||||
* @see <a href="https://open.dingtalk.com/document/isvapp-server/obtain-the-userid-of-a-user-by-using-the-log-free"></a>
|
||||
*/
|
||||
public String getUserIdByCode(String service, String code) {
|
||||
String response = HttpRequest.post("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo?access_token=" + getAccessToken(service))
|
||||
.body(JSONUtil.createObj().putOpt("code", code).toString()).execute().body();
|
||||
return JSONUtil.parseObj(response).getJSONObject("result").getStr("userid");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 通过userId获取用户详情
|
||||
*
|
||||
* @param service
|
||||
* @param ddUserId
|
||||
* @return
|
||||
* @see <a href="https://open.dingtalk.com/document/isvapp-server/query-user-details"></a>
|
||||
*/
|
||||
public DingUserInfo topapiV2UserGet(String service, String ddUserId) {
|
||||
DingConfigBean dingConfigBean = getConfigBean(service);
|
||||
String response = HttpRequest.post("https://oapi.dingtalk.com/topapi/v2/user/get?access_token=" + getAccessToken(service))
|
||||
.body(JSONUtil.createObj().putOpt("userid", ddUserId).toString()).execute().body();
|
||||
JSONObject resultJson = JSONUtil.parseObj(response).getJSONObject("result");
|
||||
DingUserInfo userInfo = JSONUtil.toBean(resultJson, DingUserInfo.class);
|
||||
|
||||
// 设置一下job_number
|
||||
userInfo.setJobNumber(resultJson.getStr("job_number"));
|
||||
userInfo.setAppId(dingConfigBean.getAppKey());
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门列表
|
||||
*
|
||||
* @param deptId 部门id
|
||||
* @return
|
||||
* @see <a href='https://open.dingtalk.com/document/orgapp-server/obtain-the-department-list-v2'></a>
|
||||
*/
|
||||
public List<DingDeptVo> topapiV2DepartmentListsub(String service, String deptId) {
|
||||
String token = getAccessToken(service);
|
||||
if (StrUtil.isEmpty(token)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
String response = HttpRequest.post("https://oapi.dingtalk.com/topapi/v2/department/listsub?access_token=" + token)
|
||||
.body(JSONUtil.createObj().putOpt("dept_id", deptId).toString()).execute().body();
|
||||
DingResponse<List<DingDeptVo>> result = JSONUtil.toBean(response, new TypeReference<DingResponse<List<DingDeptVo>>>() {
|
||||
}.getType(), true);
|
||||
|
||||
if (!result.isOk()) {
|
||||
result.setResult(new ArrayList<>());
|
||||
}
|
||||
return result.getResult();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取部门用户详情
|
||||
*
|
||||
* @return
|
||||
* @see <a href='https://open.dingtalk.com/document/orgapp-server/queries-the-complete-information-of-a-department-user'></a>
|
||||
*/
|
||||
public DingUserListVo topapiV2UserList(String service, String deptId, Integer cursor) {
|
||||
String token = getAccessToken(service);
|
||||
if (StrUtil.isEmpty(token)) {
|
||||
return DingUserListVo.fail();
|
||||
}
|
||||
|
||||
String response = HttpRequest.post("https://oapi.dingtalk.com/topapi/v2/user/list?access_token=" + token)
|
||||
.body(JSONUtil.createObj().putOpt("dept_id", deptId).putOpt("cursor", cursor).putOpt("size", 100).toString())
|
||||
.execute().body();
|
||||
DingResponse<DingUserListVo> result = JSONUtil.toBean(response, new TypeReference<DingResponse<DingUserListVo>>() {
|
||||
}.getType(), true);
|
||||
if (!result.isOk()) {
|
||||
result.setResult(DingUserListVo.fail());
|
||||
}
|
||||
return result.getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步钉钉的通讯录
|
||||
*
|
||||
* @param deptVo 为null时从第一级获取
|
||||
* @param consumer 回调
|
||||
*/
|
||||
public void syncDeptUser(String service, DingDeptVo deptVo, Consumer<DingUserInfo> consumer) {
|
||||
|
||||
if (deptVo == null) {
|
||||
deptVo = new DingDeptVo();
|
||||
deptVo.setDeptId("1");
|
||||
}
|
||||
|
||||
// 同步当前部门的用户
|
||||
DingUserListVo userListVo = new DingUserListVo();
|
||||
userListVo.setNextCursor(0);
|
||||
userListVo.setHasMore(true);
|
||||
while (userListVo.getHasMore()) {
|
||||
userListVo = topapiV2UserList(service, deptVo.getDeptId(), userListVo.getNextCursor());
|
||||
for (DingUserInfo dingUserInfo : userListVo.getList()) {
|
||||
dingUserInfo.setDeptVo(deptVo);
|
||||
consumer.accept(dingUserInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// 同步下级部门
|
||||
List<DingDeptVo> dingDeptVos = topapiV2DepartmentListsub(service, deptVo.getDeptId());
|
||||
for (DingDeptVo dingDeptVo : dingDeptVos) {
|
||||
syncDeptUser(service, dingDeptVo, consumer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发送工作通知
|
||||
*
|
||||
* @param service
|
||||
* @param content
|
||||
* @param actionUrl
|
||||
* @param userIds
|
||||
*/
|
||||
public void messageNotification(String service, String title, String content, String actionUrl, List<String> userIds) {
|
||||
|
||||
if (CollUtil.isEmpty(userIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DingConfigBean configBean = getConfigBean(service);
|
||||
|
||||
JSONObject actionCard = new JSONObject();
|
||||
actionCard.set("title", title);
|
||||
actionCard.set("markdown", "### " + title + "\n" + content);
|
||||
actionCard.set("single_title", "点击查看");
|
||||
actionCard.set("single_url", actionUrl);
|
||||
|
||||
JSONObject msg = new JSONObject();
|
||||
msg.set("msgtype", "action_card");
|
||||
msg.set("action_card", actionCard);
|
||||
|
||||
HashMap<String, Object> body = new HashMap<>(10);
|
||||
body.put("agent_id", configBean.getAgentId());
|
||||
body.put("userid_list", CollUtil.join(userIds, ","));
|
||||
body.put("msg", msg);
|
||||
String resp = HttpUtil.post("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=" + getAccessToken(service),
|
||||
JSONUtil.toJsonStr(body));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Map<String, DingConfigBean> getConfigs() {
|
||||
return configs;
|
||||
}
|
||||
|
||||
public void setConfigs(Map<String, DingConfigBean> configs) {
|
||||
this.configs = configs;
|
||||
}
|
||||
|
||||
public DingConfigBean getGlobal() {
|
||||
return global;
|
||||
}
|
||||
|
||||
public void setGlobal(DingConfigBean global) {
|
||||
this.global = global;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.tiesheng.platform.config.ding.bean;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
public class DingConfigBean {
|
||||
|
||||
private String corpId;
|
||||
private String agentId;
|
||||
private String appKey;
|
||||
private String appSecret;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getCorpId() {
|
||||
return corpId;
|
||||
}
|
||||
|
||||
public void setCorpId(String corpId) {
|
||||
this.corpId = corpId;
|
||||
}
|
||||
|
||||
public String getAgentId() {
|
||||
return agentId;
|
||||
}
|
||||
|
||||
public void setAgentId(String agentId) {
|
||||
this.agentId = agentId;
|
||||
}
|
||||
|
||||
public String getAppKey() {
|
||||
return appKey;
|
||||
}
|
||||
|
||||
public void setAppKey(String appKey) {
|
||||
this.appKey = appKey;
|
||||
}
|
||||
|
||||
public String getAppSecret() {
|
||||
return appSecret;
|
||||
}
|
||||
|
||||
public void setAppSecret(String appSecret) {
|
||||
this.appSecret = appSecret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.tiesheng.platform.config.ding.bean;
|
||||
|
||||
public class DingDeptVo {
|
||||
|
||||
private String deptId;
|
||||
private String name;
|
||||
private String parentId;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getDeptId() {
|
||||
return deptId;
|
||||
}
|
||||
|
||||
public void setDeptId(String deptId) {
|
||||
this.deptId = deptId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(String parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.tiesheng.platform.config.ding.bean;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
|
||||
/**
|
||||
* jssdk配置
|
||||
*
|
||||
* @author hao
|
||||
*/
|
||||
public class DingJsapiSignature {
|
||||
|
||||
private String corpId;
|
||||
private String agentId;
|
||||
private String nonceStr;
|
||||
private long timestamp;
|
||||
private String url;
|
||||
private String signature;
|
||||
|
||||
public static DingJsapiSignature create(String corpId, String agentId, String url, String ticket) {
|
||||
DingJsapiSignature wxJsapiSignature = new DingJsapiSignature();
|
||||
wxJsapiSignature.setCorpId(corpId);
|
||||
wxJsapiSignature.setAgentId(agentId);
|
||||
wxJsapiSignature.setUrl(url);
|
||||
wxJsapiSignature.setTimestamp(DateUtil.currentSeconds());
|
||||
wxJsapiSignature.setNonceStr(RandomUtil.randomString(10));
|
||||
|
||||
// 生成签名
|
||||
String builder = "jsapi_ticket=" + ticket +
|
||||
"&noncestr=" + wxJsapiSignature.getNonceStr() +
|
||||
"×tamp=" + wxJsapiSignature.getTimestamp() +
|
||||
"&url=" + wxJsapiSignature.getUrl();
|
||||
wxJsapiSignature.setSignature(SecureUtil.sha256(builder));
|
||||
|
||||
return wxJsapiSignature;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
public String getCorpId() {
|
||||
return corpId;
|
||||
}
|
||||
|
||||
public void setCorpId(String corpId) {
|
||||
this.corpId = corpId;
|
||||
}
|
||||
|
||||
public String getAgentId() {
|
||||
return agentId;
|
||||
}
|
||||
|
||||
public void setAgentId(String agentId) {
|
||||
this.agentId = agentId;
|
||||
}
|
||||
|
||||
public String getNonceStr() {
|
||||
return nonceStr;
|
||||
}
|
||||
|
||||
public void setNonceStr(String nonceStr) {
|
||||
this.nonceStr = nonceStr;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.tiesheng.platform.config.ding.bean;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DingResponse<T> {
|
||||
|
||||
private String errcode;
|
||||
private String errmsg;
|
||||
private T result;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 逻辑方法
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public boolean isOk() {
|
||||
return Objects.equals(errcode, "0");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getErrcode() {
|
||||
return errcode;
|
||||
}
|
||||
|
||||
public void setErrcode(String errcode) {
|
||||
this.errcode = errcode;
|
||||
}
|
||||
|
||||
public String getErrmsg() {
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
public void setErrmsg(String errmsg) {
|
||||
this.errmsg = errmsg;
|
||||
}
|
||||
|
||||
public T getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(T result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package com.tiesheng.platform.config.ding.bean;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
public class DingUserInfo {
|
||||
|
||||
private String name;
|
||||
private String userid;
|
||||
private String avatar;
|
||||
private String mobile;
|
||||
private String email;
|
||||
private String jobNumber;
|
||||
private String nickname;
|
||||
private String title;
|
||||
private String remark;
|
||||
private String unionid;
|
||||
private String appId;
|
||||
private List<String> deptIdList;
|
||||
private boolean leader;
|
||||
private boolean boss;
|
||||
private boolean admin;
|
||||
|
||||
/**
|
||||
* 该用户所在的部门
|
||||
*/
|
||||
private DingDeptVo deptVo;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUnionid() {
|
||||
return unionid;
|
||||
}
|
||||
|
||||
public void setUnionid(String unionid) {
|
||||
this.unionid = unionid;
|
||||
}
|
||||
|
||||
public String getUserid() {
|
||||
return userid;
|
||||
}
|
||||
|
||||
public void setUserid(String userid) {
|
||||
this.userid = userid;
|
||||
}
|
||||
|
||||
public String getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
public void setAvatar(String avatar) {
|
||||
this.avatar = avatar;
|
||||
}
|
||||
|
||||
public String getMobile() {
|
||||
return mobile;
|
||||
}
|
||||
|
||||
public void setMobile(String mobile) {
|
||||
this.mobile = mobile;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getJobNumber() {
|
||||
return jobNumber;
|
||||
}
|
||||
|
||||
public void setJobNumber(String jobNumber) {
|
||||
this.jobNumber = jobNumber;
|
||||
}
|
||||
|
||||
public String getNickname() {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public void setNickname(String nickname) {
|
||||
this.nickname = nickname;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
public DingDeptVo getDeptVo() {
|
||||
return deptVo;
|
||||
}
|
||||
|
||||
public void setDeptVo(DingDeptVo deptVo) {
|
||||
this.deptVo = deptVo;
|
||||
}
|
||||
|
||||
public boolean isLeader() {
|
||||
return leader;
|
||||
}
|
||||
|
||||
public void setLeader(boolean leader) {
|
||||
this.leader = leader;
|
||||
}
|
||||
|
||||
public boolean isBoss() {
|
||||
return boss;
|
||||
}
|
||||
|
||||
public void setBoss(boolean boss) {
|
||||
this.boss = boss;
|
||||
}
|
||||
|
||||
public boolean isAdmin() {
|
||||
return admin;
|
||||
}
|
||||
|
||||
public void setAdmin(boolean admin) {
|
||||
this.admin = admin;
|
||||
}
|
||||
|
||||
public List<String> getDeptIdList() {
|
||||
return deptIdList;
|
||||
}
|
||||
|
||||
public void setDeptIdList(List<String> deptIdList) {
|
||||
this.deptIdList = deptIdList;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.tiesheng.platform.config.ding.bean;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DingUserListVo {
|
||||
|
||||
private Integer nextCursor;
|
||||
private Boolean hasMore;
|
||||
private List<DingUserInfo> list;
|
||||
|
||||
|
||||
/**
|
||||
* 失败数据
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static DingUserListVo fail() {
|
||||
DingUserListVo listVo = new DingUserListVo();
|
||||
listVo.setHasMore(false);
|
||||
listVo.setNextCursor(0);
|
||||
listVo.setList(new ArrayList<>());
|
||||
return listVo;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Integer getNextCursor() {
|
||||
return nextCursor;
|
||||
}
|
||||
|
||||
public void setNextCursor(Integer nextCursor) {
|
||||
this.nextCursor = nextCursor;
|
||||
}
|
||||
|
||||
public Boolean getHasMore() {
|
||||
return hasMore;
|
||||
}
|
||||
|
||||
public void setHasMore(Boolean hasMore) {
|
||||
this.hasMore = hasMore;
|
||||
}
|
||||
|
||||
public List<DingUserInfo> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setList(List<DingUserInfo> list) {
|
||||
this.list = list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
package com.tiesheng.platform.config.wxmp;
|
||||
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.tiesheng.platform.config.wxmp.bean.WxConfigBean;
|
||||
import com.tiesheng.platform.config.wxmp.bean.WxJsapiSignature;
|
||||
import com.tiesheng.platform.config.wxmp.bean.WxOAuth2AccessToken;
|
||||
import com.tiesheng.platform.config.wxmp.bean.WxUserInfo;
|
||||
import com.tiesheng.util.TimedCacheHelper;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "platform.wxmp")
|
||||
public class PlatformWxmpConfig {
|
||||
|
||||
private static final String CACHE_ACCESS_TOKEN = "cache_weixin_access_token_";
|
||||
private static final String CACHE_JSAPI_TICKET = "cache_weixin_jsapi_ticket_";
|
||||
|
||||
|
||||
private WxConfigBean global;
|
||||
private Map<String, WxConfigBean> configs = MapUtil.newHashMap();
|
||||
|
||||
/**
|
||||
* 获取一个DingConfigBean
|
||||
*
|
||||
* @param service
|
||||
* @return
|
||||
*/
|
||||
public WxConfigBean getConfigBean(String service) {
|
||||
WxConfigBean bean = configs.get(service);
|
||||
if (bean == null) {
|
||||
bean = global;
|
||||
}
|
||||
if (bean == null) {
|
||||
throw new ApiException("该服务未配置微信授权");
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 业务逻辑
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* 获取accessToken
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String getAccessToken(String service) {
|
||||
WxConfigBean configBean = getConfigBean(service);
|
||||
String accessToken = TimedCacheHelper.getTimedCache().get(CACHE_ACCESS_TOKEN + configBean.getAppId(), false);
|
||||
if (StrUtil.isEmpty(accessToken)) {
|
||||
Map<String, Object> query = new HashMap<>(10);
|
||||
query.put("grant_type", "client_credential");
|
||||
query.put("appid", configBean.getAppId());
|
||||
query.put("secret", configBean.getAppSecret());
|
||||
String response = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/token", query);
|
||||
LogFactory.get().info("getAccessToken: " + response);
|
||||
JSONObject respJson = JSONUtil.parseObj(response);
|
||||
accessToken = respJson.getStr("access_token");
|
||||
TimedCacheHelper.getTimedCache().put(CACHE_ACCESS_TOKEN + configBean.getAppId(), accessToken, respJson.getLong("expires_in"));
|
||||
}
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取jsapi_ticket
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String getJsapiTicket(String service) {
|
||||
WxConfigBean configBean = getConfigBean(service);
|
||||
String jsapiTicket = TimedCacheHelper.getTimedCache().get(CACHE_JSAPI_TICKET + configBean.getAppId(), false);
|
||||
if (StrUtil.isEmpty(jsapiTicket)) {
|
||||
Map<String, Object> query = new HashMap<>(10);
|
||||
query.put("access_token", getAccessToken(service));
|
||||
query.put("type", "jsapi");
|
||||
String response = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/ticket/getticket", query);
|
||||
LogFactory.get().info("getJsapiTicket: " + response);
|
||||
JSONObject respJson = JSONUtil.parseObj(response);
|
||||
jsapiTicket = respJson.getStr("ticket");
|
||||
TimedCacheHelper.getTimedCache().put(CACHE_JSAPI_TICKET + configBean.getAppId(), jsapiTicket, respJson.getLong("expires_in"));
|
||||
}
|
||||
return jsapiTicket;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建jssdk配置
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public WxJsapiSignature createJsapiSignature(String service, String url) {
|
||||
WxConfigBean configBean = getConfigBean(service);
|
||||
if (StrUtil.contains(url, "#")) {
|
||||
url = StrUtil.sub(url, 0, StrUtil.indexOf(url, '#'));
|
||||
}
|
||||
return WxJsapiSignature.create(configBean.getAppId(), url, getJsapiTicket(service));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成认证url
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String buildAuthorizationUrl(String service, String redirectUrl, String scope) {
|
||||
WxConfigBean configBean = getConfigBean(service);
|
||||
return "https://open.weixin.qq.com/connect/oauth2/authorize"
|
||||
+ "?appid=" + configBean.getAppId()
|
||||
+ "&redirect_uri=" + URLUtil.encodeAll(redirectUrl)
|
||||
+ "&response_type=code&scope=" + scope
|
||||
+ "&state=STATE#wechat_redirect";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 通过code获取用户授权信息
|
||||
*
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
public WxUserInfo getOAuth2AccessToken(String service, String code) {
|
||||
WxConfigBean configBean = getConfigBean(service);
|
||||
WxOAuth2AccessToken wxOAuth2AccessToken = WxOAuth2AccessToken.create(configBean.getAppId(), configBean.getAppSecret(), code);
|
||||
WxUserInfo wxUserInfo = WxUserInfo.create(wxOAuth2AccessToken);
|
||||
wxUserInfo.setAppId(configBean.getAppId());
|
||||
return wxUserInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取临时素材-图片
|
||||
*
|
||||
* @return
|
||||
* @link <a href='https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Get_temporary_materials.html'></a>
|
||||
*/
|
||||
public void mediaPicGet(String service, String mediaId, String filePath) {
|
||||
String fileUrl = String.format("https://api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s",
|
||||
getAccessToken(service), mediaId);
|
||||
HttpUtil.downloadFile(fileUrl, filePath);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Map<String, WxConfigBean> getConfigs() {
|
||||
return configs;
|
||||
}
|
||||
|
||||
public void setConfigs(Map<String, WxConfigBean> configs) {
|
||||
this.configs = configs;
|
||||
}
|
||||
|
||||
public WxConfigBean getGlobal() {
|
||||
return global;
|
||||
}
|
||||
|
||||
public void setGlobal(WxConfigBean global) {
|
||||
this.global = global;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.tiesheng.platform.config.wxmp.bean;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
public class WxConfigBean {
|
||||
|
||||
private String appId;
|
||||
private String appSecret;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
|
||||
public String getAppSecret() {
|
||||
return appSecret;
|
||||
}
|
||||
|
||||
public void setAppSecret(String appSecret) {
|
||||
this.appSecret = appSecret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.tiesheng.platform.config.wxmp.bean;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
|
||||
/**
|
||||
* jssdk配置
|
||||
*
|
||||
* @author hao
|
||||
*/
|
||||
public class WxJsapiSignature {
|
||||
|
||||
private String appId;
|
||||
private String nonceStr;
|
||||
private long timestamp;
|
||||
private String url;
|
||||
private String signature;
|
||||
|
||||
public static WxJsapiSignature create(String appId, String url, String ticket) {
|
||||
WxJsapiSignature wxJsapiSignature = new WxJsapiSignature();
|
||||
wxJsapiSignature.setAppId(appId);
|
||||
wxJsapiSignature.setUrl(url);
|
||||
wxJsapiSignature.setTimestamp(DateUtil.currentSeconds());
|
||||
wxJsapiSignature.setNonceStr(RandomUtil.randomString(10));
|
||||
|
||||
// 生成签名
|
||||
String builder = "jsapi_ticket=" + ticket +
|
||||
"&noncestr=" + wxJsapiSignature.getNonceStr() +
|
||||
"×tamp=" + wxJsapiSignature.getTimestamp() +
|
||||
"&url=" + wxJsapiSignature.getUrl();
|
||||
wxJsapiSignature.setSignature(SecureUtil.sha1(builder));
|
||||
|
||||
return wxJsapiSignature;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
|
||||
public String getNonceStr() {
|
||||
return nonceStr;
|
||||
}
|
||||
|
||||
public void setNonceStr(String nonceStr) {
|
||||
this.nonceStr = nonceStr;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.tiesheng.platform.config.wxmp.bean;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
public class WxOAuth2AccessToken {
|
||||
|
||||
private String accessToken;
|
||||
private String openid;
|
||||
|
||||
public static WxOAuth2AccessToken create(String appId, String secret, String code) {
|
||||
String response = HttpUtil.get("https://api.weixin.qq.com/sns/oauth2/access_token" +
|
||||
"?appid=" + appId + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code");
|
||||
JSONObject respJson = JSONUtil.parseObj(response);
|
||||
|
||||
WxOAuth2AccessToken oAuth2AccessToken = new WxOAuth2AccessToken();
|
||||
oAuth2AccessToken.setOpenid(respJson.getStr("openid"));
|
||||
oAuth2AccessToken.setAccessToken(respJson.getStr("access_token"));
|
||||
return oAuth2AccessToken;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
public String getOpenid() {
|
||||
return openid;
|
||||
}
|
||||
|
||||
public void setOpenid(String openid) {
|
||||
this.openid = openid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package com.tiesheng.platform.config.wxmp.bean;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
public class WxUserInfo {
|
||||
|
||||
private String accessToken;
|
||||
private String nickname;
|
||||
private String sex;
|
||||
private String province;
|
||||
private String city;
|
||||
private String country;
|
||||
private String headimgurl;
|
||||
private String openid;
|
||||
private String appId;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 逻辑方法
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* 通过oAuth2AccessToken获取用户信息
|
||||
*
|
||||
* @param oAuth2AccessToken
|
||||
* @return
|
||||
*/
|
||||
public static WxUserInfo create(WxOAuth2AccessToken oAuth2AccessToken) {
|
||||
String s = HttpUtil.get("https://api.weixin.qq.com/sns/userinfo"
|
||||
+ "?access_token=" + oAuth2AccessToken.getAccessToken()
|
||||
+ "&openid=" + oAuth2AccessToken.getOpenid() + "&lang=zh_CN");
|
||||
return JSONUtil.toBean(s, WxUserInfo.class);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public void setAccessToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
public String getNickname() {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public void setNickname(String nickname) {
|
||||
this.nickname = nickname;
|
||||
}
|
||||
|
||||
public String getSex() {
|
||||
return sex;
|
||||
}
|
||||
|
||||
public void setSex(String sex) {
|
||||
this.sex = sex;
|
||||
}
|
||||
|
||||
public String getProvince() {
|
||||
return province;
|
||||
}
|
||||
|
||||
public void setProvince(String province) {
|
||||
this.province = province;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
public String getHeadimgurl() {
|
||||
return headimgurl;
|
||||
}
|
||||
|
||||
public void setHeadimgurl(String headimgurl) {
|
||||
this.headimgurl = headimgurl;
|
||||
}
|
||||
|
||||
public String getOpenid() {
|
||||
return openid;
|
||||
}
|
||||
|
||||
public void setOpenid(String openid) {
|
||||
this.openid = openid;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user