SpringBoot
SpringBoot简介
SpringBoot本质就是一个javaweb的开发框架,和SpringMVC类似,对比其他javaweb框架的好处,官方说是简化开发,约定大于配置,能迅速的开发web应用。不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程。另外SpringBoot通过集成大量的框架使得依赖包的版本冲突,以及引用的不稳定性等问题得到了很好的解决。
- 特点:
(1)可以创建独立的Spring应用程序,并且基于其Maven或Gradle插件,可以创建可执行的JARs和WARs;
(2)内嵌Tomcat或Jetty等Servlet容器;
(3)提供自动配置的“starter”项目对象模型(POMS)以简化Maven配置;
(4)自动配置Spring以及第三方功能;
(5)提供生产级别的监控、健康检查及外部化配置;
(6)无代码生成、无需编写XML;
SpringBoot的使用
SpringBoot的入门使用
一、Maven方式创建
创建一个maven工程
导入maven依赖
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
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>springBoot_01</artifactId>
<version>1.0-SNAPSHOT</version>
<!--父项目做依赖管理-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<!--开发导入starter场景启动器
1、见到很多 spring-boot-starter-* : *就某种场景
2、只要引入starter,这个场景的所有常规需要的依赖我们都自动引入
3、SpringBoot所有支持的场景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
4、见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器。
5、所有场景启动器最底层的依赖-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<!-- 把项目打成jar包,直接在目标服务器执行即可。-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>创建主程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16package com.wht.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @SpringBootApplication告诉springboot这是个springboot应用
*/
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class,args);
}
}编写业务层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package com.wht.boot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
public class HelloController {
public String handler01(){
return"hello ,spring boot 2!";
}
}测试
直接运行main方法
二、通过idea直接创建SpringBoot工程
SpringBoot的自动配置
自动配好Tomcat
引入Tomcat依赖。
配置Tomcat
1 | <dependency> |
自动配好SpringMVC
引入SpringMVC全套组件
自动配好SpringMVC常用组件(功能)
自动配好Web常见功能,如:字符编码问题
SpringBoot帮我们配置好了所有web开发的常见场景
默认的包结构
主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
无需以前的包扫描配置
想要改变扫描路径,@SpringBootApplication(scanBasePackages=“com.wht”)
或者@ComponentScan 指定扫描路径
@SpringBootApplication是合成注解
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(“com.wht.boot”)
各种配置拥有默认值
默认配置最终都是映射到某个类上,如:MultipartProperties
配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
按需加载所有自动配置项
非常多的starter
引入了哪些场景这个场景的自动配置才会开启
SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面
SpringBoot相关注解
1、@Configuration
基本使用
Full模式与Lite模式
配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
1 | /** |
2、@Bean、@Component、@Controller、@Service、@Repository
与spring用法相同
3、@ComponentScan、@Import
1 | /* 4、@Import({User.class, DBHelper.class}) |
4、@Conditional
条件装配:满足Conditional指定的条件,则进行组件注入
1 |
|
5、原生配置文件引入 @ImportResource
1 | <?xml version="1.0" encoding="UTF-8"?> |
6、配置绑定
1、@Component + @ConfigurationProperties
1 | /** |
2、@EnableConfigurationProperties + @ConfigurationProperties
1 | @EnableConfigurationProperties(Car.class) |
7、使用外部properties文件@PropertySource+@value
1 |
|
各种插件
Lombok插件
简化javaBean的编写
依赖:
1
2
3
4<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19//空参构造
//@AllArgsConstructor 全参构造
//日志
//设置get/set
//重写toString
//重写equals和hashCode
public class User {
private String name;
private Integer age;
private Pet pet;
public User(String name,Integer age){
this.name = name;
this.age = age;
log.info("构造函数");
}
}dev-tool
对项目进行热部署
依赖:
1
2
3
4
5<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>使用
导入依赖后,每次修改后使用Ctrl+F重新build项目
配置提示插件
将自定义的类的属性在配置文件中进行提示
依赖:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>使用
属性绑定后,在配置文件中就会有提示
配置文件YAML
key: value kv之间有空格
大小写敏感
使用缩进表示层级关系
缩进不允许使用tab,只允许空格
缩进的空格数不重要,只要相同层级的元素左对齐即可
‘#’表示注释
字符串无需加引号,如果要加,’’与””表示字符串内容 会被 转义/不转义
字面量:单个的、不可再分的值。date、boolean、string、number、null
- k:v
对象:键值对的集合。map、hash、set、object
- 行内写法: k: {k1:v1,k2:v2,k3:v3}
- k:
k1: v1 k2: v2 k3: v3
数组:一组按次序排列的值。array、list、queue
- 行内写法: k: [v1,v2,v3]
- k:
- v1
- v2
- v3
多配置文件:
- 我们在配置文件编写的时候,文件名可以是 application-{profile}.properties/yml用来指定多个环境版本如:
- application-test.properties 代表测试环境配置
- application-dev.properties 代表开发环境配置
- 并在默认
application.properties
主配置文件中配置:spring.profiles.active=dev
Web开发
1、静态资源目录
只要静态资源放在类路径下: called /static (or /public or /resources or /META-INF/resources
访问 : 当前项目根路径/ + 静态资源名
原理:请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面
改变默认的静态资源路径
1
2
3
4
5
6spring:
mvc:
static-path-pattern: /res/**
resources:
static-locations: [classpath:/haha/]2、欢迎页以及错误页面
静态资源路径下 index.html
○ 可以配置静态资源路径
○ 但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问错误页面:静态资源路径下创建/error文件夹下4xx.html,5xx.html,springboot会被自动解析(需要有模板引擎thymeleaf等)
3、自定义Favicon
favicon.ico 放在静态资源目录下即可,会自动展示
4、使用Restful风格请求
配置请求方式过滤器:
1
2
3
4
5spring:
mvc:
hiddenmethod:
filter:
enabled: true #开启页面表单的Rest功能注意表单要添加**_method=GET/PUT/POST..**的隐藏input
配置请求映射:
@RequestMapping(value = "/user",method = RequestMethod.GET)
5、相关注解
- @PathVariable:获取路径参数
/car/{id}
- @RequestHeader:获取请求头
- @RequestParam:获取请求参数
- @MatrixVariable:获取矩阵变量如
/car/sell;low=34;brand=byd
(但需要在webMvcConfigurer进行配置开启) - @CookieValue:获取cookie
- @RequestBody:获取请求体的内容
- @ResponseBody:可以配合json的三方依赖如:fastJson等来实现直接将响应对象转换为json传给前端
- ……同SpringMVC
6、注入web原生组件(Servlet、Filter、Listener)
Servlet
创建servlet
1
2
3
4
5
6
7
8
9
10
11
12public class MyServlet extends HttpServlet {
// 处理get请求
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hello MyServlet");
}
}注册servlet
1
2
3
4
5
6
7
8
9
10
11
public class MyMvcConfig implements WebMvcConfigurer {
public ServletRegistrationBean myServlet() {
ServletRegistrationBean register = new ServletRegistrationBean(new MyServlet(), "/myServlet");
// 可以在这里设置相关配置
register.setLoadOnStartup(1);
return register;
}
}Filter
创建Filter
1
2
3
4
5
6
7
8
9
10
11
12
13public class MyFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("MyFilter process...");
filterChain.doFilter(servletRequest, servletResponse);
}
public void destroy() {}
}注册Filter
1
2
3
4
5
6
7
8
9
public class MyMvcConfig implements WebMvcConfigurer {
public FilterRegistrationBean myFilter() {
FilterRegistrationBean register = new FilterRegistrationBean(new MyFilter());
register.setUrlPatterns(Arrays.asList("/myServlet","/"));
return register;
}
}Listener
创建Listener
1
2
3
4
5
6
7
8
9
10
11public class MyListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
System.out.println("MyListener.contextInitialized -- web应用启动");
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("MyListener.contextDestroyed -- web应用关闭");
}
}注册Listener
1
2
3
4
5
6
7
public class MyMvcConfig implements WebMvcConfigurer {
public ServletListenerRegistrationBean myServletContextListener(){
return new ServletListenerRegistrationBean(new MyServletContextListener());
}
}拦截器
创建拦截器(实现HandlerInterceptor 接口):
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
public class LoginInterceptor implements HandlerInterceptor {
/**
* 目标方法执行之前
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
log.info("preHandle拦截的请求路径是{}",requestURI);
//登录检查逻辑
HttpSession session = request.getSession();
Object loginUser = session.getAttribute("loginUser");
if(loginUser != null){
//放行
return true;
}
//拦截住。未登录。跳转到登录页
request.setAttribute("msg","请先登录");
//re.sendRedirect("/");重定向
request.getRequestDispatcher("/").forward(request,response);//请求转发
return false;
}
/**
* 目标方法执行完成以后
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("postHandle执行{}",modelAndView);
}
/**
* 页面渲染以后
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("afterCompletion执行异常{}",ex);
}
}在web配置类中添加拦截器
1
2
3
4
5
6
7
8
9
10
11
12
13
14/**
* 1、编写一个拦截器实现HandlerInterceptor接口
* 2、拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)
* 3、指定拦截规则【如果是拦截所有,静态资源也会被拦截】
*/
public class AdminWebConfig implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/**") //所有请求都被拦截包括静态资源
.excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**"); //放行的请求
}
}单元测试
Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库
如果要继续使用JUnit 4需要导入vintage的依赖
1 | <dependency> |
SpringBoot中JUnit 5的使用:
依赖:
1
2
3
4
5<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>创建测试类:
现在的Junit类具有Spring的功能,@Autowired、比如 @Transactional 标注测试方法,测试完成后自动回滚
1
2
3
4
5
6
7
class ApplicationTests {
void contextLoads() {
}
}Junit5的常用注解:
@Test
:表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试@ParameterizedTest
:表示方法是参数化测试,下方会有详细介绍@RepeatedTest
:表示方法可重复执行,下方会有详细介绍@DisplayName
:为测试类或者测试方法设置展示名称@BeforeEach
:表示在每个单元测试之前执行@AfterEach
:表示在每个单元测试之后执行@BeforeAll
:表示在所有单元测试之前执行@AfterAll
:表示在所有单元测试之后执行@Tag
:表示单元测试类别,类似于JUnit4中的@Categories@Disabled
:表示测试类或测试方法不执行,类似于JUnit4中的@Ignore@Timeout
:表示测试方法运行如果超过了指定时间将会返回错误@ExtendWith
:为测试类或测试方法提供扩展类引用