第3章 用户模块开发

1. 使用SpringMVC的方式开发用户信息

model层即之前配置的数据库对象的映射的组成 因为包括密码才是一个完整的model 再但是返回给前端的model不需要也不应该包括所有信息 所以目录结构长这个样子

UserController.java 即控制层

@Controller("user")//用来被spring扫描到
@RequestMapping("/user")//在url上通过/user的方式访问到
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("/get")
    @ResponseBody
    public CommonReturnType getUser(@RequestParam(name="id")Integer id){
        //接收一个入参 调用service服务获取对应id的用户对象并返回给前端
        UserModel userModel = userService.getUserById(id);
        //将核心领域模型用户对象转化为可供UI使用的viewobject
        UserVO userVO = convertFromModel(userModel);
        return CommonReturnType.create(userVO);
    }
    private UserVO convertFromModel(UserModel userModel){
        if (userModel == null){
            return null;
        }
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userModel,userVO);
        return userVO;
    }
}

UserServiceImpl.java 服务层
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDOMapper userDOMapper;
    @Autowired
    private UserPasswordDOMapper userPasswordDOMapper;

    @Override
    public UserModel getUserById(Integer id) {
        //调用userdommapper获取到对应的用户dataobject
        UserDO userDO = userDOMapper.selectByPrimaryKey(id);
        if (userDO == null){
            return null;
        }
        //业务逻辑要求通过user的用户名获取密码
        UserPasswordDO userPasswordDO = userPasswordDOMapper.selectByUserId(userDO.getId());
        return convertFromDataObject(userDO,userPasswordDO);
    }

    private UserModel convertFromDataObject(UserDO userDO, UserPasswordDO userPasswordDO){
        if (userDO == null){
            return null;
        }
        UserModel userModel = new UserModel();
        BeanUtils.copyProperties(userDO, userModel);
        if (userPasswordDO == null){
            return userModel;
        }
        userModel.setEncrptPassword(userPasswordDO.getEncrptPassword());
        return userModel;
    }
}

 

2. 定义通用的返回对象

刚开始的代码是返回一个model类型给前端 那么前端每次都要解析json对象对应的model类型 出错的时候没有json对象就无法解析 所以需要给程序返回一个有意义的错误信息 现在定义通用的返回对象

public class CommonReturnType {
    //表明对应请求的返回处理结果"success" or "fail"
    private String status;

    //若status=success 则data内返回前端需要的json数据
    //若status=fail 则打他内使用通用的错误码格式
    private Object data;

    //定义一个通用的常见方法
    public  static CommonReturnType create(Object res){
        return CommonReturnType.create(res,"success");
    }

    public  static CommonReturnType create(Object res,String status){
        CommonReturnType type = new CommonReturnType();
        type.setStatus(status);
        type.setData(res);
        return type;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

定义了一个CommonReturnType 用对应的status和object类型的data的方式返回所有json序列化对象,供前端解析使用,摒弃了使用httpstatuscode和tomcat内置的error页的方式处理 并且定义了一个BusinessException的方式 去统一管理我们想要的错误码 在BaseController里面定义了通用的handlerException方法 解决未被controller层吸收的exception 并且使用errCode和errMsg统一的配置方式 吃掉了所有内部所有不可预知的异常

3. 实现用户的第一个行为 手机验证码注册

    //Spring默认bean的装配是单例的 如何满足多个用户的同时访问?
    //答:本质是一个process 里面实现了Threadlocal修饰的map 让每个线程都能够处理自己的request
    //https://www.cnblogs.com/xrq730/p/4854820.html
    @Autowired
    private HttpServletRequest httpServletRequest;

    @RequestMapping("/getotp")
    @ResponseBody
    public CommonReturnType getOtp(@RequestParam(name="telphone")String telphone){
        //需要按照一定的规则生成OTP验证码
        Random random = new Random();
        int randomInt = random.nextInt(99999);
        randomInt+=10000;
        String otpCode = String.valueOf(randomInt);

        //将OTP验证码同对应用户的手机号关联(这个需求最好使用Redis实现) 还没讲到分布式 先用httpsession
        httpServletRequest.getSession().setAttribute(telphone,otpCode);

        //将OTP验证码通过短信通道发送给用户 省略
        System.out.println("telphone = "+ telphone+"&otpCode = "+otpCode);
        return CommonReturnType.create(null);
    }

4. 注册的功能实现

在UserDommapper里面指定用户表的keyProperty字段和useGeneratedKeys字段 否则会出错

<insert id="insertSelective" parameterType="com.miaoshaproject.dataobject.UserDO"
        keyProperty="id" useGeneratedKeys="true">

volidator相关不表

遇到的一个问题自增id不是从最大的开始

Controller里的逻辑
    //用户注册接口
    @RequestMapping(value = "register")
    @ResponseBody
    public CommonReturnType register(@RequestParam(name = "telphone")String telphone,
                                     @RequestParam(name = "otpCode")String otpCode,
                                     @RequestParam(name = "name")String name,
                                     @RequestParam(name = "gender")Integer gender,
                                     @RequestParam(name = "age")Integer age,
                                     @RequestParam(name = "password")String password) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        //验证手机号和对应的otpcode相符合(otpcode放在httpServletRequest)
        String inSessionOtpCode = (String)this.httpServletRequest.getSession().getAttribute(telphone);//获取otpcode
        if (!StringUtils.equals(otpCode, inSessionOtpCode)){    //与前端传上来的otpCode进行对比
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "短信验证码不符合");
        }

