SpringBoot

SpringBoot

SpringBoot自动配置包:spring-boot-autoconfigure

1、启动器

  • Springboot将所有的场景,定义为一个个启动器。需要什么功能,就导入什么启动器
NameDescription
spring-boot-starterCore starter, including auto-configuration support, logging and YAML
spring-boot-starter-activemqStarter for JMS messaging using Apache ActiveMQ
spring-boot-starter-amqpStarter for using Spring AMQP and Rabbit MQ
spring-boot-starter-aopStarter for aspect-oriented programming with Spring AOP and AspectJ
spring-boot-starter-artemisStarter for JMS messaging using Apache Artemis
spring-boot-starter-batchStarter for using Spring Batch
spring-boot-starter-cacheStarter for using Spring Framework’s caching support
spring-boot-starter-data-cassandraStarter for using Cassandra distributed database and Spring Data Cassandra
spring-boot-starter-data-cassandra-reactiveStarter for using Cassandra distributed database and Spring Data Cassandra Reactive
spring-boot-starter-data-couchbaseStarter for using Couchbase document-oriented database and Spring Data Couchbase
spring-boot-starter-data-couchbase-reactiveStarter for using Couchbase document-oriented database and Spring Data Couchbase Reactive
spring-boot-starter-data-elasticsearchStarter for using Elasticsearch search and analytics engine and Spring Data Elasticsearch
spring-boot-starter-data-jdbcStarter for using Spring Data JDBC
spring-boot-starter-data-jpaStarter for using Spring Data JPA with Hibernate
spring-boot-starter-data-ldapStarter for using Spring Data LDAP
spring-boot-starter-data-mongodbStarter for using MongoDB document-oriented database and Spring Data MongoDB
spring-boot-starter-data-mongodb-reactiveStarter for using MongoDB document-oriented database and Spring Data MongoDB Reactive
spring-boot-starter-data-neo4jStarter for using Neo4j graph database and Spring Data Neo4j
spring-boot-starter-data-r2dbcStarter for using Spring Data R2DBC
spring-boot-starter-data-redisStarter for using Redis key-value data store with Spring Data Redis and the Lettuce client
spring-boot-starter-data-redis-reactiveStarter for using Redis key-value data store with Spring Data Redis reactive and the Lettuce client
spring-boot-starter-data-restStarter for exposing Spring Data repositories over REST using Spring Data REST
spring-boot-starter-data-solrStarter for using the Apache Solr search platform with Spring Data Solr
spring-boot-starter-freemarkerStarter for building MVC web applications using FreeMarker views
spring-boot-starter-groovy-templatesStarter for building MVC web applications using Groovy Templates views
spring-boot-starter-hateoasStarter for building hypermedia-based RESTful web application with Spring MVC and Spring HATEOAS
spring-boot-starter-integrationStarter for using Spring Integration
spring-boot-starter-jdbcStarter for using JDBC with the HikariCP connection pool
spring-boot-starter-jerseyStarter for building RESTful web applications using JAX-RS and Jersey. An alternative to spring-boot-starter-web
spring-boot-starter-jooqStarter for using jOOQ to access SQL databases. An alternative to spring-boot-starter-data-jpa or spring-boot-starter-jdbc
spring-boot-starter-jsonStarter for reading and writing json
spring-boot-starter-jta-atomikosStarter for JTA transactions using Atomikos
spring-boot-starter-jta-bitronixStarter for JTA transactions using Bitronix. Deprecated since 2.3.0
spring-boot-starter-mailStarter for using Java Mail and Spring Framework’s email sending support
spring-boot-starter-mustacheStarter for building web applications using Mustache views
spring-boot-starter-oauth2-clientStarter for using Spring Security’s OAuth2/OpenID Connect client features
spring-boot-starter-oauth2-resource-serverStarter for using Spring Security’s OAuth2 resource server features
spring-boot-starter-quartzStarter for using the Quartz scheduler
spring-boot-starter-rsocketStarter for building RSocket clients and servers
spring-boot-starter-securityStarter for using Spring Security
spring-boot-starter-testStarter for testing Spring Boot applications with libraries including JUnit, Hamcrest and Mockito
spring-boot-starter-thymeleafStarter for building MVC web applications using Thymeleaf views
spring-boot-starter-validationStarter for using Java Bean Validation with Hibernate Validator
spring-boot-starter-webStarter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container
spring-boot-starter-web-servicesStarter for using Spring Web Services
spring-boot-starter-webfluxStarter for building WebFlux applications using Spring Framework’s Reactive Web support
spring-boot-starter-websocketStarter for building WebSocket applications using Spring Framework’s WebSocket support
spring-boot-starter-actuatorStarter for using Spring Boot’s Actuator which provides production ready features to help you monitor and manage your application
spring-boot-starter-jettyStarter for using Jetty as the embedded servlet container. An alternative to spring-boot-starter-tomcat
spring-boot-starter-log4j2Starter for using Log4j2 for logging. An alternative to spring-boot-starter-logging
spring-boot-starter-loggingStarter for logging using Logback. Default logging starter
spring-boot-starter-reactor-nettyStarter for using Reactor Netty as the embedded reactive HTTP server.
spring-boot-starter-tomcatStarter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web
spring-boot-starter-undertowStarter 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.namelogging.file.pathExampleDescription
(none)(none)仅在控制台输出
Specific file(none)my.logWrites to the specified log file. Names can be an exact location or relative to the current directory.
(none)Specific directory/var/logWrites 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=0are 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 SystemCustomization
Logbacklogback-spring.xml, logback-spring.groovy, logback.xml, or logback.groovy
Log4j2log4j2-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);

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值