用springboot做一个电脑商城项目,第一天

系统概述与环境搭建

1 系统开发及运行环境

学习的视频地址【SpringBoot项目实战完整版】SpringBoot+MyBatis+MySQL电脑商城项目实战_哔哩哔哩_bilibili

电脑商城系统开发所需的环境及相关软件进行介绍。

1.操作系统:Windows 10

2.Java开发包:JDK 8

3.项目管理工具:Maven 3.6.3

4.项目开发工具:IntelliJ IDEA 2020.3.2 x64

5.数据库:MariaDB-10.3.7-winx64

6.浏览器:Google Chrome

7.服务器架构:Spring Boot 2.4.7 + MyBatis 2.1.4 + AJAX

2 项目分析

1.在开发某个项目之前,应先分析这个项目中可能涉及哪些种类的数据。本项目中涉及的数据:用户、商品、商品类别、收藏、订单、购物车、收货地址。

2.关于数据,还应该要确定这些数据的开发顺序。设计开发顺序的原则是:先开发基础、简单或熟悉的数据。以上需要处理的数据的开发流程是:用户-收货地址-商品类别-商品-收藏-购物车-订单。

3.在开发每种数据的相关功能时,先分析该数据涉及哪些功能。在本项目中以用户数据为例,需要开发的功能有:登录、注册、修改密码、修改资料、上传头像。

4.然后,在确定这些功能的开发顺序。原则上,应先做基础功能,并遵循增查删改的顺序来开发。则用户相关功能的开发顺序应该是:注册-登录-修改密码-修改个人资料-上传头像。

5.在实际开发中,应先创建该项目的数据库,当每次处理一种新的数据时,应先创建该数据在数据库中的数据表,然后在项目中创建该数据表对应的实体类。

6.在开发某个具体的功能时,应遵循开发顺序:持久层-业务层-控制器-前端页面。

3 创建数据库

1.首先确保计算机上安装了MariaDB-10.3.7-winx64数据库,将来在数据库中创建与项目相关的表。

2.创建电脑商城项目对应的后台数据库系统store。

CREATE DATABASE store character SET utf8;

4 创建Spring Initializr项目

本质上Spring Initializr是一个Web应用程序,它提供了一个基本的项目结构,能够帮助开发者快速构建一个基础的Spring Boot项目。在创建Spring Initializr类型的项目时需在计算机连网的状态下进行创建。

1.首先确保计算机上安装了JDK、IDEA、MariaDB等开发需要使用的软件,并在IDEA中配置了Maven 3.6.3项目管理工具。

2.在IDEA欢迎界面,点击【New Project】按钮创建项目,左侧选择【Spring Initializr】选项进行Spring Boot项目快速构建。

3.将Group设置为com.cy,Artifact设置为store,其余选项使用默认值。单击【Next】进入Spring Boot场景依赖选择界面。

4.给项目添加Spring Web、MyBatis Framework、MySQL Driver的依赖。点击【Next】按钮完成项目创建。

5.首次创建完Spring Initializr项目时,解析项目依赖需消耗一定时间(Resolving dependencies of store...)。

5 配置并运行项目

5.1 运行项目

找到项目的入口类(被@SpringBootApplication注解修饰),然后运行启动类;启动过程如果控制台输出Spring图形则表示启动成功。

在我的电脑上将版本号设置成2.5.6就会运行失败,降级成2.5.5并且重启运行成功成功出现Spring图标!

package com.cy.store;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
​
@SpringBootApplication
public class StoreApplication {
    public static void main(String[] args) {
        SpringApplication.run(StoreApplication.class, args);
    }
}

5.2 配置项目

1.如果启动项目时提示:“配置数据源失败:'url'属性未指定,无法配置内嵌的数据源”。有如下的错误提示。

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

2.解决以上操作提示的方法:在resources文件夹下的application.properties文件中添加数据源的配置。

spring.datasource.url=jdbc:mysql://localhost:3306/store?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456

3.为了便于查询JSON数据,隐藏没有值的属性,减少流量的消耗,服务器不应该向客户端响应为NULL的属性。可以在属性或类之前添加@JsonInclude(value=Include.NON_NULL),也可以在application.properties中添加全局的配置。

# 服务器向客户端不响应为null的属性
spring.jackson.default-property-inclusion=NON_NULL

4.SpringBoot项目的默认访问名称是“/”,如果需要修改可以手动在配置文件中指定SpringBoot 2.x访问项目路径的项目名。不建议修改。

