Commit a4c79a5d authored by 王亮's avatar 王亮

Feature/modify phone no 20221117

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
...@@ -46,18 +46,6 @@ ...@@ -46,18 +46,6 @@
<artifactId>SensorsAnalyticsSDK</artifactId> <artifactId>SensorsAnalyticsSDK</artifactId>
<version>3.2.0</version> <version>3.2.0</version>
</dependency> </dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-core</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>RELEASE</version>
</dependency>
<!-- swagger2 end -->
<dependency> <dependency>
<groupId>com.google.code.gson</groupId> <groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId> <artifactId>gson</artifactId>
......
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.controller.modifyphoneno.resp.UserModifyPhoneRecordResp;
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.entity.UserModifyPhoneRecord;
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.beans.BeanUtils;
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
...@@ -37,6 +33,7 @@ public class ModifyPhoneNoController implements IBaseController { ...@@ -37,6 +33,7 @@ public class ModifyPhoneNoController implements IBaseController {
@Resource @Resource
private IModifyPhoneNoService modifyPhoneNoService; private IModifyPhoneNoService modifyPhoneNoService;
@GetMapping("/progress") @GetMapping("/progress")
public JsonResult<ProgressResp> progress() { public JsonResult<ProgressResp> progress() {
User user = getCurrentUserFromRedis(); User user = getCurrentUserFromRedis();
...@@ -113,4 +110,41 @@ public class ModifyPhoneNoController implements IBaseController { ...@@ -113,4 +110,41 @@ public class ModifyPhoneNoController implements IBaseController {
} }
/*------------------------------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------------------------------*/
/**
* 客服系统修改手机号
* @param modifyPhoneRecord
* @return
*/
@PostMapping("/submitModify")
public JsonResult submitModify(@Valid @RequestBody ModifyPhoneRecord modifyPhoneRecord) {
modifyPhoneNoService.submitModify(modifyPhoneRecord);
return JsonResult.buildSuccessResult();
}
/**
* 金融修改手机号
* @param modifyPhoneRecord
* @return
*/
@PostMapping("/financial/submitModify")
public JsonResult financialSubmitModify(@Valid @RequestBody ModifyPhoneRecord modifyPhoneRecord) {
modifyPhoneNoService.financialSubmitModify(modifyPhoneRecord);
return JsonResult.buildSuccessResult();
}
@PostMapping( "/modifyPhoneNolist")
public JsonResult getModifyPhoneNolist(@RequestParam("userId") Long userId,
@RequestParam(value = "pageNo", defaultValue = "1", required = false) int pageNo,
@RequestParam(value = "pageSize", defaultValue = "10", required = false) int pageSize) {
Page<UserModifyPhoneRecordResp> pageData = modifyPhoneNoService.query(userId, pageNo, pageSize).map(record -> {
UserModifyPhoneRecordResp userModifyPhoneRecordResp = new UserModifyPhoneRecordResp();
BeanUtils.copyProperties(record, userModifyPhoneRecordResp);
userModifyPhoneRecordResp.setReason(record.getReason().name());
return userModifyPhoneRecordResp;
});
return JsonResult.buildSuccessResult("修改手机号列表", pageData);
}
} }
package cn.quantgroup.xyqb.controller.modifyphoneno.req;
import cn.quantgroup.xyqb.entity.enums.Reason;
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 Reason reason;
@NotBlank(message = "操作人不能为空")
private String operator;
// @NotBlank(message = "备注不能为空")
private String remark;
}
package cn.quantgroup.xyqb.controller.modifyphoneno.resp;
import cn.quantgroup.xyqb.entity.enums.Reason;
import lombok.Data;
import java.sql.Timestamp;
@Data
public class UserModifyPhoneRecordResp {
private Long id;
private Long userId;
private String prevPhoneNo;
private String curPhoneNo;
private String reason;
private String operator;
private String remark;
private String financialResponse;
private Timestamp createdAt;
private Timestamp updatedAt;
}
package cn.quantgroup.xyqb.entity;
import cn.quantgroup.xyqb.entity.enums.Reason;
import cn.quantgroup.xyqb.util.encrypt.CryptConverter;
import javax.persistence.Convert;
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")
@Convert(converter = CryptConverter.class)
private String prevPhoneNo;
@Column(name = "cur_phone_no")
@Convert(converter = CryptConverter.class)
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.xyqb.entity.enums;
/**
* Created by FrankChow on 15/7/15.
*/
public enum Reason {
ABANDONED("原注册手机已经废弃"),
SYNCHRONOUSCHANGE("电商侧手机号需同步修改金融侧"),
ORTHER("其它原因"),
;
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> {
}
...@@ -16,5 +16,4 @@ public interface IUserHashMappingRepository extends JpaRepository<UserHashMappin ...@@ -16,5 +16,4 @@ public interface IUserHashMappingRepository extends JpaRepository<UserHashMappin
@Transactional @Transactional
void deleteByUserId(Long userId); void deleteByUserId(Long userId);
} }
...@@ -63,4 +63,6 @@ public interface IHttpService { ...@@ -63,4 +63,6 @@ public interface IHttpService {
String post(String uri, Map<String, String> headers, Map<String, String> parameters); String post(String uri, Map<String, String> headers, Map<String, String> parameters);
String postJson(String uri, Map<String, String> parameters); String postJson(String uri, Map<String, String> parameters);
String postJson(String uri, Map<String, String> headers, Map<String, String> parameters);
} }
...@@ -6,15 +6,6 @@ import cn.quantgroup.xyqb.service.http.IHttpService; ...@@ -6,15 +6,6 @@ import cn.quantgroup.xyqb.service.http.IHttpService;
import cn.quantgroup.xyqb.util.PasswordUtil; import cn.quantgroup.xyqb.util.PasswordUtil;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.net.ssl.SSLContext;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.Charsets; import org.apache.commons.codec.Charsets;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
...@@ -53,6 +44,12 @@ import org.apache.http.message.BasicNameValuePair; ...@@ -53,6 +44,12 @@ import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
/** /**
* @author mengfan.feng * @author mengfan.feng
* @time 2015-08-13 10:19 * @time 2015-08-13 10:19
...@@ -90,8 +87,8 @@ public class HttpServiceImpl implements IHttpService { ...@@ -90,8 +87,8 @@ public class HttpServiceImpl implements IHttpService {
} }
@Override @Override
public String post(String uri, Map<String, String> headers, Map<String, String> parameters) { public String postJson(String uri, Map<String, String> headers, Map<String, String> parameters) {
return doHttp(RequestBuilder.post(), uri, headers, parameters, BodyType.FORM); return doHttp(RequestBuilder.post(), uri, headers, parameters, BodyType.JSON);
} }
@Override @Override
...@@ -99,6 +96,11 @@ public class HttpServiceImpl implements IHttpService { ...@@ -99,6 +96,11 @@ public class HttpServiceImpl implements IHttpService {
return doHttp(RequestBuilder.post(), uri, null, parameters, BodyType.JSON); return doHttp(RequestBuilder.post(), uri, null, parameters, BodyType.JSON);
} }
@Override
public String post(String uri, Map<String, String> headers, Map<String, String> parameters) {
return doHttp(RequestBuilder.post(), uri, headers, parameters, BodyType.FORM);
}
/** /**
* Send Http * Send Http
* *
......
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 cn.quantgroup.xyqb.entity.UserModifyPhoneRecord;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
/** /**
...@@ -33,4 +31,10 @@ public interface IModifyPhoneNoService { ...@@ -33,4 +31,10 @@ public interface IModifyPhoneNoService {
void feedback(Long id); void feedback(Long id);
void audit(AuditReq auditReq); void audit(AuditReq auditReq);
void submitModify(ModifyPhoneRecord modifyPhoneRecord);
void financialSubmitModify(ModifyPhoneRecord modifyPhoneRecord);
Page<UserModifyPhoneRecord> query(Long userId, int pageNo, int pageSize);
} }
...@@ -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.User;
import cn.quantgroup.xyqb.entity.UserModifyPhoneRecord;
import cn.quantgroup.xyqb.entity.enums.Reason;
import cn.quantgroup.xyqb.exception.AppletException;
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;
import cn.quantgroup.xyqb.service.session.ISessionService;
import cn.quantgroup.xyqb.service.sms.ISmsService; 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.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;
import java.util.Objects;
/** /**
* Date: 2019/11/4 * Date: 2019/11/4
* Time: 下午2:59 * Time: 下午2:59
...@@ -71,6 +83,19 @@ public class ModifyPhoneNoServiceImpl implements IModifyPhoneNoService { ...@@ -71,6 +83,19 @@ 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;
@Autowired
private ISessionService sessionService;
/** /**
* @param userId user.id * @param userId user.id
* @param step1Req * @param step1Req
...@@ -215,13 +240,144 @@ public class ModifyPhoneNoServiceImpl implements IModifyPhoneNoService { ...@@ -215,13 +240,144 @@ public class ModifyPhoneNoServiceImpl implements IModifyPhoneNoService {
if (userRepository.findByPhoneNo(modifyPhoneNo.getCurPhoneNo()) != null) { if (userRepository.findByPhoneNo(modifyPhoneNo.getCurPhoneNo()) != null) {
throw new DataException("新手机号已存在,不支持更换。"); throw new DataException("新手机号已存在,不支持更换。");
} }
checkLoanStatus(modifyPhoneNo.getUserId()); // 请求其他系统信息
userService.modifyPhoneNo(modifyPhoneNo.getPrevPhoneNo(), modifyPhoneNo.getCurPhoneNo()); HashMap<String, String> parameters = new HashMap<>();
modifyPhoneNo.setApplyStatus(ModifyPhoneNoApplyStatusEnum.DONE.ordinal()); HashMap<String, String> headers = new HashMap<>();
modifyPhoneNo.setProcessingStatus(ModifyPhoneNoProcessingStatusEnum.WAIT_4_USER_FEEDBACK.ordinal()); headers.put("qg-tenant-id", TenantUtil.TENANT_DEFAULT.toString());
parameters.put("oldPhoneNo", modifyPhoneNo.getPrevPhoneNo());
parameters.put("phoneNo", modifyPhoneNo.getCurPhoneNo());
parameters.put("exUserId", String.valueOf(modifyPhoneNo.getUserId()));
// parameters.put("remark", modifyPhoneNo.getApplyStatusReason());
parameters.put("changeRecord", Reason.SYNCHRONOUSCHANGE.toString());
String resultStr = httpService.postJson(userHost + "/api/finance-gateway/finance-user/shop/notify/changePhoneNo", headers, parameters);
JsonResult resultStrJson = JSONObject.parseObject(resultStr, JsonResult.class);
// 如果有返回值
if ("0000".equals(resultStrJson.getBusinessCode()) || "4014".equals(resultStrJson.getBusinessCode())) {
// 同步金融修改电商
userService.modifyPhoneNo(modifyPhoneNo.getPrevPhoneNo(), modifyPhoneNo.getCurPhoneNo());
modifyPhoneNo.setApplyStatus(ModifyPhoneNoApplyStatusEnum.DONE.ordinal());
modifyPhoneNo.setProcessingStatus(ModifyPhoneNoProcessingStatusEnum.WAIT_4_USER_FEEDBACK.ordinal());
} else {
String msg = resultStrJson.getMsg();
throw new DataException("金融返回失败" + (StringUtils.isNotBlank(msg) ? ":" + msg : ""));
}
} }
} }
@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("新手机号已存在,不支持更换");
}
if (Objects.isNull(modifyPhoneRecord.getUserId())){
throw new DataException("用户ID不能为空");
}
User user = userService.findById(modifyPhoneRecord.getUserId());
if (user == null) {
throw new DataException("用户不存在");
}
if (!modifyPhoneRecord.getPrevPhoneNo().equals(user.getPhoneNo()) && !modifyPhoneRecord.getPrevPhoneNo().equals(user.getEncryptedPhoneNo())) {
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.postJson(userHost + "/api/finance-gateway/finance-user/shop/notify/changePhoneNo", headers, parameters);
JsonResult resultStrJson = JSONObject.parseObject(resultStr, JsonResult.class);
// 如果有返回值
if ("0000".equals(resultStrJson.getBusinessCode()) || "4014".equals(resultStrJson.getBusinessCode())) {
// 同步金融修改电商
userService.submitModifyPhone(modifyPhoneRecord.getPrevPhoneNo(), modifyPhoneRecord.getCurPhoneNo());
UserModifyPhoneRecord record = new UserModifyPhoneRecord();
BeanUtils.copyProperties(modifyPhoneRecord, record);
record.setFinancialResponse(JSONObject.toJSONString(resultStrJson));
modifyPhoneRecordRepository.saveAndFlush(record);
//登出此用户
sessionService.deleteByUserId(user.getId());
} else {
String msg = resultStrJson.getMsg();
throw new DataException("金融返回失败" + (StringUtils.isNotBlank(msg) ? ":" + msg : ""));
}
}
} catch (Exception e) {
e.printStackTrace();
throw new DataException(e.getMessage());
} finally {
lock.unlock();
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void financialSubmitModify(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("新手机号已存在,不支持更换");
}
User user = userService.findByPhoneInDb(modifyPhoneRecord.getPrevPhoneNo());
if (user == null) {
throw new AppletException("用户不存在", "1001");
}
if (!modifyPhoneRecord.getPrevPhoneNo().equals(user.getPhoneNo()) && !modifyPhoneRecord.getPrevPhoneNo().equals(user.getEncryptedPhoneNo())) {
throw new DataException("原手机号填写不符");
}
userService.submitModifyPhone(modifyPhoneRecord.getPrevPhoneNo(), modifyPhoneRecord.getCurPhoneNo());
UserModifyPhoneRecord record = new UserModifyPhoneRecord();
BeanUtils.copyProperties(modifyPhoneRecord, record);
record.setUserId(user.getId());
modifyPhoneRecordRepository.saveAndFlush(record);
//登出此用户
sessionService.deleteByUserId(user.getId());
}
} catch (Exception e) {
e.printStackTrace();
log.error("金融来修改手机号失败--{}, 原因:---", JSONObject.toJSONString(modifyPhoneRecord), e);
String failString = String.format("金融来修改手机号失败--%s", e.getMessage());
throw new DataException(failString);
} finally {
lock.unlock();
}
}
@Override
public Page<UserModifyPhoneRecord> query(Long userId, int pageNo, int pageSize) {
Pageable pageable = getPageable(pageNo, pageSize);
Page<UserModifyPhoneRecord> userModifyPhoneRecord = modifyPhoneRecordRepository.findAll((root, query, criteriaBuilder) -> {
List<Predicate> predicates = Lists.newArrayList();
predicates.add(criteriaBuilder.equal(root.get("userId"),userId));
query.where(predicates.toArray(new Predicate[predicates.size()]));
return query.getRestriction();
}, pageable);
return userModifyPhoneRecord;
}
private Pageable getPageable(int currentPage, int pageSize) {
return new PageRequest(currentPage - 1, pageSize, new Sort(Sort.Direction.DESC, "id"));
}
/** /**
* 验证用户是否允许修改手机号 * 验证用户是否允许修改手机号
* <p> * <p>
...@@ -255,12 +411,14 @@ public class ModifyPhoneNoServiceImpl implements IModifyPhoneNoService { ...@@ -255,12 +411,14 @@ public class ModifyPhoneNoServiceImpl implements IModifyPhoneNoService {
if (userService.findByPhoneInDb(curPhoneNo) != null) { if (userService.findByPhoneInDb(curPhoneNo) != null) {
throw new DataException("填写信息有误,新手机号已注册。"); throw new DataException("填写信息有误,新手机号已注册。");
} }
checkLoanStatus(userId); // checkLoanStatus(userId); 调用金融接口方式是错误的,改为同步金融一起修改手机号
} }
/** /**
* @param userId user.id * @param userId user.id
* 弃用,这里调金融传的是电商userId,结果不可信
*/ */
@Deprecated
public void checkLoanStatus(Long userId) { public void checkLoanStatus(Long userId) {
log.info("allowModify userId = 【{}】", userId); log.info("allowModify userId = 【{}】", userId);
String res = httpService.get(apiHttps + "/ex/loan/user/loan_status.json?userId=" + userId); String res = httpService.get(apiHttps + "/ex/loan/user/loan_status.json?userId=" + userId);
......
...@@ -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;
}
} }
package cn.quantgroup.xyqb.util;
import cn.quantgroup.security.AESEncryption;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import org.apache.commons.lang3.StringUtils;
public class AESUtils {
public static AESEncryption encryption;
/**
* V2方法不再考虑历史数据兼容问题
*
* @param plainValue 明文
* @return 密文
*/
public static String encryptV2(final String plainValue) {
if (StringUtils.isNotEmpty(plainValue)) {
return encryption().encryptBase64(plainValue);
}
return plainValue;
}
/**
* V2方法不再考虑历史数据兼容问题
*
* @param cipherValue 明文
* @return 密文
*/
public static String decryptV2(String cipherValue) {
return StringUtils.isNotEmpty(cipherValue) ? encryption().decryptBase64(cipherValue)
: cipherValue;
}
public static AESEncryption encryption() {
if (encryption == null) {
Config config = ConfigService.getAppConfig();
String key = config.getProperty("keystone.security.key", "");
String iv = config.getProperty("keystone.security.iv", "");
encryption = new AESEncryption(key, iv, true);
}
return encryption;
}
}
package cn.quantgroup.xyqb.util.encrypt;
import cn.quantgroup.xyqb.util.AESUtils;
import javax.persistence.AttributeConverter;
public class CryptConverter implements AttributeConverter<String, String> {
@Override
public String convertToDatabaseColumn(String attribute) {
return AESUtils.encryptV2(attribute);
}
@Override
public String convertToEntityAttribute(String dbData) {
return AESUtils.decryptV2(dbData);
}
}
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