package com.uas.sso.service.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.uas.sso.common.encrypt.MD5; import com.uas.sso.common.util.HttpUtil; import com.uas.sso.core.Const; import com.uas.sso.core.Status; import com.uas.sso.core.Type; import com.uas.sso.dao.UserDao; import com.uas.sso.dao.UserRecordDao; import com.uas.sso.entity.*; import com.uas.sso.exception.VisibleError; import com.uas.sso.foreign.entity.ForeignInfo; import com.uas.sso.foreign.bihe.entity.BiHeInfo; import com.uas.sso.foreign.weixin.entity.OAuthInfo; import com.uas.sso.i.CountCallBack; import com.uas.sso.logging.LoggerManager; import com.uas.sso.logging.SyncBufferedLogger; import com.uas.sso.logging.UserBufferedLogger; import com.uas.sso.service.*; import com.uas.sso.support.SyncFail; import com.uas.sso.util.AccountTypeUtils; import com.uas.sso.util.CountUtils; import com.uas.sso.util.PasswordLevelUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import org.springframework.ui.ModelMap; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import javax.persistence.criteria.*; import javax.validation.constraints.NotNull; import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.ExecutorService; /** * 用户service实现类 * * @author wangmh * @date 2018/1/2 */ @Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Autowired private UserRecordDao userRecordDao; @Autowired private UserValidService userValidService; @Autowired private UserspaceService userspaceService; @Autowired private AppService appService; @Autowired private ExecutorService executorService; @Autowired private UserQuestionService userQuestionService; @Autowired private TokenService tokenService; private UserBufferedLogger userLogger = LoggerManager.getLogger(UserBufferedLogger.class); private SyncBufferedLogger syncLogger = LoggerManager.getLogger(SyncBufferedLogger.class); @Override public User findByMobile(String mobile, String mobileArea) { return userDao.findByMobileAndMobileArea(mobile, mobileArea); } @Override public User findByMobile(String mobile) { return userDao.findByMobile(mobile); } @Override public boolean mobileHasRegistered(String mobile) { User user = userDao.findByMobile(mobile); if (user == null) { return false; } return true; } @Override public boolean emailHasRegistered(String email) { List users = userDao.findByEmail(email); if (CollectionUtils.isEmpty(users)) { return false; } return true; } @Override public synchronized User register(User user, String appId) { String noEncryPwd = user.getPassword(); // 校验手机号是否被注册 if (mobileHasRegistered(user.getMobile())) { throw new VisibleError("该手机号已被注册"); } // 由于现在不考虑手机号所属区域,默认为中国大陆 if (StringUtils.isEmpty(user.getMobileArea())) { user.setMobileArea(Const.CONTINENT); } if (user.getMobile() == null || !user.getMobile().matches(Const.REGEXP_MOBILE_CONTINENT)) { throw new VisibleError("请填写正确的手机号"); } // 设置基本属性,手机号默认已认证 user.setRegisterDate(new Timestamp(System.currentTimeMillis())); Long uu = userDao.findMaxUU(); user.setUserUU(uu == null ? 1000060000L : (uu + 1)); user.setSalt(String.valueOf(user.getUserUU())); user.setMobileValidCode((short) Status.AUTHENTICATED.getCode()); user.setEmailValidCode((short) Status.NOT_APPLYING.getCode()); user.setIdentityValidCode((short) Status.NOT_APPLYING.getCode()); user.setPassword(getEncryPassword(Const.ENCRY_FORMAT, user.getPassword(), user.getSalt())); user.setFromApp(appId); user = userDao.save(user); UserRecord userRecord = new UserRecord(user.getUserUU()); userRecordDao.save(userRecord); userLogger.info(user, Type.UPDATE_REGISTER.getValue()); // 同步到各个应用 App app = appService.findOne(appId); return syncUserInfo(user, noEncryPwd, "个人注册", app); } @Override public String getEncryPassword(String format, String noEncryPwd, String salt) { if (StringUtils.isEmpty(format)) { return noEncryPwd; } // 超过32认为是已加密过的密文 if (noEncryPwd.length() >= 32) { /// 之后添加日志时恢复 //logger.error("用户密码加密", String.format("传递过来的密码(%s)必须是未加密的明文", noEncryPwd)); throw new VisibleError("密码过长,请重新输入"); } // $password{$salt} String password = format.replace(Const.ENCRY_PARAM_PASSWORD, noEncryPwd); password = password.replace(Const.ENCRY_PARAM_SALT, salt == null ? "" : salt); return MD5.toMD5(password); } @Override public User save(User user) { user = userDao.save(user); return syncUserInfo(user, null, "修改用户信息", null); } @Override public void checkPassword(Long userUU, String password, boolean isEncry) { // 根据用户uu号找到旧数据 User oldUser = userDao.findByUserUU(userUU); if (oldUser == null) { throw new VisibleError("用户名或密码错误"); } // 校验密码 checkPassword(oldUser, password, isEncry); } @Override public void checkPasswordByMobile(String mobile, String password, boolean isEncry) { // 找到用户 User oldUser = userDao.findByMobile(mobile); if (oldUser == null) { throw new VisibleError("用户名或密码错误"); } // 校验密码 checkPassword(oldUser, password, isEncry); } @Override public void checkPasswordByEmail(String email, String password, boolean isEncry) { // 找到用户 List oldUsers = userDao.findByEmailAndEmailValidCode(email, (short) Status.AUTHENTICATED.getCode()); if (CollectionUtils.isEmpty(oldUsers)) { throw new VisibleError("该邮箱未认证,请使用手机号登录"); } // 校验密码 for (User oldUser : oldUsers) { checkPassword(oldUser, password, isEncry); } } @Override public boolean checkPasswordByUsername(String username, String password, boolean isEncry) { Assert.hasText(username, "用户名不能为空"); Assert.hasText(password, "密码不能为空"); User user = findByUsername(username); checkPassword(user, password, isEncry); return true; } @Override public int getPwdErrorCount(String username) { User user = findByUsername(username); if (user == null) { throw new VisibleError("用户名不存在"); } UserRecord userRecord = userRecordDao.findOne(user.getUserUU()); if (userRecord == null) { return 0; } return userRecord.getPwdErrorCount(); } @Override public User findByUsername(String username) { String type = AccountTypeUtils.getAccountType(username); User user = null; if (AccountTypeUtils.MOBILE.equals(type)) { // 手机号 user = userDao.findByMobile(username); } else if (AccountTypeUtils.EMAIL.equals(type)) { // 邮箱 List users = userDao.findByEmailAndEmailValidCode(username, (short) Status.AUTHENTICATED.getCode()); // 认证邮箱只有一条记录,直接选择第一个 if (!CollectionUtils.isEmpty(users)) { user = users.get(0); } } else if (AccountTypeUtils.UU_NUMBER.equals(type)) { // uu号 user = userDao.findByUserUU(Long.valueOf(username)); } return user; } /** * 校验用户密码 * * @param oldUser 用户信息 * @param password 需要校验的密码 * @param isEncry 需校验的密码是否被加密 */ private void checkPassword(User oldUser, String password, boolean isEncry) { // 密码未加密,转换成加密后的密码 String encryPassword = password; if (!isEncry) { encryPassword = getEncryPassword(Const.ENCRY_FORMAT, password, oldUser.getSalt()); } // 校验密码 if (!encryPassword.equals(oldUser.getPassword())) { throw new VisibleError("您输入的密码与已有账号的登录密码不一致,请重新输入。"); } } @Override public UserRecord save(UserRecord userRecord) { return userRecordDao.save(userRecord); } @Override public User findOne(Long userUU) { return userDao.findOne(userUU); } @Override public boolean realNameIsValid(String realName) { User user = userDao.findByRealName(realName); if (user != null && user.getIdentityValidCode() == Status.AUTHENTICATED.getCode()) { return true; } return false; } @Override public boolean idCardIsValid(String idCard) { User user = userDao.findByIdCard(idCard); if (user != null && user.getIdentityValidCode() == Status.AUTHENTICATED.getCode()) { return true; } return false; } @Override public void submitIdValidInfo(User user) { // 校验企业名和营业执照是否被认证 boolean isValid = idCardIsValid(user.getIdCard()); if (isValid) { throw new VisibleError("该身份证号已被认证,请确认"); } User oldUser = userDao.findByUserUU(user.getUserUU()); oldUser.setIdentityValidCode((short) Status.TO_BE_CERTIFIED.getCode()); oldUser.setRealName(user.getRealName()); oldUser.setIdCard(user.getIdCard()); this.save(oldUser); // 保存日志 userValidService.submitValid(user); } @Override public void updateMobile(Long userUU, String newMobile) { // 参数空校验 Assert.notNull(userUU, "userUU must not be null!"); Assert.hasText(newMobile, "新手机号不能为空"); // 获取用户信息 User user = userDao.findOne(userUU); if (user == null) { throw new VisibleError("用户不存在"); } // 判断手机号是否被注册 if (!newMobile.equals(user.getMobile())) { User oldUser = userDao.findByMobile(newMobile); if (oldUser != null) { throw new VisibleError("该手机号已被注册"); } } // 修改手机号 user.setMobile(newMobile); user.setMobileValidCode((short) Status.AUTHENTICATED.getCode()); // 保存用户信息 user = userDao.save(user); // 保存日志 userLogger.info(user, Type.UPDATE_MOBILE.getValue()); // 同步到各个应用 syncUserInfo(user, null, "修改手机号", null); } @Override public void updateEmail(Long userUU, String newEmail) { // 获取用户信息 User user = userDao.findOne(userUU); if (user == null) { throw new VisibleError("用户不存在"); } // 修改手机号 user.setEmail(newEmail); user.setEmailValidCode((short) Status.AUTHENTICATED.getCode()); // 保存用户信息 user = userDao.save(user); // 保存日志 userLogger.info(user, Type.UPDATE_EMAIL.getValue()); // 同步信息到各应用 syncUserInfo(user, null, "修改邮箱", null); } @Override public Page findMemberBySpaceUU(int page, int size, final Long spaceUU) { Pageable pageable = PageInfo.pageRequest(new PageRequest(page, size)); Page pUsers = userDao.findAll(new Specification() { @Override public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) { List list = new ArrayList<>(); list.add(cb.equal(root.join("userSpaces", JoinType.INNER).get("spaceUU").as(Long.class), spaceUU)); Predicate[] predicates = new Predicate[list.size()]; predicates = list.toArray(predicates); return cb.and(predicates); } }, pageable); return new PageInfo(pUsers.getContent(), pageable, pUsers.getTotalElements()); } @Override public void bindUserspace(String appId, Long userUU, Long spaceUU) { if (StringUtils.isEmpty(userUU) || StringUtils.isEmpty(spaceUU)) { throw new VisibleError("参数错误"); } // 找到用户和企业 User user = findOne(userUU); Userspace userspace = userspaceService.findOne(spaceUU); // 将企业添加到用户列表上 Set userspaces = user.getUserSpaces(); userspaces.add(userspace); // 保存 userDao.save(user); syncUserBindSpace(userUU, spaceUU); // 保存日志 userLogger.info(user, Type.BIND_USERSPACE.getValue() + spaceUU); } /** * 同步用户绑定企业关系 * * @param userUU 用户uu号 * @param spaceUU 企业uu号 */ private void syncUserBindSpace(Long userUU, Long spaceUU) { syncRelation(userUU, spaceUU, "bind"); } /** * 同步用户解除绑定企业关系 * * @param userUU 用户uu号 * @param spaceUU 企业uu号 */ private void syncUserUnbindSpace(Long userUU, Long spaceUU) { syncRelation(userUU, spaceUU, "unbind"); } /** * 同步用户与企业的关系 * * @param userUU 用户uu号 * @param spaceUU 企业uu号 * @param type 类型 (bind or unbind) */ private void syncRelation(final Long userUU, final Long spaceUU, final String type) { Userspace userspace = userspaceService.findOne(spaceUU); List apps = userspace.getApps(); final ModelMap formData = new ModelMap(); formData.put("userUU", userUU); formData.put("spaceUU", spaceUU); formData.put("type", type); for (final App app : apps) { executorService.execute(new Runnable() { @Override public void run() { String url = app.getBackRelationUrl(); HttpUtil.ResponseWrap res = null; try { res = HttpUtil.doPost(url, formData, 10000); if (!res.isSuccess()) { SyncLog syncLog = syncLogger.error(app.getUid(), "同步绑定信息失败", JSON.toJSONString(formData), res.getContent()); SyncFail.add(syncLog.getId(), formData, url, app.getUid()); } else { syncLogger.info(app.getUid(), "同步绑定信息成功", JSON.toJSONString(formData)); } } catch (Exception e) { syncLogger.error(app.getUid(), "同步绑定信息失败", JSON.toJSONString(formData), e.getMessage()); } } }); } } @Override public void unbindUserspace(Long userUU, Long spaceUU) { if (StringUtils.isEmpty(userUU) || StringUtils.isEmpty(spaceUU)) { throw new VisibleError("参数错误"); } // 找到用户和企业 User user = findOne(userUU); if (user == null) { throw new VisibleError("未找到用户信息"); } Userspace userspace = userspaceService.findOne(spaceUU); if (userspace == null) { throw new VisibleError("未找到企业信息"); } // 将企业添加到用户列表上 Set userspaces = user.getUserSpaces(); userspaces.remove(userspace); // 保存 userDao.save(user); syncUserUnbindSpace(userUU, spaceUU); // 保存日志 userLogger.info(user, Type.UNBIND_USERSPACE.getValue() + spaceUU); } @Override public void setQuestion(Long userUU, List questions) { // 找到用户密保 User user = userDao.findOne(userUU); List userQuestions = user.getQuestions(); // 清空旧的并添加新的 if (CollectionUtils.isEmpty(userQuestions)) { user.setQuestions(questions); } else { for (int i = 0; i < questions.size(); i++) { if (userQuestions.get(i) == null) { user.getQuestions().add(questions.get(i)); } else { userQuestions.get(i).setQuestion(questions.get(i).getQuestion()); userQuestions.get(i).setAnswer(questions.get(i).getAnswer()); userQuestions.get(i).setSort(questions.get(i).getSort()); } } } // 保存并添加日志 user = userDao.save(user); syncUserInfo(user, null, "修改密保", null); userLogger.info(user, Type.UPDATE_QUESTION.getValue(), JSON.toJSONString(user.getQuestions())); } @Override public List findRepeatEmail() { return userDao.findRepeatEmail(); } @Override public List findByEmail(String email) { return userDao.findByEmail(email); } @Override public User updatePassword(Long userUU, String noEncryPwd) { User user = userDao.findOne(userUU); if (user == null) { throw new VisibleError("该用户不存在"); } user.setPassword(getEncryPassword(Const.ENCRY_FORMAT, noEncryPwd, user.getSalt())); user.setPasswordLevel(PasswordLevelUtils.checkPasswordLevel(noEncryPwd).getValue()); user = syncUserInfo(user, noEncryPwd, "用户修改密码", null); return userDao.save(user); } @Override public List findUserByTels(List tels) { // 获取用户列表 List users = userDao.findUsersByTels(tels); if (CollectionUtils.isEmpty(users)) { return null; } List data = new ArrayList<>(users.size()); UserSpaceDetailInfo info; // 遍历用户列表取数据 for (User user : users) { info = new UserSpaceDetailInfo(); Set spaces = user.getUserSpaces(); if (!CollectionUtils.isEmpty(spaces)) { // 有企业的话随便取一个,uu互联需求 Iterator iterator = spaces.iterator(); Userspace userspace = iterator.next(); info.setAddress(userspace.getRegAddress()); info.setCompany(userspace.getSpaceName()); } info.setEmail(user.getEmail()); info.setImid(user.getImId()); info.setUsertel(user.getMobile()); info.setUsername(user.getVipName()); data.add(info); } return data; } @Override public void resetErrorCount(Long userUU) { UserRecord userRecord = userRecordDao.findOne(userUU); if (userRecord == null) { userRecord = new UserRecord(userUU); } userRecord.setPwdErrorCount(0); userRecordDao.save(userRecord); } @Override public User updateUser(@NotNull Long userUU, User newUser) { User oldUser = userDao.findOne(userUU); if (oldUser == null) { throw new VisibleError("未找到用户信息"); } // 修改手机号 if (!StringUtils.isEmpty(newUser.getMobile()) && !newUser.getMobile().equals(oldUser.getMobile())) { if (mobileHasRegistered(newUser.getMobile())) { throw new VisibleError("手机号已被注册"); } if (!newUser.getMobile().matches(Const.REGEXP_MOBILE_CONTINENT)) { throw new VisibleError("请输入正确的手机号"); } oldUser.setMobile(newUser.getMobile()); oldUser.setMobileValidCode((short) Status.NOT_APPLYING.getCode()); } // 修改邮箱 if (!StringUtils.isEmpty(newUser.getEmail()) && !newUser.getEmail().equals(oldUser.getEmail())) { if (emailHasRegistered(newUser.getEmail())) { throw new VisibleError("邮箱已被注册"); } if (!newUser.getEmail().matches(Const.REGEXP_EMAIL)) { throw new VisibleError("请输入正确的邮箱"); } oldUser.setEmail(newUser.getEmail()); oldUser.setEmailValidCode((short) Status.NOT_APPLYING.getCode()); } // 修改用户名 if (!StringUtils.isEmpty(newUser.getVipName())) { oldUser.setVipName(newUser.getVipName()); } // 保存用户信息 oldUser = userDao.save(oldUser); oldUser = syncUserInfo(oldUser, null, "(接口调用)修改用户信息", null); return oldUser; } @Override public long count() { return userDao.count(); } @Override public Long countByLogin(String start, String end) throws ParseException { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date startTime = simpleDateFormat.parse(start); Date endTime = simpleDateFormat.parse(end); Calendar starttime = Calendar.getInstance(); starttime.setTime(startTime); Calendar endtime = Calendar.getInstance(); endtime.setTime(endTime); return userRecordDao.getCountByLogin(new Timestamp(starttime.getTimeInMillis()),new Timestamp(endtime.getTimeInMillis())); } @Override public Long countByLoginInputMonth(String startTime,String endTime, int month) throws ParseException { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date startToDate = simpleDateFormat.parse(startTime); Date endToDate = simpleDateFormat.parse(endTime); Calendar start = Calendar.getInstance(); start.setTime(startToDate); start.add(Calendar.MONTH, -month); Calendar end = Calendar.getInstance(); end.setTime(endToDate); end.add(Calendar.MONTH, -month); return userRecordDao.getCountByLogin(new Timestamp(start.getTimeInMillis()),new Timestamp(end.getTimeInMillis())); } @Override public Long getMaxUUInLastWeek() { Calendar start = Calendar.getInstance(); start.set(Calendar.HOUR_OF_DAY, 0); start.set(Calendar.MINUTE, 0); start.set(Calendar.SECOND, 0); start.set(Calendar.MILLISECOND, 0); int dayofweek = start.get(Calendar.DAY_OF_WEEK); if (dayofweek == 1) { dayofweek += 7; } start.add(Calendar.DATE, 2 - dayofweek); return userDao.findMaxUUBefore(start.getTime()); } @Override public long countByRegisterDate(final Calendar start, final Calendar end) { return userDao.count(new Specification() { @Override public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) { Predicate predicate = cb.between(root.get("registerDate").as(Calendar.class), start, end); query.where(predicate); return null; } }); } @Override public Map countByRegisterDate(Timestamp start, Timestamp end, List fromApps) { Map data = new HashMap<>(); List> counts = userDao.getCountByRegisterDate(start, end, fromApps); for (Map count : counts) { data.put((String) count.get("appId"), (Long) count.get("count")); fromApps.remove(count.get("appId")); } for(String fromApp: fromApps){ data.put(fromApp, 0L); } return data; } @Override public long countInCurrentMonth() { return CountUtils.countInCurrentMonth(new CountCallBack() { @Override public Long countByTime(Calendar start, Calendar end) { return countByRegisterDate(start, end); } }); } @Override public long countInLastMonth() { return CountUtils.countInLastMonth(new CountCallBack() { @Override public Long countByTime(Calendar start, Calendar end) { return countByRegisterDate(start, end); } }); } @Override public long countInCurrentWeek() { return CountUtils.countInCurrentWeek(new CountCallBack() { @Override public Long countByTime(Calendar start, Calendar end) { return countByRegisterDate(start, end); } }); } @Override public Map count(final List fromApps) { Map data = new HashMap<>(); List> counts = userDao.getCountByRegisterDate(fromApps); for (Map count : counts) { data.put((String) count.get("appId"), (Long) count.get("count")); } return data; } @Override public Map countInCurrentMonth(final List fromApps) { return CountUtils.countInCurrentMonth(new CountCallBack>() { @Override public Map countByTime(Calendar start, Calendar end) { return countByRegisterDate(new Timestamp(start.getTimeInMillis()), new Timestamp(end.getTimeInMillis()), fromApps); } }); } @Override public Map countInCurrentWeek(final List fromApps) { return CountUtils.countInCurrentWeek(new CountCallBack>() { @Override public Map countByTime(Calendar start, Calendar end) { return countByRegisterDate(new Timestamp(start.getTimeInMillis()), new Timestamp(end.getTimeInMillis()), fromApps); } }); } @Override public Map countInToday(List fromApps) { return CountUtils.countInToday(new CountCallBack>() { @Override public Map countByTime(Calendar start, Calendar end) { return countByRegisterDate(new Timestamp(start.getTimeInMillis()), new Timestamp(end.getTimeInMillis()), fromApps); } }); } @Override public Map countInYesterday(List fromApps) { return CountUtils.countInYesterday(new CountCallBack>() { @Override public Map countByTime(Calendar start, Calendar end) { return countByRegisterDate(new Timestamp(start.getTimeInMillis()), new Timestamp(end.getTimeInMillis()), fromApps); } }); } @Override public Map countgInLastMonth(List fromApps) { return CountUtils.countInLastMonth(new CountCallBack>() { @Override public Map countByTime(Calendar start, Calendar end) { return countByRegisterDate(new Timestamp(start.getTimeInMillis()), new Timestamp(end.getTimeInMillis()), fromApps); } }); } @Override public Map countInInputTime(String startTime, String endTime, List fromApps) throws ParseException { CountCallBack> countCallBack = new CountCallBack>() { @Override public Map countByTime(Calendar start, Calendar end) { return countByRegisterDate(new Timestamp(start.getTimeInMillis()),new Timestamp(end.getTimeInMillis()),fromApps); } }; return CountUtils.countInInputTime(countCallBack,startTime,endTime); } @Override public User findByWxUnionid(String unionid) { return userDao.findByWxUnionid(unionid); } @Override public User findByBhOpenId(String openId) { return userDao.findByBhOpenId(openId); } @Override public User bindUnionId(String username, String password, String unionid) { Assert.hasText(username, "用户名不能为空"); Assert.hasText(password, "密码不能为空"); User user = findByUsername(username); if (user == null) { throw new IllegalArgumentException("该用户不存在"); } checkPassword(user.getUserUU(), password, false); user.setWxUnionid(unionid); userDao.save(user); userLogger.info(user, Type.BIND_WEIXIN.getValue()); return user; } @Override public User bindBhOpenId(String username, String password, String openId) { Assert.hasText(username, "用户名不能为空"); Assert.hasText(password, "密码不能为空"); User user = findByUsername(username); if (user == null) { throw new IllegalArgumentException("该用户不存在"); } checkPassword(user.getUserUU(), password, false); user.setBhOpenId(openId); userDao.save(user); userLogger.info(user, Type.BIND_BIHE.getValue()); return user; } @Override public User findByForeignId(ForeignInfo foreignInfo) { User user = null; if (foreignInfo instanceof OAuthInfo) { user = userDao.findByWxUnionid(foreignInfo.getForeignOpenId()); } else if (foreignInfo instanceof BiHeInfo) { user = userDao.findByBhOpenId(foreignInfo.getForeignOpenId()); } return user; } @Override public User bindForeignOpenId(String username, String password, ForeignInfo foreignInfo) { // 校验空参数 try { Assert.hasText(username, "用户名不能为空"); Assert.hasText(password, "密码不能为空"); } catch (IllegalArgumentException e) { throw new VisibleError(e.getMessage()); } // 校验用户名密码是否正确 User user = findByUsername(username); if (user == null) { throw new VisibleError("该用户不存在"); } checkPassword(user.getUserUU(), password, false); // 设置第三方openId setForeignOpenId(user, foreignInfo); userDao.save(user); userLogger.info(user, Type.BIND_FOREIGN.getValue()); return user; } @Override public User bindForeignOpenId(String code, String mobile, String codeToken, ForeignInfo foreignInfo) { // 校验空参数 try { Assert.hasText(code, "验证码不能为空"); Assert.hasText(mobile, "手机号不能为空"); Assert.hasText(codeToken, "token不能为空"); } catch (IllegalArgumentException e) { throw new VisibleError(e.getMessage()); } // 校验验证码是否正确 Token existToken = tokenService.findOne(codeToken); if (existToken == null || existToken.isExpired()) { throw new VisibleError("验证码过期"); } if (!mobile.equals(existToken.getMobile())) { throw new VisibleError("手机号已被修改,请重新获取验证码"); } if (!code.equals(existToken.getBind())) { throw new VisibleError("验证码不正确,请重新输入"); } // 设置第三方openId User user = userDao.findByMobile(mobile); if (user == null) { throw new VisibleError("该用户不存在"); } setForeignOpenId(user, foreignInfo); userDao.save(user); userLogger.info(user, Type.BIND_FOREIGN.getValue()); return user; } /** * 设置用户第三方openId,不同应用对应不同字段 * * @param user 用户信息 * @param foreignInfo * @return */ @Override public User setForeignOpenId(User user, ForeignInfo foreignInfo) { if (user == null) { return null; } if (foreignInfo instanceof OAuthInfo) { user.setWxUnionid(foreignInfo.getForeignOpenId()); } else if (foreignInfo instanceof BiHeInfo) { user.setBhOpenId(foreignInfo.getForeignOpenId()); } return user; } @Override public User findByImId(String imId) { return userDao.findByImId(imId); } /** * 同步用户信息到各个应用 * * @param user 用户信息 * @param noEncryPwd 未加密密码,用于同步im * @param msg 同步信息描述,用户区分同步类型 */ private User syncUserInfo(User user, String noEncryPwd, final String msg, App otherApp) { List apps = appService.findDefaultUseApp(); if (otherApp != null && !apps.contains(otherApp)) { apps.add(otherApp); } try { // 其他应用可能会用到IMID,要先同步到im之后再同步到其他应用 String imId = syncUserToIm(user, noEncryPwd, msg); user.setImId(imId); user = userDao.save(user); } catch (Exception e) { e.printStackTrace(); } // 封装同步其他应用数据并同步 boolean hasQuestion = !CollectionUtils.isEmpty(user.getQuestions()); JSONObject formData = JSON.parseObject(JSON.toJSONString(user)); formData.put("password", user.getPassword()); formData.put("hasQuestion", hasQuestion); syncUserInfo(formData, msg, apps); return user; } private String syncUserToIm(User user, String noEncryPwd, String msg) throws Exception { String appId = "im"; App app = appService.findOne(appId); if (StringUtils.isEmpty(app.getBackUserUrl())) { return null; } // 封装数据同步到im String url = app.getBackUserUrl(); HttpUtil.ResponseWrap res = null; ModelMap formData = new ModelMap(); formData.put("dialectUID", user.getImId()); formData.put("realName", StringUtils.isEmpty(user.getRealName()) ? user.getVipName() : user.getRealName()); formData.put("password", noEncryPwd); formData.put("email", StringUtils.isEmpty(user.getEmail()) ? "0" : user.getEmail()); formData.put("mobile", user.getMobile()); res = HttpUtil.doPost(url, formData, 10000); if (!res.isSuccess()) { syncLogger.error(appId, msg + ",同步用户信息失败", formData.toString(), res.getContent()); throw new Exception(res.getContent()); } else { JSONObject obj = JSON.parseObject(res.getContent()); if (obj.getString("resultMsg") != null) { syncLogger.error(appId, msg + ",同步用户信息失败", formData.toString(), res.getContent()); } syncLogger.info(appId, msg + ",同步用户信息成功", formData.toString(), res.getContent()); return obj.getString("dialectUID"); } } /** * 同步信息到指定应用 * * @param formData 同步数据 * @param msg 同步信息 * @param apps 需要同步的应用 */ private void syncUserInfo(final Map formData, final String msg, List apps) { for (final App app : apps) { executorService.execute(new Runnable() { @Override public void run() { String url = app.getBackUserUrl(); if (StringUtils.isEmpty(url)) { return; } HttpUtil.ResponseWrap res; try { res = HttpUtil.doPost(url, formData, 10000); if (!res.isSuccess()) { SyncLog syncLog = syncLogger.error(app.getUid(), msg + ",同步用户信息失败", JSON.toJSONString(formData), res.getContent()); SyncFail.add(syncLog.getId(), formData, url, app.getUid()); } else { syncLogger.info(app.getUid(), msg + ",同步用户信息成功", JSON.toJSONString(formData)); } } catch (Exception e) { syncLogger.error(app.getUid(), msg + ",同步用户信息失败", JSON.toJSONString(formData), e.getMessage()); } } }); } } @Override public long countByNotLogin(int month) { return CountUtils.countBeforeInputMonth(new CountCallBack() { @Override public Long countByTime(Calendar start, Calendar end) { return countBeforeTime(end); } }, month); } private long countBeforeTime(Calendar end) { return userRecordDao.count((root, query, cb) -> { Predicate lessPredicate = cb.lessThan(root.get("lastLoginTime").as(Calendar.class), end); Predicate nullPredicate = cb.isNull(root.get("lastLoginTime")); query.where(cb.or(lessPredicate, nullPredicate)); return null; }); } }