用户注册实现

一.数据库创建

用户表

CREATE TABLE `t_user` (
  `uid` int NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `username` varchar(20) NOT NULL COMMENT '用户名',
  `password` char(32) NOT NULL COMMENT '密码',
  `md5password` varchar(255) DEFAULT NULL,
  `salt` char(36) DEFAULT NULL COMMENT '盐值',
  `phone` varchar(20) DEFAULT NULL COMMENT '电话号码',
  `email` varchar(30) DEFAULT NULL COMMENT '电子邮箱',
  `gender` int DEFAULT NULL COMMENT '性别:0-女,1-男',
  `avatar` varchar(50) DEFAULT NULL COMMENT '头像',
  `is_delete` int DEFAULT NULL COMMENT '是否删除:0-未删除,1-已删除',
  `created_user` varchar(20) DEFAULT NULL COMMENT '日志-创建人',
  `created_time` datetime DEFAULT NULL COMMENT '日志-创建时间',
  `modified_user` varchar(20) DEFAULT NULL COMMENT '日志-最后修改执行人',
  `modified_time` datetime DEFAULT NULL COMMENT '日志-最后修改时间',
  PRIMARY KEY (`uid`),
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb3;

二.用户类的创建

后面的created_user ,created_time, modified_user,  modified_time属性可以作为基类专门设定

package com.cy.store.entity;


import java.util.Date;
import java.util.Objects;

/**
    创建用户的基类
 */
public class BaseEntity {
    private String createdUser;
    private Date createdTime;
    private String modifiedUser;
    private Date modifiedTime;


    @Override
    public String toString() {
        return "BaseEntity{" +
                "createdUser='" + createdUser + '\'' +
                ", createdTime=" + createdTime +
                ", modifiedUser='" + modifiedUser + '\'' +
                ", modifiedTime=" + modifiedTime +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof BaseEntity)) return false;
        BaseEntity that = (BaseEntity) o;
        return Objects.equals(createdUser, that.createdUser) && Objects.equals(createdTime, that.createdTime) && Objects.equals(modifiedUser, that.modifiedUser) && Objects.equals(modifiedTime, that.modifiedTime);
    }

    @Override
    public int hashCode() {
        return Objects.hash(createdUser, createdTime, modifiedUser, modifiedTime);
    }

    public String getCreatedUser() {
        return createdUser;
    }

    public void setCreatedUser(String createdUser) {
        this.createdUser = createdUser;
    }

    public Date getCreatedTime() {
        return createdTime;
    }

    public void setCreatedTime(Date createdTime) {
        this.createdTime = createdTime;
    }

    public String getModifiedUser() {
        return modifiedUser;
    }

    public void setModifiedUser(String modifiedUser) {
        this.modifiedUser = modifiedUser;
    }

    public Date getModifiedTime() {
        return modifiedTime;
    }

    public void setModifiedTime(Date modifiedTime) {
        this.modifiedTime = modifiedTime;
    }
}



然后User类继承基类创建,置于bean目录当中

package com.cy.store.bean;

import com.cy.store.entity.BaseEntity;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.Objects;

/**
 * 用户类的实体类
 * 继承基类
 * SpringBoot约定大于配置
 */
//@Component
public class User extends BaseEntity implements Serializable {
    private Integer uid;
    private String username;
    private String password;
    private String md5Password;
    private String salt;//盐值,加密使用
    private String phone;
    private String email;
    private Integer gender;//性别,男1女0
    private String avatar;//头像
    private Integer isDelete;//是否删除,0未删除,1已删除

/*
    public User() {
    }
*/

    public User(Integer uid, String username, String password, String md5Password, String salt, String phone, String email, Integer gender, String avatar, Integer isDelete) {
        this.uid = uid;
        this.username = username;
        this.password = password;
        this.md5Password = md5Password;
        this.salt = salt;
        this.phone = phone;
        this.email = email;
        this.gender = gender;
        this.avatar = avatar;
        this.isDelete = isDelete;
    }

