🍁
博客主页:👉@不会压弯的小飞侠
✨欢迎关注:👉点赞👍收藏⭐留言✒
✨系列专栏:👉SpringBoot电商项目实战
✨学习社区:👉不会压弯的小飞侠
✨知足上进,不负野心。
🔥欢迎大佬指正,一起学习!一起加油!

在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;
选中store数据库一>点击新建查询一>粘贴SQL语句一>运行t_user用户数据表就创建OK了

package com.jkj.entity;
import java.io.Serializable;
import java.util.Date;
/** 实体类的基类 */
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 String toString() {
return "BaseEntity{" +
"createdUser='" + createdUser + '\'' +
", createdTime=" + createdTime +
", modifiedUser='" + modifiedUser + '\'' +
", modifiedTime=" + modifiedTime +
'}';
}
}
package com.jkj.entity;
import java.io.Serializable;
import java.util.Objects;
/** 用户数据的实体类 */
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;
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 instanceof User)) return false;
User user = (User) o;
if (getUid() != null ? !getUid().equals(user.getUid()) : user.getUid() != null) return false;
if (getUsername() != null ? !getUsername().equals(user.getUsername()) : user.getUsername() != null)
return false;
if (getPassword() != null ? !getPassword().equals(user.getPassword()) : user.getPassword() != null)
return false;
if (getSalt() != null ? !getSalt().equals(user.getSalt()) : user.getSalt() != null) return false;
if (getPhone() != null ? !getPhone().equals(user.getPhone()) : user.getPhone() != null) return false;
if (getEmail() != null ? !getEmail().equals(user.getEmail()) : user.getEmail() != null) return false;
if (getGender() != null ? !getGender().equals(user.getGender()) : user.getGender() != null) return false;
if (getAvatar() != null ? !getAvatar().equals(user.getAvatar()) : user.getAvatar() != null) return false;
return getIsDelete() != null ? getIsDelete().equals(user.getIsDelete()) : user.getIsDelete() == null;
}
@Override
public int hashCode() {
int result = getUid() != null ? getUid().hashCode() : 0;
result = 31 * result + (getUsername() != null ? getUsername().hashCode() : 0);
result = 31 * result + (getPassword() != null ? getPassword().hashCode() : 0);
result = 31 * result + (getSalt() != null ? getSalt().hashCode() : 0);
result = 31 * result + (getPhone() != null ? getPhone().hashCode() : 0);
result = 31 * result + (getEmail() != null ? getEmail().hashCode() : 0);
result = 31 * result + (getGender() != null ? getGender().hashCode() : 0);
result = 31 * result + (getAvatar() != null ? getAvatar().hashCode() : 0);
result = 31 * result + (getIsDelete() != null ? getIsDelete().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 +
"} " + super.toString();
}
}
package com.jkj;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.sql.DataSource;
import java.sql.SQLException;
@SpringBootTest
class StoreApplicationTests {
@Autowired
private DataSource dataSource;
@Test
public void getConnection() throws SQLException {
System.out.println(dataSource.getConnection());
}
}

