感谢支持
我们一直在努力

Spring Boot 实践心得笔记

开始前…

最近闲下来,看了些spring Boot和Docker的相关资料,说实话,Spring Boot官网的demo和文档写得真是”简洁”,看起好像是那么回事,挺好懂的,但自己实践后才知道是坑坑不少,而且boot的文档较少,相比而言,docker的文档一搜一大把,系列里不会过多的介绍docker,主要是穿插着使用。于是,想着写个简单的Spring Boot学习与使用系列,以Spring Boot为切入点,总结下折腾Spring Boot和docker的结果。

Spring Boot项目的目的就是为了简化常用的配置,提升效率,而提出的一种新的解决思路,让笨重的Java,也可以像js和Python一样,快速的应用部署。快速、快速、还是快速。

系列开篇,想着直接开始工程搭建上代码吧,怕太枯燥了,所以,写了以上这些废话,接下来开始,实际操作。

本系列相关DEMO下载到Linux公社资源站下载:

——————————————分割线——————————————

免费下载地址在 http://linux.linuxidc.com/

用户名与密码都是www.linuxidc.com

具体下载目录在 /2017年资料/1月/15日/Spring Boot 实践心得笔记/

下载方法见 http://www.linuxidc.com/Linux/2013-07/87684.htm

——————————————分割线——————————————

Spring Boot有哪些核心功能

  1. 基于Spring框架的独立运行的项目
  2. 内嵌Servlet容器
  3. 提供starter简化Maven配置
  4. 自动配置Spring
  5. 无xml配置和简化代码配置

Spring Boot版本

1.3.5.RELEASE   

使用的是最新的稳定发布版。

IDE

IntelliJ IDEA 15.0.5

推荐使用idea,如果喜欢用eclipse的,示例并不影响,只是可能需要自行配置一些环境设置。

构建Maven项目

虽说可以使用idea建立spring boot项目,但为了方便还是使用maven来建工程。

建立父项目

为了后续多个demo演示方便,这里建立一个多个子项目的maven父工程,并引入一次boot-starter-web,这样后续子项目中不需要再添加boot-starter-web依赖。

//pom.xml

<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
    <module>boot-start</module>
</modules>

<properties>
    <spring.boot.version>1.3.5.RELEASE</spring.boot.version
</properties>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>${spring.boot.version}</version>
</dependency>

这里先不添加编译插件,后续在不同的应用模块里再分别添加。

建立子项目

包名:com.hjf.boot.demo.boot_start

在pom.xml中增加编译项

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring.boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

Hello World

com.hjf.boot.demo.boot_start.StartApp.Class

为了自动配置的方便,按照Spring Boot约定规则,在最外层的目录添加启动类StartApp

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by hjf on 2016/6/7.
 * com.hjf.boot.demo.boot_start
 */
@EnableAutoConfiguration  //1
@ComponentScan  //2
@RestController //3
public class StartApp {
    public static void main(String[] args) {
        SpringApplication.run(StartApp.class,args); //4
    }

    @RequestMapping("/hello")  //5
    public String hello(){
        return "Hello world!";
    }
}

说明:
1:开启自动配置
2:开启bean扫描
3:spring mvc的rest控制器方法
4:boot启动的核心方法,使用SpringApplication对象
5:提供一个访问接口”/hello”,来展示数据。

启动

点击Run –> Edit Configuration,编辑Spring Boot启动参数,如下图:

这里写图片描述

启动应用,查看控制台打印,默认端口是8080

这里写图片描述
这里写图片描述

访问:http://localhost:8080/hello 查看数据
这里写图片描述
到此,本章内容结束。

小结

本章只是引入Spring Boot一个最简单的例子,说明Spring Boot启动的快速,不需要配置文件,不需要按安装tomcat,只需要一个class文件,即可启动基于Spring MVC的应用。

更多详情见请继续阅读下一页的精彩内容: http://www.linuxidc.com/Linux/2017-01/139576p2.htm

开始前…

这章的主题是切入点,找到一个点我们慢慢展开,逐渐深入,没有一上来就讲新的东西的原因是:过去的使用经验同样重要,正是因为有了过去的经验,才会有更新更好的思路出现,新思路帮助我们改进提高。同样有了对比,才能更直观的感受到新的方案是否更快速,是否更好,哪些优缺点有明显的变化。简单不代表容易,只有动手实践,才能真正理解。

所以,这章内容是复习一下如何使用spring MVC搭建一个常用的基于maven的web项目,并最终集成Mybatis使用MySQL数据库显示数据,而mysql,我采用Docker镜像安装,不使用直接安装方式。

Windows
使用boot2docker,下载地址,版本:1.8.0(这个版本为最后版本,该项目后续就迁移到Docker ToolBox了,toolbox我下载了最新的1.11.2尝试,但是就是启动不了虚拟机,暂时不管,并不影响使用)

Linux
直接安装docker使用,详细可见:Ubuntu 16.04安装使用Docker  http://www.linuxidc.com/Linux/2017-01/139573.htm

环境版本

jdk : 1.7.80 //第一章忘记写了,后续统一使用这个jdk版本
tomcat : 6.0.33 //因为父项目里有8.0.33的内嵌版本,用7.0.x版本启动似时校验jar包会报错,或者用8.0.33也可以
mysql : 5.5.45 
Spring MVC : 4.2.6.RELEASE
MyBatis : 3.2.5
mybatis-spring : 1.2.2
tomcat-jdbc : 7.0.52
mysql-connector-Java : 5.1.39

docker运行mysql

docker pull mysql:5.5.45
docker run -d -p 3306:3306 mysql:5.5.45 -e MYSQL_ROOT_PASSWORD=123456

建立maven项目

包名: com.hjf.boot.demo.boot_mybatis_mvc

新增pom.xml

    <packaging>war</packaging>

    <properties>
        <jdbc.driver.version>5.1.39</jdbc.driver.version>
        <tomcat-jdbc.version>7.0.52</tomcat-jdbc.version>
        <mybatis.version>3.2.5</mybatis.version>
        <mybatis-spring.version>1.2.2</mybatis-spring.version>
    </properties>

    <dependencies>
         <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>
        <!-- mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>${mybatis-spring.version}</version>
        </dependency>
         <!-- connection pool -->
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jdbc</artifactId>
            <version>${tomcat-jdbc.version}</version>
            <scope>runtime</scope>
        </dependency>

        <!-- jdbc driver -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${jdbc.driver.version}</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
        <plugins>
            <!-- compiler插件, 设定JDK版本 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <showWarnings>true</showWarnings>
                </configuration>
            </plugin>

            <!-- war打包插件, 设定war包名称不带版本号 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <warName>mickjoust</warName>
                </configuration>
            </plugin>
        </plugins>
        </pluginManagement>
    </build>

变更为web项目

添加Web支持

首先在src/main/下新建webapp文件夹
idea中然后点击File–>Project Structure–>Modules—>boot-mybatis-mvc增加web项目支持,如图:

这里写图片描述

添加Spring上下文支持

在src/main/resources下新增applicationContext.xml和application.properties文件,并在WEB-INF/下增加spring-mvc.xml的mvc severlet配置文件

// applicationContext.xml

<!-- 使用annotation自动注册bean-->
    <context:component-scan base-package="com.hjf.boot.demo.boot_mybatis_mvc">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>
    <!--<aop:aspectj-autoproxy proxy-target-class="true" />-->

    <!-- 配置读取properties属性文件 -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="fileEncoding" value="UTF-8" />
        <property name="ignoreUnresolvablePlaceholders" value="true" />
        <property name="locations">
            <list>
                <value>classpath:/config/app.properties</value>
            </list>
        </property>
    </bean>

    <!-- 分开标示特定的bean  -->
    <import resource="classpath:/spring/app-config.xml" />

    <!-- MyBatis配置 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
        <property name="typeAliasesPackage" value="com.hjf.boot.demo.boot_mybatis_mvc.domain" />
        <!-- 显式指定Mapper文件位置 -->
        <property name="mapperLocations" value="classpath:/mybatis/*Mapper.xml" />
    </bean>
    <!-- 扫描basePackage下所有定义为 @Mapper 的接口-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.hjf.boot.demo.boot_mybatis_mvc" />
        <property name="annotationClass" value="com.hjf.boot.demo.boot_mybatis_mvc.dao.Mapper"/>
    </bean>

//profile配置较多,此处省略...
// application.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
jdbc.username=test
jdbc.password=123456
jdbc.pool.maxIdle=2
jdbc.pool.maxActive=5
// spring-mvc.xml

<!-- aop动态代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true" />

    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <!-- 将StringHttpMessageConverter的默认编码设为UTF-8 -->
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <constructor-arg value="UTF-8" />
            </bean>
             <!--将Jackson2HttpMessageConverter的默认格式化输出设为true -->
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="prettyPrint" value="true"/>
            </bean>

        </mvc:message-converters>
    </mvc:annotation-driven>

    <!-- Velocity配置 -->
    <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
        <property name="resourceLoaderPath" value="/WEB-INF/views/" />
        <property name="velocityProperties">
            <props>
                <prop key="input.encoding">UTF-8</prop>
                <prop key="output.encoding">UTF-8</prop>
                <prop key="contentType">text/html;charset=UTF-8</prop>
            </props>
        </property>
    </bean>

    <!-- Velocity视图解析器 -->
    <bean id="velocityViewResolver" class="org.springframework.web.servlet.view.velocity.VelocityLayoutViewResolver">
        <property name="contentType" value="text/html;charset=UTF-8" />
        <property name="prefix" value="" />
        <property name="suffix" value=".vm" />
        <property name="order" value="0" />
        <property name="dateToolAttribute" value="dateTool" />
        <property name="numberToolAttribute" value="numberTool" />
        <property name="requestContextAttribute" value="rc" />
        <property name="exposeRequestAttributes" value="true" />
        <property name="exposeSpringMacroHelpers" value="true" />
        <!--<property name="layoutUrl" value="/page/index.vm" />-->
    </bean>

    <!-- 容器默认的DefaultServletHandler,处理所有静态内容与无RequestMapping处理的URL-->   
    <mvc:default-servlet-handler />

    <!-- 静态资源配置 -->
    <mvc:resources location="/static/" mapping="/static/**" cache-period="864000" />

    <!-- bean -->
    <bean id="loginInterceptor" class="com.hjf.boot.demo.boot_mybatis_mvc.interceptor.LoginInterceptor" />

    <!-- 拦截器配置 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <mvc:exclude-mapping path="/favicon.ico" />
            <mvc:exclude-mapping path="/WEB-INF/views/error/**" />
            <ref bean="loginInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>

同样点击File–>Project Structure–>Modules—>boot-mybatis-mvc增加spring支持,如图:

这里写图片描述

添加完spring支持后,velocity的配置使用,这里不做过多解释了,后续在单页应用实战中里专门说明。本文的重点还是,spring mvc和mybatis的配置。

建立静态文件夹

在src/main/webapp/WEB-INF/下新建静态文件夹static,拷贝bootstrap和jQuery文件夹(本章只是导入静态文件夹,演示静态路径的配置,后续会对静态文件配置和视图层解析专门做boot的对比)

测试model

public class Info {

    private Long id;
    private String name;
    private Integer age;

    //省略get、set方法
}

自定义注解@Mapper

@Mapper这个注解是从Mybatis的3.4.0开始的,但在之前的版本里,我们如果要使用注解来注入mybatis的接口,要吗在config文件里自定义每个mapper,要吗就要自定义一个注解,并手动注入到mybatis里去:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Component
public @interface Mapper {
    String value() default "";
}

mybatis dao

@Mapper
public interface ShowDao {

    List<Info> findByAge(Integer age);
}

xml mapper

使用xml的方式,在src/main/resources/下新建mybatis/ShowDaoMapper.xml文件

<!-- namespace必须指向Dao接口 -->
<mapper namespace="com.hjf.boot.demo.boot_mybatis_mvc.dao.ShowDao">

    <select id="findByAge" parameterType="int" resultType="Info">
        SELECT
        id,
        name,
        age
        FROM info
        WHERE age = #{age}
    </select>

</mapper>

使用sql插入数据

使用如下sql语句在mysql里建库:test,然后插入测试数据。

CREATE TABLE `info` (
`id`  bigint NOT NULL AUTO_INCREMENT ,
`name`  varchar(255) NULL ,
`age`  int NULL ,
PRIMARY KEY (`id`)
);

INSERT INTO info (name,age) VALUES ('mick','20');
INSERT INTO info (name,age) VALUES ('mick1','20');
INSERT INTO info (name,age) VALUES ('mickjoust1','21');
INSERT INTO info (name,age) VALUES ('joust','22');

启动

查看主页:http://localhost:8080
查看数据库数据:http://localhost:8080/show

小结

本章篇幅配置的东西比较多,文中省略了部分代码,详细代码可在示例中查看。今天配置spring mvc 还是觉得很费事啊,各种配置,各种关联,但,切入点是很有必要的,后续大家用过spring boot后才能知道简化的优势和好处。本章关键点有:自定义注解(其实mybatis 3.4.0后,不需要自己写了,官方已经写了一个了)、spring mvc的servlet配置,spring context的配置,spring mvc的maven依赖,总结发现搭建一个项目,如果不熟悉的话,还是会花费很多时间的,就算有现成,建议大家多动手,自己操作,就会体会个中滋味。本章就此结束,至于什么原理架构,我个人更喜欢最后再去深入探讨,前面章节都会是实战,先行动着再说。

