UserServiceImpl.java 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. package com.uas.sso.service.impl;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.uas.sso.common.encrypt.MD5;
  5. import com.uas.sso.common.util.HttpUtil;
  6. import com.uas.sso.core.Const;
  7. import com.uas.sso.core.Status;
  8. import com.uas.sso.core.Type;
  9. import com.uas.sso.dao.UserDao;
  10. import com.uas.sso.dao.UserRecordDao;
  11. import com.uas.sso.entity.*;
  12. import com.uas.sso.exception.VisibleError;
  13. import com.uas.sso.foreign.entity.ForeignInfo;
  14. import com.uas.sso.foreign.bihe.entity.BiHeInfo;
  15. import com.uas.sso.foreign.weixin.entity.OAuthInfo;
  16. import com.uas.sso.i.CountCallBack;
  17. import com.uas.sso.logging.LoggerManager;
  18. import com.uas.sso.logging.SyncBufferedLogger;
  19. import com.uas.sso.logging.UserBufferedLogger;
  20. import com.uas.sso.service.*;
  21. import com.uas.sso.support.SyncFail;
  22. import com.uas.sso.util.AccountTypeUtils;
  23. import com.uas.sso.util.CountUtils;
  24. import com.uas.sso.util.PasswordLevelUtils;
  25. import org.springframework.beans.factory.annotation.Autowired;
  26. import org.springframework.data.domain.Page;
  27. import org.springframework.data.domain.PageRequest;
  28. import org.springframework.data.domain.Pageable;
  29. import org.springframework.data.jpa.domain.Specification;
  30. import org.springframework.stereotype.Service;
  31. import org.springframework.ui.ModelMap;
  32. import org.springframework.util.Assert;
  33. import org.springframework.util.CollectionUtils;
  34. import org.springframework.util.StringUtils;
  35. import javax.persistence.criteria.*;
  36. import javax.validation.constraints.NotNull;
  37. import java.sql.Timestamp;
  38. import java.text.ParseException;
  39. import java.text.SimpleDateFormat;
  40. import java.util.*;
  41. import java.util.concurrent.ExecutorService;
  42. /**
  43. * 用户service实现类
  44. *
  45. * @author wangmh
  46. * @date 2018/1/2
  47. */
  48. @Service
  49. public class UserServiceImpl implements UserService {
  50. @Autowired
  51. private UserDao userDao;
  52. @Autowired
  53. private UserRecordDao userRecordDao;
  54. @Autowired
  55. private UserValidService userValidService;
  56. @Autowired
  57. private UserspaceService userspaceService;
  58. @Autowired
  59. private AppService appService;
  60. @Autowired
  61. private ExecutorService executorService;
  62. @Autowired
  63. private UserQuestionService userQuestionService;
  64. @Autowired
  65. private TokenService tokenService;
  66. private UserBufferedLogger userLogger = LoggerManager.getLogger(UserBufferedLogger.class);
  67. private SyncBufferedLogger syncLogger = LoggerManager.getLogger(SyncBufferedLogger.class);
  68. @Override
  69. public User findByMobile(String mobile, String mobileArea) {
  70. return userDao.findByMobileAndMobileArea(mobile, mobileArea);
  71. }
  72. @Override
  73. public User findByMobile(String mobile) {
  74. return userDao.findByMobile(mobile);
  75. }
  76. @Override
  77. public boolean mobileHasRegistered(String mobile) {
  78. User user = userDao.findByMobile(mobile);
  79. if (user == null) {
  80. return false;
  81. }
  82. return true;
  83. }
  84. @Override
  85. public boolean emailHasRegistered(String email) {
  86. List<User> users = userDao.findByEmail(email);
  87. if (CollectionUtils.isEmpty(users)) {
  88. return false;
  89. }
  90. return true;
  91. }
  92. @Override
  93. public synchronized User register(User user, String appId) {
  94. String noEncryPwd = user.getPassword();
  95. // 校验手机号是否被注册
  96. if (mobileHasRegistered(user.getMobile())) {
  97. throw new VisibleError("该手机号已被注册");
  98. }
  99. // 由于现在不考虑手机号所属区域,默认为中国大陆
  100. if (StringUtils.isEmpty(user.getMobileArea())) {
  101. user.setMobileArea(Const.CONTINENT);
  102. }
  103. if (user.getMobile() == null || !user.getMobile().matches(Const.REGEXP_MOBILE_CONTINENT)) {
  104. throw new VisibleError("请填写正确的手机号");
  105. }
  106. // 设置基本属性,手机号默认已认证
  107. user.setRegisterDate(new Timestamp(System.currentTimeMillis()));
  108. Long uu = userDao.findMaxUU();
  109. user.setUserUU(uu == null ? 1000060000L : (uu + 1));
  110. user.setSalt(String.valueOf(user.getUserUU()));
  111. user.setMobileValidCode((short) Status.AUTHENTICATED.getCode());
  112. user.setEmailValidCode((short) Status.NOT_APPLYING.getCode());
  113. user.setIdentityValidCode((short) Status.NOT_APPLYING.getCode());
  114. user.setPassword(getEncryPassword(Const.ENCRY_FORMAT, user.getPassword(), user.getSalt()));
  115. user.setFromApp(appId);
  116. user = userDao.save(user);
  117. UserRecord userRecord = new UserRecord(user.getUserUU());
  118. userRecordDao.save(userRecord);
  119. userLogger.info(user, Type.UPDATE_REGISTER.getValue());
  120. // 同步到各个应用
  121. App app = appService.findOne(appId);
  122. return syncUserInfo(user, noEncryPwd, "个人注册", app);
  123. }
  124. @Override
  125. public String getEncryPassword(String format, String noEncryPwd, String salt) {
  126. if (StringUtils.isEmpty(format)) {
  127. return noEncryPwd;
  128. }
  129. // 超过32认为是已加密过的密文
  130. if (noEncryPwd.length() >= 32) {
  131. /// 之后添加日志时恢复
  132. //logger.error("用户密码加密", String.format("传递过来的密码(%s)必须是未加密的明文", noEncryPwd));
  133. throw new VisibleError("密码过长,请重新输入");
  134. }
  135. // $password{$salt}
  136. String password = format.replace(Const.ENCRY_PARAM_PASSWORD, noEncryPwd);
  137. password = password.replace(Const.ENCRY_PARAM_SALT, salt == null ? "" : salt);
  138. return MD5.toMD5(password);
  139. }
  140. @Override
  141. public User save(User user) {
  142. user = userDao.save(user);
  143. return syncUserInfo(user, null, "修改用户信息", null);
  144. }
  145. @Override
  146. public void checkPassword(Long userUU, String password, boolean isEncry) {
  147. // 根据用户uu号找到旧数据
  148. User oldUser = userDao.findByUserUU(userUU);
  149. if (oldUser == null) {
  150. throw new VisibleError("用户名或密码错误");
  151. }
  152. // 校验密码
  153. checkPassword(oldUser, password, isEncry);
  154. }
  155. @Override
  156. public void checkPasswordByMobile(String mobile, String password, boolean isEncry) {
  157. // 找到用户
  158. User oldUser = userDao.findByMobile(mobile);
  159. if (oldUser == null) {
  160. throw new VisibleError("用户名或密码错误");
  161. }
  162. // 校验密码
  163. checkPassword(oldUser, password, isEncry);
  164. }
  165. @Override
  166. public void checkPasswordByEmail(String email, String password, boolean isEncry) {
  167. // 找到用户
  168. List<User> oldUsers = userDao.findByEmailAndEmailValidCode(email, (short) Status.AUTHENTICATED.getCode());
  169. if (CollectionUtils.isEmpty(oldUsers)) {
  170. throw new VisibleError("该邮箱未认证,请使用手机号登录");
  171. }
  172. // 校验密码
  173. for (User oldUser : oldUsers) {
  174. checkPassword(oldUser, password, isEncry);
  175. }
  176. }
  177. @Override
  178. public boolean checkPasswordByUsername(String username, String password, boolean isEncry) {
  179. Assert.hasText(username, "用户名不能为空");
  180. Assert.hasText(password, "密码不能为空");
  181. User user = findByUsername(username);
  182. checkPassword(user, password, isEncry);
  183. return true;
  184. }
  185. @Override
  186. public int getPwdErrorCount(String username) {
  187. User user = findByUsername(username);
  188. if (user == null) {
  189. throw new VisibleError("用户名不存在");
  190. }
  191. UserRecord userRecord = userRecordDao.findOne(user.getUserUU());
  192. if (userRecord == null) {
  193. return 0;
  194. }
  195. return userRecord.getPwdErrorCount();
  196. }
  197. @Override
  198. public User findByUsername(String username) {
  199. String type = AccountTypeUtils.getAccountType(username);
  200. User user = null;
  201. if (AccountTypeUtils.MOBILE.equals(type)) {
  202. // 手机号
  203. user = userDao.findByMobile(username);
  204. } else if (AccountTypeUtils.EMAIL.equals(type)) {
  205. // 邮箱
  206. List<User> users = userDao.findByEmailAndEmailValidCode(username, (short) Status.AUTHENTICATED.getCode());
  207. // 认证邮箱只有一条记录,直接选择第一个
  208. if (!CollectionUtils.isEmpty(users)) {
  209. user = users.get(0);
  210. }
  211. } else if (AccountTypeUtils.UU_NUMBER.equals(type)) {
  212. // uu号
  213. user = userDao.findByUserUU(Long.valueOf(username));
  214. }
  215. return user;
  216. }
  217. /**
  218. * 校验用户密码
  219. *
  220. * @param oldUser 用户信息
  221. * @param password 需要校验的密码
  222. * @param isEncry 需校验的密码是否被加密
  223. */
  224. private void checkPassword(User oldUser, String password, boolean isEncry) {
  225. // 密码未加密,转换成加密后的密码
  226. String encryPassword = password;
  227. if (!isEncry) {
  228. encryPassword = getEncryPassword(Const.ENCRY_FORMAT, password, oldUser.getSalt());
  229. }
  230. // 校验密码
  231. if (!encryPassword.equals(oldUser.getPassword())) {
  232. throw new VisibleError("您输入的密码与已有账号的登录密码不一致,请重新输入。");
  233. }
  234. }
  235. @Override
  236. public UserRecord save(UserRecord userRecord) {
  237. return userRecordDao.save(userRecord);
  238. }
  239. @Override
  240. public User findOne(Long userUU) {
  241. return userDao.findOne(userUU);
  242. }
  243. @Override
  244. public boolean realNameIsValid(String realName) {
  245. User user = userDao.findByRealName(realName);
  246. if (user != null && user.getIdentityValidCode() == Status.AUTHENTICATED.getCode()) {
  247. return true;
  248. }
  249. return false;
  250. }
  251. @Override
  252. public boolean idCardIsValid(String idCard) {
  253. User user = userDao.findByIdCard(idCard);
  254. if (user != null && user.getIdentityValidCode() == Status.AUTHENTICATED.getCode()) {
  255. return true;
  256. }
  257. return false;
  258. }
  259. @Override
  260. public void submitIdValidInfo(User user) {
  261. // 校验企业名和营业执照是否被认证
  262. boolean isValid = idCardIsValid(user.getIdCard());
  263. if (isValid) {
  264. throw new VisibleError("该身份证号已被认证,请确认");
  265. }
  266. User oldUser = userDao.findByUserUU(user.getUserUU());
  267. oldUser.setIdentityValidCode((short) Status.TO_BE_CERTIFIED.getCode());
  268. oldUser.setRealName(user.getRealName());
  269. oldUser.setIdCard(user.getIdCard());
  270. this.save(oldUser);
  271. // 保存日志
  272. userValidService.submitValid(user);
  273. }
  274. @Override
  275. public void updateMobile(Long userUU, String newMobile) {
  276. // 参数空校验
  277. Assert.notNull(userUU, "userUU must not be null!");
  278. Assert.hasText(newMobile, "新手机号不能为空");
  279. // 获取用户信息
  280. User user = userDao.findOne(userUU);
  281. if (user == null) {
  282. throw new VisibleError("用户不存在");
  283. }
  284. // 判断手机号是否被注册
  285. if (!newMobile.equals(user.getMobile())) {
  286. User oldUser = userDao.findByMobile(newMobile);
  287. if (oldUser != null) {
  288. throw new VisibleError("该手机号已被注册");
  289. }
  290. }
  291. // 修改手机号
  292. user.setMobile(newMobile);
  293. user.setMobileValidCode((short) Status.AUTHENTICATED.getCode());
  294. // 保存用户信息
  295. user = userDao.save(user);
  296. // 保存日志
  297. userLogger.info(user, Type.UPDATE_MOBILE.getValue());
  298. // 同步到各个应用
  299. syncUserInfo(user, null, "修改手机号", null);
  300. }
  301. @Override
  302. public void updateEmail(Long userUU, String newEmail) {
  303. // 获取用户信息
  304. User user = userDao.findOne(userUU);
  305. if (user == null) {
  306. throw new VisibleError("用户不存在");
  307. }
  308. // 修改手机号
  309. user.setEmail(newEmail);
  310. user.setEmailValidCode((short) Status.AUTHENTICATED.getCode());
  311. // 保存用户信息
  312. user = userDao.save(user);
  313. // 保存日志
  314. userLogger.info(user, Type.UPDATE_EMAIL.getValue());
  315. // 同步信息到各应用
  316. syncUserInfo(user, null, "修改邮箱", null);
  317. }
  318. @Override
  319. public Page<User> findMemberBySpaceUU(int page, int size, final Long spaceUU) {
  320. Pageable pageable = PageInfo.pageRequest(new PageRequest(page, size));
  321. Page<User> pUsers = userDao.findAll(new Specification<User>() {
  322. @Override
  323. public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
  324. List<Predicate> list = new ArrayList<>();
  325. list.add(cb.equal(root.join("userSpaces", JoinType.INNER).get("spaceUU").as(Long.class), spaceUU));
  326. Predicate[] predicates = new Predicate[list.size()];
  327. predicates = list.toArray(predicates);
  328. return cb.and(predicates);
  329. }
  330. }, pageable);
  331. return new PageInfo<User>(pUsers.getContent(), pageable, pUsers.getTotalElements());
  332. }
  333. @Override
  334. public void bindUserspace(String appId, Long userUU, Long spaceUU) {
  335. if (StringUtils.isEmpty(userUU) || StringUtils.isEmpty(spaceUU)) {
  336. throw new VisibleError("参数错误");
  337. }
  338. // 找到用户和企业
  339. User user = findOne(userUU);
  340. Userspace userspace = userspaceService.findOne(spaceUU);
  341. // 将企业添加到用户列表上
  342. Set<Userspace> userspaces = user.getUserSpaces();
  343. userspaces.add(userspace);
  344. // 保存
  345. userDao.save(user);
  346. syncUserBindSpace(userUU, spaceUU);
  347. // 保存日志
  348. userLogger.info(user, Type.BIND_USERSPACE.getValue() + spaceUU);
  349. }
  350. /**
  351. * 同步用户绑定企业关系
  352. *
  353. * @param userUU 用户uu号
  354. * @param spaceUU 企业uu号
  355. */
  356. private void syncUserBindSpace(Long userUU, Long spaceUU) {
  357. syncRelation(userUU, spaceUU, "bind");
  358. }
  359. /**
  360. * 同步用户解除绑定企业关系
  361. *
  362. * @param userUU 用户uu号
  363. * @param spaceUU 企业uu号
  364. */
  365. private void syncUserUnbindSpace(Long userUU, Long spaceUU) {
  366. syncRelation(userUU, spaceUU, "unbind");
  367. }
  368. /**
  369. * 同步用户与企业的关系
  370. *
  371. * @param userUU 用户uu号
  372. * @param spaceUU 企业uu号
  373. * @param type 类型 (bind or unbind)
  374. */
  375. private void syncRelation(final Long userUU, final Long spaceUU, final String type) {
  376. Userspace userspace = userspaceService.findOne(spaceUU);
  377. List<App> apps = userspace.getApps();
  378. final ModelMap formData = new ModelMap();
  379. formData.put("userUU", userUU);
  380. formData.put("spaceUU", spaceUU);
  381. formData.put("type", type);
  382. for (final App app : apps) {
  383. executorService.execute(new Runnable() {
  384. @Override
  385. public void run() {
  386. String url = app.getBackRelationUrl();
  387. HttpUtil.ResponseWrap res = null;
  388. try {
  389. res = HttpUtil.doPost(url, formData, 10000);
  390. if (!res.isSuccess()) {
  391. SyncLog syncLog = syncLogger.error(app.getUid(), "同步绑定信息失败", JSON.toJSONString(formData), res.getContent());
  392. SyncFail.add(syncLog.getId(), formData, url, app.getUid());
  393. } else {
  394. syncLogger.info(app.getUid(), "同步绑定信息成功", JSON.toJSONString(formData));
  395. }
  396. } catch (Exception e) {
  397. syncLogger.error(app.getUid(), "同步绑定信息失败", JSON.toJSONString(formData), e.getMessage());
  398. }
  399. }
  400. });
  401. }
  402. }
  403. @Override
  404. public void unbindUserspace(Long userUU, Long spaceUU) {
  405. if (StringUtils.isEmpty(userUU) || StringUtils.isEmpty(spaceUU)) {
  406. throw new VisibleError("参数错误");
  407. }
  408. // 找到用户和企业
  409. User user = findOne(userUU);
  410. if (user == null) {
  411. throw new VisibleError("未找到用户信息");
  412. }
  413. Userspace userspace = userspaceService.findOne(spaceUU);
  414. if (userspace == null) {
  415. throw new VisibleError("未找到企业信息");
  416. }
  417. // 将企业添加到用户列表上
  418. Set<Userspace> userspaces = user.getUserSpaces();
  419. userspaces.remove(userspace);
  420. // 保存
  421. userDao.save(user);
  422. syncUserUnbindSpace(userUU, spaceUU);
  423. // 保存日志
  424. userLogger.info(user, Type.UNBIND_USERSPACE.getValue() + spaceUU);
  425. }
  426. @Override
  427. public void setQuestion(Long userUU, List<UserQuestion> questions) {
  428. // 找到用户密保
  429. User user = userDao.findOne(userUU);
  430. List<UserQuestion> userQuestions = user.getQuestions();
  431. // 清空旧的并添加新的
  432. if (CollectionUtils.isEmpty(userQuestions)) {
  433. user.setQuestions(questions);
  434. } else {
  435. for (int i = 0; i < questions.size(); i++) {
  436. if (userQuestions.get(i) == null) {
  437. user.getQuestions().add(questions.get(i));
  438. } else {
  439. userQuestions.get(i).setQuestion(questions.get(i).getQuestion());
  440. userQuestions.get(i).setAnswer(questions.get(i).getAnswer());
  441. userQuestions.get(i).setSort(questions.get(i).getSort());
  442. }
  443. }
  444. }
  445. // 保存并添加日志
  446. user = userDao.save(user);
  447. syncUserInfo(user, null, "修改密保", null);
  448. userLogger.info(user, Type.UPDATE_QUESTION.getValue(), JSON.toJSONString(user.getQuestions()));
  449. }
  450. @Override
  451. public List<String> findRepeatEmail() {
  452. return userDao.findRepeatEmail();
  453. }
  454. @Override
  455. public List<User> findByEmail(String email) {
  456. return userDao.findByEmail(email);
  457. }
  458. @Override
  459. public User updatePassword(Long userUU, String noEncryPwd) {
  460. User user = userDao.findOne(userUU);
  461. if (user == null) {
  462. throw new VisibleError("该用户不存在");
  463. }
  464. user.setPassword(getEncryPassword(Const.ENCRY_FORMAT, noEncryPwd, user.getSalt()));
  465. user.setPasswordLevel(PasswordLevelUtils.checkPasswordLevel(noEncryPwd).getValue());
  466. user = syncUserInfo(user, noEncryPwd, "用户修改密码", null);
  467. return userDao.save(user);
  468. }
  469. @Override
  470. public List<UserSpaceDetailInfo> findUserByTels(List<String> tels) {
  471. // 获取用户列表
  472. List<User> users = userDao.findUsersByTels(tels);
  473. if (CollectionUtils.isEmpty(users)) {
  474. return null;
  475. }
  476. List<UserSpaceDetailInfo> data = new ArrayList<>(users.size());
  477. UserSpaceDetailInfo info;
  478. // 遍历用户列表取数据
  479. for (User user : users) {
  480. info = new UserSpaceDetailInfo();
  481. Set<Userspace> spaces = user.getUserSpaces();
  482. if (!CollectionUtils.isEmpty(spaces)) {
  483. // 有企业的话随便取一个,uu互联需求
  484. Iterator<Userspace> iterator = spaces.iterator();
  485. Userspace userspace = iterator.next();
  486. info.setAddress(userspace.getRegAddress());
  487. info.setCompany(userspace.getSpaceName());
  488. }
  489. info.setEmail(user.getEmail());
  490. info.setImid(user.getImId());
  491. info.setUsertel(user.getMobile());
  492. info.setUsername(user.getVipName());
  493. data.add(info);
  494. }
  495. return data;
  496. }
  497. @Override
  498. public void resetErrorCount(Long userUU) {
  499. UserRecord userRecord = userRecordDao.findOne(userUU);
  500. if (userRecord == null) {
  501. userRecord = new UserRecord(userUU);
  502. }
  503. userRecord.setPwdErrorCount(0);
  504. userRecordDao.save(userRecord);
  505. }
  506. @Override
  507. public User updateUser(@NotNull Long userUU, User newUser) {
  508. User oldUser = userDao.findOne(userUU);
  509. if (oldUser == null) {
  510. throw new VisibleError("未找到用户信息");
  511. }
  512. // 修改手机号
  513. if (!StringUtils.isEmpty(newUser.getMobile()) && !newUser.getMobile().equals(oldUser.getMobile())) {
  514. if (mobileHasRegistered(newUser.getMobile())) {
  515. throw new VisibleError("手机号已被注册");
  516. }
  517. if (!newUser.getMobile().matches(Const.REGEXP_MOBILE_CONTINENT)) {
  518. throw new VisibleError("请输入正确的手机号");
  519. }
  520. oldUser.setMobile(newUser.getMobile());
  521. oldUser.setMobileValidCode((short) Status.NOT_APPLYING.getCode());
  522. }
  523. // 修改邮箱
  524. if (!StringUtils.isEmpty(newUser.getEmail()) && !newUser.getEmail().equals(oldUser.getEmail())) {
  525. if (emailHasRegistered(newUser.getEmail())) {
  526. throw new VisibleError("邮箱已被注册");
  527. }
  528. if (!newUser.getEmail().matches(Const.REGEXP_EMAIL)) {
  529. throw new VisibleError("请输入正确的邮箱");
  530. }
  531. oldUser.setEmail(newUser.getEmail());
  532. oldUser.setEmailValidCode((short) Status.NOT_APPLYING.getCode());
  533. }
  534. // 修改用户名
  535. if (!StringUtils.isEmpty(newUser.getVipName())) {
  536. oldUser.setVipName(newUser.getVipName());
  537. }
  538. // 保存用户信息
  539. oldUser = userDao.save(oldUser);
  540. oldUser = syncUserInfo(oldUser, null, "(接口调用)修改用户信息", null);
  541. return oldUser;
  542. }
  543. @Override
  544. public long count() {
  545. return userDao.count();
  546. }
  547. @Override
  548. public Long countByLogin(String start, String end) throws ParseException {
  549. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
  550. Date startTime = simpleDateFormat.parse(start);
  551. Date endTime = simpleDateFormat.parse(end);
  552. Calendar starttime = Calendar.getInstance();
  553. starttime.setTime(startTime);
  554. Calendar endtime = Calendar.getInstance();
  555. endtime.setTime(endTime);
  556. return userRecordDao.getCountByLogin(new Timestamp(starttime.getTimeInMillis()),new Timestamp(endtime.getTimeInMillis()));
  557. }
  558. @Override
  559. public Long countByLoginInputMonth(String startTime,String endTime, int month) throws ParseException {
  560. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
  561. Date startToDate = simpleDateFormat.parse(startTime);
  562. Date endToDate = simpleDateFormat.parse(endTime);
  563. Calendar start = Calendar.getInstance();
  564. start.setTime(startToDate);
  565. start.add(Calendar.MONTH, -month);
  566. Calendar end = Calendar.getInstance();
  567. end.setTime(endToDate);
  568. end.add(Calendar.MONTH, -month);
  569. System.out.println(new Timestamp(start.getTimeInMillis()));
  570. System.out.println(new Timestamp(end.getTimeInMillis()));
  571. return userRecordDao.getCountByLogin(new Timestamp(start.getTimeInMillis()),new Timestamp(end.getTimeInMillis()));
  572. }
  573. @Override
  574. public Long getMaxUUInLastWeek() {
  575. Calendar start = Calendar.getInstance();
  576. start.set(Calendar.HOUR_OF_DAY, 0);
  577. start.set(Calendar.MINUTE, 0);
  578. start.set(Calendar.SECOND, 0);
  579. start.set(Calendar.MILLISECOND, 0);
  580. int dayofweek = start.get(Calendar.DAY_OF_WEEK);
  581. if (dayofweek == 1) {
  582. dayofweek += 7;
  583. }
  584. start.add(Calendar.DATE, 2 - dayofweek);
  585. return userDao.findMaxUUBefore(start.getTime());
  586. }
  587. @Override
  588. public long countByRegisterDate(final Calendar start, final Calendar end) {
  589. return userDao.count(new Specification<User>() {
  590. @Override
  591. public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
  592. Predicate predicate = cb.between(root.get("registerDate").as(Calendar.class), start, end);
  593. query.where(predicate);
  594. return null;
  595. }
  596. });
  597. }
  598. @Override
  599. public Map<String, Long> countByRegisterDate(Timestamp start, Timestamp end, List<String> fromApps) {
  600. Map<String, Long> data = new HashMap<>();
  601. List<Map<String, Object>> counts = userDao.getCountByRegisterDate(start, end, fromApps);
  602. for (Map<String, Object> count : counts) {
  603. data.put((String) count.get("appId"), (Long) count.get("count"));
  604. fromApps.remove(count.get("appId"));
  605. }
  606. for(String fromApp: fromApps){
  607. data.put(fromApp, 0L);
  608. }
  609. return data;
  610. }
  611. @Override
  612. public long countInCurrentMonth() {
  613. return CountUtils.countInCurrentMonth(new CountCallBack<Long>() {
  614. @Override
  615. public Long countByTime(Calendar start, Calendar end) {
  616. return countByRegisterDate(start, end);
  617. }
  618. });
  619. }
  620. @Override
  621. public long countInLastMonth() {
  622. return CountUtils.countInLastMonth(new CountCallBack<Long>() {
  623. @Override
  624. public Long countByTime(Calendar start, Calendar end) {
  625. return countByRegisterDate(start, end);
  626. }
  627. });
  628. }
  629. @Override
  630. public long countInCurrentWeek() {
  631. return CountUtils.countInCurrentWeek(new CountCallBack<Long>() {
  632. @Override
  633. public Long countByTime(Calendar start, Calendar end) {
  634. return countByRegisterDate(start, end);
  635. }
  636. });
  637. }
  638. @Override
  639. public Map<String, Long> count(final List<String> fromApps) {
  640. Map<String, Long> data = new HashMap<>();
  641. List<Map<String, Object>> counts = userDao.getCountByRegisterDate(fromApps);
  642. for (Map<String, Object> count : counts) {
  643. data.put((String) count.get("appId"), (Long) count.get("count"));
  644. }
  645. return data;
  646. }
  647. @Override
  648. public Map<String, Long> countInCurrentMonth(final List<String> fromApps) {
  649. return CountUtils.countInCurrentMonth(new CountCallBack<Map<String, Long>>() {
  650. @Override
  651. public Map<String, Long> countByTime(Calendar start, Calendar end) {
  652. return countByRegisterDate(new Timestamp(start.getTimeInMillis()), new Timestamp(end.getTimeInMillis()), fromApps);
  653. }
  654. });
  655. }
  656. @Override
  657. public Map<String, Long> countInCurrentWeek(final List<String> fromApps) {
  658. return CountUtils.countInCurrentWeek(new CountCallBack<Map<String, Long>>() {
  659. @Override
  660. public Map<String, Long> countByTime(Calendar start, Calendar end) {
  661. return countByRegisterDate(new Timestamp(start.getTimeInMillis()), new Timestamp(end.getTimeInMillis()), fromApps);
  662. }
  663. });
  664. }
  665. @Override
  666. public Map<String, Long> countInToday(List<String> fromApps) {
  667. return CountUtils.countInToday(new CountCallBack<Map<String, Long>>() {
  668. @Override
  669. public Map<String, Long> countByTime(Calendar start, Calendar end) {
  670. return countByRegisterDate(new Timestamp(start.getTimeInMillis()), new Timestamp(end.getTimeInMillis()), fromApps);
  671. }
  672. });
  673. }
  674. @Override
  675. public Map<String, Long> countInYesterday(List<String> fromApps) {
  676. return CountUtils.countInYesterday(new CountCallBack<Map<String, Long>>() {
  677. @Override
  678. public Map<String, Long> countByTime(Calendar start, Calendar end) {
  679. return countByRegisterDate(new Timestamp(start.getTimeInMillis()), new Timestamp(end.getTimeInMillis()), fromApps);
  680. }
  681. });
  682. }
  683. @Override
  684. public Map<String, Long> countgInLastMonth(List<String> fromApps) {
  685. return CountUtils.countInLastMonth(new CountCallBack<Map<String, Long>>() {
  686. @Override
  687. public Map<String, Long> countByTime(Calendar start, Calendar end) {
  688. return countByRegisterDate(new Timestamp(start.getTimeInMillis()), new Timestamp(end.getTimeInMillis()), fromApps);
  689. }
  690. });
  691. }
  692. @Override
  693. public Map<String, Long> countInInputTime(String startTime, String endTime, List<String> fromApps) throws ParseException {
  694. CountCallBack<Map<String, Long>> countCallBack = new CountCallBack<Map<String, Long>>() {
  695. @Override
  696. public Map<String, Long> countByTime(Calendar start, Calendar end) {
  697. return countByRegisterDate(new Timestamp(start.getTimeInMillis()),new Timestamp(end.getTimeInMillis()),fromApps);
  698. }
  699. };
  700. return CountUtils.countInInputTime(countCallBack,startTime,endTime);
  701. }
  702. @Override
  703. public User findByWxUnionid(String unionid) {
  704. return userDao.findByWxUnionid(unionid);
  705. }
  706. @Override
  707. public User findByBhOpenId(String openId) {
  708. return userDao.findByBhOpenId(openId);
  709. }
  710. @Override
  711. public User bindUnionId(String username, String password, String unionid) {
  712. Assert.hasText(username, "用户名不能为空");
  713. Assert.hasText(password, "密码不能为空");
  714. User user = findByUsername(username);
  715. if (user == null) {
  716. throw new IllegalArgumentException("该用户不存在");
  717. }
  718. checkPassword(user.getUserUU(), password, false);
  719. user.setWxUnionid(unionid);
  720. userDao.save(user);
  721. userLogger.info(user, Type.BIND_WEIXIN.getValue());
  722. return user;
  723. }
  724. @Override
  725. public User bindBhOpenId(String username, String password, String openId) {
  726. Assert.hasText(username, "用户名不能为空");
  727. Assert.hasText(password, "密码不能为空");
  728. User user = findByUsername(username);
  729. if (user == null) {
  730. throw new IllegalArgumentException("该用户不存在");
  731. }
  732. checkPassword(user.getUserUU(), password, false);
  733. user.setBhOpenId(openId);
  734. userDao.save(user);
  735. userLogger.info(user, Type.BIND_BIHE.getValue());
  736. return user;
  737. }
  738. @Override
  739. public User findByForeignId(ForeignInfo foreignInfo) {
  740. User user = null;
  741. if (foreignInfo instanceof OAuthInfo) {
  742. user = userDao.findByWxUnionid(foreignInfo.getForeignOpenId());
  743. } else if (foreignInfo instanceof BiHeInfo) {
  744. user = userDao.findByBhOpenId(foreignInfo.getForeignOpenId());
  745. }
  746. return user;
  747. }
  748. @Override
  749. public User bindForeignOpenId(String username, String password, ForeignInfo foreignInfo) {
  750. // 校验空参数
  751. try {
  752. Assert.hasText(username, "用户名不能为空");
  753. Assert.hasText(password, "密码不能为空");
  754. } catch (IllegalArgumentException e) {
  755. throw new VisibleError(e.getMessage());
  756. }
  757. // 校验用户名密码是否正确
  758. User user = findByUsername(username);
  759. if (user == null) {
  760. throw new VisibleError("该用户不存在");
  761. }
  762. checkPassword(user.getUserUU(), password, false);
  763. // 设置第三方openId
  764. setForeignOpenId(user, foreignInfo);
  765. userDao.save(user);
  766. userLogger.info(user, Type.BIND_FOREIGN.getValue());
  767. return user;
  768. }
  769. @Override
  770. public User bindForeignOpenId(String code, String mobile, String codeToken, ForeignInfo foreignInfo) {
  771. // 校验空参数
  772. try {
  773. Assert.hasText(code, "验证码不能为空");
  774. Assert.hasText(mobile, "手机号不能为空");
  775. Assert.hasText(codeToken, "token不能为空");
  776. } catch (IllegalArgumentException e) {
  777. throw new VisibleError(e.getMessage());
  778. }
  779. // 校验验证码是否正确
  780. Token existToken = tokenService.findOne(codeToken);
  781. if (existToken == null || existToken.isExpired()) {
  782. throw new VisibleError("验证码过期");
  783. }
  784. if (!mobile.equals(existToken.getMobile())) {
  785. throw new VisibleError("手机号已被修改,请重新获取验证码");
  786. }
  787. if (!code.equals(existToken.getBind())) {
  788. throw new VisibleError("验证码不正确,请重新输入");
  789. }
  790. // 设置第三方openId
  791. User user = userDao.findByMobile(mobile);
  792. if (user == null) {
  793. throw new VisibleError("该用户不存在");
  794. }
  795. setForeignOpenId(user, foreignInfo);
  796. userDao.save(user);
  797. userLogger.info(user, Type.BIND_FOREIGN.getValue());
  798. return user;
  799. }
  800. /**
  801. * 设置用户第三方openId,不同应用对应不同字段
  802. *
  803. * @param user 用户信息
  804. * @param foreignInfo
  805. * @return
  806. */
  807. @Override
  808. public User setForeignOpenId(User user, ForeignInfo foreignInfo) {
  809. if (user == null) {
  810. return null;
  811. }
  812. if (foreignInfo instanceof OAuthInfo) {
  813. user.setWxUnionid(foreignInfo.getForeignOpenId());
  814. } else if (foreignInfo instanceof BiHeInfo) {
  815. user.setBhOpenId(foreignInfo.getForeignOpenId());
  816. }
  817. return user;
  818. }
  819. @Override
  820. public User findByImId(String imId) {
  821. return userDao.findByImId(imId);
  822. }
  823. /**
  824. * 同步用户信息到各个应用
  825. *
  826. * @param user 用户信息
  827. * @param noEncryPwd 未加密密码,用于同步im
  828. * @param msg 同步信息描述,用户区分同步类型
  829. */
  830. private User syncUserInfo(User user, String noEncryPwd, final String msg, App otherApp) {
  831. List<App> apps = appService.findDefaultUseApp();
  832. if (otherApp != null && !apps.contains(otherApp)) {
  833. apps.add(otherApp);
  834. }
  835. try {
  836. // 其他应用可能会用到IMID,要先同步到im之后再同步到其他应用
  837. String imId = syncUserToIm(user, noEncryPwd, msg);
  838. user.setImId(imId);
  839. user = userDao.save(user);
  840. } catch (Exception e) {
  841. e.printStackTrace();
  842. }
  843. // 封装同步其他应用数据并同步
  844. boolean hasQuestion = !CollectionUtils.isEmpty(user.getQuestions());
  845. JSONObject formData = JSON.parseObject(JSON.toJSONString(user));
  846. formData.put("password", user.getPassword());
  847. formData.put("hasQuestion", hasQuestion);
  848. syncUserInfo(formData, msg, apps);
  849. return user;
  850. }
  851. private String syncUserToIm(User user, String noEncryPwd, String msg) throws Exception {
  852. String appId = "im";
  853. App app = appService.findOne(appId);
  854. if (StringUtils.isEmpty(app.getBackUserUrl())) {
  855. return null;
  856. }
  857. // 封装数据同步到im
  858. String url = app.getBackUserUrl();
  859. HttpUtil.ResponseWrap res = null;
  860. ModelMap formData = new ModelMap();
  861. formData.put("dialectUID", user.getImId());
  862. formData.put("realName", StringUtils.isEmpty(user.getRealName()) ? user.getVipName() : user.getRealName());
  863. formData.put("password", noEncryPwd);
  864. formData.put("email", StringUtils.isEmpty(user.getEmail()) ? "0" : user.getEmail());
  865. formData.put("mobile", user.getMobile());
  866. res = HttpUtil.doPost(url, formData, 10000);
  867. if (!res.isSuccess()) {
  868. syncLogger.error(appId, msg + ",同步用户信息失败", formData.toString(), res.getContent());
  869. throw new Exception(res.getContent());
  870. } else {
  871. JSONObject obj = JSON.parseObject(res.getContent());
  872. if (obj.getString("resultMsg") != null) {
  873. syncLogger.error(appId, msg + ",同步用户信息失败", formData.toString(), res.getContent());
  874. }
  875. syncLogger.info(appId, msg + ",同步用户信息成功", formData.toString(), res.getContent());
  876. return obj.getString("dialectUID");
  877. }
  878. }
  879. /**
  880. * 同步信息到指定应用
  881. *
  882. * @param formData 同步数据
  883. * @param msg 同步信息
  884. * @param apps 需要同步的应用
  885. */
  886. private void syncUserInfo(final Map<String, Object> formData, final String msg, List<App> apps) {
  887. for (final App app : apps) {
  888. executorService.execute(new Runnable() {
  889. @Override
  890. public void run() {
  891. String url = app.getBackUserUrl();
  892. if (StringUtils.isEmpty(url)) {
  893. return;
  894. }
  895. HttpUtil.ResponseWrap res;
  896. try {
  897. res = HttpUtil.doPost(url, formData, 10000);
  898. if (!res.isSuccess()) {
  899. SyncLog syncLog = syncLogger.error(app.getUid(), msg + ",同步用户信息失败", JSON.toJSONString(formData), res.getContent());
  900. SyncFail.add(syncLog.getId(), formData, url, app.getUid());
  901. } else {
  902. syncLogger.info(app.getUid(), msg + ",同步用户信息成功", JSON.toJSONString(formData));
  903. }
  904. } catch (Exception e) {
  905. syncLogger.error(app.getUid(), msg + ",同步用户信息失败", JSON.toJSONString(formData), e.getMessage());
  906. }
  907. }
  908. });
  909. }
  910. }
  911. @Override
  912. public long countByNotLogin(int month) {
  913. return CountUtils.countBeforeInputMonth(new CountCallBack<Long>() {
  914. @Override
  915. public Long countByTime(Calendar start, Calendar end) {
  916. return countBeforeTime(end);
  917. }
  918. }, month);
  919. }
  920. private long countBeforeTime(Calendar end) {
  921. return userRecordDao.count((root, query, cb) -> {
  922. Predicate lessPredicate = cb.lessThan(root.get("lastLoginTime").as(Calendar.class), end);
  923. Predicate nullPredicate = cb.isNull(root.get("lastLoginTime"));
  924. query.where(cb.or(lessPredicate, nullPredicate));
  925. return null;
  926. });
  927. }
  928. }