    @Override
    public String toString() {
        return "User{" +
                "uid=" + uid +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", md5Password='" + md5Password + '\'' +
                ", salt='" + salt + '\'' +
                ", phone='" + phone + '\'' +
                ", email='" + email + '\'' +
                ", gender=" + gender +
                ", avatar='" + avatar + '\'' +
                ", isDelete=" + isDelete +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;
        if (!super.equals(o)) return false;
        User user = (User) o;
        return Objects.equals(uid, user.uid) && Objects.equals(username, user.username) && Objects.equals(password, user.password) && Objects.equals(md5Password, user.md5Password) && Objects.equals(salt, user.salt) && Objects.equals(phone, user.phone) && Objects.equals(email, user.email) && Objects.equals(gender, user.gender) && Objects.equals(avatar, user.avatar) && Objects.equals(isDelete, user.isDelete);
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), uid, username, password, md5Password, salt, phone, email, gender, avatar, isDelete);
    }

    public String getMd5Password() {
        return md5Password;
    }

    public void setMd5Password(String md5Password) {
        this.md5Password = md5Password;
    }

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public String getAvatar() {
        return avatar;
    }

    public void setAvatar(String avatar) {
        this.avatar = avatar;
    }

    public Integer getIsDelete() {
        return isDelete;
    }

    public void setIsDelete(Integer isDelete) {
        this.isDelete = isDelete;
    }
}

三.mapper的创建

首先创建一个mapper接口,便于springboot注入,接口里只有方法名和其返回值

package com.cy.store.mapper;

import com.cy.store.bean.User;

/**
 * 用户模块的持久层接口
 */
//@Mapper
public interface UserMapper {
    /**
     * 插入用户的数据
     * @param user 用户数据
     * @return 受影响的行数(增删改查受影响行数返回值
     */
    Integer insert(User user);

    /**
     * 根据用户名来查找用户的数据
     * @param username 用户名
     * @return 如果找到对应用户返回这个用户数据,没找到返回null
     */
    User findByUsername(String username);
}

然后再进行mapper.xml的编写,sql语句放在这个模块中

<?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">
<!--namespace属性,用于指定当前的映射文件和那个接口进行映射,需要指定接口的文件路径,需要标注包的完整路径接口-->
<mapper namespace="com.cy.store.mapper.UserMapper">
    <!--在mapper标签里编写mysql语句-->
    <!--id属性,表示映射的接口中方法的名称,直接在标签内部编写SQL语句-->
    <!--
        useGeneratedKeys="true"开启某个字段的值自增(一般情况下为主键)
        keyProperty="uid":标签将表中的哪个字段作为主键进行递增
    -->
    <insert id="insert" useGeneratedKeys="true" keyProperty="uid">
        INSERT INTO t_user(
            username,
            password,
            md5password,
            salt,
            phone,
            email,
            gender,
            avatar,
            is_delete,
            created_user,
            created_time,
            modified_user,
            modified_time
        )VALUES (
            #{username},
            #{password},
            #{md5Password},
            #{salt},
            #{phone},
            #{email},
            #{gender},
            #{avatar},
            #{isDelete},
            #{createdUser},
            #{createdTime},
            #{modifiedUser},
            #{modifiedTime}
        )
    </insert>


    <!--自定义映射,resultMap标签来完成映射规则的定义-->
    <!--id属性:标签给这个映射分配的唯一id值,对应的是resultMap="id属性的值"的取值-->
    <!--type属性:取值是一个类,表示的是数据库中查询结果与Java中哪个实体类进行结果集的映射-->
    <resultMap id="UserEntityMap" type="com.cy.store.bean.User">
        <!--将表的资源和类的属性不一致的字段进行匹配指定,名称一致的字段可以省略不写-->
        <!--在定义映射规则是主键是不可以省略的-->
        <id column="uid" property="uid"></id>
        <!--column 表中资源名称  property 类中资源名称-->
        <result column="is_delete" property="isDelete" ></result>
        <result column="created_user" property="createdUser" ></result>
        <result column="created_time" property="createdTime" ></result>
        <result column="modified_user" property="modifiedUser" ></result>
        <result column="modified_time" property="modifiedTime" ></result>
    </resultMap>


    <!--select语句执行的时候,查询的是一个对象,多个对象-->
    <!--
        resultType:表示查询的结果类型,只需要指定对应的映射类的类型,并且包含完整包接口
        resultMap:标签 当表的资源和类是属性字段名称不一致是,来自查询结果集的映射规则
    -->
    <select id="findByUsername" resultMap="UserEntityMap">
        SELECT * FROM t_user WHERE username = #{username}
    </select>