        //用户的注册流程
        UserModel userModel = new UserModel();
        userModel.setName(name);
        userModel.setGender(new Byte(String.valueOf(gender.intValue())));
        userModel.setAge(age);
        userModel.setTelphone(telphone);
        userModel.setRegisterMode("byphone");
        userModel.setEncrptPassword(this.EncodeByMD5(password));//将密码加密存入数据库

        //这里是Controller 调用了service的方法
        userService.register(userModel);
        return CommonReturnType.create(null);//只需要返回成功的状态码 而不需要再把这个用户的相关信息返回
    }
    public String EncodeByMD5(String str) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        //java9里的BASE64Encoder取消了
        //https://blog.csdn.net/Cha0DD/article/details/87794268

        // 确定计算方法
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        Encoder base64Encoder = Base64.getEncoder();
        //加密字符串
        String newstr = base64Encoder.encodeToString(md5.digest(str.getBytes("utf-8")));
        return newstr;
    }

Service里的逻辑
    @Override
    public void register(UserModel userModel) throws BusinessException {
        if (userModel == null){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }

        ValidationResult result = validator.validate(userModel);
        if (result.isHasErrors()){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, result.getErrMsg());
        }

        //注册用户
        //实现model -> dataobject 方法
        UserDO userDO = convertFromModel(userModel);
        //手机号重复注册发生异常
        try {
            userDOMapper.insertSelective(userDO);
        }catch (DuplicateKeyException ex){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "手机号已注册");
        }
        //id是自增字段 所以插入后再取出来赋值给userModel
        userModel.setId(userDO.getId());
        UserPasswordDO userPasswordDO = convertPasswordFromModel(userModel);
        userPasswordDOMapper.insertSelective(userPasswordDO);
    }

5. 登录逻辑的实现

Controller
//用户登录接口
    @RequestMapping(value = "login", method = {RequestMethod.POST})
    @ResponseBody
    public CommonReturnType login(@RequestParam(name = "telphone")String telphone,
                                  @RequestParam(name = "password")String password) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        //入参校验(手机号密码不能为空)
        if (org.apache.commons.lang3.StringUtils.isEmpty(telphone)
                || org.apache.commons.lang3.StringUtils.isEmpty(password)){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "不能为空");
        }

        //用户登录服务,校验用户登录是否合法。将手机号和加密后的密码传到Service层
        UserModel userModel = userService.validateLogin(telphone, this.EncodeByMD5(password));

        //将登陆凭证加入到用户登录成功的session中
        //如果用户的会话标识中有IS_LOGIN,则表示登录成功
        this.httpServletRequest.getSession().setAttribute("IS_LOGIN", true);//key:IS_LOGIN
        //将userModel放到对应的session里
        this.httpServletRequest.getSession().setAttribute("LOGIN_USER", userModel);

        //返回前端一个正确的信息(通用对象)
        return CommonReturnType.create(null);//success
    }

Service
@Override
    public UserModel validateLogin(String telphone, String encryptPassword) throws BusinessException {
        //通过用户手机号,获取用户信息。(添加sql语句)
        UserDO userDO = userDOMapper.selectByTelphone(telphone);
        if (userDO == null){
            throw new BusinessException(EmBusinessError.USER_LOGIN_FAIL);
        }
        //再通过用户信息(id),到用户密码表中 拿到用户密码信息
        UserPasswordDO userPasswordDO = userPasswordDOMapper.selectByUserId(userDO.getId());
        UserModel userModel = convertFromDataObject(userDO, userPasswordDO);    //组装成UserModel


        //比对用户信息内加密的密码是否和传输进来的密码匹配
        if (!StringUtils.equals(encryptPassword, userModel.getEncryptPassword())){
            throw new BusinessException(EmBusinessError.USER_LOGIN_FAIL);
        }else {
            return userModel;//如果用户登录成功,则将model返回controller层
        }
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值