项目(SpringBoot+MyBatis)-- 注册功能实现

项目基本环境

1:JDK:1.8
2:maven:需要配置到idea,3.6.1版本
3:数据库:MariaDB,MySQL,要求是5.1版本
4:开发的平台:idea开发

1.创建数据库

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

2.创建用户的实体类

1.通过表的结构提取出表的公共字段,放在一个实体类的基类中,起名BaseEntity基类中

//实体类User因为要在网络中以流的形式传输,所以需要serialize序列化
//开发项目的时候需要在实体类上面加@Component然后spring才能自动进行对象的创建维护,而springboot不再需要,因为springboot遵循的原则是约定大于配置,如果字段名称相同那就可以自动完成字段的初始化
public class BaseEntity implements Serializable {
    private String createdUser;
    private Date createdTime;
    private String modifiedUser;
    private Date emodifiedTime;
/**
 * get,set
 * equals和hashCode
 * toString
 */
}

2.创建用户的实体类,并使其继承BaseEntity基类

public class User extends BaseEntity {
    private Integer uid;
    private String username;
    private String PASSWORD;
    private String salt;
    private String phone;
    private String email;
    private Integer gender;
    private String avatar;
    private Integer isDelete;
/**
 * get,set
 * equals和hashCode
 * toString
 */
}

3.注册-持久层

3.1设计接口和抽象方法及实现

public interface UserMapper {

    /**
     * 插入用户的数据
     * @param user 用户的数据
     * @return 受影响的行数(增删改都将受影响的行数作为返回值,可以根据返回值来判断是否执行成功)
     */
    Integer insert(User user);

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

3.2编写映射

<?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">
<!--将配置接口的方法对应到SQL语句上-->

<!--在sql语句的最上面借助ResultMap标签来自定义映射规则
    id属性:表示给这个映射规则分配一个唯一的id值,对应的就是resultMap="id属性值"
    type属性:取值是一个类,表示数据库中的查询结果与java中哪个实体类进行结果集的映射
 -->
<resultMap id="UserEntityMap" type="com.cy.store.entity.User">
    <!--将表的字段和类的属性名不一致的进行匹配指定,名称一致的也可以指定,但没必要
        但是,在定义映射规则时无论主键名称是否一致都不能省
        column属性:表示表中的字段名称
        property属性:表示类中的属性名称
        -->
    <id column="uid" property="uid"></id>
    <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>

<!--id属性:表示映射的接口中方法的名称,直接标签的内容部来编写SQL语句-->
<!--useGeneratedKeys="true"表示开启某个字段的值递增(大部分都是主键递增)
    keyProperty="uid"表示将表中哪个字段进行递增
    -->
<insert id="insert" useGeneratedKeys="true" keyProperty="uid">
    insert into t_user(
        username,`password`,salt,phone,email,gender,avatar,is_delete,
        created_user,created_time,modified_user,modified_time
    ) values (
    #{username},#{password},#{salt},#{phone},#{email},#{gender},#			{avatar},#{isDelete},#{createdUser},#{createdTime},#{modifiedUser},#	{modifiedTime}
    )
</insert>


<!--select语句在执行的时候查询的结果无非两种:一个对象或多个对象
    resultType:表示查询的结果集类型,用来指定对应映射类的类型,且包含完整的包结构,但此处不能是resultType="com.cy.store.entity.User",因为这种写法要求表的字段的名字和类的属性名一模一样
    resultMap:表示当表的字段和类的对象属性名不一致时,来自定义查询结果集的映射规则
-->
<select id="findByUsername" resultMap="UserEntityMap">
    select * from t_user where username=#{username}
</select>

</mapper>

4.注册-业务层

4.1规划异常(后续用到的异常都要继承ServiceException类并重写里面的所有方法)

/**
 * 因为整个业务的异常只有一种情况下才会产生:只有运行时才会产生,不运行不会产生
 * 所以要求业务层的异常都要继承运行时异常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);
    }
}

4.2设计接口和抽象方法
1.在service包下创建IUserService接口(接口命名的默认规则:I+业务名字+层的名字)

/**用户模块业务层接口*/
public interface IUserService {
    /**
     * 用户注册方法
     * @param user 用户的数据对象
     */
    void reg(User user);
}

2.创建一个实现UserServiceImpl类,需要实现IUserService接口,并且实现抽象的方法

@Service
public class UserServiceImpl implements IUserService {

