SpringBoot+MyBatis+MySQL电脑商城项目实战(二)用户注册—持久层
用户注册
1 创建数据表
- 选中数据表
use store
- 创建t_user
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 创建用户实体类
- 通过表的结构提取出表的公共字段,放在一个实体类的基类中,起名叫BaseEntity基类中
- 声明私有属性变量
- 声明私有属性的get,set方法
- 生成equals和hashCode()方法
- toString()方法
package com.cy.store.entity;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
/**
* 作为实体类的基类
*/
//@Data
public class BaseEntity implements Serializable {
private String createdUser;
private Date createdTime;
private String modifiedUser;
private Date 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;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BaseEntity that = (BaseEntity) o;
if (!Objects.equals(createdUser, that.createdUser)) return false;
if (!Objects.equals(createdTime, that.createdTime)) return false;
if (!Objects.equals(modifiedUser, that.modifiedUser)) return false;
return Objects.equals(modifiedTime, that.modifiedTime);
}
@Override
public String toString() {
return "BaseEntity{" +
"createdUser='" + createdUser + '\'' +
", createdTime=" + createdTime +
", modifiedUser='" + modifiedUser + '\'' +
", modifiedTime=" + modifiedTime +
'}';
}
@Override
public int hashCode() {
int result = createdUser != null ? createdUser.hashCode() : 0;
result = 31 * result + (createdTime != null ? createdTime.hashCode() : 0);
result = 31 * result + (modifiedUser != null ? modifiedUser.hashCode() : 0);
result = 31 * result + (modifiedTime != null ? modifiedTime.hashCode() : 0);
return result;
}
}
- 创建用户的实体类。需要继承BaseEntity基类
package com.cy.store.entity;
import java.io.Serializable;
import java.util.Objects;
/**
* 用户的实体类:SpringBoot约定大于配置
*/
public class User extends BaseEntity implements Serializable {
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;
//1、get和set方法,equals和hashCode(),toString()方法
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;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
User user = (User) o;
if (!Objects.equals(uid, user.uid)) return false;
if (!Objects.equals(username, user.username)) return false;
if (!Objects.equals(password, user.password)) return false;
if (!Objects.equals(salt, user.salt)) return false;
if (!Objects.equals(phone, user.phone)) return false;
if (!Objects.equals(email, user.email)) return false;
if (!Objects.equals(gender, user.gender)) return false;
if (!Objects.equals(avatar, user.avatar)) return false;
return Objects.equals(isDelete, user.isDelete);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (uid != null ? uid.hashCode() : 0);
result = 31 * result + (username != null ? username.hashCode() : 0);
result = 31 * result + (password != null ? password.hashCode() : 0);
result = 31 * result + (salt != null ? salt.hashCode() : 0);
result = 31 * result + (phone != null ? phone.hashCode() : 0);
result = 31 * result + (email != null ? email.hashCode() : 0);
result = 31 * result + (gender != null ? gender.hashCode() : 0);
result = 31 * result + (avatar != null ? avatar.hashCode() : 0);
result = 31 * result + (isDelete != null ? isDelete.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "User{" +
"uid=" + uid +
", username='" + username + '\'' +
", password='" + password + '\'' +
", salt='" + salt + '\'' +
", phone='" + phone + '\'' +
", email='" + email + '\'' +
", gender=" + gender +
", avatar='" + avatar + '\'' +
", isDelete=" + isDelete +
'}';
}
}
3 注册-持久层
通过MyBatis来操作数据库。在做MyBatis开发的流程。
3.1 规划需要执行的SQL语句
- 用户的注册功能,相当于在做数据的插入操作。
insert into t_user(user,password) values (值列表)
- 在用户的注册时首先要去查询当前的用户名是否存在,如果存在则不能进行注册,相当于是一条查询语句。
select * from t_user where username = ?
3.2 设计接口和抽象方法
- 定义mapper接口。在项目的目录结构下首先创建一个mapper接口,在这个包下再根据不同的功能模块来创建mapper接口。创建一个UserMapper的接口。要在接口中定义这两个SQL语句的抽象方法。
- 在启动类配置mapper接口文件的位置
//MapperScan注解指定当前项目中的Mapper接口路径的位置,在项目启动的时候会自动加载所有的接口文件
@MapperScan("com.cy.mapper")
3.3 编写映射
- 定义xml映射文件,与对应的接口进行关联。所有的映射文件需要放置resources目录下,在这个目录下创建一个mapper文件夹,在这个文件夹下存放Mapper的映射文件。
- 创建接口对应的映射文件,遵循和接口的名称保持一致即可。创建一个UserMapper.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">
<!--namespace属性:用于指定当前的映射文件和哪个接口进行映射,需要指定接口的文件路径,需要标注包的完整路径结构-->
<mapper namespace="com.cy.store.mapper.UserMapper">
</mapper>
- 配置接口中的方法对应SQL语句上。需要借助标签来完成,insert/update/delete/select,对应的是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">
<!--自定义映射规则:resultMap标签来完成映射规则的定义-->
<!--
id属性:标签给这个映射负责分配一个唯一的id值,对应的就是resultMap="id属性值"属性的取值
type属性:取值是一个类,表示的时数据库中的查询结果与Java中哪个实体类进行结果集的映射
-->
<resultMap id="UserEntityMap" type="com.cy.store.entity.User">
<!--将表的字段和类的属性不一致的字段进行匹配指定,名称一致的字段可以省略不写-->
<!--
配合完成名称不一致的映射
column属性:表示表中的资源名称
property属性:表示类中的属性名称
-->
<!--在定义映射规则时,主键是不可以省略的,无论名称是否一致-->
<id column="id" 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属性:表示开启某个字段的值递增(主键设置为递增)
keyProperty属性:表示将表中的哪个字段作为主键进行递增,uid不是uuid
-->
<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:表示查询的结果集类型,只需要指定对应映射类的类型,并且包含完完整包接口-->
<!--resultMap:表示当表的字段和类的对象属性的字段名称不一致时,来自定义查询结果集的映射规则。-->
<select id="findByUsername" resultMap="UserEntityMap">
select * from t_user where username = #{username}
</select>
</mapper>
-
单元测试:每个独立的层编写完毕后需要编写单元测试方法,来测试当前的功能。在test包结构下创建一个mapper包,在这个包下再创建持久层的功能测试。
接口自动装配时,显示无法自动装配,显示红色波浪线的解决办法:
setting→inspections→Spring→Spring Core
![image]()
package com.cy.store.mapper;
import com.cy.store.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
//@SpringBootTest:表示标注当前的类是一个测试类,不会随同项目一块打包
@SpringBootTest
//@RunWith:表示启动这个单元测试类(不写这个注解的话单元测试类是不能够运行的),需要传递一个参数,必须是SpringRunner的实例类型
@RunWith(SpringRunner.class)
public class UserMapperTests {
/*
* 报无法自动装载的原因:
* idea有检测的功能,接口是不能够直接创建Bean的,MyBatis创建了接口的动态代理,实现类来完成了对象的创建(底层动态代理技术来解决)
* */
@Autowired
private UserMapper userMapper;
/*单元测试方法特点:就可以单独独立运行,不用启动整个项目,可以做单元测试,提升了代码的测试效率
* 1、必须被Test注解修饰
* 2、返回值类型必须是void
* 3、方法的参数列表不指定任何类型
* 4、方法的访问修饰符必须是public
* */
@Test
public void insert(){
User user = new User();
user.setUsername("water");
user.setPassword("123");
Integer rows = userMapper.insert(user);
System.out.println(rows);
}
@Test
public void findByUsername(){
User user = userMapper.findByUsername("water");
System.out.println(user);
}
}


浙公网安备 33010602011771号