你要搞清楚自己人生的剧本:不是你父母的续集,不是你子女的前传,更不是你朋友的外篇。对待生命你不妨大胆冒险一点,因为好歹你要失去它。——源自尼采

开始前…

上面的金句是被转载很多的一句话,spring Boot也有自己的舞台,只是这个舞台还没有大量展开。今天接着上一篇的内容开始正式的切入到Spring Boot,按照从Spring mvc里的xml配置导入使用到class类配置,最后使用starter的方法来实战,到最后,大家就能看到是怎么过渡到的了,还能体会到最后那快速的畅快感。

实战

1、建立启动类

建包: com.hjf.boot.demo.boot_mybatis

首先建立StartApp启动程序类

// StartApp.class

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication //1
public class StartApp {
    public static void main(String[] args) {
        SpringApplication.run(StartApp.class,args);
    }
}

说明:
1:用这个注解,就能实现自动扫描包和自动配置默认配置的功能,它包含了@ComponentScan和@EnableAutoConfiguration这两个注解,同时这个类自身也是一个配置类@Configuration,可以直接在这个类里添加@Bean来注入Java bean,第一章用的注解组合实现的和这个注解功能是一致的,这也是Spring Boot官方推荐的配置方式,是不是觉得很简单,以前需要在xml里写自动扫描的bean,现在只需要一个注解就搞定,快速、快速、快速,重要的原则说三遍,这也是Spring Boot的目标。

2、建立演示用服务类

我们使用现在基本通用的设计模式来设计类,包含controller(我更喜欢叫api),dao,domain,service,每一个都只有一个类。

模型类:domain—>TestPOJO.class

public class TestPOJO {
    private Long id;
    private String name;
    private int age;

   //省略 get、set
}

服务类:service—>TestServices.class

import com.hjf.boot.demo.boot_mybatis.dao.TestDao;
import com.hjf.boot.demo.boot_mybatis.domain.TestPOJO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TestServices { //1

    @Autowired
    private TestDao testDao; 


    public String show(){
        return "hello world!";
    }

    public List<TestPOJO> showDao(int age){
        return testDao.get(age);
    }
}

说明:
1:这里提供两个方法,一个只是简单返回字符串,另个从MySQL数据库里去取出数据显示。

接口控制器类:api—>TestController.class

import com.hjf.boot.demo.boot_mybatis.services.TestServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController //1
public class TestController {

    @Autowired
    private TestServices testServices; //2

    @RequestMapping(value = "/show")  //3
    public String show(){
        return testServices.show();
    }

    @RequestMapping(value = "/showDao")  //4
    public Object showDao(int age){
        return testServices.showDao(age);
    }

}

说明:
1:使用这个方法代表rest风格的控制器,这个是Spring MVC的特性。主要是方便不写@ResponseBody;
2:注入服务方法;
3:调用普通服务接口方法;
4:调用查询数据库接口方法。

文件结构配置完后,接下来我们开始配置链接数据库的dao接口和配置,这里就会有三种方法:

三板斧

方法1:引用xml配置

在Spring Boot里其实是不推荐使用导入xml配置的,但不是说就不能导入xml,只能用starter,之前也看过有关的集成的文章,都是一笔带过,我还是那个感触,不能一篇文章就成功过的,反正我自己折腾了很久才成功。

第1步:添加pom依赖。这需要添加mybatis相关的驱动依赖和jdbc连接池的依赖。

第2步:建立文件applicationContext.xml。我们要在resources下新建applicationContext.xml并将上一章同名xml文件里的datasource和mybatis的配置放入这里(我们不用profile配置,直接使用datasource简单一点):

applicationContext.xml

<!-- 数据源配置, 使用Tomcat JDBC连接池 -->
    <bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
        <!-- Connection Info -->
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />

        <!-- Connection Pooling Info -->
        <property name="maxActive" value="10" />
        <property name="maxIdle" value="50" />
        <property name="minIdle" value="0" />
        <property name="defaultAutoCommit" value="false" />
    </bean>

    <!-- MyBatis配置 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
        <property name="typeAliasesPackage" value="com.hjf.boot.api.domain" />
        <!-- 显式指定Mapper文件位置 -->
        <property name="mapperLocations" value="classpath:/mybatis/*Mapper.xml" />
    </bean>
    <!-- 扫描basePackage下所有以@MyBatisRepository标识的 接口-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.hjf.boot.demo.boot_mybatis.domain" />
        <property name="annotationClass" value="com.hjf.boot.demo.boot_mybatis.dao.Mapper"/>
    </bean>

使用同样注入自定义@Mapper的方式来发现接口,并且使用xml的真实Mapper来执行sql,这里没有写propertites的读取,是因为Spring Boot会默认自动读取application.properties里的内容。

第3步:建立application.properties,并写入如下属性内容。

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF-8
jdbc.username=test
jdbc.password=123456
jdbc.pool.minIdle=0
jdbc.pool.maxIdle=10
jdbc.pool.maxActive=50

第4步:在dao文件夹下新建dao接口和@Mapper注解类。

TestDao.class

import com.hjf.boot.demo.boot_mybatis.domain.TestPOJO;

import java.util.List;

@Mapper
public interface TestDao {

    //根据age查找info
    List<TestPOJO> get(int age);

}

Mapper.class

import org.springframework.stereotype.Component;
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Component
public @interface Mapper {
    String value() default "";
}

TestDaoMapper.xml

<?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">

<!-- namespace必须指向Dao接口 -->
<mapper namespace="com.hjf.boot.demo.boot_mybatis.dao.TestDao">

    <!-- 所有列 -->
    <sql id="Column_list">
        id,
        name,
        age
    </sql>

    <resultMap id="ListTest" type="TestPOJO" >
        <id  column="id" property="id" />
        <result column="name" property="name" />
        <result column="age" property="age" />
    </resultMap>

    <!-- 根据ID查询数据 -->
    <select id="get" parameterType="int" resultMap="ListTest">
        SELECT
        <include refid="Column_list" />
        FROM info
        WHERE age = #{age}
    </select>

</mapper>

到此类已经建立完毕了,启动,然后报错!为什么呢?通过idea的上下文关联图可以看得比较明白:

这里写图片描述

这个图是生成的,其实用boot,可以不用在项目工程里加载spring的上下文的,这里是为了方便说明,我手动建立了spring的上下文,那什么启动会报错呢,这个跟Spring Boot的启动机制有关,boot在启动启动类以后,才会根据类文件间的依赖去加载spring的bean类,boot本身并不会自动去读取xml文件,所以boot是不知道我们在xml里注入的bean的,所以肯定找不到datasource和mybatis配置,所以,我们要在StartApp类里增加一个注解@@ImportResource,让boot主动加载我们的bean。