server.servlet.context-path=/store

5.重新启动项目,则不在提示配置数据源失败的问题

6.在单元测试类中测试数据库的连接是否能够正常的加载

@Autowiredprivate 
DataSource dataSource;
@Test
void getConnection(){    
try {        
System.out.println(dataSource.getConnection());    
} catch (SQLException throwables) {  
      throwables.printStackTrace();   
 }

证明数据库连接成功

Springboot默认连接池是Hikari

用户注册

1 用户-创建数据表

1.使用use命令先选中store数据库。

USE store;

2.在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 用户-创建实体类

1.项目中许多实体类都会有日志相关的四个属性,所以在创建实体类之前,应先创建这些实体类的基类,将4个日志属性声明在基类中。在com.cy.store.entity包下创建BaseEntity类,作为实体类的基类。

package com.cy.store.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;
​
    // Generate: Getter and Setter、toString()
}
​

因为这个基类的作用就是用于被其它实体类继承的,所以应声明为抽象类。

2.创建com.cy.store.entity.User用户数据的实体类,继承自BaseEntity类,在类中声明与数据表中对应的属性。

package com.cy.store.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;
​
    // Generate: Getter and Setter、Generate hashCode() and equals()、toString()
}

3 用户-注册-持久层

3.1 准备工作

1.在src/test/java下的com.cy.store.StoreApplicationTests测试类中编写并执行“获取数据库连接”的单元测试,以检查数据库连接的配置是否正确。

@Autowired
private DataSource dataSource;
​
@Test
public void getConnection() throws Exception {
    System.out.println(dataSource.getConnection());
}

2.执行src/test/java下的com.cy.toreApplicationTests测试类中的contextLoads()测试方法,以检查测试环境是否正常。

3.2 规划需要执行的SQL语句

1.用户注册的本质是向用户表中插入数据,需要执行的SQL语句大致是:

INSERT INTO t_user (除了uid以外的字段列表) VALUES (匹配的值列表)

2.由于数据表中用户名字段被设计为UNIQUE,在执行插入数据之前,还应该检查该用户名是否已经被注册,因此需要有“根据用户名查询用户数据”的功能。需要执行的SQL语句大致是:

SELECT * FROM t_user WHERE username=?

3.3 接口与抽象方法

1.创建com.cy.store.mapper.UserMapper接口,并在接口中添加抽象方法。

package com.cy.mapper;
import com.cy.store.entity.User;
​
/** 处理用户数据操作的持久层接口 */
public interface UserMapper {
    /**
     * 插入用户数据
     * @param user 用户数据
     * @return 受影响的行数
     */
    Integer insert(User user);
​
    /**
     * 根据用户名查询用户数据
     * @param username 用户名
     * @return 匹配的用户数据,如果没有匹配的数据,则返回null
     */
    User findByUsername(String username);
}

2.由于这是项目中第一次创建持久层接口,还应在StoreApplication启动类之前添加@MapperScan("com.cy.store.mapper")注解,以配置接口文件的位置。

MyBatis与Spring整合后需要实现实体和数据表的映射关系。实现实体和数据表的映射关系可以在Mapper接口上添加@Mapper注解。但建议以后直接在SpringBoot启动类中加@MapperScan("mapper包") 注解,这样会比较方便,不需要对每个Mapper都添加@Mapper注解。

@SpringBootApplication
@MapperScan("com.cy.store.mapper")
public class StoreApplication {
​
    public static void main(String[] args) {
        SpringApplication.run(StoreApplication.class, args);
    }
}

3.4 配置SQL映射

1.在src/main/resources下创建mapper文件夹,并在该文件夹下创建UserMapper.xml映射文件,进行以上两个抽象方法的映射配置。




    
        
        
        
        
        
        
    
    
    
        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})
    
​
    
    

2.由于这是项目中第一次使用SQL映射,所以需要在application.properties中添加mybatis.mapper-locations属性的配置,以指定XML文件的位置。