</mapper>

四.Service的编写

首先编写IUserService接口,只写方法,之后的service实现类都可以继承当前接口

package com.cy.store.service;

import com.cy.store.bean.User;

public interface IUserService{
    void reg(User user);
}

然后编写Service的实现类,即UserServiceImpl

package com.cy.store.service.impl;

import com.cy.store.bean.User;
import com.cy.store.mapper.UserMapper;
import com.cy.store.service.IUserService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.UsernameDuplicatedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.xml.crypto.Data;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.UUID;

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public void reg(User user) {
        //通过传来的user获取username
        String username = user.getUsername();
        //调用findByUsername(username)判断用户是否注册过
        User result = userMapper.findByUsername(username);
        //判断结果集不是null则抛出用户名被占用的异常
        if (result != null){
            //抛出异常
            throw new UsernameDuplicatedException("用户名被占用");
        }

        //密码加密处理实现:md5算法的形式
        //串 + password + 串 ----md5算法进行加密,连续加载三次
        //这个串是随机生成的,也叫做盐值
        String oldPassword = user.getPassword();
        //获取盐值
        String salt = UUID.randomUUID().toString().toUpperCase();//全大写
        //将密码和盐值作为一个整体进行加密处理
        String md5Password = getMD5Password(oldPassword, salt);
        //将加密之后的密码重新补全到user对象中
        user.setSalt(salt);//盐值栏存盐值的记录
        user.setMd5Password(md5Password);
        //存md5的密码
        //忽略了原有密码的安全强度,提升了数据的安全性


        //补全数据,is_delete设为0
        user.setIsDelete(0);
        //补全数据:四个日志字段信息
        user.setCreatedUser(user.getUsername());
        user.setModifiedUser(user.getUsername());
        Date date = new Date();
        user.setCreatedTime(date);
        user.setModifiedTime(date);

        //执行注册业务功能的实现
        Integer rows = userMapper.insert(user);
        if (rows != 1){
            throw new InsertException("用户注册过程中出现了未知的异常");
        }

    }


    /**
     * 定义一个md5算法的加密
     * */
    private String getMD5Password(String password,String salt){
        String s = "";
        for (int i = 0; i < 3; i++) {
            //MD5的加密算法加密三次
            s=DigestUtils.md5DigestAsHex((salt+password+salt).getBytes()).toUpperCase();
        }
        return s;
    }
}

 注:这里有关盐值了解了一些

在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”。

加密方式即在密码的前后都加上随机的盐值,然后对生成的字符串进行md5的加密操作,一般连续加密三次。

最后是三个异常的继承实现

package com.cy.store.service.ex;

/**
 * 数据插入过程中所产生的异常
 */
public class InsertException extends ServiceException{
    public InsertException() {
    }

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

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

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

    public InsertException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}
package com.cy.store.service.ex;

/**
 * 业务层异常基类
 */
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;

/**
 * 用户名被占用的异常
 */
public class UsernameDuplicatedException extends ServiceException{



    public UsernameDuplicatedException() {
        super();
    }

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

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

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

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

五.Controller的编写

package com.cy.store.controller;

import com.cy.store.bean.User;
import com.cy.store.service.IUserService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.UsernameDuplicatedException;
import com.cy.store.service.impl.UserServiceImpl;
import com.cy.store.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

//@Controller
@RestController//组合注解,相当于 @Controller + @ResponseBody
@RequestMapping("/users")
public class UserController extends BaseController{

