SpringBoot学习笔记

SpringBoot

1. 学习目标

在这里插入图片描述

2. Spring框架发展史

2.1. Spring1.x 时代

​ 在 Spring1.x 时代,都是通过 xml ⽂件配置 bean,随着项⽬的不断扩⼤,需要将 xml 配置分放到不同的配置⽂件中,需要频繁的在 java 类和 xml 配置⽂件中切换。

2.2. Spring2.x 时代

​ 随着 JDK 1.5 带来的注解⽀持,Spring2.x 可以使⽤注解对Bean进⾏声明和注⼊,大大的减少了 xml配置⽂件,同时也大大简化了项⽬的开发。

那么,问题来了,究竟是应该使⽤ xml 还是注解呢?

最佳实践:

  1. 应⽤的基本配置⽤ xml,⽐如:数据源、资源⽂件等;

  2. 业务开发⽤注解,⽐如:Service 中注⼊ bean 等;

2.3. Spring3.x到 Spring4.x 再到 Spring5.x

​ 从 Spring3.x 开始提供了 Java 配置⽅式,使⽤ Java 配置⽅式可以更好的理解你配置的 Bean,现在我们就处于这个时代,并且 Spring4.x、Spring5.x 和 Spring Boot 都推荐使⽤ java 配置的⽅式。

3.Spring 5.X应用零配置开发

​ Spring 框架从 5.x 版本推荐使⽤注解形式来对 java 应⽤程序进行开发与配置,并且可以完全替代原始的 XML + 注解形式的开发,在使⽤注解形式进行项目开发与环境配置时,Spring 框架提供了针对环境配置与业务 bean 开发相关注解。

3.1. 注解

3.1.1. 声明Bean 注解
@Component: 组件 没有明确规定其⻆⾊,作⽤在类级别上声明当前类为⼀个业务组件,被Spring Ioc容器维护
@Service: 在业务逻辑层(Service 层)类级别进⾏声明
@Repository: 在数据访问层(dao 层) 类级别声明
@Controller: 在展现层(MVC) 使⽤ 标注当前类为⼀个控制器
3.1.2.注入Bean 注解
@AutoWired: Spring 官⽅提供注解
@Inject: JSR-330 提供注解(标准制定⽅)
@Resource: JSR-250 提供注解

​ 以上三种注解在 Set ⽅法或属性上声明,⼀般情况下通⽤⼀般开发中更习惯声明在属性上,代码简洁清晰。基于5.x 注解配置⽅式简化了xml 配置,应⽤程序开发与xml 环境配置均通过相应注解来实现。

3.1.3. Spring5.x 中配置与获取Bean注解
 @Configuration: 作⽤与类上,将当前类声明为⼀个配置类,相当于⼀个xml 配置⽂件
 @ComponentScan: ⾃动扫描指定包下标注有@Repository,@Service,@Controller
 @Component: 注解的类并由Ioc 容器进⾏实例化和维护
 @Bean: 作⽤于⽅法上,相当于xml ⽂件中<bean> 声明当前⽅法返回值为⼀个bean
 @Value: 获取properties ⽂件指定key value值

3.2.实例1 - IOC中Bean的实例化与获取

3.2.1. 创建 Spring普通⼯程

​ 在 pom.xml 中添加坐标相关配置

<dependencies>
  <!-- spring的依赖坐标 -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.4.RELEASE</version>
  </dependency>
</dependencies>
  <build>
    <plugins>
      <!-- 指定Maven编译的JDK版本和编码 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
          <!-- 源代码使⽤的JDK版本 -->
          <source>1.8</source>
          <!-- 需要⽣成的⽬标class⽂件的编译版本 -->
          <target>1.8</target>
          <!-- 字符集编码 -->
          <encoding>utf-8</encoding>
        </configuration>
      </plugin>
    </plugins>
  </build>
3.2.2. 创建 Bean 对象

UserDao.java

@Repository
public class UserDao {
 	public void test(){
 		System.out.println("UserDao.test...");
 	}
}

UserService.java

@Service
public class UserService {
 	@Resource
	private UserDao userDao;
 	public void test(){
 		System.out.println("UserService.test...");
 		userDao.test();
 	}
}
3.2.3. 创建 IocConfig 配置类
// 将当前类声明为⼀个配置类
@Configuration
// 设置扫描包范围
@ComponentScan("com.xxxx.springboot")
	public class IocConfig {
}
3.2.4. 创建启动类执行测试
public class Starter {
 	public static void main(String[] args) {
 		// 基于Java的配置类加载Spring的应⽤上下⽂
 		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(IocConfig.class);
 		// 获取指定的Bean对象
 		UserService userService = ac.getBean(UserService.class);
 		// 调⽤Bean对象的⽅法
 		userService.test();
 	}
}

​ 此时启动 Spring IOC 容器,通过实例化 AnnotationConfigApplicationContext 类,接收配置参数类IocConfig,并获取 UserService Bean 实现⽅法调⽤,此时应⽤环境不存在 xml 配置⽂件,简化了应⽤的 xml 配置。

3.3. 实例2 - @Bean注解使用

​ 使⽤@Bean 注解声明在⽅法(注意:⽅法名⼀般为bean对象名称)级别⽤于返回实例化的Bean对象。

3.3.1. 创建 Bean 对象

AccountDao.java

// 注意:此时类级别并未添加 @Repository 注解
public class AccountDao {
 	public void test(){
 		System.out.println("AccountDao.test...");
 	}
}
3.3.2. 修改 IocConfig 配置类

添加返回AccountDao Bean对象⽅法

@Configuration
@ComponentScan("com.shsxt")
public class IocConfig2 {
    @Bean
    public UserDao userDao(){
        return new UserDao();
    }
}
3.3.3. 创建启动类并执⾏测试
public class Starter {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(IocConfig.class);
        UserService userService = (UserService) ac.getBean("userService");
        userService.test();
        System.out.println(ac.isSingleton("iocConfig"));
        IocConfig2 iocConfig2 = (IocConfig2) ac.getBean("iocConfig2");
        UserDao userDao = iocConfig2.userDao();
        UserDao userDao2 = iocConfig2.userDao();
        System.out.println(userDao+"---"+userDao2);
    }
}