@ImportResource(locations = "classpath*:/applicationContext.xml")

这时启动还是会报错,因为boot本着自动配置的原则,会帮你去加载mybatias的自动配置类,但自动配置类又是用的包内自有的mapper,导致找不到包,这时我们排除一下自动配置:

@SpringBootApplication(exclude = MybatisAutoConfiguration.class)

启动,成功,测试数据成功。

这里写图片描述

方法2:使用class类配置

虽然我们能够使用导入xml的配置,但是还是显得有点麻烦,并且配置xml文件有一个很大的缺点:容易出现拼写错误。上一个例子中我自己写的类的位置很多时候检查不够充分,也因为写错两个字母,一直报类找不到,spring 从4.x开始推荐使用class配置的方式来配置bean,我刚开始其实还是挺不喜欢class的方式的,觉得,这就是写代码了配置了,有时想修改下配置变量也需要提交上线,岂不是太麻烦了。class有class的好处,保密性比配置文件好,但不如xml方便,具体使用看使用场景和个人习惯。我是觉得,小项目配置改动比较小的可以使用class方式,对于协作比较多的项目还是使用xml和配置的方式。接下来使用class的方法来配置dao。

第1步:建立配置类文件config。这里需要三个类文件:
DataSourceConfig —>datasource源配置
MyBatisConfig —> 配置sqlSessionFactory
MyBatisMapperScannerConfig —> 配置mapperScannerConfigurer
这里需要说明一下:最后一个配置因为依赖前两个,需要最后一个加载,否则会报错。

DataSourceConfig .class

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration //1
public class DataSourceConfig {

    @Bean //2
    public DataSource dataSource(){ //3
        DataSource dataSource = new DataSource(); 
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF-8");
        dataSource.setUsername("test");
        dataSource.setPassword("123456");
        return dataSource;
    }

}

说明:
1:代表此类为配置类;
2:代表需要注入的bean;
3:使用代码的方式传入值到对象。

MyBatisConfig .class

import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

@Configuration
public class MyBatisConfig implements TransactionManagementConfigurer {//1

    @Autowired //2
    DataSource dataSource;

    @Bean(name = "sqlSessionFactory")//3
    public SqlSessionFactory sqlSessionFactoryBean() {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setTypeAliasesPackage("com.hjf.boot.demo.boot_mybatis.domain");

        //分页插件 //4
//        PageHelper pageHelper = new PageHelper();
//        Properties properties = new Properties();
//        properties.setProperty("reasonable", "true");
//        properties.setProperty("supportMethodsArguments", "true");
//        properties.setProperty("returnPageInfo", "check");
//        properties.setProperty("params", "count=countSql");
//        pageHelper.setProperties(properties);
        //添加插件
//        bean.setPlugins(new Interceptor[]{pageHelper});

        //添加XML目录
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            bean.setMapperLocations(resolver.getResources("classpath:/mybatis/*Mapper.xml"));
            return bean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return new DataSourceTransactionManager(dataSource);
    }
}

说明:
1:实现TransactionManagementConfigurer接口,配置spring事务的管理;
2:注入datasource;
3:注入的名称指定,如果不指定,默认方法名为bean的名字,命名规则需要遵守spring命名规范;
4:跳过分页插件,需要使用的,自行去了解mybatis分页插件的内容。

MyBatisMapperScannerConfig

import com.hjf.boot.demo.boot_mybatis.dao.Mapper;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@AutoConfigureAfter(MyBatisConfig.class)//1
public class MyBatisMapperScannerConfig {

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("com.hjf.boot.demo.boot_mybatis");
        mapperScannerConfigurer.setAnnotationClass(Mapper.class);
        return mapperScannerConfigurer;
    }
}
说明:
1 : 让此类在上一个类加载完毕后再加载,代码都是xml内容的转化,比较简单。

现在,我们来看一下上下文的依赖变化成什么样了,如下图:

这里写图片描述

这个图很好的说明了boot在建立配置的方式,和xml是有一定区别的,所以才需要注意配置类的加载顺序。

到此,方法2建立dao完毕,我们注释掉方法1里的@ImportResource和application.properties里的所有内容,启动,成功!测试数据成功!

这里写图片描述

方法3:使用starter配置

终于来到最简单的方法了,能够自己实践,然后读到这里的同学,是不是感觉到,xml反而比class的方式还麻烦呢,讲了这么多,也没有觉得Spring Boot有多方便呢,但是在前两个方法的过渡中,很多配置其实是逐渐减少了,比如web.xml,spring-mvc的serverlet配置文件,读取properties,是不是没有配置了,虽然mvc里的配置更自由,但boot也是加载了默认配置,适用于大多数场景,并且它同样提供了强大的mvc的配置和自定义的配置,后续章节会涉及到。现在,我们继续建立dao。

第1步:引入mybatis的starter的包。 Spring Boot将封装的一系列支持boot的应用的工程都叫做starter,我们这里引入mybatis对boot的支持的starter。如果是同一个的pom,要注释掉mybatis的依赖,starter会自动引入依赖包。

pom.xml

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

第2步:配置properties。

spring.datasource.driver-class-name=com.mysql.jdbc.Driver //1
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=test
spring.datasource.password=123456
spring.datasource.max-active=10
spring.datasource.max-idle=5
spring.datasource.min-idle=0

