• 【电商项目实战】用户注册(详细篇)


    🍁博客主页:👉@不会压弯的小飞侠
    欢迎关注:👉点赞👍收藏留言
    系列专栏:👉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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 选中store数据库一>点击新建查询一>粘贴SQL语句一>运行
    • t_user用户数据表就创建OK了

    在这里插入图片描述

    在这里插入图片描述

    🍁创建实体类

    • 项目中许多实体类都会有日志相关的四个属性,所以在创建实体类之前,应先创建这些实体类的基类,将4个日志属性声明在基类中。在com.jkj.entity包下创建BaseEntity类作为实体类的基类。
    • 因为这个基类的作用就是用于被其它实体类继承的,所以应声明为抽象类。
    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 +
                    '}';
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 创建com.jkj.entity.User用户数据的实体类,继承自BaseEntity类,在类中声明与数据表中对应的属性。
    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();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139

    🍁注册-持久层

    🔥准备工作

    • 在src/test/java下的com.jkj.StoreApplicationTests测试类中编写并执行“获取数据库连接”的单元测试,以检查数据库连接的配置是否正确。
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 测试成功

    在这里插入图片描述

    🔥创建接口与抽象方法

    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);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 注意:
      • 由于这是项目中第一次创建持久层接口,还应在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);
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    🔥配置SQL映射

    • 1.在src/main/resources下创建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">
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 注意:

      • 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
    
    • 1
    • 3.完成后及时执行单元测试,检查以上开发的功能是否可正确运行。
      • 在src/test/java下创建com.jkj.mapper.UserMapperTests单元测试类
      • 在测试类的声明之前添加@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);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 插入数据和查询数据测试成功

    在这里插入图片描述
    在这里插入图片描述

    🍁注册-业务层

    • 业务的定位
      • 1.业务:一套完整的数据处理过程,通常表现为用户认为的一个功能,但是在开发时对应多项数据操作。在项目中,通过业务控制每个“功能”(例如注册、登录等)的处理流程和相关逻辑。
      • 2.流程:先做什么,再做什么。例如:注册时,需要先判断用户名是否被占用,再决定是否完成注册。
      • 3.逻辑:能干什么,不能干什么。例如:注册时,如果用户名被占用,则不允许注册;反之,则允许注册。
      • 4.业务的主要作用是保障数据安全和数据的完整性、有效性。

    🔥异常规划

    • 为了便于统一管理自定义异常,应先创建com.jkj.service.exception.ServiceException自定义异常的基类异常,继承自RuntimeException类,并从父类生成子类的五个构造法。
    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);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 当用户进行注册时,可能会因为用户名被占用而导致无法正常注册,此时需要抛出用户名被占用的异常,因此可以设计一个用户名重复的com.jkj.service.exception.UsernameDuplicateException异常类,继承自ServiceException类,并从父类生成子类的五个构造方法。
    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);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 在用户进行注册时,会执行数据库的INSERT操作,该操作也是有可能失败的。则创建
      com.jkj.service.exception.InsertException`异常类,继承自ServiceException类,并从父类生成子类的5个构造方法。
    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);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    🔥接口与抽象方法

    • 先创建com.jkj.service.IUserService业务层接口,并在接口中添加抽象方法。
    package com.jkj.service;
    
    
    import com.jkj.entity.User;
    
    /** 处理用户数据的业务层接口 */
    public interface IUserService {
        /**
         * 用户注册
         * @param user 用户数据
         */
        void register(User user);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    🔥实现抽象方法

    • 创建com.jkj.service.impl.UserServiceImpl业务层实现类,并实现IUserService接口。在类之前添加@Service注解,并在类中添加持久层UserMapper对象。
    • UserServiceImpl类需要重写IUserService接口中的抽象方法,实现步骤大致是:
    @Override
    public void register(User user) {
    // 根据参数user对象获取注册的用户名
    // 调用持久层的User findByUsername(String username)方法,根据用户名查询用户数据
    // 判断查询结果是否不为null
    // 是:表示用户名已被占用,则抛出UsernameDuplicateException异常
    // 创建当前时间对象
    // 补全数据:加密后的密码
    // 补全数据:盐值
    // 补全数据:isDelete(0)
    // 补全数据:4项日志属性
    // 表示用户名没有被占用,则允许注册
    // 调用持久层Integer insert(User user)方法,执行注册并获取返回值(受影响的行数)
    // 判断受影响的行数是否不为1
    // 是:插入数据时出现某种错误,则抛出InsertException异常
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    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;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 完成后在src/test/java下创建com.jkj.service.UserServiceTests测试类,编写并执行用户注册业务层的单元测试。
    
    @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());
            }
        }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 插入数据测试成功

    在这里插入图片描述

    • 数据库显示插入成功

    在这里插入图片描述

    🍁注册-控制器

    🔥创建响应结果类

    • 创建com.jkj.util.JsonResult响应结果类型。
    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;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    🔥设计请求

    • 设计用户提交的请求,并设计响应的方式:
    请求路径:/users/register
    请求参数:User user
    请求类型:POST
    响应结果:JsonResult<Void>
    
    • 1
    • 2
    • 3
    • 4

    🔥处理请求

    • 创建com.jkj.controller.UserController控制器类,在类的声明之前添加@RestController和
      @RequestMapping(“users”)注解,在类中添加IUserService业务对象并使用@Autowired注解修饰,然后在类中添加处理请求的用户注册方法。
    /** 处理用户相关请求的控制器类 */
    @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;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 启动项目,去浏览器访问:http://localhost:8080/users/register?username=jkj&password=555555
    • 测试结果:

    在这里插入图片描述

    • 去数据库查看是否插入成功

    在这里插入图片描述

    🔥改进控制层

    • 创建提供控制器类的基类com.jkj.controller.BaseController,在其中定义表示响应成功的
      状态码及统一处理异常的方法。
    • @ExceptionHandler注解用于统一处理方法抛出的异常。当我们使用这个注解时,需要定义一个异常的处理方法,再给这个方法加上@ExceptionHandler注解,这个方法就会处理类中其他方法(被@RequestMapping注解)抛出的异常。@ExceptionHandler注解中可以添加参数,参数是某个异常类的class,代表这个方法专门处理该类异常。
    /** 控制器类的基类 */
    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;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 简化UserController控制器类中的用户注册register()方法的代码。
    /** 处理用户相关请求的控制器类 */
    @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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 启动项目,去浏览器访问:http://localhost:8080/users/register?username=jkj&password=555555(注册过的)
    • 测试结果:
      在这里插入图片描述

    🍁注册-前端页面

    • 1.在register页面中编写发送请求的方法,点击事件来完成。选选中对应的按钮($("选择器")),再去添加点击的事件,$.ajax()函数发送异步请求。
    • 2.JQUery封装了一个函数,称之为$.ajax()函数,通过对象调用ajax()函数,可以异步加载相关的请求。依靠的是Javascript提供的一个对象XHR (XmlHttpResponse),封装了这个对象。
    • 3.ajax()使用方式。需要传递一个方法体作为方法的参数来使用,一对大括号称之为方法体。ajax接收多个参数,参数与参数之间要求使用"∵,"进行分割,语法结构:
    $.ajax({
        ur1 : "",
        type: "",
        data: "",
        dataType: "",
        success : function( {
        },
       error : function( {
       }
    });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    参数功能描述
    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 后启动项目,打开浏览器访问http://localhost:8080/web/register.html页面并进行注册。
    • 提示注册成功

    在这里插入图片描述

    • 去数据库查看到底插入成功没。

    在这里插入图片描述

    • 注意:
    • js代码无法正常被服务器解析执行,体现在点击页面中的按钮没有任何的响应。
      • 在项目的maven下clear清理项目-install重新部署
      • 在项目的file选项下-cash清理缓存
      • 重新的去构建项目: build选项下-rebuild选项重启idea
      • 重启电脑

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

  • 相关阅读:
    SVN教程-SVN的基本使用
    【题目集2】链表经典题目
    基于nodejs的二手物物交换平台【毕业设计源码】
    SystemVerilog——面向对象编程
    react之组件与JSX
    【GPGPU编程模型与架构原理】第一章1.2 GPGPU 发展概述
    金仓数据库KingbaseES客户端编程接口指南-DCI(6. 附录-DCI错误码)
    UniApp iOS 原生插件开发之插件包格式
    统信UOS升级Python3及安装spyder5
    MQTT连接阿里云物联网上报物模型数据
  • 原文地址:https://blog.csdn.net/qq_43514330/article/details/126285200