【java总结】框架之SpringBoot
SpringBoot基础
什么是 Spring Boot?
传统的 SSM/SSH 框架组合配置繁琐臃肿,不同项目有很多重复、模板化的配置,严重降低了 Java 工程师的开发效率,而 Spring Boot 可以轻松创建基于 Spring 的、可以独立运行的、生产级的应用程序。通过对 Spring 家族和一些第三方库提供一系列自动化配置的 Starter,来使得开发快速搭建一个基于 Spring 的应用程序。
Spring Boot 让日益臃肿的 Java 代码又重回简洁。在配合 Spring Cloud 使用时,还可以发挥更大的威力。
Spring Boot有哪些优点?
- 配置简单
- 独立运行
- 自动装配
- 无代码生成和 xml 配置
- 提供应用监控
- 易上手
- 提升开发效率
- 内嵌服务器、安全管理、运行数据监控、运行状况检查和外部化配置等
spring boot 核心配置文件是什么?
spring boot 配置文件有两种类型,它们主要的区别是书法风格不同。
- bootstrap (. yml 或者 . properties):boostrap 由父 ApplicationContext 加载的,比 applicaton 优先加载,且 boostrap 里面的属性不能被覆盖;
- application (. yml 或者 . properties):用于 spring boot 项目的自动化配置。
什么是 JavaConfig?
Spring JavaConfig 是 Spring 社区的产品,它提供了配置 Spring IoC 容器的纯 Java 方法。因此 它有助于避免使用 XML 配置。使用 JavaConfig 的优点在于:
- 面向对象的配置。由于配置在JavaConfig中定义为类,因此用户可以充分利用Java中面向对象的功能。一个配置类可以子类化另一个,覆盖其@Bean方法等。
- 减少或消除XML配置。已经证明了基于依赖注入原理的外部化配置的好处。但是,许多开发人员不希望在XML和Java之间来回切换。JavaConfig为开发人员提供了一种纯Java方法来配置Spring容器,该容器在概念上类似于XML配置。在技术上可以仅使用JavaConfig配置类来配置容器,但是在实践中,许多人发现将JavaConfig与XML混合匹配是理想的。
- 类型安全和重构友好。JavaConfig提供了一种类型安全的方法来配置Spring容器。由于Java 5.0支持泛型,现在可以按类型而不是按名称检索bean,而不需要任何强制转换或基于字符串的查找。
spring boot 有哪些方式可以实现热部署?
Spring Boot 实现热部署其实很容易,引入 devtools 依赖即可,这样当编译文件发生变化时,Spring Boot 就会自动重启。在 Eclipse 中,用户按下保存按键,就会自动编译进而重启 Spring Boot,IDEA 中由于是自动保存的,自动保存时并未编译,所以需要开发者按下 Ctrl+F9 进行编译,编译完成后,项目就自动重启了。
如果仅仅只是页面模板发生变化,Java 类并未发生变化,此时可以不用重启 Spring Boot,使用 LiveReload 插件就可以轻松实现热部署。
什么是Spring Profiles?
Spring Profiles允许用户根据配置文件(dev,test,prod等)来注册bean。因此,当应用程序在开发中运行时,
只有某些bean可以加载,而在PRODUCTION中,某些其他bean可以加载。假设我们的要求是Swagger文档仅适用于QA环境,
并且禁用所有其他文档。这可以使用配置文件来完成。Spring Boot使得使用配置文件非常简单。
什么是Spring Batch?
Spring Boot Batch提供可重用的函数,这些函数在处理大量记录时非常重要,包括日志/跟踪,事务管理,作业处理统计信息,
作业重新启动,跳过和资源管理。它还提供了更先进的技术服务和功能,通过优化和分区技术,可以实现极高批量和高性能批处理作业。
简单以及复杂的大批量批处理作业可以高度可扩展的方式利用框架处理重要大量的信息。
Spring Boot 中如何实现定时任务?
定时任务也是一个常见的需求,Spring Boot 中对于定时任务的支持主要还是来自 Spring 框架。
在 Spring Boot 中使用定时任务主要有两种不同的方式,一个就是使用 Spring 中的 @Scheduled 注解,另一个则是使用第三方框架 Quartz。
使用 Spring 中的 @Scheduled 的方式主要通过 @Scheduled 注解来实现。
使用 Quartz ,则按照 Quartz 的方式,定义 Job 和 Trigger 即可。
什么是 Spring Data ?
Spring Data 是 Spring 的一个子项目。用于简化数据库访问,支持NoSQL 和 关系数据存储。其主要目标是使数据库的访问变得方便快捷。Spring Data 具有如下特点:
- SpringData 项目支持 NoSQL 存储:
- MongoDB (文档数据库)
- Neo4j(图形数据库)
- Redis(键/值存储)
- Hbase(列族数据库)
SpringData 项目所支持的关系数据存储技术:
- JDBC
- JPA
Spring Data Jpa 致力于减少数据访问层 (DAO) 的开发量. 开发者唯一要做的,就是声明持久层的接口,其他都交给 Spring Data JPA 来帮你完成!Spring Data JPA 通过规范方法的名字,根据符合规范的名字来确定方法需要实现什么样的逻辑。
SpringBoot使用
⭐⭐⭐常用注解
先把注解都写到前面,方便统一复习
@SpringBootApplication //Sprnig Boot项目的核心注解,目的是开启自动配置,也是下面三个的总和
@EnableAutoConfiguration //启用 SpringBoot 的自动配置机制
@Configuration //表示这是一个配置类,类似xml的配置文件
@ComponentScan //表示配置包扫描,里面的属性和xml的属性一一对应
@Autowired //自动根据类型注入
@Qualifier(“名称”) //指定自动注入的id名称
@Resource(“名称”) //和autowired类似,这个注解属于J2EE的
@PostConstruct //被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行
@PreDestroy //被@PreDestroy修饰的方法会在服务器卸载Servlet的时候运行
@Component //所有要让spring管理的bean都要标注这个注解,一般标注在pojo类
//但是在web开发中,又衍生出了三个类,他们功能一样
@Repository(“名称”) //dao层
@Service(“名称”) //service层
@Controller(“名称”) //web层
@Scope //声明 Spring Bean 的作用域
//-------singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
//-------prototype : 每次请求都会创建一个新的 bean 实例。
//-------request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
//-------session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
@Configuration //一般用来声明配置类,可以使用 @Component注解替代,不过使用Configuration注解声明配置类更加语义化。
@PropertySource("classpath:user.properties") //在pojo类中引入配置文件
@ConfigurationProperties(prefix = "user") //在顶部注解后可以自动引入
@Value("${user.id}")//手动引入
@ControllerAdvice //全局异常处理,全局数据绑定,全局数据预处理
@ExceptionHandler() //全局异常处理,符合就近原则
@ExceptionHandler(NumberFormatException.class) //或者指定异常
//------------web注解----------------
@RestController //@Controller和 @ResponseBody 的合集,REST风格的控制器
@ResponseBody //将java对象转为json格式的数据。
@GetMapping("users") //等价于 @RequestMapping(value="/users",method=RequestMethod.GET)
@PostMapping("users") //等价于@RequestMapping(value="/users",method=RequestMethod.POST)
@PutMapping("/users/{userId}") //等价于@RequestMapping(value="/users/{userId}",method=RequestMethod.PUT)
@DeleteMapping("/users/{userId}") //等价于@RequestMapping(value="/users/{userId}",method=RequestMethod.DELETE)
@PatchMapping("/profile") //一般实际项目中,我们都是 PUT 不够用了之后才用 PATCH 请求去更新数据。
//----------前后端传值---------------
@PathVariable //用于获取路径参数
@RequestParam //用于获取查询参数。
@RequestBody //用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分并且Content-Type 为 application/json 格式的数据
@Valid //用于验证接收参数是否符合pojo定义的要求
//参数校验 JSR 注解见另一篇文章RESTful
@Entity //声明一个类对应一个数据库实体。
@Table //设置表名
@Id //声明主键
@GeneratedValue //指定主键生成策略。
@Column(name = "user_name", nullable = false, length=32) //声明字段。
@Column(columnDefinition = "tinyint(1) default 1") //设置字段类型并且加默认值
@Transient //指定不持久化特定字段
@Transactional //在要开启事务的方法上使用@Transactional注解即可!
基础配置
三种创建方式
其实 Spring Boot 工程本质上就是一个 Maven 工程
在线创建
首先打开 https://start.spring.io
这个网站,如下:
打不开也可以使用阿里https://start.aliyun.com/
使用开发工具创建
可以使用 IDE 来创建,在创建项目时选择 Spring Initializr
Maven 创建
直接next下一步
然后手动添加依赖
然后创建主启动,添加@SpringBootApplication注解
public static void main(String[] args) {
SpringApplication.run(SpringbootDemoApplication.class, args);
}
配置文件 application.properties
位置问题
首先,当我们创建一个 Spring Boot 工程时,默认 resources 目录下就有一个 application.properties 文件,可以在 application.properties 文件中进行项目配置,但是这个文件并非唯一的配置文件,在 Spring Boot 中,一共有 4 个地方可以存放 application.properties 文件。
当前项目根目录下的 config 目录下
当前项目的根目录下
resources 目录下的 config 目录下
resources 目录下
按如上顺序,四个配置文件的优先级依次降低。如下:
文件名问题
对于 application.properties 而言,它不一定非要叫 application ,但是项目默认是去加载名为 application 的配置文件,如果我们的配置文件不叫 application ,也是可以的,但是,需要明确指定配置文件的文件名。
方式和指定路径一致,只不过此时的 key 是 spring.config.name 。
指定完配置文件名之后,再次启动项目,此时系统会自动去默认的四个位置下面分别查找名为 app.properties 的配置文件。当然,允许自定义文件名的配置文件不放在四个默认位置,而是放在自定义目录下,此时就需要明确指定 spring.config.location 。
配置文件位置和文件名称可以同时自定义。
普通的属性注入
在配置文件中写的配置,可以通过@Value获取到,但是要使用 ${}
@Component
public class Book {
@Value("${book.id}")
private Long id;
@Value("${book.name}")
private String name;
}
如果配置文件名称不是 application.properties 的话
这时候做完了,项目启动并不会自动的加载该配置文件,如果是在 XML 配置中,可以通过如下方式引用该 properties 文件:
<context:property-placeholder location="classpath:user.properties"/>
如果是在 Java 配置中,可以通过 @PropertySource 来引入配置:
//在pojo文件中引入配置
@Component
@PropertySource("classpath:user.properties")
public class User {
@Value("${user.userName}")
private String userName;
@Value("${user.isAdmin}")
private boolean isAdmin;
@Value("${user.regTime}")
private Date regTime;
}
还可以这样玩:
//在pojo文件中引入配置
@Component
@PropertySource("classpath:user.properties")
@ConfigurationProperties(prefix = "user")
public class User {
private String userName;
private boolean isAdmin;
private Date regTime;
}
Spring Boot 整合 Thymeleaf
Spring Boot 中整合 Thymeleaf 非常容易,只需要创建项目时添加 Thymeleaf 即可:
创建 Controller
创建 Thymeleaf
在 Thymeleaf
中,通过 th:each
指令来遍历一个集合,数据的展示通过 th:text
指令来实现,
注意 index.html
最上面要引入 thymeleaf
名称空间。
配置完成后,就可以启动项目了,访问 /index 接口,就能看到集合中的数据了:
Spring Boot 整合 Freemarker
其他配置
如果我们要修改模版文件位置等,可以在 application.properties 中进行配置:
spring.freemarker.allow-request-override=falsespring.freemarker.allow-session-override=falsespring.freemarker.cache=falsespring.freemarker.charset=UTF-8spring.freemarker.check-template-location=truespring.freemarker.content-type=text/htmlspring.freemarker.expose-request-attributes=falsespring.freemarker.expose-session-attributes=falsespring.freemarker.suffix=.ftlspring.freemarker.template-loader-path=classpath:/templates/
配置文件按照顺序依次解释如下:
- HttpServletRequest的属性是否可以覆盖controller中model的同名项
- HttpSession的属性是否可以覆盖controller中model的同名项
- 是否开启缓存
- 模板文件编码
- 是否检查模板位置
- Content-Type的值
- 是否将HttpServletRequest中的属性添加到Model中
- 是否将HttpSession中的属性添加到Model中
- 模板文件后缀
- 模板文件位置
整合 Web 开发
Spring Boot 中的静态资源到底要放在哪里?
在 Spring Boot 中,如果我们是从 https://start.spring.io
这个网站上创建的项目,或者使用 IntelliJ IDEA 中的 Spring Boot 初始化工具创建的项目,默认都会存在 resources/static
目录,很多小伙伴也知道静态资源只要放到这个目录下,就可以直接访问
在 Spring Boot 中,默认情况下,一共有 5 个位置可以放静态资源,五个路径分别是如下 5 个:
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
/
这里第 5 个 /
其实就是表示 webapp 目录中的静态资源也不被拦截。
如果我们也可以自定义静态资源位置和映射,自定义的方式也有两种,可以通过 application.properties 来定义,也可以在 Java 代码中来定义,下面分别来看。
application.properties
在配置文件中定义的方式比较简单,如下:
spring.resources.static-locations=classpath:/
spring.mvc.static-path-pattern=/**
第一行配置表示定义资源位置,第二行配置表示定义请求 URL 规则。以上文的配置为例,如果我们这样定义了,表示可以将静态资源放在 resources 目录下的任意地方,我们访问的时候当然也需要写完整的路径,例如在 resources/static
目录下有一张名为 1.png 的图片,那么访问路径就是 http://localhost:8080/static/1.png
,注意此时的 static
不能省略。
Java 代码定义
当然,在 Spring Boot 中我们也可以通过 Java 代码来自定义,方式和 Java 配置的 SSM 比较类似,如下:
@Configuration
public class WebMVCConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/aaa/");
}
}
CORS 解决跨域问题
首先可以通过 @CrossOrigin
注解配置某一个方法接受某一个域的请求
@CrossOrigin(value = "http://localhost:8081") //表示服务端愿意接收来自 http://localhost:8081 的请求
provider 上,每一个方法上都去加注解未免太麻烦了,有的小伙伴想到可以讲注解直接加在 Controller 上,不过每个 Controller 都要加还是麻烦,在 Spring Boot 中,还可以通过全局配置一次性解决这个问题,全局配置只需要在 SpringMVC 的配置类中重写 addCorsMappings 方法即可,如下:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8081")
.allowedMethods("*")
.allowedHeaders("*");
}
}
/**
表示本应用的所有方法都会去处理跨域请求,allowedMethods 表示允许通过的请求数,allowedHeaders 则表示允许的请求头。经过这样的配置之后,就不必在每个方法上单独配置跨域了。
定义系统启动任务的两种方式
CommandLineRunner
使用 CommandLineRunner 时,首先自定义 MyCommandLineRunner1 并且实现 CommandLineRunner 接口:
@Component
@Order(100)
public class MyCommandLineRunner1 implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
}
}
关于这段代码,我做如下解释:
- 首先通过 @Compoent 注解将 MyCommandLineRunner1 注册为Spring容器中的一个 Bean。
- 添加 @Order注解,表示这个启动任务的执行优先级,因为在一个项目中,启动任务可能有多个,所以需要有一个排序。@Order 注解中,数字越小,优先级越大,默认情况下,优先级的值为 Integer.MAX_VALUE,表示优先级最低。
- 在 run 方法中,写启动任务的核心逻辑,当项目启动时,run方法会被自动执行。
- run 方法的参数,来自于项目的启动参数,即项目入口类中,main方法的参数会被传到这里。
此时启动项目,run方法就会被执行,至于参数,可以通过两种方式来传递,如果是在 IDEA 中,可以通过如下方式来配置参数:
另一种方式,则是将项目打包,在命令行中启动项目,然后启动时在命令行传入参数,如下:
java -jar devtools-0.0.1-SNAPSHOT.jar 三国演义 西游记
注意,这里参数传递时没有 key,直接写 value 即可,执行结果如下:
ApplicationRunner
ApplicationRunner 和 CommandLineRunner 功能一致,用法也基本一致,唯一的区别主要体现在对参数的处理上,ApplicationRunner 可以接收更多类型的参数(ApplicationRunner 除了可以接收 CommandLineRunner 的参数之外,还可以接收 key/value 形式的参数)。
使用 ApplicationRunner ,自定义类实现 ApplicationRunner 接口即可,组件注册以及组件优先级的配置都和 CommandLineRunner 一致,如下:
@Component
@Order(98)
public class MyApplicationRunner1 implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
List<String> nonOptionArgs = args.getNonOptionArgs();
System.out.println("MyApplicationRunner1>>>"+nonOptionArgs);
Set<String> optionNames = args.getOptionNames();
for (String key : optionNames) {
System.out.println("MyApplicationRunner1>>>"+key + ":" + args.getOptionValues(key));
}
String[] sourceArgs = args.getSourceArgs();
System.out.println("MyApplicationRunner1>>>"+Arrays.toString(sourceArgs));
}
}