Commit 58939807 authored by 李健华's avatar 李健华

修改手机号

parent d5f001a8
@startuml 用户注销
actor 用户 as user
participant 电商 as kdsp
participant 卡包 as kb
participant Talos as talos
participant 用户中心 as uc
participant 消息中心 as msg
database 数据库 as db
== 注销入口 /close/account/exist ==
hnote across: 注销入口API开放给电商,入参经过RSA证书加密
user -> kdsp : 获取注销入口
kdsp -> kb : 是否需要注销
note right
1. 用户已经注销,直接返回check=false
2. 有绑定关系,返回check=true,url
3. 检测是否开户,返回check=true,url
end note
kb -> db : FinanceUserRef,判断注销状态、绑定关系
kb -> uc : 获取是否存在金融用户
kb -> talos : 检测是否开户
alt 不需要注销
kb --> kdsp : check:false
kdsp --> user : check:false, 没有注销入口
else 需要注销
kb -> uc : 获取用户token
uc --> kb : 返回token和用户数据
kb --> kdsp : check:true, 组装带token的注销URL返回
kdsp --> user : check:true, 返回注销URL, 显示注销入口
end
hnote across: 以下API为金融API,校验金融token
== 检测在途 /close/account/check ==
user -> kb : 跳转注销页面,检测是否可以注销
kb-> talos : 检测是否有在途
talos --> kb : 返回是否有在途
kb --> user : 有在途,不允许注销,无在途可以注销
== 发送[注销/解绑]短信 /account/sendSms ==
user -> kb : 获取验证码
note right
校验短信发送规则
1. 当天最大发送10次
2. 1小时最大发送5次
3. 58秒内不能重复发送
end note
kb -> msg : 规则校验通过,发送短信
msg --> kb : 短信发送完成
note left
1. 保存验证码到redis
2. 更新短信校验规则到redis[发送次数和时间]
end note
== 确认注销 /close/account/confirm ==
user -> kb : 确认注销
note right
1. 短信验证码校验
2. 注销状态校验
3. 是否在途校验
end note
kb -> talos : 调用注销API
talos --> kb : 返回注销结果
note left
1. BusinessCode成功是0000 用户不存在是4001 用户已注销4002
2. 以上状态都认为注销成功
end note
alt API调用异常
kb -> db : UserLogoffLog,新增处理中[PROCESS]记录,job异步补偿
kb --> user : 返回注销中,job异常处理
else 注销失败
kb -> db : UserLogoffLog,新增注销失败[FAIL]记录
kb --> user : 返回注销失败
else 注销成功
kb -> db : FinanceUserRef,更新status=注销
kb -> db : UserLogoffLog,新增注销成功[SUCCESS]记录
kb --> kdsp : 异步通知电商清除缓存
kb --> user : 返回注销成功
note over kb, user: 注销成功,通知KDSP清除缓存,卡包清理缓存
end
== 确认解绑 /unbind/account/confirm ==
user -> kb : 确认解绑
note right
1. 短信验证码校验
2. 注销状态校验
3. 是否在途校验
4. 更新绑定状态
end note
kb -> db : FinanceUserRef,更新enable=无效
kb --> kdsp : 异步通知电商清除缓存
kb --> user : 解绑成功
note over kb, user: 解绑成功,通知KDSP清除缓存,卡包清理缓存
@enduml
package cn.quantgroup.customer.enums;
public enum ErrorCodeEnum {
NET_ERROR(6001L, "网络通讯异常"),
RETURN_ERROR(7001L, "返回值异常"),
PARAM_ERROR(7002L, "参数异常"),
NO_TOKEN(8001L,"缺少token信息"),
ILLEGAL_TOKEN(8002L,"token信息有误"),
PHONE_EQUALS(8003L, "新手机号与原手机号相同"),
;
public String getMessage() {
return message;
}
public Long getCode() {
return code;
}
private Long code;
private String message;
ErrorCodeEnum(Long code, String message) {
this.code = code;
this.message = message;
}
}
package cn.quantgroup.xyqb.controller.modifyphoneno; package cn.quantgroup.xyqb.controller.modifyphoneno;
import cn.quantgroup.xyqb.controller.IBaseController; import cn.quantgroup.xyqb.controller.IBaseController;
import cn.quantgroup.xyqb.controller.modifyphoneno.req.AuditReq; import cn.quantgroup.xyqb.controller.modifyphoneno.req.*;
import cn.quantgroup.xyqb.controller.modifyphoneno.req.ModifyPhoneNoQueryReq;
import cn.quantgroup.xyqb.controller.modifyphoneno.req.Step1Req;
import cn.quantgroup.xyqb.controller.modifyphoneno.req.Step2Req;
import cn.quantgroup.xyqb.controller.modifyphoneno.resp.ProgressResp; import cn.quantgroup.xyqb.controller.modifyphoneno.resp.ProgressResp;
import cn.quantgroup.xyqb.entity.ModifyPhoneNo; import cn.quantgroup.xyqb.entity.ModifyPhoneNo;
import cn.quantgroup.xyqb.entity.User; import cn.quantgroup.xyqb.entity.User;
import cn.quantgroup.xyqb.model.JsonResult; import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.service.user.IModifyPhoneNoService; import cn.quantgroup.xyqb.service.user.IModifyPhoneNoService;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import java.text.SimpleDateFormat; import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import org.springframework.data.domain.Page; import java.text.SimpleDateFormat;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** /**
* 用户手机号修改相关api * 用户手机号修改相关api
...@@ -113,4 +106,11 @@ public class ModifyPhoneNoController implements IBaseController { ...@@ -113,4 +106,11 @@ public class ModifyPhoneNoController implements IBaseController {
} }
/*------------------------------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------------------------------*/
@PostMapping("/submitModify")
public JsonResult submitModify(@Valid @RequestBody ModifyPhoneRecord modifyPhoneRecord) {
modifyPhoneNoService.submitModify(modifyPhoneRecord);
return JsonResult.buildSuccessResult();
}
} }
package cn.quantgroup.xyqb.controller.modifyphoneno.req;
import cn.quantgroup.xyqb.util.ValidationUtil;
import lombok.Data;
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.io.Serializable;
@Data
public class ModifyPhoneRecord implements Serializable {
@NotNull(message = "用户ID不能为空")
private Long userId;
@NotBlank(message = "原手机号不能为空")
@Pattern(regexp = ValidationUtil.phoneRegExp, message = "原手机号码格式错误")
private String prevPhoneNo;
@NotBlank(message = "新手机号不能为空")
@Pattern(regexp = ValidationUtil.phoneRegExp, message = "新手机号码格式错误")
private String curPhoneNo;
@NotNull(message = "修改原因不能为空")
private Integer reason;
@NotBlank(message = "操作人不能为空")
private String operator;
@NotBlank(message = "备注不能为空")
private String remark;
}
package cn.quantgroup.xyqb.entity;
import cn.quantgroup.user.enums.Reason;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.io.Serializable;
/**
* Created by 11 on 2017/3/22.
*/
@Data
@Entity
@Table(name = "user_modify_phone_record")
public class UserModifyPhoneRecord extends BaseEntity implements Serializable {
@Column(name = "user_id")
private Long userId;
@Column(name = "prev_phone_no")
private String prevPhoneNo;
@Column(name = "cur_phone_no")
private String curPhoneNo;
@Column(name = "reason")
private Reason reason;
@Column(name = "operator")
private String operator;
@Column(name = "remark")
private String remark;
@Column(name = "financial_response")
private String financialResponse;
}
package cn.quantgroup.user.enums;
/**
* Created by FrankChow on 15/7/15.
*/
public enum Reason {
FIRSTREASON("原因一")
;
private String name;
Reason(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return name;
}
}
package cn.quantgroup.xyqb.repository;
import cn.quantgroup.xyqb.entity.UserModifyPhoneRecord;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface IModifyPhoneRecordRepository extends JpaRepository<UserModifyPhoneRecord, Long>, JpaSpecificationExecutor<UserModifyPhoneRecord> {
}
package cn.quantgroup.xyqb.service.user; package cn.quantgroup.xyqb.service.user;
import cn.quantgroup.xyqb.controller.modifyphoneno.req.AuditReq; import cn.quantgroup.xyqb.controller.modifyphoneno.req.*;
import cn.quantgroup.xyqb.controller.modifyphoneno.req.ModifyPhoneNoQueryReq;
import cn.quantgroup.xyqb.controller.modifyphoneno.req.Step1Req;
import cn.quantgroup.xyqb.controller.modifyphoneno.req.Step2Req;
import cn.quantgroup.xyqb.controller.modifyphoneno.resp.ProgressResp; import cn.quantgroup.xyqb.controller.modifyphoneno.resp.ProgressResp;
import cn.quantgroup.xyqb.entity.ModifyPhoneNo; import cn.quantgroup.xyqb.entity.ModifyPhoneNo;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
...@@ -33,4 +30,6 @@ public interface IModifyPhoneNoService { ...@@ -33,4 +30,6 @@ public interface IModifyPhoneNoService {
void feedback(Long id); void feedback(Long id);
void audit(AuditReq auditReq); void audit(AuditReq auditReq);
void submitModify(ModifyPhoneRecord modifyPhoneRecord);
} }
...@@ -6,9 +6,10 @@ import cn.quantgroup.xyqb.entity.User; ...@@ -6,9 +6,10 @@ import cn.quantgroup.xyqb.entity.User;
import cn.quantgroup.xyqb.model.JsonResult; import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.model.LoginProperties; import cn.quantgroup.xyqb.model.LoginProperties;
import cn.quantgroup.xyqb.model.UserInfo; import cn.quantgroup.xyqb.model.UserInfo;
import javax.servlet.http.HttpServletRequest;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletRequest;
/** /**
* Created by Miraculous on 15/7/5. * Created by Miraculous on 15/7/5.
...@@ -114,4 +115,6 @@ public interface IUserService { ...@@ -114,4 +115,6 @@ public interface IUserService {
* @param userId 用户id * @param userId 用户id
*/ */
void deregister(Long userId); void deregister(Long userId);
User submitModifyPhone(String prevPhoneNo, String curPhoneNo);
} }
package cn.quantgroup.xyqb.service.user.impl; package cn.quantgroup.xyqb.service.user.impl;
import cn.quantgroup.xyqb.aspect.limit.AccessLimit; import cn.quantgroup.xyqb.aspect.limit.AccessLimit;
import cn.quantgroup.xyqb.controller.modifyphoneno.req.AuditReq; import cn.quantgroup.xyqb.controller.modifyphoneno.req.*;
import cn.quantgroup.xyqb.controller.modifyphoneno.req.ModifyPhoneNoQueryReq;
import cn.quantgroup.xyqb.controller.modifyphoneno.req.Step1Req;
import cn.quantgroup.xyqb.controller.modifyphoneno.req.Step2Req;
import cn.quantgroup.xyqb.controller.modifyphoneno.resp.ProgressResp; import cn.quantgroup.xyqb.controller.modifyphoneno.resp.ProgressResp;
import cn.quantgroup.xyqb.entity.ModifyPhoneNo; import cn.quantgroup.xyqb.entity.ModifyPhoneNo;
import cn.quantgroup.xyqb.entity.UserModifyPhoneRecord;
import cn.quantgroup.xyqb.exception.DataException; import cn.quantgroup.xyqb.exception.DataException;
import cn.quantgroup.xyqb.model.JsonResult; import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.model.ModifyPhoneNoApplyStatusEnum; import cn.quantgroup.xyqb.model.ModifyPhoneNoApplyStatusEnum;
import cn.quantgroup.xyqb.model.ModifyPhoneNoProcessingStatusEnum; import cn.quantgroup.xyqb.model.ModifyPhoneNoProcessingStatusEnum;
import cn.quantgroup.xyqb.repository.IModifyPhoneNoRepository; import cn.quantgroup.xyqb.repository.IModifyPhoneNoRepository;
import cn.quantgroup.xyqb.repository.IModifyPhoneRecordRepository;
import cn.quantgroup.xyqb.repository.IUserDetailRepository; import cn.quantgroup.xyqb.repository.IUserDetailRepository;
import cn.quantgroup.xyqb.repository.IUserRepository; import cn.quantgroup.xyqb.repository.IUserRepository;
import cn.quantgroup.xyqb.service.http.IHttpService; import cn.quantgroup.xyqb.service.http.IHttpService;
...@@ -19,28 +18,37 @@ import cn.quantgroup.xyqb.service.sms.ISmsService; ...@@ -19,28 +18,37 @@ import cn.quantgroup.xyqb.service.sms.ISmsService;
import cn.quantgroup.xyqb.service.user.IModifyPhoneNoService; import cn.quantgroup.xyqb.service.user.IModifyPhoneNoService;
import cn.quantgroup.xyqb.service.user.IUserService; import cn.quantgroup.xyqb.service.user.IUserService;
import cn.quantgroup.xyqb.util.DateUtils; import cn.quantgroup.xyqb.util.DateUtils;
import cn.quantgroup.xyqb.util.RedisLock;
import cn.quantgroup.xyqb.util.TenantUtil;
import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.qiniu.util.Auth; import com.qiniu.util.Auth;
import java.util.List;
import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.HashMap;
import java.util.List;
/** /**
* Date: 2019/11/4 * Date: 2019/11/4
* Time: 下午2:59 * Time: 下午2:59
...@@ -71,6 +79,16 @@ public class ModifyPhoneNoServiceImpl implements IModifyPhoneNoService { ...@@ -71,6 +79,16 @@ public class ModifyPhoneNoServiceImpl implements IModifyPhoneNoService {
@Value("${qiniu.storage.secretKey}") @Value("${qiniu.storage.secretKey}")
public String secretKey; public String secretKey;
@Autowired
@Qualifier("stringRedisTemplate")
private RedisTemplate<String, String> redisTemplate;
@Value("${xyqb.user.service.host}")
private String userHost;
@Resource
private IModifyPhoneRecordRepository modifyPhoneRecordRepository;
/** /**
* @param userId user.id * @param userId user.id
* @param step1Req * @param step1Req
...@@ -222,6 +240,50 @@ public class ModifyPhoneNoServiceImpl implements IModifyPhoneNoService { ...@@ -222,6 +240,50 @@ public class ModifyPhoneNoServiceImpl implements IModifyPhoneNoService {
} }
} }
@Override
public void submitModify(ModifyPhoneRecord modifyPhoneRecord) {
String lockKey = "modifyPhone:".concat(modifyPhoneRecord.getCurPhoneNo());
RedisLock lock = new RedisLock(redisTemplate, lockKey);
try {
if (lock.lock()) {
if (modifyPhoneRecord.getCurPhoneNo().equals(modifyPhoneRecord.getPrevPhoneNo())) {
throw new DataException("新旧手机号相同");
}
// 请求其他系统信息
HashMap<String, String> parameters = new HashMap<>();
HashMap<String, String> headers = new HashMap<>();
headers.put("qg-tenant-id", TenantUtil.TENANT_DEFAULT.toString());
parameters.put("oldPhoneNo", modifyPhoneRecord.getPrevPhoneNo());
parameters.put("phoneNo", modifyPhoneRecord.getCurPhoneNo());
parameters.put("exUserId", String.valueOf(modifyPhoneRecord.getUserId()));
parameters.put("remark", modifyPhoneRecord.getRemark());
// todo: 记得映射
parameters.put("changeRecord", modifyPhoneRecord.getReason().toString());
String resultStr = httpService.post(userHost + "/operation/finance-gateway/finance-user/changePhoneNo", headers, parameters);
JsonResult<JsonResult> tokenExchangeResult = JSONObject.parseObject(resultStr, new TypeReference<JsonResult<JsonResult>>(){});
// 如果有返回值
JsonResult tokenExchange = tokenExchangeResult.getData();
if (tokenExchange != null) {
// 同步金融修改电商
userService.submitModifyPhone(modifyPhoneRecord.getPrevPhoneNo(), modifyPhoneRecord.getCurPhoneNo());
UserModifyPhoneRecord record = new UserModifyPhoneRecord();
BeanUtils.copyProperties(modifyPhoneRecord, record);
record.setFinancialResponse(JSONObject.toJSONString(modifyPhoneRecord));
modifyPhoneRecordRepository.saveAndFlush(record);
} else {
throw new DataException("金融返回失败");
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
/** /**
* 验证用户是否允许修改手机号 * 验证用户是否允许修改手机号
* <p> * <p>
......
...@@ -628,4 +628,29 @@ public class UserServiceImpl implements IUserService, IBaseController { ...@@ -628,4 +628,29 @@ public class UserServiceImpl implements IUserService, IBaseController {
/* 删除用户租户关联 羊小咩租户*/ /* 删除用户租户关联 羊小咩租户*/
productLoginRepository.deleteTenantAndPhoneNo("qtg", "yxm", user.getPhoneNo()); productLoginRepository.deleteTenantAndPhoneNo("qtg", "yxm", user.getPhoneNo());
} }
@Override
@Transactional(rollbackFor = Exception.class)
public User submitModifyPhone(String prevPhoneNo, String curPhoneNo) {
//1. 判断新手机号是否存在
User newPhoneUser = findByPhoneInDb(curPhoneNo);
if (Objects.nonNull(newPhoneUser)) {
//新手机号已存在
throw new DataException("新手机号存在, 用户修改手机号后新手机号注册了。");
}
User oldPhoneUser = findByPhoneInDb(prevPhoneNo);
if (Objects.isNull(oldPhoneUser)) {
throw new DataException("旧手机号不存在, 可能已经修改成功了。");
}
//2. 执行修改
oldPhoneUser.setPhoneNo(curPhoneNo);
oldPhoneUser.setEncryptedPhoneNo(curPhoneNo);
User user = userRepository.saveAndFlush(oldPhoneUser);
//3. 发送事件
PhoneNoUpdateEvent phoneNoUpdateEvent = new PhoneNoUpdateEvent(this, user, prevPhoneNo);
applicationEventPublisher.publishEvent(phoneNoUpdateEvent);
return oldPhoneUser;
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment