spring boot 总结

1.0 spring boot是做到如何简化配置的

  我们来看下启动类,发现特别的地方有两个

    - 注解:@SpringBootApplication
    - run方法:SpringApplication.run()

  1.1 @SpringBootApplication分析

    点进去查看源码,发现注解上还有三个注解@SpringBootConfiguration@EnableAutoConfiguration、@ComponentScan

    1.1.1 @SpringBootConfiguration分析

      点进去查看源码,在这个注解上面,又有一个@Configuration注解,这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了`@Configuration`的类,并且读取其中的配置信息。而`@SpringBootConfiguration`是来声明当前类是SpringBoot应用的配置类,项目中只能有一个

    1.1.2 @EnableAutoConfiguration分析

      点进去查看源码,注释上面写道此注解可以开启spring boot自动配置,简单来讲作用就是根据引用的jar包猜测你想要做什么,然后自动帮你配置

    1.1.3 @ComponentScan分析

      点进去查看源码,注释上面写道,此注解可以开启包扫描

  1.2 SpringApplication.run()分析

    return new SpringApplication(primarySources).run(args);   
      this(null, primarySources); 
        deduceFromClasspath()判断当前应用类型
          如果是 WEBFLUX_INDICATOR_CLASS,则为spring5里面的新的react响应式编程
          如果不包含任何一个"javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext"
          否则项目是web工程     
        getSpringFactoriesInstances()加载初始化工厂类
          loadFactoryNames,从 FACTORIES_RESOURCE_LOCATION,即META-INF/spring.factories中读取需要初始化的类,他在spring boot
autoconfigure jar包中,通过这个加载了自动配置包中的大部分自动配置类,配置类是否生效呢,在类名称上面有条件判断注解,以WebMvcAutoConfiguration类为例
      - `@ConditionalOnWebApplication(type = Type.SERVLET)`
          ConditionalOn,翻译就是在某个条件下,此处就是满足项目的类是是Type.SERVLET类型,也就是一个普通web工程,显然我们就是
      - `@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })`
          这里的条件是OnClass,也就是满足以下类存在:Servlet、DispatcherServlet、WebMvcConfigurer,其中Servlet只要引入了tomcat依赖自然会有,后两个需要引入SpringMVC才会有。这里就是判断你是否引入了相关依赖,引入依赖后该条件成立,当前类的配置才会生效!
      - `@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)`
          这个条件与上面不同,OnMissingBean,是说环境中没有指定的Bean这个才生效。其实这就是自定义配置的入口,也就是说, 如果我们自己配置了一个WebMVCConfigurationSupport的类,那么这个默认配置就会失效!

 

2.0 spring boot 如何修改默认配置

  2.1 简单默认配置

    如果我们要覆盖这些默认属性,只需要在application.properties中定义与其前缀prefix和字段名一致的属性即可

    例如修改静态资源加载位置

    spring.resources.static-locations = classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${file.uploadPath}

  2.2 其它复杂配置

    例如配置拦截器

    拦截器不是一个普通属性,而是一个类,所以就要用到java配置方式了。在SpringBoot官方文档中有这么一段说明:

      > If you want to keep Spring Boot MVC features and you want to add additional [MVC configuration](https://docs.spring.io/spring/docs/5.0.5.RELEASE/spring-framework-reference/web.html#mvc) (interceptors, formatters, view controllers, and other features), you can add your own `@Configuration` class of type `WebMvcConfigurer` but **without** `@EnableWebMvc`. If you wish to provide custom instances of `RequestMappingHandlerMapping`, `RequestMappingHandlerAdapter`, or `ExceptionHandlerExceptionResolver`, you can declare a `WebMvcRegistrationsAdapter` instance to provide such components.
      > If you want to take complete control of Spring MVC, you can add your own `@Configuration` annotated with `@EnableWebMvc`. 

    翻译:
    > 如果你想要保持Spring Boot 的一些默认MVC特征,同时又想自定义一些MVC配置(包括:拦截器,格式化器, 视图控制器、消息转换器 等等),你应该让一个类实现`WebMvcConfigurer`,并且添加`@Configuration`注解,但是** 千万不要**加` @EnableWebMvc`注解。如果你想要自定义`HandlerMapping`、`HandlerAdapter`、`ExceptionResolver`等组件,你可以创建一个`WebMvcRegistrationsAdapter`实例 来提供以上组件。

    > 如果你想要完全自定义SpringMVC,不保留SpringBoot提供的一切特征,你可以自己定义类并且添加`@Configuration`注解和`@EnableWebMvc`注解

 

public class LoginInterceptor implements HandlerInterceptor {

    private Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        logger.debug("preHandle method is now running!");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        logger.debug("postHandle method is now running!");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        logger.debug("afterCompletion method is now running!");
    }
}

  

@Configuration
public class MvcConfig implements WebMvcConfigurer{
    /**
     * 通过@Bean注解,将我们定义的拦截器注册到Spring容器
     * @return
     */
    @Bean
    public LoginInterceptor loginInterceptor(){
        return new LoginInterceptor();
    }

    /**
     * 重写接口中的addInterceptors方法,添加自定义拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 通过registry来注册拦截器,通过addPathPatterns来添加拦截路径
        registry.addInterceptor(this.loginInterceptor()).addPathPatterns("/**");
    }
}

  数据库连接池配置

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
    </dependency>

  引入jdbc启动器的时候SpringBoot已经自动帮我们引入了一个连接池HikariCP应该是目前速度最快的连接池了

  # 连接四大参数
    spring.datasource.url=jdbc:mysql://localhost:3306/springboot
    spring.datasource.username=root
    spring.datasource.password=123
    # 可省略,SpringBoot自动推断
    spring.datasource.driverClassName= com.mysql.jdbc.Driver    com.mysql.cj.jdbc.Driver
    spring.datasource.hikari.idle-timeout=60000
    spring.datasource.hikari.maximum-pool-size=30
    spring.datasource.hikari.minimum-idle=10
   如果你更喜欢Druid连接池,也可以使用Druid官方提供的启动器

  <!-- Druid连接池 -->
  <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid-spring-boot-starter</artifactId>
      <version>1.1.6</version>
  </dependency>
 

   连接信息的配置与上面是类似的,只不过在连接池特有属性上,方式略有不同
 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
  #初始化连接数
  spring.datasource.druid.initial-size=1
  #最小空闲连接
  spring.datasource.druid.min-idle=1
  #最大活动连接
  spring.datasource.druid.max-active=20
  #获取连接时测试是否可用
  spring.datasource.druid.test-on-borrow=true
  #监控页面启动
  spring.datasource.druid.stat-view-servlet.allow=true

  spring 2.0之前数据库连接池的默认初始化方式

  检查tomcat的数据库连接池实现是否可用,如可用,则启用。使用spring.datasource.tomcat.*可以控制连接池的行为。
  检查hikari是否可用,如可用,则启用。使用spring.datasource.hikari.*可以控制连接池的行为。
  检查dbcp是否可用,如可用,则启用;该连接池被Spring Boot标记为deprecated,不建议在生产环境使用该连接池的实现。
  检查dbcp2是否可用,如可用,则启用。使用spring.datasource.dbcp2.*可以控制连接池的行为。

  spring 2.0之后数据库连接池的默认初始化方式

  检查hikari是否可用,如可用,则启用。使用spring.datasource.hikari.*可以控制连接池的行为。
  检查tomcat的数据库连接池实现是否可用,如可用,则启用。使用spring.datasource.tomcat.*可以控制连接池的行为。
  检查dbcp2是否可用,如可用,则启用。使用spring.datasource.dbcp2.*可以控制连接池的行为。

  使用时最好指定数据源格式,防止默认数据源的变动带来的不确定

  整合mybatis

    SpringBoot官方并没有提供Mybatis的启动器,不过Mybatis[官网](https://github.com/mybatis/spring-boot-starter)自己实现了

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.3.2</version>
    </dependency>

    # mybatis 别名扫描
    mybatis.type-aliases-package=com.study.pojo
    # mapper.xml文件位置,如果没有映射文件,请注释掉
    mybatis.mapper-locations=classpath:mappers/*.xml

  需要注意,这里没有配置mapper接口扫描包,因此我们需要给每一个Mapper接口添加`@Mapper`注解,才能被识别。

  整合通用mapper

    通用Mapper的作者也为自己的插件编写了启动器,我们直接引入即可,里面包含了mybatis依赖,jdbc依赖

    <!-- 通用mapper -->
    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper-spring-boot-starter</artifactId>
        <version>2.0.2</version>
    </dependency>

  @Mapper
  public interface UserMapper extends tk.mybatis.mapper.common.Mapper<User>{
  }

  如果你使用的是包扫描而不是@Mapper注解,那你的包扫描应该是这个@tk.mybatis.spring.annotation.MapperScan(basePackages = "扫描包")

  注意:

  1、表名默认使用类名,驼峰转下划线(只对大写字母进行处理),如UserInfo默认对应的表名为user_info。

  2、表名可以使用@Table(name = "tableName")进行指定,对不符合第一条默认规则的可以通过这种方式指定表名.

  3、字段默认和@Column一样,都会作为表字段,表字段默认为Java对象的Field名字驼峰转下划线形式.

  4、可以使用@Column(name = "fieldName")指定不符合第3条规则的字段名

  5、使用@Transient注解可以忽略字段,添加该注解的字段不会作为表字段使用.

  6、建议一定是有一个@Id注解作为主键的字段,可以有多个@Id注解的字段作为联合主键

  详解:

    https://www.cnblogs.com/lichangyun/p/8530975.html

    https://www.cnblogs.com/kitor/p/11009434.html

    http://www.mybatis.tk/

    https://github.com/abel533

  整合thymeleaf

  模板默认放在classpath下的templates文件夹,我们新建一个html文件放入其中:
 
  编写html模板,渲染模型中的数据:
  注意,把html 的名称空间,改成:`xmlns:th="http://www.thymeleaf.org"` 会有语法提示
  ```html
  <!DOCTYPE html>
  <html xmlns:th="http://www.thymeleaf.org">
   <head>
      <meta charset="UTF-8">
      <title>首页</title>
      <style type="text/css">
          table {border-collapse: collapse; font-size: 14px; width: 80%; margin: auto}
          table, th, td {border: 1px solid darkslategray;padding: 10px}
      </style>
  </head>
  <body>
  <div style="text-align: center">
      <span style="color: darkslategray; font-size: 30px">欢迎光临!</span>
      <hr/>
    <table class="list">
        <tr>
            <th>id</th>
            <th>姓名</th>
            <th>用户名</th>
            <th>年龄</th>
            <th>性别</th>
            <th>生日</th>
            <th>备注</th>
        </tr>
        <tr th:each="user : ${users}">
            <td th:text="${user.id}">1</td>
            <td th:text="${user.name}">张三</td>
            <td th:text="${user.userName}">zhangsan</td>
            <td th:text="${user.age}">20</td>
            <td th:text="${user.sex} == 1 ? '男': '女'">男</td>
            <td th:text="${#dates.format(user.birthday, 'yyyy-MM-dd')}">1980-02-30</td>
            <td th:text="${user.note}">1</td>
        </tr>
    </table>
</div>
</body>
</html>
```
我们看到这里使用了以下语法:
- `${}` :这个类似与el表达式,但其实是ognl的语法,比el表达式更加强大
- `th-`指令:`th-`是利用了Html5中的自定义属性来实现的。如果不支持H5,可以用`data-th-`来代替
  - `th:each`:类似于`c:foreach`  遍历集合,但是语法更加简洁
  - `th:text`:声明标签中的文本
    - 例如`<td th-text='${user.id}'>1</td>`,如果user.id有值,会覆盖默认的1
    - 如果没有值,则会显示td中默认的1。这正是thymeleaf能够动静结合的原因,模板解析失败不影响页面的显示效果,因为会显示默认值!
 
 

猜你喜欢

转载自www.cnblogs.com/helloworldmybokeyuan/p/11625205.html