SpringBoot + MyBatis 重构 Web 应用

8 篇文章 0 订阅

前言

 项目构建的时候是截取了另一个项目的部分功能形成的,截取出的功能代码少但项目结构比较复杂,依赖严重 。改写过后,不少代码成了”鸡肋”,搞不清楚谁是谁 。

 web/controller在一块,dao/domain独占一方 ; junit在6个pom。xml中出现了4次,版本还不一样 ; spring/mybatis的配置文件也有好几个,里面的xml代码也是长而杂 。

Clean Code,之前专门买了一本书,讲述代码清洁之道 。 整洁的代码对项目的开发效率至关重要,宏观一点,项目结构的清晰,也对后续的开发有所帮助。

SpringBoot

  GitHub示例 Anddd7/SSM-SpringBoot-Starter`

 前一段时间还没正式学习使用Spring时就听说了SpringBoot,还记得学生时代配置SSH,满篇的xml简直是童年阴影(- -如果xml节点还没对齐的话, 那 ……)。
 SpringBoot可以达到0配置 (- -当然这是不可能的) 快速启动一个Spring应用,对简化配置有显著提升。

准备 - pom.xml

  • 首先还是从Maven配置入手
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>anddd7.boot4ssh</groupId>
    <artifactId>SSM-SpringBoot-Starter</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <!--官方推荐使用 spring-boot-starter-parent 包括一些预设配置:
        1.使用java6编译级别<java.version>1.8</java.version>
        2.使用utf-8编码<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        3.实现了通用的测试框架 (JUnit, Hamcrest, Mockito).
        4.智能资源过滤
        5.智能的插件配置(exec plugin, surefire, Git commit ID, shade).

        不继承也可使用dependcy引入 ,因为scope是import,不再允许在<properties>覆盖第三方包版本
        如果要使用其他版本,需要在上面的前面添加一个完整的dependency
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>1.4.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
        <mybatis.version>3.4.2</mybatis.version>
        <mybatis-spring.version>1.3.1</mybatis-spring.version>
        <spring-boot.version>1.4.4.RELEASE</spring-boot.version>
    </properties>

    <!-- 对应模块的starter包含常用依赖 ,例如starter-web{spring-web,spring-mvc}-->
    <dependencies>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>${mybatis-spring.version}</version>
        </dependency>

        <!-- springboot+mybatis官方连接包 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-autoconfigure</artifactId>
            <version>1.1.1</version>
        </dependency>

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

        <!-- dbcp 数据源 -->
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>

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

    </dependencies>

    <build>
        <plugins>
            <!--用于将项目打包成fat jar(executable jar)-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!-- mybatis 工具 -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <configuration>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  • 如果使用Jetty ,需要替换掉内置的Tomcat
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>${spring-boot.version}</version>
    <!-- 使用jetty启动 ,先移除tomcat组件 -->
    <exclusions>
        <exclusion>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- 添加jetty支持 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
    <version>${spring-boot.version}</version>
</dependency>

开始 - Application 和 Configuration

引入Maven后 ,准备一个Controller ,然后通过SpringApplication启动Spring就可以使用了 Spring Boot 快速入门 ;需要对Spring进行一些配置的时候(和Mybatis融合、配置数据源等)就需要将Application单独出来 。

  • 1 Spring配置application.xml -> application.yaml
# application.yaml
# Server settings (ServerProperties)
# 以数据为中心的标记语言 ,易于读写 ,替代xml
# springboot 默认是8080端口 ,没有项目地址

# 服务器设置
server:
  port: 8080
  address: 127.0.0.1
  sessionTimeout: 30
  contextPath: /testboot

  # 内置tomcat设置
tomcat:
  accessLogEnabled: false
  protocolHeader: x-forwarded-proto
  remoteIpHeader: x-forwarded-for
  basedir:
  backgroundProcessorDelay: 30 # secs
  • 2 设置SpringBoot启动入口
package anddd7.springboot;

import anddd7.springboot.configuration.MapperScannerConfiguration;
import anddd7.springboot.configuration.MyBatisConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;

/**
 * 将spring的启动和配置单独出来
 *
 * @SpringBootApplication 等价于 :
 * -     @Configuration 通过@ImportResource引入xml文件,@Value读取键值 ,@Bean读取配置的bean实例
 * -     @ComponentScan 同xml中的自动扫描组件
 * -     @EnableAutoConfiguration
 * @EnableAutoConfiguration 下包含了一系列自动配置类的清单 ,并按顺序执行 ,在Spring3时代就有@EnableWebMvc注解
 * [SpringBoot之@EnableAutoConfiguration原理及自定义扩展 ](http://blog.csdn.net/xiaoyu411502/article/details/52770723)
 * <p>
 * MongoAutoConfiguration.class为例 :
 * -    使用了@Configuration ,标识是一个配置
 * -    定义了必要的Mongo对象@Bean
 * -    使用了@EnableConfigurationProperties ,将application.properties配置文件中的属性映射到Java类中 ,便于使用
 * -    @ConditionOnClass表明加载条件 - Mongo.class位于类路径上
 * -    @ConditionalOnMissingBean说明Spring Boot仅仅在当前上下文中不存在Mongo对象时,才会实例化一个Bean
 */

@Import({MyBatisConfiguration.class, MapperScannerConfiguration.class})
@SpringBootApplication
public class Application {

    public static void main(String[] args) {

        //一键自动启动
        SpringApplication.run(Application.class, args);

        //配置启动
//        SpringApplication app = new SpringApplication();
//        app.setBannerMode(Banner.Mode.OFF);

        //链式API构建器
//        new SpringApplicationBuilder()
//                .bannerMode(Banner.Mode.OFF)
//                .child(Application.class)
//                .run();

    }
}

依旧是@SpringBootApplication,只不过@Import了一些配置类,使用过xml配置Mybatis和Spring的童鞋对这些类名一定很熟悉,其实就是将原来xml转化为了Java类配置 — @Configuration注解

  • 3.1 数据源
package anddd7.springboot.configuration;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;


/**
 * 对应xml中datasource的配置
 */
@Configuration
@PropertySource("classpath:prop.properties")
public class DataSourceConfiguration {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.maxActive}")
    private int maxActive;
    @Value("${jdbc.maxIdel}")
    private int maxIdel;
    @Value("${jdbc.maxWait}")
    private long maxWait;

    @Bean(name = "dataSource")
    public BasicDataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setMaxActive(maxActive);
        dataSource.setMaxIdle(maxIdel);
        dataSource.setMaxWait(maxWait);
        dataSource.setValidationQuery("SELECT 1");
        dataSource.setTestOnBorrow(true);
        return dataSource;
    }
}
  • 3.2 prop.properties
#jdbc
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=214124
jdbc.maxActive=2335
jdbc.maxIdel=120
jdbc.maxWait=100
  • 4 MapperScanner
package anddd7.springboot.configuration;

import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 扫描mybatis的接口
 */
@Configuration
// 因为这个对象的扫描,需要在MyBatisConfig的后面注入,所以加上下面的注解
@AutoConfigureAfter(MyBatisConfiguration.class)
public class MapperScannerConfiguration {
    @Bean(name = "mapperScannerConfigurer")
    public MapperScannerConfigurer mapperScannerConfigurer() {
        //创建内置的config
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        //获取之前注入的beanName为sqlSessionFactory的对象
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        //指定mapper接口的路径 ,批量加上@Mapper ,也可以手动加上 ,省略此配置
        //会触发 No MyBatis mapper was found in '[anddd7.springboot.controller, anddd7.springboot]' package.  警告
        //mapperScannerConfigurer.setBasePackage("anddd7.springboot.dao");
        return mapperScannerConfigurer;
    }
}
  • 5.1 SqlSessionFactory
package anddd7.springboot.configuration;

import org.apache.ibatis.session.SqlSessionFactory;
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.context.annotation.Import;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
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.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

import javax.sql.DataSource;
import java.io.IOException;

/**
 * 对应xml中事务和sqlSessionFactory的配置
 */
@Configuration
@EnableTransactionManagement
@Import(DataSourceConfiguration.class)
public class MyBatisConfiguration implements TransactionManagementConfigurer {

    @Autowired
    private DataSource dataSource;

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

    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactoryBean() {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        //设置数据源
        bean.setDataSource(dataSource);
        //设置config路径
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        bean.setConfigLocation(resourceLoader.getResource("classpath:mybatis-configuration.xml "));
        //设置mapper.xml路径
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            bean.setMapperLocations(resolver.getResources("classpath:anddd7/springboot/mapping/*.xml"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            return bean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
  • 5.2 mybatis-configuration.xml
<?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>
    <settings>
        <setting name="cacheEnabled" value="false" />
        <setting name="lazyLoadingEnabled" value="false" />
        <setting name="multipleResultSetsEnabled" value="true" />
        <setting name="useColumnLabel" value="true" />
        <setting name="useGeneratedKeys" value="false" />
        <setting name="defaultExecutorType" value="SIMPLE" />
        <setting name="defaultStatementTimeout" value="25000" />
    </settings>
</configuration>
  • 6 除了application.xml还以properties或yaml存在,其他配置都Java化了,web.xml自然也不存在了(顺应servlet 3.0的注解方式)。
package anddd7.springboot.configuration;


import anddd7.springboot.filter.LoginFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.Filter;

/**
 * 对应web.xml中的所有设置
 */
public class WebXmlConfiguration {

    @Bean(name = "LoginFilter")
    public Filter getLoginFilter() {
        return new LoginFilter();
    }

    @Autowired
    DispatcherServlet dispatcherServlet;

    /*
    新的springboot不需要再设置servlet -> DispatcherServlet ,默认会拦截请求交给DispatcherServlet

    @Bean
    public ServletRegistrationBean defaultServletRegistration() {
        ServletRegistrationBean registrationBean = new ServletRegistrationBean();
        registrationBean.setServlet(dispatcherServlet);
        registrationBean.addUrlMappings("*.ajax");
        return registrationBean;
    }
    */

    @Bean
    public FilterRegistrationBean loginFilterRegistration() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(getLoginFilter());
        registrationBean.setName("LoginFilter");
        registrationBean.addUrlPatterns("*.html", "*.ajax");
        return registrationBean;
    }
}

 从上面文件可以看到 ,通过@Configuration+@Import将xml转化成了容易理解的Java 。所以不是不需要配置,而是规范化、简单化的配置,而且启动方式上也简便不少。
 SpringBoot 将原来一些固定的启动方式打包在了一起 ,包含了很多自动化的配置 (@Enable*注解系列); 采用易读写的yaml和Java,摒弃xml(真的头晕)。

运行

Application.main()

总结

GitHub示例 Anddd7/SSM-SpringBoot-Starter`

 如果要添加webapp(网页静态资源),重命名为resources放在源目录下 (SpringBoot默认查找resources/static/public作为静态目录)。熟练过后 ,配置一个可用的Spring要比之前快得多 ,而且配置文件减少 ,项目目录结构清晰不少 。
 不过对Spring不熟悉 ,没有一条一条配过xml的入门者 ,这种一键式配置推荐使用不推荐学习 。封装太深 ,很难理解每一步的意义 ,所以使用过后还是对照xml一步步探究Spring所做的事 ,共勉

 Next ,SpringBoot原理和Spring源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值