当前位置: 首页 > news >正文

使用 Spark Java 框架构建 API

1.简介

在本文中,我们将快速介绍Spark 框架。Spark 框架是一个快速开发的 Web 框架,其灵感来自 Ruby 的 Sinatra 框架,并围绕 Java 8 Lambda 表达式理念构建,使其比使用其他 Java 框架编写的大多数应用程序更简洁。

如果您想在使用 Java 开发 Web API 或微服务时获得类似Node.js的体验,这是一个不错的选择。使用 Spark,您只需不到 10 行代码就可以准备好提供 JSON 的 REST API。

我们将从一个“Hello World”示例快速开始,然后是一个简单的 REST API。

2.Maven依赖

2.1。星火框架

在pom.xml中包含以下 Maven 依赖项:

<dependency>
    <groupId>com.sparkjava</groupId>
    <artifactId>spark-core</artifactId>
    <version>2.5.4</version>
</dependency>

您可以在Maven Central上找到最新版本的 Spark 。

2.2. 格森图书馆

在示例中的各个地方,我们将使用 Gson 库进行 JSON 操作。要在您的项目中包含 Gson,请在您的pom.xml中包含此依赖项:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.0</version>
</dependency>

您可以在Maven Central上找到最新版本的 Gson 。

3. Spark 框架入门

让我们看一下 Spark 应用程序的基本构建块,并演示一个快速 Web 服务。

3.1。路线

Spark Java 中的 Web 服务建立在路由及其处理程序之上。路由是 Spark 中必不可少的元素。根据文档,每条路由都由三个简单的部分组成——动词路径回调

  1. 动词是对应于 HTTP 方法的方法。动词方法包括:get、post、put、delete、head、trace、connectoptions
  2. 路径(也称为路由模式)确定路由应该监听哪些 URI 并提供响应
  3. 回调是一个处理函数,为给定的动词和路径调用,以便生成并返回对相应 HTTP 请求的响应。回调将请求对象和响应对象作为参数

在这里,我们展示了使用get动词的路由的基本结构:

get("/your-route-path/", (request, response) -> {
    // your callback code
});

3.2. 你好世界API

让我们创建一个简单的 Web 服务,它有两条 GET 请求路由并返回“Hello”消息作为响应。这些路由使用get方法,这是从类spark.Spark的静态导入:

import static spark.Spark.*;

public class HelloWorldService {
    public static void main(String[] args) {
 
        get("/hello", (req, res)->"Hello, world");
        
        get("/hello/:name", (req,res)->{
            return "Hello, "+ req.params(":name");
        });
    }
}

get方法的第一个参数是路由的路径。第一个路由包含一个静态路径,仅代表一个 URI(“/hello”)。

第二条路由的路径(“/hello/:name” )包含“name”参数的占位符,通过在参数前面加上冒号(“:”)来表示。将调用此路由以响应对 URI 的 GET 请求,例如“/hello/Joe”“/hello/Mary”

get方法的第二个参数是一个lambda 表达式,为该框架提供了函数式编程风格。

lambda 表达式将请求和响应作为参数并帮助返回响应。我们将把控制器逻辑放在 REST API 路由的 lambda 表达式中,我们将在本教程后面看到。

3.3. 测试 Hello World API

将HelloWorldService类作为普通 Java 类运行后,您将能够使用上述get方法定义的路由在其默认端口4567上访问该服务。

让我们看看第一个路由的请求和响应:

要求:

GET http://localhost:4567/hello

回复:

Hello, world

让我们测试第二条路由,在其路径中传递name参数:

要求:

GET http://localhost:4567/hello/baeldung

回复:

Hello, baeldung

了解如何使用 URI 中文本“baeldung”的位置来匹配路由模式“/hello/:name” ——导致调用第二个路由的回调处理函数。

4. 设计一个 RESTful 服务

在本节中,我们将为以下用户实体设计一个简单的 REST Web 服务:

public class User {
    private String id;
    private String firstName;
    private String lastName;
    private String email;

    // constructors, getters and setters
}

4.1。路线

让我们列出构成我们 API 的路由:

  • GET /users — 获取所有用户的列表
  • GET /users/:id — 获取给定 id 的用户
  • POST /users/:id — 添加用户
  • PUT /users/:id — 编辑特定用户
  • 选项 /users/:id — 检查是否存在具有给定 id 的用户
  • DELETE /users/:id — 删除特定用户

4.2. 用户服务

下面是为User实体声明 CRUD 操作的UserService接口:

public interface UserService {
 
    public void addUser (User user);
    
    public Collection<User> getUsers ();
    public User getUser (String id);
    
    public User editUser (User user) 
      throws UserException;
    
    public void deleteUser (String id);
    
    public boolean userExist (String id);
}