3.4. 实例3 - 读取外部配置文件

​ 在开发 Java web 应⽤时,配置⽂件是⽐较常⻅的,⽐如 xml,properties,yml 等⽂件,在 Spring应⽤中对于配置⽂件的读取同样提供⽀持。对于配置⽂件读取,我们可以通过 @PropertySource 注解声明到类级别来指定读取相关配置。

​ Spring El 表达式语⾔,⽀持在 Xml 和注解中使⽤表达式,类似于 JSP 中 EL 表达式,Spring 框架借助该表达式实现资源注⼊,主要通过 @Value 注解来使⽤表达式,通过 @Value 注解,可以实现普通字符串,表达式运算结果,Bean 属性⽂件内容,属性⽂件等参数注⼊。具体使⽤如下:

3.4.1. 准备配置文件

​ src/main/resources ⽬录下添加 user.properties、jdbc.properties ⽂件

# user.properties
user.userName=admin
user.password=admin

# jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/hr?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
3.4.2. @PropertySource加载配置⽂件

通过 @PropertySource 加载 properties 配置⽂件

@Configuration
@ComponentScan("com.shsxt")
@PropertySource(value = {"classpath:db.properties"})
public class IocConfig3 {

    @Value("${jdbc.userName}")
    private String username;
    @Value("${jdbc.pwd}")
    private String pwd;
    
