基于Spring Boot的RESTful API实践(一)
1. RESTful简述
REST是一种设计风格,是一组约束条件及原则,而遵循REST风格的架构就称为RESTful架构,资源是RESTful的核心,一个好的RESTful架构,通过URL就能很清晰的了解其相应的操作和需求是什么,即
1. 通过URL定位资源,如:
com.mobin/api/v1/shenzhen/subways //获取深圳地铁列表
com.mobin/api/v1/shenzhen/schools //获取深圳学校列表
2. HTTP描述操作
GET:获取资源
POST:创建资源
PUT:更新资源
DELETE:删除资源
如:
GET com.mobin/api/v1/shenzhen/subways/1:获取ID为1的地铁信息
请求的资源通常都以JSON或XML等返回给Client,使用RESTful架构只需在Sever端提供一套RESTful API便能在web、IOS、Android共用
API设计是个很讲究的事情,可以参考GitHub的API设计规范
2. SpringBoot集成MyBatis
1. 将xxxMapper.xml及sqlMapConfig.xml放入resource对应目录
2. application.properties加载MyBatis配置文件及配置数据源
##application.properties
#加载mybatis配置文件
mybatis.mapper-locations = classpath:mapper/*Mapper.xml
mybatis.config-location = classpath:mapper/config/sqlMapConfig.xml
#指定别名
mybatis.type-aliases-package = com.mobin.entity
#数据源
spring.datasource.url = jdbc:postgresql://localhost:5432/xxx
spring.datasource.driver-class-name = org.postgresql.Driver
spring.datasource.username = postgres
spring.datasource.password = xxxx
MyBatis 3之后官方提供了特定的API来的支持动态SQL,可以使用注解+Java代码来替代XML,但是复杂的SQL语句还是走XML的方式,XML更直观(其实也恶心),注解的方式对于代码的侵入太严重,修改后还需要重新编译。
3. 日志配置
Spring boot默认的日志框架为Logback,配置起来相当友好具有更好的性能,还可以对指定的服务的日志进行不同级别的过滤并不影响其他服务日志的级别
1. 控制台日志配置
2. 开发、测试、生产环境的配置
##logbcak-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<contextName>${appname}</contextName>
<!--控制台日志配置-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread]%-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILEPROD" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>SpringBootRESTful.%d{yyyy-MM-dd}.log</FileNamePattern>
<!-- 日志保留天数-->
<MaxHistory>20</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread]%-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILETEST" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>test.SpringBootRESTful.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>20</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread]%-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!--开发环境的日志配置 -->
<springProfile name="dev">
<!--开发环境通常会对指定包或类进行测试 -->
<logger name="com.mobin.dao" level="DEBUG">
<appender-ref ref="STDOUT"/>
</logger>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</springProfile>
<!--测试环境的日志配置 -->
<springProfile name="test">
<root level="DEBUG">
<appender-ref ref="FILETEST"/>
<appender-ref ref="STDOUT"/>
</root>
</springProfile>
<!--生产环境的日志配置 -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="FILEINFO"/>
<appender-ref ref="STDOUT"/>
</root>
</springProfile>
</configuration>
4. 异常处理
4.1 在API设计规范中,对异常的处理至少是
1. 返回相应的错误代码
2. 返回相应的错误描述
3. 对应的资源模块
4.2 使用@RestControllerAdvice定义全局异常处理
@RestControllerAdvice是Spring 4.3之后的新特性,其相当于@ControllerAdvice+ResponseBody,所以使用@RestControllerAdvice可以将错误信息以Json的格式返回
1. 自定义异常类
##com.mobin.exception.EntityNotFoundException
//当请求的资源不存在时抛出该异常
public class EntityNotFoundException extends RuntimeException{
public EntityNotFoundException(String mes){
super(mes);
}
}
2. 定义全局异常类
##com.mobin.exception.GlobalExceptionHadlerActice
@RestControllerAdvice
public class GlobalExceptionHadlerActice {
private static final long serialVersionUID = 1L;
@ExceptionHandler(value = EntityNotFoundException.class)
public ErrorMessage entityNotFoundException(HttpServletRequest request, Exception e){
ErrorMessage errorMessage = new ErrorMessage();
errorMessage.setStatus(HttpStatus.NOT_FOUND.value());
errorMessage.setMessage(e.getLocalizedMessage());
errorMessage.setUrl(request.getRequestURL().toString());
return errorMessage;
}
}
ErrorMessage为自定义的实体类,包含statusCode,message及url字段。
3. 相应的请求方法
## com.mobin.controller.SubwayController
@RequestMapping(value="/{id}",method = RequestMethod.GET )
public SubwayResult<Subway> getSubwayByID(@PathVariable Integer id) {
SubwayResult<Subway> result = new SubwayResult();
Subway subway = subwayService.findSubwayByID(id);
if (subway == null){
throw new EntityNotFoundException("资源不存在");
}
result.setStatus(HttpStatus.OK.value());
result.setData(subway);
return result;
}
4. 通过curl进行测试
MOBIN:~ mobin$ curl -XGET -w "\n" 'localhost:8089/api/subways/1999'
{
"message":"资源不存在",
"status":404,
"url":"http://localhost:8089/api/subways/1999"
}
5. 使用fastjson
1. 引入fastJson依赖
2. 自定义WebMvcConfigurer并继承WebMvcConfigurerAdapter
3. 重写configureMessageConverters方法
4. 自定义配置FastJsonConfig
5. 将FastJsonHttpMessageConverter添加到HttpMessageConverter
相应代码:
##com.mobin.config.WebMvcConfigurer
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter{
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullBooleanAsFalse,
SerializerFeature.PrettyFormat);
converter.setDateFormat("yyyy-MM-dd HH:mm:ss");
converter.setFastJsonConfig(config);
converters.add(converter);
}
}
SerializerFeature.WriteNullListAsEmpty:List类型字段为null时输出[]而非null
SerializerFeature.WriteMapNullValue:显示空字段
SerializerFeature.WriteNullStringAsEmpty:字符串类型字段为null时间输出""而非null
SerializerFeature.WriteNullBooleanAsFalse:Boolean类型字段为null时输出false而null
SerializerFeature.PrettyFormat:美化json输出,否则会作为整行输出
解决浏览器中返回json显示乱码问题(参考自:http://blog.csdn.net/kingboyworld/article/details/70068676)
##application.properties
spring.http.encoding.charset=UTF-8
spring.http.encoding.enable=true
spring.http.encoding.force=true
6. 使用PageHelper进行分页
分页使用的是PageHelper插件,基本原理就是在Executor及mappedStatement之间对SQL语句进行拦截并对SQL添加相应的分页操作再封装传递给mappedStatement,该插件支持单表及多表的分页,使用方便,只需在SQL执行语句前加上一条分布代码即可(通常是在server层),想想如果是手动的设置SQL语句的limit和offset,分页场景一旦多了就特别恶心,即便配合MyBatis的逆向工程也是。
1. 引入Spring boot对应的PageHelper依赖
2. 在application.properties配置PageHelper
3. 在指定的SQL语句前添加分页代码
##application.properties
#指定数据库方言
pagehelper.helperDialect=postgresql
#pageNum<=0时返回第一页数据,pageNum超过总页数时返回最后一页数据
pagehelper.reasonable=true
相应代码:
##com.mobin.service.impl.SubwayServiceImpl
public List<Subway> findSubways(int pageNum,int pageSize){
//第三个参数为fales时表示不对表进行count操作
PageHelper.startPage(pageNum,pageSize,false);
return subwayMapper.findSubways();
}
项目地址:
https://github.com/MOBIN-F/SpringBootRESTful
参考资料:
How to use @RestControllerAdvice for handling Exception with RestfulApi
基于Spring Boot的RESTful API实践(一)的更多相关文章
- 使用 Spring Boot 构建 RESTful API
1. 使用 Idea 创建 Spring Initializer 项目 在创建项目的对话框中添加 Web 和 Lombok,或者建立项目后在 pom.xml 中添加依赖: <dependency ...
- Spring Boot中Restful Api的异常统一处理
我们在用Spring Boot去向前端提供Restful Api接口时,经常会遇到接口处理异常的情况,产生异常的可能原因是参数错误,空指针异常,SQL执行错误等等. 当发生这些异常时,Spring B ...
- Spring Boot构建RESTful API与单元测试
如果您对Spring MVC不熟悉并且还没有尝试过快速入门案例,建议先看一下相关的内容. @Controller:修饰class,用来创建处理http请求的对象 @RestController:Spr ...
- 用Kotlin写一个基于Spring Boot的RESTful服务
Spring太复杂了,配置这个东西简直就是浪费生命.尤其在没有什么并发压力,随便搞一个RESTful服务 让整个业务跑起来先的情况下,更是么有必要纠结在一堆的XML配置上.显然这么想的人是很多的,于是 ...
- Spring Boot构建RESTful API
@Controller:修饰class,用来创建处理http请求的对象 @RestController:Spring4之后加入的注解,原来在@Controller中返回json需要@ResponseB ...
- 通过spring boot提供restful api
1 将返回设置为produces = "application/json" 返回给客户端json格式的response. 2 对各种异常的处理 各种异常如何返回给客户端? 各种异常 ...
- 基于Spring Boot、Spring Cloud、Docker的微服务系统架构实践
由于最近公司业务需要,需要搭建基于Spring Cloud的微服务系统.遍访各大搜索引擎,发现国内资料少之又少,也难怪,国内Dubbo正统治着天下.但是,一个技术总有它的瓶颈,Dubbo也有它捉襟见肘 ...
- 基于spring boot 2.x 的 spring-cloud-admin 实践
spring cloud admin 简介 Spring Boot Admin 用于监控基于 Spring Boot 的应用,它是在 Spring Boot Actuator 的基础上提供简洁的可视化 ...
- 基于Spring Boot和Spring Cloud实现微服务架构学习
转载自:http://blog.csdn.net/enweitech/article/details/52582918 看了几周Spring相关框架的书籍和官方demo,是时候开始总结下这中间的学习感 ...
随机推荐
- BZOJ 1426: 收集邮票 [DP 期望 平方]
传送门 题意: 有n种不同的邮票,皮皮想收集所有种类的邮票.唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是n种邮票中的哪一种是等概率的,概率均为1/n.但是由于凡凡也很喜欢邮 ...
- BZOJ 3790: 神奇项链 [Manacher 贪心]
3790: 神奇项链 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 405 Solved: 200[Submit][Status][Discuss] ...
- ajax请求 readyState为0 可能原因之一
问题:同样的代码逻辑,PC端和iOS都能正常访问,但是Android系统请求都是报错: 上网查阅,关于ajax请求失败且状态码都是0的情况有很多,最后排查的原因是:域名证书问题:
- Java并发编程Semaphore
信号量 信号量类Semaphore,用来保护对唯一共享资源的访问.一个简单的打印队列,并发任务进行打印,加入信号量同时之能有一个线程进行打印任务 . import java.util.concurre ...
- mac 上node.js环境的安装与测试
如果大家之前做过web服务器的人都知道,nginx+lua与现在流行的Node.js都是可以做web服务器的,前者在程序的写法和配置上要比后者麻烦,但用起来都是差不多.在这里建议大家如果对lua脚本语 ...
- Spring MVC 原理
一.什么是springmvc springMVC是spring框架的一个模块,springMVC和spring无需通过中间整合层进行开发. springMVC是一个基于mvc的web框架. Sprin ...
- MysqL 主从事务数据安全之sync_binlog
sync_binlog:是MySQL 的二进制日志(binary log)同步到磁盘的频率(刷新二进制日志到磁盘),默认是0,意味着mysql并不刷新,由操作系统自己决定什么时候刷新缓存到持久化设置, ...
- php的ob函数实现页面静态化
首先介绍一下php中ob缓存常用到的几个常用函数ob_start():开启缓存机制ob_get_contents():获取ob缓存中的内容ob_clean()清除ob缓存中的内容,但不关闭缓存ob_e ...
- C#中await和async关键字的简单理解
C# 5.0之后,为了简化异步编程,引入了异步函数的概念,也就是方法标记async,然后可以使用await表达式来等待异步操作返回. await关键字看起来是一个阻塞线程的调用,但是实际上执行到awa ...
- Jquery就是这么简单
什么是Jquery? Jquey就是一款跨主流浏览器的JavaScript库,简化JavaScript对HTML操作 就是封装了JavaScript,能够简化我们写代码的一个JavaScript库 为 ...