spark restful_使用Spark构建简单的RESTful API

spark restful

免责声明 :这篇文章是关于名为Spark的Java微型Web框架的,而不是关于数据处理引擎Apache Spark的 。

在此博客文章中,我们将看到如何使用Spark构建简单的Web服务。 如免责声明中所述,Spark是受Ruby框架Sinatra启发的Java微型Web框架。 Spark的目的是简化操作,仅提供最少的功能集。 但是,它提供了用几行Java代码构建Web应用程序所需的一切。


入门

假设我们有一个带有一些属性的简单域类和一个提供一些基本CRUD功能的服务:

public class User {private String id;private String name;private String email;// getter/setter
}
public class UserService {// returns a list of all userspublic List<User> getAllUsers() { .. }// returns a single user by idpublic User getUser(String id) { .. }// creates a new userpublic User createUser(String name, String email) { .. }// updates an existing userpublic User updateUser(String id, String name, String email) { .. }
}

现在,我们希望将UserService的功能公开为RESTful API(为简单起见,我们将跳过REST的超媒体部分)。 为了访问,创建和更新用户对象,我们要使用以下URL模式:

得到 /用户 获取所有用户的列表
得到 / users / <id> 获取特定用户
开机自检 /用户 创建一个新用户
/ users / <id> 更新用户

返回的数据应为JSON格式。

要开始使用Spark,我们需要以下Maven依赖项:

<dependency><groupId>com.sparkjava</groupId><artifactId>spark-core</artifactId><version>2.0.0</version>
</dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.7</version>
</dependency>

Spark使用SLF4J进行日志记录,因此我们需要SLF4J活页夹才能查看日志和错误消息。 在此示例中,我们为此目的使用slf4j-simple依赖项。 但是,您也可以使用Log4j或您喜欢的任何其他绑定程序。 在类路径中使用slf4j-simple足以在控制台中查看日志输出。

我们还将使用GSON生成JSON输出,并使用JUnit编写简单的集成测试。 您可以在完整的pom.xml中找到这些依赖项。

返回所有用户

现在该创建一个负责处理传入请求的类了。 我们首先实现GET / users请求,该请求应返回所有用户的列表。