    public String show() {
        return "IocConfig3{" +
                "username='" + username + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
3.4.3. 其他Bean对象获取properties文件内容
@Service
public class UserService {
 	@Resource
 	private UserDao userDao;
 	@Value("${user.userName}")
 	private String userName;
 	@Value("${user.password}")
 	private String password;
 	public void test(){
 		System.out.println("UserService.test...");
 		userDao.test();
 		System.out.println("userName:" + userName + ",password:" + password);
	 }
}

3.5. 组合注解与元注解

​ Spring 从2.x版本开始引⼊注解⽀持(⽬的是jdk1.5中推出注解功能),通过引⼊注解来消除⼤量xml 配置,Spring 引⼊注解主要⽤来注⼊ bean 以及 aop 切⾯相关配置,但由于注解⼤量使⽤,就会造成⼤量重复注解代码出现,代码出现了重复,Spring 为了消除重复注解,在元注解上引⼊了组合注解,其实可以理解为对代码的重构,相当于注解的注解,拥有元注解的原始功能,⽐如在定义配置类时⽤到的@Configuration 注解就是组合注解,拥有 @Component 注解功能,即配置类本身也是⼀个被 IOC 维护的单例 Bean。

3.5.1. ⾃定义组合注解

定义 MyCompScan 注解,拥有 @ComponentScan 扫描器注解功能

/**
* 组合注解MyCompScan 定义
* 拥有元注解@Configuration + @ComponentScan 两者功能
* 覆盖 value 属性
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Configuration
@ComponentScan
public @interface MyCompScan {
 	String[] value() default {};
}

若出现错误需要配置别名value设置在@ComponentScan中

3.5.2. 应用组合注解
@MyCompScan("com.xxxx.springboot")
@PropertySource(value = {"classpath:jdbc.properties","classpath:user.properties"})
public class IocConfig04 {
    
}

4. Spring MVC 零配置创建与部署

​ 基于 Spring Mvc 5.X 使⽤ Maven 搭建 SpringMvc Web项⽬,通过 Spring 提供的注解与相关配置来对项⽬进⾏创建与部署。

4.1. 创建Spring MVC Web⼯程

创建 Maven 的 web 项⽬

4.2. pom.xml 添加坐标相关配置

4.3. 添加源代码

4.4. 添加视图

​ 在 WEB-INF/views ⽬录下创建 index.jsp(这⾥以jsp为模板)

4.5. SpringMVC 配置类添加

​ Spring Mvc 配置信息 MvcConfig ⽂件添加,作为 Mvc 框架环境,原来是通过 xml 来进⾏配置 (视图解析器、Json转换器、⽂件上传解析器等),这⾥基于注解通过继承 WebMvcConfigurerAdapter 类并重写相关⽅法来进⾏配置 (注意通过 @EnableWebMvc 注解来启动 MVC 环境)。

​ MvcConfig 类定义好了,那么问题来了,怎么加载 MvcConfig 类呢,原来在构建 Mvc 应⽤时是通过容器启动应⽤时加载 web.xml ⽂件实现配置⽂件加载,现在的环境 web.xml ⽂件不存在,此时基于注解⽅式构建的 Mvc 应⽤,定义 WebInitializer 实现 WebApplicationInitializer 接⼝ (该接⼝⽤来配置Servlet3.0+ 配置的接⼝,⽤于替代 web.xml 配置),当 servlet 容器启动Mvc应⽤时会通过SpringServletContainerInitializer 接⼝进⾏加载,从⽽加载 Mvc 应⽤信息配置。实现该接⼝onStartup ⽅法 ,加载应⽤信息配置。

4.6. 入口文件代码添加

5. Spring Boot 概念&特点

5.1. 框架概念

​ 随着动态语⾔流行(Ruby、Scala、NodeJs等),Java 开发变得相对笨重,配置繁琐,开发效率低下,部署流程复杂,以及第三⽅集成难度也相对较大,针对该环境,Spring Boot 被开发出来,其使⽤“习惯⼤于配置⽬标”,借助Spring Boot 能够让项目快速运⾏起来,同时借助 Spring Boot 可以快速创建 web应⽤并独⽴进行部署(jar包 war 包方式,内嵌 servlet 容器),同时借助 Spring Boot 在开发应用时可以不用或很少去进行相关 xml 环境配置,简化了开发,大大提高项目开发效率。

​ Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化 Spring 应用的初始搭建以及开发过程。该框架使用了特定的⽅式来进⾏配置,从而使开发⼈员不再需要定义样板化的配置。通过这种⽅式,让 Spring Boot在蓬勃发展的快速应⽤开发领域 (rapid application development) 成为领导者。

5.2. 框架特点

​ 创建独⽴ Spring 应⽤程序、嵌入式 Tomcat、Jetty 容器、⽆需部署 WAR 包、简化 Maven 及 Gradle配置、尽可能⾃动化配置 Spring、直接植入产品环境下的实用功能,比如度量指标、健康检查及扩展配置、⽆需代码⽣成及 XML 配置等,同时 Spring Boot 不仅对 web 应⽤程序做了简化,还提供⼀系列的依赖包来把其它⼀些⼯作做成开箱即⽤。

5.3. Spring Boot 快速入门

5.3.1.环境准备:Idea、MavenJdk 1.8+ 、Spring Boot 2.x
5.3.2. 创建项目

通过 Maven 创建⼀个普通的 java 项⽬

5.3.3. 添加依赖坐标
 <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
  </parent>
  
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  </dependencies>

​ Spring Boot 的项⽬必须要将 parent 设置为 Spring Boot 的 parent,该 parent 包含了⼤量默认的配置,简化程序的开发。

5.3.4. 导入Spring Bootweb坐标与相关插件

打jar包时需要

<plugin>
 	<groupId>org.springframework.boot</groupId>
 	<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
5.3.5. 添加源代码
@Controller
public class HelloController {
 	@RequestMapping("hello")
 	@ResponseBody
 	public String hello(){
 		return "Hello SpringBoot";
 	}
}
5.3.6. 创建启动程序

在 HelloController.java 所在包下,创建 StarterApplication.java

@SpringBootApplication
public class Starter{
	public static void main(String[] args) {
 		SpringApplication.run(Starter.class);
 	}
}

6. Spring Boot 核心配置

6.1. 设置 Banner 图标

​ 在搭建 Spring Boot 项⽬环境时,程序启动后会在控制台打印醒⽬的 SpringBoot 图标,图标描述了Spring Boot 版本信息,这是 Spring Boot 项⽬与 Spring 项⽬启动区别较⼤的地⽅,Spring Boot 通过默认 Banner 在程序启动时显示应⽤启动图标,当然图标我们也可以进⾏⾃定义。

6.1.1. Banner 图标⾃定义

​ Spring Boot 项⽬启动时默认加载 src/main/resources ⽬录下的 banner.txt 图标⽂件,如果该⽬录⽂件未提供,则使⽤ Spring Boot 默认。在 main ⽬录下新建 resources 资源⽬录,并在该⽬录下新建banner.txt ⽂本⽂件,可以设置⾃定义图标。

打开⽹址: http://patorjk.com/software/taag/#p=display&f=Graffiti&t=Type%20Something

在线⽣成图标对应⽂本并将⽂本内容copy 到 banner.txt 中

6.1.2. Banner 图标关闭

​ 如果启动时不想要看到启动图标 ,这⾥也可以通过代码进⾏关闭操作,修改 StarterApplication 设置BannerMode 值为 Banner.Mode.OFF,启动 Spring Boot 应⽤关闭图标输出功能即可

@SpringBootApplication
public class StarterApplication {
 	public static void main(String[] args) {
 		SpringApplication springApplication = new SpringApplication(StarterApplication .class);
 		// 设置 banner 图标关闭
 		springApplication.setBannerMode(Banner.Mode.OFF);
 		springApplication.run();
 	}
}

6.2. Spring Boot 配置⽂件

​ Spring Boot 默认会读取全局配置⽂件,配置⽂件名固定为:application.properties 或application.yml,放置在 src/main/resources 资源⽬录下,使⽤配置⽂件来修改 SpringBoot ⾃动配置的默认值。

​ 在 resources 资源⽬录下添加 application.properties ⽂件,配置信息如下:

server.port=8088
server.servlet.context-path=/lsh

或者 application.yml ⽂件

server:
  port: 8989
  servlet:
    context-path: /lsh

6.3. Starter 坐标 & 自动化配置

6.3.1. Starter坐标配置

​ Spring Boot 引⼊了全新的Starter坐标体系,简化企业项⽬开发⼤部分场景的 Starter pom,应⽤程序引⼊指定场景的 Start pom 相关配置就可以消除 ,通过 Spring Boot 就可以得到⾃动配置的 Bean。

6.3.1.1. Web starter

​ 使⽤ Spring MVC 来构建 RESTful Web 应⽤,并使⽤ Tomcat 作为默认内嵌容器

<dependency>
 	<groupId>org.springframework.boot</groupId>
 	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
6.3.1.2. Freemarker Starter & Thymeleaf starter

集成视图技术,引⼊ Freemarker Starter , Thymeleaf Starter

<dependency>
 	<groupId>org.springframework.boot</groupId>
 	<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
 	<groupId>org.springframework.boot</groupId>
 	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
6.3.1.4. 引⼊AOP环境
<dependency>
 	<groupId>org.springframework.boot</groupId>
 	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

相关starter系列坐标参考

在这里插入图片描述

在这里插入图片描述
spring-boot-starter-ws 对Spring Web服务的⽀持

传统的 maven 坐标这⾥同样适⽤,如果引⼊传统 maven 坐标需要考虑相关配置类的编写。

如果引⼊相关starter坐标这⾥不存在,可以到这⾥搜索。

6.3.2. 自动化配置
6.3.2.1. SpringBoot Starter坐标版本查看

​ 前⾯介绍了 SpringBoot Starter 相关坐标,引⼊ Starter 坐标来简化应⽤环境的配置。这⾥以环境搭建 spring-boot-starter-web 坐标来简单分析 SpringBoot ⾃动化配置过程。

<dependency>
 	<groupId>org.springframework.boot</groupId>
 	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

​ 这⾥引⼊的 web 环境坐标不像传统的maven坐标那样包含坐标的版本号,项⽬中引入的 starter 系列坐标对应的版本库统⼀由父⼯程坐标统⼀控制即项⽬中引⼊的 parent 标签。

<parent>
 	<groupId>org.springframework.boot</groupId>
 	<artifactId>spring-boot-starter-parent</artifactId>
 	<!--
 		⽗类项⽬统⼀对项⽬依赖版本统⼀控制!
 		--> 
 	<version>2.2.2.RELEASE</version>
</parent>
6.3.2.2. Spring Boot自动化配置

​ Spring Boot的项⽬⼀般都会有 *Application 的⼊⼝类,⼊⼝类中提供 main ⽅法,这是⼀个标准的Java 应⽤程序的⼊⼝⽅法。@SpringBootApplication 注解是 Spring Boot 的核⼼注解,它其实是⼀个组合注解:

​ @SpringBootApplication

	spring.factories ⽂件中配置类默认不会都⽣效,具体哪些配置类⽣效由配置类上标注的@ConditionalOnClass 注解来决定,这⾥了解下 @ConditionalOnClass 注解含义。
@ConditionalOnBean // 当给定的在bean存在时,则实例化当前Bean
@ConditionalOnMissingBean // 当给定的在bean不存在时,则实例化当前Bean
@ConditionalOnClass // 当给定的类名在类路径上存在,则实例化当前Bean
@ConditionalOnMissingClass // 当给定的类名在类路径上不存在,则实例化当前Bean

​ 意味着 WebMvcAutoConfiguration 配置类⽣效需要环境中存在 Servlet.class,DispatcherServlet.class,WebMvcConfigurer.class 实例,配置类才会⽣效。

从以上分析可以得出如下结论:

	Spring Boot 通过 maven 中的 starter 导⼊了所需场景下的 jar 包,并通过主启动类上的@SpringBootApplication 中的 @EnableAutoConfiguration 读取了类路径下的 META-INF/spring.factories下 EnableAutoConfiguration 的配置类,这些配置类使⽤@ConditionalOnClass 来标注,根据@ConditionalOnClass 标注的约束条件来引⼊⾃动化的环境配置。

6.4. Profile 配置

​ Profile 是 Spring ⽤来针对不同环境对不同配置提供⽀持的全局 Profile 配置使⽤ application-{profile}.yml,⽐如 application-dev.yml ,application-test.yml。

​ 通过在 application.yml 中设置 spring.profiles.active=test|dev|prod 来动态切换不同环境,具体配置如下:

application-dev.yml 开发环境配置⽂件

server:
  port: 8083
  servlet:
    context-path: /dev

application-test.yml 测试环境配置⽂件

server:
  port: 8085
  servlet:
    context-path: /test

application-prod.yml ⽣产环境配置⽂件

server:
  port: 8084
  servlet:
    context-path: /prod

application.yml 主配置⽂件

spring:
  profiles:
    active: dev

6.5. ⽇志配置

​ 在开发企业项⽬时,⽇志的输出对于系统 bug 定位⽆疑是⼀种⽐较有效的⽅式,也是项⽬后续进⼊⽣产环境后快速发现错误解决错误的⼀种有效⼿段,所以⽇志的使⽤对于项⽬也是⽐较重要的⼀块功能。

​ Spring Boot 默认使⽤ LogBack ⽇志系统,如果不需要更改为其他⽇志系统如 Log4j2 等,则⽆需多余的配置,LogBack 默认将⽇志打印到控制台上。如果要使⽤ LogBack,原则上是需要添加dependency 依赖的。

<dependency>
 	<groupId>org.springframework.boot</groupId>
 	<artifactId>spring-boot-starter-logging</artifactId>
</dependency>

​ 因为新建的 Spring Boot 项⽬⼀般都会引⽤ spring-boot-starter 或者 spring-boot-starter-web ,⽽这两个起步依赖中都已经包含了对于 spring-boot-starter-logging 的依赖,所以,⽆需额外添加依赖。

6.5.1. 项⽬中⽇志信息输出

Starter 启动类中添加 Log ⽇志类,控制台打印⽇志信息。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Starter {
    static Logger logger= LoggerFactory.getLogger(Starter.class);
    public static void main(String[] args) {
        logger.info("日志启动了了");
        SpringApplication.run(Starter.class);
    }
}
6.5.2. 日志输出格式配置

​ 修改 application.yml ⽂件添加⽇志输出格式信息配置,可以修改 application.yml ⽂件来控制控制台⽇志输出格式,同时可以设置⽇志信息输出到外部⽂件。

logging:
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger- %msg%n"
    level: debug
  file:
    path: "."
    name: "springboot.log"

7. Freemarker & Thymeleaf 视图技术集成

7.1. Freemarker 视图集成

​ SpringBoot 内部⽀持 Freemarker 视图技术的集成,并提供了⾃动化配置类FreeMarkerAutoConfiguration,借助⾃动化配置可以很⽅便的集成 Freemarker基础到 SpringBoot环境中。这⾥借助⼊⻔项⽬引⼊ Freemarker 环境配置。

Starter 坐标引⼊

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

添加 Freemarker 配置信息

Freemarker 默认默认视图路径⽂ resources/templates ⽬录(由⾃动化配置类FreemarkerProperties 决定),该⽬录可以进⾏在 application.yml 中进⾏修改。

默认(部分代码):

​ 在templates文件下,以.ftlh结尾。

@ConfigurationProperties(
    prefix = "spring.freemarker"
)
public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {
    public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/";
    public static final String DEFAULT_PREFIX = "";
    public static final String DEFAULT_SUFFIX = ".ftlh";
    private Map<String, String> settings = new HashMap();
    private String[] templateLoaderPath = new String[]{"classpath:/templates/"};
    private boolean preferFileSystemAccess = true;
}

自行配置:

​ 修改 application.yml 添加 freemarker 基本配置如下:

​ 配置为views文件下以.ftl结尾

spring:  
  freemarker:
  	suffix: .ftl
  	content-type: text/html
  	charset: UTF-8
  	template-loader-path: classpath:/views/

7.2. Thymeleaf 视图集成

​ SpringBoot ⽀持多种视图技术集成,并且 SpringBoot 官⽹推荐使⽤ Thymeleaf 作为前端视图⻚⾯,这⾥实现Thymeleaf 视图集成,借助⼊⻔项⽬引⼊ Thymeleaf 环境配置。

starter坐标引⼊

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

添加 Thymeleaf 配置信息

​ Thymeleaf 默认默认视图路径 resources/templates ⽬录(由⾃动化配置类ThymeleafProperties 类决定),该⽬录可以进⾏在 application.yml 中进⾏修改。

默认(部分代码):

templates文件夹下,以.html结尾

@ConfigurationProperties(
    prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    public static final String DEFAULT_SUFFIX = ".html";
    private boolean checkTemplate = true;
    private boolean checkTemplateLocation = true;
    private String prefix = "classpath:/templates/";
    private String suffix = ".html";
    private String mode = "HTML";
    private Charset encoding;
}

自行配置:

​ html文件下,以.html结尾

Spring:  
  thymeleaf:
    prefix: classpath:/html/
  ## 关闭 thymeleaf ⻚⾯缓存
    cache: false
    suffix: .html

8. SpringBoot 静态资源访问

​ 从⼊⻔项⽬中可以看到:对于 Spring Mvc 请求拦截规则为 ‘/’ ,Spring Boot 默认静态资源路径如下:

部分代码:

public class ResourceProperties {
    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
    private String[] staticLocations;
    private boolean addMappings;
    private final ResourceProperties.Chain chain;
    private final ResourceProperties.Cache cache;
}

即:我们可以在 resources 资源⽬录下存放 web 应⽤静态资源⽂件。

classpath:/resources/:指的是资源文件夹下的resources文件

8.1. 默认静态资源路径

在 resources ⽬录下创建 static 或者 public ⽬录,存放 images、js、css 等静态资源⽂件

8.2. 自定义静态资源路径

在 spring.resources.static-locations 后⾯追加⼀个配置

spring:
 # 修改默认的静态寻址资源⽬录 多个路径之间⽤逗号隔开
 resources:
 static-locations: classpath:/public/,classpath:/static/,classpath:/os/

9. SpringBoot应⽤打包与部署

​ 当项⽬开发完毕进⾏部署上线时,需要对项⽬进⾏打包操作,⼊⻔中构建的项⽬属于普通应⽤,由于SpringBoot 内嵌 Tomcat 容器,所有打包后的 jar 包默认可以⾃⾏运⾏。

9.1. Jar 包部署

9.1.1. 配置打包命令

​ idea 下配置 clean compile package -Dmaven.test.skip=true 执⾏打包命令,target ⽬录得到待部署的项⽬⽂件。

<packaging>jar</packaging><build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

在这里插入图片描述

9.1.2.部署并访问

​ 打开本地 dos 窗⼝,执⾏ java -jar 命令 部署已打好的 jar 包⽂件。

​ 命令: java -jar jar包所在⽬录

9.2. war 包部署

应⽤类型修改

由于⼊⻔项⽬构建的项⽬默认为 jar 应⽤,所以这⾥打 war 需要作如下修改

<packaging>war</packaging>

内嵌tomcat忽略

​ 构建 SpringBoot 应⽤时,引⼊的 spring-boot-starter-web 默认引⼊ Tomcat 容器,这⾥忽略掉内容 Tomcat

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <scope>provided</scope>
</dependency><build>
    <!--
       配置⽣成的war⽂件名
    -->
    <finalName>springboot</finalName>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

9.2.2. Starter 修改

​ 添加容器启动加载⽂件 (类似于读取 web.xml),这⾥通过继承 SpringBootServletInitializer 类并重写 configure ⽅法来实现,在部署项⽬时指定外部 Tomcat 读取项⽬⼊⼝⽅法。

@SpringBootApplication
public class Starter extends SpringBootServletInitializer {
    static Logger logger= LoggerFactory.getLogger(Starter.class);
    public static void main(String[] args) {
        logger.info("日志启动了了");
        SpringApplication.run(Starter.class);
    }
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(Starter.class);
    }
}
9.2.4. 部署并访问

​ 外部tomcat部署并访问

放入webapps中

在这里插入图片描述

双击运行startup.bat

在这里插入图片描述

​ 端口号为tomcat的端口号,项目地址默认为项目名springboot

10.总结

	Spring 框架的发展史,然后引⼊今天的 SpringBoot 框架,使⽤SpringBoot 框架的最终⽬标是简化原⽣的 Spring 应⽤开发带来的繁琐配置,SpringBoot 引⼊的全新的 Starter 坐标简化了原有坐标的引⼊⽅式,借助 SpringBoot 的⾃动化配置让开发者⾯更加专注业务本身的开发,⽽不是花费⼤量的时间来解决配置的问题,同时 SpringBoot 还提供了便捷的环境切换操作,做到不同环境⽅便快捷的切换,在开发 web 项⽬中遇到的视图整合与静态⽂件的访问操作,更多要归功于 SpringBoot 本身 Starter 坐标与⾃动化配置功能,最后给⼤家讲了 SpringBoot 打包与部署问题,相⽐较原有的 Maven 项⽬打包与部署更加简单。

1. 学习目标

在这里插入图片描述

2. Mybatis 整合 & 数据访问

​ 使⽤ SpringBoot 开发企业项⽬时,持久层数据访问是前端⻚⾯数据展示的基础,SpringBoot ⽀持市⾯上常⻅的关系库产品 (Oracle、Mysql、SqlServer、DB2等) 对应的相关持久层框架,当然除了对于关系库访问的⽀持,也⽀持当下众多的⾮关系库 (Redis、Solr、MongoDB等) 数据访问操作,这⾥主要介绍 SpringBoot 集成 Mybatis 并实现持久层数据基本增删改查操作。

2.1. SpringBoot 整合 Mybatis

2.1.1. 环境整合配置

​ Idea 下创建 Maven 普通⼯程 springboot_mybatis

​ pom.xml 添加核⼼依赖

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
    </parent>

    <dependencies>
        <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.1</version>
        </dependency>
        <!-- springboot 分⻚插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.13</version>
        </dependency>
        <!-- mysql 驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- c3p0 数据源 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.5</version>
        </dependency>

application.yml整合配置

server:
  # 设置项⽬启动的端⼝号
  port: 8080
  # 设置项⽬的访问路径(上下⽂路径)
  servlet:
    context-path: /sbm
## 数据源配置
spring:
  datasource:
    type: com.mchange.v2.c3p0.ComboPooledDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/springboot_mybatis?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
    username: root
    password: 123456

## mybatis 配置
mybatis:
  mapper-locations: classpath:/mappers/*.xml
  type-aliases-package: com.shsxt.pojo
  configuration:
    ## 下划线转驼峰配置
    map-underscore-to-camel-case: true
  ## pageHelper
  pagehelper:
    helper-dialect: mysql
  ## 显示dao 执⾏sql语句
  logging:
    level:
      com:
        shsxt:
          dao: debug

2.1.2. 源代码添加

​ JavaBean 对象定义

public class User {
    private Integer userId;
    private String userName;
    private String userPassword;
}

Dao层接⼝⽅法定义

public interface UserDao {
    User queryByName(String name);
}

SQL映射⽂件添加

​ resources/mappers ⽬录下添加 UserMapper.xml 配置,查询 statetment

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.shsxt.dao.UserDao">

    <select id="queryByName" resultType="com.shsxt.pojo.User" parameterType="string">
        select
            *
        from
            tb_user
        where
            user_Name=#{name}
    </select>

添加 service 、controller 对应代码

@Service
public class UserService {
    @Resource
    private UserDao userDao;
    public User queryByName(String name){
        return userDao.queryByName(name);
    }
}
@Controller
public class UserController {
    @Resource
    private UserService userService;

    @GetMapping("user/{name}")
    @ResponseBody
    public User queryBuName(@PathVariable String name){
        return userService.queryByName(name);
    }
}

添加应⽤启动⼊⼝

@SpringBootApplication
@MapperScan("com.shsxt.dao")
public class App 
{
    public static void main( String[] args )
    {
        SpringApplication.run(App.class);
    }
}

2.2. SpringBoot 数据访问操作

​ 完成 SpringBoot 与 Mybatis 集成后,接下来以⽤户表为例实现⼀套⽤户模块基本数据维护。

2.2.2.3. 添加 commons-lang3 依赖

如果需要使⽤ StringUtils ⼯具类,需要引⼊ commons-lang3 依赖。

<dependency>
    <groupId>org.apache.commons</groupId>
  	<artifactId>commons-lang3</artifactId>
</dependency>
2.2.2.4. AssertUtil 工具类
public class AssertUtil {
    /**
     * 判断结果是否为true
     * 如果结果为true,抛出自定义的Params异常
     * @param
     * @return
     */
    public static void isTrue(Boolean flag, String msg){
        if(flag){
            throw new ParamsException(msg);
        }
    }
}
2.2.2.5. ParamsException 自定义异常
public class ParamsException extends RuntimeException {
    private String msg="参数异常";
    private Integer code=300;

