SpringBoot快速开发REST服务最佳实践
一、为什么选择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>
数据库驱动:
MySQL:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
SQLServer:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.4.0.jre8</version>
</dependency>
隆重公告,微软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
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 = #{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 = #{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 = #{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=#{disabled} WHERE GoodsId=#{goodsId} </insert> <insert id="deleteGoods" parameterType="java.lang.String"> DELETE FROM Goods WHERE GoodsId=#{goodsId} </insert> </mapper>
最后,在应用程序入口,添加一行注解:
// 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>
需要在应用程序入口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());//
System.out.println(GoodsType.Discount.ordinal());// System.out.println(goodsType.getCode());
System.out.println(goodsType.getDescription()); Assert.isTrue(goodsType.getCode() == 1024, "折扣商品Code为1024"); }
}
如果需要单元测试的方法需要配置文件,那么test下也要有resources目录用于存放资源文件。
本文demo提供了完整的各层单元测试方法,大家可以参考下。
总结:使用Spring Boot全家桶,你可以快速上手开发Java的REST接口应用,配合Java8+的相关新特性,写Java也越来越省心(虽然Java8的lambda比较难受,Checked Exception层层感染有点受不了,Date非常不好用-_-),听说Java10要有var,估计还可以少写很多代码,而且VS也要支持Java了(不是J#),作为有丰富开发经验的.NET开发者,也就更加有尝试的冲动了。
最后提供demo下载。
参考:
<<阿里巴巴Java开发手册>>
<<Spring in Action>>
<<Spring Boot in Action>>
https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/
https://www.jianshu.com/u/6a622d516e32
SpringBoot快速开发REST服务最佳实践的更多相关文章
- RESTful服务最佳实践
本文主要读者 引言 REST是什么 统一接口 基于资源 通过表征来操作资源 自描述的信息 超媒体即应用状态引擎(HATEOAS) 无状态 可缓存 C-S架构 分层系统 按需编码(可选) REST快速提 ...
- RESTful服务最佳实践(转)
原文:https://www.cnblogs.com/jaxu/p/7908111.html 译文作者:Jaxu 英文原文:https://files-cdn.cnblogs.com/files/ja ...
- 我们必须要知道的RESTful服务最佳实践
看过很多RESTful相关的文章总结,参齐不齐,结合工作中的使用,非常有必要归纳一下关于RESTful架构方式了,RESTful只是一种架构方式的约束,给出一种约定的标准,完全严格遵守RESTful标 ...
- LBPL--基于Asp.net、 quartz.net 快速开发定时服务的插件化项目
LBPL 这一个基于Asp.net. quartz.net 快速开发定时服务的插件化项目 由于在实际项目开发中需要做定时服务的操作,大体上可以理解为:需要动态化监控定时任务的调度系统. 为了实现快速开 ...
- 在ASP.NET Core中使用Apworks快速开发数据服务
不少关注我博客的朋友都知道我在2009年左右开发过一个名为Apworks的企业级应用程序开发框架,旨在为分布式企业系统软件开发提供面向领域驱动(DDD)的框架级别的解决方案,并对多种系统架构风格提供支 ...
- springboot 快速开发的定制补充
增强 SpringBoot 快速开发工具 项目地址:https://gitee.com/sanri/web-ui 优点:这是一个 web 通用配置的组件,即插即用,可用于新项目或私活.是对 Sprin ...
- Typescript 开发环境的最佳实践
Typescript 开发环境的最佳实践 0️⃣ git init(略) 1️⃣️️ 初始化:$ yarn add -D ts-node typescript 2️⃣ 生成 tsconfig.json ...
- SpringBoot 快速构建微服务体系 知识点总结
可以通过http://start.spring.io/构建一个SpringBoot的脚手架项目 一.微服务 1.SpringBoot是一个可使用Java构建微服务的微框架. 2.微服务就是要倡导大家尽 ...
- 001-RESTful服务最佳实践-RestFul准则、HTTP动词表示含义、合理的资源命名、响应格式XML和JSON
一.概述 因为REST是一种架构风格而不是严格的标准,所以它可以灵活地实现.由于这种灵活性和结构自由度,对设计最佳实践也有很大的差异. API的方向是从应用程序开发人员的角度考虑设计选择. 幂等性 不 ...
随机推荐
- Bind、Apply、Call三者的区别
1)bind与apply.call 的最大区别就是:bind不会立即调用,其他两个会立即调用 var fn = { _int: function(){return 3}, fun: function( ...
- vxworks下文件读写示例
dev 1.create file on floopy disk and write contents: -> pdev=fdDevCreate(0,0,0,0) /* A:,1.44M ...
- php出现Can't use function return value in write context
<?php if(session('uid')){ }else{ } ?> 在用empty判断值为空的时候,报了这个Can't use function return value in w ...
- Caused by: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Truncated incorrect DOUBLE value: 'L
1.错误描述 [ERROR:]2015-06-08 09:49:42,523 [异常拦截] org.hibernate.exception.DataException: error executing ...
- freemarker报错之六
1.错误描述 五月 28, 2014 10:32:40 下午 freemarker.log.JDK14LoggerFactory$JDK14Logger error 严重: Template proc ...
- OpenStack_I版 5.Nova部署
Nova安装 创建配置存放目录,日志存放目录,执行文件目录,虚拟机目录 Nova配置修改 生成主配置文件 创建Nova数据库 同步Nova数据库 验证 Nova连接RabbitMQ配置修改 key ...
- 第二个scala程序
计算昨日收益,读取hdfs文件,使用临时表sqlcontext进行计算,结果保存于mysql中. 之前考虑过将结果存储于Hbase中,由于各种原因及问题,在加上数据量真的很小很小,就改成mysql了. ...
- 分类导航菜单的制作(附源码)--HTML
不多说,直接贴代码哈!有疑问,可追加评论哈! demo.html: <!DOCTYPE html><html> <head> <title>分类导航菜单 ...
- iOS 双击tabbar刷新页面
/*在继承UITabBarController控制器中*/ #pragma mark <UITabBarControllerDelegate> -(void)tabBarControlle ...
- linux命令类型及执行顺序
一 为什么要使用命令行 当初级Linux用户面对缺乏图形界面的Linux时很多人都会抱怨:为何要死守命令行?为什么不采用人机互交好.更简单的图形界面呢?事实上,图形界面在某些任务方面确实高效而且简 ...