
注册业务
我们先来给一下整个业务流程
注册业务具体的包
controller层
@RestController
@RequestMapping("/user")
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(RegisterRequestDTO.class);//日志
@Resource
private UserService userService;
@PostMapping("/register")
public Response<Void> register(RegisterRequestDTO requestDTO){
RegisterRequestDTO.checkDTO(requestDTO);
userService.regisiter(requestDTO);
return Response.ok();
}
用户前端发来的信息JSON文件,在被传到controller层,经过反序列化之后变成RegisterRequestDTO这个类所创建的对象(requestdto),在类里调用checkDTO方法去检查requestDTO
这是RegsiterRequestDTO类,下面的方法包括(checkDTO是JSON文件序列化后传来的requestdto里的email,password,checkPassword,username,调用isEmpty看看是否为空,还有输入的email格式通过模式串 match类看看是否正确 (正则表达式),并且检测输入的userNumber身份证号长度是否为18)如果检测到的不正常就会抛出异常
@Data
@AllArgsConstructor
public class RegisterRequestDTO {
private static final Logger logger = LoggerFactory.getLogger(RegisterRequestDTO.class);
private String email;
private String password;
private String checkpassword;
private String userName;
private String userNumber;
private Long createAt;
private Long createBy;
public static void checkDTO(@RequestBody RegisterRequestDTO dto){
if (StringTools.isEmpty(dto.getEmail())
||StringTools.isEmpty(dto.getPassword())
||StringTools.isEmpty(dto.getCheckpassword())
||StringTools.isEmpty(dto.getUserName())){
logger.info("{} 错误:{}",CodeEnum.REGISTER_FAILED_03.getCode(),CodeEnum.REGISTER_FAILED_03.getMsg());
throw new BusinessException(CodeEnum.REGISTER_FAILED_03);
}
String pattern="^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$";
if (!ReUtil.isMatch(pattern, dto.getEmail())) {
logger.info("{} 错误:{}",CodeEnum.REGISTER_FAILED_04.getCode(),CodeEnum.REGISTER_FAILED_04.getMsg());
throw new BusinessException(CodeEnum.REGISTER_FAILED_04);
}
if(StringTools.isEmpty(dto.getUserNumber())){
if (dto.getUserNumber().length() !=18){
throw new BusinessException(CodeEnum.REGSITER_FAILED_05);
}
}
if (!dto.getPassword().equals(dto.getCheckpassword())) {
logger.info("{} 错误:{}",CodeEnum.REGISTER_FAILED_02.getCode(),CodeEnum.REGISTER_FAILED_02.getMsg());
throw new BusinessException(CodeEnum.REGISTER_FAILED_02);
}
Date date=new Date();
dto.setCreateAt(date.getTime());
}
}
关于异常
这里是自己创建的异常类,为什么要自己创建一个异常类呢,如果不创建用默认的RuntimeException,因为RuntimeException只能传codeEnum.getmsg(),会使前端的code与msg不一致,而自己定义的BusinessException,可以直接传codeEnum这个引用,msg与code同时上传,不会导致msg与code对不上
注:子类想访问父类就得用super()
@Getter
public class BusinessException extends RuntimeException{
private final CodeEnum codeEnum;
public BusinessException(CodeEnum codeEnum){
super(codeEnum.getMsg());
this.codeEnum=codeEnum;
}
}
我详细讲一下CodeEnum
@Getter
public enum CodeEnum {
SUCCESS_CODE(200,"成功"),
DEFAULT_CODE(900,"不许注册"),
REGSITER_FAILED_00(800,"注册错误"),
REGISTER_FAILED_01(901,"邮箱已经注册"),
REGISTER_FAILED_02(902,"两次密码不一致"),
REGISTER_FAILED_03(903,"格式不正确"),
REGISTER_FAILED_04(904,"请输入正确邮箱"),
REGSITER_FAILED_05(905,"身份证信息错误");
private final Integer code;
private final String msg;
CodeEnum(Integer code,String msg){
this.code=code;
this.msg=msg;
}
}
因为这是一个枚举类,枚举类不允许有setter方法,不是只需要getter方法。因为所有属性是final的,构造器也是默认修饰符,不允许在其他地方进行构建。因为你这一列粉色的都是已经构造好的对象了,外面的类可以直接使用这些对象,也就是定义好的code和msg枚举了所有的失败可能方法,与成功的情况
然后你抛出的这个异常(在RegsiterRequestdto这个类里抛出的)会被GlobalExceptionHandler这个类给捕获
@RestControllerAdvice
public class GlobalExceptionHandler {
private final static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(BusinessException.class)
{
return Response.error(ex.getCodeEnum());
}
}
这个注解指定了我们要拦截异常的类型,只拦截BusinessException这个类,单独.class是表示这个类的意思
@ExceptionHandler(BusinessException.class)
public Response<Void>handleException(BusinessException ex,WebRequest request)
BusinessException ex,是被捕获的异常,也就是在RegisterRequestDTO中抛出的异常(由BusinessException创建的,也就是ex即是CodeEnum.REGISTER_FAILED_0X),然后返回Response.error调用.getMessage最后得到这个信息
以下是Response的对象以及可调用的方法(.error .ok)
通用返回类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Response<T> {
private Integer code;
public String msg;
private String data;
public static <T> Response<T> ok() {
return new Response<>(CodeEnum.SUCCESS_CODE.getCode(), CodeEnum.SUCCESS_CODE.getMsg(),null );
}
public static <T> Response<T> ok(T data){
String dataJson = JSONUtil.toJsonStr(data);
return new Response<>(CodeEnum.SUCCESS_CODE.getCode(), CodeEnum.SUCCESS_CODE.getMsg(), dataJson);
}
public static <T> Response<T> ok(T data,String msg){
String dataJson = JSONUtil.toJsonStr(data);
return new Response<>(CodeEnum.SUCCESS_CODE.getCode(), msg, dataJson);
}
public static <T> Response<T> ok(String msg){
return new Response<>(CodeEnum.SUCCESS_CODE.getCode(), msg,null);
}
public static <T> Response<T> error(){
return new Response<>(CodeEnum.REGISTER_FAILED_01.getCode(), CodeEnum.DEFAULT_CODE.getMsg(), null);
}
public static <T> Response<T> error(CodeEnum codeEnum,String msg){
return new Response<>(codeEnum.getCode(),msg,null);
}
public static <T> Response<T> error(CodeEnum codeEnum){
return new Response<>(codeEnum.getCode(),codeEnum.getMsg(),null);
}
public static <T> Response<T> error(String msg){
return new Response<>(CodeEnum.DEFAULT_CODE.getCode(),msg,null);
}
}
以上只是说了当你输入了空信息,两次密码不一致,身份证号长度不等于18,邮箱格式不正确的时候,在controller层会发生的流程,即当出错时,会走完controller层之后给用户界面返回msg,统一返回给前端的数据格式
dao层
service 层注入 dao 层的类,也就是 RedisComment 和 MybatisPlus 等操作数据库的类,为了实现具体的业务需求
Redis其实也是一个数据库
也就是如果在RegsiterExceptionDTO中没有被拦截下,通过了四个if的检测,用户端发来的(DTO)那就要,经过RedisComment类,把DTO存入Redis缓存中
这个就是RedisComment类的内容
@Component("redisComent")
public class RedisComment {
@Resource
private RedisUtils redisUtils;
//判断邮箱是否存在于redis
public boolean emailIsRegister(RegisterRequestDTO requestDTO){
String o =(String) redisUtils.get(RedisComponent.REDIS_CACHE_REGISTER_EMAIL + requestDTO.getEmail());
return !StringTools.isEmpty(o);
}
//将当前邮箱存入 redis
public void emailSaveRedis(String email){
redisUtils.set(RedisComponent.REDIS_CACHE_REGISTER_EMAIL + email,"yes");
}
}
你可以看到,它主要是判断缓存中是否有相同的邮箱,redisUtils调用get方法,得到RedisComponent.REDIS_CACHE_REGISTER_EMAIL + requestDTO.getEmail()的key,存在一个o的字符串里,然后调用StringTools的isEmpty方法判断缓存中是否有这个邮箱
如果没有就用redisUtil的set方法把他存入缓存
以下是StringTools的isEmpty的方法
public static boolean isEmpty(String str) {
if (null == str || "".equals(str) || "null".equals(str) || "\u0000".equals(str)) {
return true;
} else if ("".equals(str.trim())) {
return true;
}
return false;
}
返回的是ture or false 用来判断是否存在相同的邮箱
RedisComponent类
一个简单的字符串用来表明缓存中的邮箱,起识别作用
public static final String REDIS_CACHE_REGISTER_EMAIL="axaxedx:redis:register:email";
Service层
主要就是UserServiceimpl这个类用来实现Service层的业务,通过调用redsicomment的方法看缓存中是否有相同的邮箱,有就抛异常,与上面介绍的方法相同 boolean isRegister = redisComment.emailIsRegister(requestDTO);
@Service("userService")
public class UserServiceimpl implements UserService {
@Resource
private UserInfoMapper userInfoMapper;
@Resource
private RedisComment redisComment;
@Override
public void regisiter(RegisterRequestDTO requestDTO) {
boolean isRegister = redisComment.emailIsRegister(requestDTO);
if(isRegister){
throw new BusinessException(CodeEnum.REGISTER_FAILED_01);
// throw new RuntimeException(CodeEnum.REGISTER_FAILED_01.getMsg());
}
UserInfo userInfo=UserInfo.DTO2po(requestDTO);
if(StringTools.isEmpty(requestDTO.getUserNumber())){
userInfo.setStatus(UserStatus.NEED_NUMBER.getStatus());
}else {
userInfo.setStatus(UserStatus.NORMAL.getStatus());
}
userInfoMapper.insert(userInfo);
redisComment.emailSaveRedis(userInfo.getEmail());
}
}
UserInfo userInfo=UserInfo.DTO2po(requestDTO);这句的意思是把dto通过userInfo类的方法dto2po把dto转为po这样就可以通过
userInfoMapper.insert(userInfo);
redisComment.emailSaveRedis(userInfo.getEmail());
这两句语句,第一句是插入缓存,如果第一句没问题也就是缓存中没有相同的邮箱,就会执行第二句,第二句是送入数据库
这里的意思是如果dto里的这个身份证号码是空的,就会返回UserStatus中的NEED_NUMBER,否则就返回正常
if(StringTools.isEmpty(requestDTO.getUserNumber())){
userInfo.setStatus(UserStatus.NEED_NUMBER.getStatus());
}else {
userInfo.setStatus(UserStatus.NORMAL.getStatus());
}