    public ParamsException() {
        super("参数异常");
    }
    public ParamsException(String msg) {
        super("参数异常");
        this.msg = msg;
    }
    public ParamsException(Integer code) {
        super("参数异常");
        this.code = code;
    }
    public ParamsException(String msg, Integer code) {
        super(msg);
        this.msg = msg;
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }
}
2.2.2.6. UserService
 public void saveUser(User user){
        AssertUtil.isTrue(StringUtils.isBlank(user.getUserName()),"用户名不能为空");
        AssertUtil.isTrue(StringUtils.isBlank(user.getUserPassword()),"密码不能为空");
        AssertUtil.isTrue(userDao.queryByName(user.getUserName())!=null,"用户名已存在");
        AssertUtil.isTrue(userDao.saveUser(user)<1,"添加失败");
    }

controller:

 @PostMapping("user")
    @ResponseBody
    public ResultInfo saveUser(@RequestBody User user){
        ResultInfo resultInfo=new ResultInfo();
        try {
            userService.saveUser(user);
        } catch (ParamsException e) {
            resultInfo.setMsg(e.getMsg());
            resultInfo.setCode(e.getCode());
        }catch (Exception e) {
            e.printStackTrace();
            resultInfo.setCode(300);
            resultInfo.setMsg("记录添加失败!");
        }
        return resultInfo;
    }

resultInfo(用于存放信息):

public class ResultInfo {
    private String msg="成功";
    private Integer code=200;
    private Object object;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }
}
update
 tb_user
 set
 user_name =#{userName},user_pwd=#{userPwd}
 where
 id = #{id}
2.2.5. 分页条件查询操作
2.2.5.1. UserQuery
package com.shsxt.query;

public class UserQuery {
    private Integer pageNum = 1; // 当前⻚
    private Integer pageSize = 10; // 每⻚显示的数量
    private String userName; // 查询条件:⽤户名

    public Integer getPageNum() {
        return pageNum;
    }

    public void setPageNum(Integer pageNum) {
        this.pageNum = pageNum;
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}
2.2.5.2. 接口方法定义
public interface UserMapper {
 	// 通过条件,分⻚查询⽤户列表
 	public List<User> selectByParams(UserQuery userQuery);
}
2.2.5.3. 映射文件配置
 <select id="selectByParams" resultType="com.shsxt.pojo.User" parameterType="com.shsxt.query.UserQuery">
        select
            *
        from tb_user
        <where>
            <if test="userName!=null and userName !=''" >
                and user_name like concat('%',${userName},'%')
            </if>
        </where>
    </select>
2.2.5.4. UserService
public PageInfo<User>queryUserByParams(UserQuery userQuery){
        PageHelper.startPage(userQuery.getPageNum(),userQuery.getPageSize());
        return new PageInfo<User>(userDao.selectByParams(userQuery));
    }
2.2.5.5. UserController
    @GetMapping("user/params1")
    @ResponseBody
    public PageInfo<User> queryByParams(){
        UserQuery userQuery=new UserQuery();
        userQuery.setPageSize(10);
        userQuery.setPageNum(1);
        userQuery.setUserName("");
        return userService.queryUserByParams(userQuery);
    }

4.2. 热部署环境配置与测试

​ 热部署,就是在应⽤正在运⾏的时候升级软件(增加业务/修改bug),却不需要重新启动应⽤。

​ ⼤家都知道在项⽬开发过程中,常常会改动⻚⾯数据或者修改数据结构,为了显示改动效果,往往需要重启应⽤查看改变效果,其实就是重新编译⽣成了新的 Class ⽂件,这个⽂件⾥记录着和代码等对应的各种信息,然后 Class ⽂件将被虚拟机的 ClassLoader 加载。

​ ⽽热部署正是利⽤了这个特点,它监听到如果有 Class ⽂件改动了,就会创建⼀个新的ClaassLoader 进⾏加载该⽂件,经过⼀系列的过程,最终将结果呈现在我们眼前,Spring Boot 通过配置 DevTools ⼯具来达到热部署效果。

​ 在原理上是使⽤了两个 ClassLoader,⼀个 ClassLoader 加载那些不会改变的类(第三⽅ Jar 包),另⼀个ClassLoader 加载会更改的类,称为 restart ClassLoader,这样在有代码更改的时候,原来的restart ClassLoader 被丢弃,重新创建⼀个 restart ClassLoader,由于需要加载的类相⽐较少,所以实现了较快的重启时间。

4.2.1. 配置 DevTools 环境

修改 Pom ⽂件,添加 DevTools 依赖

<!-- DevTools 的坐标 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <!--当前这个项⽬被继承之后,这个不向下传递-->
            <optional>true</optional>
        </dependency>

同时在 plugin 中添加 devtools ⽣效标志

<plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork><!-- 如果没有该配置,热部署的devtools不⽣效 -->
                </configuration>
            </plugin>

​ devtools 可以实现⻚⾯热部署(即⻚⾯修改后会⽴即⽣效,这个可以直接在 application.properties⽂件中配置 spring.thymeleaf.cache=false 来实现),实现类⽂件热部署(类⽂件修改后不会⽴即⽣效),实现对属性⽂件的热部署。即 devtools 会监听 classpath 下的⽂件变动,并且会⽴即重启应⽤(发⽣在保存时机),注意:因为其采⽤的虚拟机机制,该项重启是很快的。配置了后在修改 java ⽂件后也就⽀持了热启动,不过这种⽅式是属于项⽬重启(速度⽐较快的项⽬重启),会清空 session 中的值,也就是如果有⽤户登陆的话,项⽬重启后需要重新登陆。

默认情况下,/META-INF/maven,/META-INF/resources,/resources,/static,/templates,/public 这些⽂件夹下的⽂件修改不会使应⽤重启,但是会重新加载( devtools 内嵌了⼀个 LiveReload server,当资源发⽣改变时,浏览器刷新)

4.2.2. 全局配置⽂件配置

​ 在 application.yml 中配置 spring.devtools.restart.enabled=false,此时 restart 类加载器还会初始化,但不会监视⽂件更新。

spring:
 ## 热部署配置
 devtools:
 	restart:
 		enabled: true
 		# 设置重启的⽬录,添加⽬录的⽂件需要restart
 		additional-paths: src/main/java
 		# 解决项⽬⾃动重新编译后接⼝报404的问题
 		poll-interval: 3000
 		quiet-period: 1000

4.2.3. IDEA 配置

​ 当我们修改了 Java 类后,IDEA 默认是不⾃动编译的,⽽ spring-boot-devtools ⼜是监测 classpath下的⽂件发⽣变化才会重启应⽤,所以需要设置 IDEA 的⾃动编译。

⾃动编译配置

​ File -> Settings -> Compiler -> Build Project automatically

Registry 属性修改

​ ctrl + shift + alt + /,选择Registry,勾上 Compiler autoMake allow when app running

5. SpringBoot 单元测试

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

5.2. Service业务方法测试

​ 这⾥以 UserService 为例,src/test/java ⽬录下添加测试包 com.xxxx.sprinboot.service 定义测试类代码如下 :

package com.shsxt.service;

import com.shsxt.App;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {App.class})
public class UserServiceTest {
    private Logger log= LoggerFactory.getLogger(UserServiceTest.class);
    @Resource
    private UserService userService;

    @Before
    public void before(){
        System.out.println("前");
    }

    @Test
    public void test(){
        System.out.println(userService.queryByName("admin"));
    }
    @After
    public void after(){
        System.out.println("hou");
    }
}

7. 定时调度集成 - Quartz

​ 在⽇常项⽬运⾏中,我们总会有需求在某⼀时间段周期性的执⾏某个动作。⽐如每天在某个时间段导出报表,或者每隔多久统计⼀次现在在线的⽤户量等。

​ 在 Spring Boot 中有 Java ⾃带的 java.util.Timer 类,也有强⼤的调度器 Quartz,还有 SpringBoot⾃带的Scheduled 来实现。Scheduled 在 Spring3.X 引⼊,默认 SpringBoot ⾃带该功能,使⽤起来也很简单,在启动类级别添加 @EnableScheduling 注解即可引⼊定时任务环境。但遗憾的是 Scheduled 默认不⽀持分布式环境,这⾥主要讲解 Quartz 时钟调度框架与 Spring Boot 集成。

7.1. 环境整合配置:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

7.2. 源代码添加

7.2.1. 定义 job
public class MyFirstJob implements Job {

    private Logger log = LoggerFactory.getLogger(MyFirstJob.class);
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        log.info(sdf.format(new Date()) + "-->" + "Hello Spring Boot Quartz...");
    }
}
7.2.2. 构建调度配置类