mybatis.mapper-locations=classpath:mapper/*.xml

3.完成后及时执行单元测试,检查以上开发的功能是否可正确运行。在src/test/java下创建com.cy.store.mapper.UserMapperTests单元测试类,在测试类的声明之前添加@RunWith(SpringRunner.class)和@SpringBootTest注解,并在测试类中声明持久层对象,通过自动装配来注入值。

@RunWith(SpringRunner.class)注解是一个测试启动器,可以加载SpringBoot测试注解。

package com.cy.store.mapper;
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;
​
// @RunWith(SpringRunner.class)注解是一个测试启动器,可以加载Springboot测试注解
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTests {
    @Autowired
    private UserMapper userMapper;
​
}

导包的时候junit的版本必须控制在4.12,否则在我的电脑是哪个会出现runner包找不到,导致runwith注解不可用

4.如果在第四步自动装配userMapper时,报“Could not autowire. No beans of 'UserMapper' type found”错,无法进行自动装配。解决方案是,将Autowiring for bean class选项下的Severity设置为Warning即可。

5.然后编写两个测试方法,对以上完成的两个功能进行单元测试。

单元测试方法必须为public修饰,方法的返回值类型必须为void,方法不能有参数列表,并且方法被@Test注解修饰。

@Test
public void insert() {
    User user = new User();
    user.setUsername("user01");
    user.setPassword("123456");
    Integer rows = userMapper.insert(user);
    System.out.println("rows=" + rows);
}
​
@Test
public void findByUsername() {
    String username = "user01";
    User result = userMapper.findByUsername(username);
    System.out.println(result);
}

如果出现org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)异常可能原因:

1.在resources文件加下创建的mapper文件夹类型没有正确选择(eclipse选择Folder,idea选择Directory)。

2.映射文件的mapper标签的namespace属性没有正确映射到dao层接口,或者application.properties中的属性mybatis.mapper-locations没有正确配置xml映射文件。

 

几个错误:

1.数据库的连接必须要在右边连接上并且将设置中的sql语句解析范围勾选正确的表,mapper.xml中的表才能被正确读出

2.一个粗心的错误,找了半天的连不上数据库的原因竟然是在配置文件的url中没有写明是哪一个表

3.instantiating interface com.xu.supermarket2.mapper.UserMapper with invalid types () or values ()

错误提示使用无效的类型或者值实例化接口


    
    
    
    
    
    
    

 

错误原因在写resultmap时将type类型写成了UserMappper接口

实际上应该返回的是一个User实体类,低级错误

4 用户-注册-业务层

4.1 业务的定位

1.业务:一套完整的数据处理过程,通常表现为用户认为的一个功能,但是在开发时对应多项数据操作。在项目中,通过业务控制每个“功能”(例如注册、登录等)的处理流程和相关逻辑。

2.流程:先做什么,再做什么。例如:注册时,需要先判断用户名是否被占用,再决定是否完成注册。

3.逻辑:能干什么,不能干什么。例如:注册时,如果用户名被占用,则不允许注册;反之,则允许注册。

4.业务的主要作用是保障数据安全和数据的完整性、有效性。

4.2 规划异常

1.关于异常

1.请列举你认识的不少于十种异常:

Throwable
    Error
        OutOfMemoryError(OOM)
    Exception
        SQLException
        IOException
            FileNotFoundException
        RuntimeException
            NullPointerException
            ArithmeticException
            ClassCastException
            IndexOutOfBoundsException
                ArrayIndexOutOfBoundsException
                StringIndexOutOfBoundsException

2.异常的处理方式和处理原则:

异常的处理方式有:捕获处理(try...catch...finally),声明抛出(throw/throws)。如果当前方法适合处理,则捕获处理;如果当前方法不适合处理,则声明抛出。

2.异常规划

1.为了便于统一管理自定义异常,应先创建com.cy.store.service.ex.ServiceException自定义异常的基类异常,继承自RuntimeException类,并从父类生成子类的五个构造方法。

package com.cy.store.service.ex;
​
/** 业务异常的基类 */
public class ServiceException extends RuntimeException {
    // Override Methods...  
}

2.当用户进行注册时,可能会因为用户名被占用而导致无法正常注册,此时需要抛出用户名被占用的异常,因此可以设计一个用户名重复的com.cy.store.service.ex.UsernameDuplicateException异常类,继承自ServiceException类,并从父类生成子类的五个构造方法。

package com.cy.store.service.ex;
​
/** 用户名重复的异常 */
public class UsernameDuplicateException extends ServiceException {
    // Override Methods...
}

