UsersService.java 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. package com.qxgmat.service;
  2. import com.github.pagehelper.Page;
  3. import com.nuliji.tools.AbstractService;
  4. import com.nuliji.tools.CipherHelp;
  5. import com.nuliji.tools.Tools;
  6. import com.nuliji.tools.Transform;
  7. import com.nuliji.tools.exception.AuthException;
  8. import com.nuliji.tools.exception.ParameterException;
  9. import com.nuliji.tools.exception.SystemException;
  10. import com.nuliji.tools.mybatis.Example;
  11. import com.nuliji.tools.mybatis.NativeJsonHandler;
  12. import com.nuliji.tools.third.OauthData;
  13. import com.qxgmat.data.constants.enums.status.DirectionStatus;
  14. import com.qxgmat.data.constants.enums.user.PrepareExaminationTime;
  15. import com.qxgmat.data.dao.UserMapper;
  16. import com.qxgmat.data.dao.entity.User;
  17. import com.qxgmat.data.dao.entity.UserOrder;
  18. import com.qxgmat.data.inline.UserToken;
  19. import com.qxgmat.data.relation.UserRelationMapper;
  20. import com.qxgmat.data.relation.entity.UserPrepareRelation;
  21. import com.qxgmat.help.WechatHelp;
  22. import com.qxgmat.service.extend.MessageExtendService;
  23. import com.qxgmat.service.extend.OrderFlowService;
  24. import com.qxgmat.service.inline.UserCourseService;
  25. import com.qxgmat.service.inline.UserMessageService;
  26. import com.qxgmat.service.inline.UserOrderService;
  27. import org.hibernate.criterion.Order;
  28. import org.springframework.beans.factory.annotation.Value;
  29. import org.springframework.stereotype.Service;
  30. import org.springframework.transaction.annotation.Transactional;
  31. import javax.annotation.Resource;
  32. import java.math.BigDecimal;
  33. import java.util.*;
  34. /**
  35. * Created by GaoJie on 2017/11/1.
  36. */
  37. @Service
  38. public class UsersService extends AbstractService {
  39. final public String PLATORM_WECHAT_NATIVE = "wechatOpenidWechat";
  40. final public String PLATORM_WECHAT_PC = "wechatOpenidPc";
  41. final public String PLATORM_WECHAT = "wechatUnionid";
  42. @Value("${self.secret}")
  43. private String secret;
  44. private NativeJsonHandler<UserToken> tokenHandler = new NativeJsonHandler<UserToken>(UserToken.class);
  45. @Resource
  46. private UserMapper userMapper;
  47. @Resource
  48. private WechatHelp wechatHelp;
  49. @Resource
  50. private UserRelationMapper userRelationMapper;
  51. @Resource
  52. private OrderFlowService orderFlowService;
  53. @Resource
  54. private MessageExtendService messageExtendService;
  55. /**
  56. * 生成有效期token
  57. * @param user
  58. * @return
  59. */
  60. public String getTokenByUser(User user){
  61. UserToken ut = new UserToken();
  62. ut.setId(user.getId());
  63. Date expire = new Date(new Date().getTime() + 86400);
  64. ut.setExpire(expire);
  65. String info = tokenHandler.toJson(ut);
  66. return CipherHelp.encrypt(info, CipherHelp.DES, secret);
  67. }
  68. /**
  69. * 解析有效期token
  70. * @param token
  71. * @return
  72. */
  73. public User getUserByToken(String token){
  74. // 默认测试token
  75. if (token.equals("1234567890")){
  76. return get(1);
  77. }else{
  78. String info = CipherHelp.decrypt(token, CipherHelp.DES, secret);
  79. UserToken ut = tokenHandler.toObject(info);
  80. Date expire = ut.getExpire();
  81. if (expire.before(new Date())){
  82. throw new AuthException("token错误");
  83. }
  84. return get(ut.getId());
  85. }
  86. }
  87. /**
  88. * 绑定第三方账号信息
  89. * @param user 当前登录用户
  90. * @param code
  91. * @param platform
  92. * @return
  93. */
  94. @Transactional
  95. public User Oauth(User user, String code, String platform, boolean userInfo){
  96. OauthData data;
  97. switch(platform){
  98. case "wechat_pc":
  99. data = wechatHelp.oauthPc(code, userInfo);
  100. break;
  101. case "wechat_native":
  102. data = wechatHelp.oauthNative(code, userInfo);
  103. break;
  104. default:
  105. throw new ParameterException("第三方平台"+platform+"不支持");
  106. }
  107. // 获取已关联的账号
  108. if (user == null){
  109. user = getByOpen(data.getOpenId(), data.getUnionId(), platform);
  110. } else {
  111. // 检验是否已经绑定
  112. User openUser = getByOpen(data.getOpenId(), data.getUnionId(), platform);
  113. if(openUser != null && !openUser.getId().equals(user.getId())){
  114. // // 自动合并账号
  115. // // 更新消息
  116. // userMessageService.mergeUser(openUser.getId(), user.getId());
  117. // // 更新消费记录
  118. // userOrderService.mergeUser(openUser.getId(), user.getId());
  119. // // 更新课程信息
  120. // userCourseService.mergeUser(openUser.getId(), user.getId());
  121. // // 更新服务信息
  122. // userServiceService.mergeUser(openUser.getId(), user.getId());
  123. //
  124. // // 更新实名认证
  125. // if (openUser.getRealStatus() > 0){
  126. // user.setRealAddress(openUser.getRealAddress());
  127. // user.setRealIdentity(openUser.getRealIdentity());
  128. // user.setRealName(openUser.getRealName());
  129. // user.setRealPhotoFront(openUser.getRealPhotoFront());
  130. // user.setRealPhotoBack(openUser.getRealPhotoBack());
  131. // user.setRealStatus(openUser.getRealStatus());
  132. // }
  133. //
  134. // // 删除旧账号
  135. // delete(openUser.getId());
  136. throw new ParameterException("该微信账户已绑定其他手机号,您可直接使用微信登录");
  137. }
  138. }
  139. if (user == null){
  140. user = new User();
  141. user.setAvatar(data.getAvatar());
  142. user.setNickname(data.getNickName());
  143. }
  144. switch(platform){
  145. case "wechat_pc":
  146. user.setWechatOpenidPc(data.getOpenId());
  147. user.setWechatUnionid(data.getUnionId());
  148. break;
  149. case "wechat_native":
  150. user.setWechatOpenidWechat(data.getOpenId());
  151. user.setWechatUnionid(data.getUnionId());
  152. user.setWechatAccessToken(data.getAccessToken());
  153. user.setWechatRefreshToken(data.getRefreshToken());
  154. user.setWechatExpireTime(data.getExpiresTime());
  155. break;
  156. }
  157. if (!user.getMobile().isEmpty()){
  158. // 直接更新数据
  159. edit(user);
  160. }
  161. return user;
  162. }
  163. /**
  164. * 通过手机号注册
  165. * @param mobile
  166. * @param inviteCode
  167. * @param openUser
  168. * @return
  169. */
  170. @Transactional
  171. public User register(String area, String mobile, String inviteCode, String email, User openUser, String registerIp, String[] registerInfo){
  172. boolean n = false;
  173. User user = getByMobile(area, mobile);
  174. if (user != null){
  175. if (openUser == null) {
  176. // 直接手机登录,异常抛出,根据情况忽略
  177. throw new ParameterException("手机号已注册");
  178. }else if(user.getWechatUnionid() != null && !user.getWechatUnionid().equals("")){
  179. // openUser不为空,则用于绑定微信
  180. throw new ParameterException("该手机已绑定其他账号,请更换手机号码");
  181. }
  182. if (user.getRegisterIp() == null || user.getRegisterIp().isEmpty()){
  183. user.setRegisterIp(registerIp);
  184. user.setRegisterCity(registerInfo != null ? String.join(",",registerInfo) : "");
  185. user.setLatestLoginIp(registerIp);
  186. }
  187. }else{
  188. // 注册,并且绑定邀请者
  189. user = User.builder().area(area).mobile(mobile).email(email).build();
  190. n = true;
  191. if (inviteCode != null && !inviteCode.isEmpty()){
  192. User origin = getByInviteCode(inviteCode);
  193. user.setOriginId(origin.getId());
  194. edit(User.builder().id(origin.getId()).inviteNumber(origin.getInviteNumber() + 1).build());
  195. // 邀请奖励
  196. orderFlowService.giveInvite(origin.getId());
  197. }
  198. // 生成邀请码: 10位字符串
  199. user.setInviteCode(Tools.getRandomString(10));
  200. user.setRegisterIp(registerIp);
  201. user.setRegisterCity(registerInfo != null ? String.join(",",registerInfo) : "");
  202. user.setLatestLoginIp(registerIp);
  203. }
  204. // 绑定第三方登录信息
  205. if (openUser != null){
  206. this.bind(user, openUser);
  207. }
  208. if (n){
  209. user = add(user);
  210. messageExtendService.sendRegister(user);
  211. }else{
  212. user = edit(user);
  213. }
  214. if(user == null)
  215. throw new SystemException("注册失败");
  216. return user;
  217. }
  218. public User bind(User user, User openUser){
  219. // 绑定第三方登录信息
  220. if(openUser.getWechatOpenidPc() != null) user.setWechatOpenidPc(openUser.getWechatOpenidPc());
  221. if(openUser.getWechatOpenidWechat() != null) user.setWechatOpenidWechat(openUser.getWechatOpenidWechat());
  222. if(openUser.getWechatExpireTime() != null) user.setWechatExpireTime(openUser.getWechatExpireTime());
  223. if(openUser.getWechatUnionid() != null) user.setWechatUnionid(openUser.getWechatUnionid());
  224. if(openUser.getWechatAccessToken() != null) user.setWechatAccessToken(openUser.getWechatAccessToken());
  225. if(openUser.getWechatRefreshToken() != null) user.setWechatRefreshToken(openUser.getWechatRefreshToken());
  226. if(openUser.getNickname() != null) user.setNickname(openUser.getNickname());
  227. if(openUser.getAvatar() != null) user.setAvatar(openUser.getAvatar());
  228. return user;
  229. }
  230. // 获取微信快到期账号
  231. public Page<User> listByWechatExpire(int page, int size, Date expire){
  232. Example example = new Example(User.class);
  233. example.and(
  234. example.createCriteria()
  235. .andLessThan("wechatExpireTime", expire)
  236. );
  237. return page(()->select(userMapper, example), page, size);
  238. }
  239. // 通过手机号获取用户
  240. public User getByMobile(String area, String mobile){
  241. User user = User.builder().area(area).mobile(mobile).build();
  242. return one(userMapper, user);
  243. }
  244. // 通过身份证获取用户
  245. public User getByIdentity(String identity){
  246. User user = User.builder().realIdentity(identity).build();
  247. return one(userMapper, user);
  248. }
  249. // 通过openid获取用户
  250. public User getByOpen(String openId, String unionId, String platform){
  251. String platformField;
  252. String unionField;
  253. switch(platform){
  254. case "wechat_pc":
  255. platformField = PLATORM_WECHAT_PC;
  256. unionField = PLATORM_WECHAT;
  257. break;
  258. case "wechat_native":
  259. platformField = PLATORM_WECHAT_NATIVE;
  260. unionField = PLATORM_WECHAT;
  261. break;
  262. default:
  263. throw new ParameterException("第三方平台"+platform+"不支持");
  264. }
  265. Example example = new Example(User.class);
  266. example.or(
  267. example.createCriteria()
  268. .andEqualTo(platformField, openId)
  269. );
  270. if (unionId != null && !unionId.isEmpty()){
  271. example.or(
  272. example.createCriteria()
  273. .andEqualTo(unionField, unionId)
  274. );
  275. }
  276. return one(userMapper, example);
  277. }
  278. /**
  279. * 通过邀请码或者手机好获取邀请人
  280. * @param inviteCode
  281. * @return
  282. */
  283. public User getByInviteCode(String inviteCode){
  284. User user = new User();
  285. Example example = new Example(User.class);
  286. // 查找手机或邀请码
  287. example.and(
  288. example.createCriteria()
  289. .orEqualTo("invite_code", inviteCode)
  290. .orEqualTo("mobile", inviteCode)
  291. );
  292. return one(userMapper, example);
  293. }
  294. /**
  295. * 获取备考统计:身份
  296. * @return
  297. */
  298. public List<UserPrepareRelation> statPrepareStatus(){
  299. return userRelationMapper.groupPrepareString("prepare_status");
  300. }
  301. /**
  302. * 获取备考统计:目标分数
  303. * @return
  304. */
  305. public List<UserPrepareRelation> statPrepareGoal(){
  306. List<UserPrepareRelation> relations = userRelationMapper.groupPrepareInteger("prepare_goal");
  307. // 按考分分组
  308. List<UserPrepareRelation> userPrepareRelationList = new ArrayList<>();
  309. Integer[] goalGroup = new Integer[]{600, 650, 700, 750};
  310. for(Integer goal : goalGroup){
  311. UserPrepareRelation real = new UserPrepareRelation();
  312. real.setI(goal);
  313. real.setNumber(0);
  314. userPrepareRelationList.add(real);
  315. }
  316. for(UserPrepareRelation relation : relations){
  317. int goal = -1;
  318. for(int i = 0; i < goalGroup.length; i++){
  319. // 根据考分判断层级
  320. if (goalGroup[i] > relation.getI()){
  321. // 属于上一层
  322. goal = i - 1;
  323. break;
  324. }
  325. }
  326. if (goal > 0){
  327. // 按层级归类
  328. UserPrepareRelation real = userPrepareRelationList.get(goal);
  329. real.setNumber(real.getNumber()+relation.getNumber());
  330. }
  331. }
  332. return userPrepareRelationList;
  333. }
  334. /**
  335. * 获取备考统计:考试时间
  336. * @return
  337. */
  338. public List<UserPrepareRelation> statPrepareExaminationTime(){
  339. return userRelationMapper.groupPrepareString("prepare_examination_time");
  340. }
  341. /**
  342. * 获取备考统计:出分时间
  343. * @return
  344. */
  345. public List<UserPrepareRelation> statPrepareScoreTime(){
  346. // 直接按不同时间段统计
  347. Example example;
  348. List<UserPrepareRelation> userPrepareRelationList = new ArrayList<>();
  349. Calendar calendar = Calendar.getInstance();
  350. // 一个月内
  351. calendar.setTime(new Date());
  352. calendar.add(Calendar.MONTH, 1);
  353. example = new Example(User.class);
  354. example.and(
  355. example.createCriteria()
  356. .andLessThan("prepareScoreTime", calendar.getTime())
  357. );
  358. UserPrepareRelation oneMonth = new UserPrepareRelation();
  359. oneMonth.setS(PrepareExaminationTime.ONE_MONTH.key);
  360. oneMonth.setNumber(count(userMapper, example));
  361. userPrepareRelationList.add(oneMonth);
  362. // 两个月内
  363. calendar.setTime(new Date());
  364. calendar.add(Calendar.MONTH, 2);
  365. example = new Example(User.class);
  366. example.and(
  367. example.createCriteria()
  368. .andLessThan("prepareScoreTime", calendar.getTime())
  369. );
  370. UserPrepareRelation twoMonth = new UserPrepareRelation();
  371. twoMonth.setS(PrepareExaminationTime.TWO_MONTH.key);
  372. twoMonth.setNumber(count(userMapper, example) - oneMonth.getNumber());
  373. userPrepareRelationList.add(twoMonth);
  374. // 三个月内
  375. calendar.setTime(new Date());
  376. calendar.add(Calendar.MONTH, 3);
  377. example = new Example(User.class);
  378. example.and(
  379. example.createCriteria()
  380. .andLessThan("prepareScoreTime", calendar.getTime())
  381. );
  382. UserPrepareRelation threeMonth = new UserPrepareRelation();
  383. threeMonth.setS(PrepareExaminationTime.THREE_MONTH.key);
  384. threeMonth.setNumber(count(userMapper, example) - twoMonth.getNumber());
  385. userPrepareRelationList.add(threeMonth);
  386. // 半年
  387. calendar.setTime(new Date());
  388. calendar.add(Calendar.MONTH, 6);
  389. example = new Example(User.class);
  390. example.and(
  391. example.createCriteria()
  392. .andLessThan("prepareScoreTime", calendar.getTime())
  393. );
  394. UserPrepareRelation sixMonth = new UserPrepareRelation();
  395. sixMonth.setS(PrepareExaminationTime.SIX_MONTH.key);
  396. sixMonth.setNumber(count(userMapper, example) - threeMonth.getNumber());
  397. userPrepareRelationList.add(sixMonth);
  398. // 一年
  399. calendar.setTime(new Date());
  400. calendar.add(Calendar.MONTH, 12);
  401. example = new Example(User.class);
  402. example.and(
  403. example.createCriteria()
  404. .andLessThan("prepareScoreTime", calendar.getTime())
  405. );
  406. UserPrepareRelation oneYear = new UserPrepareRelation();
  407. oneYear.setS(PrepareExaminationTime.ONE_YEAR.key);
  408. oneYear.setNumber(count(userMapper, example) - sixMonth.getNumber());
  409. userPrepareRelationList.add(oneYear);
  410. // 其他
  411. example = new Example(User.class);
  412. example.and(
  413. example.createCriteria()
  414. // 设置过备考信息的人:mapper中做为基本条件
  415. .andGreaterThan("prepareGoal", 0)
  416. .andIsNull("prepareScoreTime")
  417. );
  418. UserPrepareRelation other = new UserPrepareRelation();
  419. other.setS(PrepareExaminationTime.OTHER.key);
  420. other.setNumber(count(userMapper, example));
  421. userPrepareRelationList.add(other);
  422. return userPrepareRelationList;
  423. }
  424. private Map<String, String> adminMap = new HashMap<String, String>(){{
  425. put("", "u");
  426. }};
  427. /**
  428. * 获取购买过课程的用户
  429. * @param page
  430. * @param pageSize
  431. * @param keyword
  432. * @param courseId
  433. * @return
  434. */
  435. public Page<User> listAdminByCourse(int page, int pageSize, String keyword, Integer courseId, String order, DirectionStatus direction){
  436. if(order == null || order.isEmpty()){
  437. order = "id";
  438. }
  439. if(adminMap.containsKey(order)){
  440. order = adminMap.get(order)+".`"+Tools.underscoreName(order)+"`";
  441. }else{
  442. order = adminMap.get("")+".`"+Tools.underscoreName(order)+"`";
  443. }
  444. if (direction == null){
  445. direction = DirectionStatus.DESC;
  446. }
  447. String finalOrder = order;
  448. DirectionStatus finalDirection = direction;
  449. Page<User> p = page(()->{
  450. userRelationMapper.listByCourse(keyword, courseId, finalOrder, finalDirection.key);
  451. }, page, pageSize);
  452. Collection ids = Transform.getIds(p, User.class, "id");
  453. // 获取详细数据
  454. List<User> list = select(ids);
  455. Transform.replace(p, list, User.class, "id");
  456. return p;
  457. }
  458. /**
  459. * 获取总用户数
  460. * @return
  461. */
  462. public Integer count(){
  463. Example example = new Example(User.class);
  464. return count(userMapper, example);
  465. }
  466. /**
  467. * 累加支付金额
  468. * @param userId
  469. * @param money
  470. */
  471. public void accumulation(Integer userId, BigDecimal money){
  472. userRelationMapper.accumulation(userId, money);
  473. }
  474. public Page<User> listAdmin(int page, int pageSize, String keyword, Boolean real, Boolean wechat, Boolean prepare, String startTime, String endTime, String order, DirectionStatus direction){
  475. Example example = new Example(User.class);
  476. if(keyword != null)
  477. example.and(
  478. example.createCriteria()
  479. .orLike("id", "%"+keyword+"%")
  480. .orLike("mobile", "%"+keyword+"%")
  481. );
  482. if (real != null)
  483. example.and(
  484. example.createCriteria().andEqualTo("realStatus", real?1:0)
  485. );
  486. if (wechat != null)
  487. example.and(
  488. wechat ? example.createCriteria().andNotEqualTo("wechatUnionid", "") : example.createCriteria().andEqualTo("wechatUnionid", "")
  489. );
  490. if (prepare != null)
  491. example.and(
  492. prepare ? example.createCriteria().andIsNotNull("prepareTime"):example.createCriteria().andIsNull("prepareTime")
  493. );
  494. if (startTime != null){
  495. example.and(
  496. example.createCriteria().andGreaterThanOrEqualTo("createTime", startTime)
  497. );
  498. }
  499. if(endTime != null){
  500. example.and(
  501. example.createCriteria().andLessThan("createTime", endTime)
  502. );
  503. }
  504. if(order==null||order.isEmpty()) order = "id";
  505. if (direction != null){
  506. switch(direction){
  507. case ASC:
  508. example.orderBy(order).asc();
  509. break;
  510. case DESC:
  511. default:
  512. example.orderBy(order).desc();
  513. }
  514. } else {
  515. example.orderBy(order).desc();
  516. }
  517. return select(userMapper, example, page, pageSize);
  518. }
  519. public boolean equalsPassword(User user, String password){
  520. return Objects.equals(user.getPassword(), Tools.stringMD5(Tools.stringMD5(password)));
  521. }
  522. public boolean changePassword(User user, String password){
  523. User updateUser = User.builder().id(user.getId()).password(Tools.stringMD5(Tools.stringMD5(password))).build();
  524. int result = update(userMapper, updateUser);
  525. return result > 0;
  526. }
  527. public User add(User user){
  528. if(user.getPassword() != null) user.setPassword(Tools.stringMD5(user.getPassword()));
  529. int result = insert(userMapper, user);
  530. user = one(userMapper, user.getId());
  531. if(user == null){
  532. throw new SystemException("用户添加失败");
  533. }
  534. return user;
  535. }
  536. public User edit(User user){
  537. User in = one(userMapper, user.getId());
  538. if(in == null){
  539. throw new ParameterException("用户不存在");
  540. }
  541. if(user.getPassword() != null) user.setPassword(Tools.stringMD5(user.getPassword()));
  542. int result = update(userMapper, user);
  543. return user;
  544. }
  545. public boolean delete(Number id){
  546. User in = one(userMapper, id);
  547. if(in == null){
  548. throw new ParameterException("用户不存在");
  549. }
  550. int result = delete(userMapper, id);
  551. return result > 0;
  552. }
  553. public User get(Number id){
  554. User in = one(userMapper, id);
  555. if(in == null){
  556. throw new ParameterException("用户不存在");
  557. }
  558. return in;
  559. }
  560. public Page<User> select(int page, int pageSize){return select(userMapper, page, pageSize);
  561. }
  562. public Page<User> select(Integer[] ids){
  563. return page(()->select(userMapper, ids), 1, ids.length);
  564. }
  565. public List<User> select(Collection ids){
  566. return select(userMapper, ids);
  567. }
  568. }