​ 创建 JobDetail 实例并定义 Trigger 注册到 scheduler ,启动 scheduler 开启调度

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QuartzConfig {
    @Bean
    public JobDetail jobDetail1(){
        return JobBuilder.newJob(MyFirstJob.class).storeDurably().build();
    }
    //@Bean
    public Trigger trigger1(){
        SimpleScheduleBuilder scheduleBuilder =
                SimpleScheduleBuilder.simpleSchedule()
                        // 每⼀秒执⾏⼀次
                        .withIntervalInSeconds(1)
                        // 永久重复,⼀直执⾏下去
                        .repeatForever();
        return TriggerBuilder.newTrigger()
                .withIdentity("trigger1","group1")
                .withSchedule(scheduleBuilder)
                .forJob(jobDetail1())
                .build();
    }
    // 每5秒触发⼀次任务
    @Bean
    public Trigger trigger2(){
        return TriggerBuilder.newTrigger()
                .withIdentity("trigger2", "group1")
                .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ? *"))
                        .forJob(jobDetail1())
                        .build();
    }

}

8. 全局异常与事务控制

8.1. Spring Boot 事务⽀持

​ 在使⽤ Jdbc 作为数据库访问技术时,Spring Boot 框架定义了基于 jdbc 的PlatformTransactionManager 接⼝的实现 DataSourceTransactionManager,并在 Spring Boot 应⽤启动时⾃动进⾏配置。如果使⽤ jpa 的话 Spring Boot 同样提供了对应实现。

