springboot
1.概念
官方文档https://docs.spring.io/spring-boot/docs/1.5.17.RELEASE/reference/htmlsingle/#boot-features-external-config
2.自动配置
2.1自动配置启动(源码分析)
@SpringBootApplication//启动类注解 public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
@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 {
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration//配置类 public @interface SpringBootConfiguration {
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage//自动加载的包 @Import({EnableAutoConfigurationImportSelector.class})//加载EnableAutoConfigurationImportSelector
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({Registrar.class})//加载Registrar public @interface AutoConfigurationPackage {
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { Registrar() { } public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()); }//(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()扫描的包,可以打断点使用计算查看
public class EnableAutoConfigurationImportSelector extends AutoConfigurationImportSelector {
public class AutoConfigurationImportSelector implements DeferredImportSelector, ..//这个可以看官网spring的注解,对于这个类有相关介绍 .... public String[] selectImports(AnnotationMetadata annotationMetadata) List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); try {//读取的文件的位置 Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
其中例如有HttpEncodingAutoConfiguration编码的处理类,该类所有在配置文件中能配置的属性都是在xxxxProperties类中封装
总结:
1》@SpringBootApplication的main方法运行时自动扫描的包为:(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()扫描的包,可以打断点使用计算查看,默认为同包下
2》@SpringBootApplication会加载META-INF/spring.factories文件,将该配置文件中的配置载入到Spring容器。每种具有相应的xxxxProperties与之对应
2.2 @ConfigurationProperties
配置该注解后会出现如下
解决方法
添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
添加后如下,添加后的作用增加书写配置的提示功能
功能:自动注入相应的属性。并具备支持jsr3.3功能
例如:配置数据源
DataSourceAutoConfiguration自动配置类,对应的自动的properties为DataSourceProperties。
我们看DataSourceProperties类如下
所以相应的配置为:
spring.datasource.属性
总结:@ConfigurationProperties具有自动注解的功能
备注:其他注解
@Conditional派生注解//指定的条件成立才生效,否则无效
我们可以在配置文件中添加debug=true;来让控制台打印自动配置报告,这样可以很方便的知道哪些自动配置类生效;
2.3依赖的基本讲解
例如如下
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.17.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <!--web依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId>//web依赖及启动 </dependency> <!--测试--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
在父依赖中我们可以看到这样的一个依赖,里面有相应的的版本和依赖
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.5.17.RELEASE</version>
在配置文件中我们可以看到相应的配置的顶级依赖
假如我们需要添加向相应的依赖,那么可以参考官网添加相应的组件,如下
2.4 可自动加载的配置文件类型及位置及顺序及书写规范及使用
1)可自动加载的配置文件类型
2)加载的位置及顺序
a)优先级由高到低
file:./config/
file:./
classpath:/config/
classpath:/
b)现在加载的配置优先级高,高优先级的配置会覆盖低优先级的配置,同一文件夹下,文件顺序靠前的优先级高
c)配置外的加载顺序,,优先级由高到低,也可以使用如下方式
命令行参数
所有的配置都可以在命令行上进行指定
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.context-path=/abc,多个配置用空格分开; --配置项=值
来自java:comp/env的JNDI属性
Java系统属性(System.getProperties())
操作系统环境变量
RandomValuePropertySource配置的random.*属性值
优先加载带profile
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)配置文件
总结:所有的配置都可以在命令行上进行指定优先级是最高的,然后是系统环境类配置,然后是外部的application-{profile},然后是内部的application-{profile},然后是外部的application,然后是内部的application
3)书写规范
a)yml文件概念
YAML A Markup Language:是一个标记语言,YAML isn't Markup Language:不是一个标记语言;YAML:以数据为中心,比json、xml等更适合做配置文件;
b)规范
属性和值也是大小写敏感
字面量:普通的值(数字,字符串,布尔)
直接写
字符串默认不用加上单引号或者双引号;
"":双引号;不会转义字符串里面的特殊字符;
'':单引号;会转义特殊字符
对象、Map(属性和值)(键值对):
k: v:的方式书写属性和值的关系;例如//注意空格:后有空格
map: name: 张三 age: 23
行内写法:map: {name: 张三,age: 23}
数组(List、Set):
用- 值表示数组中的一个元素//在-后又空格
例如
pets: ‐ dog ‐ cat
行内写法 pets: [dog,cat]
4) 使用
map: {name: 张三, age: 23}
@Component @ConfigurationProperties(prefix = "map")//会提示红色,需要导入提示jar,当然不导入也可以运行 public class Person {
<dependency>//提示依赖 <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
备注:
yml书写是要注意层级关系,yml是依靠空格来控制层级关系的,对齐表示同一层级,靠后表示子层级,类似xml。
占位符
例如${random.value}、${random.int}、${random.long},person.last‐name=张三${random.uuid}
3.@Value获取值和@ConfigurationProperties获取值区别
4.@PropertySource&@ImportResource的区别
@PropertySource:加载指定的配置文件,配置中的内容不会生效,需要使用例如spel的方式获取
@ImportResource:导入Spring的配置文件,让配置文件里面的内容生效;
备注:在配置文件中可以添加随机占位符,${random.xxx}
5.@Profile
server: port: 8081 spring: profiles: active: prod #激活prod 端口变为8084 多配置选择 ‐‐‐ #分块 server: port: 8083 spring: profiles: dev ‐‐‐ server: port: 8084 spring: profiles: prod #指定属于哪个环境
激活的方式除了上述还有如下方式
配置文件中指定 spring.profiles.active=dev需要配合application-{profile}.properties/yml方式使用,默认加载的是application.properties的配置在其中通过spring.profiles.active=dev指定 命令行 java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev; 可以直接在测试的时候,配置传入命令行参数
虚拟机参数 -Dspring.profiles.active=dev
5.web中的使用
5.1静态资源的访问(WebMvcAutoConfiguration)
webjars:可以以jar包的方式引入静态资源;http://www.webjars.org/
<!‐‐例如 :引入jquery‐‐> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.3.1</version> </dependency>
所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找资源;
"/**" 访问当前项目的任何资源,都去(静态资源的文件夹)找映射(源码中就是采用的/**),所以也可以放入如下位置
"classpath:/META‐INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"
private static final String[] SERVLET_RESOURCE_LOCATIONS = new String[]{"/"}; private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/",
"classpath:/public/"};
也可以自己指定文件位置,spring.resources.static-locations=值的方式指定多个多个位置,用逗号隔开,但是默认位置就不在生效
默认页面的加载欢迎页; 静态资源文件夹下的所有index.html页面;
private WelcomePageHandlerMapping(Resource welcomePage, String staticPathPattern) { if (welcomePage != null && "/**".equals(staticPathPattern)) { logger.info("Adding welcome page: " + welcomePage); ParameterizableViewController controller = new ParameterizableViewController(); controller.setViewName("forward:index.html"); this.setRootHandler(controller); this.setOrder(0); } }
图标所有的 **/favicon.ico 都是在静态资源文件下找;
@Bean public SimpleUrlHandlerMapping faviconHandlerMapping() { SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); mapping.setOrder(-2147483647); mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", this.faviconRequestHandler())); return mapping; }
综上:
5.2 thymeleaf(官方推荐支持thymeleaf,不支持jsp)(官方文档https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.pdf)
引入依赖(已经有了相应的管理)
依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
<-- 不需要写版本,假如想更改版本,可以这样写!-->
<properties> <thymeleaf.version>3.0.9.RELEASE</thymeleaf.version> <!‐‐ 布局功能的支持程序 thymeleaf3主程序 layout2以上版本 ‐‐> <!‐‐ thymeleaf2 layout1‐‐> <thymeleaf‐layout‐dialect.version>3.0.9</thymeleaf‐layout‐dialect.version> </properties>
配置thymeleaf的默认解析,前缀为classpath:/templates/,后缀为.html
public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html";
基本使用:
其他(可以去官网看示例)
Simple expressions:(表达式语法) Variable Expressions: ${...}:获取变量值;OGNL; 1)、获取对象的属性、调用方法 2)、使用内置的基本对象: #ctx : the context object. #vars: the context variables. #locale : the context locale. #request : (only in Web Contexts) the HttpServletRequest object. #response : (only in Web Contexts) the HttpServletResponse object. #session : (only in Web Contexts) the HttpSession object. #servletContext : (only in Web Contexts) the ServletContext object. ${session.foo} 3)、内置的一些工具对象: #execInfo : information about the template being processed. #messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax. #uris : methods for escaping parts of URLs/URIs #conversions : methods for executing the configured conversion service (if any). #dates : methods for java.util.Date objects: formatting, component extraction, etc. #calendars : analogous to #dates , but for java.util.Calendar objects. #numbers : methods for formatting numeric objects. #strings : methods for String objects: contains, startsWith, prepending/appending, etc. #objects : methods for objects in general. #bools : methods for boolean evaluation. #arrays : methods for arrays. #lists : methods for lists. #sets : methods for sets. #maps : methods for maps. #aggregates : methods for creating aggregates on arrays or collections. #ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration). Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样; 补充:配合 th:object="${session.user}: <div th:object="${session.user}"> <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p> </div> Message Expressions: #{...}:获取国际化内容 Link URL Expressions: @{...}:定义URL; @{/order/process(execId=${execId},execType='FAST')} Fragment Expressions: ~{...}:片段引用表达式 <div th:insert="~{commons :: main}">...</div> 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: No‐Operation: _
[[]]会转义特殊字符 [()]不会特殊转义
6.springmvc
自动配置
Converter , GenericConverter , Formatter beans 视图解析器ContentNegotiatingViewResolver and BeanNameViewResolver beans 静态资源处理等
具体可以查看
拓展的配置
<mvc:view‐controller path="/hello" view‐name="success"/> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/hello"/> <bean></bean> </mvc:interceptor> </mvc:interceptors>
自定义配置
@Configuration
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Configuration {
自己添加功能可以实现WebMvcConfigurerAdapter,也就spring注解的中的一些接口实现
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能 @Configuration public class MyMvcConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(ViewControllerRegistry registry) { // super.addViewControllers(registry); //浏览器发送 /index请求来到 success registry.addViewController("/index").setViewName("success"); } }
当使用@EnableWebMvc自动配置就失效
原因
@Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc {
@Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
@Configuration @ConditionalOnWebApplication @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurerAdapter.class }) //容器中没有这个组件的时候,这个自动配置类才生效 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration {
转发重定向前后缀处理:自定拼串
public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html";
国际化
@ConfigurationProperties( prefix = "spring.messages" ) public class MessageSourceAutoConfiguration { private static final Resource[] NO_RESOURCES = new Resource[0]; private String basename = "messages";
默认的就是根据请求头带来的区域信息获取Locale进行国际化
@Bean @ConditionalOnMissingBean @ConditionalOnProperty(prefix = "spring.mvc", name = "locale") public LocaleResolver localeResolver() { if (this.mvcProperties .getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) { return new FixedLocaleResolver(this.mvcProperties.getLocale()); } AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver(); localeResolver.setDefaultLocale(this.mvcProperties.getLocale()); return localeResolver; }
点击链接切换国际化
public class MyLocaleResolver implements LocaleResolver { @Override public Locale resolveLocale(HttpServletRequest request) { String l = request.getParameter("l"); Locale locale = Locale.getDefault(); if(!StringUtils.isEmpty(l)){ String[] split = l.split("_"); locale = new Locale(split[0],split[1]); } return locale; } @Override public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) { } } @Bean public LocaleResolver localeResolver(){ return new MyLocaleResolver(); } }
例如
login.remember=记住我
<input type="checkbox" value="remember-me"> [[#{login.remember}]]
spring.messages.basename=i18n.index
禁用thymeleaf模板的缓存,ctrl+f9可以重写编译便于开发
spring.thymeleaf.cache=false
th:if
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
登录检查
public class LoginHandlerInterceptor implements HandlerInterceptor { //目标方法执行之前 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object user = request.getSession().getAttribute("loginUser"); if(user == null){ //未登陆,返回登陆页面 request.setAttribute("msg","没有权限请先登陆"); request.getRequestDispatcher("/index.html").forward(request,response); return false; }else{ //已登陆,放行请求 return true; } }
注册拦截器
@Override public void addInterceptors(InterceptorRegistry registry) { //super.addInterceptors(registry); //静态资源; *.css , *.js SpringBoot已经做好了静态资源映射 registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**") .excludePathPatterns("/index.html","/","/user/login"); } };
restful
thymeleaf引入片段
抽取公共片段 <div th:fragment="copy"> © 2018 The Good Thymes Virtual Grocery </div> 引入公共片段 <div th:insert="~{footer :: copy}"></div> ~{templatename::selector}:模板名::选择器 ~{templatename::fragmentname}:模板名::片段名 默认效果: insert的公共片段在div标签中 如果使用th:insert等属性进行引入,可以不用写~{}: 行内写法可以加上:[[~{}]];[(~{})];
th:insert:将公共片段整个插入到声明引入的元素中
th:replace:将声明引入的元素替换为公共片段
th:include:将被引入的片段的内容包含进这个标签中
例如
<footer th:fragment="copy"> © 2018 The Good Thymes Virtual Grocery </footer> 引入方式 <div th:insert="footer :: copy"></div> <div th:replace="footer :: copy"></div> <div th:include="footer :: copy"></div> 效果 <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>
日期格式化
public Formatter<Date> dateFormatter() { return new DateFormatter(this.mvcProperties.getDateFormat()); }
默认格式
修改
spring.mvc.date-format=yyyy-MM-dd
定义了的格式类型
static { Map<ISO, String> formats = new EnumMap(ISO.class); formats.put(ISO.DATE, "yyyy-MM-dd"); formats.put(ISO.TIME, "HH:mm:ss.SSSZ"); formats.put(ISO.DATE_TIME, "yyyy-MM-dd'T'HH:mm:ss.SSSZ"); ISO_PATTERNS = Collections.unmodifiableMap(formats); }
错误处理机制
根据不同的头信息accept返回相应的值,html/text返回的是页面,*/*返回的是json数据
原理:
可以参照ErrorMvcAutoConfiguration;错误处理的自动配置;
给容器中添加了以下组件
DefaultErrorAttributes:
@Override public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) { Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>(); errorAttributes.put("timestamp", new Date()); addStatus(errorAttributes, requestAttributes); addErrorDetails(errorAttributes, requestAttributes, includeStackTrace); addPath(errorAttributes, requestAttributes); return errorAttributes; }
BasicErrorController:处理默认/error请求,根据不同的accept,返回相应的值
ErrorPageCustomizer
@Value("${error.path:/error}") private String path = "/error"; 系统出现错误以后来到error请求进行处理;(web.xml注册的错误页面规则)
DefaultErrorViewResolver:
static { Map<Series, String> views = new HashMap(); views.put(Series.CLIENT_ERROR, "4xx"); views.put(Series.SERVER_ERROR, "5xx"); SERIES_VIEWS = Collections.unmodifiableMap(views); }
@Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) { ModelAndView modelAndView = resolve(String.valueOf(status), model); if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) { modelAndView = resolve(SERIES_VIEWS.get(status.series()), model); } return modelAndView; } private ModelAndView resolve(String viewName, Map<String, Object> model) { //默认SpringBoot可以去找到一个页面? error/404 String errorViewName = "error/" + viewName; //模板引擎可以解析这个页面地址就用模板引擎解析 TemplateAvailabilityProvider provider = this.templateAvailabilityProviders .getProvider(errorViewName, this.applicationContext); if (provider != null) { //模板引擎可用的情况下返回到errorViewName指定的视图地址 return new ModelAndView(errorViewName, model); } //模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面 error/404.html return resolveResource(errorViewName, model); }
thymeleaf模板能获取的信息;
timestamp:时间戳
status:状态码
error:错误提示
exception:异常对象
message:异常消息
errors:JSR303数据校验的错误都在这里
备注:假如以上页面都没有那么返回默认的页面
另外一种处理异常的方式,这里是转发到error页面来处理,进行根据不同的头信息accept返回相应的值,html/text返回的是页面,*/*返回的是json数据
@ExceptionHandler(UserNotExistException.class) public String handleException(Exception e, HttpServletRequest request){ Map<String,Object> map = new HashMap<>(); //传入我们自己的错误状态码 4xx 5xx,否则就不会进入定制错误页面的解析流程 /** * Integer statusCode = (Integer) request .getAttribute("javax.servlet.error.status_code"); */ request.setAttribute("javax.servlet.error.status_code",500); map.put("code","user.notexist"); map.put("message",e.getMessage());
request.setAttribute("ext",map)//将map的数据放入,其实这个可要可不要 //转发到/error return "forward:/error"; }
以上定义存在自定义数据不能携带的问题
出现错误以后,会来到/error请求,会被BasicErrorController处理,响应出去可以获取的数据是由getErrorAttributes得到的(是AbstractErrorController(ErrorController)规定的方法);
1、完全来编写一个ErrorController的实现类【或者是编写AbstractErrorController的子类】,放在容器中;
2、页面上能用的数据,或者是json返回能用的数据都是通过errorAttributes.getErrorAttributes得到;容器中DefaultErrorAttributes.getErrorAttributes();默认进行数据处理的;
自定义ErrorAttributes
@Component public class MyErrorAttributes extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) { Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
Map ext=requestAttributes.getAttribute("ext",0);//上述放入在request中的ext
map.put("ext",ext) return map; //这样就将上述的数据携带出去,还可以自定义的在map中添加属性 } }
7 与servlet之间的配合
设置相关属性
配置文件方式
server.port=8082 server.context‐path=/test server.tomcat.uri‐encoding=UTF‐8
另一种方式
@Bean //一定要将这个定制器加入到容器中 public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){ return new EmbeddedServletContainerCustomizer() { //定制嵌入式的Servlet容器相关的规则 @Override public void customize(ConfigurableEmbeddedServletContainer container) { container.setPort(8083); } }; }
备注:
SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来;
在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置
在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置
三大组件的使用
ServletRegistrationBean
@Bean public ServletRegistrationBean myServlet(){ ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet"); return registrationBean; }
FilterRegistrationBean
@Bean public FilterRegistrationBean myFilter(){ FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new MyFilter()); registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet")); return registrationBean; }
ServletListenerRegistrationBean
@Bean public ServletListenerRegistrationBean myListener(){ ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener()); return registrationBean; }
8. 外置的Servlet容器:外面安装Tomcat---应用war包的方式打包;
必须创建一个war项目;(利用idea创建好目录结构)
将嵌入式的Tomcat指定为provided;
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring‐boot‐starter‐tomcat</artifactId> <scope>provided</scope> </dependency>
必须编写一个SpringBootServletInitializer的子类,并调用configure方法
public class ServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { //传入SpringBoot应用的主程序 return application.sources(SpringBoot04WebJspApplication.class); } }
启动服务器就可以使用
9 jdbc
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring‐boot‐starter‐jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql‐connector‐java</artifactId> <scope>runtime</scope> </dependency>
spring: datasource: username: root password: 123456 url: jdbc:mysql://192.168.15.22:3306/jdbc driver‐class‐name: com.mysql.jdbc.Driver
自动配置原理:
org.springframework.boot.autoconfigure.jdbc:
参考DataSourceConfiguration,根据配置创建数据源,默认使用Tomcat连接池;可以使用spring.datasource.type指定自定义的数据源类型;
SpringBoot默认可以支持:org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource
自定义数据源类型
@ConditionalOnMissingBean(DataSource.class) @ConditionalOnProperty(name = "spring.datasource.type") static class Generic { @Bean public DataSource dataSource(DataSourceProperties properties) { //使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性 return properties.initializeDataSourceBuilder().build(); } }
DataSourceInitializer:ApplicationListener
runSchemaScripts();运行建表语句;
runDataScripts();运行插入数据的sql语句;
默认只需要将文件命名为:
schema‐*.sql、data‐*.sql 默认规则:schema.sql,schema‐all.sql; 可以使用 schema: classpath:department.sql //指定位置
整合Druid数据源
spring: datasource: username: root password: 123456 url: jdbc:mysql://192.168.15.22:3306/jdbc driver‐class‐name: com.mysql.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource
@Configuration public class DruidConfig { @ConfigurationProperties(prefix = "spring.datasource")//yml的前缀spring.datasource,导入资源 @Bean public DataSource druid(){ return new DruidDataSource(); } //配置Druid的监控 //1、配置一个管理后台的Servlet @Bean public ServletRegistrationBean statViewServlet(){ ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); Map<String,String> initParams = new HashMap<>(); initParams.put("loginUsername","admin"); initParams.put("loginPassword","123456"); initParams.put("allow","");//默认就是允许所有访问 initParams.put("deny","192.168.15.21"); bean.setInitParameters(initParams); return bean; } //2、配置一个web监控的filter @Bean public FilterRegistrationBean webStatFilter(){ FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new WebStatFilter()); Map<String,String> initParams = new HashMap<>(); initParams.put("exclusions","*.js,*.css,/druid/*"); bean.setInitParameters(initParams); bean.setUrlPatterns(Arrays.asList("/*")); return bean; } }