stroe商城项目一:用户注册功能

项目功能- 用户注册功能

1 创建数据表

-- 创建用户信息表
CREATE TABLE `store`.`t_user`(
    `uid` int NOT NULL AUTO_INCREMENT COMMENT '用户id',
    `username` varchar(20) NOT NULL UNIQUE COMMENT '用户名',
    `password` varchar(32) NOT NULL COMMENT '密码',
    `salt` varchar(36) NULL COMMENT '盐值',
    `phone` varchar(20) NULL COMMENT '电话号码',
    `email` varchar(30) NULL COMMENT '电子邮箱',
    `gender` int NULL COMMENT '性别:0-女;1-男',
    `avatar` varchar(50) NULL COMMENT '头像',
    `is_delete` int NULL COMMENT '是否删除:0-未删除;1-已删除',
    `created_user` varchar(20) NULL COMMENT '创建人',
    `created_time` datetime NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
    `modified_user` varchar(20) NULL COMMENT '更新人',
    `modified_time` datetime NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    PRIMARY KEY (`uid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

2 创建用户实体类

2-1 创建实体类的基类

将类中公共的属性抽取出来形成一个基类,被所有实体类继承

package com.cy.store.common;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/*
    实体类的基类
 */
@Data
public class BaseEntity implements Serializable {
    // 创建人
    private String createdUser;
    //创建时间
    private Date createdTime;
    //更新人
    private String modifiedUser;
    //更新时间
    private Date modifiedTime;
    //是否删除:0-未删除;1-已删除
    private Integer isDelete;

}
2-2 创建用户实体类 继承基类
package com.cy.store.entity;

import com.cy.store.common.BaseEntity;
import lombok.Data;

import java.io.Serializable;

/*
    用户对象实体类
 */
@Data
public class UserEntity extends BaseEntity implements Serializable {

    // 用户id
    private Integer uid;
    // 用户名
    private String username;
    // 密码
    private String password;
    // 盐值
    private String salt;
    // 电话号码
    private String phone;
    // 电子邮箱
    private String email;
    // 性别:0-女;1-男
    private Integer gender;
    // 头像
    private String avatar;

}

3 注册-持久层

通过Mybatis来操作数据库,在做mybatis的开发流程
分析:
1.先查询用户是否存在,存在则不能进行注册,并给出提示。(对应查询语句)
2.用户不存在,在进行注册。

3-1 规划需要执行的sql语句

用户注册功能,相当于在做数据库的插入操作。

insert into t_user (username,password,...) values (....);
3-2 设计接口和抽象方法

定义mapper接口。

package com.cy.store.mapper;

import com.cy.store.entity.UserEntity;

/*
    用户持久层mapper接口
 */
public interface UserMapper {
    /**
     *  插入用户
     * @param userEntity 用户对象
     * @return 影响的行数
     */
    Integer insertUser(UserEntity userEntity);

    /**
     * 通过用户名查询用户信息
     * @param username 用户名称
     * @return UserEntity 用户对象
     */
    UserEntity selectByUserName(String username);
}
3-3 编写映射

定义xml映射文件,与对应的接口进行关联。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cy.store.mapper.UserMapper">
	<!--  当数据表中的字段与实体类中不一致时,做映射关系处理  -->
    <resultMap id="userMap" type="com.cy.store.entity.UserEntity">
        <result property="isDelete" column="is_delete"/>
        <result property="modifiedTime" column="modified_time"/>
        <result property="modifiedUser" column="modified_user"/>
        <result property="createdTime" column="created_time"/>
        <result property="createdUser" column="created_user"/>
    </resultMap>
    
	<!-- 重复使用的sql片段 -->
    <sql id="userColumn">
        uid,
        username,
        password,
        salt,
        phone,
        email,
        gender,
        avatar,
        is_delete,
        created_time,
        created_user,
        modified_time,
        modified_user
    </sql>
    <!--    根据用户名称查询用户信息   -->
    <select id="selectByUserName" parameterType="string" resultMap="userMap">
        select
        <include refid="userColumn"></include>
        from Blog where  username= #{username}
    </select>
    
    <!--    插入用户    -->
    <insert id="insertUser" parameterType="com.cy.store.entity.UserEntity" useGeneratedKeys="true" keyProperty="uid">
        insert into t_user (<include refid="userColumn"></include>) values (
        #{username},#{password},#{salt},#{phone},#{email},#{gender},#{avatar},#{isDelete},#{createdUser},#{createdTime},#{modifiedUser},#{modifiedTime}
        )
    </insert>
</mapper>
3-4 单元测试

每一个层都应要写单元测试,对已开发好的功能做自测,确保没有问题后才可以发布到测试环境,移交测试人员进行测试。

4 注册-业务层(****)

业务功能层是整个系统实现过程中最重要的一层。因为这层不仅需要考虑具体功能的实现过程,还要考虑问题的出现。

  • 功能具体实现的逻辑设计
  • 实现该功能时有可能出现的问题,也就是异常的规划。
4-1 异常的规划
1 设计业务层的异常机制

分析 业务层的异常首先是属于运行时抛出的异常,所有我们设计的异常都是 RunTimeException的子类,因为异常是有很多的,所以我们应该设计一个异常基类,用于被其他不同业务异常继承。

具体实现如下:

package com.cy.store.common;
/*
    设计整个系统的异常基类,这个类继承RunTimeException
    并重写父类中的构造方法
 */
public class ServiceException  extends RuntimeException{

    public ServiceException() {
        super();
    }

    public ServiceException(String message) {
        super(message);
    }

    public ServiceException(String message, Throwable cause) {
        super(message, cause);
    }

    public ServiceException(Throwable cause) {
        super(cause);
    }

    protected ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

可能出现的异常

  • 注册时用户已经存在,被占用异常。
  • 数据插入时异常。
package com.cy.store.service.ex;

import com.cy.store.common.ServiceException;

/**
 * 数据插入异常
 */
public class InsertException extends ServiceException {
    public InsertException() {
        super();
    }

    public InsertException(String message) {
        super(message);
    }

    public InsertException(String message, Throwable cause) {
        super(message, cause);
    }

    public InsertException(Throwable cause) {
        super(cause);
    }

    protected InsertException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
4-2 业务层接口以及实现类设计
  • 接口设计
package com.cy.store.service;


import com.cy.store.entity.UserEntity;

public interface UserService {

    // 用户注册功能,这里不需要返回。业务层通过mapper的影响行数做逻辑判断。
    void register(UserEntity userEntity);
    // 用户查询功能
    UserEntity queryByName(String username);

}

  • 实现类设计
package com.cy.store.service.impl;

import com.cy.store.entity.UserEntity;
import com.cy.store.mapper.UserMapper;
import com.cy.store.service.UserService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.UserDuplicatedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.InvalidPropertiesFormatException;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public void register(UserEntity userEntity) {
        // 判断参数是否为空
        String username = userEntity.getUsername();
        if (username == null || username == "") {
            throw new NullPointerException("用户名不能为空");
        }
        // 查询用户是否存在
        UserEntity entity = userMapper.selectByUserName(username);
        if (entity != null) {
            throw new UserDuplicatedException("用户已存在");
        }
        // 插入用户信息
        userEntity.setIsDelete(0);
        userEntity.setCreatedUser("system");
        userEntity.setCreatedTime(new Date());
        userEntity.setModifiedUser("system");
        userEntity.setModifiedTime(new Date());
        Integer integer = userMapper.insertUser(userEntity);
        if (integer != 1) {
            throw new InsertException("用户插入时出现异常");
        }
    }

    @Override
    public UserEntity queryByName(String username) {
        if (username == "" || username == null) {
            throw new NullPointerException("用户姓名不能为空");
        }
        UserEntity userEntity = userMapper.selectByUserName(username);
        return userEntity;
    }
}

4-3 单元测试 略
4-4 业务层逻辑补充-密码处理

在这里插入图片描述

分析:

  • 1、确定密码加密的算法逻辑。
  • 2、使用UUID类生成一个随机的盐值,并将盐值保留存入数据库表中,这个字段在后面用户登录的时候 需要解密使用。
  • 3、将 用户输入的M密码+盐值,利用加密算法加密,等到新的加密密码保存在数据库表中。这样就做到了密码的加密。
  • 4、用户登入的时候,可以利用原始密码+盐值 进行加码 得到的密码与 数据库中注册时存入的你密码做比对。一致则登入成功,否则失败。

代码实现:

package com.cy.store.utils;


import org.springframework.util.DigestUtils;

public class EncryptMD5 {

    /**
     *
     * @param oldPassword 原始密码
     * @param salt 盐值
     * @return 新的密码
     */
    public static String MD5PASSWORD(String oldPassword,String salt){
        String newPassword  =  oldPassword + salt;
        for (int i = 0; i < 3; i++) {
            newPassword = DigestUtils.md5DigestAsHex(newPassword.getBytes());
        }
        return newPassword;
    }
}
package com.cy.store.service.impl;

import com.cy.store.entity.UserEntity;
import com.cy.store.mapper.UserMapper;
import com.cy.store.service.UserService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.UserDuplicatedException;
import com.cy.store.utils.EncryptMD5;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.InvalidPropertiesFormatException;
import java.util.UUID;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public void register(UserEntity userEntity) {
        // 判断参数是否为空
        String username = userEntity.getUsername();
        String oldPassword = userEntity.getPassword();
        if (username== null || username == "") {
            throw new NullPointerException("用户名不能为空");
        }
        // 查询用户是否存在
        UserEntity entity = userMapper.selectByUserName(username);
        if (entity != null) {
            throw new UserDuplicatedException("用户已存在");
        }
        // 插入用户信息
        userEntity.setIsDelete(0);
        userEntity.setCreatedUser("system");
        userEntity.setCreatedTime(new Date());
        userEntity.setModifiedUser("system");
        userEntity.setModifiedTime(new Date());

        // 密码加密处理
        String salt = UUID.randomUUID().toString().replace("-", "");
        userEntity.setSalt(salt);
        String newPassword = EncryptMD5.MD5PASSWORD(oldPassword, salt);
        userEntity.setPassword(newPassword);
        Integer integer = userMapper.insertUser(userEntity);
        if (integer != 1) {
            throw new InsertException("用户插入时出现异常");
        }
    }

    @Override
    public UserEntity queryByName(String username) {
        if (username == "" || username == null) {
            throw new NullPointerException("用户姓名不能为空");
        }
        UserEntity userEntity = userMapper.selectByUserName(username);
        return userEntity;
    }
}

5 注册-控制层

5-1 统一结果数据封装

分析: 前端请求后得到的结果,可以看做是一个对象。这个对象包含的属性有:状态码、数据、描述信息。

封装响应对象

package com.cy.store.common;

import java.io.Serializable;

/**
 * Json格式的数据对象
 */
public class JsonResult<E> implements Serializable {

    // 业务状态码
    private Integer code;
    // 描述信息
    private String msg;
    // 数据对象
    private E data;

    public JsonResult() {
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public E getData() {
        return data;
    }

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

    /**
     * 逻辑处理正常,返回成功场景
     * @param data 返回数据
     * @param msg   返回消息
     * @param <E>   数据类型
     * @return JsonResult 对象
     */
    public static <E> JsonResult<E> ok(E data ,String msg){
        JsonResult<E> result = new JsonResult<>();
        result.setCode(1001);
        result.setMsg(msg);
        result.setData(data);
        return result;
    }

    /**
     * 逻辑处理异常,返回失败场景
     * @param msg
     * @param <E>
     * @return
     */
    public static  JsonResult<Void> fail(String msg){
        JsonResult<Void> result = new JsonResult<>();
        result.setCode(9999);
        result.setMsg(msg);
        return result;
    }

}
5-2 设计请求

分析: 对于注册功能来说

  • 请求路径: /user/reg
  • 请求参数: User user
  • 请求方式: post
  • 响应结果: JsonResult

创建一个Controller类用来接受处理请求,UserController

package com.cy.store.controller;

import com.cy.store.common.JsonResult;
import com.cy.store.entity.UserEntity;
import com.cy.store.service.UserService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.UserDuplicatedException;
import org.springframework.beans.factory.annotation.Autowired;
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;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 用户注册
     * @param user java实体类对象的形式传参
     * @return
     */
    //@PostMapping("/reg")
    //public JsonResult<Void> reg(@RequestBody UserEntity user){
    //
    //    try {
    //        userService.register(user);
    //        return JsonResult.ok(null, "用户注册成功");
    //    } catch (UserDuplicatedException e) {
    //        return JsonResult.fail(e.getMessage());
    //    }catch (InsertException e){
    //        return JsonResult.fail(e.getMessage());
    //    }
    //}

    /**
     * 封装了 异常统一处理类后的写法
     * 如果请求发生了异常,会去调用异常处理类,处理异常并返回给前端,没有异常就直接返回处理成功的结果。
     * @param user
     * @return
     */
    @PostMapping("/reg")
    public JsonResult<Void> reg(@RequestBody UserEntity user) {
        userService.register(user);
        return JsonResult.ok(null, "用户注册成功");

    }
}

创建系统业务异常的统一处理全局类 StoreExceptionHandler

package com.cy.store.common;

import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.UserDuplicatedException;
import com.cy.store.service.ex.UserNameNotNullException;
import com.cy.store.service.ex.UserNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * StoreExceptionHandler 统一对请求中的异常做处理,
 * 系统·抛出异常后才会调用这个类。
 * 通过捕获异常的类型,判断属于哪个异常,然后返回给前端。
 */
@RestControllerAdvice
@Slf4j
public class StoreExceptionHandler {

    @ExceptionHandler(ServiceException.class)
    public JsonResult<Void> handlerException(Throwable e) {
        log.info("Exception:==>" + e.getMessage());
        if (e instanceof UserDuplicatedException) {
            return JsonResult.fail(e.getMessage());
        } else if (e instanceof InsertException) {
            return JsonResult.fail(e.getMessage());
        } else if (e instanceof UserNotFoundException) {
            return JsonResult.fail(e.getMessage());
        } else if (e instanceof UserNameNotNullException) {
            return JsonResult.fail(e.getMessage());
        } else {
            return JsonResult.fail(e.getMessage());
        }
    }
}
  • 24
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值