在这里插入图片描述

​ 这⾥ Spring Boot 集成了 mybatis 框架,mybatis 底层数据访问层实现基于 jdbc 来实现,所以在Spring Boot 环境下对事务进⾏控制,事务实现由 Spring Boot 实现并⾃动配置,在使⽤时通过注解⽅式标注相关⽅法加⼊事务控制即可。

声明式事务配置

@Transactional(propagation = Propagation.REQUIRED)
    public void saveUser(User user){
        AssertUtil.isTrue(StringUtils.isBlank(user.getUserName()),"用户名不能为空");
        AssertUtil.isTrue(StringUtils.isBlank(user.getUserPassword()),"密码不能为空");
        AssertUtil.isTrue(userDao.queryByName(user.getUserName())!=null,"用户名已存在");
        AssertUtil.isTrue(userDao.saveUser(user)<1,"添加失败");
    }

8.2. Spring Boot 全局异常处理

​ SpringMvc 中对异常统⼀处理提供了相应处理⽅式,推荐⼤家使⽤的是实现接⼝HandlerExceptionResolver的⽅式,对代码侵⼊性较⼩。

​ 在Spring Boot 应⽤中同样提供了对异常的全局性处理,相关注解如下:

8.2.1. @ControllerAdvice

​ 该注解组合了 @Component 注解功能,最常⽤的就是作为全局异常处理的切⾯类,同时通过该注解可以指定包扫描的范围。@ControllerAdvice 约定了⼏种可⾏的返回值,如果是直接返回 model 类的话,需要使⽤@ResponseBody 进⾏ json 转换

8.2.2. @ExceptionHandler

​ 该注解在 Spring 3.X 版本引⼊,在处理异常时标注在⽅法级别,代表当前⽅法处理的异常类型有哪些具体应⽤以 Restful 接⼝为例,测试保存⽤户接⼝。

8.2.3. 全局异常应⽤
8.2.3.1. 异常抛出与全局异常捕获

​ UserController 查询接⼝

 @PutMapping("user2")
    @ResponseBody
    public ResultInfo updateUser2(@RequestBody User user){
        ResultInfo resultInfo=new ResultInfo();
         userService.updateUser(user);
        return resultInfo;
    }

UsrService 查询业务⽅法,抛出 ParamExceptions 异常

public void updateUser(User user){
        AssertUtil.isTrue(null==user.getUserId(),"用户不存在");
        AssertUtil.isTrue(StringUtils.isBlank(user.getUserName()),"用户名不能为空");
        AssertUtil.isTrue(StringUtils.isBlank(user.getUserPassword()),"密码不能为空");
        User result=userDao.queryByName(user.getUserName());
        AssertUtil.isTrue(result!=null && user.getUserId()!=result.getUserId(),"用户名已存在");
        AssertUtil.isTrue(userDao.updateUser(user)<1,"修改失败");
    }

全局异常处理类 GlobalExceptionHandler 定义

import com.shsxt.exception.ParamsException;
import com.shsxt.pojo.vo.ResultInfo;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = ParamsException.class)
    @ResponseBody
    public ResultInfo exc(ParamsException e){
        ResultInfo resultInfo=new ResultInfo();
        resultInfo.setCode(e.getCode());
        resultInfo.setMsg(e.getMsg());
        return resultInfo;
    }

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResultInfo exc2(Exception e){
        ResultInfo resultInfo=new ResultInfo();
        resultInfo.setCode(300);
        resultInfo.setMsg("操作失败!");
        return resultInfo;
    }
}

UsrService 查询业务⽅法,抛出 ParamExceptions 异常

public void updateUser(User user){
        AssertUtil.isTrue(null==user.getUserId(),"用户不存在");
        AssertUtil.isTrue(StringUtils.isBlank(user.getUserName()),"用户名不能为空");
        AssertUtil.isTrue(StringUtils.isBlank(user.getUserPassword()),"密码不能为空");
        User result=userDao.queryByName(user.getUserName());
        AssertUtil.isTrue(result!=null && user.getUserId()!=result.getUserId(),"用户名已存在");
        AssertUtil.isTrue(userDao.updateUser(user)<1,"修改失败");
    }

全局异常处理类 GlobalExceptionHandler 定义


import com.shsxt.exception.ParamsException;
import com.shsxt.pojo.vo.ResultInfo;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = ParamsException.class)
    @ResponseBody
    public ResultInfo exc(ParamsException e){
        ResultInfo resultInfo=new ResultInfo();
        resultInfo.setCode(e.getCode());
        resultInfo.setMsg(e.getMsg());
        return resultInfo;
    }

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResultInfo exc2(Exception e){
        ResultInfo resultInfo=new ResultInfo();
        resultInfo.setCode(300);
        resultInfo.setMsg("操作失败!");
        return resultInfo;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值