1. SpringBoot框架的作用
SpringBoot框架可以直接理解为是一个更好用的SpringMVC框架!
SpringBoot框架遵循“约定大于配置”的思想,它默认完成了绝大部分通用的配置(不管创建哪个项目,配置的方式甚至配置值都不变的那些内容),并且,默认就集成了绝大部分常用的依赖。
2. 创建SpringBoot项目
创建SpringBoot项目的方式有:
- 在任何开发工具中,将SpringBoot设置为当前项目的父级项目即可;
- 打开
https://start.spring.io
网站,在网站上填写新项目的信息,下载得到项目压缩包,通过开发工具导入下载得到的项目即可; - 直接在开发工具中,通过创建向导来创建SpringBoot项目,如果使用的是Eclipse,则需要额外安装SpringTools插件。
本次将使用IntelliJ IDEA来创建SpringBoot项目,在IntelliJ IDEA的主界面选择Create New Project开始创建新项目,在项目类型界面中,左侧选中Spring Initializr,然后继续创建项目,在创建过程中自行设置Group和Artifact,将Packaging选择为war
,默认情况下,可以暂不添加其它依赖,创建成功后,项目会自动下载所需的大量依赖,整个过程中,务必保证当前计算机可以连接到Maven服务器。
3. 启动SpringBoot项目
在创建好的SpringBoot项目,在src/main/java默认就存在cn.tedu.demo
包(包名与创建项目时填写的Group和Artifact有关),并且,在这个包默认就存在DemoApplication类(类名是使用创建项目时填写的Artifact拼接Application
单词组成的),该类中有main()
方法,当执行main()
方法时,整个项目就会启动,所以这个也称之为项目的启动类。
在启动后,会自动打开Run面板,在启动日志中可以看到Tomcat相关的字样!其实,SpringBoot项目自带Tomcat,当启动项目时(执行启动类的main()
方法时),会自动的将当前项目部署到内置的Tomcat中!
注意:由于启动SpringBoot项目时会启动内置的Tomcat,所以,务必保证端口没有被占用,否则就会发生冲突,导致无法启动项目!
如果项目可以正常启动,则核心的jar包文件应该是没有损坏的!
在项目的src/test/java下默认也有cn.tedu.demo
包,在这个包里默认就存在DemoApplicationTests
类,这是一个单元测试类,并且,在这个类中,默认就存在一个空的测试方法,可以在该方法中添加简单的输出语句,例如:
void contextLoads() {
System.err.println("DemoApplicationTests.contextLoads");
}
然后,执行单元测试,如果能够成功执行,则表示测试环境是正常的!
4. 显示静态页面
在SpringBoot项目的src/main/resources下,默认就存在static文件夹,这个文件夹是用于存放静态资源的,最终在访问时,这里的文件将是URL中根级路径下的文件。
静态资源:可以直接在浏览器的地址栏中输入网址进行访问的,通常是.html文件、.css文件、.js文件、图片文件等。
可以直接在static文件夹下创建index.html,并自行设计页面内容,例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello, SpringBoot!!!</title>
</head>
<body>
<h1>欢迎使用SpringBoot框架!!!</h1>
</body>
</html>
完成后,启动项目,打开浏览器,输入http://localhost:8080/
即可访问到该页面。
启动时,可以看到以下信息:
Tomcat started on port(s): 8080 (http) with context path ''
表示:Tomcat已经在8080端口启动,并且设置了context path
值为''
,所以,在访问当前项目时,直接输入http://localhost:8080/
即可,并不需要像以前一样在URL中添加项目名称!
同时,由于index.html是默认的访问页面,当没有显式的在URL中指定所访问的资源时,就会自动访问这个页面,所以,在URL中不必添加文件,当然,如果显式的添加了,也是可以访问的。
也可以在static中自行添加其它文件,在访问时,就需要在URL中显式的添加文件名。
在src/main/resources下,默认还有application.properties文件,这个文件就是SpringBoot的配置文件,当启动项目或执行单元测试时,都会加载这个文件中的配置信息!可以根据SpringBoot的使用要求,在当前文件中添加/修改某些配置,例如:
server.port=80
注意:固定配置内容的属性名是固定的,如果出现拼写错误,会导致配置无效,但是,当前文件也允许自定义配置,所以,就算出现拼写错误,文件本身也不会报错!
以上配置表示:将Tomcat运行的端口号改为80
!
由于80
端口是HTTP协议的默认端口,所以,在访问时,URL中不必显式的指定端口号,例如访问以上index.html时,就只需要在浏览器的地址栏中输入http://localhost
即可访问!
5. 使用控制器接收请求
在src/main/java下,原本就有cn.tedu.demo
包,在这个包下创建子级的controller
包,用于存放控制器类,在这个包下再创建HelloController
控制器:
package cn.tedu.demo.controller;
import org.springframework.stereotype.Controller;
@Controller
public class HelloController {
}
注意:SpringBoot项目将默认就已经创建出来的cn.tedu.demo
包设置为了组件扫描的包,所以,在项目中创建的所有组件类都必须放在这个包或其子级包中!
然后, 在控制器类中添加简单的处理请求的方法:
@GetMapping("hello")
@ResponseBody
public String hello() {
return "SpringBoot真好用!!!";
}
注意:SpringBoot项目将SpringMVC框架处理的请求路径默认设置为/*
(以前的练习案例中自定义的都是*.do
),所以,访问当前项目的所有资源都会被SpringMVC框架处理,在配置请求路径时,并不需要使用.do
作为资源名的后缀!
注意:SpringBoot项目默认将字符编码全部设置成了UTF-8。
编写完成后,重启项目,在浏览器的地址栏中访问http://localhost/hello
即可访问到以上控制器!
6. 连接数据库
默认情况下,SpringBoot项目并没有自带数据库相关的依赖,如果需要实现数据库编程,必须添加连接数据的依赖及数据库编程框架的依赖,例如:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
对于绝大部分常用的依赖,添加时并不需要指定版本号,因为SpringBoot已经设置了版本号,通常是较新的、且稳定的版本。
当然,如果由SpringBoot指定的版本可能与当前环境不匹配(例如mysql-connector-java的版本较高,而服务器的MySQL数据库版本较低就会连接不上),也可以自行添加
<version>
节点来指定版本,将以当前指定的版本为准!
当添加以上依赖后,启动项目时,就会出错,提示信息如下:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
因为SpringBoot项目在启动时,如果当前项目是添加了连接数据库的依赖,就会自动加载连接数据库的配置信息,而当前并没有添加这些配置,导致读取不到这些信息,就出现了以上错误!
所以,需要在application.properties中添加连接数据库的配置:
spring.datasource.url=jdbc:mysql://localhost:3306/tedu_ums?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
注意:在启动项目时,只会读取以上配置信息,并不会实际连接数据库,所以,即使以上配置值有误,也不会报告任何错误!
为了检验以上配置信息是否正确,可以在src/test/java的cn.tedu.sample.SampleApplicationTests测试类中进行测试:
@Test
void getConnection() throws SQLException {
Connection connection = dataSource.getConnection();
System.err.println(connection);
}
在SpringBoot项目中,凡是以前(使用普通的Spring / SpringMVC或其它基于Spring的项目)通过Spring容器调用
getBean()
获取对象的,都改为自动装配即可!
7. 实现用户注册
7.1. 持久层
为了保证注册时插入数据不会出错,且保证“用户名唯一”的数据规则,应该在插入数据之前检查用户名是否已经被注册,所以,“注册”时需要实现的数据访问功能有:
-
SELECT * FROM t_user WHERE username=?
-
INSERT INTO t_user (除了id以外字段列表) VALUES (匹配的值列表)
首先,应该在cn.tedu.sample.entity
包下创建User
实体类,用于封装用户数据:
package cn.tedu.sample.entity;
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private String phone;
private String email;
// Setters & Getters
// toString()
}
然后,在cn.tedu.sample.mapper
包下创建UserMapper
接口,用于定义持久层的抽象方法:
package cn.tedu.sample.mapper;
import cn.tedu.sample.entity.User;
public interface UserMapper {
Integer insert(User user);
User findByUsername(String username);
}
接下来,还需要通过配置,使得MyBatis框架知道这个接口的位置!可以在配置类的声明之前添加@MapperScan
注解来配置接口所在的包!
在SpringBoot项目中,启动类也是配置类,所以,可以在启动类的声明之前添加该注解进行配置:
package cn.tedu.sample;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("cn.tedu.sample.mapper")
@SpringBootApplication
public class SampleApplication {
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
接下来,还需要配置以上抽象方法映射的SQL语句,先在src/main/resources下创建mappers文件夹,用于存放配置SQL语句的XML文件。并在application.properties中配置将要使用到的XML文件的位置:
mybatis.mapper-locations=classpath:mappers/*.xml
然后,向mappers文件夹中粘贴UserMapper.xml文件,并配置以上接口中的抽象方法对应的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">
<mapper namespace="cn.tedu.sample.mapper.UserMapper">
<insert id="insert" useGeneratedKeys="true"
keyProperty="id">
INSERT INTO t_user (
username, password, age, phone, email
) VALUES (
#{username}, #{password}, #{age}, #{phone}, #{email}
)
</insert>
<select id="findByUsername"
resultType="cn.tedu.sample.entity.User">
SELECT * FROM t_user WHERE username=#{username}
</select>
</mapper>
接下来,应该通过单元测试来检查以上功能是否可以正确运行,则在src/test/java的cn.tedu.sample.mapper
包下创建UserMapperTests
测试类,并在这个类中测试以上2个方法:
package cn.tedu.sample.mapper;
import cn.tedu.sample.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class UserMapperTests {
@Autowired(required=false)
UserMapper userMapper;
@Test
void insert() {
User user = new User();
user.setUsername("boot");
user.setPassword("1234");
user.setAge(25);
user.setPhone("13000130000");
user.setEmail("boot@spring.io");
Integer rows = userMapper.insert(user);
System.err.println("rows=" + rows);
}
@Test
void findByUsername() {
String username = "boot";
User user = userMapper.findByUsername(username);
System.err.println(user);
}
}
注意:自定义的单元测试类也必须在项目的根包cn.tedu.sample
之下,否则将无法正常使用!同时,还需要在类的声明之前添加注解(具体添加哪些注解,可参考项目被创建出来时就已经存在的SampleApplicationTests
测试类)!
7.2. 控制器
先在cn.tedu.sample.util
包下创建JsonResult
(自定义类名),并在类中声明2个属性,分别表示操作结果的状态和信息:
package cn.tedu.sample.util;
public class JsonResult {
private Integer state;
private String message;
// Setters & Getters
}
在cn.tedu.sample.controller
包下创建UserController
类,在类的声明之前@RestController
和@RequestMapping("user")
注解,并在控制器类中添加处理请求的方法,此次将使用以上创建的JsonResult
类型作为方法的返回值类型:
package cn.tedu.sample.controller;
import cn.tedu.sample.entity.User;
import cn.tedu.sample.mapper.UserMapper;
import cn.tedu.sample.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("user")
public class UserController {
@Autowired(required = false)
private UserMapper userMapper;
// http://localhost:8080/user/reg?username=sample&password=8888&age=26&phone=13100131111&email=sample@baidu.com
@RequestMapping("reg")
public JsonResult reg(User user) {
System.err.println("UserController.reg"); // soutm
System.err.println("user = " + user); // soutp
String username = user.getUsername();
User result = userMapper.findByUsername(username);
// result.null
JsonResult jsonResult = new JsonResult();
if (result == null) {
userMapper.insert(user);
jsonResult.setState(1);
jsonResult.setMessage("注册成功!");
} else {
jsonResult.setState(2);
jsonResult.setMessage("注册失败!用户名已经被占用!");
}
return jsonResult;
}
}
7.3. 前端页面
在static文件夹下创建register.html页面,用于填写注册信息并将这些信息提交到服务器。