Spring Boot快速开发REST服务最佳实践

作者: JeffWong

一、为什么选择Spring Boot Spring Boot是由Pivotal团队提供的全新框架,被很多业内资深人士认为是可能改变游戏规则的新项目。早期们搭建一个SSH或者Spring Web应用,需要非常繁琐的步骤,比如配置web.xml,配置数据库连接,配置事务,配置日志,配置Tomcat,装配Bean,声明和配置切面等等等等,如果项目过大多人协作各种冗长啰嗦的配置让人烦不胜烦,这么多年下来,给人一种Java就是大型配置文件的感觉。 Spring Boot的设计目的是用来简化新Spring应用的初始搭建以及开发过程,吸引更多开发者的最大亮点之一是集成了自动配置的魔力。Spring Boot的四个主要新特性如下: 1、Spring Boot Starter:它将常用的依赖分组进行了整合, 将其合并到一个依赖中, 这样就可以一次性添加到项目的Maven或Gradle构建中;Spring Boot通过提供众多起步依赖降低项目依赖的复杂度。起步依赖本质上是一个Maven项目对象模型(Project Object Model, POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。很多起步依赖的命名都暗示了它们提供的某种或某类功能。Spring Boot经过了足够的测试,确保引入的全部依赖都能相互兼容。这是一种解脱,只需指定起步依赖,不用担心自己需要维护哪些库,也不必担心它们的版本。
2、自动配置 :Spring Boot的自动配置特性利用了Spring 4对条件化配置的支持, 合理地推测应用所需的bean并自动化配置它们;最后, Spring Boot没有引入任何形式的代码生成,而是利用了Spring 4的条件化配置特性,以及Maven和Gradle提供的传递依赖解析,以此实现Spring应用程序上下文里的自动配置。简而言之, Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。每当应用程序启动的时候, Spring Boot的自动配置都要做将近200个这样的决定,涵盖安全、集成、持久化、 Web开发等诸多方面。所有这些自动配置就是为了尽量不让你自己写配置。
3、命令行接口(Command-line interface, CLI):Spring Boot的CLI发挥了Groovy编程语言的优势, 并结合自动配置进一步简化Spring应用的开发;
4、Actuator: 它为Spring Boot应用添加了一定的管理特性。

常见的搭建一个Spring Boot应用只要如下几步: 1、打开http://start.spring.io/ 2、点击"Switch to the full version,选择Java版本,如1.8,选择好构建工具,如Maven或Gradle 4、点击Generate Project下载项目压缩包 5、解压后,使用eclipse或者intellij idea,导入项目即可

当然,对于经验丰富的老鸟,不需要打开网页再下载解压导入文件那么多步骤,通过Idea也可以一步一步构造Spring Boot项目。 二、工程结构

官方生成的Spring Boot项目,默认结构说明: 1、src/main/java 程序开发以及主程序入口
2、src/main/resources 配置文件
3、src/test/java 测试程序 src/main/java根目录下面,有如下Java类和包: 1、Application.java 应用程序入口,包括一个静态main方法,可以做一些框架配置,比如mybatis、swagger等
2、domain目录主要用于数据访问实体(DataObject)与数据访问层(Repository)
3、service目录主要是业务逻辑相关的服务接口和实现
4、controller负责页面访问控制,对外暴露API

当然,们需要参考成熟的项目结构或者根据个人经验来改造项目结构,本文的SpringBootDemo为了方便仅做简单调整,项目结构如下:

主要包说明: 公共模块 1、common:公共类,如枚举,常量、业务无关的通用公共实体等 2、util:常用实用的帮助类,如反射、字符串、集合、枚举、正则、缓存、队列等 3、config:自定义的配置项,可从配置文件读取 表现层 1、controller:负责页面访问控制,对外暴露Rest API接口 数据访问层 1、domain:数据对象实体DO,通常和数据表、视图或其他业务对象一一对应 2、dao:数据访问对象,本文demo选择比较熟悉的mybatis作为ORM工具 业务逻辑层 1、service:服务 contract是接口,impl是服务实现 2、entity:实体 vo是服务可对外公开的实体;dto是数据传输对象,可在服务间传递;qo:查询对象,可以认为是查询条件的封装

本文demo没有写dto和qo示例,很多中小型项目,entity其实是非常混乱的,实体设计和分层抽象有问题,有时候直接影响到业务逻辑复杂程度。

关于工程结构,尤其是应用分层和领域实体抽象(数据访问对象DO和显示层对象VO等),强烈推荐大家参考<<阿里巴巴Java开发手册>>终极版本的工程结构一章。 三、MyBatis使用 Maven依赖:

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

View Code

数据库驱动: MySQL:

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

View Code SQLServer:

        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
            <version>6.4.0.jre8</version>
        </dependency>

View Code

隆重公告,微软Microsoft JDBC Driver For SQL Server已发布到maven中央仓库,本文的demo选择的是SQLServer,主要是MySQL很多人都写了,资料太充足,不如试试不同的风格,而且在前厂写的第一个线上Spring Boot应用也是访问SQLServer,demo就哪个好举例就用哪个了。

配置文件中的配置:

 MYSQL数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdb?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
 MSSQL数据源配置
spring.datasource.url=jdbc:sqlserver://localhost;databaseName=TestDB
spring.datasource.username=sa
spring.datasource.password=123456
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.jpa.show-sql=true
spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.hibernate.ddl-auto = create-drop
 Mybatis 配置
mybatis.typeAliasesPackage=com.power.demo.domain
mybatis.mapperLocations=classpath:mapper/*.xml

View Code 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.power.demo.dao.GoodsDao">
    <resultMap id="BaseResultMap" type="com.power.demo.domain.GoodsDO">
        <result column="GoodsId" property="goodsId"/>
        <result column="GoodsCode" property="goodsCode"/>
        <result column="GoodsName" property="goodsName"/>
        <result column="GoodsType" property="goodsType"/>
        <result column="CreateTime" property="createTime"/>
        <result column="Disabled" property="disabled"/>
    </resultMap>
    <parameterMap id="Goods" type="com.power.demo.domain.GoodsDO"/>
    <sql id="Base_Column_List">
        GoodsId,GoodsCode,GoodsName,GoodsType,CreateTime,Disabled
    </sql>
    <select id="findGoodsByGoodsId" resultType="GoodsDO" parameterType="java.lang.String">
        SELECT
        <include refid="Base_Column_List"/>
        FROM Goods WITH(NOLOCK) WHERE 1=1
        AND Disabled=0
        AND GoodsId = 
    </select>
    <select id="findGoodsByGoodsCode" resultType="GoodsDO" parameterType="java.lang.String">
        SELECT
        <include refid="Base_Column_List"/>
        FROM Goods WITH(NOLOCK) WHERE 1=1
        AND Disabled=0
        AND GoodsCode = 
    </select>
    <select id="findGoodsByGoodsType" resultType="GoodsDO" parameterType="java.lang.Integer">
        SELECT
        <include refid="Base_Column_List"/>
        FROM Goods WITH(NOLOCK) WHERE 1=1
        AND Disabled=0
        AND GoodsType = 
    </select>
    <select id="findAllGoods" resultType="GoodsDO">
        SELECT
        <include refid="Base_Column_List"/>
        FROM Goods WITH(NOLOCK) WHERE 1=1
    </select>
    <insert id="insertGoods" parameterMap="Goods">
        INSERT INTO Goods (GoodsId,GoodsCode,GoodsName,GoodsType,CreateTime,Disabled)
        VALUES({goodsId},{goodsCode},{goodsName},{goodsType},{createTime},{disabled})
    </insert>
    <insert id="updateGoods" parameterMap="Goods">
        UPDATE Goods SET Disabled= WHERE GoodsId={goodsId}
    </insert>
    <insert id="deleteGoods" parameterType="java.lang.String">
        DELETE FROM Goods WHERE GoodsId=
    </insert>
</mapper>

View Code

最后,在应用程序入口,添加一行注解:

// mapper 接口类扫描包配置
@MapperScan("com.power.demo.dao")
public class Application {
}

本文demo只提供了简单的CRUD,但是常见的开发还有很多东西要写。比如:

如何做多库配置,如何动态拼接执行复杂SQL,如何批量插入,如何拿到运行时SQL语句,如何使用存储过程,如何进行数据缓存、如何使用事务、如何级联查询等。

这些遗留内容希望有心的你慢慢去发掘尝试了。

推荐MyBatis代码生成器:MyBatis Generator 四、API文档描述

使用应用广泛的Swagger,生成API文档。 Maven中添加依赖:

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.2.2</version>
        </dependency>

View Code

需要在应用程序入口Application里面加一行注解:

@EnableSwagger2
public class Application {
}

不要忘了Api说明和实体说明配置,demo提供了完整示例。 五、单元测试

使用Junit进行单元测试

/**
 * Created by JeffWong.
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class CommonTests {
    @Test
    public void testGoodsTypeEnum() throws Exception {
        GoodsType goodsType = GoodsType.Discount;
        System.out.println(GoodsType.Normal.ordinal());//0
        System.out.println(GoodsType.Discount.ordinal());//1
        System.out.println(goodsType.getCode());
        System.out.println(goodsType.getDescription());
        Assert.isTrue(goodsType.getCode() == 1024, "折扣商品Code为1024");
    }
}

View Code

如果需要单元测试的方法需要配置文件,那么test下也要有resources目录用于存放资源文件。

本文demo提供了完整的各层单元测试方法,大家可以参考下。

总结:使用Spring Boot全家桶,你可以快速上手开发Java的REST接口应用,配合Java8+的相关新特性,写Java也越来越省心(虽然Java8的lambda比较难受,Checked Exception层层感染有点受不了,Date非常不好用-_-),听说Java10要有var,估计还可以少写很多代码,而且VS也要支持Java了(不是J),作为有丰富开发经验的.NET开发者,也就更加有尝试的冲动了。

最后提供demo下载

参考: <<阿里巴巴Java开发手册>> <> <> https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/ https://www.jianshu.com/u/6a622d516e32 http://spring.io/



原文创作:JeffWong

原文链接:https://www.cnblogs.com/jeffwongishandsome/p/quick-develop-rest-api-by-using-spring-boot.html

更多推荐

更多
  • Spring Boot实战-00开篇词从零开始:为什么要学习SpringBoot? 你为什么需要学习这门课程?,这门课程是如何设计的?,讲师寄语, 你好,我是鉴湘,有 10 年以上大型 Java EE 和分布架进行系统开发和维护有着丰富的实践经验。 在我的从业生涯中,曾经带过不少项目,以我所带领的电商项目开发团队为例
  • Spring Boot实战-04定制配置:如何创建和管理自定义的配置信息? 如何在应用程序中嵌入系统配置信息?,如何创建和使用自定义配置信息?,如何组织和整合配置信息?,如何覆写内置的配置类?,小结与预告,03 讲中,我们介绍了 Spring Boot ...
  • Spring Boot实战-09数据抽象:SpringData如何对数据访问过程进行统一抽象? Repository 接口及实现,多样化查询支持,Spring Data 中的组件,小结与预告, 事实上,JdbcTemplate 是相对偏底层的一个工具类,作为系统开发最重要的基础功能之一,族中另一个重要成员 Spring Data
  • Spring Boot实战-13服务调用:如何正确理解RestTemplate远程调用实现原理? 初始化 RestTemplate 实例,RestTemplate 核心执行流程,从源码解析到日常开发,小结与预告, 在 12 讲中,我们详细描述了如何使用 RestTemplate 访问 HTTP 端点的使用方法,它涉及 Res中的这些
  • Spring Boot实战-12服务调用:如何使用RestTemplate消费RESTful服务? 使用 RestTemplate 访问 HTTP 端点,实现 SpringCSS 案例中的服务交互,小结与预告,11 讲我们介绍了如何使用 Spring Boot 构建 RESTful 风格 Web 服务的实现方法,而 S 服务的构建后,
  • Spring Boot实战-结束语以终为始:SpringBoot总结和展望 Spring Boot 的创新性,Spring Boot 课程总结,Spring Boot 的发展和演进, 终于到了课程的最后一讲啦,这一讲我们将对整个 Spring Boot 课程进行总结。 Spring Boring Boot 提供
  • Spring Boot实战-08数据访问:如何剖析JdbcTemplate数据访问实现原理? 从模板方法模式和回调机制说起,JDBC API 到 JdbcTemplate 的演变,JdbcTemplate 源码解析,从源码解析到日常开发,小结与预告,07 讲中,我们介绍了使用 JdbcTemplate ...
  • Spring Boot实战-03多维配置:如何使用SpringBoot中的配置体系? 创建第一个 Spring Boot Web 应用程序,Spring Boot 中的配置体系,小结与预告, 配置体系是基于 Spring Boot 框架开发应用程序的基础,而自动配置也是该框架的核心功能之一。今eb 应用程序开始吧。 创
  • Spring Boot实战-21指标定制:如何实现自定义度量指标和Actuator端点? Actuator 中的度量指标,自定义 Actuator 端点,小结与预告,20 讲中我们引入了 Spring Boot Actuator 组件来满足 这一讲我们继续讨论如何扩展 Actuator 端点,但更多关注与度量指标相关的内容
  • Spring Boot实战-02案例驱动:如何剖析一个SpringWeb应用程序? Spring MVC VS Spring Boot,剖析一个 Spring Web 应用程序,案例驱动:SpringCSS,小结与预告, 在 01 讲中,我们提到 Spring 家族具备很多款开源框架,开发人员可以基于这些开发框架实现各种 ...
  • 近期文章

    更多
    文章目录

      推荐作者

      更多