什么是Spring Boot
-
一般把Spring Boot称为搭建程序的脚手架或者说是便捷搭建基于Spring的工程脚手架。
-
Spring的主要作用就是帮助开发人员快速的构建庞大的spring项目,并且尽可能的减少一切xml配置,让开发人员更多的关注业务而不是配置。
-
Spring Boot简化了spring的应用开发
-
Spring Boot是整个Spring技术栈的大整合
Spring Boot的优点
- 可以创建独立的spring应用
- 其内嵌了web服务器,即已经在内部默认配置好了应该Tomcat服务器,无需我们再去配置发布
- 实现自动starter依赖,我们只需要在pom.xml文件导入spring-boot-starter-web依赖,springboot就会自动将我们整个springboot所需要的依赖都配置好,简化了配置
编写一个SpringBoot入门程序
对于maven的配置
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
在IDEA创建一个maven项目
在pom文件引入依赖
//引入此springboot的父项目配置,用于依赖管理
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<!--此依赖引入之后,springboot会自动将我们整个项目所需要的web相关依赖自动导入-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
创建一个主程序
- 创建一个主程序,每个Spring Boot工程都有一个启动引导类,作为整个springboot项目的入口
- 同时我们需要在该类上使用@SpringBootApplication标注这个类
- @SpringBootApplication这个注解标注在某个类上表示这个类是一个SpringBoot的配置类,告诉springboot运行这个类的main方法来启动Springboot应用
- 这个注解内部定义了自动整合、自动配置、自动扫描的功能,会扫描该注解标注的类的包下所有的注解
/**
* 主程序类
* @SpringBootApplication:这是一个SpringBoot应用
*/
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
//这里run方法的第一个参数以这个类的类名加“.class”,第二个参数为main方法的参数列表中的args参数
SpringApplication.run(MainApplication.class,args);
}
}
编写业务
- 我们需要编写一个Controller类来定义请求的业务
- 同时我们需要使用@RestController来标注这个类,这个注解集成了数据响应所需要的注解等等
- 然后使用@RequestMapping标注方法声明映射路径
@RestController
public class HelloController {
@RequestMapping("/hello")
public String handle01(){
return "Hello, Spring Boot 2!";
}
}
测试
最后我们只需要启动mian方法运行即可
对于整个Spring Boot项目的配置
Spring Boot简化了配置,我们不需要再去通过大量的xml文件去配置项目
我们只需要在resource文件下创建一个扩展名为.properties的文件然后将我们需要修改的配置在这个文件内进行重新配置即可
//例如将访问端口改为8888
server.port=8888
Spring Boot简化了部署
在初级的spring开发,我们需要安装Tomcat服务器然后将spring项目打包成war包之后发布到服务器然后再通过游览器去访问
但是在SpringBoot中,SpringBoot为我们提供了一个插件自动将我们的项目打包成一个jar包,为我们创建了一个可执行的jar包,这个jar包内自带了我们整个项目的运行环境,然后我们通过终端执行相应的命令来运行这个jar包即可启动项目
- 为此,我们需要在pom.xml文件中添加插件的相关依赖
//在pom.xml文件写引入
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
-
然后我们选中clean和package然后运行,进行打包()
-
如果打包出错,我们就需要减低springboot的版本或者降低maven-resources版本
降低maven-resources版本为3.1.0
- 注1:如果是通过终端terminal敲命令打包的,请打开一个新的终端terminal
- 注2:如果是通过右侧maven管理窗口打包的,请重启idea
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <!--修改版本--> <version>3.1.0</version> </plugin>
降低springboot版本为2.3.7.RELEASE
注1:如果是通过终端terminal敲命令打包的,请打开一个新的终端terminal
注2:如果是通过右侧maven管理窗口打包的,请重启idea
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.7.RELEASE</version> </parent>
- 然后我们打开cmd运行该jar包即可实现对该项目的运行
以上这种方式为我们简化了部署
SpringBoot的依赖管理
父项目做依赖管理
- 引入SpringBoot的父项目,通过这种方式在项目配置中继承父项目,用于依赖管理,通过这个依赖管理,springboot在引入项目其他依赖的时候会统一版本号
- 引入之后,我们在之后引入其他依赖的时候无需指定版本号
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version></parent>
几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制
开发导入starter场景启动器
- 在springboot中有很多场景,例如web场景的应用,所以我们在开发的时候只需要在pom文件下引入某个场景的依赖,maven就会根据这个场景的依赖将所有需要的依赖都自动引入
- spring-boot-starter-*(web场景:spring-boot-starter-web)
- SpringBoot所有支持的场景
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter - 所有场景启动器最底层的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-*</artifactId>
</dependency>
修改版本号
-
当我们需要的版本号与springboot自动仲裁的版本不一样的时候我们可以修改版本号
1、查看spring-boot-dependencies里面规定当前依赖的版本 用的 key。 2、在当前项目里面重写配置 <!--例如修改mysql驱动版本--> <properties> <mysql.version>5.1.43</mysql.version> </properties>
SpringBoot的自动配置
注解
基于注解的组件注册
结合@Configuration以及@Bean组件,实现对组件的注册和添加
@Configuration
作用:标注一个配置类
-
在spring阶段,我们对spring进行配置都是通过xml文件去执行的
-
但是现在在springboot中,我们不再需要使用xml配置去配置配置spring的容器了,而是直接去创建一个类作为配置类,然后使用@Comfiguration去标注这个类,这个类就相当于一个xml配置文件,我们可以在里面给IoC容器添加bean组件等等。
//标注成一个配置类,告诉SpringBoot这是一个配置类@Configurationpublic class Myconfig { //配置 ......}
使用@Configuration标注的配置类实质上也是容器中的一个组件,也就是说我们也可以通过getBean()来获取这个组件
//获取配置类组件run.getBean(Myconfig.class)
proxyBeanMethods属性
@Configuration的proxyBeanMethods属性
这个属性主要用来配置在我们从容器中获取bean组件的时候是否保持组件的单例性
- 属性值:true或false(默认为true)
- 当为true时:(Full)
- SpringBoot每次都会去检查容器内是否存在我们获取的组件,如果有直接返回,如果没有则新建,但是保持单例性
- 当为false时:(Lite)
- 每次我们获取组件的时候都会新建一个对象返回
对于这个属性值的设置,分为两种模式:
- Full模式:(proxyBeanMethods = true):保证每个@Bean方法被调用多少次返回的组件都是单实例的
- Lite模式:(proxyBeanMethods = false):每个@Bean方法被调用多少次返回的组件都是新创建的
- Full模式由于每次都要去检查组件是否存在,所以运行效率比Lite低
对于这两种模式的使用场景:当我们需要实现组件间依赖的时候就要使用默认的Full模式,反之使用Lite模式
@Bean
- 在spring阶段,我们去给容器添加bean组件都是在xml配置文件中使用去创建一个bean组件然后通过依赖注入的方式去对这个组件进行配置
- 但是在SpringBoot中,我们只需要在配置类内声明一个返回值为bean对象类型的方法然后通过@Bean标注即可实现创建bean组件并添加到Spring的IoC容器中的操作,对该bean组件的相应配置也可以直接在该方法内编写
- 同时,对于bean组件的id,springBoot默认为方法的方法名
- 我们可以通过@Bean(“beanName”)这种形式直接给bean组件设置id
- 在这里创建的bean组件在默认情况下都是单例的,无论我们怎么调用这个方法去获得对象,获取的都是IoC容器内的那个对象
- 原因:springBoot默认每次都会去容器内查找该bean组件对象是否存在,如果存在则返回容器内的对象
- 我们也可以通过配置使其不为单例,而是每次都去重新实例化一个bean
//标注为一个配置类
@Configurationpublic class Myconfig {
//使用@Bean标注,调用方法并将返回的bean添加到IoC容器内。id为“userName”
@Bean("username")
public User user(){
return new User();
}}
如何获取容器内的bean组件
- 通过这里面的run()方法执行之后的返回值,该返回值是就是我们的IoC容器
- 我们直接通过getBean()方法在run内获取bean对象即可
- getBean()的两个参数
- 第一个参数:bean的id
- 第二个参数:bean的类类型.class
- getBean()的两个参数
@SpringBootApplicationpublic class Application {
public static void main(String[] args) {
//这里的run方法执行之后的除了启动项目之外会返回这个项目的IOC容器
ConfigurableApplicationContext run=SpringApplication.run(Application.class,args);
User user=run.getBean("user",User.class);
System.out.println(user);
}}
@Import导入组件
-
在我们项目的任何一个组件类上使用该注解标注,就可以将组件导入到对应的组件类中
-
该注解的属性类型是一个数组,我们可以将多个组件通过该组件进行导入
-
该注解会根据我们给定的属性值自动的调用无参构造去给容器创建出对应的组件
-
//创建User类型的组件和DBhelper类型的组件 @Import({User.class,DBhelper.class}) @Configurationpublic class Myconfig { //使用@Bean标注,调用方法并将返回的bean添加到IoC容器内。id为“userName” @Bean("username") public User user(){ return new User(); }}
@Conditional
该注解的工作原理就是根据条件进行装配,当满足指定条件的时候,该注解下的类内的配置或者方法内的配置才生效
两种级别标注
-
放在配置类上表示,当容器中满足条件时,配置类中的组件才生效;
-
放在配置方法上的时候,表示的意思是当满足条件的时候配置方法才生效;
下图为@Conditional派生出来的注解,各自的执行原理都有所不同
应用场景
- 当我们容器内的组件之间存在依赖关系同时被依赖的组件又有可能不存在与容器中,那按原来的配置运行之后所产生的那个bean内部就会存在问题,这时候我们就可以在注册这个bean组件的方法上使用@Conditional的相关注解来先对依赖项进行判断是否存在与容器中,如果存在则方法内部的配置才生效否则不生效。
例如:下面的例子,我们的user方法内部是依赖了tom方法所注册的bean组件,但是由于tom方法没有被@Bean注解,则容器内不会存在有tom方法注册的bean组件,那么在user方法内部对于tom组件的依赖就会存在问题,这时候我们就可以在user上使用@Conditinal注解来对tom是否存在进行判断然后再决定user方法是否生效
@Configurationpublic class myconfig{ //判断id为tom的bean组件是否存在 @ConditionalOnBean(name="tom") @Bean public User user(){ return new User(tom); } //@Bean("tom") -->当这个注解存在的时候tom存在否则不存在 public Tom tom(){ return new Tom(); }}
- 当我们把Conditional注解标注在类上的时候,只有条件成立我们类内部的配置才生效
@ImportResource
注解描述
当我们的项目中有基于spring阶段的xml配置文件同时我们需要把这些文件修改成基于springboot的配置类但是一个一个去重新配置又很麻烦,这时候我们就可以直接在某个配置类上使用该注解将指定的xml配置文件导入到配置类下
例如我们要将spring.xml中的配置迁移到MyConfig配置类下
@Configuration @ImportResource(classpath:"spring.xml") public class MyConfig{ ..... }
配置绑定
@ConfigurationProperties
-
为了便于项目的灵活配置以及更好的模块化整合,我们在springboot项目内将大量的参数配置配置在properties文件或者yml文件中,然后我只需要通过@ConfigurationProperties这个注解来获取这些数据即可
-
注意点:
- 使用@ConfigurationProperties进行配置绑定的组件必须存在于容器当中,(在@Conmponent、@Bean、@Controller、@Service、@Repository注解下的组件都存在于容器中),因此我们可以先对组件使用这些注解进行标注然后在使用我们的@ConfigurationProperties来实现配置绑定
- 与properties文件中的配置进行绑定的数据之间,对应的属性名应该一致
使用方式
-
@Component+@ConfigurationProperties直接在对应类上使用这两个直接将bean组件添加到容器内并进行配置绑定
-
@EnableConfigurationProperties+@ConfigurationProperties
-
使用@EnableConfigurationProperties在配置类内指定实现配置绑定的类,开启其配置绑定
-
在对应的类中使用@ConfigurationProperties实现配置绑定
-
方式一
将bean添加到容器中在进行绑定
@ConfigurationProperties
//properties文件中 //这里定义属性的方式一般都在属性名前加一个前缀用于@ConfigurationProperties通过该前缀确定属性 myuser.name="小明" //对应的在组件中 @Component //这里对于该注解的prefix属性,该属性定义了该类内部属性的前缀,用于与properties文件内相互识别 @ConfigurationProperties(prefix = "mycuser") public class Car { private String name; public void setName(String name){ this.name=name; } public String getName(){ return name; } /* 如上:properties文件内的myuser.name属性就会于Car下的name实现单向绑定 */
//通过以上的方式将数据进行绑定之后,该类的bean已经存在于容器内,这样我们可以直接来使用这个bean @RestController public class test{ //直接通过注解从容器中获取并自动注入即可 @Autowired Car car; @RequestMapping("/car") public Car car(){ return this.car } }
方式二
@EnableConfigurationProperties,直接开启注解,直接在配置类中使用并指定某个类,开启这个类的配置绑定,所以不用使用@Componet这些注解去将bean添加到容器内
@EnableConfigurationProperties
两个功能:
- 开启指定的类的配置绑定功能
- 把指定类这个组件注册到容器中
使用该注解配合
操作容器对象的相关API
- 获取容器对象
ConfigurableApplicationContext run=SpringApplication.run(Application.class,args
- 获取bena组件
//参数分别为:组件id、组件对于的类类型名.class
run.getBean(BeanId,BeanClassName.class);
- 判断容器内是否有指定的组件
boolean beanx=run.containsBean(BeanIdName);
自动配置原理
LomBok
这个插件简化我们的开发,例如在编译的时候自动生成get set方法
- 引入lombok插件
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
- @Data
- 在类上使用该注解进行标注可以自动生成get和set方法
- @ToString
- 在类上用该注解进行标注可以自动生成每个属性的toString方法
- @AllArgsConstructor
- 在类上使用该注解标注自动生成有参构造,将对所有的属性的注入都写在自动生成的有参构造中
- @NoArgsConstructor
- 自动生成无参构造
- @Slf4j
- 相当于注入了日志类,我们通过调用log的方法去操作日志即可
- 例如:在处理方法内使用log.info(“…”),就可以在该请求方法处理之后在控制台看到相应的日志打印
devtools
引入该插件,我们可以直接ctrl+F9就可以重新加载我们的项目,无需我们去手动去点击重新加载
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
请求参数预处理
通过使用@ControllerAdvice以及@InitBinder结合实现对请求参数的预处理,即在获取到表单中的数据进行绑定到实体的时候先进行一些额外的处理
使用场景
- 例如我们前端将请求参数传递到后台时我们要先将参数绑定到指定的实体上时,存在实体之间属性名相同,那么在这种情况下就会到导致参数绑定的时候会混淆,为了解决这一问题,我们可以通过@ControllerAdvice以及@InitBinder在配置类内对配置对指定的请求参数进行预处理(例如加上前缀),然后再绑定的奥指定的实体上
代码实现
//实体A
public class A{
private String name;
//省略set和get方法
}
//实体B
public class B{
private String name;
//省略set和get方法
}
//Controller类下的配置
@RequestMapping('/ab')
//在请求参数前使用@ModelAttribute将参数与@InitBinder标注的预处理方法进行绑定
public String AB(@ModelAttribute("a") A a,@ModelAttribute("b") B b){
return a.getName()+">>"b.getName();
}
//使用@ControllerAdvice定义预处理类以及方法
@ControllerAdivce
public class Controlleradvice{
//指定该方法与@ModelAttribute属性值为a的进行绑定
@InitBinder('a')
public void init1(WebDataBinder binder){
//加上前缀a.
binder.setFieldDefaultPrefix("a.");
}
@InitBinder('b')
public void init1(WebDataBinder binder){
//加上前缀a.
binder.setFieldDefaultPrefix("b.");
}
}
//最后只需要在游览器上输入‘http://localhost:8888?a.name=111&b.name=22’
//这里的演示是在没有前端的情况下为了测试我们自己写好请求参数在url上,如果从前端接收过来的情况下会自动将参数进行绑定
web开发
静态资源访问
静态资源目录
只要将静态资源放在对应的类路径下:
- /resources/static
- /resources/public
- /resources
- /META-INF/resources
都可以通过静态资源的文件名来访问
**访问:**当前项目根目录/+静态资源名 ---->例如:localhost:8080/xxx.jpg
!!!!!!!!!!!!!!!!!!!!!!
对于静态资源的访问原理:首先请求进来之后先去找Controller看看能不能有没有相应的映射去处理请求,如果有这处理请求返回请求结果;如果没有,则会将请求交给静态资源管理器,静态资源管理器去寻找有没有相应的静态资源,有则返回该静态资源,没有则显示404错误
修改默认的静态资源拦截配置
由于springboot默认的拦截规则是 /** ,这样就会导致与我们的动态资源拦截冲突
所以为了解决这个问题,我们可以在application.properties文件中对静态资源的拦截规则以及静态资源的路径进行配置
#请求拦截规则
spring.mvc.static-path-patten=/static/**
#静态资源路径
spring.mvc.resources.static-locations=classpath:/static/**
以上配置之后,我们就可以通过localhost:8080/static/xxx.jpg 的请求去请求静态资源了**
还可以通过java类进行配置,就是定义一个配置类!
欢迎页
SpringBoot支持两种方式的欢迎页
静态资源方式
-
直接欢迎页的html文件放在静态资源的路径下(static),在不修改默认配置的情况下,访问localhost:8080,springboot 会自动解析index.html文件作为我们的欢迎页
-
或者将index.html放在我们自己指定的静态资源路径下,通过配置定义我们的静态资源路径,但是这种情况下不能配置静态资源拦截规则
自定义Favicon
请求参数处理
请求处理
-
首先我们在编写接口来对请求进行映射的时候,一般都是有一个请求对应一个映射方法
- 例如:“/getUser”—用于映射“获取User”的请求,“/deleteUser"—用于映射”删除User“的请求…
-
但是现在我们不用那样繁琐的去命名每一个请求路径表示一种请求了
-
现在我们只需要声明@RequestMapping注解的value以及method属性的值即可实现使用在同一个请求路径下执行不同的请求处理操作
-
如下:
-
//f该方法用于处理与/getUser(获取)同样的请求 @RequestMapping(value = "/user",method = RequestMethod.GET) public String getUser(){ return "GET-张三"; } //postUser保存 @RequestMapping(value = "/user",method = RequestMethod.POST) public String saveUser(){ return "POST-张三"; } //putUser修改 @RequestMapping(value = "/user",method = RequestMethod.PUT) public String putUser(){ return "PUT-张三"; } //deleteUser删除 @RequestMapping(value = "/user",method = RequestMethod.DELETE) public String deleteUser(){ return "DELETE-张三"; }
-
这种方式下提交方式要求为post
-
需配置:
spring.mvc.hiddenmethod.filter.enabled=true #开启页面表单的Rest功能
-
前端表单:
<form action="/test" method="post"> <input name="_method" type="hidden" value="DELETE"> <input type="submit" value="REST_DELETE" > </form>
-
-
这种方式会先将表单中的DELETE绑定到_method上,然后springboot拦截请求之后寻找对应 _method的请求方法去处理
基于注解实现以上
- @GetMapping(“/user”) ------------相当于@RequestMapping(value = “/user”,method = RequestMethod.GET)
- @PostMapping(“/user”) ------------相当于@RequestMapping(value = “/user”,method = RequestMethod.POST)
- @PutMapping(“/user”) ------------相当于@RequestMapping(value = “/user”,method = RequestMethod.PUT)
- @DeleteMapping(“/user”) ------------相当于@RequestMapping(value = “/user”,method = RequestMethod.DELETE)
普通参数与基本注解
接收请求参数
@PathVariable-----绑定url获取参name数
@RequestMapping("/test1/{id}/{name}")
public Map<String,Object> test1(@PathVariable("id") String id,
@PathVariable("name") String name,
@PathVariable Map<String,String> map
){
Map<String,Object> mapx=new HashMap<>();
mapx.put("id",id);
mapx.put("name",name);
mapx.put("map",map);
return mapx;
}
//接收请求url中id跟name,或者直接接收所有参数
@RequestHeader(“请求头名”) —用于获取请求头
@RequestMapping("/test2")
public Map<String,Object> test2(@RequestHeader("User-Agent") String useragent,
@RequestHeader Map<String,Object> map
){
Map<String,Object> mapx=new HashMap<>();
mapx.put("useragent",useragent);
mapx.put("所有请求头",map);
return mapx;
}
@RequestParam() 获取请求参数
@RequestMapping("/test3")
public Map<String ,Object> test3(@RequestParam("id") String id,
@RequestParam("name") String name,
@RequestParam Map<String,Object> map){
Map<String,Object> mapx=new HashMap<>();
mapx.put("id",id);
mapx.put("name",name);
mapx.put("map",map);
return mapx;
}
CookieValue 获取cookie值
@RequestMapping("/test4/cookie")
//获取Webstorm-58540ded这个cookie的值
public String test4(@CookieValue("Webstorm-58540ded") String cookie){
return "Webstorm-58540ded="+cookie;
}
@RequestBody (获取post方式提交的请求体) 由于post提交不是在url
@PostMapping("/test5")
public String postmathod(@RequestBody String name){
return name;
}
@RequestAttribute ----获取request域中属性,当我们执行页面转发的时候可以从request中拿数据到下一个页面
@GetMapping("/test6")
public String forwardtesst7(HttpServletRequest httpServletRequest){
httpServletRequest.setAttribute("name","由test6转发到test,在test7中获取request");
//转发
return "/test7";
}
@ResponseBody
@GetMapping("/test7")
//从request域中获取name
public Map<String,Object> test7(@RequestAttribute("name") String name,
HttpServletRequest httpServletRequest
){
Map<String,Object> mapx=new HashMap<>();
mapx.put("name1",name);
mapx.put("name2",httpServletRequest.getAttribute("name"));
return mapx;
}
复杂参数描述
Map与Model
对于map与model,我们只要往map或者model内放数据就相当于调用request.setAttributes(),往request内放参数
RedierctAttributes
重定向携带数据
ServletResponse
将请求参数自动封装为实体对象
<form action="/booktestpojo" method="get">
<input type="text" name="name">
<input type="text" name="author">
<input type="submit" value="提交">
</form>
//自动将请求参数封装到对应的实体上
@RequestMapping("/booktestpojo")
public Book book(Book book){
return book;
}
响应json数据
使用@RespouseBody标注将数据响应出去,用于处理异步请求时向前端返回json数据、
@Controller
@RequestMapping("/body")
public class RespouseBodyTest {
@RequestMapping("/user")
@ResponseBody
public User getUser(){
User user=new User();
user.setName("小白");
return user;
}
}