3.在用户进行注册时,会执行数据库的INSERT操作,该操作也是有可能失败的。则创建cn.tedu.store.service.ex.InsertException`异常类,继承自ServiceException类,并从父类生成子类的5个构造方法。

package com.cy.store.service.ex;
​
/** 插入数据的异常 */
public class InsertException extends ServiceException {
    // Override Methods...
}

4.所有的自定义异常,都应是RuntimeException的子孙类异常。项目中目前异常的继承结构是见下。

RuntimeException
    -- ServiceException
        -- UsernameDuplicateException
        -- InsertException

4.3 接口与抽象方法

1.先创建com.cy.store.service.IUserService业务层接口,并在接口中添加抽象方法。

package com.cy.store.service;
import com.cy.store.entity.User;
​
/** 处理用户数据的业务层接口 */
public interface IUserService {
    /**
     * 用户注册
     * @param user 用户数据
     */
    void reg(User user);
}

2.创建业务层接口目的是为了解耦。关于业务层的抽象方法的设计原则。

1.仅以操作成功为前提来设计返回值类型,不考虑操作失败的情况;
2.方法名称可以自定义,通常与用户操作的功能相关;
3.方法的参数列表根据执行的具体业务功能来确定,需要哪些数据就设计哪些数据。通常情况下,参数需要足以调用持久层对应的相关功能;同时还要满足参数是客户端可以传递给控制器的;
4.方法中使用抛出异常的方式来表示操作失败。

4.4 实现抽象方法

1.创建com.cy.store.service.impl.UserServiceImpl业务层实现类,并实现IUserService接口。在类之前添加@Service注解,并在类中添加持久层UserMapper对象。

package com.cy.store.service.impl;
import com.cy.store.entity.User;
import com.cy.store.mapper.UserMapper;
import com.cy.store.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
​
/** 处理用户数据的业务层实现类 */
@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;
​
    @Override
    public void reg(User user) {
        // TODO
    }
}

2.UserServiceImpl类需要重写IUserService接口中的抽象方法,实现步骤大致是:

@Override
public void reg(User user) {
    // 根据参数user对象获取注册的用户名
    // 调用持久层的User findByUsername(String username)方法,根据用户名查询用户数据
    // 判断查询结果是否不为null
    // 是:表示用户名已被占用,则抛出UsernameDuplicateException异常
    
    // 创建当前时间对象
    // 补全数据:加密后的密码
    // 补全数据:盐值
    // 补全数据:isDelete(0)
    // 补全数据:4项日志属性
​
    // 表示用户名没有被占用,则允许注册
    // 调用持久层Integer insert(User user)方法,执行注册并获取返回值(受影响的行数)
    // 判断受影响的行数是否不为1
    // 是:插入数据时出现某种错误,则抛出InsertException异常
    
}

3.reg()方法的具体实现过程。

@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;
    
    @Override
    public void reg(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;
    }
}

4.完成后在src/test/java下创建com.cy.store.service.UserServiceTests测试类,编写并执行用户注册业务层的单元测试。

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTests {
    @Autowired
    private IUserService iUserService;
    
    @Test
    public void reg() {
        try {
            User user = new User();
            user.setUsername("lower");
            user.setPassword("123456");
            user.setGender(1);
            user.setPhone("17858802974");
            user.setEmail("[email protected]");
            user.setAvatar("xxxx");
            iUserService.reg(user);
            System.out.println("注册成功!");
        } catch (ServiceException e) {
            System.out.println("注册失败!" + e.getClass().getSimpleName());
            System.out.println(e.getMessage());
        }
    }
}

4.5 密码加密介绍

密码加密可以有效的防止数据泄密后带来的账号安全问题。通常,程序员不需要考虑加密过程中使用的算法,因为已经存在非常多成熟的加密算法可以直接使用。但是所有的加密算法都不适用于对密码进行加密,因为加密算法都是可以进行逆向运算的。即:如果能够获取加密过程中所有的参数,就可以根据密文得到原文。

对密码进行加密时,需使用消息摘要算法。消息摘要算法的特点是:

1.原文相同时,使用相同的摘要算法得到的摘要数据一定相同;
2.使用相同的摘要算法进行运算,无论原文的长度是多少,得到的摘要数据长度是固定的;
3.如果摘要数据相同,则原文几乎相同,但也可能不同,可能性极低。

不同的原文,在一定的概率上能够得到相同的摘要数据,发生这种现象时称为碰撞。

以MD5算法为例,运算得到的结果是128位的二进制数。在密码的应用领域中,通常会限制密码长度的最小值和最大值,可是密码的种类是有限的,发生碰撞在概率上可以认为是不存在的。

常见的摘要算法有SHA(Secure Hash Argorithm)家族和MD(Message Digest)系列的算法。

关于MD5算法的破解主要来自两方面。一个是王小云教授的破解,学术上的破解其实是研究消息摘要算法的碰撞,也就是更快的找到两个不同的原文却对应相同的摘要,并不是假想中的“根据密文逆向运算得到原文”。另一个是所谓的“在线破解”,是使用数据库记录大量的原文与摘要的对应关系,当尝试“破解”时本质上是查询这个数据库,根据摘要查询原文。

为进一步保障密码安全,需满足以下加密规则:

1.要求用户使用安全强度更高的原始密码;
2.加盐;
3.多重加密;
4.综合以上所有应用方式。

5 用户-注册-控制器

5.1 创建响应结果类

创建com.cy.store.util.JsonResult响应结果类型。

package com.cy.store.util;
import java.io.Serializable;
​
/**
 * 响应结果类
 * @param  响应数据的类型
 */
public class JsonResult 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;
    }
​
    // Generate: Getter and Setter
}

5.2 设计请求

设计用户提交的请求,并设计响应的方式:

请求路径:/users/reg
请求参数:User user
请求类型:POST
响应结果:JsonResult

5.3 处理请求

1.创建com.cy.store.controller.UserController控制器类,在类的声明之前添加@RestController和@RequestMapping("users")注解,在类中添加IUserService业务对象并使用@Autowired注解修饰。

​
package com.cy.store.controller;
import com.cy.store.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
/** 处理用户相关请求的控制器类 */
@RestController
@RequestMapping("users")
public class UserController {
    @Autowired
    private IUserService userService;
}

​

2.然后在类中添加处理请求的用户注册方法。

@RequestMapping("reg")
public JsonResult reg(User user) {
    // 创建返回值
    JsonResult result = new JsonResult();
    try {
        // 调用业务对象执行注册
        userService.reg(user);
        // 响应成功
        result.setState(200);
    } catch (UsernameDuplicateException e) {
        // 用户名被占用
        result.setState(4000);
        result.setMessage("用户名已经被占用");
    } catch (InsertException e) {
        // 插入数据异常
        result.setState(5000);
        result.setMessage("注册失败,请联系系统管理员");
    }
    return result;
}

3.完成后启动项目,打开浏览器访问http://localhost:8080/users/reg?username=controller&password=123456请求进行测试。

{
    state: 200,
    message: null,
    data: null
}

5.4 控制器层的调整

1.然后创建提供控制器类的基类com.cy.store.controller.BaseController,在其中定义表示响应成功的状态码及统一处理异常的方法。

@ExceptionHandler注解用于统一处理方法抛出的异常。当我们使用这个注解时,需要定义一个异常的处理方法,再给这个方法加上@ExceptionHandler注解,这个方法就会处理类中其他方法(被@RequestMapping注解)抛出的异常。@ExceptionHandler注解中可以添加参数,参数是某个异常类的class,代表这个方法专门处理该类异常。

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.UsernameDuplicateException;
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 handleException(Throwable e) {
        JsonResult result = new JsonResult(e);
        if (e instanceof UsernameDuplicateException) {
            result.setState(4000);
        } else if (e instanceof InsertException) {
            result.setState(5000);
        }
        return result;
    }
}

2.最后简化UserController控制器类中的用户注册reg()方法的代码。

/** 处理用户相关请求的控制器类 */
@RestController
@RequestMapping("users")
public class UserController extends BaseController {
    @Autowired
    private IUserService userService;
​
    @RequestMapping("reg")
    public JsonResult reg(User user) {
        // 调用业务对象执行注册
        userService.reg(user);
        // 返回
        return new JsonResult(OK);
    }
}

3.完成后启动项目,打开浏览器访问http://localhost:8080/users/reg?username=controller&password=123456请求进行测试。

6 用户-注册-前端页面

1.将电脑商城前端资源页面pages文件夹下的静态资源:bootstrap3、css、images、js、web、index.html相关的资源复制到项目src/main/resources/static文件夹下。如图所示。

2.在register.html页面中body标签内部的最后,添加script标签用于编写JavaScript程序。请求的url中需要添加项目的访问名称。

serialize()方法通过序列化表单值,创建URL编码文本字符串。

3.完成后启动项目,打开浏览器访问http://localhost:8080/web/register.html页面并进行注册。

今天的结果用springboot做一个电脑商城项目,第一天_第1张图片

 

 用springboot做一个电脑商城项目,第一天_第2张图片

 

注意:由于没有验证数据,即使没有填写用户名或密码,也可以注册成功。

你可能感兴趣的:(spring,boot,intellij-idea,java)