出于演示目的,我们在 GitHub 代码中提供了这个UserService接口的Map实现来模拟持久性。您可以使用您选择的数据库和持久层来提供您自己的实现。

4.3. JSON 响应结构

下面是我们的 REST 服务中使用的响应的 JSON 结构:

{
    status: <STATUS>
    message: <TEXT-MESSAGE>
    data: <JSON-OBJECT>
}

状态字段值可以是SUCCESSERRORdata字段将包含返回数据的 JSON 表示,例如User或Users集合。

当没有返回数据,或者状态ERROR时,我们将填充消息字段以传达错误或缺少返回数据的原因。

让我们用一个 Java 类来表示上面的 JSON 结构:

public class StandardResponse {
 
    private StatusResponse status;
    private String message;
    private JsonElement data;
    
    public StandardResponse(StatusResponse status) {
        // ...
    }
    public StandardResponse(StatusResponse status, String message) {
        // ...
    }
    public StandardResponse(StatusResponse status, JsonElement data) {
        // ...
    }
    
    // getters and setters
}

其中StatusResponse是一个枚举,定义如下:

public enum StatusResponse {
    SUCCESS ("Success"),
    ERROR ("Error");
 
    private String status;       
    // constructors, getters
}

5. 实现 RESTful 服务

现在让我们为我们的 REST API 实现路由和处理程序。

5.1。创建控制器

以下 Java 类包含我们 API 的路由,包括动词和路径以及每个路由的处理程序大纲:

public class SparkRestExample {
    public static void main(String[] args) {
        post("/users", (request, response) -> {
            //...
        });
        get("/users", (request, response) -> {
            //...
        });
        get("/users/:id", (request, response) -> {
            //...
        });
        put("/users/:id", (request, response) -> {
            //...
        });
        delete("/users/:id", (request, response) -> {
            //...
        });
        options("/users/:id", (request, response) -> {
            //...
        });
    }
}

我们将在以下小节中展示每个路由处理程序的完整实现。

5.2. 添加用户

下面是post方法响应处理程序,它将添加一个User

post("/users", (request, response) -> {
    response.type("application/json");
    User user = new Gson().fromJson(request.body(), User.class);
    userService.addUser(user);

    return new Gson()
      .toJson(new StandardResponse(StatusResponse.SUCCESS));
});

注意:在此示例中,用户对象的 JSON 表示作为 POST 请求的原始正文传递。

让我们测试一下路线:

要求:

POST http://localhost:4567/users
{
    "id": "1012", 
    "email": "your-email@your-domain.com", 
    "firstName": "Mac",
    "lastName": "Mason1"
}

回复:

{
    "status":"SUCCESS"
}

5.3. 获取所有用户

下面是从UserService返回所有用户的get方法响应处理程序:

get("/users", (request, response) -> {
    response.type("application/json");
    return new Gson().toJson(
      new StandardResponse(StatusResponse.SUCCESS,new Gson()
        .toJsonTree(userService.getUsers())));
});

现在让我们测试一下路线:

要求:

GET http://localhost:4567/users

回复:

{
    "status":"SUCCESS",
    "data":[
        {
            "id":"1014",
            "firstName":"John",
            "lastName":"Miller",
            "email":"your-email@your-domain.com"
        },
        {
            "id":"1012",
            "firstName":"Mac",
            "lastName":"Mason1",
            "email":"your-email@your-domain.com"
        }
    ]
}

5.4. 按 ID 获取用户

下面是get方法响应处理程序,它返回具有给定id的User

get("/users/:id", (request, response) -> {
    response.type("application/json");
    return new Gson().toJson(
      new StandardResponse(StatusResponse.SUCCESS,new Gson()
        .toJsonTree(userService.getUser(request.params(":id")))));
});

现在让我们测试一下路线:

要求:

GET http://localhost:4567/users/1012

回复:

{
    "status":"SUCCESS",
    "data":{
        "id":"1012",
        "firstName":"Mac",
        "lastName":"Mason1",
        "email":"your-email@your-domain.com"
    }
}

5.5. 编辑用户

下面是put方法响应处理程序,它编辑具有路由模式中提供的id的用户:

put("/users/:id", (request, response) -> {
    response.type("application/json");
    User toEdit = new Gson().fromJson(request.body(), User.class);
    User editedUser = userService.editUser(toEdit);
            
    if (editedUser != null) {
        return new Gson().toJson(
          new StandardResponse(StatusResponse.SUCCESS,new Gson()
            .toJsonTree(editedUser)));
    } else {
        return new Gson().toJson(
          new StandardResponse(StatusResponse.ERROR,new Gson()
            .toJson("User not found or error in edit")));
    }
});

