Browse Source

Merge branch 'master' of gitee.com:ccsens_s/ccsenscloud

master
zhangye 5 years ago
parent
commit
aa56d6b522
  1. 41
      cloudutil/src/main/java/com/ccsens/cloudutil/feign/HealthFeignClient.java
  2. 126
      health/src/main/java/com/ccsens/health/api/WeixinController.java
  3. 16
      health/src/main/java/com/ccsens/health/bean/dto/EmployeeDto.java
  4. 15
      health/src/main/java/com/ccsens/health/persist/dao/DepartmentDao.java
  5. 14
      health/src/main/java/com/ccsens/health/persist/dao/DepartmentEmployeeDao.java
  6. 8
      health/src/main/java/com/ccsens/health/persist/dao/EmployeeDao.java
  7. 13
      health/src/main/java/com/ccsens/health/service/IWeiXinService.java
  8. 193
      health/src/main/java/com/ccsens/health/service/WeiXinService.java
  9. 17
      health/src/main/resources/mapper_dao/DepartmentDao.xml
  10. 17
      health/src/main/resources/mapper_dao/DepartmentEmployeeDao.xml
  11. 19
      health/src/main/resources/mapper_dao/EmployeeDao.xml
  12. 6
      tall/src/main/java/com/ccsens/tall/bean/dto/UserDto.java
  13. 2
      tall/src/main/java/com/ccsens/tall/service/IUserService.java
  14. 110
      tall/src/main/java/com/ccsens/tall/service/UserService.java
  15. 5
      tall/src/main/java/com/ccsens/tall/web/UserController.java
  16. 3
      tall/src/main/resources/application-test.yml
  17. 1
      util/home
  18. 3
      util/src/main/java/com/ccsens/util/CodeEnum.java
  19. 5
      util/src/main/java/com/ccsens/util/PropUtil.java
  20. 6
      util/src/main/java/com/ccsens/util/WebConstant.java
  21. 90
      util/src/main/java/com/ccsens/util/enterprisewx/WeiXinConstant.java
  22. 1
      util/src/main/java/com/ccsens/util/enterprisewx/dto/MessageDto.java
  23. 49
      util/src/main/java/com/ccsens/util/enterprisewx/vo/WeiXinVo.java

41
cloudutil/src/main/java/com/ccsens/cloudutil/feign/HealthFeignClient.java

@ -0,0 +1,41 @@
package com.ccsens.cloudutil.feign;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "health", path = "", fallbackFactory = HealthFeignClientFallBack.class)
public interface HealthFeignClient {
/**
* 获取suiteAccessToken
* @param suiteId
* @return
*/
@GetMapping("getSuiteAccessToken")
String getSuiteAccessToken(@RequestParam(name = "suiteId") String suiteId);
}
@Slf4j
@Component
class HealthFeignClientFallBack implements FallbackFactory<HealthFeignClient> {
@Override
public HealthFeignClient create(Throwable throwable) {
String msg = throwable == null ? "" : throwable.getMessage();
if (!StringUtils.isEmpty(msg)) {
log.error(msg);
}
return new HealthFeignClient() {
@Override
public String getSuiteAccessToken(String suiteId) {
return null;
}
};
}
}

126
health/src/main/java/com/ccsens/health/api/WeixinController.java