    @Autowired
    private UserServiceImpl userService;

    @RequestMapping("reg")
    //@ResponseBody//表示此方法的响应结果以json的格式进行数据的响应给到前端
    public JsonResult<Void> req(User user){
        //创建响应结果对象
        //JsonResult<Void> result = new JsonResult<>();
        /**
         * 如果类很多的话,会重复以下代码多次
         * 则可以抽离一个父类,在父类中统一处理关于异常的相关操作
         * 编写一个BaseController,让当前类继承基类
         * */
        
        try {
            userService.reg(user);
            result.setState(200);
            result.setMessage("用户注册成功");
        }catch (UsernameDuplicatedException e){
           result.setState(404);
           result.setMessage("用户名被占用");
        }catch (InsertException e){
            result.setState(500);
            result.setMessage("注册时产生未知的异常");
        }
        return result;
         
    }
}

这样处理每一个方法都需要进行异常的处理,所以可以创建一个controller基类,专门用来对异常的处理

package com.cy.store.controller;

import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.ServiceException;
import com.cy.store.service.ex.UsernameDuplicatedException;
import com.cy.store.util.JsonResult;
import org.springframework.web.bind.annotation.ExceptionHandler;

/**
 * 用这个类表示控制层类的基类
 * */
public class BaseController {
    /* 操作成功的状态码 */
    public static final int OK = 200;

    /**
     * @ExceptionHandler 用于统一处理抛出的异常
     * 请求处理方法,这个方法的返回值就是要传递给前端的数据
     * 自动将异常对象传递给此方法的参数列表上
     *      当前项目中产生了异常,被统一拦截到此方法中,
     *      这个方法此时就充当请求处理方法,方法的返回值给到前端
     *
     */
    @ExceptionHandler({ServiceException.class})
    public JsonResult<Void> handleException(Throwable e){
        JsonResult<Void> result = new JsonResult<>(e);
        if (e instanceof UsernameDuplicatedException){
            result.setState(404);
            result.setMessage("用户名被占用");
        }else if (e instanceof InsertException){
            result.setState(500);
            result.setMessage("注册时产生未知的异常");
        }

        return result;
    }
}

添加基类后原代码变为

package com.cy.store.controller;

import com.cy.store.bean.User;
import com.cy.store.service.IUserService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.UsernameDuplicatedException;
import com.cy.store.service.impl.UserServiceImpl;
import com.cy.store.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

//@Controller
@RestController//组合注解,相当于 @Controller + @ResponseBody
@RequestMapping("/users")
public class UserController extends BaseController{

    @Autowired
    private UserServiceImpl userService;

    @RequestMapping("reg")
    //@ResponseBody//表示此方法的响应结果以json的格式进行数据的响应给到前端
    public JsonResult<Void> req(User user){

        /**
         * 继承基类后代码:
         * 如果遇到异常会被基类的 handleException处理
         * 加了@ExceptionHandler注解后悔自动将异常对象传递给此方法的参数列表上
         * */
        userService.reg(user);
        return new JsonResult<>(OK);
    }
}

JsonResult类:用来前后端交互,存放返回给前端的各种信息等

package com.cy.store.util;


import java.io.Serializable;

/**
 * Json格式的数据进行响应
 * */
public class JsonResult<E> implements Serializable {
    /*  状态码  */
    private Integer state;
    /*  描述信息  */
    private String message;
    /*  响应数据  */
    private E data;

    public JsonResult() {
    }

    public JsonResult(Integer state) {
        this.state = state;
    }

    public JsonResult(Throwable e) {
        this.message = e.getMessage();
    }

    public JsonResult(Integer state, E data) {
        this.state = state;
        this.data = data;
    }

    public JsonResult(Integer state, String message, E data) {
        this.state = state;
        this.message = message;
        this.data = data;
    }


    public Integer getState() {
        return state;
    }

    public void setState(Integer state) {
        this.state = state;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public E getData() {
        return data;
    }

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

猜你喜欢

转载自blog.csdn.net/m0_63061397/article/details/127952078