注意:在此示例中,数据作为 JSON 对象在 POST 请求的原始正文中传递,其属性名称与要编辑的用户对象的字段匹配。

让我们测试一下路线:

要求:

PUT http://localhost:4567/users/1012
{
    "lastName": "Mason"
}

回复:

{
    "status":"SUCCESS",
    "data":{
        "id":"1012",
        "firstName":"Mac",
        "lastName":"Mason",
        "email":"your-email@your-domain.com"
    }
}

5.6. 删除用户

下面是删除方法响应处理程序,它将删除具有给定id的用户

delete("/users/:id", (request, response) -> {
    response.type("application/json");
    userService.deleteUser(request.params(":id"));
    return new Gson().toJson(
      new StandardResponse(StatusResponse.SUCCESS, "user deleted"));
});

现在,让我们测试一下路线:

要求:

DELETE http://localhost:4567/users/1012

回复:

{
    "status":"SUCCESS",
    "message":"user deleted"
}

5.7. 检查用户是否存在

options方法是条件检查的不错选择。下面是options方法响应处理程序,它将检查具有给定id的用户是否存在:

options("/users/:id", (request, response) -> {
    response.type("application/json");
    return new Gson().toJson(
      new StandardResponse(StatusResponse.SUCCESS, 
        (userService.userExist(
          request.params(":id"))) ? "User exists" : "User does not exists" ));
});

现在让我们测试一下路线:

要求:

OPTIONS http://localhost:4567/users/1012

回复:

{
    "status":"SUCCESS",
    "message":"User exists"
}

6.结论

在本文中,我们快速介绍了用于快速 Web 开发的 Spark 框架。

该框架主要用于在 Java 中生成微服务。具有 Java 知识且想要利用基于 JVM 库构建的库的Node.js开发人员应该对使用此框架感到宾至如归。

和往常一样,您可以在Github 项目中找到本教程的所有资源。

相关文章:

  • 【文献导读】XPBD: Position-Based Simulation of Compliant Constrained Dynamics
  • 直流有刷电机转速、电流双闭环调速系统及Matlab/Simulink仿真分析
  • 诡异错误 Unresolved reference: styleable
  • exception错误处理库学习
  • 蔚来、小鹏、吉利走到了跨界分叉口
  • 神卓互联SDWAN技术实现异地组网办公(无需硬件)
  • Redis分布式锁(下篇)
  • Vue--整合SVG Icon图标--方法/实例
  • STC15单片机-整合代码,完成软件设计
  • 直流有刷电机调速原理及Matlab/Simulink仿真
  • 基于bootstrap+Java+MySQL的高校成绩管理系统
  • java基于ssm+vue+elementui的旅游线路分享管理系统
  • 最近公共祖先 LCA
  • Deterministic Policy Gradient Algorithms
  • Java8时间日期库DateTime API及示例
  • 【node学习】协程
  • Golang-长连接-状态推送
  • linux安装openssl、swoole等扩展的具体步骤
  • MySQL数据库运维之数据恢复
  • React-flux杂记
  • use Google search engine
  • webpack4 一点通
  • 分布式熔断降级平台aegis
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 使用Swoole加速Laravel(正式环境中)
  • 线性表及其算法(java实现)
  • AI又要和人类“对打”,Deepmind宣布《星战Ⅱ》即将开始 ...
  • 大数据全解:定义、价值及挑战
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • #HarmonyOS:基础语法
  • #include<初见C语言之指针(5)>
  • #我与Java虚拟机的故事#连载03:面试过的百度,滴滴,快手都问了这些问题
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (0)Nginx 功能特性
  • (七)c52学习之旅-中断
  • (一)Java算法:二分查找
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • .NET面试题解析(11)-SQL语言基础及数据库基本原理
  • @RequestParam @RequestBody @PathVariable 等参数绑定注解详解
  • @require_PUTNameError: name ‘require_PUT‘ is not defined 解决方法
  • @Transactional 详解
  • [BZOJ] 2044: 三维导弹拦截
  • [GN] 后端接口已经写好 初次布局前端需要的操作(例)
  • [hdu 1247]Hat’s Words [Trie 图]
  • [HTML]Web前端开发技术28(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页
  • [IE技巧] 让IE 以全屏模式启动
  • [IOI2007 D1T1]Miners 矿工配餐
  • [iOS开发]事件处理与响应者链
  • [linux time命令学习篇] time 统计命令执行的时间
  • [Thinking in JAVA] 关于内部类的一些知识点
  • [Ubuntu] 运行.AppImage格式文件
  • [UIUCTF 2022] crypto ASR,WringingRing
  • [Usaco2012 Dec]First! BZOJ3012
  • [xdoj] 13011302 数字计数 数字计数的复仇
  • [第五章]图论BFS