SpringBoot
SpringBoot自动配置包:spring-boot-autoconfigure
1、启动器
- Springboot将所有的场景,定义为一个个启动器。需要什么功能,就导入什么启动器
Name | Description |
---|---|
spring-boot-starter | Core starter, including auto-configuration support, logging and YAML |
spring-boot-starter-activemq | Starter for JMS messaging using Apache ActiveMQ |
spring-boot-starter-amqp | Starter for using Spring AMQP and Rabbit MQ |
spring-boot-starter-aop | Starter for aspect-oriented programming with Spring AOP and AspectJ |
spring-boot-starter-artemis | Starter for JMS messaging using Apache Artemis |
spring-boot-starter-batch | Starter for using Spring Batch |
spring-boot-starter-cache | Starter for using Spring Framework’s caching support |
spring-boot-starter-data-cassandra | Starter for using Cassandra distributed database and Spring Data Cassandra |
spring-boot-starter-data-cassandra-reactive | Starter for using Cassandra distributed database and Spring Data Cassandra Reactive |
spring-boot-starter-data-couchbase | Starter for using Couchbase document-oriented database and Spring Data Couchbase |
spring-boot-starter-data-couchbase-reactive | Starter for using Couchbase document-oriented database and Spring Data Couchbase Reactive |
spring-boot-starter-data-elasticsearch | Starter for using Elasticsearch search and analytics engine and Spring Data Elasticsearch |
spring-boot-starter-data-jdbc | Starter for using Spring Data JDBC |
spring-boot-starter-data-jpa | Starter for using Spring Data JPA with Hibernate |
spring-boot-starter-data-ldap | Starter for using Spring Data LDAP |
spring-boot-starter-data-mongodb | Starter for using MongoDB document-oriented database and Spring Data MongoDB |
spring-boot-starter-data-mongodb-reactive | Starter for using MongoDB document-oriented database and Spring Data MongoDB Reactive |
spring-boot-starter-data-neo4j | Starter for using Neo4j graph database and Spring Data Neo4j |
spring-boot-starter-data-r2dbc | Starter for using Spring Data R2DBC |
spring-boot-starter-data-redis | Starter for using Redis key-value data store with Spring Data Redis and the Lettuce client |
spring-boot-starter-data-redis-reactive | Starter for using Redis key-value data store with Spring Data Redis reactive and the Lettuce client |
spring-boot-starter-data-rest | Starter for exposing Spring Data repositories over REST using Spring Data REST |
spring-boot-starter-data-solr | Starter for using the Apache Solr search platform with Spring Data Solr |
spring-boot-starter-freemarker | Starter for building MVC web applications using FreeMarker views |
spring-boot-starter-groovy-templates | Starter for building MVC web applications using Groovy Templates views |
spring-boot-starter-hateoas | Starter for building hypermedia-based RESTful web application with Spring MVC and Spring HATEOAS |
spring-boot-starter-integration | Starter for using Spring Integration |
spring-boot-starter-jdbc | Starter for using JDBC with the HikariCP connection pool |
spring-boot-starter-jersey | Starter for building RESTful web applications using JAX-RS and Jersey. An alternative to spring-boot-starter-web |
spring-boot-starter-jooq | Starter for using jOOQ to access SQL databases. An alternative to spring-boot-starter-data-jpa or spring-boot-starter-jdbc |
spring-boot-starter-json | Starter for reading and writing json |
spring-boot-starter-jta-atomikos | Starter for JTA transactions using Atomikos |
spring-boot-starter-jta-bitronix | Starter for JTA transactions using Bitronix. Deprecated since 2.3.0 |
spring-boot-starter-mail | Starter for using Java Mail and Spring Framework’s email sending support |
spring-boot-starter-mustache | Starter for building web applications using Mustache views |
spring-boot-starter-oauth2-client | Starter for using Spring Security’s OAuth2/OpenID Connect client features |
spring-boot-starter-oauth2-resource-server | Starter for using Spring Security’s OAuth2 resource server features |
spring-boot-starter-quartz | Starter for using the Quartz scheduler |
spring-boot-starter-rsocket | Starter for building RSocket clients and servers |
spring-boot-starter-security | Starter for using Spring Security |
spring-boot-starter-test | Starter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito |
spring-boot-starter-thymeleaf | Starter for building MVC web applications using Thymeleaf views |
spring-boot-starter-validation | Starter for using Java Bean Validation with Hibernate Validator |
spring-boot-starter-web | Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container |
spring-boot-starter-web-services | Starter for using Spring Web Services |
spring-boot-starter-webflux | Starter for building WebFlux applications using Spring Framework’s Reactive Web support |
spring-boot-starter-websocket | Starter for building WebSocket applications using Spring Framework’s WebSocket support |
spring-boot-starter-actuator | Starter for using Spring Boot’s Actuator which provides production ready features to help you monitor and manage your application |
spring-boot-starter-jetty | Starter for using Jetty as the embedded servlet container. An alternative to spring-boot-starter-tomcat |
spring-boot-starter-log4j2 | Starter for using Log4j2 for logging. An alternative to spring-boot-starter-logging |
spring-boot-starter-logging | Starter for logging using Logback. Default logging starter |
spring-boot-starter-reactor-netty | Starter for using Reactor Netty as the embedded reactive HTTP server. |
spring-boot-starter-tomcat | Starter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web |
spring-boot-starter-undertow | Starter for using Undertow as the embedded servlet container. An alternative to spring-boot-starter-tomcat |
2、启动过程
SpringApplication.run为springboot项目的启动入口。
- @Import(AutoConfigurationPackages.Registrar.class)导入组件:
扫描主配置类所在包及其子包下的所有组件。 - @Import(AutoConfigurationImportSelector.class)
加载该配置文件中配置的自动配置类:META-INF/spring.factories - 配置的自动配置类不一定全部生效,类上有一个注解控制是否生效:@ConditionalOnXXX
- @ConditionalOnBean
- @ConditionalOnClass
- @ConditionalOnMissingBean
- @ConditionalOnMissingClass
3、通过yaml文件注入
- yaml文件注入属性,相当于@Value
- 名字必须为application.yaml
代码示例:
application.yaml
person:
name: zmy${random.uuid}
age: 3
lists:
- a
- b
- c
maps:
1: a
2: b
3: c
dog:
name: ${person.name:default}_旺财1号
age: 10
package com.zmy.pojo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
//使用@ConfigurationProperties指定yaml文件中的位置,即为yaml中配置的person
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private int age;
private List<String> lists;
private Map<String,Object> maps;
private Dog dog;
public Person() {
}
public Person(String name, int age, List<String> lists, Map<String, Object> maps, Dog dog) {
this.name = name;
this.age = age;
this.lists = lists;
this.maps = maps;
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getLists() {
return lists;
}
public void setLists(List<String> lists) {
this.lists = lists;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", lists=" + lists +
", maps=" + maps +
", dog=" + dog +
'}';
}
}
4、日志框架
SLF4J(日志门面) + logback(日志实现)
SLF4J的使用
@Test
void testLog(){
Logger logger = LoggerFactory.getLogger(Person.class);
logger.warn("warn......");
}
SLF4J使用不同的实现类
SLF4J统一各个日志框架
- 1.去掉系统中的其他日志框架
- 2.使用中间包替换
- 3.导入slf4j的实现
4.1、使用默认配置
SpringBoot默认配置好了日志框架
我们可以使用配置文件application.properties/application.yml来修改日志相关配置
- 设置日志输出位置:
logging.file.name | logging.file.path | Example | Description |
---|---|---|---|
(none) | (none) | 仅在控制台输出 | |
Specific file | (none) | my.log | Writes to the specified log file. Names can be an exact location or relative to the current directory. |
(none) | Specific directory | /var/log | Writes spring.log to the specified directory. Names can be an exact location or relative to the current directory. |
- 可配置内容:
属性 | 解释 |
---|---|
logging.config= | 日志配置文件的位置。例如,classpath:logback.xml 。 |
logging.exception-conversion-word=%wEx | 转换异常时使用的转换字。 |
logging.file= | 设置保存日志的日志文件 |
logging.file.max-history=0 | are neat |
logging.file.max-size=10MB | 设置日志文件最大大小 |
logging.level.*= | 设置日志等级 |
logging.path= | 日志文件的位置,例如/var/log |
logging.pattern.console= | 定义打印的日志格式 |
logging.pattern.dateformat=yyyy-MM-dd HH:mm:ss.SSS | 设置日志日期格式 |
logging.pattern.file= | 定义输出到日志文件的日志格式 |
logging.register-shutdown-hook=false | 当初始化日志系统时,为其注册一个关闭钩子。 |
# 日志文件格式
%d:表示日期时间
%thread:表示线程名
%‐5level:级别从左显示5个字符宽度
%logger{50}:表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息
%n:是换行符
%d{yyyy‐MM‐dd HH:mm:ss.SSS} [%thread] %‐5level %logger{50} ‐ %msg%n
日志文件配置示例
# 设置日志等级
logging.level.com.fjut.*=trace
# 设置在控制台输出的日志的格式
logging.pattern.console=[%d{yyyy‐MM‐dd}]-[%level]-[%msg]-%logger{50}%n
# 指定文件中日志输出的格式
logging.pattern.file=%d{yyyy‐MM‐dd} === [%thread] === %level === %logger{50} ==== %msg%n
# 设置输出日志文件
logging.file=/my.log
4.2、自定义配置文件
- 自定义日志框架的配置文件:
Logging System | Customization |
---|---|
Logback | logback-spring.xml , logback-spring.groovy , logback.xml , or logback.groovy |
Log4j2 | log4j2-spring.xml or log4j2.xml |
JDK (Java Util Logging) | logging.properties |
- logback.xml与logback-spring.xml的区别:
logback.xml会直接被日志框架识别使用
logback-spring.xml会先经过springboot解析处理,之后才会被日志框架使用,可以使用SpringBoot的高级Profile功能
logback和logback-spring.xml都可以用来配置logback,但是2者的加载顺序是不一样的。
logback.xml—>application.properties—>logback-spring.xml.
logback.xml加载早于application.properties,所以如果你在logback.xml使用了变量时,而恰好这个变量是写在application.properties时,那么就会获取不到,只要改成logback-spring.xml就可以解决。
Profile功能:
<springProfile name="staging">
<!‐‐ configuration to be enabled when the "staging" profile is active ‐‐>
可以指定某段配置只在某个环境下生效
</springProfile>1234
application.properties
# 指定环境为dev
spring.profiles.active=dev
logback-spring.xml(模板)
<?xml version="1.0" encoding="UTF-8"?>
<configuration
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.padual.com/java/logback.xsd"
debug="false" scan="true" scanPeriod="30 second">
<property name="PROJECT" value="iorder" />
<property name="ROOT" value="logs/${PROJECT}/" />
<property name="FILESIZE" value="50MB" />
<property name="MAXHISTORY" value="100" />
<timestamp key="DATETIME" datePattern="yyyy-MM-dd HH:mm:ss" />
<!-- 控制台打印 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--使用SpringBoot profile功能-->
<springProfile name="dev">
<encoder charset="utf-8">
<pattern>[%-5level] === %d{${DATETIME}} [%thread] %logger{36} - %m%n
</pattern>
</encoder>
</springProfile>
</appender>
<!-- ERROR 输入到文件,按日期和文件大小 -->
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder charset="utf-8">
<pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} - %m%n
</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${ROOT}%d/error.%i.log</fileNamePattern>
<maxHistory>${MAXHISTORY}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${FILESIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<!-- WARN 输入到文件,按日期和文件大小 -->
<appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder charset="utf-8">
<pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} - %m%n
</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${ROOT}%d/warn.%i.log</fileNamePattern>
<maxHistory>${MAXHISTORY}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${FILESIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<!-- INFO 输入到文件,按日期和文件大小 -->
<appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder charset="utf-8">
<pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} - %m%n
</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${ROOT}%d/info.%i.log</fileNamePattern>
<maxHistory>${MAXHISTORY}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${FILESIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<!-- DEBUG 输入到文件,按日期和文件大小 -->
<appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder charset="utf-8">
<pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} - %m%n
</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${ROOT}%d/debug.%i.log</fileNamePattern>
<maxHistory>${MAXHISTORY}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${FILESIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<!-- TRACE 输入到文件,按日期和文件大小 -->
<appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder charset="utf-8">
<pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} - %m%n
</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>TRACE</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${ROOT}%d/trace.%i.log</fileNamePattern>
<maxHistory>${MAXHISTORY}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${FILESIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<!-- SQL相关日志输出-->
<logger name="org.apache.ibatis" level="INFO" additivity="false" />
<logger name="org.mybatis.spring" level="INFO" additivity="false" />
<logger name="com.github.miemiedev.mybatis.paginator" level="INFO" additivity="false" />
<!-- Logger 根目录 -->
<root level="DEBUG">
<appender-ref ref="STDOUT" />
<appender-ref ref="DEBUG" />
<appender-ref ref="ERROR" />
<appender-ref ref="WARN" />
<appender-ref ref="INFO" />
<appender-ref ref="TRACE" />
</root>
</configuration>
5、Web应用开发
步骤:
- 新建SprinBoot项目,选择需要的模块
- 在配置文件中编写少量所选模块需要的配置
- 开发业务
自动配置原理?
- XXXAutoConfiguration.java(DispatcherServletAutoConfiguration.java)文件为我们导入Bean
- @EnableConfigurationProperties(WebMvcProperties.class) 注解:
- 如果一个配置类只配置@ConfigurationProperties注解,而没有使用@Component,那么在IOC容器中是获取不到properties 配置文件转化的bean。说白了 @EnableConfigurationProperties 相当于把使用 @ConfigurationProperties 的类进行了一次注入。
5.1、SpringBoot静态资源访问
WebMvcAutoConfigration中自动配置如下
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
1、所有以"/webjars/**" ,以webjars开头的请求,如果没有controller处理,则到"classpath:/META-INF/resources/webjars/"这个位置寻找静态资源
2、所有以"/**"开头的请求,如果找不到controller处理,则到:
classpath:/META-INF/resources/", “classpath:/resources/”, “classpath:/static/”, “classpath:/public/”
下寻找静态资源
3、首页
index.html也放置在
classpath:/META-INF/resources/", “classpath:/resources/”, “classpath:/static/”, “classpath:/public/”
这四个路径下
4、可在application.properties配置静态资源文件夹
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
public void setStaticLocations(String[] staticLocations) {
this.staticLocations = appendSlashIfNecessary(staticLocations);
}
spring.resources.static-locations="classpath:/hello"
5.2、模板引擎
SpringBoot的模板引擎Thymeleaf
1、引入Thymeleaf的starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
版本对应
thymeleaf3 - layout2 thymeleaf2 - layout1
2、配置
@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";
页面放在classpath:/templates/
下面,后缀为html,会自动渲染
3、thymeleaf语法
- 导入命名空间,thymeleaf语法提示
<html xmlns:th="http://www.thymeleaf.org">
- 代码示例
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<body>
<div th:text="${msg}"></div>
</body>
</html>
-
语法
th:XX :替换原有XX属性
5.3、扩展SpringMVC功能
-
implements WebMvcConfigurer(官方推荐):对原有自动配置无影响
-
extends WebMvcConfigurationSupport:该方法必须重写所有方法,对原有的自动配置有影响。比如不实现视图解析器的功能,则静态资源你无法访问
代码示例:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//将/abcd请求映射到hello.html静态页面
registry.addViewController("/abcd").setViewName("hello.html");
}
}
原理:容器加载WebMvc的相关配置时,会将容器中所有的WebMvcConfigurer的实现类都找到形成一个列表,循环调用每一个实现类的每一个方法,这样我们添加在容器中的组件也就被扫描调用了。
关键点:
-
WebMvcAutoConfiguration.java:@Import(EnableWebMvcConfiguration.class)
-
EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration
-
DelegatingWebMvcConfiguration.java
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
this.configurers.addViewControllers(registry);
}
- WebMvcConfigurerComposite.java
private final List<WebMvcConfigurer> delegates = new ArrayList<>();
public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.delegates.addAll(configurers);
}
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addViewControllers(registry);
}
}
总结:SpringBoot中会有很多的XXXConfigurer,用来扩展XXX的配置。例如WebMvcConfigurer,用来扩展SpringMVC的配置。
5.4、修改SpringBoot的默认自动配置
-
对于只能有一个组件的类型,SpringBoot先扫描容器中是否有用户自定义的组件(@Bean、@Component。。。),如果有,就不加载默认的组件了。一般依赖@ConditionnalOnXXX实现
-
对于可有多个的类型,将用户自定义的和默认的组件组合起来。
5.5、国际化
参考:https://www.cnblogs.com/iceb/p/9225678.html
1、编写国际化配置文件
2、自定义LocaleResolver
- 实现LocaleResolver接口
- 注册到容器中
自定义MyLocaleResolver
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
String l = httpServletRequest.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 httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
将自定义的LocaleResolver注册
@Configration
public class MainConfig{
@Bean
public MyLocaleResolver myLocaleResolver(){
return new MyLocaleResolver();
}
}
原理(WebMvcAutoConfiguration.java):
@Bean
//当有自定义的LocaleResolver时,将使用自定义的LocaleResolver代替SpringBoot默认的LocaleResolver
@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;
}
5.6、登陆验证-拦截器
1、自定义拦截器
实现HandlerInterceptor接口
-
preHandle(),预处理回调方法,实现处理器的预处理,如:登录检查,都是在请求controller层之前执行,
-
postHandle(),后处理回调方法,实现处理器的后处理,但是要在渲染视图之前
-
afterCompletion(),整个请求处理完毕回调方法,要在整个视图渲染完毕后回调
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器拦截了:" + request.getRequestURI());
Object user = request.getSession().getAttribute("loginUser");
if(user == null){
request.setAttribute("msg","没有权限!未登录!");
request.getRequestDispatcher("login.html").forward(request,response);
return false;
}else{
return true;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
实现了WebMvcConfigurer的配置类,注册拦截器,实现组件扩展。
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
//这种方法无法在拦截器中注入mapper等资源
//比较倾向的解释为:注入为null的时候,是通过new的方式创建的拦截器,通过new出来的实例是没有交给spring进行管理的,没有被spring管理的实例,spring是无法自动注入bean的,所以为null。详见:https://blog.csdn.net/ycf921244819/article/details/91388440
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/login.html","/user/login","/favicon.ico","/error");
}
}
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
//推荐这种写法,可以注入mapper等资源
@Bean
public MyInterceptor myInterceptor(){
return new MyInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor()).addPathPatterns("/**").excludePathPatterns("/login.html","/user/login","/favicon.ico","/error");
}
}
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/login")
public String login(HttpServletRequest request,
@RequestParam("username")String username,
@RequestParam("password")String password,
Map<String,Object> map){
System.out.println("controller。。。");
if(username != null && password.equals("123456")){
request.getSession().setAttribute("loginUser",username);
return "main";
}else{
map.put("msg","用户名密码错误");
return "login";
}
}
}
5.7、ControllerAdvice处理异常
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/login")
public String login() throws Exception {
throw new Exception("测试异常");
}
}
@ControllerAdvice//使用@ControllerAdvice注解
public class MyControllerAdvice {
@ResponseBody//返回json字符串
@ExceptionHandler(Exception.class)//处理的异常类型,此处可以用自定义的异常
public Map<String,Object> exceptionHandler(Exception e){
Map<String,Object> map = new HashMap<String,Object>();
map.put("error",e.getMessage());
return map;
}
}
自定义异常类
public class CustomException extends RuntimeException {
private long code;
private String msg;
public CustomException(Long code, String msg){
this.code = code;
this.msg = msg;
}
public long getCode() {
return code;
}
public void setCode(long code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
5.8、自定义嵌入式web容器
在application.properties修改server有关配置
5.9、注册Spring三大组件
Filter
自定义Filter
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("MyFilter doFilter method...");
filterChain.doFilter(servletRequest,servletResponse);//继续向下执行,比如接下来的自定义servlet
}
}
注册Filter
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new MyFilter());
filterRegistrationBean.setUrlPatterns(Arrays.asList("/myservlet"));
return filterRegistrationBean;
}
Servlet
自定义Servlet
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("自定义Servlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注册Servlet
@Bean
public ServletRegistrationBean servletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new MyServlet(),"/myservlet");
return servletRegistrationBean;
}
Listener
自定义listener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("容器启动");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("容器关闭");
}
}
注册listener
@Bean
public ServletListenerRegistrationBean servletListenerRegistrationBean(){
ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean();
servletListenerRegistrationBean.setListener(new MyListener());
return servletListenerRegistrationBean;
}
5.10、切换其他servlet容器
springboot支持的容器:
tomcat
jetty 长连接
undertow 非阻塞,高并发
切换时,排除原有容器pon依赖,增加目标依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
6、SpringBoot与数据库访问
6.1、JDBC
1)、导入依赖
<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>
2)、配置数据源
数据源自动配置在这个包下:org.springframework.boot.autoconfigure.jdbc
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://119.29.228.75:3306/springboot
spring.datasource.username=root
spring.datasource.password=123456
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
自定义数据源的自动配置
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
@Bean
DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
}
3)、使用
@Autowired
private JdbcTemplate jdbcTemplate;
public List<Map<String, Object>> getUsers(){
List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from user");
return maps;
}
6.2、使用Druid数据源
1)、导入依赖
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2)、配置数据源type
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://119.29.228.75:3306/springboot
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=6000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
#配置一个连接在池中最小生存时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxOpenPreparedStatements=20
spring.datasource.filters=stat,wall,log4j
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
3)、java配置类(开启数据监控)
- StatViewServlet
- WebStatFilter
@Configuration
public class MainConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource dataSource(){
return new DruidDataSource();
}
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
Map<String,String> maps = new HashMap<String,String>();
maps.put("loginUsername","admin");
maps.put("loginPassword","123456");
maps.put("allow","");//默认允许所有人登录
servletRegistrationBean.setInitParameters(maps);
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
Map<String,String> maps = new HashMap<String,String>();
maps.put("exclusions","*.js,*.css,/druid/*");
filterRegistrationBean.setInitParameters(maps);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegistrationBean;
}
}
测试:
访问http://localhost:8080/druid
6.3、整合MyBatis
增加依赖:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
MyBatis包提供了@Mapper、@Select。。。注解等。
1)、绑定mybatis配置文件及mapper配置文件
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://119.29.228.75:3306/springboot
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=6000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
#配置一个连接在池中最小生存时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxOpenPreparedStatements=20
spring.datasource.filters=stat,wall,log4j
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
#绑定配置文件
mybatis.config-location=classpath:/mybatis/mybatis-config.xml
# mapper接口和配置文件的包名一致时,可以不配置该项
mybatis.mapper-locations=classpath:/mybatis/mapper/*.xml
2)、编写mybatis配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.zmy.pojo"/>
</typeAliases>
</configuration>
3)、编写mapper配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zmy.mapper.UserMapper">
<select id="getUserById" resultType="user">
select * from user where id = #{id}
</select>
</mapper>
4)、编写mapper接口
//使用mabatis提供的注解,表明这是一个Mapper类
@Mapper
public interface UserMapper {
public User getUserById(int id);
}