import static spark.Spark.*;public class UserController {public UserController(final UserService userService) {get("/users", new Route() {@Overridepublic Object handle(Request request, Response response) {// process requestreturn userService.getAllUsers();}});// more routes}
}

注意第一行中的spark.Spark。*的静态导入。 这使我们可以访问各种静态方法,包括get(),post(),put()等。 在构造函数中,get()方法用于注册一个Route,该Route侦听/ users上的GET请求。 路由负责处理请求。 每当发出GET / users请求时,都会调用handle()方法。 在handle()内部,我们返回一个应发送给客户端的对象(在本例中为所有用户的列表)。

Spark从Java 8 Lambda表达式中受益匪浅。 Route是一个功能性接口(仅包含一种方法),因此我们可以使用Java 8 Lambda表达式来实现它。 使用Lambda表达式,上面的Route定义如下所示:

get("/users", (req, res) -> userService.getAllUsers());

要启动该应用程序,我们必须创建一个简单的main()方法。 在main()内部,我们创建服务的实例,并将其传递给我们新创建的UserController:

public class Main {public static void main(String[] args) {new UserController(new UserService());}
}

如果现在运行main(),Spark将启动一个侦听端口4567的嵌入式Jetty服务器。我们可以通过启动GET http:// localhost:4567 / users请求来测试我们的第一个路由。

如果服务返回包含两个用户对象的列表,则响应主体可能如下所示:

[com.mscharhag.sparkdemo.User@449c23fd, com.mscharhag.sparkdemo.User@437b26fe]

显然,这不是我们想要的回应。

Spark使用名为ResponseTransformer的接口将路由返回的对象转换为实际的HTTP响应。
ReponseTransformer看起来像这样:

public interface ResponseTransformer {String render(Object model) throws Exception;
}

ResponseTransformer具有使用一个对象并返回此对象的String表示形式的单个方法。 ResponseTransformer的默认实现只是在传递的对象上调用toString()(它创建如上所示的输出)。

由于我们要返回JSON,因此我们必须创建一个ResponseTransformer,将传递的对象转换为JSON。 为此,我们使用一个带有两个静态方法的小型JsonUtil类:

public class JsonUtil {public static String toJson(Object object) {return new Gson().toJson(object);}public static ResponseTransformer json() {return JsonUtil::toJson;}
}

toJson()是一种通用方法,可以使用GSON将对象转换为JSON。 第二种方法利用Java 8方法引用来返回ResponseTransformer实例。 ResponseTransformer还是一个功能接口,因此可以通过提供适当的方法实现(toJson())来满足它。 因此,每当我们调用json()时,我们都会获得一个新的ResponseTransformer,它利用了我们的toJson()方法。

在我们的UserController中,我们可以将ResponseTransformer作为第三个参数传递给Spark的get()方法:

import static com.mscharhag.sparkdemo.JsonUtil.*;public class UserController {public UserController(final UserService userService) {get("/users", (req, res) -> userService.getAllUsers(), json());...}
}

再次注意第一行中JsonUtil。*的静态导入。 这使我们可以选择仅通过调用json()来创建新的ResponseTransformer。

现在,我们的响应如下所示:

[{"id": "1866d959-4a52-4409-afc8-4f09896f38b2","name": "john","email": "john@foobar.com"
},{"id": "90d965ad-5bdf-455d-9808-c38b72a5181a","name": "anna","email": "anna@foobar.com"
}]

我们还有一个小问题。 返回的响应带有错误的Content-Type 。 为了解决这个问题,我们可以注册一个设置JSON Content-Type的Filter:

after((req, res) -> {res.type("application/json");
});

过滤器还是一个功能接口,因此可以通过一个简短的Lambda表达式实现。 在我们的Route处理完请求后,过滤器会将每个响应的Content-Type更改为application / json。 我们还可以使用before()代替after()来注册过滤器。 然后,在路由处理请求之前,将调用过滤器。

GET / users请求现在应该可以工作了!

返回特定用户

要返回特定用户,我们只需在UserController中创建一条新路由:

get("/users/:id", (req, res) -> {String id = req.params(":id");User user = userService.getUser(id);if (user != null) {return user;}res.status(400);return new ResponseError("No user with id '%s' found", id);
}, json());

使用req.params(“:id”),我们可以从URL获取:id路径参数。 我们将此参数传递给我们的服务以获取相应的用户对象。 如果未找到具有传递ID的用户,则假定服务返回null。 在这种情况下,我们将HTTP状态代码更改为400(错误请求)并返回一个错误对象。

ResponseError是一个小的帮助程序类,我们用于将错误消息和异常转换为JSON。 看起来像这样:

public class ResponseError {private String message;public ResponseError(String message, String... args) {this.message = String.format(message, args);}public ResponseError(Exception e) {this.message = e.getMessage();}public String getMessage() {return this.message;}
}

现在,我们可以使用以下请求查询单个用户:

GET / users / 5f45a4ff-35a7-47e8-b731-4339c84962be

如果存在具有此ID的用户,我们将收到如下所示的响应:

{"id": "5f45a4ff-35a7-47e8-b731-4339c84962be","name": "john","email": "john@foobar.com"
}

如果我们使用无效的用户ID,将创建ResponseError对象并将其转换为JSON。 在这种情况下,响应如下所示:

{"message": "No user with id 'foo' found"
}

创建和更新用户

创建和更新用户非常容易。 就像返回所有用户的列表一样,这是通过单个服务调用完成的:

post("/users", (req, res) -> userService.createUser(req.queryParams("name"),req.queryParams("email")
), json());put("/users/:id", (req, res) -> userService.updateUser(req.params(":id"),req.queryParams("name"),req.queryParams("email")
), json());

要为HTTP POST或PUT请求注册路由,我们只需使用Spark的静态post()和put()方法。 在Route内部,我们可以使用req.queryParams()访问HTTP POST参数。

为了简单起见(并显示另一个Spark功能),我们不在路由内进行任何验证。 相反,我们假设如果传入无效值,则服务将引发IllegalArgumentException。

Spark为我们提供了注册ExceptionHandlers的选项。 如果在处理路由时引发Exception,则将调用ExceptionHandler。 ExceptionHandler是我们可以使用Java 8 Lambda表达式实现的另一个单一方法接口:

exception(IllegalArgumentException.class, (e, req, res) -> {res.status(400);res.body(toJson(new ResponseError(e)));
});

在这里,我们创建一个ExceptionHandler,如果抛出IllegalArgumentException则调用它。 捕获的Exception对象作为第一个参数传递。 我们将响应代码设置为400,并在响应正文中添加一条错误消息。

如果当email参数为空时服务抛出IllegalArgumentException,我们可能会收到如下响应:

{"message": "Parameter 'email' cannot be empty"
}

控制器的完整资源可以在这里找到。

测试中

由于Spark的简单性质,因此为示例应用程序编写集成测试非常容易。

让我们从基本的JUnit测试设置开始:

public class UserControllerIntegrationTest {@BeforeClasspublic static void beforeClass() {Main.main(null);}@AfterClasspublic static void afterClass() {Spark.stop();}...
}

在beforeClass()中,我们通过简单地运行main()方法来启动应用程序。 所有测试完成后,我们调用Spark.stop()。 这将停止运行我们的应用程序的嵌入式服务器。

之后,我们可以在测试方法中发送HTTP请求,并验证我们的应用程序返回了正确的响应。 发送请求创建新用户的简单测试如下所示:

@Test
public void aNewUserShouldBeCreated() {TestResponse res = request("POST", "/users?name=john&email=john@foobar.com");Map<String, String> json = res.json();assertEquals(200, res.status);assertEquals("john", json.get("name"));assertEquals("john@foobar.com", json.get("email"));assertNotNull(json.get("id"));
}

request()和TestResponse是两个小型的自制测试实用程序。 request()将HTTP请求发送到传递的URL,并返回TestResponse实例。 TestResponse只是一些HTTP响应数据的小包装。 request()和TestResponse的源包含在GitHub上的完整测试类中 。

结论

与其他Web框架相比,Spark仅提供了少量功能。 但是,它是如此简单,您可以在几分钟之内构建小型Web应用程序(即使您以前从未使用过Spark)。 如果您想研究Spark,则应该清楚地使用Java 8,它减少了您必须编写的代码量。

  • 您可以在GitHub上找到示例项目的完整源代码。

翻译自: https://www.javacodegeeks.com/2014/06/building-a-simple-restful-api-with-spark.html

spark restful

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/342187.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何正确使用工业级交换机?

工业交换机具有电信级性能特征&#xff0c;可耐受严苛的工作环境&#xff0c;产品系列丰富&#xff0c;端口配置灵活&#xff0c;可满足各种工业领域的使用需求。那么&#xff0c;我们在使用工业级交换机的过程中该如何正确使用呢&#xff1f;接下来就跟随飞畅科技的小编一起来…

[渝粤教育] 盐城工学院 无机及分析化学C 参考 资料

教育 -无机及分析化学C-章节资料考试资料-盐城工学院【】 第一章 线上单元作业 第一章 单元测验 1、【单选题】下列数据中有效数字为四位的是 A、0.017 B、0.5810 C、0.202 D、pH11.21 参考资料【 】 2、【单选题】以下测量数据明确为4位有效数字的是 A、pKb 5.652 B、5010 C、…

更好的默认NullPointerException消息是否会传入Java?

我最近对OpenJDK core-libs-dev邮件列表上的2019年 2月至2019年 3月的讨论感兴趣&#xff0c;该讨论涉及解决缺少与NullPointerException相关联的详细消息的问题&#xff0c;该消息在用其无参数构造函数实例化后抛出。 这是我在使用Java时经常遇到的一个问题&#xff0c;甚至导…

什么是工业光纤环网交换机?

环网交换机就是可以组建环形网络的交换机&#xff0c;与其他类型交换机相比&#xff0c;具有稳定、自愈时间段等优点。每个环网交换机上有两个用于组环的端口&#xff0c;交换机之间通过手拉手形式构成了环形的网络拓扑。此外&#xff0c;环网交换机采用了某些特殊技术&#xf…

[渝粤教育] 苏州大学文正学院 网络互联技术与实践 参考 资料

教育 -网络互联技术与实践-章节资料考试资料-苏州大学文正学院【】 计算机网络互联设备随堂测验 1、【单选题】网桥处理的是 A、脉冲信号 B、MAC 帧 C、IP 包 D、ATM 包 参考资料【 】 2、【单选题】交换机工作在 OSI 七层的哪一层 A、一层 B、二层 C、三层 D、三层以上 参考资…

什么是工业级交换机?工业交换机作用有哪些?

最近有很多朋友来问我&#xff0c;什么是工业级交换机&#xff0c;跟商用交换机有什么区别。今天&#xff0c;咱们在这里具体来介绍下什么是工业交换机。工业交换机&#xff0c;即应用于工业控制领域的以太网交换机设备&#xff0c;无论是在性能还是作用方面都与普通交换机有很…

[渝粤教育] 西北大学 数据结构 参考 资料

教育 -数据结构-章节资料考试资料-西北大学【】 数据结构的基础概念随堂测验 1、【单选题】一个抽象类型包括数据对象、 和一组处理数据的操作。 A、数据对象中各元素间的结构关系 B、数据元素集 C、接口 D、数据对象集 参考资料【 】 2、【填空题】抽象数据类型具有 、信息隐蔽…

Spring Boot CommandLineRunner和ApplicationRunner

在本快速教程中&#xff0c;我们将探索Spring Boot中两个非常流行的界面&#xff1a; CommandLineRunner和ApplicationRunner 。 这些接口的一种常见用例是在应用程序启动时加载一些静态数据。 虽然&#xff0c;我看到这种用法主要用于测试数据设置。 它们都是带有run&#x…

visualvm远程jvm_如何使用VisualVM监视服务器上的多个JVM

visualvm远程jvm在上一篇文章中&#xff0c;我向您展示了如何使用单个管理员服务器和多个托管服务器启动WebLogic Server。 这些启动之后&#xff0c;您如何检查它们的健康状况&#xff1f; 您可以使用管理员的/ console网络应用。 但是&#xff0c;所有默认Oracle / Open JDK …

[渝粤教育] 西南石油大学 岩体力学 参考 资料

教育 -岩体力学-章节资料考试资料-西南石油大学【】 第一章测试 1、【单选题】大部分岩体属于&#xff08; &#xff09;。 A、均质连续材料 B、非均质材料 C、非连续材料 D、非均质、非连续、各向异性材料 参考资料【 】 2、【单选题】岩石的弹性模量一般指&#xff08; &…

如何区别标准POE交换机和非标POE交换机

通俗的说&#xff0c;POE交换机就是支持网线供电的交换机&#xff0c;其不但可以实现普通交换机的数据传输功能还能同时对网络终端进行供电。那么&#xff0c;我们该如何来区别如何区别标准POE交换机和非标POE交换机呢&#xff1f;接下来我们就跟随飞畅科技的小编一起来详细看看…

[渝粤教育] 西安电子科技大学 工程制图与计算机绘图 参考 资料

教育 -工程制图与计算机绘图-章节资料考试资料-西安电子科技大学【】 *****单元测验–国家制图标准的基本规定 1、【单选题】绘图比例包括原值、放大比例、缩小比例&#xff0c;优先选择&#xff1a; A、原值 B、缩小比例 C、放大比例 D、无所谓 参考资料【 】 2、【单选题】细…

Spring Boot退出代码–创建自定义退出代码

当运行Spring Boot应用程序时&#xff0c;一切正常&#xff0c;我们将获得系统退出代码0 。 对于任何未处理的异常&#xff0c;应用程序将返回退出代码1 。 我们有可能从Spring Boot应用程序返回自定义退出代码。 在本教程中&#xff0c;我们将学习如何做。 实现 让我们从创建…

[渝粤教育] 郑州升达经贸管理学院 大学英语混合式课程 参考 资料

教育 -大学英语混合式课程-章节资料考试资料-郑州升达经贸管理学院【】 Quiz 1、【多选题】According to the clip, what are the major sources of the English words?(从电影中&#xff0c;你了解到英语词汇主要来自于哪些语言&#xff1f;) A、Latin B、Japanese C、Greek …

如何挑选一款合适的POE工业级交换机?

由于工业级交换机能够耐受各种比较苛刻的作业环境&#xff0c;而且产品系列多&#xff0c;端口装备灵敏&#xff0c;能够满足各种工业操控范畴的运用需求&#xff0c;因此在电力、冶金、石化、环保、交通、建筑等行业领域应用非常的广泛&#xff0c;各行各业信息化的建造对工业…

建设IPTV电视系统是否有必要?

随着信息化、智能化时代的发展&#xff0c;传统意义上的竞争方式和经营管理模式都在经营变革&#xff0c;建设IPTV电视系统及方案是否有必要&#xff1f; 下面我们先以几个场所为例&#xff0c;看看建设IPTV电视系统到底有什么用&#xff1f; 酒店 统一前端管理&#xff0c;方…

[渝粤教育] 郑州航空工业管理学院 航空概论 参考 资料

教育 -航空概论-章节资料考试资料-郑州航空工业管理学院【】 第1部分单元作业 第1部分单元测验 1、【单选题】航空是指载人或不载人的飞行器在地球 的航行活动。 A、高空 B、大气层内 C、宇宙 D、大气层外 参考资料【 】 2、【单选题】轻于空气的航空器靠 升空。 A、与空气相对…

高效的企业测试-工作流和代码质量(4/6)

本文的这一部分将讨论在开发过程中拥有有效工作流程的影响&#xff0c;以及适当的测试代码质量如何使我们能够创建可维护的测试&#xff0c;尤其是对于复杂项目。 开发工作流程和管道 编程是一项流程活动&#xff0c;我们开发人员应该对保持工作流程高效和缩短周转时间感兴趣…

飞畅科技-图解交换机接口及连接方式

局域网交换机作为局域网的集中连接设备&#xff0c;它的接口类型是随着各种局域网和传输介质类型的发展而变化的&#xff0c;交换机的许多接口与路由器接口完全一样。接下来就由杭州飞畅的小编来为大家介绍下交换机的接口类型以及连接方式有哪些&#xff1f;一起来看看吧&#…

[渝粤教育] 重庆工业职业技术学院 汽车安全与舒适系统维修 参考 资料

教育 -汽车安全与舒适系统维修-章节资料考试资料-重庆工业职业技术学院【】 认识汽车数据总线系统 1、【单选题】开发CAN总线的公司是 A、西门子 B、摩托罗拉 C、BOSCH D、爱立信 参考资料【 】 2、【单选题】本地内部连接网络&#xff0c;又称“局域子系统”的英文缩写是 A、L…