mybatis.mapper-locations=classpath:/mybatis/*Mapper.xml //2
mybatis.type-aliases-package=com.hjf.boot.demo.boot_mybatis.domain

说明:
1: spring.开头的是spring boot自动配置的属性开头,后面我们会讨论怎么自定义自己类型安全的配置项。
2: 这是mybatis配置的自动配置的属性。

第3步,新建dao。

import com.hjf.boot.demo.boot_mybatis.domain.TestPOJO;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper  //1
public interface TestDao {

    //根据age查找info
    List<TestPOJO> get(int age);

}

说明:
1:这里的Mapper是Mybatis自己定义的注解。
到此,结束,启动,成功!测试成功!

这里写图片描述

小结

到此,本章内容结束了,到方法3的时候,会不会觉得,这么简单?就这么简单,快速配置,快速启动,你只需要关注你的核心业务。三种方法各有优缺点,适用的场景也不相同。
上面提到的要排除自动配置,其实是因为我的demo里的pom引入了mybatis的starter,细心的同学可能已经发现,可以不用加exclude。

生活不可能像你想象的那么好,但也不会像你想象的那么糟。我觉得人的脆弱和坚强都超乎自己的想象。有时,可能脆弱得一句话就泪流满面;有时,也发现自己咬着牙走了很长的路。——源自 莫泊桑

开始前…

本章内容主要介绍的是spring Boot常用的配置,相对前一篇来说,比较简单。“配置即使用“的意思就是,在工程里配置了自带的默认配置或自定义配置后,就能生效的一种功能,这也是Spring Boot推荐的一种做法。常用配置,就是一般用得最多的配置,大家默认推荐的配置。其实大家都知道官方有最标准的配置,但是有时就是不愿去看,反而喜欢常用配置,为什么呢?一般的技术文档都是枯燥乏味的,写的井然有序,适合查找,但是一般的情况下,有些配置很少会用到,所以,就逐渐形成了常用配置。

说说@SpringBootApplication

@SpringBootApplication是Spring Boot的核心注解,它本身是一个的注解组合,包含了启动配置的一系列功能,让我们来看下源码:

import Java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
    Class<?>[] exclude() default {};

    String[] excludeName() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};
}

组合包含了以下重要注解:

@Configuration
@EnableAutoConfiguration
@ComponentScan

其中,@Configuration表示这是一个配置,@EnableAutoConfiguration表示让Spring Boot根据类路径中的jar包依赖为当前项目进行自动配置。

比如,添加了spring-boot-starter-web这个基础依赖,Spring Boot会自动添加tomcat和Spring MVC的依赖,并且自动对他们进行配置。

@ComponentScan表示的是大家都熟悉的自动bean扫描注入。

如果不使用@SpringBootApplication,可以像我第一章那样,使用单独的注解,效果是一样的。

再来说一下入口类,Spring Boot的启动是靠一个名为*Application的入口类来实现的,入口类其实就是一个标准的Java静态方法类,只不过是在类中使用了一个对象SpringApplication的run方法来启动Spring Boot项目。如下图:

这里写图片描述

由于Spring Boot会自动扫描@SpringBootApplication所在类的同级包(如com.hjf.boot.demo.boot_mybatis)以及下级包里的所有bean,所以,官方建议入口类放在最外层的包名下。如下图:

这里写图片描述

最后,还有一个新的注解@AliasFor,这个注解应该是从4.2开始的标示注解属性别名的含义。

属性文件配置

Spring Boot的默认属性配置文件是在resources下的application.properties,也可以使用application.yaml来配置默认参数。如果是使用Spring Boot自带的配置的话,配置即使用,无需再单独去声明内容。例如:

这里写图片描述

也可以使用自己习惯的配置,但是这种方式不太安全,有可能会和自带的配置或第三方配置冲突,例如:

test.user=mickjoust
test.age=30

Spring Boot推荐使用类型安全的方式来进行自定义配置,例如:

@ConfigurationProperties(
        prefix = "safe"   //定义了一个safe前缀的配置类
)
public class SafeProperties {
}

日志配置

Spring Boot支持 Java Utile Logging、Log4J、Log4J2和Logback作为日志框架,无论使用哪种框架,Spring Boot都为当前使用日志框架及文件输出做好了配置。

默认情况下,Spring Boot使用LogBack作为默认日志框架,输出格式的文件是logback.cml

配置日志级别:

logging.file=/export/log

配置日志文件,按照格式loggin.level.包名=级别:

logging.level.org.springframework.web=DEBUG

或者直接配置root所有日志级别:

logging.level.root=DEBUG

Profile配置

Profile是Spring针对不同的环境提供不同的配置支持的一种功能,一般应用在生产环境和测试环境的配置区分上(比如,测试环境一般需要打印更多日志信息或者http响应中会有很多测试标示信息等等,生产环境则不会有)。Spring Boot中通过类似格式applicaiotn-{profile_name}.properties的配置形式指定当前活动的Profile。
例如:首先在application.properties中配置如下:

spring.profiles.active=dev

新建application-dev.properties和application-online.properties两个配置文件,内容分别如下:
application-dev.properties

server.port=8181

application-online.properties

server.port=9090

文件结构如下:
这里写图片描述
启动不同配置即可看到用的是测试环境配置,如下,切换配置同理。
使用测试环境配置

这里写图片描述

使用生产环境配置

这里写图片描述

引用xml配置

上一章里已经使用过,使用@ImportResource来加载xml配置,使我们在特定的应用的场景下去使用xml的配置:

@ImportResource(locations = "classpath*:/applicationContext.xml")

关闭自动配置

同样,上一章中已经配置过,当我们需要关闭自动配置的功能是,找到对应的自动配置的类,添加到排除项里即可,多项采用逗号隔开.class名称:

@SpringBootApplication(exclude = {MybatisAutoConfiguration.class})

Banner配置

关闭banner

Banner是什么?其实就是启东时显示的一个图案,Spring Boot默认显示如下:

如果不想显示它,直接在配置文件里配置即可关闭,如下:

spring.main.banner-mode=off

修改banner

我们也可以定制自己的启动图案,通过字符生成网站生成好看的字母或图案字符来显示自己的启动图案。

1、在src/main/resources下新建一个banner.txt。
2、将生成好的字符复制到banner.txt中。
3、启动即可显示自定义图案了。

这里写图片描述

starter pom

Spring Boot为我们提供了大多数常用的封装依赖,叫做starter pom,只要使用相关的starter pom,则Spring Boot会为我们自动的配置Bean,使用配置文件即可修改常用参数。除了官方提供的starter pom以外,页可以自己封装starter应用于自己的项目,后面再抽空演示如何自定义starter pom,像上一章里的mybatis就是mybatis小组封装的starter提供对Spring Boot的支持。

官方地址starter pom地址:

Favicon配置

关闭Favicon

说到favicon.ico这个小图标,Spring Boot提供了默认的小叶子,如果不需要使用

定制Favicon

但是,绝大多数时候,我们都会定制自己的小图标,用以区分我们的项目。设置它很简单,只需要将favicon.ico文件放到以下目录下,即可实现。

1、类路径 根目录 下
2、类路径 META-INF/resources/下
3、类路径 resources/下
4、类路径 static/下
5、类路径 public/下

后续文章在集成web项目详细配置时,会单独说明除了Spring Boot默认识别的静态文件路径外,怎么自定义静态路径或其它过滤路径。

一份简单的配置

#自定义:��型不安全
demo.author=mickjoust
demo.name=mickjoust-boot-demo

#内嵌tomcat配置
server.port=8080
#server.context-path= //如果没有值就不配置,可以使用默认,但不要在这里留空,会有错误
server.tomcat.uri-encoding=UTF-8

#Profile
spring.profiles.active=dev

#http encoding
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true

#日志
#logging.file=/export/log
#logging.level.root=DEBUG
#logging.level.org.springframework.web=DEBUG
#logging.level.sample.mybatis.mapper=TRACE

#datasource
#spring.datasource.driver-class-name=com.MySQL.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
#spring.datasource.username=test
#spring.datasource.password=123456
#spring.datasource.max-active=10
#spring.datasource.max-idle=5
#spring.datasource.min-idle=0

#converters 默认jackson
spring.http.converters.preferred-json-mapper=gson

#spring.main.banner-mode=off

小结

本章主要是对常用的Spring Boot配置做了简单的说明,更详细的配置可以参考官方的解释。配置内容和集成使用的依赖有关系,比如,ssl,jpa,jackson,httpconvert,mvc等等,具体使用时再说明。

每日金句

专注和简单一直是我的秘诀之一。简单可能比复杂更难做到:你必须努力理清思路,从而使其变得简单。但最终这是值得的,因为一旦你做到了,便可以创造奇迹。——源自乔布斯

题记

前两天有点忙,没有连续更新,今天接着聊。金句里老乔的话说得多好,但能真正做到的人又有多少?至少就我个人而言,我还远远没有做到这样,只是一个在朝着这个方向努力的人,力求简明易懂,用大白话让人快速的明白理解,简单的例子上手,让使用的人更多的去实战使用扩展,折腾记即是对自己学习使用很好的一次总结,对看的人也是一个参考的方法,希望大家能够找到对自己有用的思路或方法。今天主要说的是,继续上一章的配置,我们自己如何自定义类型安全的配置,并使用一个常用的工具fastjson集成来切入,虽然有自定义的jacson和gson,折腾记就是要折腾一下嘛,不然怎么能打开新思路。

类型安全的配置

在上一篇文章中,我们有使用过直接在application.properties中设置变量,这种方式是spring中常用的方式,但对Spring Boot来说,既不是安全的,也会因为频繁使用@Value来注入配置而过于繁琐,项目中使用起来尤其麻烦,真实项目中的变量就不像我演示的Demo里的只有一两行了,很多时候都会是几十行上百行,所以,Spring Boot中提供了基于类型安全的配置方式,通过@ConfigurationProperties将properties属性和一个Bean及其属性关联,从而实现类型安全的配置。

实战1——自定义的配置通过类似Service的方式注入是使用

项目使用:boot_properties

1、创建Bean。

// TestInfoSettings.class

@Component
@ConfigurationProperties( //1
        prefix = "usetest",
        locations = "classpath:config/app.properties"
)
public class TestInfoSettings {
    private String name;
    private String age;
    //省略get、set
}

说明:
1:@ConfigurationProperties加载properties文件内的配置,prefix属性指定配置的前缀,例如:usetest.*=string 。locations可以指定自定义的文件位置,不指定默认使用application.properties。

2、在src/main/resources下新增config/app.properties。

usetest.name=mickjoust
usetest.age=18

3、在Controller里添加一个接口调用.

//TestController.class

...原有省略

@RequestMapping("/showSetting")
    public Object showSetting(){
        StringBuffer sb = new StringBuffer();
        sb.append("setting name is : ").append(testInfoSettings.getName());
        sb.append("setting age is : ").append(testInfoSettings.getAge());
        sb.append("all is : ").append(testInfoSettings);
        return JsonResp.success(sb);
    }

4、启动,设置的数据注入进去了。
这里写图片描述

Spring Boot里的Spring MVC配置

用惯了Spring MVC,突然用Spring Boot反而会觉得很不习惯,因为很多配置消失了。简单不是说配置都没有了,而是Spring Boot通过某种方式帮助你快速的完成了一些前期的工作,上一章里说过,Spring Boot的一大特性就是自动配置并采用了条件注解@Conditional的方式自动扫描并开启你配置的功能,二是对于MVC里的viewResolver、interceptors、静态资源、formatter和converter、HttpMessageConverts、Servlet、Filter、Listener等,Spring Boot使用了一个叫WebMvcAutoConfigurationWebMvcProperties的文件来进行自动配置,如图路径下:
这里写图片描述

接下来我们看看一般都有哪些自动配置

自动配置的静态资源

在原有的Spring MVC的配置,静态资源通常是这样配置的。

<mvc:default-servlet-handler />

<mvc:resources location="/static/" mapping="/static/**" cache-period="864000" />

在Spring Boot里是在方法addResourceHandlers中来定义静态资源的配置的。其实,就是一个if-else(有兴趣的同学自行看看源码),概括起来包含两类:

1、类路径文件
把类路径下的/static、/public、/resources和/META-INF/resources文件夹下的静态文件直接映射为/**来提供访问。

2、webjar
把webjar的/META-INF/resources/webjars下的静态文件映射为/webjar/**。
什么是webjar?就是有人帮我们将常用的前端脚本框架之类封装在jar包里,然后通过jar包的方式来调用脚本,详细的可以看网站:http://www.webjar.org

最后,如果我们要修改静态路径的映射并增加缓存时间,只需要在配置文件修改static-path-pattern和cache-period:

spring.mvc.static-path-pattern=/static/**
spring.resources.cache-period=864000

至于静态文件的存放路径,因为一般常用的静态文件都是放在这几个目录下的,基本上可以满足要求了,如果要自定义,修改spring.resources.static-locations=即可。

自动配置Formatter和Converter

搜索Formatter,就能够找到addFormatters这个方法里的定义,我们只需要定义Converter、GenericConverter和Formatter接口实现的实现类Bean,就会注册Bean到Spring MVC中了。比较简单,不再举例子了。

自动配置HttpMessageConverters

同理,搜索MessageConverters,会找到configureMessageConverters,这个方法就是直接添加HttpMessageConverters的Bean,而这个Bean是在HttpMessageConvertAutoConfiguration类中定义的,源码如下:
这里写图片描述

比较简单,就是加入定义好的converter,其中,默认加载的有以下八类:
这里写图片描述

有同学要问StringHttpMessageConverter为什么有两个,其实只是字符集使用了一个UTF-8和一个ISO-8859-1。还有默认goson的convert为啥没有看到呢,本章后面会说到原因。

自动配置的ViewResolver

同样道理,搜索ViewResolver,会搜索到三个: InternalResourceViewResolver、BeanNameViewResolver、ContentNegotiatingViewResolver。

【1】ContentNegotiatingViewResolver
Spring MVC里提供的特殊的ViewResolver,它自己是不处理View的,它的作用是代理给不同的ViewResolver来处理不同的View。源码如下:
这里写图片描述

【2】InternalResourceViewResolver
这个是内置最常用的解析器,通过设置前缀,后缀和controller中方法来返回视图名的字符串,以此来得到实际页面。源码如下:
这里写图片描述

它是通过配置文件获取前后缀的,设置参数如下:

spring.mvc.view.prefix=
spring.mvc.view.suffix=

【3】BeanNameViewResolver
定义很简单,作用就是它会去查找Controller方法返回值的字符串中是否有定义过的Bean名称,如果有,则用定义的View来渲染。

例如:我们定义一个Bean叫testView,返回类型是MappingJackson2JsonView,只要在@Controller返回的方法中返回,就可以获得指定的视图渲染。

return "testView";

对于视图,这里多说一句,不同的人有不同的喜好和习惯,有的项目喜欢直接前后分离,有的项目需要返回一些视图模板渲染基本的框架,怎么用顺手怎么用,没有好坏优劣之分,只有使用的场景不同,用得好,视图一样能发挥作用。


上面只是简单说明了一些常用的自动配置,至于更多更详细的配置,大家抽空可以看看自动配置的相关源码,对思路扩展也是有好处的。因为如果只想快速应用,通常的常用配置已经够用了,对于需要自定义的应用场景里,可自行参看配置修改。

扩展Spring MVC配置

上面大概介绍了Spring Boot里对MVC的自动配置,其实,大家可以对照着原有MVC的配置查看Spring Boot都有哪些配置项,你会发现其实都是原来已经有的,现在只是换了一种方式:通过配置或重写方法来达到修改或增加Spring MVC的配置。下面用一个例子来说明接管Spring Boot的Spring MVC的配置的方式并通过修改的方式来配置一个fastjson的converter。

如何定制Boot里的MVC配置?

在又需要默认的配置,又需要自己定制的配置的时候,我们需要���定义配置,Spring Boot官方提供了一个适配器类WebMvcConfigurerAdapter来扩展功能。可以通过重写接口来支持MVC配置。

@Configuration
public class CustomMVCConfiguration extends WebMvcConfigurerAdapter{//1

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.clear(); //实验发现,不起作用,可能是boot的bug,或者官方不让修改?
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        for (HttpMessageConverter<?> messageConverter : converters) {
            System.out.println(messageConverter); //2
        }
    }
}

说明:
1:继承父类,是一个适配器模式类,可以重新定义MVC的功能和配置,但不会影响已有配置,属于增加功能扩展,不知道这是好还是不好。
2:找到扩展方法,可以添加自定义方法。

实战2——在已有的自动功能中增加新的功能fastjson

fastjson,国产,有很多人喜欢用,因为速度快,操作简单。以前老版本时其实也是坑很多啦,不过还是挺好用的,支持起,现在官方版本1.2.12,并没有支持Spring Boot的starter,但是它有HttpMessageConvert的支持,其实要支持也很方便。下面演示一下如何集成。

方法1:直接注册HttpMessageConverts的Bean

1、首先新建一个配置文件。

//FastJsonHttpMessageConvertersConfiguration .class

@Configuration
@ConditionalOnClass({JSON.class}) //1
public class FastJsonHttpMessageConvertersConfiguration {

    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters(){
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();//2

        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(
                SerializerFeature.PrettyFormat,
                SerializerFeature.WriteClassName
        );
        fastConverter.setFastJsonConfig(fastJsonConfig);

        HttpMessageConverter<?> converter = fastConverter;

        return new HttpMessageConverters(converter);
    }

说明:
1、判断JSON这个类文件是否存在,存在才会创建配置。
2、我看官方文档说的1.2.10以后,会有两个方法支持HttpMessageconvert,一个是FastJsonHttpMessageConverter,支持4.2以下的版本,一个是FastJsonHttpMessageConverter4支持4.2以上的版本,具体有什么区别暂时没有深入研究。

2、查看是否注册成功。

这里写图片描述
成功了。

3、启动。执行http://locahost:8080/showSetting

这里写图片描述

这个方法其实只是注册了Bean,由于没有指定执行的配置,使用了新方法,这种方式其实并不好,没办法灵活控制。所以我们看能不能像gson那样指定使用,看图:

这里写图片描述

如图,httpmessageconvert在自动配置时就会自动初始化gson和jackson,默认使用用jackson,找到了配置名为:spring.http.converters.preferred-json-mapper。于是有了方法2.

方法2:自动配置Bean并指定配置项

1、创建新配置

// FastJsonHttpMessageConvertersConfiguration.class
//...注释方法1的代码

    @Configuration
    @ConditionalOnClass({FastJsonHttpMessageConverter.class}) //1
    @ConditionalOnProperty(//2
            name = {"spring.http.converters.preferred-json-mapper"},
            havingValue = "fastjson", 
            matchIfMissing = true
    )
    protected static class FastJson2HttpMessageConverterConfiguration{
        protected FastJson2HttpMessageConverterConfiguration() {
        }

        @Bean
        @ConditionalOnMissingBean({FastJsonHttpMessageConverter.class})//3
        public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
            FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();

            FastJsonConfig fastJsonConfig = new FastJsonConfig();//4
            fastJsonConfig.setSerializerFeatures(
                    SerializerFeature.PrettyFormat,
                    SerializerFeature.WriteClassName,
                    SerializerFeature.WriteMapNullValue
            );
            ValueFilter valueFilter = new ValueFilter() {//5
                //o 是class
                //s 是key值
                //o1 是value值
                public Object process(Object o, String s, Object o1) {
                    if (null == o1){
                        o1 = "";
                    }
                    return o1;
                }
            };
            fastJsonConfig.setSerializeFilters(valueFilter);

            converter.setFastJsonConfig(fastJsonConfig);

            return converter;
        }
    }

说明:
1:判断是否存在类。
2:使用spring.http.converters.preferred-json-mapper属性来启动功能。
3:当没有注册这个类时,自动注册Bean。
4:使用最新的官方推荐配置对象的方式来注入fastjson的序列化特征。
5:添加对json值的过滤,因为像移动APP,服务端在传json值时最好不要传null,而是使用“”,这是一个演示。

2、指定使用fastjson。

spring.http.converters.preferred-json-mapper=fastjson

3、启动运行,成功。现在就能很方便的切换fastjson或gson了。

这里写图片描述

小结

本章主要是说明了如何在自定义配置的基础上定制MVC和集成新的自动配置功能,很多同学觉得配置很简单基本已经够用了,自定义配置干啥?默认配置也许刚开始能满足一些需求,但更多的时候还需要针对特定的场景来自定义配置,比如拦截器和过滤器,虽然这一节没有讲,实际中用得是很多的,但通常基本原理是想通的,多实战实战,有写的不对的地方,大家多讨论交流。

每日金句

在人生或者职业的各种事务中,性格的作用比智力大得多,头脑的作用不如心情,天资不如由判断力所节制着的自制,耐心和规律。——源自 海明威

题记

虽然以前在spring MVC中有时会涉及到配置容器,但是大多数同学会觉得这是运维或者测试的工作,只要能用就行,只要自己的代码能运行就行。其实,多了解一些原理的作用不只是为了完成任务,它可以帮助你更积极的去思考代码运行的原理,提升你的思维结构,因为你习惯知其所以然,以后你不管是做需求分析,架构设计,模块重构优化、性能调优等等,都会有很多帮助的。扯远了点,本章讲解的比较简单的,也是常用的容器的配置的修改,ssl支持这几年越来越受到重视了,开始实战吧。

实战

servlet容器配置

Spring Boot快速的原因除了自动配置外,另一个就是将web常用的容器也集成进来并做自动配置,让使用它的人能更快速的搭建web项目,快速的实现自己的业务目的。什么是容器?在这里就是支持Java程序运行的程序。本节内容只详细展开Tomcat配置,不过,本节内容对后面提到的Jetty、Undertow都是通用。

1-配置文件配置Tomcat

之前我们在配置章节介绍了如何查看配置的定义,这里,我们同样能在org.springframework.boot.autoconfigure.web中找到ServerProperties,通用的servler通用的配置就是在这里定义的,以“server”作为前缀,而作为默认内嵌容器的Tomcat的配置是以server.tomcat作为前缀的。以下为举例:

// servlet 容器
server.port=9090   #监听端口,默认是8080
server.context-path=  #访问路径,默认为/
// 配置tomcat
server.tomcat.uri-encoding=  #tomcat编码,默认为UTF-8
server.tomcat.accesslog.directory=  #访问日志,默认为logs

以上为简单说明,详细的配置可在application.properties输入server或server.tomcat来查看,idea可以很方便的提示有哪些功能,如图:
这里写图片描述

2-代码配置Tomcat

Spring Boot的自动配置有一个特性就是能够通过代码来修改配置,这样可以很方便的修改配置,而我们只需要实现Spring Boot定义的接口即可。这里,我们需要注册一个实现了EmbeddedServletContainerCustomizer的Bean。而如果直接配置指定容器,那么使用对应工厂类实现即可,对应如下:

Tomcat   ---> TomcatEmbeddedServletContainerFactory
Jetty    ---> JettyEmbeddedServletContainerFactory
Undertow ---> UndertowEmbeddedServletContainerFactory

公用配置

新建一个可修改的公用server配置:

package com.hjf.boot.demo.boot_ssl.config;

import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;

public class CustomerServlet implements EmbeddedServletContainerCustomizer {

    public void customize(ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) {
        configurableEmbeddedServletContainer.setPort(9090); //1
        configurableEmbeddedServletContainer.setContextPath("/test"); //2
    }
}  

说明:
1:修改监听端口
2:修改访问路径,和配置文件修改是类似的。

特殊配置

增加配置类,并注册Bean

@Configuration
public class ServletConfig {
}

Tomcat配置

@Bean
    public EmbeddedServletContainerFactory servletContainer(){
        TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
        factory.setPort(9999);
        factory.setContextPath("/test");
        return factory;
    }

Jetty配置

@Bean
    public EmbeddedServletContainerFactory servletContainer(){
        JettyEmbeddedServletContainerFactory factory = new JettyEmbeddedServletContainerFactory();
        factory.setPort(9999);
        factory.setContextPath("/test");
        return factory;
    }

Undertow配置

@Bean
    public EmbeddedServletContainerFactory servletContainer(){
        UndertowEmbeddedServletContainerFactory factory = new UndertowEmbeddedServletContainerFactory();
        factory.setPort(9999);
        factory.setContextPath("/test");
        return factory;
    }

注意:一个项目只用配置一个容器即可,不要重复注册多个。

替换内嵌容器

Spring Boot默认是用Tomcat作为Servlet的容器,我们上面可以配置另外另个容器,那么这里就需要排除掉Tomcat为对应容器:

使用Jetty

在pom.xml中修改如下:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starte-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
    </dependencies>

使用Undertow

在pom.xml中修改如下:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starte-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
    </dependencies>

使用SSL

什么是SSL?百度百科这样解释的,SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。

SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。 SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。

使用SSL通常就两步,一是,生成有效的证书,让你的http链接有据可循,这个证书是可以自签名的,也可以是从SSL证书授权中心获得的,一般大的网站都是授权了,比如,百度、京东等,也有没授权的,例如:12306,但是都不影响使用;二是,在web容器里配置开启SSL,让配置的ssl生效。

生成证书

1、先找到你使用的Java JDK,在bin文件夹中找到工具keytool,如何你设置了java的环境变量的话,直接在命令行执行命令如下(Windows和Linux都是一样的):

keytool -genkey -alias mickjoust -keyalg RSA  //1

说明:
1:如果不指定算法格式的话,会使用老的加密格式,高版本的容器,都会报安全格式不支持的错误。
这里写图片描述

这时生成了一个.keystore,就是证书文件了。

配置SSL

在Spring Boot中配置SSL非常简单,同样在application.properties下配置:

server.port=8443  //1
#server.session.timeout=
#server.context-path=

server.tomcat.uri-encoding=UTF-8
#server.tomcat.compression= #新版已经没有了

server.ssl.key-store=.keystore  //2
server.ssl.key-store-password=123456 //3
server.ssl.key-store-type=JKS   //4
server.ssl.key-alias=mickjoust  //5

说明:
1:指定监听端口
2:ssl存储的文件名
3:证书密码
4:证书类型
5:证书别名

使用代码配置http自动跳转https

上面配置了SSL,只是支持SSL,也就是说,当你输入同样的网址带上https时,是可以访问的,但我们有时习惯了只输入网址,而浏览器默认是使用的http,这时我们希望能够自动跳转,要实现这个功能,我们需要配置容器的自动重定向功能。使用tomcat作为示例,jetty和Undertow类似,需要查看对应文档。

import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Http2HttpsConfig {

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory(){//1
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(httpConnector());
        return tomcat;
    }

    @Bean
    public Connector httpConnector(){//2
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(9090);
        connector.setSecure(false);
        connector.setRedirectPort(8443);
        return connector;
    }
}

说明:
1:重写上下文设置,添加路径和安全集合。
2:创建一个httpconnector以被使用。

启动成功,看到https端口了
这里写图片描述

执行localhost:9090测试
这里写图片描述

自动跳转到https了
这里写图片描述

很多同学比较疑惑,这也太麻烦了,还不如直接使用tomcat,当然,使用某种方法,也就有某种方法的代价牺牲,这里其实是通过代码的方式去配置tomcat,而平时我们都是手动操作tomcat的xml配置,这也是上面最开始说到的,如果没有一定的耐心,那么只是在完成任务,一旦遇见有一点困难的配置或任务,那么就不知道该怎么办了。其实,只要理解了原理,无论用什么配置,都是达到目的的手段而已。

小结

本章内容主要介绍了Spring Boot中如何配置内嵌tomcat和替换tomcat的方法,同时对ssl的配置进行了实战,其中要主要的是,内嵌的配置是通过代码的方式来配置的,和通用的容器里的ssl配置还有点区别,网上有很多教程,这里就不再介绍类似tomcat如何配置ssl的方法了。本章比较简单,算是配置的完结了,Spring Boot的配置其实有很多,需要在使用时自己去使用体会。

示例地址:https://github.com/mickjoust1018/mickjoust-boot-demo

本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-01/139576.htm

赞(0) 打赏
转载请注明出处:服务器评测 » Spring Boot 实践心得笔记
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