@ -4,10 +4,14 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ccsens.health.bean.dto.EmployeeDto;
import com.ccsens.health.bean.po.HealthAuth;
import com.ccsens.health.persist.dao.EmployeeDao;
import com.ccsens.health.service.IConstantService;
import com.ccsens.health.service.IWeiXinService;
import com.ccsens.util.HttpsUtil;
import com.ccsens.util.JacksonUtil;
import com.ccsens.util.JsonResponse;
import com.ccsens.util.RestTemplateUtil;
import com.ccsens.util.enterprisewx.AesException;
import com.ccsens.util.enterprisewx.WXBizMsgCrypt;
@ -15,15 +19,11 @@ import com.ccsens.util.enterprisewx.WeiXinConstant;
import com.ccsens.util.enterprisewx.dto.MessageDto;
import io.swagger.annotations.ApiModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
/**
* @author wu
@ -54,37 +54,88 @@ public class WeixinController {
* 数据回调URL
*/
@GetMapping("userChangeNotice")
public String userChangeNotice(MessageDto dto) throws Exception{
public String userChangeNoticeGet(MessageDto dto) throws Exception{
log.info("数据回调请求参数:{}", dto);
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(WeiXinConstant.token, WeiXinConstant.encodingAESKey, WeiXinConstant.corpID);
String verifyURL = wxcpt.VerifyURL(dto.getMsg_signature(), dto.getTimestamp(), dto.getNonce(), dto.getEchostr());
log.info("数据回调解析结果:{}", verifyURL);
return verifyURL;
}
/**
* 指令回调URL
* 指令回调get
* @param dto
* @return
* @throws Exception
*/
@GetMapping("authorizationChangeNotice")
public String authorizationChangeNotice(MessageDto dto) throws Exception{
public String authorizationChangeNoticeGet(MessageDto dto) throws Exception {
log.info("请求参数:{}", dto);
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(WeiXinConstant.token, WeiXinConstant.encodingAESKey, WeiXinConstant.corpID);
String verifyURL = wxcpt.VerifyURL(dto.getMsg_signature(), dto.getTimestamp(), dto.getNonce(), dto.getEchostr());
log.info("解析结果:{}", verifyURL);
if (StrUtil.isBlank(verifyURL) || !(verifyURL.startsWith("<xml") || verifyURL.startsWith("<XML"))){
return verifyURL;
}
return verifyURL;
}
/**
* 数据回调URL post
*/
@PostMapping("userChangeNotice")
public String userChangeNoticePost(MessageDto dto, @RequestBody String body) throws Exception{
log.info("数据回调请求参数:{}", dto);
String xmlStr = JacksonUtil.xmlToJson(body);
log.info("数据回到xml转换:{}", xmlStr);
JSONObject jsonObject = JSONObject.parseObject(xmlStr);
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(WeiXinConstant.token, WeiXinConstant.encodingAESKey, WeiXinConstant.corpID);
String verifyURL = wxcpt.VerifyURL(dto.getMsg_signature(), dto.getTimestamp(), dto.getNonce(), jsonObject.getString("Encrypt"));
log.info("数据回调解析结果:{}", verifyURL);
return "success";
}
/**
* 指令回调URL
*/
@PostMapping("authorizationChangeNotice")
public String authorizationChangeNotice(MessageDto dto, @RequestBody String body) throws Exception{
log.info("指令回调请求参数:{}, body:{}", dto, body);
String xmlStr = JacksonUtil.xmlToJson(body);
log.info("指令回到xml转换:{}", xmlStr);
JSONObject jsonObject = JSONObject.parseObject(xmlStr);
log.info("jsonObject:{}", jsonObject);
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(WeiXinConstant.token, WeiXinConstant.encodingAESKey, WeiXinConstant.suiteID);
String verifyURL = wxcpt.VerifyURL(dto.getMsg_signature(), dto.getTimestamp(), dto.getNonce(), jsonObject.getString("Encrypt"));
log.info("解析结果:{}", verifyURL);
String jsonStr = JacksonUtil.xmlToJson(verifyURL);
JSONObject json = JSONObject.parseObject(jsonStr);
log.info("指令回调业务参数:{}", json);
switch (json.getString("InfoType")){
case "suite_ticket" :
MessageDto.Ticket ticket = JSONObject.parseObject(jsonStr, MessageDto.Ticket.class);
constantService.saveConstant(WeiXinConstant.getSuiteTicket(ticket.getSuiteId()), ticket.getSuiteTicket());
//获取第三方应用凭证
new Thread(new Runnable() {
@Override
public void run() {
getSuiteAccessToken(ticket.getSuiteId(),ticket.getSuiteTicket());
}
}).start();
break;
case "create_auth" :
MessageDto.Grant grant = JSONObject.parseObject(jsonStr, MessageDto.Grant.class);
constantService.saveConstant(WeiXinConstant.getTempAuthCodeKey(grant.getSuiteId()), grant.getAuthCode());
getPermanentCode(grant.getAuthCode());
//获取永久授权
log.info("grant:{}", grant);
new Thread(new Runnable() {
@Override
public void run() {
getPermanentCode(grant.getSuiteId(), grant.getAuthCode());
}
}).start();
break;
case "change_auth" :
//TODO 变更授权通知
@ -94,22 +145,39 @@ public class WeixinController {
break;
//TODO 成员变更和部门变更通知
}
return verifyURL;
log.info("-----------------------------------------------------");
return "success";
}
/**
* 异步获取suite_access_token
* @param suite_id
* @param suite_ticket
*/
@Async
public void getSuiteAccessToken(String suite_id, String suite_ticket) {
weiXinService.getSuiteToken(suite_id, suite_ticket);
}
/**
* 获取永久授权码
* @param authCode
*/
@Async
public void getPermanentCode(String authCode){
weiXinService.savePermanentCode(authCode);
// TODO 读取部门信息和成员信息
public void getPermanentCode(String suiteId, String authCode){
String suiteTicket = constantService.getByKey(WeiXinConstant.getSuiteTicket(suiteId));
String suiteToken = weiXinService.getSuiteToken(suiteId, suiteTicket);
HealthAuth auth = weiXinService.savePermanentCode(authCode, suiteToken);
if (auth != null) {
weiXinService.initDepartment(auth.getAccessToken());
}
}
/**
* 系统验证
*/
@GetMapping("reciveSysMsg")
@RequestMapping(value = "reciveSysMsg",method = {RequestMethod.POST, RequestMethod.GET})
public String reciveSysMsg(MessageDto dto) throws Exception{
log.info("请求参数:{}", dto);
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(WeiXinConstant.token, WeiXinConstant.encodingAESKey, WeiXinConstant.corpID);
@ -117,4 +185,26 @@ public class WeixinController {
log.info("解析结果:{}", verifyURL);
return verifyURL;
}
/**
* 获取第三方应用凭证suiteAccessToken
* @param suiteId
* @return
*/
@GetMapping("getSuiteAccessToken")
public String getSuiteAccessToken(String suiteId) {
String suiteTicket = constantService.getByKey(WeiXinConstant.getSuiteTicket(suiteId));
return weiXinService.getSuiteToken(suiteId, suiteTicket);
}
/**
* 获取第三方应用凭证suiteAccessToken
* @param bind
* @return
*/
@GetMapping("bindUser")
public JsonResponse bindUser(@RequestBody EmployeeDto.Bind bind) {
weiXinService.bindUser(bind);
return JsonResponse.newInstance().ok();
}
}

16
health/src/main/java/com/ccsens/health/bean/dto/EmployeeDto.java

@ -0,0 +1,16 @@
package com.ccsens.health.bean.dto;
import io.swagger.annotations.ApiModel;
import lombok.Data;
@Data
@ApiModel("员工信息")
public class EmployeeDto {
@Data
@ApiModel("绑定用户")
public static class Bind{
private Long tallUserId;
private String userid;
}
}

15
health/src/main/java/com/ccsens/health/persist/dao/DepartmentDao.java

@ -0,0 +1,15 @@
package com.ccsens.health.persist.dao;
import com.ccsens.health.bean.po.Department;
import com.ccsens.health.persist.mapper.DepartmentMapper;
import java.util.List;
public interface DepartmentDao extends DepartmentMapper {
/**
* 批量添加部門信息
* @param departmentList
*/
void insertBatch(List<Department> departmentList);
}

14
health/src/main/java/com/ccsens/health/persist/dao/DepartmentEmployeeDao.java

@ -0,0 +1,14 @@
package com.ccsens.health.persist.dao;
import com.ccsens.health.bean.po.DepartmentEmployee;
import com.ccsens.health.persist.mapper.DepartmentEmployeeMapper;
import java.util.List;
public interface DepartmentEmployeeDao extends DepartmentEmployeeMapper {
/**
* 批量添加部門员工信息
* @param des
*/
void insertBatch(List<DepartmentEmployee> des);
}

8
health/src/main/java/com/ccsens/health/persist/dao/EmployeeDao.java

@ -1,8 +1,16 @@
package com.ccsens.health.persist.dao;
import com.ccsens.health.bean.po.Employee;
import com.ccsens.health.persist.mapper.EmployeeMapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface EmployeeDao extends EmployeeMapper {
/**
* 批量添加部門信息
* @param employees
*/
void insertBatch(List<Employee> employees);
}

13
health/src/main/java/com/ccsens/health/service/IWeiXinService.java

@ -1,5 +1,8 @@
package com.ccsens.health.service;
import com.ccsens.health.bean.dto.EmployeeDto;
import com.ccsens.health.bean.po.HealthAuth;
/**
* 企业微信相关业务
*/
@ -9,14 +12,14 @@ public interface IWeiXinService {
* 保存永久授权
* @param authCode 微信返回永久授权字符串
*/
void savePermanentCode(String authCode);
HealthAuth savePermanentCode(String authCode, String suiteAccessToken);
/**
* 获取第三方应用凭证
* @param suiteId
* @param suiteTicket
*/
void getSuiteToken(String suiteId, String suiteTicket);
String getSuiteToken(String suiteId, String suiteTicket);
/**
* 获取第三方授权
@ -32,4 +35,10 @@ public interface IWeiXinService {
* @param accessToken
*/
void initDepartment(String accessToken);
/**
* 用户绑定
* @param bind
*/
void bindUser(EmployeeDto.Bind bind);
}

193
health/src/main/java/com/ccsens/health/service/WeiXinService.java

@ -5,21 +5,28 @@ import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ccsens.health.bean.po.Department;
import com.ccsens.health.bean.po.HealthAuth;
import com.ccsens.health.bean.po.HealthAuthAgent;
import com.ccsens.health.bean.dto.EmployeeDto;
import com.ccsens.health.bean.po.*;
import com.ccsens.health.persist.dao.DepartmentDao;
import com.ccsens.health.persist.dao.DepartmentEmployeeDao;
import com.ccsens.health.persist.dao.EmployeeDao;
import com.ccsens.health.persist.mapper.HealthAuthAgentMapper;
import com.ccsens.health.persist.mapper.HealthAuthMapper;
import com.ccsens.util.CodeEnum;
import com.ccsens.util.RedisUtil;
import com.ccsens.util.RestTemplateUtil;
import com.ccsens.util.WebConstant;
import com.ccsens.util.enterprisewx.WeiXinConstant;
import com.ccsens.util.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import javax.annotation.Resource;
import java.util.ArrayList;
@ -38,8 +45,16 @@ public class WeiXinService implements IWeiXinService {
private HealthAuthMapper healthAuthMapper;
@Resource
private HealthAuthAgentMapper healthAuthAgentMapper;
@Autowired
@Resource
private RedisUtil redisUtil;
@Resource
private PlatformTransactionManager transactionManager;
@Resource
private DepartmentDao departmentDao;
@Resource
private EmployeeDao employeeDao;
@Resource
private DepartmentEmployeeDao departmentEmployeeDao;
@Override
public String getAccessToken(String suiteId, String corpId, String permanent_code ) {
@ -64,7 +79,26 @@ public class WeiXinService implements IWeiXinService {
}
@Override
public void getSuiteToken(String suiteId, String suiteTicket) {
public void bindUser(EmployeeDto.Bind bind) {
log.info("用户绑定:{}", bind);
EmployeeExample example = new EmployeeExample();
example.createCriteria().andUseridEqualTo(bind.getUserid());
List<Employee> employees = employeeDao.selectByExample(example);
log.info("有无用户信息");
if (CollectionUtil.isEmpty(employees)) {
throw new BaseException(CodeEnum.PARAM_ERROR);
}
Employee employee = employees.get(0);
if (employee.getTallUserId() == null || employee.getTallUserId() == 0) {
Employee bindEmployee = new Employee();
bindEmployee.setId(employee.getId());
bindEmployee.setTallUserId(bind.getTallUserId());
employeeDao.updateByPrimaryKeySelective(bindEmployee);
}
}
@Override
public String getSuiteToken(String suiteId, String suiteTicket) {
log.info("获取suiteToken, suiteId:{}, suiteTicket:{}", suiteId, suiteTicket);
String key = WeiXinConstant.getSuiteAccessToken(suiteId);
String suiteAccessToken = (String)redisUtil.get(key);
@ -75,7 +109,7 @@ public class WeiXinService implements IWeiXinService {
int expireTime = 1200;
if (expire > expireTime) {
log.info("有效时长大于1200,无需更新");
return;
return suiteAccessToken;
}
}
@ -89,23 +123,26 @@ public class WeiXinService implements IWeiXinService {
if (!WeiXinConstant.pageResult(result)) {
log.info("获取suite_ticket异常");
// TODO
return;
return null;
}
redisUtil.set(key, result.getString("suite_access_token"), result.getInteger("expires_in"));
return result.getString("suite_access_token");
}
@Override
public void savePermanentCode(String authCode) {
public HealthAuth savePermanentCode(String authCode, String suiteAccessToken) {
//授权成功通知
Map<String, String> params = new HashMap<>();
params.put("auth_code", authCode);
String result = RestTemplateUtil.postBody(WeiXinConstant.GET_PERMANENT_CODE, params);
String url = WeiXinConstant.GET_PERMANENT_CODE + " ?suite_access_token=" + suiteAccessToken;
log.info("获取永久授权参数, auth_code:{}, suite:{}", authCode, suiteAccessToken);
String result = RestTemplateUtil.postBody(url, params);
log.info("获取永久授权返回:{}", result);
JSONObject json = JSONObject.parseObject(result);
if (json.getInteger(WeiXinConstant.ERR_CODE).intValue() != 0) {
if (json.getInteger(WeiXinConstant.ERR_CODE) !=null && json.getIntValue(WeiXinConstant.ERR_CODE) != 0) {
log.error("获取永久授权码异常:{}", result);
//TODO 异常如何处理
return;
return null;
}
HealthAuth auth = initAuth(json);
HealthAuthAgent agent = initAuthAgent(json);
@ -114,22 +151,148 @@ public class WeiXinService implements IWeiXinService {
if (agent != null) {
healthAuthAgentMapper.insertSelective(agent);
}
return auth;
}
@Override
public void initDepartment(String accessToken) {
Map<String, Object> param = new HashMap<>();
param.put("access_token", accessToken);
List departmentList = (List) RestTemplateUtil.getForEntity(WeiXinConstant.DEPARTMENT_LIST, param, List.class);
log.info("部門信息:{}", departmentList);
JSONObject result = (JSONObject) RestTemplateUtil.getForEntity(WeiXinConstant.DEPARTMENT_LIST, param, JSONObject.class);
log.info("部門信息:{}", result);
if (!WeiXinConstant.pageResult(result)) {
//TODO 读取部门信息异常
return;
}
JSONArray departmentList = result.getJSONArray("department");
if (CollectionUtil.isEmpty(departmentList)) {
return;
}
List<Department> departments = new ArrayList<>();
departmentList.forEach(obj -> {
JSONObject json = (JSONObject) obj;
Department department = json.toJavaObject(Department.class);
departments.add(department);
});
insertBatchDepartment(departments);
//初始化員工信息
departments.forEach(department -> {
initEmployee(accessToken, department);
});
}
/**
* 初始化员工信息
* @param accessToken
* @param department
*/
private void initEmployee(String accessToken, Department department) {
// 查询员工信息
Map<String, Object> params = new HashMap<>();
params.put("access_token", accessToken);
params.put("department_id", department.getId());
params.put("fetch_child", 0);
JSONObject userResult = (JSONObject) RestTemplateUtil.getForEntity(WeiXinConstant.USER_LIST, params, JSONObject.class);
if (WeiXinConstant.pageResult(userResult)) {
log.error("查询员工信息异常:{},{}", params, userResult);
return;
}
JSONArray userlist = userResult.getJSONArray("userlist");
if (CollectionUtil.isEmpty(userlist)) {
return;
}
//解析员工信息
List<Employee> employees = new ArrayList<>();
List<DepartmentEmployee> des = new ArrayList<>();
userlist.forEach(obj -> {
JSONObject user = (JSONObject)obj;
Employee employee = user.toJavaObject(Employee.class);
employee.setId(snowflake.nextId());
employees.add(employee);
JSONArray departmentIds = user.getJSONArray("department");
JSONArray orders = user.getJSONArray("order");
for (int i = 0; i < departmentIds.size(); i++) {
DepartmentEmployee de = new DepartmentEmployee();
de.setId(snowflake.nextId());
de.setEmployeeId(employee.getId());
de.setDepartmentId((Long)departmentIds.get(0));
de.setSort(i);
des.add(de);
}
});
// 保存员工信息
insertBatchEmployee(employees, des);
}
private void insertBatchEmployee(List<Employee> employees, List<DepartmentEmployee> des) {
TransactionStatus status = getTransactionStatus();
int empSize = employees.size();
int deSize = des.size();
int once = 100;
for (int i = 0; i < empSize; i+=once) {
int end = i+once > empSize ? empSize : i+once;
try {
employeeDao.insertBatch(employees.subList(i, end));
//提交事务
transactionManager.commit( status );
} catch (TransactionException e) {
e.printStackTrace();
log.error("存储员工{}时发生异常:{}", employees.subList(i,end), e);
transactionManager.rollback(status);
}
}
for (int i = 0; i < deSize; i+=once) {
int end = i+once > deSize ? deSize : i+once;
try {
departmentEmployeeDao.insertBatch(des.subList(i, end));
//提交事务
transactionManager.commit( status );
} catch (TransactionException e) {
e.printStackTrace();
log.error("存儲部門员工{}時發發生異常:{}", des.subList(i,end), e);
transactionManager.rollback(status);
}
}
}
/**
* 批量保存部門信息
* @param departments
*/
private void insertBatchDepartment(List<Department> departments) {
TransactionStatus status = getTransactionStatus();
int size = departments.size();
int once = 100;
for (int i = 0; i < size; i+=once) {
int end = i+once > size ? size : i+once;
try {
departmentDao.insertBatch(departments.subList(i, end));
//提交事务
transactionManager.commit( status );
} catch (TransactionException e) {
e.printStackTrace();
log.error("存儲部門{}時發發生異常:{}", departments.subList(i,end), e);
transactionManager.rollback(status);
}
}
}
/**
* 手动开启事务获取事务状态
* @return
*/
private TransactionStatus getTransactionStatus() {
//开启手动事务
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// 事务隔离级别,开启新事务
def.setPropagationBehavior( TransactionDefinition.PROPAGATION_REQUIRES_NEW );
//获取事务状态,并开启事务,相当于transation.begin();
return transactionManager.getTransaction( def );
}
/**
* 初始化永久授权信息
* @param json

17
health/src/main/resources/mapper_dao/DepartmentDao.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ccsens.health.persist.dao.DepartmentDao">
<insert id="insertBatch" parameterType="ArrayList">
insert into t_department (id, name,
name_en, parentid, order
)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=BIGINT}, #{item.name,jdbcType=VARCHAR},#{item.nameEn,jdbcType=VARCHAR},
#{item.parentid,jdbcType=VARCHAR}, #{item.order,jdbcType=INTEGER}
)
</foreach>
</insert>
</mapper>

17
health/src/main/resources/mapper_dao/DepartmentEmployeeDao.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ccsens.health.persist.dao.DepartmentEmployeeDao">
<insert id="insertBatch" parameterType="ArrayList">
insert into t_department_employee (id, department_id, employee_id,
order, sort
)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=BIGINT}, #{item.departmentId,jdbcType=BIGINT},
#{item.employeeId,jdbcType=BIGINT},
#{item.order,jdbcType=INTEGER}, #{item.sort,jdbcType=INTEGER})
</foreach>
</insert>
</mapper>

19
health/src/main/resources/mapper_dao/EmployeeDao.xml

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ccsens.health.persist.dao.EmployeeDao">
<insert id="insertBatch" parameterType="ArrayList">
insert into t_employee (id, userid, name,
gender, status, address,
hide_mobile, english_name, tall_user_id
)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=BIGINT}, #{item.userid,jdbcType=VARCHAR}, #{item.name,jdbcType=VARCHAR},
#{item.gender,jdbcType=TINYINT}, #{item.status,jdbcType=TINYINT}, #{item.address,jdbcType=VARCHAR},
#{item.hideMobile,jdbcType=TINYINT}, #{item.englishName,jdbcType=VARCHAR}, #{item.tallUserId,jdbcType=BIGINT}
)
</foreach>
</insert>
</mapper>

6
tall/src/main/java/com/ccsens/tall/bean/dto/UserDto.java

@ -24,14 +24,16 @@ public class UserDto {
@ApiModelProperty("用户凭据|密码")
private String credential;
}
@ApiModelProperty("登录客户端:0-wxmp,1-H5,2-Android,3-IOS")
@ApiModelProperty("登录客户端:0-wxmp,1-H5,2-Android,3-IOS,4-WxEnterprise")
@NotNull(message = "client is required.")
private Integer client;
@ApiModelProperty("登录类型:0-wxmp,1-phone,2-email,3-accounts,4-OAUTH2_Wx,5-Wx_H5,6-OAUTH2_WeiBo")
@ApiModelProperty("登录类型:0-wxmp,1-phone,2-email,3-accounts,4-OAUTH2_Wx,5-Wx_H5,6-OAUTH2_WeiBo, 7-Wx_Enterprise")
@NotNull(message = "type is required.")
private Integer type;
@ApiModelProperty("登录信息")
private Data data;
@ApiModelProperty("通知消息")
private String redirect;
}
@Data

2
tall/src/main/java/com/ccsens/tall/service/IUserService.java

@ -14,7 +14,7 @@ import java.util.Map;
public interface IUserService {
UserVo.UserSign signin(WebConstant.CLIENT_TYPE clientType, WebConstant.IDENTIFY_TYPE identifyType,
String identifier, String credential, String clientIp) throws Exception;
String identifier, String credential, String clientIp, String redirect) throws Exception;
UserVo.TokenBean generateToken(WebConstant.CLIENT_TYPE client_type, Object subject, Map<String, Object> payLoads) throws Exception;

110
tall/src/main/java/com/ccsens/tall/service/UserService.java

@ -7,6 +7,7 @@ import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.ccsens.cloudutil.feign.HealthFeignClient;
import com.ccsens.tall.bean.dto.ProjectDto;
import com.ccsens.tall.bean.dto.UserDto;
import com.ccsens.tall.bean.po.*;
@ -15,10 +16,13 @@ import com.ccsens.tall.exception.SmsException;
import com.ccsens.tall.persist.dao.*;
import com.ccsens.util.*;
import com.ccsens.util.bean.wx.po.WxOauth2UserInfo;
import com.ccsens.util.enterprisewx.WeiXinConstant;
import com.ccsens.util.enterprisewx.vo.WeiXinVo;
import com.ccsens.util.exception.BaseException;
import com.ccsens.util.wx.WxGzhUtil;
import com.ccsens.util.wx.WxXcxUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -28,6 +32,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.xhtmlrenderer.css.parser.property.PrimitivePropertyBuilders;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
@ -57,6 +62,8 @@ public class UserService implements IUserService {
private SysProjectDao sysProjectDao;
@Autowired
private UserAttentionDao userAttentionDao;
@Autowired
private HealthFeignClient healthFeignClient;
/**
@ -64,10 +71,10 @@ public class UserService implements IUserService {
*/
@Override
public UserVo.UserSign signin(WebConstant.CLIENT_TYPE clientType, WebConstant.IDENTIFY_TYPE identifyType,
String identifier, String credential, String clientIp) throws Exception {
String identifier, String credential, String clientIp,String redirect) throws Exception {
UserVo.UserSign userSignVo = null;
//1.登陆
userSignVo = __signin(identifyType, identifier, credential);
userSignVo = __signin(identifyType, identifier, credential, redirect);
if (ObjectUtil.isNotNull(userSignVo) && ObjectUtil.isNotNull(userSignVo.getAuthId())) {
//2.添加登陆记录
__addSigninRecord(clientType, clientIp, userSignVo.getAuthId());
@ -76,8 +83,10 @@ public class UserService implements IUserService {
}
private UserVo.UserSign __signin(WebConstant.IDENTIFY_TYPE identifyType,
String identifier, String credential) throws Exception {
String identifier, String credential, String redirect) throws Exception {
switch (identifyType) {
case WxEnterprise:
return wxEnterpriseLogin(identifier, credential, redirect);
case Wxmp:
credential = credential == null ? "old" : credential;
return wxmplogin(identifier,credential);
@ -100,6 +109,33 @@ public class UserService implements IUserService {
return null;
}
/**
* 企业登录
* @param identifier
* @param credential
* @return
*/
private UserVo.UserSign wxEnterpriseLogin(String identifier, String credential, String redirect) {
log.info("企业微信登录:{},{}, {}");
String suiteId = WeiXinConstant.SuiteId.getValue(credential);
if (StrUtil.isBlank(suiteId) || StrUtil.isBlank(identifier)) {
throw new BaseException(CodeEnum.PARAM_ERROR);
}
String suiteAccessToken = healthFeignClient.getSuiteAccessToken(suiteId);
WeiXinVo.UserInfo userInfo = WeiXinConstant.getUserInfo(identifier, suiteAccessToken);
log.info("用户信息");
if (userInfo == null) {
throw new BaseException(CodeEnum.PARAM_ERROR);
}
WxEnterpriseParam param = new WxEnterpriseParam();
param.setRedirect(redirect);
param.setSuiteAccessToken(suiteAccessToken);
param.setUserTicket(userInfo.getUser_ticket());
UserVo.UserSign userSignVo = getUserSign(userInfo.getUserId(), null, (byte) WebConstant.IDENTIFY_TYPE.WxEnterprise.value, param);
return userSignVo;
}
/**
* 微信网页登陆
*
@ -348,19 +384,36 @@ public class UserService implements IUserService {
* 微信小程序
*/
private UserVo.UserSign wxmplogin(String code,String gameType) throws Exception {
UserVo.UserSign userSignVo = null;
//0.获取openid
WxXcxUtil.WechatUser wechatUser = WxXcxUtil.getUserInfo(code,gameType);
String openId = wechatUser.openid;
String unionId = wechatUser.unionid;
log.info("小程序登录,openid:{} ,unionId:{}", openId, unionId);
//1.查找对应账户,不存在则注册
UserVo.UserSign userSignVo = getUserSign(openId, unionId, (byte) WebConstant.IDENTIFY_TYPE.Wxmp.value,null);
return userSignVo;
}
@Data
private static class WxEnterpriseParam{
private String suiteAccessToken;
private String userTicket;
private String redirect;
}
/**
*
* @param openId
* @param unionId
* @return
*/
private UserVo.UserSign getUserSign(String openId, String unionId,
byte identifyType, WxEnterpriseParam param) {
UserVo.UserSign userSignVo;//1.查找对应账户,不存在则注册
List<SysAuth> authList = null;
SysAuth theAuth = null;
if(ObjectUtil.isNotNull(openId)) {
SysAuthExample authExample = new SysAuthExample();
authExample.createCriteria().andIdentifyTypeEqualTo((byte) WebConstant.IDENTIFY_TYPE.Wxmp.value)
authExample.createCriteria().andIdentifyTypeEqualTo(identifyType)
.andIdentifierEqualTo(openId);
authList = authDao.selectByExample(authExample);
}
@ -372,25 +425,31 @@ public class UserService implements IUserService {
sysAuthList = authDao.selectByExample(sysAuthExample);
}
if (CollectionUtil.isNotEmpty(sysAuthList)) {
// SysAuth sysAuth = sysAuthList.get(0);
//添加认证方式
theAuth = new SysAuth();
theAuth.setId(snowflake.nextId());
theAuth.setUserId(sysAuthList.get(0).getUserId());
theAuth.setIdentifyType((byte) WebConstant.IDENTIFY_TYPE.Wxmp.value);
theAuth.setIdentifier(openId);
theAuth.setCredential(unionId);
authDao.insertSelective(theAuth);
if (identifyType == WebConstant.IDENTIFY_TYPE.Wxmp.value) {
//添加认证方式
theAuth = new SysAuth();
theAuth.setId(snowflake.nextId());
theAuth.setUserId(sysAuthList.get(0).getUserId());
theAuth.setIdentifyType(identifyType);
theAuth.setIdentifier(openId);
theAuth.setCredential(unionId);
authDao.insertSelective(theAuth);
} else {
theAuth = sysAuthList.get(0);
}
} else {
//新建用户并保存微信信息
SysUser user = new SysUser();
user.setId(snowflake.nextId());
//企业微信获取详细用户信息,并绑定用户信息
getUserDetail(identifyType, param, user);
userDao.insertSelective(user);
//添加认证方式
theAuth = new SysAuth();
theAuth.setId(snowflake.nextId());
theAuth.setUserId(user.getId());
theAuth.setIdentifyType((byte) WebConstant.IDENTIFY_TYPE.Wxmp.value);
theAuth.setIdentifyType(identifyType);
theAuth.setIdentifier(openId);
theAuth.setCredential(unionId);
authDao.insertSelective(theAuth);
@ -416,6 +475,23 @@ public class UserService implements IUserService {
return userSignVo;
}
private void getUserDetail(byte identifyType, WxEnterpriseParam param, SysUser user) {
if (identifyType == WebConstant.IDENTIFY_TYPE.Wxmp.value) {
WeiXinVo.UserDetail userDetail = WeiXinConstant.getUserDetail(param.getSuiteAccessToken(), param.getUserTicket());
if (userDetail != null) {
user.setNickname(userDetail.getName());
user.setGender(userDetail.getGender());
user.setAvatarUrl(userDetail.getAvatar());
}
Map<String, Object> map = new HashMap<>();
map.put("tallUserId", user.getId());
map.put("userid", userDetail.getUserid());
String s = RestTemplateUtil.postBody(WeiXinConstant.getBindUrl(param.getRedirect()), map);
log.info("{}绑定关系结果:{}", s);
//TODO 绑定失败如何处理
}
}
/**
* 微信登陆后天添加用户和认证方式
*

5
tall/src/main/java/com/ccsens/tall/web/UserController.java

@ -52,16 +52,19 @@ public class UserController {
//1.验证参数
switch (clientType) {
case Wxmp:
case H5:
case Android:
case IOS:
case WxEnterprise:
break;
default:
throw new UserLoginException(-1, String.format("Not supported client type: %1$d(%2$s)",
clientType.value, clientType));
}
switch (identify_type) {
case WxEnterprise:
case Wxmp:
case OAUTH2_Wx:
case Wx_H5:
@ -86,7 +89,7 @@ public class UserController {
//2.调用业务方法(注册/添加登陆记录)
UserVo.UserSign userSignVo = userService.signin(
clientType, identify_type, identifier, credential,
ServletUtil.getClientIP(request));
ServletUtil.getClientIP(request), dto.getRedirect());
//3.生成token(access_token,refresh_token)
if (ObjectUtil.isNotNull(userSignVo)) {

3
tall/src/main/resources/application-test.yml

@ -28,4 +28,5 @@ swagger:
enable: true
eureka:
instance:
ip-address: 49.233.89.188
ip-address: 49.233.89.188
gatewayUrl: https://test.tall.wiki/gateway/

1
util/home

@ -1 +0,0 @@
{"errcode":41030,"errmsg":"invalid page hint: [foP7da0210b464]"}

3
util/src/main/java/com/ccsens/util/CodeEnum.java

@ -96,7 +96,8 @@ public enum CodeEnum {
ALREADY_ATTENTION(79,"您已经关注了这个项目",true),
NOT_EMPLOYEE(80,"未找到成员信息",true),
NOT_SITE(81,"未找到该场所",true),
ALREADY_REAL_AUTH(82,"您已经完成认证",true)
ALREADY_REAL_AUTH(82,"您已经完成认证",true),
LACK_CONFIG(82,"缺少配置",true),
;
public CodeEnum addMsg(String msg){

5
util/src/main/java/com/ccsens/util/PropUtil.java

@ -16,7 +16,12 @@ public class PropUtil {
public static String imgDomain;
public static String projectName;
public static String contextPath;
public static String gatewayUrl;
@Value("${gatewayUrl:}")
public void setGatewayUrl(String gatewayUrl) {
PropUtil.gatewayUrl = gatewayUrl;
}
@Value("${file.path:}")
public void setPath(String path) {
PropUtil.path = path;

6
util/src/main/java/com/ccsens/util/WebConstant.java

@ -146,7 +146,8 @@ public class WebConstant {
public enum CLIENT_TYPE {
Wxmp(0,"微信小程序"), H5(1,"网页"),Android(2
,"安卓客户端"),IOS(3,"苹果客户端");
,"安卓客户端"),IOS(3,"苹果客户端"),
WxEnterprise(4, "企业微信");
public int value;
public String phase;
@ -170,7 +171,7 @@ public class WebConstant {
Wxmp(0,"微信小程序"), Phone(1,"电话")
, Email(2,"Email"), Account(3,"账号")
,OAUTH2_Wx(4,"微信公众号"),Wx_H5(5,"网页微信登陆")
,OAUTH2_WeiBo(6,"微博");
,OAUTH2_WeiBo(6,"微博"),WxEnterprise(7, "企业微信"),;
public int value;
public String phase;
@ -188,6 +189,7 @@ public class WebConstant {
case 4: return OAUTH2_Wx;
case 5: return Wx_H5;
case 6: return OAUTH2_WeiBo;
case 7: return WxEnterprise;
default: return null;
}
}

90
util/src/main/java/com/ccsens/util/enterprisewx/WeiXinConstant.java

@ -1,10 +1,22 @@
package com.ccsens.util.enterprisewx;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.ccsens.util.CodeEnum;
import com.ccsens.util.PropUtil;
import com.ccsens.util.RestTemplateUtil;
import com.ccsens.util.enterprisewx.vo.WeiXinVo;
import com.ccsens.util.exception.BaseException;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
/**
* @author wu
*/
@Slf4j
public class WeiXinConstant {
public static final String token = "4CxIpRDBWHMiePP3x6muNe4hRj";
@ -16,10 +28,33 @@ public class WeiXinConstant {
public static final String secret= "HyhFPrD_7gObsQdX1RTTH6nDeJNduVKGuaF62zqmgYs";
public static final String ERR_CODE = "errcode";
public static final String ERR_MSG = "errmsg";
@Getter
public static enum SuiteId{
Health("health","wwb9ce2061d1cce110"),;
private String suiteType;
private String suiteValue;
private SuiteId(String suiteType, String suiteValue){
this.suiteType = suiteType;
this.suiteValue = suiteValue;
}
/**
* 根据类型获取value
* @param suiteType
* @return
*/
public static String getValue(String suiteType) {
switch (suiteType) {
case "health" : return Health.getSuiteValue();
default: return null;
}
}
}
/**
* 获取永久授权
*/
@ -27,7 +62,9 @@ public class WeiXinConstant {
public static final String GET_SUITE_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token";
public static final String GET_CORP_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/service/get_corp_token";
public static final String DEPARTMENT_LIST = "https://qyapi.weixin.qq.com/cgi-bin/department/list";
public static final String USER_LIST = "https://qyapi.weixin.qq.com/cgi-bin/user/list";
public static final String USER_INFO_3RD = "https://qyapi.weixin.qq.com/cgi-bin/service/getuserinfo3rd";
public static final String USER_DETAIL = "https://qyapi.weixin.qq.com/cgi-bin/service/getuserdetail3rd";
/**
* 获取第三方凭证
@ -74,7 +111,56 @@ public class WeiXinConstant {
* @return
*/
public static boolean pageResult(JSONObject result) {
return result.getIntValue(ERR_CODE) == 0;
return result.getInteger(ERR_CODE) == null || result.getIntValue(ERR_CODE) == 0;
}
/**
* 查询用户信息
* @param code
* @param suiteAccessToken
* @return
*/
public static WeiXinVo.UserInfo getUserInfo(String code, String suiteAccessToken) {
Map<String, Object> param = new HashMap<>();
param.put("suite_access_token", suiteAccessToken);
param.put("code", code);
WeiXinVo.UserInfo userInfo = (WeiXinVo.UserInfo) RestTemplateUtil.getForEntity(USER_INFO_3RD, param, WeiXinVo.UserInfo.class);
log.info("获取用户信息:{}", userInfo);
if (StrUtil.isNotBlank(userInfo.getErrcode()) && !"0".equals(userInfo.getErrcode())) {
return null;
}
return userInfo;
}
/**
* 获取用户详细信息
* @param suite_access_token
* @param user_ticket
* @return
*/
public static WeiXinVo.UserDetail getUserDetail(String suite_access_token, String user_ticket){
String url = USER_DETAIL + "?suite_access_token=" + suite_access_token;
Map<String, Object> param = new HashMap<>();
param.put("user_ticket", user_ticket);
String result = RestTemplateUtil.postBody(url, param);
log.info("获取用户详细信息返回:{}", result);
WeiXinVo.UserDetail userDetail = JSONObject.parseObject(result, WeiXinVo.UserDetail.class);
if (StrUtil.isNotBlank(userDetail.getErrcode()) && !"0".equals(userDetail.getErrcode())) {
return null;
}
return userDetail;
}
/**
* 获取绑定路径
* @param type
* @return
*/
public static String getBindUrl(String type){
if (StrUtil.isBlank(PropUtil.gatewayUrl)) {
throw new BaseException(CodeEnum.LACK_CONFIG);
}
return PropUtil.gatewayUrl + type + "/bindUser";
}
}

1
util/src/main/java/com/ccsens/util/enterprisewx/dto/MessageDto.java

@ -16,6 +16,7 @@ public class MessageDto {
private String msg_signature;
private String timestamp;
private String nonce;
//get方法返回
private String echostr;

49
util/src/main/java/com/ccsens/util/enterprisewx/vo/WeiXinVo.java

@ -0,0 +1,49 @@
package com.ccsens.util.enterprisewx.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("微信相关接口返回")
public class WeiXinVo {
@Data
@ApiModel("微信用戶信息")
public static class UserInfo{
@ApiModelProperty("返回码")
private String errcode;
@ApiModelProperty("对返回码的文本描述内容")
private String errmsg;
@ApiModelProperty("用户所属企业的corpid")
private String CorpId;
@ApiModelProperty("用户在企业内的UserID,如果该企业与第三方应用有授权关系时,返回明文UserId,否则返回密文UserId")
private String UserId;
@ApiModelProperty("手机设备号(由企业微信在安装时随机生成,删除重装会改变,升级不受影响)")
private String DeviceId;
@ApiModelProperty("成员票据,最大为512字节。")
private String user_ticket;
@ApiModelProperty("user_ticket的有效时间(秒),随user_ticket一起返回")
private String expires_in;
}
@Data
@ApiModel("用户详细信息")
public static class UserDetail{
@ApiModelProperty("返回码")
private String errcode;
@ApiModelProperty("对返回码的文本描述内容")
private String errmsg;
@ApiModelProperty("用户所属企业的corpid")
private String corpid;
@ApiModelProperty("成员UserID")
private String userid;
@ApiModelProperty("成员姓名,此字段从2019年12月30日起,对新创建第三方应用不再返回,2020年6月30日起,对所有历史第三方应用不再返回,第三方页面需要通过通讯录展示组件来展示名字")
private String name;
@ApiModelProperty("性别。0表示未定义,1表示男性,2表示女性")
private Byte gender;
@ApiModelProperty("头像url。仅在用户同意snsapi_privateinfo授权时返回")
private String avatar;
@ApiModelProperty("员工个人二维码(扫描可添加为外部联系人),仅在用户同意snsapi_privateinfo授权时返回")
private String qr_code;
}
}
Loading…
Cancel
Save