1.yaml配置文件
以数据为中心,取代了xml配置文件,标记语言
server:
port: 8080
语法:
1.字面量:(字符串,数字,布尔)
直接写即可,字符串无需加引号
userName: zhangsan
password: 1111
isSure: true
加双引号表示不转义特殊字符
加单引号转义特殊字符
2.对象(map)
server:
port: 8081
行内式写法
server: {port: 8081}
3.数组(list)
server:
- t1: a1
- t2: a2
- t3: a3
行内式写法
server: [t1: a1, t2: a2]
2.@ConfigurationProperties
加载配置文件中的属性
配置在类上,(prefix="") 类名
配置的类必须是springboot组件(添加@Component)
@ConfigurationProperties 与 @Value的区别
@ConfigurationProperties |
||
功能 |
批量注入配置文件中的属性 |
单个注入 |
松散绑定(驼峰等语法) |
支持 |
不支持 |
spEL(Spring的el表达式) |
不支持 |
支持 |
JSR303数据校验 |
支持 |
不支持 |
复杂的数据类型(Map,List) |
支持 |
不支持 |
业务不负责,只获取某个配置文件的属性时使用@Value
如果是bean类 注入值就使用@ConfigurationProperties
@PropertySource
加载某一个配置文件
@PropertySource(value={"classpath:***.properties"})
yml配置文件使用这种方法注入不生效
@ImportResource
修饰在主程序类上,引入spring的配置文件
@ImportResource(locations={"classpath:beans.xml"})
@Bean
@Configuration
public class Myconfig {
@Bean
public HelloService helloService(){
return new HelloService();
}
}
使用@Bean注解注入组件,代替了spring 使用配置文件注入组件的方式
配置类注入的组件,名称就是方法名
3.profile切换环境
多配置文件 可以创建多个application-{profile}.properties/yml文件
如application-dev.properties
.properties文件
spring.profiles.active=dev
激活dev命名的配置文件
.yml文件
server:
port: 18082
spring:
profiles:
active: test
---
server:
port: 8083
spring:
profiles: test
使用---分割多文档块,每一个文档块就是一个配置环境
同样使用
spring:
profiles:
active: test
激活哪个环境的配置
除了 spring.profiles.active=dev 之外可以使用命令行方式制定激活哪个配置文件
命令行方式
--spring.profiles.active=dev
虚拟机参数
-Dspring.profiles.active=dev
经过测试.properties配置文件的优先级要高于.yml的优先级
4.springboot配置文件优先级
file:/config/ >>> file:/ >>> classpath:/config/ >>>classpath:/
高优先级会覆盖低优先级
配置项目的访问路径
server:
servlet:
context-path: /boot
配置之后访问项目的根路径就修改了
修改默认配置文件位置
spring:
config:
location:
外部配置文件加载顺序(优先级由高到低)
1.命令行参数
java -jar ***.jar --server.port = 8089
代替配置文件中的server.port
2.带profile的配置文件
##### jar包外部的配置文件
jar包内部的配置文件
3.不带profile的配置文件
##### jar包外部的配置文件
jar包内部的配置文件
4.@Configuration注解类上的@PropertySource引入的配置文件
具体可以看官网文档
5.自动配置的原理
- 加载主程序时,开启@EnableAutoConfiguration自动配置功能
- @EnableAutoConfiguration详细剖析:
protected static final String PATH = "META-INF/" + "spring-autoconfigure-metadata.properties";
private AutoConfigurationMetadataLoader() {
}
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
return loadMetadata(classLoader, PATH);
}
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
try {
Enumeration urls = (classLoader != null) ? classLoader.getResources(path)
: ClassLoader.getSystemResources(path);
Properties properties = new Properties();
while (urls.hasMoreElements()) {
properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
}
return loadMetadata(properties);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
}
}
把autoConfig包类路径下的"META-INF/spring-autoconfigure-metadata.properties"文件读取出来后转为一个properties
再看一下META-INF/spring-autoconfigure-metadata.properties的内容
![1571987704850](E:\张尧\ zy_Typora笔记\images\1571987704850.png)
都是***AutoConfiguration自动配置类,用这些类才能实现自动配置功能
以简单的HTTPEncodingAutoConfiguration类做例子
@Configuration //注解类,也可注入容器
@EnableConfigurationProperties({HttpProperties.class}) //启用@ConfigurationProperties注解
@ConditionalOnWebApplication( //判断是否是web应用 是的话当前配置类 才生效
type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class}
CharacterEncodingFilter SpringMVC中进行乱码处理的过滤器
) //判断是否存在这个类
@ConditionalOnProperty( //判断配置文件是是否存在"spring.http.encoding"这个属性
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true //如果不存在,也生效
)
public class HttpEncodingAutoConfiguration {
private final Encoding properties;
Spring底层注解 @Conditional注解 根据不同的条件判断条件是否满足,如果满足,配置类才生效
HTTPProperties.class
@ConfigurationProperties(prefix = "spring.http")//从配置文件中获取属性绑定Bean
public class HttpProperties {
/**
* Whether logging of (potentially sensitive) request details at DEBUG and TRACE level
* is allowed.
*/
private boolean logRequestDetails;
当自动配置类生效的时候,就会从对应的***properties中获取对应的属性,例如(HttpProperties),而HttpProperties中的属性又是通过@ConfigurationProperties(prefix="")从配置文件中获取到的
自动配置类必须满足条件才能生效
查看哪些自动配置类生效的方法:
开启Spring Boot的debug模式,启动后打印自动配置报告
debug=true
Positive matches:(启动的自动配置类)
-----------------
CodecsAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.http.codec.CodecConfigurer' (OnClassCondition)
CodecsAutoConfiguration.JacksonCodecConfiguration matched:
- @ConditionalOnClass found required class 'com.fasterxml.jackson.databind.ObjectMapper' (OnClassCondition)
......
Negative matches:(未启用的自动配置类)
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
AopAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'org.aspectj.lang.annotation.Aspect' (OnClassCondition)
ArtemisAutoConfiguration:
Did not match:
五.springboot的日志
日志门面(日志框架的抽象层) |
日志实现框架 |
JCL SLF4J JBOSS_LOGGING |
log4j, logback,JUL, Log4j2 |
1.springboot 使用的是SLF4J +logback
2.SLF4J使用
统一日志到slf4j:
将其他日志框架排除
用slf4j的中间包替换,
springboot底层已经引入了中间包,如果要引入其他框架的话必须排查引入框架的默认日志依赖,否则可能会引起jar包冲突
导出slf4j其他实现包
3.使用方法
- 日志记录器
Logger logger = LoggerFactory.getLogger(getClass());
- 日志级别
日志级别(由低到高) trace
logger.trace("trace日志");
logger.debug("debug日志");
logger.info("info日志");
logger.warn("warn日志");
logger.error("error日志");
- springboot默认输入info级别,只会输出info级别上的日志
- 调整日志级别
注意如果不加com.zy会报错
logging:
level:
com:
zy: trace
- 指定日志文件的生成,位置
logging.file生成日志文件的名字,可以指定全路径,如不指定,在项目目录下生成
logging.path指定生成日志文件的路径,无法指定日志文件的名称,默认日志文件名称为spring.log
logging:
# file: springbootlog.log
path: /springboot/testlog
- 日志文件的格式
%d表示时间{yyyy-MM-dd HH:mm:ss.SSS}
%thread 表示线程名
%-5level 日志的级别从左到右显示5个字符宽度
%logger{50}表示记录器logger的名字(类的全路径)最长50个字符,否则按照据点分割
%msg 日志消息
%n 换行
logging:
#控制台输出日志的格式
pattern:
console: '%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n'
#日志文件输出日志的格式
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} ========== %msg%n"
- 指定自定义日志配置文件
对应的日志框架只要在类路径下直接放对应的配置文件即可
如果加了spring后缀,就可以使用高级功能--根据环节激活不同的配置文件
例如:
logback.xml:直接被日志框架识别
logback-spring.xml:日志框架不直接加载日志的配置项 根据配置激活的当前环境来激活不同的springprofile
在配置文件里这样区别,springboot就会根据是不是dev环境来加载不同的配置文件
Logging System |
Customization |
Logback |
logback-spring.xml, logback-spring.groovy, logback.xml or logback.groovy |
Log4j2 |
Log4j2-spring.xml or log4j2.xml |
JDK(JUL) |
logging.properties |
日志格式
日志格式
- 切换日志框架
直接切换实现jar
六.springBoot web开发
1.springboot对静态资源的映射规则
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if(!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if(!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if(!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
}
- 访问/webjars/*,都去classpath:/META-INF/resources/webjars/找资源
- webjars:以jar包的方式引入静态资源 如jquery等jar
org.webjar
jquery
3.3.1
可以设置跟静态资源相关的属性,如缓存时间等
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {
- "/**" 访问此路径则会再以下路径寻找静态资源,换言之,静态资源可以存放在下面几个文件里
"classpath:/META-INF/resources/,
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/,
"/" 当前项目的根路径
- 首页: 上述静态资源文件夹下的所有index页面 都被"/**"映射
也就是说 访问localhost:8080/ 时会自动寻找上述文件夹下的index页面 - 网站图标
所有页面访问**/favicon.ico 都会被映射到静态资源路径下
@Bean
public SimpleUrlHandlerMapping faviconHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(-2147483647);
mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", this.faviconRequestHandler()));
return mapping;
}
- 配置自定义静态资源文件夹
spring:
resources:
static-locations: classpath:/hello/
2.模板引擎
Thymeleaf: springboot专用
@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";
Thymeleaf使用
1.导入命名空间
xmlns:th="http://www.thymeleaf.org"
2.快速使用
欢迎
3.基本语法
1.th:text="${}" 改变元素的文本内容
th: 修改html元素的任意属性
2.表达式
Simple expressions:
Variable Expressions: ${...} 获取变量值 包括对象的属性 OGNL
Selection Variable Expressions: *{...} 与${}功能一致,配合${}使用
Message Expressions: #{...} 获取国际化内容
Link URL Expressions: @{...} url使用
Fragment Expressions: ~{...} 片段引用表达式
Literals 字面量
Text literals: 'one text' , 'Another one!' ,…
Number literals: 0 , 34 , 3.0 , 12.3 ,…
Boolean literals: true , false
Null literal: null
Literal tokens: one , sometext , main ,…
Text operations: 文本操作
String concatenation: +
Literal substitutions: |The name is ${name}|
Arithmetic operations: 数学运算
Binary operators: + , - , * , / , %
Minus sign (unary operator): -
Boolean operations: 布尔运算
Binary operators: and , or
Boolean negation (unary operator): ! , not
Comparisons and equality: 比较运算
Comparators: > , < , >= , <= ( gt , lt , ge , le )
Equality operators: == , != ( eq , ne )
Conditional operators: 条件运算
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
Special tokens: 特殊操作
Page 17 of 106No-Operation: _
3.th:replace 和 th:insert th:include 的区别
1,th:inssert:保留当前主标签,保留th:fragment主标签;
2,th:replace:舍弃当前主标签,保留th:fragment主标签;
3,th:include:保留当前主标签,舍弃th:fragment主标签
4.thymeleaf与script冲突
当java script中同样出现[[]]等thymeleaf解析符号时,thymeleaf会把js中的变量解析为thymeleaf中的属性,导致页面报错
解决办法:
</div><div id="u138bfeb1"><br /></div><h2 id="c320bf74"><span>3.springmvc的自动配置原理</span></h2><div id="u4ba006df"><br /></div><div id="u46449faa"><span>1.增加视图解析映射</span></div><div id="udc7e01b0"><br /></div><div>@Configuration</div><div>public class MyConfig extends WebMvcConfigurationSupport {</div><div><br /></div><div> @Override</div><div> protected void addViewControllers(ViewControllerRegistry registry) {</div><div> registry.addViewController("index.html").setViewName("index");</div><div> registry.addViewController("index").setViewName("index");</div><div> registry.addViewController("/").setViewName("index");</div><div>// super.addViewControllers(registry);</div><div> }</div><div>}</div><div id="uaaf72f53"><br /></div><h2 id="794d4fae"><span>4.修改springboot的默认配置</span></h2><div id="u50e03b94"><br /></div><div id="u77b04d77"><span>1.大多数模块直接注入一个自己的bean即可,springboot会先检测是否由用户配置,如果容器中有用户自定义的配置,就使用用户的配置</span></div><div id="uf9253cda"><br /></div><div id="u54568676"><span>2.另外一种情况是合并,spingboot会合并多个配置,如视图解析器(viewResolver) springboot会把多个视图解析器合并每个都生效</span></div><div id="u0e0051a5"><br /></div><h2 id="0379a285"><span>5.实际开发简单demo用到的功能点</span></h2><div id="ub98a2c46"><br /></div><h3 id="d562aef5"><span>1.国际化</span></h3><div id="u460a6e66"><br /></div><ol><li><span> 在类路径下建立国际化文件如下</span></li><li><span> springboot默认配置国际化信息在类路径下的message中 源码如下 </span> <br /><span>可以在配置文件中使用spring.message来修改配置路径 </span></li></ol><div>public class MessageSourceProperties {</div><div> private String basename = "messages";</div><div>@Bean</div><div>@ConfigurationProperties(</div><div> prefix = "spring.messages"</div><div>)</div><div>public MessageSourceProperties messageSourceProperties() {</div><div> return new MessageSourceProperties();</div><div>}</div><div>spring:</div><div> messages:</div><div> basename: i18n.test</div><ol start="3"><li><span> thymeleaf中使用#{}获取国际化信息 </span></li></ol><div><div th:text="#{name}"></div></div><div><a th:href="@{/index.html(l='zh_CN')}">中文</a></div><div><a th:href="@{/index.html(l='en_US')}">英文</a></div><ol start="4"><li><span> 修改默认的国际化解析器<br /></span><span>默认的国际化解析器是由浏览器请求头传递国家和语言信息的<br /></span><strong><span>request.getHeader("Accept-Language")</span></strong></li></ol><div> public Locale resolveLocale(HttpServletRequest request) {</div><div> Locale defaultLocale = this.getDefaultLocale();</div><div> if (defaultLocale != null && request.getHeader("Accept-Language") == null) {</div><div> return defaultLocale;</div><div> } else {</div><div> Locale requestLocale = request.getLocale();</div><div> List<Locale> supportedLocales = this.getSupportedLocales();</div><div> if (!supportedLocales.isEmpty() && !supportedLocales.contains(requestLocale)) {</div><div> Locale supportedLocale = this.findSupportedLocale(request, supportedLocales);</div><div> if (supportedLocale != null) {</div><div> return supportedLocale;</div><div> } else {</div><div> return defaultLocale != null ? defaultLocale : requestLocale;</div><div> }</div><div> } else {</div><div> return requestLocale;</div><div> }</div><div> }</div><div> }</div><div id="ua0a31e01"><br /></div><div id="u2c0d55e3"><span>修改默认的国际化信息解析器为如下逻辑</span></div><div id="u4b9da5b1"><br /></div><div id="u318cf710"><span>如果我们传递的参数没有带国际化信息,就使用默认的国际化解析器(从请求头中获取国际化信息并解析),如果我们传递的参数有国际化信息,就从参数中获取国际化信息</span></div><div id="u4fb3a2a6"><br /></div><div>package com.zy.hello.component;</div><div><br /></div><div>import org.springframework.util.StringUtils;</div><div>import org.springframework.web.servlet.LocaleResolver;</div><div><br /></div><div>import javax.servlet.http.HttpServletRequest;</div><div>import javax.servlet.http.HttpServletResponse;</div><div>import java.util.Locale;</div><div><br /></div><div>/**</div><div> * @author: zhangyao</div><div> * @create:2019-10-31 11:13</div><div> **/</div><div>public class MyLocaleResovler implements LocaleResolver {</div><div><br /></div><div> @Override</div><div> public Locale resolveLocale(HttpServletRequest httpServletRequest) {</div><div><br /></div><div> Locale locale = Locale.getDefault();</div><div> String l = httpServletRequest.getParameter("l");</div><div> if(!StringUtils.isEmpty(l)){</div><div> //参数中以下划线分割了语言和国家</div><div> String[] localArray = l.split("_");</div><div> locale = new Locale(localArray[0],localArray[1]);</div><div> }</div><div><br /></div><div> return locale;</div><div> }</div><div><br /></div><div> @Override</div><div> public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {</div><div><br /></div><div> }</div><div>}</div><div id="u908a5cd5"><br /></div><div id="u2e726109"><span>传递路径示例:</span></div><div id="u8b43f580"><br /></div><div id="u734a277e"><a href="http://localhost:8080/index.html?l=zh_CN" target="_blank"><span>http://localhost:8080/index.html?l=zh_CN</span></a></div><div id="u12dc28ab"><br /></div><div id="u2308256e"><span>把重写的国际化解析器放入容器</span></div><div id="ucd45c99d"><br /></div><div> @Bean</div><div> public LocaleResolver localeResolver(){</div><div> return new MyLocaleResovler();</div><div> }</div><div id="uc066afc0"><br /></div><h3 id="2cfe70f9"><span>2.禁用thymeleaf缓存</span></h3><div id="u94f4ef67"><br /></div><div>spring:</div><div> thymeleaf:</div><div> cache: false</div><div id="u40a97ba5"><br /></div><div id="u10aeec9b"><span>ctrl+F9 编译idea 项目</span></div><div id="u4ae83a45"><br /></div><div id="ufbbfaa73"><span>这两个操作 使页面修改后不必重启服务 就可以生效</span></div><div id="u6c189a22"><br /></div><h3 id="9bb0e2b6"><span>3.springBoot的错误页面剖析</span></h3><div id="u2b091fab"><br /></div><h4 id="1.DefaultErrorAttributes"><span>1.DefaultErrorAttributes</span></h4><div id="ua13bc9f9"><br /></div><div>@Bean</div><div> @ConditionalOnMissingBean(</div><div> value = {ErrorAttributes.class},</div><div> search = SearchStrategy.CURRENT</div><div> )</div><div> public DefaultErrorAttributes errorAttributes() {</div><div> return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());</div><div> }</div><div id="uf495db45"><br /></div><h4 id="29b50052"><span>2.BasicErrorController // 处理/error请求的</span></h4><div id="u0d1ab37e"><br /></div><div>@Bean</div><div>@ConditionalOnMissingBean(</div><div> value = {ErrorController.class},</div><div> search = SearchStrategy.CURRENT</div><div>)</div><div>public BasicErrorController basicErrorController(ErrorAttributes errorAttributes, ObjectProvider<ErrorViewResolver> errorViewResolvers) {</div><div> return new BasicErrorController(errorAttributes, this.serverProperties.getError(), (List)errorViewResolvers.orderedStream().collect(Collectors.toList()));</div><div>}</div><div id="ub7dc0326"><br /></div><div>@Controller</div><div>@RequestMapping({"${server.error.path:${error.path:/error}}"})</div><div>public class BasicErrorController extends AbstractErrorController {</div><div> private final ErrorProperties errorProperties;</div><div> </div><div> </div><div>@RequestMapping(</div><div> produces = {"text/html"}</div><div>)//请求头如果是text/html返回html页面</div><div> public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {</div><div> HttpStatus status = this.getStatus(request);</div><div> Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));</div><div> response.setStatus(status.value());</div><div> </div><div> //返回的错误页面 如果有视图解析就返回视图解析 如果没有 就返回默认的/error</div><div> ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);</div><div> return modelAndView != null ? modelAndView : new ModelAndView("error", model);</div><div> }</div><div><br /></div><div> @RequestMapping //如果不是text/html就返回json数据</div><div> public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {</div><div> HttpStatus status = this.getStatus(request);</div><div> if (status == HttpStatus.NO_CONTENT) {</div><div> return new ResponseEntity(status);</div><div> } else {</div><div> Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));</div><div> return new ResponseEntity(body, status);</div><div> }</div><div> }</div><div id="ud6d75b03"><br /></div><div>protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) {</div><div> //拿到所有的错误页面解析器 如果没有视图解析器就返回了null</div><div> Iterator var5 = this.errorViewResolvers.iterator();</div><div> </div><div> ModelAndView modelAndView;</div><div> do {</div><div> if (!var5.hasNext()) {</div><div> return null;</div><div> }</div><div><br /></div><div> ErrorViewResolver resolver = (ErrorViewResolver)var5.next();</div><div> modelAndView = resolver.resolveErrorView(request, status, model);</div><div> } while(modelAndView == null);</div><div><br /></div><div> return modelAndView;</div><div> }</div><div id="ub828ecdd"><br /></div><h4 id="f9ed1bbb"><span>3.ErrorPageCustomizer 当发生错误时确定应该返回什么请求 默认是/error</span></h4><div id="u53d5d8ed"><br /></div><div> @Value("${error.path:/error}")</div><div> private String path = "/error";//返回错误请求</div><div id="u84025924"><br /></div><h4 id="6d9c8f55"><span>4.DefaultErrorViewResolver 生成默认的错误页面</span></h4><div id="udb5cd4bb"><br /></div><div>public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {</div><div> //解析</div><div> ModelAndView modelAndView = this.resolve(String.valueOf(status.value()), model);</div><div> if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {</div><div> modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);</div><div> }</div><div><br /></div><div> return modelAndView;</div><div>}</div><div><br /></div><div>//生成错误页面的抿成</div><div>private ModelAndView resolve(String viewName, Map<String, Object> model) {</div><div> String errorViewName = "error/" + viewName;</div><div> //模板引擎可用就使用模板引擎 error/ 404.html这种格式</div><div> TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);</div><div> </div><div> //不可用的情况下就去静态资源文件夹下找资源</div><div> return provider != null ? new ModelAndView(errorViewName, model) : </div><div> this.resolveResource(errorViewName, model);</div><div>}</div><div><br /></div><div><br /></div><div>//静态资源文件夹里寻找资源</div><div>private ModelAndView resolveResource(String viewName, Map<String, Object> model) {</div><div> //所有的静态资源文件</div><div> String[] var3 = this.resourceProperties.getStaticLocations();</div><div> int var4 = var3.length;</div><div><br /></div><div> for(int var5 = 0; var5 < var4; ++var5) {</div><div> String location = var3[var5];</div><div><br /></div><div> try {</div><div> Resource resource = this.applicationContext.getResource(location);</div><div> resource = resource.createRelative(viewName + ".html");</div><div> if (resource.exists()) {</div><div> return new ModelAndView(new DefaultErrorViewResolver.HtmlResourceView(resource), model);</div><div> }</div><div> } catch (Exception var8) {</div><div> }</div><div> }</div><div><br /></div><div> return null;</div><div> }</div><div id="u3f87d805"><br /></div><h4 id="d320ad68"><span>5.错误页面生成的步骤总结</span></h4><div id="u1c2449cc"><br /></div><div id="u91cd4c84"><span>1.当发生错误时 由 </span><strong><span>ErrorPageCustomizer</span></strong><span> 确定错误请求是什么(默认是/error,可以配置)</span></div><div id="u37421fd5"><br /></div><div id="u2b9fbbc9"><span>2.由</span><strong><span>BasicErrorController</span></strong><span> 处理错误请求</span></div><div id="ua94226e4"><br /></div><div id="ucef302cb"><span>3.</span><strong><span>DefaultErrorViewResolver</span></strong><span> 生成返回的错误页面</span></div><div id="ua86accdd"><br /></div><h4 id="c8ed424b"><span>6.如果想要自定义错误页面</span></h4><div id="ufa6adfe0"><br /></div><div id="u566a0ed2"><span>1.有模板引擎直接在templates下建立error文件夹 里面存放404.html 500.html等文件即可</span></div><div id="uf8e21f1b"><br /></div><div id="uc7286855"><span> 或者直接使用4xx这样的文件名,所有以4开头的错误都会跳转到此页面</span></div><div id="u8abe0c4f"><br /></div><h2 id="e0041cf1"><span>6.自定义拦截器</span></h2><div id="u906b6cd3"><br /></div><div>package com.zy.blog.interceptor;</div><div><br /></div><div>import com.zy.blog.entity.User;</div><div>import org.springframework.web.servlet.HandlerInterceptor;</div><div>import org.springframework.web.servlet.ModelAndView;</div><div><br /></div><div>import javax.servlet.http.HttpServletRequest;</div><div>import javax.servlet.http.HttpServletResponse;</div><div><br /></div><div>/**</div><div> * @author: zhangyao</div><div> * @create:2019-11-06 09:38</div><div> **/</div><div><br /></div><div>public class LoginInterceptor implements HandlerInterceptor {</div><div> @Override</div><div> public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {</div><div><br /></div><div> if(request.getRequestURL().indexOf("admin")!=-1){</div><div> User user = (User) request.getSession().getAttribute("user");</div><div> if(user!=null){</div><div> //已登录</div><div> return true;</div><div> }else{</div><div> request.setAttribute("message","请先登录");</div><div> request.getRequestDispatcher("/admin/login").forward(request,response);</div><div> return false;</div><div> }</div><div> }</div><div> return false;</div><div> }</div><div><br /></div><div> @Override</div><div> public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {</div><div><br /></div><div> }</div><div><br /></div><div> @Override</div><div> public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {</div><div><br /></div><div> }</div><div>}</div><div id="ub0dfec29"><br /></div><div id="u4431a755"><span>1.实现handlerInterceptor接口 在preHandle里判断拦截器实现的需求</span></div><div id="u7bfdd657"><br /></div><div id="ua27788a6"><span>2.将自定义的拦截器配置到MVC中</span></div><div id="u766620fc"><br /></div><div>package com.zy.blog.component;</div><div><br /></div><div>import com.zy.blog.interceptor.LoginInterceptor;</div><div>import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;</div><div>import org.springframework.context.annotation.Configuration;</div><div>import org.springframework.web.servlet.config.annotation.InterceptorRegistry;</div><div>import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;</div><div><br /></div><div>/**</div><div> * @author: zhangyao</div><div> * @create:2019-11-06 11:11</div><div> **/</div><div>@Configuration</div><div>public class WebMvcConfigAdapt implements WebMvcConfigurer {</div><div> @Override</div><div> public void addInterceptors(InterceptorRegistry registry) {</div><div> registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/admin/**").excludePathPatterns("**/login","/login","/admin/login");</div><div> }</div><div>}</div><div id="u75f756b8"><br /></div><div id="uea3e1110"><span>需要注意 springboot2.x 后 WebMvcConfigurationAdapt类废弃,需要使用WebMvcConfigurer代替</span></div><div id="ua5658006"><br /></div><div id="u81997f95"><strong><span>WebMvcConfigurer: 继续使用springboot提供的 webMvc配置和功能,与自定义的mvc配置合并</span></strong></div><div id="u3f455197"><br /></div><div id="u6f4dc37c"><strong><span>WebMvcConfigurationSupport: 使用后取代了springboot的默认配置,需要自己配置mvc功能</span></strong></div><div id="ub1427ee9"><br /></div><div id="u392926b5"><strong><span>@EnableWebMvc:使用此注解则springboot提供的默认配置失效</span></strong></div><div id="uc37f9371"><br /></div><h2 id="8047ee6a"><span>7.嵌入式容器详解</span></h2><div id="u0db44f67"><br /></div><div id="uc6f09b79"><br /></div><div id="ubd6640bf"><br /></div><div id="u4132e864"><strong><span>springboot默认使用tomcat作为嵌入式容器</span></strong></div><div id="ub9153626"><br /></div><h3 id="84cf0ba5"><span>修改tomcat的配置:</span></h3><div id="u3d38bb5a"><br /></div><div id="u6452ce74"><span>1.通过配置文件修改 (serverProperties)</span></div><div id="ud5ad3304"><br /></div><div>server:</div><div> tomcat:</div><div> accept-count: 100</div><div id="u64e52ef7"><br /></div><div>@ConfigurationProperties(</div><div> prefix = "server",</div><div> ignoreUnknownFields = true</div><div>)</div><div>public class ServerProperties {</div><div> private Integer port;</div><div> private InetAddress address;</div><div id="u50fdfa98"><br /></div><div id="ufe640026"><span>可以修改server的通用属性如 server.port属性</span></div><div id="uc692beee"><br /></div><div id="u39e8dba2"><span>也可以修改不同容器的特殊属性 如server.tomcat.accept-count tomcat的最大连接数等</span></div><div id="ua1040c90"><br /></div><div id="u36d9ed19"><span>2.通过自定义配置类修改(WebServerFactoryCustomizer)</span></div><div id="uba8cc634"><br /></div><div>@Bean</div><div>public WebServerFactoryCustomizer webServerFactoryCustomizer(){</div><div> return new WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>() {</div><div><br /></div><div> @Override</div><div> public void customize(ConfigurableServletWebServerFactory factory) {</div><div> factory.setPort(9998);</div><div> }</div><div> };</div><div>}</div><div id="u0e3567fb"><br /></div><div id="u12159368"><span>配置类修改容器属性实质上也是通过webServerFactoryCustomizer 这种方式修改</span></div><div id="ue8c65cdf"><br /></div><h3 id="6f1f7eec"><span>修改springboot的默认嵌入式容器</span></h3><div id="u7a873a46"><br /></div><div id="u4702399d"><span>1.排查tomcat 依赖</span></div><div id="u0c121513"><br /></div><div id="u77e62e63"><span>2.引入其他容器依赖 如jetty netty undertow</span></div><div id="u37093690"><br /></div><div> <dependency></div><div> <groupId>org.springframework.boot</groupId></div><div> <artifactId>spring-boot-starter-web</artifactId></div><div> <exclusions></div><div> <exclusion></div><div> <artifactId>spring-boot-starter-tomcat</artifactId></div><div> <groupId>org.springframework.boot</groupId></div><div> </exclusion></div><div> </exclusions></div><div> </dependency></div><div> <!-- <dependency></div><div> <artifactId>spring-boot-starter-jetty</artifactId></div><div> <groupId>org.springframework.boot</groupId></div><div> </dependency>--></div><div id="u4fb5ff5c"><br /></div><div id="u40ed9477"><span>改为jetty后启动报错,原因是缺少jar包,在idea中增加依赖 tomcat下的lib包和bin下的tomcat-juli</span></div><div id="u5c9d81db"><br /></div><h1 id="c957431a"><span>七 docker 与 spring boot</span></h1><div id="u116c01b7"><br /></div><h2 id="5aba6572"><span>1.docker简介</span></h2><div id="u4a696381"><br /></div><div id="uaa044b0f"><span>docker 是一个开源的应用容器引擎,基于go语言,尊村apache2.0协议开源</span></div><div id="uf6833939"><br /></div><div id="u586d4dff"><span>docker可以把软件,应用等打包发布,便于移植到其他环境,使用时直接启动通过docker下载的容器即可,类似与window镜像系统,但是是一个轻量级的容器应用</span></div><div id="u490043cf"><br /></div><h2 id="49b6eaa2"><span>2.docker核心概念</span></h2><div id="uf2f4d104"><br /></div><div id="ua263c9d4"><span>host:主机 安装了docker的主机</span></div><div id="u9b884d56"><br /></div><div id="u14968b70"><span>client:客户端 docker的客户端,可以通过客户端访问主机</span></div><div id="u2b357687"><br /></div><div id="u2eb929ca"><span>registry:仓库 存放docker镜像,分为公共仓库(docker hub) 和私人仓库(自己搭建)</span></div><div id="u5ffc8adf"><br /></div><div id="ue7e49d2a"><span>images:镜像 类似与window镜像一样的东西</span></div><div id="udd1f5014"><br /></div><div id="u9e09055c"><span>container:容器 运行镜像的 每一个镜像可以运行在多个容器中</span></div><div id="u00952c18"><br /></div><h2 id="f7c3f935"><span>3.安装docker</span></h2><div id="u1db494ed"><br /></div><div id="u64f39532"><span>linux为例</span></div><div id="u02824ca8"><br /></div><div id="u3029c0e3"><span>centos7</span></div><div id="u94370bfa"><br /></div><div id="u8d4d5cab"><span>docker 要求linux内核大于 3.10</span></div><div id="uc1236ded"><br /></div><div id="u03867c3d"><span>查看内核版本</span></div><div id="uaa41fec0"><br /></div><div>uname -r</div><div id="u6d6e2e1c"><br /></div><div id="u3326bde5"><span>如果内核版本过低,需要升级</span></div><div id="u881aa4ad"><br /></div><div>yum update</div><div id="u02f95407"><br /></div><div id="u0ec44540"><strong><span>安装docker</span></strong></div><div id="u3c8cff96"><br /></div><div>yum install docker</div><div id="u5473f4ba"><br /></div><div id="u8c6a61c5"><strong><span>启动docker 有两种方式</span></strong></div><div id="ue450b28f"><br /></div><ol><li><br /></li></ol><div>systemctl start docker</div><ol start="2"><li><br /></li></ol><div>service docker start</div><div id="ud2e0ef64"><br /></div><div id="uc7e81ddf"><strong><span>开启启动docker</span></strong></div><div id="ue334b9be"><br /></div><div>systemctl enable docker</div><div id="u4fdff9d8"><br /></div><div id="ue3fc57e7"><strong><span>停止docker</span></strong></div><div id="u5d3fa56e"><br /></div><div>systemctl stop docker</div><div id="uca0d17aa"><br /></div><div>service docker stop</div><div id="uc2dc9b49"><br /></div><h2 id="fa7198a5"><span>4.docker常用命令</span></h2><div id="ud40328b4"><br /></div><h3 id="ac42b307"><span>镜像常用操作</span></h3><div id="uc19aab89"><br /></div><div id="u907688d1"><span>1.搜索镜像</span></div><div id="u9caadbd3"><br /></div><div>docker search mysql(镜像关键字)</div><div id="ue96898ee"><br /></div><div id="u4395303d"><span>2.拉取镜像</span></div><div id="u5d05bdeb"><br /></div><div>docker pull mysql(镜像名)</div><div id="u05f59bb9"><br /></div><div id="u2cfd2247"><span>3.查询本地镜像</span></div><div id="u94cf8611"><br /></div><div>docker images</div><div id="ucf80a2a4"><br /></div><div id="u790b902a"><span>4.删除镜像</span></div><div id="ue8ed0cba"><br /></div><div>docker rmi mysql(镜像名)</div><div id="ub2bd2cbf"><br /></div><h3 id="1a37581d"><span>容器常用操作</span></h3><div id="u4c2578b9"><br /></div><div id="u95993b91"><strong><span>1.根据镜像启动容器</span></strong></div><div id="u7cb35dae"><br /></div><div>docker run -d --name mysql01 mysql01 -p 3306:3306</div><div id="uf4ebc4c8"><br /></div><div id="u2cd4d8cd"><span>-d:后台运行</span></div><div id="u25756267"><br /></div><div id="ub8a2c915"><span>--name:容器名</span></div><div id="u898aecc9"><br /></div><div id="ucd1fe63c"><span>-p:端口映射 第一个端口号是主机端口 第二个端口是docker端口</span></div><div id="u06fdab42"><br /></div><div id="u86e84c29"><strong><span>2.查看所有的运行中容器</span></strong></div><div id="ua15dfce1"><br /></div><div>docker ps -a</div><div id="u98144a65"><br /></div><div id="u99194a9e"><span>-a 所有的容器</span></div><div id="ufe6fe724"><br /></div><div id="u5ac6689c"><span>不加-a只查询运行中的容器</span></div><div id="u98449c56"><br /></div><div id="u853e95c1"><strong><span>3.停止容器</span></strong></div><div id="ue12548d9"><br /></div><div>docker stop mysql</div><div id="uafe35992"><br /></div><div id="u061b0da3"><strong><span>4.删除容器</span></strong></div><div id="ue6af95f6"><br /></div><div>docker rm mysql(容器名)</div><div id="uc0eb064a"><br /></div><div id="u298ba557"><span>5.查看防火墙</span></div><div id="uaf7b6d21"><br /></div><div>service firewalld status</div><div>service firewalld stop 关闭防火墙</div><div id="u8dcd9fe7"><br /></div><div id="u949a97e8"><span>6.查看容器日志</span></div><div id="ue79b4372"><br /></div><div>docker logs mysql(容器名)</div><div id="uc0a523fb"><br /></div><h1 id="410b114d"><span>八 springboot中的数据交互(mybatis jpa spring data)</span></h1><div id="u5c3f4ee6"><br /></div><div id="uc85d2f54"><span>缺</span></div><div id="u78fc7ec3"><br /></div><h1 id="a836c621"><span>九 cache</span></h1>