1.创建com.jkj.mapper.UserMapper接口,并在接口中添加抽象方法。
package com.jkj.mapper;
import com.jkj.entity.User;
public interface UserMapper {
/**
* 插入用户数据
* @param user 用户数据
* @return 受影响的行数
*/
Integer insert(User user);
/**
* 根据用户名查询用户数据
* @param username 用户名
* @return 匹配的用户数据,如果没有匹配的数据,则返回null
*/
User findByUsername(String username);
}
注意:
由于这是项目中第一次创建持久层接口,还应在StoreApplication启动类之前添加@MapperScan("com.jkj.mapper")注解,以配置接口文件的位置MyBatis与Spring整合后需要实现实体和数据表的映射关系。实现实体和数据表的映射关系可以在Mapper接口上添加@Mapper注解直接在SpringBoot启动类中加@MapperScan("mapper包") 注解,这样会比较方便,不需要对每个Mapper都添加@Mapper注解package com.jkj;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.jkj.mapper")
public class StoreApplication {
public static void main(String[] args) {
SpringApplication.run(StoreApplication.class, args);
}
}
<?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.jkj.mapper.UserMapper">
<resultMap id="UserEntityMap" type="com.jkj.entity.User">
<id column="uid" property="uid"/>
<result column="is_delete" property="isDelete"/>
<result column="created_user" property="createdUser"/>
<result column="created_time" property="createdTime"/>
<result column="modified_user" property="modifiedUser"/>
<result column="modified_time" property="modifiedTime"/>
</resultMap>
<!-- 插入用户数据:Integer insert(User user) -->
<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>
<!-- 根据用户名查询用户数据:User findByUsername(String username) -->
<select id="findByUsername" resultMap="UserEntityMap">
SELECT * FROM t_user WHERE username = #{username}
</select>
</mapper>
注意:
namespace属性:用于指定当前映射文件和哪个接口进行映射,需要指定接口的文件路径,需要标注包的完整路径接口result Type:表示查询的结果集类型,只需要指定对应映射类的类型。result Map:当表的资源和类的对象属性的字段不一致时,用来自定义查询结果集的映射规则。id属性:给这个映射分配唯一的id值和result Map=“id属性值”保持一致type属性:与java中哪个实体类进行结果集映射useGeneratedKeys属性:开启某个字段值的递增(主键设为递增)keyProperty属性:将表中的哪个字段作为主键进行自增2.这是项目中第一次使用SQL映射,所以需要在application.properties中添加mybatis.mapper-locations属性的配置,以指定XML文件的位置
mybatis.mapper-locations=classpath:mapper/*.xml
在测试类的声明之前添加@RunWith(SpringRunner.class)和@SpringBootTest注解,并在测试类中声明持久层对象,通过自动装配来注入值。@RunWith(SpringRunner.class)注解是一个测试启动器,可以加载SpringBoot测试注解。单元测试方法必须为public修饰,方法的返回值类型必须为void,方法不能有参数列表,并且方法被@Test注解修饰。// @RunWith(SpringRunner.class)注解是一个测试启动器,可以加载Springboot测试注解
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTests {
@Autowired
private UserMapper userMapper;
@Test
public void insert() {
User user = new User();
user.setUsername("xfx");
user.setPassword("123");
Integer rows = userMapper.insert(user);
System.out.println("rows=" + rows);
}
@Test
public void findByUsername() {
String username = "xfx";
User result = userMapper.findByUsername(username);
System.out.println(result);
}
}


package com.jkj.service.exception;
/** 业务异常的基类 */
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.jkj.service.exception;
/** 用户名重复的异常 */
public class UsernameDuplicateException extends ServiceException {
public UsernameDuplicateException() {
super();
}
public UsernameDuplicateException(String message) {
super(message);
}
public UsernameDuplicateException(String message, Throwable cause) {
super(message, cause);
}
public UsernameDuplicateException(Throwable cause) {
super(cause);
}
protected UsernameDuplicateException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package com.jkj.service.exception;
/** 插入数据的异常 */
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);
}
}
package com.jkj.service;
import com.jkj.entity.User;
/** 处理用户数据的业务层接口 */
public interface IUserService {
/**
* 用户注册
* @param user 用户数据
*/
void register(User user);
}
@Override
public void register(User user) {
// 根据参数user对象获取注册的用户名
// 调用持久层的User findByUsername(String username)方法,根据用户名查询用户数据
// 判断查询结果是否不为null
// 是:表示用户名已被占用,则抛出UsernameDuplicateException异常
// 创建当前时间对象
// 补全数据:加密后的密码
// 补全数据:盐值
// 补全数据:isDelete(0)
// 补全数据:4项日志属性
// 表示用户名没有被占用,则允许注册
// 调用持久层Integer insert(User user)方法,执行注册并获取返回值(受影响的行数)
// 判断受影响的行数是否不为1
// 是:插入数据时出现某种错误,则抛出InsertException异常
}
package com.jkj.service.impl;
import java.util.UUID;
import com.jkj.entity.User;
import com.jkj.mapper.UserMapper;
import com.jkj.service.IUserService;
import com.jkj.service.exception.InsertException;
import com.jkj.service.exception.UsernameDuplicateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import java.util.Date;
/** 处理用户数据的业务层实现类 */
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private UserMapper userMapper;
@Override
public void register(User user) {
// 根据参数user对象获取注册的用户名
String username = user.getUsername();
// 调用持久层的User findByUsername(String username)方法,根据用户名查询用户数据
User result = userMapper.findByUsername(username);
// 判断查询结果是否不为null
if (result != null) {
// 是:表示用户名已被占用,则抛出UsernameDuplicateException异常
throw new UsernameDuplicateException("尝试注册的用户名[" + username + "]已经被占用");
}
// 创建当前时间对象
Date now = new Date();
// 补全数据:加密后的密码
String salt = UUID.randomUUID().toString().toUpperCase();
String md5Password = getMd5Password(user.getPassword(), salt);
user.setPassword(md5Password);
// 补全数据:盐值
user.setSalt(salt);
// 补全数据:isDelete(0)
user.setIsDelete(0);
// 补全数据:4项日志属性
user.setCreatedUser(username);
user.setCreatedTime(now);
user.setModifiedUser(username);
user.setModifiedTime(now);
// 表示用户名没有被占用,则允许注册
// 调用持久层Integer insert(User user)方法,执行注册并获取返回值(受影响的行数)
Integer rows = userMapper.insert(user);
// 判断受影响的行数是否不为1
if (rows != 1) {
// 是:插入数据时出现某种错误,则抛出InsertException异常
throw new InsertException("添加用户数据出现未知错误,请联系系统管理员");
}
}
/**
* 执行密码加密
* @param password 原始密码
* @param salt 盐值
* @return 加密后的密文
*/
private String getMd5Password(String password, String salt) {
/*
* 加密规则:
* 1、无视原始密码的强度
* 2、使用UUID作为盐值,在原始密码的左右两侧拼接
* 3、循环加密3次
*/
for (int i = 0; i < 3; i++) {
password = DigestUtils.md5DigestAsHex((salt + password + salt).getBytes()).toUpperCase();
}
return password;
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTests {
@Autowired
private IUserService iUserService;
@Test
public void register() {
try {
User user = new User();
user.setUsername("lx");
user.setPassword("333333");
iUserService.register(user);
System.out.println("注册成功!");
} catch (ServiceException e) {
System.out.println("注册失败!" + e.getClass().getSimpleName());
System.out.println(e.getMessage());
}
}
}


package com.jkj.util;
import java.io.Serializable;
/**
* 响应结果类
* @param 响应数据的类型
*/
public class JsonResult<E> implements Serializable {
/** 状态码 */
private Integer state;
/** 状态描述信息 */
private String message;
/** 数据 */
private E data;
public JsonResult() {
super();
}
public JsonResult(Integer state) {
super();
this.state = state;
}
/** 出现异常时调用 */
public JsonResult(Throwable e) {
super();
// 获取异常对象中的异常信息
this.message = e.getMessage();
}
public JsonResult(Integer state, E data) {
super();
this.state = state;
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;
}
}
请求路径:/users/register
请求参数:User user
请求类型:POST
响应结果:JsonResult<Void>
/** 处理用户相关请求的控制器类 */
@RestController
@RequestMapping("users")
public class UserController extends BaseController {
@Autowired
private IUserService userService;
@RequestMapping("register")
public JsonResult<Void> register(User user) {
// 创建返回值
JsonResult<Void> result = new JsonResult<Void>();
try {
// 调用业务对象执行注册
userService.register(user);
// 响应成功
result.setState(200);
} catch (UsernameDuplicateException e) {
// 用户名被占用
result.setState(4000);
result.setMessage("用户名已经被占用");
} catch (InsertException e) {
// 插入数据异常
result.setState(5000);
result.setMessage("注册失败,请联系系统管理员");
}
return result;
}
}
http://localhost:8080/users/register?username=jkj&password=555555

/** 控制器类的基类 */
public class BaseController {
/** 操作成功的状态码 */
public static final int OK = 200;
/** @ExceptionHandler用于统一处理方法抛出的异常 */
@ExceptionHandler({ServiceException.class, FileUploadException.class})
public JsonResult<Void> handleException(Throwable e) {
JsonResult<Void> result = new JsonResult<Void>(e);
if (e instanceof UsernameDuplicateException) {
result.setState(4000);
} else if (e instanceof InsertException) {
result.setState(5000);
}
return result;
}
}
/** 处理用户相关请求的控制器类 */
@RestController
@RequestMapping("users")
public class UserController extends BaseController {
@Autowired
private IUserService userService;
@RequestMapping("register")
public JsonResult<Void> reg(User user) {
// 调用业务对象执行注册
userService.register(user);
// 返回
return new JsonResult<Void>(OK);
}
}
http://localhost:8080/users/register?username=jkj&password=555555(注册过的)
$("选择器")),再去添加点击的事件,$.ajax()函数发送异步请求。$.ajax({
ur1 : "",
type: "",
data: "",
dataType: "",
success : function( {
},
error : function( {
}
});
| 参数 | 功能描述 |
|---|---|
| url | 标识请求的地址(url地址),不能包含参数列表部分的内容。url:“localhost:8080/users/register” |
| type | 请求类型(GET和POST请求的类型)。 type: “POST” |
| data | 向指定的请求url地址提交的数据。data: “username=jkj&pwd=123” |
| dataType | 提交的数据的类型。数据的类型一般指定为json类型。dataType: “json” |
| success | 当服务器正常响应客户端时,会自动调用success参数的方法,并且将服务器返回的数据以参数的形式传递给这个方法的参数上 |
| error | 当服务器未正常响应客户端时,会自动调用error参数的方法,并且将服务器返回的数据以参数的形式传递给这个方法的参数上 |
在register.html页面中body标签内部的最后,添加script标签用于编写JavaScript程序。请求的url中需要添加项目的访问名称。
serialize()方法通过序列化表单值,创建URL编码文本字符串。
<!--页脚结束-->
<script type="text/javascript">
$("#btn-reg").click(function() {
console.log($("#form-reg").serialize());
$.ajax({
url: "/users/register",
type: "POST",
data: $("#form-reg").serialize(),
dataType: "json",
success: function(json) {
if (json.state == 200) {
alert("注册成功!");
} else {
alert("注册失败!" + json.message);
}
}
});
});
</script>


【SpringBoot项目实战完整版】SpringBoot+MyBatis+MySQL电脑商城项目实战-哔哩哔哩】
https://b23.tv/qGh9x9L