    //reg方法核心就是调用mapper层的方法,所以要声明UserMapper对象并加@Autowired注解
    @Autowired
    private UserMapper userMapper;

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

        /**
         * 密码加密处理作用:
         * 1.后端不再能直接看到用户的密码2.忽略了密码原来的强度,提升了数据安全性
         * 密码加密处理的实现:
         * 串+password+串->交给md5算法连续加密三次
         * 串就是数据库字段中的盐值,是一个随机字符串
         */
        String oldpassword = user.getPassword();
        //1.随机生成一个盐值(大写的随机字符串)
        String salt = UUID.randomUUID().toString().toUpperCase();
        //2.将密码和盐值作为一个整体进行加密处理
        String md5Password = getMD5Password(oldpassword, salt);
        //3.将盐值保存到数据库
        user.setSalt(salt);
        //4.将加密之后的密码重新补全设置到user对象当中
        user.setPassword(md5Password);

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


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



private String getMD5Password(String password,String salt) {
    for (int i = 0; i < 3; i++) {
        password = DigestUtils.md5DigestAsHex((salt + password + salt).getBytes()).toUpperCase();
    }
    return password;
}

}

5.注册-控制层

5.1创建响应
状态码,状态描述信息,数据是所有控制层对应的方法都涉及到的操作,所以把这部分功能封装到一个类JsonResult中,将这个类作为方法的返回值返回给前端浏览器:

//因为所有的响应的结果都采用Json格式的数据进行响应,所以需要实现Serializable接口
public class JsonResult<E> implements Serializable {
    //状态码
    private Integer state;
    //描述信息
    private String message;
    //数据类型不确定,用E表示任何的数据类型,一个类里如果声明的有泛型的数据类型,类也要声明为泛型
    private E data;
	
    //无参构造
    public JsonResult() {
    }

    //将状态码传给构造方法初始化对象
    public JsonResult(Integer state) {
        this.state = state;
    }


    //将状态码和数据传给构造方法初始化对象
    public JsonResult(Integer state, E data) {
        this.state = state;
        this.data = data;
    }

    //如果有异常,直接将异常传递给构造方法初始化对象
    public JsonResult(Throwable e) {
        this.message=e.getMessage();
    }
    /**以及属性的get和set方法*/
}

5.2处理请求

1.在controller包下创建UserController类作为控制层下类的基类,用来做统一的异常捕获:

public class BaseController {

    //操作成功的状态码
    public static final int OK = 200;

    /**
     * 1.@ExceptionHandler表示该方法用于处理捕获抛出的异常
     * 2.什么样的异常才会被这个方法处理呢?所以需要ServiceException.class,这样的话只要是抛出ServiceException异常就会被拦截到handleException方法,此时handleException方法就是请求处理方法,返回值就是需要传递给前端的数据
     * 3.被ExceptionHandler修饰后如果项目发生异常,那么异常对象就会被自动传递给此方法的参数列表上,所以形参就需要写Throwable e用来接收异常对象
     */
    @ExceptionHandler(ServiceException.class)
    public JsonResult<Void> handleException(Throwable e) {
        JsonResult<Void> result = new JsonResult<>(e);
        if (e instanceof UsernameDuplicatedException) {
            result.setState(4000);
            result.setMessage("用户名已经被占用");
        } else if (e instanceof InsertException) {
            result.setState(5000);
            result.setMessage("插入数据时产生未知的异常");
        }
        return result;
    }
}

2.让UserController继承BaseController使得reg方法只需要关注请求处理而不再需要关注异常捕获:

@RestController //其作用等同于@Controller+@ResponseBody
//@Controller
@RequestMapping("users")
public class UserController extends BaseController {

    @Autowired
    private IUserService userService;

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

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值