使用spring Initializer快速创建spring Boot项目
一.springBoot简介
1.优点:
1.1 快速创建独立运行的spring项目以及主流框架集成
1.2 使用嵌入式的Servlet容器,应用无需打成WAR包、
1.3 starters 自动依赖和版本控制
1.4 大量的自动配置,简化开发,也可修改默认值
1.5 准生产环境的运行时应用监控
1.6 与云计算的天然集成
简化spring应用开发的一个框架
二.微服务
微服务:架构风格
一个应用应该是一组小型服务;可以通过HTTP的方式进行互通;
每一个功能元素最终都是一个可独立替换和独立升级的软件单元。
三.springboot HelloWorld
一个功能:
浏览器发送hello请求,服务器接收请求并处理。
1.创建一个maven工程
2导入springBoot相关依赖
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<!-- Override inherited settings -->
<description/>
<developers>
<developer/>
</developers>
<licenses>
<license/>
</licenses>
<scm>
<url/>
</scm>
<url/>
<!-- Add typical dependencies for a web application -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
3.编写一个主程序;启动spring Boot应用
package com.tree;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 利用@SpringBootApplication注解告诉springBoot 这是一个spring boot 应用
*/
@SpringBootApplication
public class HelloWordMainApplication {
public static void main(String[] args) {
//启动spring boot 应用
SpringApplication.run(HelloWordMainApplication.class,args);
}
}
4. 编写service 、controller
package com.tree;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 利用@SpringBootApplication注解告诉springBoot 这是一个spring boot 应用
*/
@SpringBootApplication
public class HelloWordMainApplication {
public static void main(String[] args) {
//启动spring boot 应用
SpringApplication.run(HelloWordMainApplication.class,args);
}
}
四. 运行主程序测试
五.简化部署
<!-- 这个插件,可以将应用打包成一个可执行的jar包 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
将这个应用打成jar包,直接使用java -jar xxx.jar的命令进行使用
六.Hello World探索
6.1 POM文件
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
这是一个父项目,他的父项目是:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
这个父项目是真正管理spring boot应用里面的所有依赖版本
spring boot版本仲裁中心;
导入依赖默认不需要写版本;(没有在dependencies里面管理的依赖,需要声明版本号)
6.2 启动器:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
spring-boot-starter-web;
spring-boot-starter: spring boot场景启动器;帮我们导入web模块正常运行索依赖的组件;
spring boot将所有的功能场景都抽取出来,做成一个个starters(启动器),只需要在项目中引入这些相关场景的所有依赖都会导入进来。要用某一个功能就导入什么场景的启动器。
6.3 主程序类,入口类;
/**
* 利用@SpringBootApplication注解告诉springBoot 这是一个spring boot 应用
*/
@SpringBootApplication
public class HelloWordMainApplication {
public static void main(String[] args) {
//启动spring boot 应用
SpringApplication.run(HelloWordMainApplication.class,args);
}
}
@SpringBootApplication: Spring boot应用标注在某个类上,说明这个类是spring boot的主配置类。spring boot就应该运行这个类的main方法来启动spring boot应用
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@SpringBootConfiguration : spring boot的配置类;
这个注解标注在某个类上, 表示这个类是spring boot的配置类
@Configuration : 配置类上来标注这个额注解;
配置类 == 配置文件;配置类也是容器中的一个组件;@Component
@EnableAutoConfiguration ;开启自动配置功能;
以前我们需要配置的东西,springboot帮我们自动配置; @EnableAutoConfiguration告诉springboot 开启自动配置功能;这样自动配置才能生效。
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage: 自动配置包
@Import(AutoConfigurationPackages.Registrar.class)
spring的底层注解@Import ,给容器中导入一个组件;导入的组件由 @Import(AutoConfigurationPackages.Registrar.class);
将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到spring容器;
@Import(AutoConfigurationImportSelector.class)
给容器中导入组件;
AutoConfigurationImportSelector : 导入哪些组件的选择器;
将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中;
会给容器中导入自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景导入需要的所有组件,并配置好这些组件;
有了自动配置类,免去了手动配置写配置注入功能组件。
spring-boot-autoconfigure.jar 帮我们自动配置了J2ee所有解决方案
七. 使用spring initializer快速创建spring boot项目
默认生成的sping boot项目;
- 主程序已经生成好了,只需要添加自己的逻辑即可
- resources文件夹中目录结构
- static:保存素有的静态资源;js css images;
- templates;保存所有的模板页面;springboot 默认jar包使用嵌入式的tomcat,默认不支持jsp页面,可以使用模板引擎,freemarker/ thymeleaf;
- application.properties:springboot配置文件,可以修改一些默认配置。
八. spring boot配置文件
spring boot 使用一个全局配置文件,配置文件名是固定的;
-
application.properties
-
application.yml
配置文件的作用:修改springboot自动配置的默认值;
YAML(YAML Ain’t Markup language)
以数据为中心的标记语言
示例:
server:
port: 8081
8.1 YAML语法:
-
基本语法:
k:(空格)v : 表示一对键值对(空格必须有);
以空格的缩进来控制层级关系;只要是左对齐的一列数据,都是同一 个层级的;
server:
port: 8081
path: /hello
属性和值大小写敏感;
-
值的写法:
字面量:普通的值(数字,字符串,布尔)
k: v:字面直接来写;
字符串默认不用加上单引号或者双引号;
对象、map(属性和值):
对象还是k;v的方式
friends: name:zhangsan age:20
行内写法:
friends:{name: zhangsan,age: 20}
数组(List/set):
用 - 值表示数组中的一个元素
pets: - cat - dog - pig
行内写法:
pets: [cat,dog,pig]
3. 配置文件值注入:
person:
lastName: zhangsan
age: 18
boos: false
birth: 2020/12/12
maps: {k1: v1,k2: v2}
lists:
- lisi
- zhaoliu
dog:
name: 小狗
age: 6
javaBean
/**
* 将配置文件中的属性值映射到这个组件中
* @ConfigurationProperties 告诉springboot 将本类中的所有属性和配置文件中相关的配置进行绑定
* prefix = "person" 配置文件中哪个属性进行一一配置
* 只用实体类是一个组件时,才能使用属性配置
*/
@Component
@ConfigurationProperties(prefix = "person") //默认从全局配置文件中进行获取值
public class Person {
private String lastName;
private Integer age;
private Boolean boos;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
需要导入配置文件处理器,编写配置文件就会有提示:
<!-- 配置文件处理器 配置文件进行绑定就会有提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration- processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
利用properties文件进行属性注入:
person.age=12
person.birth=2020/7/7
person.boos=true
person.last-name=张三
person.lists=a,b,c,1,2,3
person.maps.k1=v1
person.maps.k2=20
person.dog.name=dog
person.dog.age=7
4. @Value获取值和@ConfigurationProperties获取值比较
@ConfigurationProperties 支持松散语法绑定; 在properties文件中可以用 - 后跟随小写字母来表示-后大写字母
@Value("${first-name}") ; person.first-name;
@Value 不支持JSR303校验;
@Value不支持复杂类型封装;比如Map比如Object类型
配置文件yml还是properties都可以获取值,如果只需要在某个业务逻辑中获取配置文件中某个值则使用@Value
如果专门编写了一个javaBean来和配置文件进行映射,则使用@configurationProperties;\
5.@PropertySource 加载指定配置文件
@Component
@ConfigurationProperties(prefix = "person")
@PropertySource(value="classpath:person.properties") //使用此注解来读取指定的配置文件
public class Person {
/**
* <bean id="" class="com.tree.Bean.Person">
* <property name="lastName" value="字面量"/${key}从环境变量、配置文件中获取值/#{Spel}></property>
* </bean>
*/
// @Value("${person.last-name}")
private String lastName;
// @Value("#{11}")
private Integer age;
// @Value("true")
private Boolean boos;
// @Value("${person.birth}")
private Date birth;
6 @ImportResource :导入Spring的配置文件,让配置文件内容生效;
spring boot里面没有spring的配置文件,我们自主编写的配置文件,也不能自动识别;
如果需要在spring boot中使用 自主编写的spring配置文件,则需要在启动类添加@ImportResource注解;
@ImportResource(locations = "classpath:beans.xml")
@SpringBootApplication
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helloService" class="com.tree.springboot.service.HelloService">
</bean>
</beans>
SpringBoot推荐给容器中添加组件的方式:推荐使用全注解的方式
1.配置类====spring配置文件
2.使用@Bean给容器中添加组件
/**
* @configuration 指明当前类是一个配置类;用来替代之前spring配置文件
* 在配置文件中使用<bean></bean> 用来添加组件
*/
@Configuration
public class MyAppConfig {
/**
* 将方法的返回值添加到容器中;容器中这个组件默认Id就是方法名;
* @return
*/
@Bean
public HelloService helloService(){
System.out.println("配置类,给容器中添加组件");
return new HelloService();
}
}
7.配置文件占位符:
1.随机数
2.占位符获取之前配置的值,如果没有则指定默认值:
person.age=12
person.birth=2020/7/7
person.boos=true
person.last-name=张三${random.uuid}
person.lists=a,b,c,1,2,3
person.maps.k1=v1
person.maps.k2=${person.last-name}
person.dog.name=${person.hello:hello}_dog
person.dog.age=${random.int}
8.Profile
-
多Profile文件
我们在主配置文件编写的时候,文件名可以是application-{profile}.properties/yml
默认使用application.properties
如果需要激活其他配置文件则需要在主配置文件中添加:
spring.profiles.active=dev
-
yml支持多文档快方式
server: port: 8081 spring: profiles: active: prod --- server: port: 8082 spring: profiles: dev --- server: port: 8283 spring: profiles: prod ---
该方式将yml分割成多个文档块,然后由首块进行选择配置
-
命令行的方式激活文档
–spring.profiles.active=dev
可以于配置界面进行配置,还可以于打包后于cmd中使用java -jar xxx.jar --spring.profiles.active=prod
虚拟机参数
-Dspring.profiles.active=dev
9 配置文件加载位置:
-file:./config/
-file:./
-classpath:/config/
-classpath:/
优先级从上往下,springboot会从这四个位置加载主配置文件;互补配置
我们可以通过spring.config.loacation来改变默认的配置文件位置
java -jar xxx.jar --spring.config.loacation=d:/xxx.properties
10 外部配置加载顺序
springboot也可以从以下位置加载配置;优先级从高到底;高优先级会覆盖低优先级配置,所有配置会形成互补配置;
-
命令行参数
java -jar xxx.jar --server.port=8087
-
来自java:comp/env的NDI属性
-
java系统属性 System.getProperties()
-
操作系统环境变量
-
RandomValueProperrySource配置的random.* 属性值
-
jar包外部的application-{profile}.properties或application.yml 带spring.profile配置文件
-
jar包内部的application-{profile}.properties或application.yml 带spring.profile配置文件
-
jar包外部的application.properties或application.yml 不带spring.profile配置文件
-
jar包内部的application.properties或application.yml 不带spring.profile配置文件
-
@Configuration注解类上的@PropertySource
-
通过springApplication.setDefaultProperties指定的默认属性
九.springboot 自动配置
- springboot启动会加载大量的自动配置类,自动配置类会从properties文件中读取各类默认值。
- springboot有没有提供我们需要的的自动配置类
- 如果有,只需要看这些自动配置类中存在哪些组件;
- 给容器中自动配置类添加组件时,会从properties类中获取某些属性。我们则可以在配置文件中指定这些属性的值。
xxxAutoConfiguration:自动配置类;给容器中个天价组件
xxxxproperties:封装配置文件中相关属性;
自动配置类必须在一定的条件下才能生效;
debug=true #开启springboot Debug模式
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:
-----------------
AopAutoConfiguration matched:
- @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)
AopAutoConfiguration.ClassProxyingConfiguration matched:
- @ConditionalOnMissingClass did not find unwanted class 'org.aspectj.weaver.Advice' (OnClassCondition)
- @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)
Negative matches:
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
AopAutoConfiguration.AspectJAutoProxyingConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'org.aspectj.weaver.Advice' (OnClassCondition)
十 springboot日志框架
springboot选用SLF4J和logback;
##SLF4J的使用:
在开发中,不应该直接调用日志的实现类,而是调用日志抽象层里面的方法;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
在使用日志框架时,需要导入SLf4j.jar 以及 slf4j实现jar 比如logback.jar 在使用一些不是直接实现slf4j的日志框架时,需要导入适配jar。具体见:
http://www.slf4j.org/manual.html
配置文件使用实现框架本身的配置文件;
如果在多个框架中想要整合多个框架用SLF4j进行日志输出,则需要使用适配jar替换原有日志jar包;
具体见:
http://www.slf4j.org/legacy.html
在这张图片中,可以看到slf4j提供了解决一个应用多个日志框架并存的解决方案;
由jcl-over.slf4j.jar log4j-over.slf4j.jar …替换掉原有的commons logging.jar log4j.jar…,这样就解决了多个日志框架并存的问题;
springboot能自动适配所有的日志,地城是用slf4j+logback的方式记录日志,引入其他框架时,需要把这个框架依赖的日志框架排除掉;
日志使用
@SpringBootTest
public class SpringbootApplicationTests {
//日志记录器
Logger logger = LoggerFactory.getLogger(getClass());
@Test
void serviceTest(){
//日志的级别,由低到高
logger.trace("这是trace日志信息");
logger.debug("这是debug信息");
logger.info("这是info信息");
logger.warn("这是warn信息");
logger.error("这是error信息");
}
在主配置文件中可调整输出级别;
logger.level.com.tree.springboot=trace
logging.file.path=/spring/log //在指定位置生成默认spring.log文件
日志输出格式:
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS}{%thread}%-5level %logger{50} - %msg%n
#在文件中输出日志的格式
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS}==={%thread}%-5level ===%logger{50} - %msg%n
指定配置:
在类路径下部署自己的配置文件即可;springboot就不使用默认配置文件;
具体可查springboot官方文档;
日志切换:
排除掉原来的logging-starter 使用新的日志starter
十一 web开发
添加模板引擎:
<!-- 添加thymeleaf模板引擎组件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
//只要根据配置将模板放在对应目录下,则会进行自动渲染
模板引擎使用:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:text="${hello}"></div>
</body>
</html>
3.模板引擎语法规则
-
th:text;改变当前元素里面的文本内容
th:任意html属性 ;替换原有属性值;
-
表达式:
- 获取属性、调用方法;
- 获取内置基本对象;
- 内置的一些工具对象:
十二.如何修改springboot默认配置
模式:
- springboot在自动配置很多组件的时候,会先看容器中是否有用户自己配置的(@Bena @Component) 如果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置和默认的组合起来;
- 在springboot中会有xxxCustomizer帮助我们进行定制配置
十三 国际化
-
添加国际化文件
-
添加国际化文件地址:
#国际化文件配置地址 spring.messages.basename=i18n.login
-
页面获取国际化值
th:text="#{login.username}" th:text="#{login.passowrd}" 如果是button使用行内表达式 [[#{login.rember}]]
4.点击链接切换国际化
package com.tree.springboot.component;
import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
/**
* 可以在链接上携带区域信息
*/
public class MyLocalResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
String l= httpServletRequest.getParameter("l");
//获取系统默认地址信息
Locale local=Locale.getDefault();
if(!StringUtils.isEmpty(l)) {
String[] split = l.split("_");
local=new Locale(split[0],split[1]);
}
return local;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
package com.tree.springboot.config;
import com.tree.springboot.component.MyLocalResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("hello");
}
//往容器中添加我们写的配置类
@Bean
public LocaleResolver localeResolver(){
return new MyLocalResolver();
}
}
4.登录错误消息表达式
<p style="color:red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
如果msg不为空则生成p标签;
- 拦截器
package com.tree.springboot.component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginHandlerInterceptor implements HandlerInterceptor {
//目标方法执行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object user=request.getSession().getAttribute("abc");
if(user == null){
request.setAttribute("msg","没有权限,请先登录");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else{
return true;
}
}
}
定义拦截组件
@Override
public void addInterceptors(InterceptorRegistry registry) {
//此拦截器拦截除login./...等的其他请求
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/login","/","/user/login");
}
注册拦截器
十四、公共片段抽取
定义和引用片段
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</div>
</body>
</html>
上面的代码定义了一个片段copy,我们可以使用th:insert或th:replace属性之一轻松地将其包含在主页中(并且th:include,尽管从Thymeleaf 3.0开始不再建议使用它):
<body>
...
<div th:insert="~{footer :: copy}"></div>
</body>
th:insert
和th:replace
(和th:include
)之间的差异
和之间有什么区别th:insert
和th:replace
(和th:include
,因为3.0不推荐)?
th:insert
最简单:它将简单地将指定的片段作为其host标签的主体插入。th:replace
实际上将其主机标签替换为指定的片段。th:include
与相似th:insert
,但不插入片段,而是仅插入该片段的内容。
因此,HTML片段如下所示:
<footer th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</footer>
…在主机``标签中包含了3次,如下所示:
<body>
...
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
</body>
…将导致:
<body>
...
<div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
</div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
<div>
© 2011 The Good Thymes Virtual Grocery
</div>
</body>
三种引入公共片段的方式:
th:insert: 插入到声明引入的元素
th:replace 替换为公共片段
th:include 将被引入的片段内容包含进这个标签中
引入片段传入参数
-
将要引入的html片段抽取出来,单独创建一个html并标记为公共片段
-
将公共片段引入到页面中
-
<th:class="${activeUri==‘main.html’?‘nav-link active’:'nav-link}"
-
<div th:replace="commons/bar::#sidebar(activeUri='emp')"></div>
发送put请求(ruest风格)
- springMVC配置hiddenHttpMethodFilter(springboot自动配置好的)
- 创建一个post表单
- 创建一个input项,name=“_method” 值就是我们制定的请求方式
<input type="hidden" name="_method" value="put" th:if=${emp!=null}>
<input type="hidden" name="_method" value="delete" th:if=${emp!=null}>
put请求:适合于修改页面
delete请求:适用于删除操作页面
<a th:${if:}></a>>
定制错误页面
原理:可以 参照ErrorMvcAutoConfiguation;
给容器中添加了如下组件:
- ErrorPageCustomizer
- BasicErrorController:处理错误请求
- ErrorPageCustomizer:系统出现错误以后,来到error请求进行处理;
- DefaultErrorViewResolver: 页面控制
步骤:系统发生错误:ErrorPageCustomizer生效,定制错误响应规则,接着来到BasicErrorController,
定制错误响应:
-
有模板引擎的情况下:
在resource下thymelaeaf文件夹下 创建error文件夹,并创建404错误页面。
如果没有匹配的指定错误,则创建4xx.html匹配其他以4开头的错误
页面能获取的信息:
timestamp:时间戳
status:状态码
error:错误提示
exception:异常对象
message:异常消息
errors: JSR303数据校验错误
-
没有模板引擎:在静态资源文件夹下找error文件夹,并找寻错误页面
-
定制错误json数据;
@ControllerAdvice public class MyExceptionHandler { @ResponseBody @ExceptionHandler(UserNotExistException.class) public Map<String,Object> handleException(Exception e ){ Map<String,Object> map=new HashMap<String,Object>(); map.put("code","user.notexits"); map.put("message",e.getMessage()); return map; } } //没有自适应效果,浏览器与客户端返回的都是json @ExceptionHandler(UserNotExistException.class) public String handleException(Exception e, HttpServletRequest request){ Map<String,Object> map=new HashMap<String,Object>(); //传入错误状态码 request.setAttribute("javax.servlet.error.status_code",400); map.put("code","user.notexits"); map.put("message",e.getMessage()); //转发值springboot默认错误处理控制器 return "forward:/error"; }
出现错误以后,回来到/error请求,会被BasicErrorControlloer处理,响应出去可以获取的数据是由getErrorAttributes得到的(是AbstractErrorController(ErrorContorller)规定的方法);
完全编写一个ErrorController实现类,放在容器中;将由我们自己控制错误处理请求;
页面上能用的数据,或者是json返回能用的数据都是通过erroeAttributes.getErrorAttributes得到的;
容器中DefaultErrorAttrributes.getErrorAttributes();默认进行数据处理;
自定义ErrorAttributes
//给容器中添加自定义errorAttributes @Component public class MyErrorAttributes extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { Map<String,Object> map=super.getErrorAttributes(webRequest,includeStackTrace); //天机错误信息 map.put("company","tree"); return map; } }
十五 配置嵌入式servlet
Springboot默认是用的嵌入式的servlet;
如何定制和修改servlet容器的相关配置
修改和server有关的配置
server.port=8080
#spring.profiles.active=dev
#用于配置项目访问路径
server.servlet.context-path=crud
//通用的servlet容器设置
server.xxxx
//tomcat的设置
server.tomcat.xxx
server.tomcat.accesslog.encoding=utf-8
public class ServerPropertiesServerProperties
//类用来配置servlet相关配置;
2.编写一个EmbeddedServletContainerCustomizer嵌入式的servlet容器定制器,来修改servlet配置;
3.注册servlet三大组件
由于springboot默认是以jar包的方式启动嵌入式的servlet容器来启动springboot的web应用,没有web.xml所以我们使用:
//注册三大组件
@Bean
public ServletRegistrationBean myServlet(){
//映射servlet请求,当发出myServlet请求时,就会来到这个servlet
ServletRegistrationBean servletRegistrationBean= new ServletRegistrationBean(new MyServlet(),"/myServlet");
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new MyFilter());
filterRegistrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean servletListenerRegistrationBean=new ServletListenerRegistrationBean<MyListener>(new MyListener());
return servletListenerRegistrationBean;
}
springboot帮我们自动注册springMVC的时候,自动的注册springmvc前端控制器,DispatcherServlet;
springMVC默认拦截所有,但是不拦截jsp请求; /*会拦截jsp
可以通过server.servletPath来修改springmvc前端控制器默认拦截的请求路径;
springboot能不能支持其他的servlet容器;
默认支持:Tomcat Jetty Undertow
引入别的容器:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入别的容器-->
<dependency>
<artifactId>spring-boot-starter-jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
? 部分注解
@ResponseBody
@Controller
以上两个注解等同于 @RestController
@Conditional
必须是@Condiiional 注解指定的条件成立,才能给容器中添加组件
@PostMapping(value=" ")
@RequestParam(" ")
@GetMapping("/emp/{id}")
public String toEditPage(@PathVariable(“id”) Integer id){
}
@PathVariable(""): 路径变量
记录
StringUtils()方法:
"redirect:重定向页面
"forward: 转发页面