UserServiceImpl.java 39 KB

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