Spring Boot
一、 Spring Boot 介绍
1 什么是 Spring Boot
Spring Boot 是一个框架,一种全新的编程规范,他的产生简化了框架的使用,所谓简化是指简化了 Spring 众多框架中所需的大量且繁琐的配置文件,所以 Spring Boot 是一个服务于框架的框架,服务范围是简化配置文件。所以从本质上来说,Spring Boot 其实就是 Spring框架的另一种表现形式。
2 Spring Boot 特征
使用 Spring Boot 可以创建独立的 Spring 应用程序
在Spring Boot中直接嵌入了Tomcat、Jetty、Undertow等Web容器,所以在使用SpringBoot做 Web 开发时不需要部署 WAR 文件
通过提供自己的启动器(Starter)依赖,简化项目构建配置
尽量的自动配置 Spring 和第三方库
提供了生产就绪特征,如:度量指标,运行状况检查和外部化配置
绝对没有代码生成,也不需要 XML 配置文件
3 Spring Boot 版本介绍
SNAPSHOT:快照版,即开发版。
CURRENT:最新版,但是不一定是稳定版。
GA:GeneralAvailability,正式发布的版本。
二、 于 创建基于 Spring Boot 的项目
1 通过官网创建项目
点击GENERATE按回车键下载生成的.zip文件,解压然后用IDEA打开
2 通过 IDEA 的脚手架工具创建
我们创建的是WEB项目只添加一个web启动器就行
3 通过 IDEA 的 的 Maven 项目创建
修改pom文件
<?xml version="1.0" encoding="UTF-8"?>
<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>com.bjsxt</groupId>
<artifactId>springbootdemo3</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<!--打包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
三、 Spring Boot 项目结构介绍
1 POM 文件
1.1继承
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
Spring Boot 的父级依赖,只有继承它项目才是 Spring Boot 项目。
spring-boot-starter-parent 是一个特殊的 starter,它用来提供相关的 Maven 默认依赖。使用它之后,常用的包依赖可以省去 version 标签。
1.2依赖
<!--WEB启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
启动器依赖 包含web全栈开发的基础jar包 不需要给版本是因为继承父启动器
1.3 插件
<plugins>
<!--打包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
spring-boot-maven-plugin 插件是将 springboot 的应用程序打包成 jar 包的插件。将所有应用启动运行所需要的 jar 包都包含进来,从逻辑上将具备了独立运行的条件。当运行"mvn package"进行打包后,使用"java -jar"命令就可以直接运行。
2 启动类
Spring Boot 的启动类的作用是启动 Spring Boot 项目,是基于 Main 方法来运行的。
注意:启动类在启动时会做注解扫描(@Controller、@Service、@Repository…),扫描位置为同包或者子包下的注解,所以启动类的位置应放于包的根下。
package com.bjsxt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* SPringBoot启动类
*/
@SpringBootApplication
public class SpringBootDemo3Application {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemo3Application.class, args);
}
}
2.1 启动类与启动器区别:
启动类表示项目的启动入口
启动器表示 jar 包的坐标
2.2 创建启动类
package com.bjsxt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* SPringBoot启动类
*/
@SpringBootApplication
public class SpringBootDemo3Application {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemo3Application.class, args);
}
}
3 启动器
Spring Boot 将所有的功能场景都抽取出来,做成一个个的 starter(启动器),只需要在项目里面引入这些 starter 相关场景的所有依赖都会导入进来,要用什么功能就导入什么场景,在 jar 包管理上非常方便,最终实现一站式开发。
Spring Boot 提供了多达 44 个启动器。
spring-boot-starter
这是 Spring Boot 的核心启动器,包含了自动配置、日志和 YAML。
导入其他启动器的时候都会包含核心启动器,导入其他启动器的时候也会把核心启动器导进去
spring-boot-starter-actuator
帮助监控和管理应用。
spring-boot-starter-web
支持全栈式 Web 开发,包括 Tomcat 和 spring-webmvc。
spring-boot-starter-amqp
通过 spring-rabbit 来支持 AMQP 协议(Advanced Message Queuing Protocol)。
spring-boot-starter-aop
支持面向方面的编程即 AOP,包括 spring-aop 和 AspectJ。
spring-boot-starter-artemis
通过 ApacheArtemis 支持 JMS 的 API(Java Message Service API)。
spring-boot-starter-batch
支持 Spring Batch,包括 HSQLDB 数据库。
spring-boot-starter-cache
支持 Spring 的 Cache 抽象。
spring-boot-starter-cloud-connectors
支持 Spring Cloud Connectors,简化了在像 Cloud Foundry 或 Heroku 这样的云平台上连接服务。
spring-boot-starter-data-elasticsearch
支持 ElasticSearch 搜索和分析引擎,包括 spring-data-elasticsearch。
spring-boot-starter-data-gemfire
支持 GemFire 分布式数据存储,包括 spring-data-gemfire。
spring-boot-starter-data-jpa
支持 JPA(Java PersistenceAPI),包括 spring-data-jpa、spring-orm、Hibernate。
spring-boot-starter-data-mongodb
支持 MongoDB 数据,包括 spring-data-mongodb。
spring-boot-starter-data-rest
通过 spring-data-rest-webmvc,支持通过 REST 暴露 Spring Data 数据仓库。
spring-boot-starter-data-solr
支持 Apache Solr 搜索平台,包括 spring-data-solr。
spring-boot-starter-freemarker
支持 FreeMarker 模板引擎。
spring-boot-starter-groovy-templates
支持 Groovy 模板引擎。
spring-boot-starter-hateoas
通过 spring-hateoas 支持基于 HATEOAS 的 RESTful Web 服务。
spring-boot-starter-hornetq
通过 HornetQ 支持 JMS。
spring-boot-starter-integration
支持通用的 spring-integration 模块。
spring-boot-starter-jdbc
支持 JDBC 数据库。
spring-boot-starter-jersey
支持 Jersey RESTful Web 服务框架。
spring-boot-starter-jta-atomikos
通过 Atomikos 支持 JTA 分布式事务处理。
spring-boot-starter-jta-bitronix
通过 Bitronix 支持 JTA 分布式事务处理。
spring-boot-starter-mail
支持 javax.mail 模块。
spring-boot-starter-mobile
支持 spring-mobile。
spring-boot-starter-mustache
支持 Mustache 模板引擎。
spring-boot-starter-redis
支持 Redis 键值存储数据库,包括 spring-redis。
spring-boot-starter-security
支持 spring-security。
spring-boot-starter-social-facebook
支持 spring-social-facebook
spring-boot-starter-social-linkedin
支持 pring-social-linkedin
spring-boot-starter-social-twitter
支持 pring-social-twitter
spring-boot-starter-test
支持常规的测试依赖,包括 JUnit、Hamcrest、Mockito 以及 spring-test 模块。
spring-boot-starter-thymeleaf
支持 Thymeleaf 模板引擎,包括与 Spring 的集成。
spring-boot-starter-velocity
支持 Velocity 模板引擎。
spring-boot-starter-websocket
支持 WebSocket 开发。
spring-boot-starter-ws
支持 Spring Web Services。
spring-boot-starter-actuator
增加了面向产品上线相关的功能,比如测量和监控。
spring-boot-starter-remote-shell
增加了远程 ssh shell 的支持。
spring-boot-starter-jetty
引入了 Jetty HTTP 引擎(用于替换 Tomcat)。
spring-boot-starter-log4j
支持 Log4J 日志框架。
spring-boot-starter-logging
引入了 Spring Boot 默认的日志框架 Logback。
spring-boot-starter-tomcat
引入了 Spring Boot 默认的 HTTP 引擎 Tomcat。
spring-boot-starter-undertow
引入了 Undertow HTTP 引擎(用于替换 Tomcat)。
4 配置文件
Spring Boot 提供一个名称为 application 的全局配置文件,支持两种格式 properteis 格式与 YAML 格式。
如果是基于官网或者是脚手架创建的SpringBoot项目在 /main/java/resource/目录下默认的就有配置文件如果是通过maven改造就自己创建
文件名必须叫 application.properties
4.1Properties 格式
配置 Tomcat 监听端口
4.2YAML 格式
删掉之前 application.properties 文件新建一个 application.yml 文件
YAML 格式配置文件的扩展名可以是 yaml 或者 yml。
4.2.1 基本格式要求
大小写敏感
使用缩进代表层级关系
相同的部分只出现一次
配置 Tomcat 监听端口
server:
port: 8888
冒号后面跟空格在跟数据
4.3 配置文件存放位置
当前项目根目录中
当前项目根目录下的一个/config 子目录中
项目的 resources 即 classpath 根路径中
项目的 resources 即 classpath 根路径下的/config 目录中
4.4 配置文件加载顺序
4.4.1 不同格式的加载顺序
如 果 同 一 个 目 录 下 , 有 application.yml 也 有 application.properties , 默 认 先 读 取
application.properties。
如果同一个配置属性,在多个配置文件都配置了,默认使用第 1 个读取到的,后面读取的不覆盖前面读取到的。
application.properties 先被读取到,application.yum后被读取到但相同的配置项并不覆盖,重启Tomcat的端口应该就是 9999
版本问题:
4.4.2 不同位置的加载顺序
4.4.2.1 当前项目根目录下的一个/config 子目录中( 最高)
config/application.properties
config/application.yml
4.4.2.2 当前项目根目录中( 其次)
application.properties
application.yml
4.4.2.3 项目的 resources 即 即 classpath 根路径下的/config 目录中( 一般)
resources/config/application.properties
resources/config/application.yml
4.4.2.4 项目的 resources 即 即 classpath 根路径中( 最后)
resources/application.properties
resources/application.yml
删掉 application.properties 文件 在项目的根目录下创建目录 config 必须叫config 将之前的 .yml文件移到项目的根目录下,把 application.yml文件复制粘贴到 config目录下
根目录下端口为 9999 config目录下的端口为 8888
启动Tomcat config 目录下的配置文件先被解析,再解析项目根目录下的配置文件,但发现有相同的key并不覆盖
将config目录下的配置文件移到resources目录下,删除config 目录,resources目录下的配置端口是 8888
先被解析的项目根目录下的配置文件
在resources目录下创建一个config目录,将根目录下的配置文件移到resources目录下的config目录中
config目录下的端口是 8888 resources 目录下的端口是 9999
先解析config 目录下的配置文件 端口是8888
删除config 只保留一个配置文件
4.5 配置文件中的占位符
4.5.1 占位符语法
语法:KaTeX parse error: Unexpected character: '' at position 16: {} 4.5.2 占位符作用 ̲ "{}"中可以获取框架提供的方法中的值如:random.int 等。
占位符可以获取配置文件中的键的值赋给另一个键作为值。
4.5.3 生成随机数
${random.value} - 类似 uuid 的随机数,没有"-"连接
${random.int} - 随机取整型范围内的一个值
${random.long} - 随机取长整型范围内的一个值
${random.long(100,200)} - 随机生成长整型 100-200 范围内的一个值
${random.uuid} - 生成一个 uuid,有短杠连接
${random.int(10)} - 随机生成一个 10 以内的数
${random.int(100,200)} - 随机生成一个 100-200 范围以内的数
随机生成端口
4.6bootstrap 配置文件
4.6.1bootstrap 配置文件介绍
Spring Boot 中有两种上下文对象,一种是 bootstrap, 另外一种是 application, bootstrap是应用程序的父上下文,也就是说 bootstrap 加载优先于 applicaton。bootstrap 主要用于从额外的资源来加载配置信息,还可以在本地外部配置文件中解密属性。这两个上下文共用一个环境,***它是任何 Spring 应用程序的外部属性的来源。***bootstrap 里面的属性会优先加载,它们默认也不能被本地相同配置覆盖。
bootstrap是applicationContext的父对象,applicationContext是bootstrap的子对象
4.6.2bootstrap 配置文件特征
boostrap 由父 ApplicationContext 加载,比 applicaton 优先加载。
boostrap 里面的属性不能被覆盖。
4.6.3bootstrap与 application 的应用场景
application 配置文件主要用于 Spring Boot 项目的自动化配置。
bootstrap 配置文件有以下几个应用场景。
使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息。
一些固定的不能被覆盖的属性。
一些加密/解密的场景。
5 Spring Boot 的核心注解
5.1@SpringBootApplication
是 SpringBoot 的启动类。
此注解等同于@Configuration+@EnableAutoConfiguration+@ComponentScan 的组合。
5.2@SpringBootConfiguration
@SpringBootConfiguration 注解是@Configuration 注解的派生注解,跟@Configuration注解的功能一致,标注这个类是一个配置类,只不过@SpringBootConfiguration 是 springboot的注解,而@Configuration 是spring 的注解
5.3@Configuration
通过对 bean 对象的操作替代 spring 中 xml 文件
5.4@EnableAutoConfiguration
Spring Boot 自动配置(auto-configuration):尝试根据你添加的 jar 依赖自动配置你的Spring 应用。是@AutoConfigurationPackage 和@Import(AutoConfigurationImportSelector.class)注解的组合。
5.5@AutoConfigurationPackage
@AutoConfigurationPackage 注解,自动注入主类下所在包下所有的加了注解的类
(@Controller,@Service 等),以及配置类(@Configuration)
5.6@Import({AutoConfigurationImportSelector.class})
直接导入普通的类
导入实现了 ImportSelector 接口的类
导入实现了 ImportBeanDefinitionRegistrar 接口的类
5.7@ComponentScan
组件扫描,可自动发现和装配一些 Bean。
5.8@ConfigurationPropertiesScan
SpringBoot 2.2.0之后单独提出来的
@ConfigurationPropertiesScan 扫描配置属性。@EnableConfigurationProperties 注解的作用是使用 @ConfigurationProperties 注解的类生效。
四、 写 编写 HelloWorld
1 创建项目
2 修改 POM
<?xml version="1.0" encoding="UTF-8"?>
<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>com.bjsxt</groupId>
<artifactId>springboothelloworld</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.4.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3 修改 Tomcat 端口
配置文件必须叫application.yum或者是application.properties
4 创建启动类
package com.bjsxt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 启动类
*/
@SpringBootApplication
public class SpringBootHelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootHelloWorldApplication.class,args);
}
}
5 创建 Controller
package com.bjsxt.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 处理请求Controller
*/
@RestController//@Controller+@ResponsBody复合体 直接返回字符串
public class HelloWorldController {
@RequestMapping("/helloWorld")
public String showHelloWorld() {
return "HelloWorld";
}
}
6 Spring Boot 在 在 Controller 中常用注解
6.1@RestController
@RestController 相当于@Controller+@ResponseBody 注解
如果使用@RestController 注解 Controller 中的方法无法返回页面,相当于在方法上面自动 加 了 @ResponseBody 注 解 , 所 以 没 办 法 跳 转 并 传 输 数 据 到 另 一 个 页 面 , 所以
InternalResourceViewResolver 也不起作用,返回的内容就是 Return 里的内容。
6.2@GetMapping
@GetMapping 注解是@RequestMapping(method = RequestMethod.GET)的缩写。
6.3@PostMapping
@PostMapping 注解是@RequestMapping(method = RequestMethod.POST)的缩写。
6.4@PutMapping
@PutMapping 注解是@RequestMapping(method = RequestMethod.PUT)的缩写。
6.5@DeleteMapping
@DeleteMapping 注解是@RequestMapping(method = RequestMethod.DELETE)的缩写。
五、 Spring Boot 整合 Web 层技术
整合 Servlet
1 整合 Servlet 方式一
1.1 通过注解扫描完成 Servlet 组件的注册
1.1.1 创建 Servlet
package com.bjsxt.springbootweb.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 整合Servlet方式一
*/
@WebServlet(name = "FirstServlet",urlPatterns = "/first")
public class FirstServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("First Servlet.........");
}
}
1.1.2修改启动类
package com.bjsxt.springbootweb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan//在SpringBoot启动时会扫描@WebServlet注解,并将该类实例化
public class SpringbootwebApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootwebApplication.class, args);
}
}
启动启功类
servlet并未设置响应
2 整合 Servlet 方式二
2.1 通过方法完成 Servlet 组件的注册
2.1.1 创建 Servlet
package com.bjsxt.springbootweb.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 整合Servlet方式二
*/
public class SecondServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Second Servlet.........");
}
}
2.1.2 创建 Servlet 配置类
这个注册方法也可以放到SpringBoot启动类中,因为@SpringBootApplication注解中包含@Configuration注解,学习阶段我们单独放到一个类中
第二种整合不如第一个方便,没有一个Servlet都得去创建一个方法去注册,如果Servlet数量很多用注解方便
package com.bjsxt.springbootweb.config;
import com.bjsxt.springbootweb.servlet.SecondServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Servlet配置类
*/
@Configuration
public class ServletConfig {
/**
* 完成Servlet组件的注册
*/
@Bean
public ServletRegistrationBean getServletRegistrationBean() {
//自己实例化Servlet并放到ServletRegistrationBean中
ServletRegistrationBean bean = new ServletRegistrationBean(new SecondServlet());
//给注册的Servlet指定一个访问的URL
bean.addUrlMappings("/second");
return bean;
}
}
3 整合 Filter 方式一
3.1 通过注解扫描完成 Filter 组件注册
3.1.1 创建 Filter
package com.bjsxt.springbootweb.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* 整合filter方式一
*/
//@WebFilter(filterName = "FirstFilter",urlPatterns = {"*.do","*.jsp"})//可以根据url后缀进行拦截
@WebFilter(filterName = "FirstFilter",urlPatterns ="/first")
public class FirstFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("进入First Filter");
//放行
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("离开First Filter");
}
@Override
public void destroy() {
}
}
3.1.2修改启动类
用的还是@ServletComponentScan注解,filter是servlet的子技术
package com.bjsxt.springbootweb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan//在SpringBoot启动时会扫描@WebServlet,@WebFilter注解,并将该类实例化
public class SpringbootwebApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootwebApplication.class, args);
}
}
4 整合 Filter 方式二
4.1 通过方法完成 Filter 组件注册
4.1.1 创建 Filter
package com.bjsxt.springbootweb.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* 整合Filter方式二
*/
public class SecondFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("进入Second Filter");
//放行
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("离开Second Filter");
}
@Override
public void destroy() {
}
}
4.1.2 创建 Filter 配置类
filter配置类完全可以和servletConfig配置类公用一个
package com.bjsxt.springbootweb.config;
import com.bjsxt.springbootweb.filter.SecondFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Filter配置类
*/
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean getFilterRegistrationBean() {
//实例化SecondFilter并放入FilterRegistrationBean
FilterRegistrationBean bean = new FilterRegistrationBean(new SecondFilter());
//根据后缀拦截,可变参数放一个String类型的数组
//bean.addUrlPatterns(new String[]{"*.do","*.jsp"});
//如果拦截的只是某个URI
bean.addUrlPatterns("/second");
return bean;
}
}
5 整合 Listener 方式一
5.1 通过注解扫描完成 Listener 组件注册
5.1.1 编写 Listener
package com.bjsxt.springbootweb.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* 整合Listener
*/
@WebListener
public class FirstListener implements ServletContextListener {
public void contextDestoryed(ServletContextEvent event) {
}
public void contextInitialized(ServletContextEvent event) {
System.out.println("Listener......Init");
}
}
5.1.2修改启动类
package com.bjsxt.springbootweb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan//在SpringBoot启动时会扫描@WebServlet,@WebFilter,@WebListener注解,并将该类实例化
public class SpringbootwebApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootwebApplication.class, args);
}
}
6 整合 Listener 方式二
6.1 通过方法完成 Listener 组件注册
6.1.1 编写 Listener
package com.bjsxt.springbootweb.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* 整合Listener方式二
*/
public class SecondListener implements ServletContextListener {
public void contextDestoryed(ServletContextEvent event) {
}
public void contextInitialized(ServletContextEvent event) {
System.out.println("Second......Listener......Init");
}
}
6.1.2 创建 Listener 配置类
放到具有@Configuration注解的类下并且在方法上加@Bean注解完成listener的注册即可
package com.bjsxt.springbootweb.config;
import com.bjsxt.springbootweb.listener.SecondListener;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Listener配置类
*/
@Configuration
public class ListenerConfig {
@Bean
public ServletListenerRegistrationBean getServletListenerRegistrationBean() {
//在ServletListenerRegistrationBean的构造方法里实例化监听器
ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean(new SecondListener());
return bean;
}
}
六、 Spring Boot 访问静态资源
在 SpringBoot 项目中没有我们之前常规 web 开发的 WebContent(WebApp),它只有src 目录。在 src/main/resources 下面有两个文件夹,static 和 templates。SpringBoot 默认在 static目录中存放静态页面,而 templates 中放动态页面。
访问静态资源默认的去classpath(resources)目录下找一个叫static的目录在static目录下找资源
1 static 目录
Spring Boot 通过 classpath/static 目录访问静态资源。注意存放静态资源的目录名称必须是 static。
index.html 放在了static目录下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>Hello BJSXT</h2>
</body>
</html>
package com.bjsxt.springbootweb.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller//需要做视图跳转不能用@RestController
public class PageController {
@RequestMapping("/page")
public String showPage() {
return "index.html";
}
}
图片和index.html同目录使用相对路径
如果图片放到了img目录下,使用相对路径
2 templates 目录
在 Spring Boot 中不推荐使用 jsp 作为视图层技术,而是默认使用 Thymeleaf 来做动态页面。Templates 目录这是存放 Thymeleaf 的页面。
3 静态资源存放其他位置
3.1Spring Boot 访问静态资源的位置
SpringBoot查找静态资源的方式:对以下几个目录进行逐一查找,查找顺序按照列出来的上下顺序
classpath:/META‐INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
在resources目录下创建目录 META‐INF/resources/
修改加载图片的路径
在resources目录下再新建一个resources目录
修改图片名称所以访问不到
在resources目录下新建public目录
3.2自定义静态资源位置
在resources目录下穿件suibian目录,此时index.html仅仅在suibian目录下其他目录下没有
那四个默认位置在application.properties目录下也是这么配置的,多个路径逗号隔开
现在将静态资源放在了自定义的目录下需要在application.properties配置路径
当前index.html放到了resources目录下的suibian目录里,图片在static目录下
先去suibian下找index.html引用图片的时候suibian没有再去static目录下找
七、 Spring Boot 文件上传
1 创建项目
2 POM 文件
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springbootfileupload</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootfileupload</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3 启动类
package com.bjsxt.springbootfileupload;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootfileuploadApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootfileuploadApplication.class, args);
}
}
4 编写上传页面
fileupload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/fileUploadController" method="post" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit" value="OKOK"/>
</form>
</body>
</html>
5 编写 Controller
package com.bjsxt.springbootfileupload.controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
/**
* 文件上传
*/
@RestController
public class FileUploadController {
/**
* 文件上传
*
* 参数file的名字必须和上传页面中定义的一样,否则报空指针
*/
@PostMapping("/fileUploadController")
public String fileUpload(MultipartFile file) throws IOException {
//打印原始文件名
System.out.println(file.getOriginalFilename());
file.transferTo(new File("D:/" + file.getOriginalFilename()));
return "OK";
}
}
6 修改上传文件大小
上传的文件过大,报错,SpringBoot默认上传文件大小是1MB
默认只有1MB
修改上传文件的大小
#配置单个上传文件的大小的限制
spring.servlet.multipart.max-file-size=2MB
#配置一次请求中上传文件的总容量的限制,默认为10MB
spring.servlet.multipart.max-request-size=20MB
八、 Spring Boot 整合视图层技术
1 Spring Boot 整合 JSP 技术
1.1创建项目
1.2 修改 POM 文件,添加 JSP 引擎与 JSTL
SpringBoot内嵌的Tomcat没有JSP引擎不能处理jsp
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springbootjsp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootjsp</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--添加JSP引擎,SpringBoot内置的Tomcat中没有此依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!--添加JSTL坐标依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.3 创建 webapp
在目录下无法床架JSP
将webapp目录标记成支持web技术的目录
1.4 标记为 web
出现蓝色的点说明可以创建JSP了
1.5 创建 JSP
index.jsp
<%--
Created by IntelliJ IDEA.
User: admin
Date: 2020/11/28
Time: 17:12
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h2>Hello JSP</h2>
</body>
</html>
1.6修改配置文件,配置视图解析器
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
1.7 创建 Controller
package com.bjsxt.springbootjsp.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* 页面跳转Controller
*/
@Controller//不能用@RestController,他不能做页面跳转只能返回一个字符串
public class PageController {
/**
* 页面跳转
*/
@GetMapping("/{page}")
public String showPage(@PathVariable String page) {
return page;
}
}
出现这个问题不是路径问题而是在IDEA中项目结构引起的
如果在 IDEA 中项目结构为聚合工程。那么在运行 jsp 是需要指定路径。如果项目结构为独立项目则不需要。
2 Spring Boot 整合 Freemarker
2.1创建项目
2.2 修改 POM 文件,添加 Freemarker
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springbootfreemarker</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootfreemarker</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--添加freemarke启动器r依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.3 创建 Users 实体
package com.bjsxt.springbootfreemarker.pojo;
public class Users {
private String username;
private String usersex;
private String userage;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUsersex() {
return usersex;
}
public void setUsersex(String usersex) {
this.usersex = usersex;
}
public String getUserage() {
return userage;
}
public void setUserage(String userage) {
this.userage = userage;
}
public Users(String username, String usersex, String userage) {
this.username = username;
this.usersex = usersex;
this.userage = userage;
}
public Users() {
}
}
2.4 创建 Controller
package com.bjsxt.springbootfreemarker.controller;
import com.bjsxt.springbootfreemarker.pojo.Users;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.ArrayList;
import java.util.List;
/**
* UsersController
*/
@Controller
public class UsersController {
/**
* 处理请求返回数据
*/
@GetMapping("/showUsers")
public String showUsers(Model model) {
List<Users> list = new ArrayList<>();
list.add(new Users("admin", "F", "22"));
list.add(new Users("LJX", "F", "21"));
list.add(new Users("AAA", "F", "23"));
model.addAttribute("list", list);
return "usersList";
}
}
2.5创建视图
每从list中迭代一个元素赋给user
将.html后缀改为.ftl会导致某些标签丢失造成页面展示错误
usersList.ftl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="1" align="center" width="50%">
<tr>
<th>Name</th>
<th>Sex</th>
<th>Age</th>
</tr>
<#list list as user>
<tr>
<td>${user.username}</td>
<td>${user.usersex}</td>
<td>${user.userage}</td>
</tr>
</#list>
</table>
</body>
</html>
2.6修改配置文件添加后缀
spring.freemarker.suffix=.ftl
3 Spring Boot 整合 Thymeleaf
3.1Thymeleaf 介绍
Thymeleaf 的主要目标是将优雅的自然模板带到开发工作流程中,并将 HTML 在浏览器中正确显示,并且可以作为静态原型,让开发团队能更容易地协作。Thymeleaf 能够处理HTML,XML,JavaScript,CSS 甚至纯文本。
长期以来 jsp 在视图领域有非常重要的地位,随着时间的变迁,出现了一位新的挑战者:Thymeleaf,Thymeleaf 是原生的,不依赖于标签库.它能够在接受原始 HTML 的地方进行编辑和渲染.因为它没有与Servelet规范耦合,因此Thymeleaf模板能进入jsp所无法涉足的领域。
就是模板引擎。可以为模板做数据渲染,模板一般是HTML,thymeleaf可以根据语法结构想HTML中做数据渲染
3.2Thymeleaf 基本使用
3.2.1创建项目
3.2.2 修改 POM 文件,添加 Thymeleaf 启动器依赖
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springbootthymeleaf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootthymeleaf</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--添加Thymeleaf启动器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
index.html被放到templates目录下,启动项目
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>北京尚学堂首页</title>
</head>
<body>
北京尚学堂
</body>
</html>
404原因:templates目录下的资源不予许通过url直接访问,这个目录是存放基于模板引擎渲染的视图,如果允许直接访问那么业务数据还没来得及渲染就被访问那么页面不完整
3.2.3 创建 Controller
package com.bjsxt.springbootthymeleaf.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
/**
* 页面跳转Controller
*/
@Controller
public class PageController {
/**
* 页面跳转方法
*/
@GetMapping("/show")
public String showPage(Model model) {
model.addAttribute("msg", "Thymeleaf");
return "index";
}
}
3.2.4创建视图
index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>北京尚学堂首页</title>
</head>
<body>
<span th:text="北京尚学堂"></span>
<hr/>
<span th:text="${msg}"></span>
</body>
</html>
3.3Thymeleaf 语法讲解
命名空间:xmlns:th=“http://www.thymeleaf.org”
3.3.1 字符串与变量输出操作
3.3.1.1 th:text
标签里所夹的尚学堂会被 th:text替换掉
3.3.1.2 th:value
th:value
可以将一个值放入到 input 标签的 value 中
值没有渲染到标签中 th:value 针对 标签的value属性的,其他的用不了
HTML并没有提供对EL表达式处理的能力
th:value
3.3.2 字符串操作
Thymeleaf 提供了一些内置对象,内置对象可直接在模板中使用。这些对象是以#引用的。
3.3.2.1 使用内置对象的语法
1)引用内置对象需要使用#
2)**大部分内置对象的名称都以 s 结尾。**如:strings、numbers、dates
${#strings.isEmpty(key)} 判断字符串是否为空,如果为空返回 true,否则返回 false |
---|
${#strings.contains(msg,‘T’)} 判断字符串是否包含指定的子串,如果包含返回 true,否则返回 false |
${#strings.startsWith(msg,‘a’)} 判断当前字符串是否以子串开头,如果是返回 true,否则返回 false |
${#strings.endsWith(msg,‘a’)} 判断当前字符串是否以子串结尾,如果是返回 true,否则返回 false |
${#strings.length(msg)} 返回字符串的长度 |
判断msg是否为空
将msg的value换成null
判断msg的值中有没有大写的T
判断有没有s
判断字符串长度 空格也算一个
3.3.3日期格式化处理
${#dates.format(key)} |
---|
格式化日期,默认的以浏览器默认语言为格式化标准 |
${#dates.format(key,‘yyyy/MM/dd’)} |
按照自定义的格式做日期转换 |
${#dates.year(key)} |
${#dates.month(key)} |
${#dates.day(key)} |
Year:取年 Month:取月 Day:取日 |
不做任何日期格式转换
做格式转换
自定义日期格式 但是必须用单引号包起来,因为是模板
取年月日
3.3.4 条件判断
3.3.4.1 th:if
3.3.4.2 th:switch / th:case
th:switch / th:case
th:switch / th:case 与 Java 中的 switch 语句等效,有条件地显示匹配的内容。如果有多个匹配结果只选择第一个显示。
th:case=" * " 表示 Java 中 switch 的 default,即没有 case 的值为 true 时则显示 th:case=" * " 的内容。
换成字符串也可以 在Thymeleaf中最终都是以字符串的形式来匹配
没有匹配到默认用 *
3.3.5 迭代遍历
3.3.5.1 th:each
th:each
迭代器,用于循环迭代集合
pojo.Users
package com.bjsxt.springbootthymeleaf.pojo;
public class Users {
private String id;
private String name;
private int age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Users(String id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public Users() {
}
}
随便定义一个变量 u 去迭代集合 list
3.3.5.2 th:each 状态变量
- index:当前迭代器的索引 从 0 开始
- count:当前迭代对象的计数 从 1 开始
- size:被迭代对象的长度
- odd/even:布尔值,当前循环是否是偶数/奇数 从 0 开始
- first:布尔值,当前循环的是否是第一条,如果是返回 true 否则返回 false
- last:布尔值,当前循环的是否是最后一条,如果是则返回 true 否则返回 false
如果要取迭代器的状态变量那就在 原来的迭代器后面再定义一个任意的变量(sb)逗号隔开,迭代器变量放在最前面,sb相当于之前的 varstatus
<hr/>
<table border="1" width="50%">
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
<th>Index</th>
<th>Count</th>
<th>Size</th>
<th>Odd</th>
<th>Even</th>
<th>First</th>
<th>Last</th>
</tr>
<tr th:each="u,sb : ${list}">
<td th:text="u.id"></td>
<td th:text="u.name"></td>
<td th:text="u.age"></td>
<td th:text="${sb.index}"></td>
<td th:text="${sb.count}"></td>
<td th:text="${sb.size}"></td>
<td th:text="${sb.odd}"></td>
<td th:text="${sb.even}"></td>
<td th:text="${sb.first}"></td>
<td th:text="${sb.last}"></td>
</tr>
</table>
3.3.6th:each 迭代 Map
迭代器在迭代时直接将map变成了Map.Entry类型
m.value获取的users对象
3.3.7 操作域对象
3.3.7.1 HttpServletRequest
request.setAttribute("req", "HttpServletRequest");
<span th:text="${#httpServletRequest.getAttribute('req')}"></span>
<span th:text="${#request.getAttribute('req')}"></span>
3.3.7.2 HttpSession
request.getSession().setAttribute("sess", "HttpSession");
<span th:text="${session.ses}"></span><br/>
<span th:text="${#session.getAttribute('ses')}"></span><br/>
3.3.7.3 ServletContext
request.getSession().getServletContext().setAttribute("app","Application");
<span th:text="${application.app}"></span>
<span th:text="${#servletContext.getAttribute('app')}"></span>
req ses app 都是key
req ses app 都是key
3.3.8URL 表达式
3.3.8.1 语法
在 Thymeleaf 中 URL 表达式的语法格式为@{}
3.3.8.2 URL 类型
3.3.8.2.1 绝对路径
<a th:href="@{http://www.baidu.com}">绝对路径</a>
3.3.8.2.2相对路径
相对于当前项目的根
<a th:href="@{/show}">相对路径</a>
<!--
相对于服务器路径的根 project2为项目名,如果用的是Tomcat,那么服务器根路径就是webapps目录,换句话说服务器根目录是项目根目录的上一级的目录,这么做的特点是一个服务器中部署了多个项目可以通过这个做跨项目的访问,如果是基于服务器的根路径去访问其他项目的资源需要在当前根路径的前面加 ~
~/要访问项目的名称/项目名称下的资源
-->
<a th:href="@{~/project2/resourcename}">相对于服务器的根</a>
所有的超链接都是基于Get方式请求
/ :当前项目的根
3.3.8.3 在 在 URL 中传递参数
3.3.8.3.1 在普通格式的 URL
<a th:href="@{/show?id=1&name=zhangsan}">普通 URL 格式传参</a>
<a th:href="@{/show(id=1,name=zhangsan)}">普通 URL 格式传参</a>
<a th:href="@{'/show?id='+${id}+'&name='+${name}}">普通 URL 格式传参</a>
<a th:href="@{/show(id=${id},name=${name})}">普通 URL 格式传参</a>
注意看地址栏
普通url传递参数方式二
注意看地址栏
如果是用 ? & 连接并且使用EL表达式传值是不可以的 直接500错误
报错原因:表达式有错误
如果使用 ? & 动态参数传递需要做字符串拼接
为避免EL表达式被常量串连在一起解析得用字符串拼接
使用括号动态传递参数
3.3.8.3.2在 在 restful 格式的 URL 传递参数
大括号和小括号里的参数名必须一致
<a th:href="@{/show/{id}(id=1)}">restful 格式传参</a>
<a th:href="@{/show/{id}/{name}(id=1,name=admin)}">restful 格 式 传 参</a>
<a th:href="@{/show/{id}(id=1,name=admin)}">restful 格式传参</a>
<a th:href="@{/show/{id}(id=${id},name=${name})}">restful 格式传参</a>
在路径中传递一个参数
传递多个参数,逗号隔开
用restful和key=value方式混搭
第四种
3.3.9 在配置文件中配置 Thymeleaf
默认配置
index3.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Title</title>
</head>
<body>
<h2>Hello BJSXT</h2>
</body>
</html>
如果视图在templates根目录下直接写视图名字也可以成功跳转,如果不在根下不能访问
加上目录路径限制
默认后缀就是 .html
配置之后路径就不用加了
默认就是HTML #配置视图模板类型 如果用的是HTML4及之前的版本不需要配置,如果是HTML5就需要指定是HTML5
配置视图模板的编码,默认utf-8
配置响应类型
配置Thymeleaf页面缓存默认为true
application.properties
spring.thymeleaf.prefix=classpath:/templates/suibian/
spring.thymeleaf.suffix=.html
#配置视图模板类型,如果视图模板使用的是HTML5需要配置
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=utf-8
#配置响应类型
spring.thymeleaf.servlet.content-type=text/html
#配置Thymeleaf页面缓存,缓存页面会影响开发,默认为true一般设为false
spring.thymeleaf.cache=false
九、 Spring Boot 整合持久层技术
1 整合 JDBC
1.1 搭建项目环境
1.1.1 创建表
1.1.1.1 建表语句
CREATE TABLE `users` (
`userid` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(30) DEFAULT NULL,
`usersex` varchar(10) DEFAULT NULL,
PRIMARY KEY (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1.1.2创建项目
1.1.3 修改 POM ,添加相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springbootjdbc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootjdbc</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--导入Thymeleaf启动坐标-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--JDBC启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--数据库驱动坐标-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.2 配置数据源
1.2.1 通过自定义配置文件方式配置数据源信息
1.2.1.1 通过@PropertySource 注解读取配置文件
1.2.1.1.1 添加 Druid 数据源依赖
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springbootjdbc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootjdbc</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--导入Thymeleaf启动坐标-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--JDBC启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--数据库驱动坐标-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!--Druid数据源依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.2.1.1.2 创建 Properties
放到项目的resources目录下
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
jdbc.username=root
jdbc.password=root
1.2.1.1.3创建配置类
package com.bjsxt.springbootjdbc.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
/**
* 数据源的JDBC配置类
*/
@Configuration
@PropertySource("classpath:/jdbc.properties")//加载指定的properties配置文件
public class JdbcConfiguration {
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 实例化Druid
*/
@Bean
public DataSource getDataSource() {
DruidDataSource source = new DruidDataSource();
source.setDriverClassName(this.driverClassName);
source.setUrl(this.url);
source.setUsername(this.username);
source.setPassword(this.password);
return source;
}
}
package com.bjsxt.springbootjdbc.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.sql.DataSource;
@Controller
public class UsersController {
@Autowired
private DataSource dataSource;
@GetMapping("/showInfo")
public String showInfo() {
return "OK";
}
}
设置断点 DEBUG运行,访问 http://localhost/showInfo
DEBUG 数据源全部注入进来了
package com.bjsxt.springbootjdbc.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
/**
* 数据源的JDBC配置类
*/
@Configuration
@PropertySource("classpath:/jdbc.properties")//加载指定的properties配置文件
public class JdbcConfiguration {
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.url}")
private String utl;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/**
* 实例化Druid
*/
@Bean
public DataSource getDataSource() {
DruidDataSource source = new DruidDataSource();
source.setDriverClassName(this.driverClassName);
source.setUrl(this.utl);
source.setUsername(this.username);
source.setPassword(this.password);
return source;
}
}
1.2.1.2 通过@ConfigurationProperties 注解读取配置信息
@ConfigurationProperties是SpringBoot里面的注解 @ConfigurationProperties只能读取application.properties或者application.yml文件,所以得把配置信息添加到application.properties文件中,在注解中设置前缀来指定读取配置文件中哪一部分内容,实体中属性名必须和配置文件中除了前缀以外的内容完全一样,在解析配置文件向JdbcProperties实体类注入时用的是set方法所以实体类JdbcProperties必须提供set方法,写@Value注解是无效的,然后把解析出来存放配置信息的属性类交给JdbcConfiguration,在JdbcConfiguration中可以通过三种方式注入
1:属性注入
2:构造方法注入
3:通过方法的入参注入
@ConfigurationProperties(prefix = "jdbc")//是SpringBoot的注解不能读取其他的配置文件,只能读取SpringBoot的application配置文件
注解会读取所有以jdbc为前缀的key并且把value解析出来
出现bug找不到该类型
需要再加个注解
为了能把配置信息充分复用我们将配置信息放到实体中
package com.bjsxt.springbootjdbc.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* JDBC配置信息属性类
*/
@ConfigurationProperties(prefix = "jdbc")//是SpringBoot的注解不能读取其他的配置文件,只能读取SpringBoot的application配置文件
public class JdbcProperties {
//实体中属性名必须和配置文件中除了前缀以外的内容完全一样
private String driverClassName;
private String url;
private String username;
private String password;
//属性名必须和配置文件里面的后缀一样
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
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;
}
}
package com.bjsxt.springbootjdbc.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
/**
* 数据源的JDBC配置类
*/
@Configuration
//@PropertySource("classpath:/jdbc.properties")//加载指定的properties配置文件
@EnableConfigurationProperties(JdbcProperties.class)//指定加载哪个配置属性类
public class JdbcConfiguration {
@Autowired
private JdbcProperties jdbcProperties;
/**
* 实例化Druid
*/
@Bean
public DataSource getDataSource() {
DruidDataSource source = new DruidDataSource();
source.setDriverClassName(this.jdbcProperties.getDriverClassName());
source.setUrl(this.jdbcProperties.getUrl());
source.setUsername(this.jdbcProperties.getUsername());
source.setPassword(this.jdbcProperties.getPassword());
return source;
}
}
DUBUG可以获取信息
之前是通过@AutoWired注入进来的,还可以通过构造方法注入实体
DEBUG成功注入
还可以通过方法的入参注入
成功注入
1.2.1.2.1 创建配置信息实体类
package com.bjsxt.springbootjdbc.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* JDBC配置信息属性类
*/
@ConfigurationProperties(prefix = "jdbc")//是SpringBoot的注解不能读取其他的配置文件,只能读取SpringBoot的application配置文件
public class JdbcProperties {
//属性名必须和配置文件里面的后缀一样
private String driverClassName;
private String url;
private String username;
private String password;
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
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;
}
}
1.2.1.2.2修改配置类
package com.bjsxt.springbootjdbc.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
/**
* 数据源的JDBC配置类
*/
@Configuration
//@PropertySource("classpath:/jdbc.properties")//加载指定的properties配置文件
@EnableConfigurationProperties(JdbcProperties.class)//指定加载哪个配置属性类
public class JdbcConfiguration {
/**
* 可以通过注解自动注入
*/
//@Autowired
private JdbcProperties jdbcProperties;
/**
* 还可以通过构造方法注入
*/
/*public JdbcConfiguration(JdbcProperties jdbcProperties) {
this.jdbcProperties = jdbcProperties;
}*/
/**
* 实例化Druid
*/
@Bean
public DataSource getDataSource(JdbcProperties jdbcProperties) {
DruidDataSource source = new DruidDataSource();
source.setDriverClassName(jdbcProperties.getDriverClassName());
source.setUrl(jdbcProperties.getUrl());
source.setUsername(jdbcProperties.getUsername());
source.setPassword(jdbcProperties.getPassword());
return source;
}
}
1.2.1.2.3@ConfigurationProperties
这个注解除了可以加到类上还可以加到方法上
source的set方法和配置文件里面除了前缀的部分完全一样
@ConfigurationProperties(prefix = "jdbc")
@ConfigurationProperties(prefix = “jdbc”)注解会把从配置文件里解析出来的内容通过调用这个方法里所创建的DruidDataSource对象的setUserName(),setUrl(),setDriverClassName(),setPassword()方法把他解析出来的值直接注入到DruidDataSource中,JdbcProperties没有任何意义可以删除
package com.bjsxt.springbootjdbc.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
/**
* 数据源的JDBC配置类
*/
@Configuration
//@PropertySource("classpath:/jdbc.properties")//加载指定的properties配置文件
//@EnableConfigurationProperties(JdbcProperties.class)//指定加载哪个配置属性类
public class JdbcConfiguration {
//@Autowired
private JdbcProperties jdbcProperties;
/**
* 还可以通过构造方法注入
*/
/*public JdbcConfiguration(JdbcProperties jdbcProperties) {
this.jdbcProperties = jdbcProperties;
}*/
/**
* 实例化Druid
*/
@Bean
@ConfigurationProperties(prefix = "jdbc")
public DataSource getDataSource() {
DruidDataSource source = new DruidDataSource();
return source;
}
}
1.2.2 通过 Spring Boot 配置文件配置数据源
在 Spring Boot1.x 版 本 中 的 spring-boot-starter-jdbc 启 动 器 中 默 认 使 用 的 是org.apache.tomcat.jdbc.pool.DataSource 作为数据源
在 Spring Boot2.x 版 本 中 的 spring-boot-starter-jdbc 启 动 器 中 默 认 使 用 的 是
com.zaxxer.hikariDataSource 作为数据源
1.2.2.1 使用 Spring Boot 默认的 HikariDataSource 数据源
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
将注解注释掉使配置类失效
不用DEBUG直接启动 输出所在包 说明现在创建的数据源就是hikari 数据源
1.2.2.2 使用第三方的 Druid
配置使用Druid数据源
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
1.3 添加用户
1.3.1 创建 POJO
package com.bjsxt.springbootjdbc.pojo;
public class Users {
private Integer userid;
private String username;
private String usersex;
public Integer getUserid() {
return userid;
}
public void setUserid(Integer userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUsersex() {
return usersex;
}
public void setUsersex(String usersex) {
this.usersex = usersex;
}
}
1.3.2 创建页面
addUser/html 放到templates目录下
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Title</title>
</head>
<body>
<form th:action="@{/user/addUser}" method="post">
<input type="text" name="username"/><br/>
<input type="text" name="usersex"/><br/>
<input type="submit" value="OK"/>
</form>
</body>
</html>
1.3.3 创建 Controller
1.3.3.1 PageController
package com.bjsxt.springbootjdbc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 页面跳转Controller
*/
@Controller
public class PageController {
/**
* 页面跳转方法
*/
@RequestMapping("/{page}")
public String showPage(@PathVariable String page) {
return page;
}
}
1.3.3.2 UsersController
package com.bjsxt.springbootjdbc.controller;
import com.bjsxt.springbootjdbc.pojo.Users;
import com.bjsxt.springbootjdbc.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.sql.DataSource;
@Controller
@RequestMapping("/user")
public class UsersController {
@Autowired//注入业务层
private UsersService usersService;
/**
* 添加用户
*/
@PostMapping("/addUser")
public String showInfo(Users users) {
try {
this.usersService.addUser(users);
}catch (Exception e){
e.printStackTrace();
return "error";
}
//重定向放在表单重复提交
return "redirect:/ok";
}
}
1.3.4 创建 Service
package com.bjsxt.springbootjdbc.service;
import com.bjsxt.springbootjdbc.pojo.Users;
public interface UsersService {
void addUser(Users users);
}
package com.bjsxt.springbootjdbc.service.impl;
import com.bjsxt.springbootjdbc.dao.UsersDao;
import com.bjsxt.springbootjdbc.pojo.Users;
import com.bjsxt.springbootjdbc.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 用户管理业务层
*/
@Service
public class UsersServiceImpl implements UsersService {
@Autowired//注入持久层
private UsersDao usersDao;
/**
* 添加用户
* @param users
*/
@Override
@Transactional//配置事务管理
public void addUser(Users users) {
this.usersDao.insertUsers(users);
}
}
1.3.5 创建 Dao
SpringBoot整合的jdbc其实就是SpringFramework中为我们提供基于JDBC来操作数据库的JDBCTemplate,如果在我们的项目中正确的配置了数据源,那SpringBoot在启动时就会初始化JDBCTemplate并且放到IOC容器中,我们可以直接从IOC容器中把JDBCTemplate注入到持久层,然后使用JDBCTemplate下的API完成对数据库的操作
package com.bjsxt.springbootjdbc.dao;
import com.bjsxt.springbootjdbc.pojo.Users;
public interface UsersDao {
void insertUsers(Users users);
}
package com.bjsxt.springbootjdbc.dao.impl;
import com.bjsxt.springbootjdbc.dao.UsersDao;
import com.bjsxt.springbootjdbc.pojo.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
* 持久层
*/
@Repository//注册到IOC容器中
public class UsersDaoImpl implements UsersDao {
@Autowired//注入基于JDBC操作的模板
private JdbcTemplate jdbcTemplate;
/**
* 添加用户
* @param users
*/
@Override
public void insertUsers(Users users) {
String sql = "insert into users(username,usersex) values(?,?)";
this.jdbcTemplate.update(sql, users.getUsername(), users.getUsersex());
}
}
启动测试
错误的解析了 favicon.ico图片
这个URI被PageController拦截下来之后去templates目录下找这个图片
1.3.6 解决 favicon.ico
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
清一下缓存再刷新
之前没有出现这种问题是因为没有用restful风格跳转而是指定url进行跳转没有被Controller拦截到而用restful风格请求时被Controller拦截到了
请求类型错误
表单是post请求而我们用的是get
解决:
1.4 查询用户
1.4.1 修改 Controller
/**
* 查询全部用户
*/
@GetMapping("/findUserAll")
public String findUserAll(Model model) {
List<Users> list = null;
try {
list = this.usersService.findUsersAll();
model.addAttribute("list", list);
} catch (Exception e) {
e.printStackTrace();
return "error";
}
//重定向放在表单重复提交
return "showUsers";
}
1.4.2修改业务层
List<Users> findUsersAll();
/**
* 查询所有用户
* @return
*/
@Override
public List<Users> findUsersAll() {
return this.usersDao.selectUsersAll();
}
1.4.3修改持久层
List<Users> selectUsersAll();
/**
* 查询所有用户
*
* @return
*/
@Override
public List<Users> selectUsersAll() {
String sql = "select * from users";
//查询返回多条数据用 new RowMapper<Users>()
return this.jdbcTemplate.query(sql, new RowMapper<Users>() {
/**
* JDBC不是自动化的ORM框架即便是SpringFramework封装了JDBCTemplate在这个模板下也无法做自动的ORM
* 所以ORM过程还得手动实现
* <p>
* 在处理RowMapper接口回调时在JDBCTemplate.query方法里就创建了list,将返回的users放到list中
* 然后返回list,最后selectUsersAll返回就拿到了所有查到的list集合
* <p>
* 做结果集的映射
*
* @param resultSet
* @param i
* @return
* @throws SQLException
*/
@Override
public Users mapRow(ResultSet resultSet, int i) throws SQLException {
Users users = new Users();
users.setUserid(resultSet.getInt("userid"));
users.setUsername(resultSet.getString("username"));
users.setUsersex(resultSet.getString("usersex"));
return users;
}
});
}
1.4.4创建页面显示查询结果
showUsers.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
<table border="1" align="center">
<tr>
<th>用户ID</th>
<th>用户姓名</th>
<th>用户性别</th>
<th>操作</th>
</tr>
<tr th:each="u : ${list}">
<td th:text="${u.userid}"></td>
<td th:text="${u.username}"></td>
<td th:text="${u.usersex}"></td>
<td>
<a th:href="@{/user/preUpdateUser(id=${u.userid})}">修改</a>
<a th:href="@{/user/deleteUser(id=${u.userid})}">删除</a>
</td>
</tr>
</table>
</body>
</html>
1.5 更新用户
1.5.1 预更新查询
1.5.1.1 修改 Controller
/**
* 预更新用户的查询
*/
@GetMapping("/preUpdateUser")
public String preUpdateUser(Integer id,Model model) {
try {
Users users = this.usersService.findUserById(id);
model.addAttribute("users", users);
} catch (Exception e) {
e.printStackTrace();
return "error";
}
//重定向防止表单重复提交
return "updateUser";
}
1.5.1.2 修改业务层
Users findUserById(Integer id);
/**
* 预更新查询
* @param id
* @return
*/
@Override
public Users findUserById(Integer id) {
return this.usersDao.selectUserById(id);
}
1.5.1.3 修改持久层
Users selectUserById(Integer id);
/**
* 预更新用户查询
*
* @param id
* @return
*/
@Override
public Users selectUserById(Integer id) {
Users user = new Users();
String sql = "select * from users where userid = ?";
//会根据数组里元素的位置和?的位置进行参数的绑定
Object[] arr = new Object[]{id};
//查询返回单条数据用 RowCallbackHandler()
this.jdbcTemplate.query(sql, arr, new RowCallbackHandler() {
@Override
public void processRow(ResultSet resultSet) throws SQLException {
user.setUserid(resultSet.getInt("userid"));
user.setUsername(resultSet.getString("username"));
user.setUsersex(resultSet.getString("usersex"));
}
});
return user;
}
1.5.1.4 创建用户更新页面
updateUsers.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
<form th:action="@{/user/updateUser}" method="post">
<!--隐藏域不给用户看,id不能手动更新-->
<input type="hidden" th:value="${users.userid}"/>
<!--th:value="${users.username}" 数据回填-->
<input type="text" name="username" th:value="${users.username}"/><br/>
<input type="text" name="usersex" th:value="${users.usersex}"/><br/>
<input type="submit" value="OK"/>
</form>
</body>
</html>
1.5.2 更新用户操作
1.5.2.1 修改 Controller
/**
* 更新用户
*/
@PostMapping("/updateUser")
public String updateUser(Users users) {
try {
this.usersService.modifyUser(users);
} catch (Exception e) {
e.printStackTrace();
return "error";
}
//重定向防止表单重复提交
return "redirect:/ok";
}
1.5.2.2 修改业务层
void modifyUser(Users users);
/**
* 更新用户
* @param users
*/
@Override
@Transactional
public void modifyUser(Users users) {
this.usersDao.updateUsers(users);
}
1.5.2.3 修改持久层
void updateUsers(Users users);
/**
* 更新用户
* @param users
*/
@Override
public void updateUsers(Users users) {
String sql = "update users set username = ? , usersex = ? where userid = ?";
this.jdbcTemplate.update(sql, users.getUsername(), users.getUsersex(), users.getUserid());
}
1.6 删除用户
1.6.1 修改 Controller
/**
* @param id 一定要和表单中传过来的key相同
* @return
*/
@GetMapping("/deleteUser")
public String deleteUsers(Integer id) {
try {
this.usersService.dropUser(id);
} catch (Exception e) {
e.printStackTrace();
return "error";
}
//重定向防止表单重复提交
return "redirect:/ok";
}
1.6.2 修改业务层
void dropUser(Integer id);
/**
* 删除用户
* @param id
*/
@Override
@Transactional
public void dropUser(Integer id) {
this.usersDao.deleteUser(id);
}
1.6.3修改持久层
void deleteUser(Integer id);
/**
* 删除用户
* @param id
*/
@Override
public void deleteUser(Integer id) {
String sql = "delete from users where userid = ?";
this.jdbcTemplate.update(sql, id);
}
2 整合 MyBatis
2.1 搭建项目环境
2.1.1创建项目
2.1.2 修改 POM 文件添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>springbootmybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootmybatis</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Mybatis启动器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<!--数据库驱动坐标-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!--Druid数据源依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.1.3 配置数据源
使用英文的冒号,冒号和value 之间有个空格,否则不变色 注意yml格式的层级与缩进的关系
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
2.2 配置 Maven 的 generator 插件
2.2.1 添加 generator插件坐标
<!--配置Generator插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<!--为插件注入数据库驱动-->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
<!--指定配置文件的路径 使用绝对路径 ${project.basedir}:项目的根路径-->
<configuration>
<configurationFile>${project.basedir}/src/main/resources/generatorConfig.xml</configurationFile>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
2.2.2 添加 generator 配置文件
放到resources目录下
修改配置信息
2.2.3 添加 generator 配置文件的 DTD
2.2.4 运行 generator 插件生成代码
2.3 配置资源拷贝插件
2.3.1添加资源拷贝插件坐标
如果将映射配置文件放到resources目录下则不用配置资源拷贝插件
<!--配置资源拷贝插件-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<!--一旦配置了资源拷贝路径默认的resources目录下的资源就不会被拷贝到jar包,得手动配置-->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
<include>**/*.xml</include>
<!--加载模板文件-->
<include>**/*.html</include>
<!--加载静态文件-->
<include>/static/</include>
</includes>
</resource>
</resources>
2.3.2 修改启动类添加@MapperScan 注解
如果不加这个注解 启动失败IOC容器中找不到映射接口和配置文件
package com.bjsxt.springbootmybatis;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.bjsxt.springbootmybatis.mapper")//指定扫描接口与映射配置文件的包名
public class SpringbootmybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootmybatisApplication.class, args);
}
}
2.4MyBatis 的其他配置项
一旦映射配置文件放到了resources目录下就得添加配置项告诉mybatis去哪找映射配置文件
配置之后mybatis就会去classpath(resources)目录下找mapper目录然后扫描所有的xml文件
这两个配置项针对当前项目是不需要配置的
mybatis:
#扫描classpath中mapper目录下的mapper映射配置文件,针对于映射配置文件放到了resources目录下
mapper-locations: classpath:/mapper/*.xml
#定义包别名,使用pojo时可以直接使用pojo的类型不用加包名
type-aliases-package: com.bjsxt.springbootmybatis.pojo
2.5 添加用户功能
2.5.1 创建页面
addUser.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
<form th:action="@{/user/addUser}" method="post">
<input type="text" name="username"/><br/>
<input type="text" name="usersex"/><br/>
<input type="submit" value="OK"/>
</form>
</body>
</html>
error.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
出错了,请与管理员联系!
</body>
</html>
ok.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
操作成功!
</body>
</html>
showUsers.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
<table border="1" align="center">
<tr>
<th>用户ID</th>
<th>用户姓名</th>
<th>用户性别</th>
<th>操作</th>
</tr>
<tr th:each="u : ${list}">
<td th:text="${u.userid}"></td>
<td th:text="${u.username}"></td>
<td th:text="${u.usersex}"></td>
<td>
<a th:href="@{/user/preUpdateUser(id=${u.userid})}">修改</a>
<a th:href="@{/user/deleteUser(id=${u.userid})}">删除</a>
</td>
</tr>
</table>
</body>
</html>
2.5.2 创建 Controller
2.5.2.1 PageController
package com.bjsxt.springbootmybatis.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 页面跳转Controller
*/
@Controller
public class PageController {
/**
* 页面跳转方法
*/
@RequestMapping("/{page}")
public String showPage(@PathVariable String page) {
return page;
}
}
2.5.2.2 UsersController
package com.bjsxt.springbootmybatis.controller;
import com.bjsxt.springbootmybatis.pojo.Users;
import com.bjsxt.springbootmybatis.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 用户管理Controller
*/
@Controller
@RequestMapping("/user")
public class UsersController {
@Autowired
private UsersService usersService;
/**
* 添加用户
*/
@PostMapping("/addUser")
public String addUsers(Users users) {
try {
this.usersService.addUsers(users);
} catch (Exception e) {
e.printStackTrace();
return "error";
}
//使用重定向跳转防止表单重复提交
return "redirect:/ok";
}
}
2.5.3 创建 Service
package com.bjsxt.springbootmybatis.service;
import com.bjsxt.springbootmybatis.pojo.Users;
public interface UsersService {
void addUsers(Users users);
}
package com.bjsxt.springbootmybatis.service.impl;
import com.bjsxt.springbootmybatis.mapper.UsersMapper;
import com.bjsxt.springbootmybatis.pojo.Users;
import com.bjsxt.springbootmybatis.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 用户管理业务层
*/
@Service
public class UsersServiceImpl implements UsersService {
@Autowired
private UsersMapper usersMapper;
@Override
@Transactional
public void addUsers(Users users) {
this.usersMapper.insert(users);
}
}
2.6 查询用户功能
2.6.1 修改 UsersController
/**
* 查询全部用户
*/
@GetMapping("/findUserAll")
public String findUserAll(Model model) {
try {
List<Users> list = this.usersService.findUserAll();
model.addAttribute("list", list);
} catch (Exception e) {
e.printStackTrace();
return "error";
}
//使用重定向跳转防止表单重复提交
return "showUsers";
}
2.6.2修改业务层
List<Users> findUserAll();
/**
* 查询所有用户
*
* @return
*/
@Override
public List<Users> findUserAll() {
//不给任何条件表示查询所有
UsersExample example = new UsersExample();
return this.usersMapper.selectByExample(example);
}
2.6.3创建页面显示查询结果
showUsers.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
<table border="1" align="center">
<tr>
<th>用户ID</th>
<th>用户姓名</th>
<th>用户性别</th>
<th>操作</th>
</tr>
<tr th:each="u : ${list}">
<td th:text="${u.userid}"></td>
<td th:text="${u.username}"></td>
<td th:text="${u.usersex}"></td>
<td>
<a th:href="@{/user/preUpdateUser(id=${u.userid})}">修改</a>
<a th:href="@{/user/deleteUser(id=${u.userid})}">删除</a>
</td>
</tr>
</table>
</body>
</html>
2.7 更新用户功能
2.7.1 预更新用户查询
2.7.1.1 修改 UsersController
/**
* 预更新用户查询
* @param id 必须和传过来请求中参数名一样
* @param model
* @return
*/
@GetMapping("/preUpdateUser")
public String preUpdateUser(Integer id,Model model) {
try {
Users users = this.usersService.preUpdateUsers(id);
model.addAttribute("users", users);
} catch (Exception e) {
e.printStackTrace();
return "error";
}
//使用重定向跳转防止表单重复提交
return "updateUser";
}
2.7.1.2 修改业务层
Users preUpdateUsers(Integer id);
/**
* 预更新查询
* @param id
* @return
*/
@Override
public Users preUpdateUsers(Integer id) {
return this.usersMapper.selectByPrimaryKey(id);
}
2.7.1.3 创建更新用户页面
updateUser.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
<form th:action="@{/user/updateUser}" method="post">
<!--隐藏域不给用户看,id不能手动更新-->
<input type="hidden" name="userid" th:value="${users.userid}"/>
<!--th:value="${users.username}" 数据回填-->
<input type="text" name="username" th:value="${users.username}"/><br/>
<input type="text" name="usersex" th:value="${users.usersex}"/><br/>
<input type="submit" value="OK"/>
</form>
</body>
</html>
2.7.2 更新用户操作
2.7.2.1 修改 UsersController
/**
* 更新用户
*/
@PostMapping("/updateUser")
public String updateUser(Users users) {
try {
this.usersService.updateUsers(users);
} catch (Exception e) {
e.printStackTrace();
return "error";
}
//使用重定向跳转防止表单重复提交
return "redirect:/ok";
}
2.7.2.2 修改业务层
void updateUsers(Users users);
/**
* 更新用户
* @param users
*/
@Override
@Transactional
public void updateUsers(Users users) {
this.usersMapper.updateByPrimaryKey(users);
}
2.8 删除用户功能
2.8.1 修改 UsersController
/**
* 删除用户
* @param id
* @return
*/
@GetMapping("/deleteUser")
public String deleteUsers(Integer id) {
try {
this.usersService.deleteUsers(id);
} catch (Exception e) {
e.printStackTrace();
return "error";
}
//使用重定向跳转防止表单重复提交
return "redirect:/ok";
}
2.8.2修改业务层
void deleteUsers(Integer id);
/**
* 删除用户
* @param id
*/
@Override
public void deleteUsers(Integer id) {
this.usersMapper.deleteByPrimaryKey(id);
}
十、 SpringBoot 中异常处理与单元测试
1 异常处理
SpringBoot 中对于异常处理提供了五种处理方式
1.1 自定义错误页面
SpringBoot默认的处理异常的机制:SpringBoot默认的已经提供了一套处理异常的机制。一旦程序中出现了异常 SpringBoot 会向/error 的 url 发送请求。在 SpringBoot 中提供了一个名为 BasicErrorController 来处理/error 请求,然后跳转到默认显示异常的页面来展示异常信息。
如 果 我 们 需 要 将 所 有 的 异 常 同 一 跳 转 到 自 定 义 的 错 误 页 面 , 需 要 再
src/main/resources/templates 目录下创建 error.html 页面。注意:页面名称必须叫 error
SpringBoot默认跳到这个页面展示错误信息
SpringBoot默认去请求 error 这个URI如果没找到这个URI对应的资源默认展示自己的错误页面,这就是为什么我们的自定义的错误页面必须叫error
error.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Title</title>
</head>
<body>
出错了,请与管理员联系!
</body>
</html>
1.2 通过@ExceptionHandler 注解处理异常
1.2.1 修改 Controller
package com.bjsxt.springbootexceptionandjunit.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class UsersController {
@RequestMapping("/showInfo")
public String showInfo() {
//人为制造异常
String str = null;
str.length();
return "ok";
}
/**
* 指定处理哪种异常就给哪种异常的类全名,处理多个异常用逗号隔开
*
* @ExceptionHandler 会向方法中注入参数 Exception e,会将出现的异常对象传递到方法中
*我们拿着异常对象做信息的处理和页面的跳转
* @return
*/
@ExceptionHandler(value = {java.lang.NullPointerException.class})
public ModelAndView nullPointExceptionHandler(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("err", e.toString());
mv.setViewName("error1");
return mv;
}
}
1.2.2 创建页面
error1.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Title</title>
</head>
<body>
出错了
<span th:text="${err}"/>
</body>
</html>
1.3 通过@ControllerAdvice 与@ExceptionHandler 注解处理异常
1.3.1创建全局异常处理类
error2.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Title</title>
</head>
<body>
出错了 ........ 算术异常
<span th:text="${err}"/>
</body>
</html>
package com.bjsxt.springbootexceptionandjunit.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
/**
* 全局异常处理类
*/
@ControllerAdvice//必须加这个注解标明是全局异常处理类
public class GlobalException {
/**
* 指定处理哪种异常就给哪种异常的类全名
*
* @ExceptionHandler 会向方法中注入参数 Exception e,会将出现的异常对象传递到方法中
*我们拿着异常对象做信息的处理和页面的跳转
* @return
*/
@ExceptionHandler(value = {java.lang.NullPointerException.class})
public ModelAndView nullPointExceptionHandler(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("err", e.toString());
mv.setViewName("error1");
return mv;
}
@ExceptionHandler(value = {java.lang.ArithmeticException.class})
public ModelAndView arithmeticExceptionExceptionHandler(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("err", e.toString());
mv.setViewName("error2");
return mv;
}
}
1.4 通过 SimpleMappingExceptionResolver 对象处理异常
1.4.1 创建全局异常处理类
注释掉使之失效
error3.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Title</title>
</head>
<body>
出错了。。。。。。。 java.lang.NullPointerException
</body>
</html>
error4.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Title</title>
</head>
<body>
出错了 ........ 算术异常 。。。java.lang.ArithmeticException
</body>
</html>
只能做异常类型和视图的映射不能传递异常对象
package com.bjsxt.springbootexceptionandjunit.exception;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.Properties;
/**
* 全局异常
* SimpleMappingExceptionResolver
*/
@Configuration
public class GlobalException2 {
/**
* 此方法返回值必须是SimpleMappingExceptionResolver对象
* @return
*/
@Bean
public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver() {
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
/**
* arg1:异常类型,并且是全名
* arg2:视图名称
*/
//只能做异常类型和视图的映射不能传递异常对象
properties.put("java.lang.NullPointerException", "error3");
properties.put("java.lang.ArithmeticException", "error4");
//将properties对象放到SimpleMappingExceptionResolver对象中
resolver.setExceptionMappings(properties);
return resolver;
}
}
1.5 通过自定义 HandlerExceptionResolver 对象处理异常
1.5.1创建全局异常处理类
将GlobalException2全部注释掉
error5.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Error5</title>
</head>
<body>
出错了。。。。。。。 <span th:text="${error}"/>
</body>
</html>
error6.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Error6</title>
</head>
<body>
出错了 ........ <span th:text="${error}"/>
</body>
</html>
package com.bjsxt.springbootexceptionandjunit.exception;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义 HandlerExceptionResolver 对象处理异常
* 必须要实现HandlerExceptionResolver接口
*/
@Configuration
public class GlobalException3 implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception e) {
ModelAndView mv = new ModelAndView();
//判断不同异常类型,做不同视图跳转
if (e instanceof NullPointerException) {
mv.setViewName("error5");
}
if (e instanceof ArithmeticException) {
mv.setViewName("error6");
}
//添加传递过来的异常信息 一次请求最多出现一种异常,所以放在if外侧
mv.addObject("error", e.toString());
return mv;
}
}
2 Spring Boot 整合 Junit 单元测试
SpringBoot2.x 使用 Junit5 作为测试平台
这是使用Junit4
2.1 修改 POM 文件添加 Test
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<!--junit-vintage-engine: 提供了Junit3和Junit4的运行平台-->
<exclusions>
<!--排除掉这个依赖,排除之后测试启动器里不支持Junit3和Junit4的测试-->
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
2.2编写测试代码
package com.bjsxt.springbootexceptionandjunit.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UsersDaoImpl {
public void insert() {
System.out.println("insert into users Test.............");
}
}
package com.bjsxt.springbootexceptionandjunit.service;
import com.bjsxt.springbootexceptionandjunit.dao.UsersDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UsersServiceImpl {
@Autowired
private UsersDaoImpl usersDao;
public void addUsers() {
this.usersDao.insert();
}
}
package com.bjsxt.springbootexceptionandjunit;
import com.bjsxt.springbootexceptionandjunit.service.UsersServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(classes = SpringbootexceptionandjunitApplication.class)
class SpringbootexceptionandjunitApplicationTests {
//将业务层注入到测试类中
@Autowired
private UsersServiceImpl usersService;
@Test
void contextLoads() {
this.usersService.addUsers();
}
}
如果只有一个启动类使用Junit5做测试添加启动器的类与否都没问题,如果有多个启动类想要针对每个不同的启动类去启动项目做测试就需要用classes指定Junit在运行时基于哪个启动类去启动项目
十一、 Spring Boot 服务端数据校验
1 Spring Boot 对实体对象的校验
1.1 搭建项目环境
1.1.1创建项目
1.1.2创建实体
package com.bjsxt.springbootvalidate.pojo;
public class Users {
private Integer userid;
private String username;
private String usersex;
public Integer getUserid() {
return userid;
}
public void setUserid(Integer userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUsersex() {
return usersex;
}
public void setUsersex(String usersex) {
this.usersex = usersex;
}
@Override
public String toString() {
return "Users{" +
"userid=" + userid +
", username='" + username + '\'' +
", usersex='" + usersex + '\'' +
'}';
}
}
1.1.3 创建 Controller
package com.bjsxt.springbootvalidate.controller;
import com.bjsxt.springbootvalidate.pojo.Users;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UsersController {
/**
* 添加用户
*/
@RequestMapping("/addUser")
public String addUser(Users users) {
System.out.println(users);
return "ok";
}
}
1.1.4创建页面
addUser.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
<form th:action="@{/user/addUser}" method="post">
<input type="text" name="username"/><br/>
<input type="text" name="usersex"/><br/>
<input type="submit" value="OK"/>
</form>
</body>
</html>
ok.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
操作成功!
</body>
</html>
1.2 对实体对象做数据校验
1.2.1Spring Boot 数据校验的技术特点
Spring Boot 中使用了 Hibernate-validator 校验框架。
<!--导入 Hibernate-validate 校验框架依赖坐标-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
1.2.2 对实体对象数据校验步骤
1.2.2.1修改实体添加校验规则
package com.bjsxt.springbootvalidate.pojo;
import com.sun.istack.internal.NotNull;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
/**
* @NotNull:对基本数据类型的对象类型做非空校验(int的对象类型是Integer)
*@NotBlank:对字符串类型做非空校验
*@NotEmpty:对集合类型做非空校验
*/
public class Users {
@NotNull
private Integer userid;
@NotBlank
private String username;
@NotBlank
private String usersex;
public Integer getUserid() {
return userid;
}
public void setUserid(Integer userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUsersex() {
return usersex;
}
public void setUsersex(String usersex) {
this.usersex = usersex;
}
@Override
public String toString() {
return "Users{" +
"userid=" + userid +
", username='" + username + '\'' +
", usersex='" + usersex + '\'' +
'}';
}
}
1.2.2.2 在Controller中开启校验
/**
* 添加用户
* 校验哪个对象就在哪个对象前添加@Validated,并在其后添加包含校验不合法信息的BindingResult result
*/
@RequestMapping("/addUser")
public String addUser(@Validated Users users, BindingResult result) {
if (result.hasErrors()) {
/*List<ObjectError> list = result.getAllErrors();
for (ObjectError err : list) {
//fieldError是ObjectError的子类,强转
FieldError fieldError = (FieldError) err;
String fieldName = fieldError.getField();
String msg = fieldError.getDefaultMessage();
System.out.println(fieldName+"\t"+msg);
}*/
return "addUser";
}
System.out.println(users);
return "ok";
}
ok.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
操作成功!
</body>
</html>
1.2.2.3 在页面中获取提示信息
addUser.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
<form th:action="@{/user/addUser}" method="post">
<input type="text" name="username"/><font color="#dc143c"><span th:errors="${users.username}"/></font><br/>
<input type="text" name="usersex"/><font color="#dc143c"><span th:errors="${users.usersex}"/></font><br/>
<input type="submit" value="OK"/>
</form>
</body>
</html>
<!--可以直接从BindingResult中获取错误信息-->
<span th:errors="${users.username}"/>
Controller返回addUser会把BindingResult对象传递到页面中,在页面中通过th:errors="" (注意key的命名)来取BindingResult对象中的错误信息
给userid一个参数
userid不报空
1.2.3 自定义错误提示信息
1.2.3.1 在注解中定义提示信息
package com.bjsxt.springbootvalidate.pojo;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* @NotNull:对基本数据类型的对象类型做非空校验(int的对象类型是Integer)
*@NotBlank:对字符串类型做非空校验
*@NotEmpty:对集合类型做非空校验
*/
public class Users {
@NotNull(message = "用户ID不能为空")
private Integer userid;
@NotBlank(message = "用户姓名不能为空")
private String username;
@NotBlank(message = "用户性别不能为空")
private String usersex;
public Integer getUserid() {
return userid;
}
public void setUserid(Integer userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getUsersex() {
return usersex;
}
public void setUsersex(String usersex) {
this.usersex = usersex;
}
@Override
public String toString() {
return "Users{" +
"userid=" + userid +
", username='" + username + '\'' +
", usersex='" + usersex + '\'' +
'}';
}
}
1.2.3.2 在配置文件中定义提示信息
配置文件名必须是 ValidationMessages.properties放到resources目录下
userid.notnull=用户ID不能为空-properties
username.notnull=用户姓名不能为空-properties
usersex.notnull=用户性别不能为空-properties
properties文件里使用的是ISO编码格式,所以出现乱码
1.2.4 解决页面跳转异常
在跳转页面的方法中注入一个对象,要求参数对象的变量名必须是对象类型名称首字母小写格式。
直接从key跳转请求addUser
这里出错,从PageController中跳转根本没有给Users对象
解决办法:在跳转页面的方法中添加一个Users
package com.bjsxt.springbootvalidate.controller;
import com.bjsxt.springbootvalidate.pojo.Users;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class PageController {
/**
* 跳转页面的方法
* 解决异常的方法:可以在跳转页面的方法中注入一个Users对象
* 由于SpringMVC会将该对象放入到Model中传递到页面中,key的名称会使用该对象的
* 驼峰命名规则来作为key
*/
@RequestMapping("/{page}")
public String showPage(@PathVariable String page, Users users) {
return page;
}
}
点击OK
1.2.5 修改参数 key 的名称
入参的参数名无关而是和入参的类型有关
即使将入参名字改为suibian也无妨
修改key
报错原因的key不匹配 放在model中对象的key叫aa而页面中叫users
在页面中的key得改名
点击OK出现错误页面是因为请求了UserController里面的addUser方法,在这个方法里出现校验不合法时会return到addUser,一返回addUser SpringMVC会把Users带回去还是使用对象的名字作为key,而在表单中的key是aa又不匹配了
所以UserController里面的入参名称也得改 表示未来跳转到addUser页面时所传递的Users对象的key用的也是aa 这样就保证了在PageController里面跳转页面所传递的Users的key是aa,UsersController里面跳转页面所传递的Users的key也叫aa
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jV3vp5h1-1607313844752)(SpringBoot.assets/
)]
package com.bjsxt.springbootvalidate.controller;
import com.bjsxt.springbootvalidate.pojo.Users;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Controller
@RequestMapping("/user")
public class UsersController {
/**
* 添加用户
* 校验哪个对象就在哪个对象前添加@Validated,并在其后添加包含校验不合法信息的BindingResult result
*/
@RequestMapping("/addUser")
public String addUser(@ModelAttribute("aa") @Validated Users users, BindingResult result) {
if (result.hasErrors()) {
List<ObjectError> list = result.getAllErrors();
for (ObjectError err : list) {
//fieldError是ObjectError的子类,强转
FieldError fieldError = (FieldError) err;
String fieldName = fieldError.getField();
String msg = fieldError.getDefaultMessage();
System.out.println(fieldName+"\t"+msg);
}
return "addUser";
}
System.out.println(users);
return "ok";
}
}
package com.bjsxt.springbootvalidate.controller;
import com.bjsxt.springbootvalidate.pojo.Users;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class PageController {
/**
* 跳转页面的方法
* 解决异常的方法:可以在跳转页面的方法中注入一个Users对象
* 由于SpringMVC会将该对象放入到Model中传递到页面中,key的名称会使用该对象的
* 驼峰命名规则来作为key
*
* @ModelAttribute("aa"):指定放在model中对象的key叫什么
*/
@RequestMapping("/{page}")
public String showPage(@PathVariable String page,@ModelAttribute("aa") Users suibian) {
return page;
}
}
addUser.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
<form th:action="@{/user/addUser}" method="post">
<input type="text" name="username"/><font color="#dc143c"><span th:errors="${aa.username}"/></font><br/>
<input type="text" name="usersex"/><font color="#dc143c"><span th:errors="${aa.usersex}"/></font><br/>
<input type="submit" value="OK"/>
</form>
</body>
</html>
如果有其他的方法要跳到addUser还有修改key为aa,方法的入参前面也得加 @ModelAttribute(“aa”)
1.2.6 其他校验规则
@NotNull: 判断基本数据类型的对象类型是否为 null
@NotBlank: 判断字符串是否为 null 或者是空串(去掉首尾空格)。
@NotEmpty: 判断集合是否为空。
@Length: 判断字符的长度(最大或者最小)
@Min: 判断数值最小值
@Max: 判断数值最大值
@Email: 判断邮箱是否合法
还可以用message属性做提示信息的替换
2 Spring Boot 对 Controller 中其他参数的校验
findUser.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head>
<title>Title</title>
</head>
<body>
<form th:action="@{/user/findUser}" method="post">
<input type="text" name="username"/><br/>
<input type="submit" value="OK"/>
</form>
</body>
</html>
对除了实体类型的其他数据做校验时并没有要求一个BindingResult参数,这时一旦校验不合法会直接以一个异常的形式通知校验不合法
按照我们的设计一旦某个参数校验不合法让它跳回到这个页面,并且将校验结果显示出来
2.1 编写页面
2.2对参数指定校验规则
@PostMapping("/findUser")
public String findUser(@NotBlank(message = "用户名不能为空") String username) {
System.out.println(username);
return "ok";
}
2.3 在 Controller 中开启校验
package com.bjsxt.springbootvalidate.controller;
import com.bjsxt.springbootvalidate.pojo.Users;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.constraints.NotBlank;
import java.util.List;
@Controller
@RequestMapping("/user")
@Validated//开启校验的注解
public class UsersController {
/**
* 添加用户
* 校验哪个对象就在哪个对象前添加@Validated,并在其后添加包含校验不合法信息的BindingResult result
*/
@RequestMapping("/addUser")
public String addUser(@ModelAttribute("aa") @Validated Users users, BindingResult result) {
if (result.hasErrors()) {
List<ObjectError> list = result.getAllErrors();
for (ObjectError err : list) {
//fieldError是ObjectError的子类,强转
FieldError fieldError = (FieldError) err;
String fieldName = fieldError.getField();
String msg = fieldError.getDefaultMessage();
System.out.println(fieldName + "\t" + msg);
}
return "addUser";
}
System.out.println(users);
return "ok";
}
@PostMapping("/findUser")
public String findUser(@NotBlank(message = "用户名不能为空") String username) {
System.out.println(username);
return "ok";
}
}
2.4通过全局异常处理来跳转页面
package com.bjsxt.springbootvalidate.exception;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
/**
* 自定义 HandlerExceptionResolver 对象处理异常
* 必须要实现HandlerExceptionResolver接口
*/
@Configuration
public class GlobalException implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception e) {
ModelAndView mv = new ModelAndView();
//判断不同异常类型,做不同视图跳转
if (e instanceof NullPointerException) {
mv.setViewName("error5");
}
if (e instanceof ArithmeticException) {
mv.setViewName("error6");
}
if (e instanceof ConstraintViolationException) {
mv.setViewName("findUser");
}
//添加传递过来的异常信息 一次请求最多出现一种异常,所以放在if外侧
mv.addObject("error", e.getMessage().split(":")[1]);//用.split()方法对返回的错误信息进行处理
return mv;
}
}
把findUser带回来了,对返回的信息进行处理即可
自定义错误信息
十二、 Spring Boot 热部署
1 通过 DevTools 工具实现热部署
只要代码有修改就自动部署运行
1.1 修改 POM 文件,添加 DevTools 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
1.2 配置 Idea
1.2.1设置自动编译
1.2.2 设置 Idea 的 Registry
通过快捷键打开该设置项:Ctrl+Shift+Alt+/
勾选 complier.automake.allow.when.app.running
勾选之后点CLOSE
启动项目测试
修改一行代码项目会自动部署运行,再刷新页面
去掉打印page的语句观察控制台
自动部署
前台页面也可以热部署
刷新
十三、 Spring Boot 度量指标监控与健康检查
1 使用 Actuator 检查与监控
1.1创建项目
1.2 需改 POM 文件,添加依赖
<!--Actuator依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
启动项目 在/actuator 基础路径上默认只开启两个端点
访问/actuator 返回了一个JSON格式的数据
/health 返回的信息是当前项目的运行状态
/info
/configprops
1.3修改配置文件
默认就是路径 /actuator
开启所有端点访问路径但是排除env
指定开启
重启项目,在/actuator 基础路径上已经暴露了13个端点
开启所有端点
访问/env /actuator返回的所有格式都是基于JSON格式返回的
/beans
1.4 各项监控指标接口 URL
2 使用可视化监控应用 Spring BootAdmin
2.1 使用步骤
Spring BootAdmin 的使用是需要建立服务端与客户端。
服务端:独立的项目,会将搜集到的数据在自己的图形界面中展示。
客户端:需要监控的项目。
对应关系:一个服务端可以监控多个客户端。
在客户端的配置文件里指定服务端的地址,相当于建立客户端和服务端的联系
2.1.1 搭建服务端
2.1.1.1 创建项目
2.1.1.2 修改 POM 文件
注意:目前在 Spring BootAdmin Starter Server2.1.6 版本中不支持 Spring Boot2.2.x 版本,只支持到 2.1.X
改变SpringBoot版本
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- https://mvnrepository.com/artifact/de.codecentric/spring-boot-admin-starter-server -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.1.6</version>
</dependency>
在服务端是不需要加Actuator依赖,只有被监控的客户端才需要,Actuator依赖的作用就是指定一些端点的开发,服务端只是手机客户端的端点信息,服务端本身是不需要的,除非服务端本身也要被监控才加Actuator依赖
2.1.1.3 修改配置文件
避免服务端和客户端端口抢占
2.1.1.4 修改启动类
@EnableAdminServer :开启Spring Boot Admin服务端
package com.bjsxt.springbootactuatorservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableAdminServer//开启Spring Boot Admin服务端
public class SpringbootactuatorserviceApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootactuatorserviceApplication.class, args);
}
}
启动:
访问9090:
2.2 搭建客户端
尽量保证服务端和客户端的版本相同,服务端用的是2.1.6,那么客户端也要用2.1.6的版本,客户端对于SpringBoot的版本没有要求
2.2.1 修改 POM
<!-- https://mvnrepository.com/artifact/de.codecentric/spring-boot-admin-starter-client -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.1.6</version>
</dependency>
2.2.2修改配置文件
被监控的客户端必须要开启访问断点,可以是 * 也可以指定端点
#配置访问端点的根路径
management.endpoints.web.base-path=/actuator
#配置开启其他端点的URI include:包含哪些访问的URI exclude:排除哪些访问的URI
#开启所有的端点访问:*
#指定开启端点访问:如beans,env端点之间逗号分隔
management.endpoints.web.exposure.include=*
#指定服务端的访问地址
spring.boot.admin.client.url=http://localhost:9090
2.2.3效果图
INSTANCES中有一个实例了
十四、 Spring Boot 的日志管理
Spring Boot 默认使用 Logback 组件作为日志管理。Logback 是由 log4j 创始人设计的一个开源日志组件。
在 Spring Boot 项目中我们不需要额外的添加 Logback 的依赖,因为在 spring-boot-starter或者 spring-boot-starter-web 中已经包含了 Logback 的依赖。
1 Logback 读取配置文件的步骤
(1)在 classpath 下查找文件 logback-test.xml
(2)如果文件不存在,则查找 logback.xml
(3)如果两个文件都不存在,LogBack 用 BasicConfiguration 自动对自己进行最小化配置,这样既实现了上面我们不需要添加任何配置就可以输出到控制台日志信息。
2 添加 Logback
3 配置 Logback
4 在代码中使用 Logback
package com.bjsxt.springbootlogback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController//返回json就可以了不要求视图跳转
@RequestMapping("/logback")
public class HelloController {
//对哪个类做日志记录就给哪个类的class
private final static Logger logger = LoggerFactory.getLogger(HelloController.class);
@RequestMapping("/showInfo")
public String showInfo() {
//输出的方法得与配置文件里的日志输出级别相符
logger.info("记录日志");
return "Hello logback";
}
}
5 在配置文件中屏蔽指定包的日志记录
屏蔽掉com包下的日志记录
屏蔽掉org日志记录
观察控制台日志输出
十五、 Spring Boot 项目打包与多环境配置
1 Spring Boot 项目打包
基于官网或者IDEA脚手架创建的项目会自带打包插件但是基于maven创建的项目不带打包插件需要手动添加
这个插件在基于maven命令打包时会把SpringBoot所依赖的所有jar放到项目中,如果没有用这个插件也可以打包但是项目中不包含SpringBoot所依赖的所有jar包,一启动就报错
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
1.1Spring Boot
1.2项目打包方式
跳过测试
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-filtering</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
</plugin>
1.3 运行命令
注意:需要正确的配置环境变量。
运行命令:java -jar 项目的名称
2 Spring Boot 的多环境配置
语法结构:application-{profile}.properties/yml
profile:代表某个配置环境的标识
示例:application-dev.properties/yml 开发环境
application-test.properties/yml 测试环境
application-prod.properties/yml 生产环境
这个命令默认加载application.properties/yum文件的,现在配置了多配置文件必须指定
2.1Windows 环境下启动方式
java -jar xxx.jar --spring.profiles.active={profile}
使用application-dev.properties文件启动项目
启动项目之后按Ctrl + C 停止项目
用另一个配置文件 application-test.properties启动项目
2.2在 在 Linux 环境下启动方式
2.2.1 安装上传下载工具
安装命令:yum install lrzsz -y
上传命令:rz
下载命令:sz 下载文件名
2.2.2 启动脚本的使用
修改脚本文件中的参数值
#!/bin/bash
cd `dirname $0`
CUR_SHELL_DIR=`pwd`
CUR_SHELL_NAME=`basename ${BASH_SOURCE}`
JAR_NAME="springbootlogback-0.0.1-SNAPSHOT.jar"
JAR_PATH=$CUR_SHELL_DIR/$JAR_NAME
#JAVA_MEM_OPTS=" -server -Xms1024m -Xmx1024m -XX:PermSize=128m"
JAVA_MEM_OPTS=""
#如果是多环境配置需要在该选项中指定profile
SPRING_PROFILES_ACTIV="-Dspring.profiles.active=dev"
#如果没有多环境配置将 SPRING_PROFILES_ACTIV注释掉,将SPRING_PROFILES_ACTIV=""释放开
#SPRING_PROFILES_ACTIV=""
LOG_DIR=$CUR_SHELL_DIR/logs
LOG_PATH=$LOG_DIR/${JAR_NAME%..log
echo_help()
{
echo -e "syntax: sh $CUR_SHELL_NAME start|stop"
}
if [ -z $1 ];then
echo_help
exit 1
fi
if [ ! -d "$LOG_DIR" ];then
mkdir "$LOG_DIR"
fi
if [ ! -f "$LOG_PATH" ];then
touch "$LOG_DIR"
fi
if [ "$1" == "start" ];then
# check server
PIDS=`ps --no-heading -C java -f --width 1000 | grep $JAR_NAME | awk '{print $2}'`
if [ -n "$PIDS" ]; then
echo -e "ERROR: The $JAR_NAME already started and the PID is ${PIDS}."
exit 1
fi
echo "Starting the $JAR_NAME..."
# start
nohup java $JAVA_MEM_OPTS -jar $SPRING_PROFILES_ACTIV $JAR_PATH >> $LOG_PATH 2>&1 &
COUNT=0
while [ $COUNT -lt 1 ]; do
sleep 1
COUNT=`ps --no-heading -C java -f --width 1000 | grep "$JAR_NAME" | awk '{print $2}' | wc -l`
if [ $COUNT -gt 0 ]; then
break
fi
done
PIDS=`ps --no-heading -C java -f --width 1000 | grep "$JAR_NAME" | awk '{print $2}'`
echo "${JAR_NAME} Started and the PID is ${PIDS}."
echo "You can check the log file in ${LOG_PATH} for details."
elif [ "$1" == "stop" ];then
PIDS=`ps --no-heading -C java -f --width 1000 | grep $JAR_NAME | awk '{print $2}'`
if [ -z "$PIDS" ]; then
echo "ERROR:The $JAR_NAME does not started!"
exit 1
fi
echo -e "Stopping the $JAR_NAME..."
for PID in $PIDS; do
kill $PID > /dev/null 2>&1
done
COUNT=0
while [ $COUNT -lt 1 ]; do
sleep 1
COUNT=1
for PID in $PIDS ; do
PID_EXIST=`ps --no-heading -p $PID`
if [ -n "$PID_EXIST" ]; then
COUNT=0
break
fi
done
done
echo -e "${JAR_NAME} Stopped and the PID is ${PIDS}."
else
echo_help
exit 1
fi
将启动脚本文件上传到 Linux 中
分配执行权限:chmod 777
777:可读可写可执行
文件变成可执行文件
通过脚本启动命令:server.sh start
用的是相对路径得保证项目和启动脚本和项目在同一个目录下
第二个是日志文件
关闭防火墙访问项目
通过脚本关闭命令:server.sh stop
将dev改为text测试不同配置文件
再次启动项目