【问题标题】:RESTful on Play! frameworkRESTful 畅玩!框架
【发布时间】:2011-05-21 17:43:01
【问题描述】:

我们正在计划一个主要为移动应用提供内容的项目,但需要有一个网站。

我的问题是使用 Jersey 或 Restlet 为我们的移动应用程序开发 REST API,然后使用 Play!为网站服务。

还是只使用 Play 更有意义!做这一切?如果是这样,如何使用 Play 进行 REST!框架?

【问题讨论】:

    标签: java rest jersey restlet playframework


    【解决方案1】:

    这仍然是一个热门问题,但投票最高的答案与当前版本的 play 不同。这是 play 2.2.1 的工作 REST 示例:

    配置/路由:

    GET     /users                 controllers.UserController.getUsers
    GET     /users/:id             controllers.UserController.getUser(id: Long)
    POST    /users                 controllers.UserController.createUser
    PUT     /users/:id             controllers.UserController.updateUser(id: Long)
    DELETE  /users/:id             controllers.UserController.deleteUser(id: Long)
    

    app/controllers/UserController.java:

    public static Result getUsers()
    {
        List<User> users = Database.getUsers();
        return ok(Json.toJson(users));
    }
    
    public static Result getUser(Long id)
    {
        User user = Database.getUser(id);
        return user == null ? notFound() : ok(Json.toJson(user));
    }
    
    public static Result createUser()
    {
        User newUser = Json.fromJson(request().body().asJson(), User.class);
        User inserted = Database.addUser(newUser);
        return created(Json.toJson(inserted));
    }
    
    public static Result updateUser(Long id)
    {
        User user = Json.fromJson(request().body().asJson(), User.class);
        User updated = Database.updateUser(id, user);
        return ok(Json.toJson(updated));
    }
    
    public static Result deleteUser(Long id)
    {
        Database.deleteUser(id);
        return noContent(); // http://stackoverflow.com/a/2342589/1415732
    }
    

    【讨论】:

    • 我也希望看到 seb 答案的更新版本,但不幸的是,您的答案删除了所有 .xml 和 .html 魔法。 :-(
    【解决方案2】:

    在 Play 1.2.3 版中,这种方法似乎被打破了。如果您下载由@seb 完成并在前面提到的https://github.com/sebhoss/play-user-sample 的源代码,则不再可能使用带有JSON 对象的POST 创建新的用户对象。

    您需要使用 json 和 xml POST 完成特定的创建方法。此处概述:https://groups.google.com/forum/#!topic/play-framework/huwtC3YZDlU

    【讨论】:

      【解决方案3】:

      你应该看看

      http://www.lunatech-labs.com/open-source/resteasy-crud-play-module

      它是一个自动构建rest界面的play模块,就像crud模块自动构建一个管理区域一样......

      【讨论】:

        【解决方案4】:

        根据要求,一种简单的类似 REST 的方法。它的工作方式与 Codemwncis 的解决方案几乎相同,但使用 Accept 标头进行内容协商。首先是路由文件:

        GET     /user/{id}            Application.user
        POST    /user/                Application.createUser
        PUT     /user/{id}            Application.updateUser
        DELETE  /user/{id}            Application.deleteUser
        

        您没有在此处指定任何内容类型。恕我直言,只有当您想要为某些资源拥有“特殊”URI 时才需要这样做。就像声明到 /users/feed/ 的路由总是在 Atom/RSS 中返回。

        应用程序控制器如下所示:

        public static void createUser(User newUser) {
            newUser.save();
            user(newUser.id);
        }
        
        public static void updateUser(Long id, User user) {
            User dbUser = User.findById(id);
            dbUser.updateDetails(user); // some model logic you would write to do a safe merge
            dbUser.save();
            user(id);
        }
        
        public static void deleteUser(Long id) {
            User.findById(id).delete();
            renderText("success");
        }
        
        public static void user(Long id)  {
            User user = User.findById(id)
            render(user);
        }
        

        如您所见,我只删除了 getUserJSON 方法并重命名了 getUser 方法。要使不同的内容类型起作用,您现在必须创建多个模板。每个所需的内容类型一个。例如:

        user.xml:

        <users>
          <user>
            <name>${user.name}</name>
            . . .
          </user>
        </users>
        

        user.json:

        {
          "name": "${user.name}",
          "id": "${user.id}",
          . . . 
        }
        

        user.html:

        <html>...</html>
        

        这种方法始终为浏览器提供 HTML 视图,因为所有浏览器都在其 Accept 标头中发送 text/html 内容类型。所有其他客户端(可能是一些基于 JavaScript 的 AJAX 请求)可以定义自己想要的内容类型。使用 jQuerys ajax() 方法,您可以执行以下操作:

        $.ajax({
          url: @{Application.user(1)},
          dataType: json,
          success: function(data) {
            . . . 
          }
        });
        

        这应该可以让您以 JSON 格式获取 ID 为 1 的用户的详细信息。 Play 目前原生支持 HTML、JSON 和 XML,但您可以通过 official documentationcontent negotiation module 轻松使用不同的类型。

        如果您使用 Eclipse 进行开发,我建议您使用 REST client plugin,它可以让您测试您的路由及其对应的内容类型。

        【讨论】:

        • 感谢您发布此信息。表演!文档是我见过的用于解释事物基本结构的最好的一些文档,但有时缺少详细的示例。在同一个示例中演示这两种方法确实可以解决问题。
        • 我正在尝试您的示例,我很好奇发布的 JSON 数据在哪里转换为 User 类。例如,在 createUser 函数中,我发现 newUser 为空。
        • @Gary:也许你用的是“user”而不是“newUser”?控制器的名称和表单参数必须匹配。我创建了一个显示上述方法的简单项目,包括github.com/sebhoss/play-user-sample 的所有用户的 HTML/XML/JSON 输出
        • 谢谢,我用curl发送JSON字符串测试了一下,播放框架似乎无法识别application/json内容类型:groups.google.com/group/play-framework/browse_thread/thread/…
        • @Gary:感谢您的提示!好像已经在master分支里修复了,你可以尝试自己构建,然后再测试..
        【解决方案5】:

        与 JAX-RS 实现集成是使用 Play 的内置 HTTP 路由的一种可能的替代方法。有关 RESTEasy 示例,请参阅RESTEasy Play! module

        如果您已经投资于 JAX-RS,或者如果您需要 JAX-RS 提供的一些高级功能 REST(例如内容协商),则这种方法很有意义。如果没有,直接使用 Play 来提供 JSON 或 XML 以响应 HTTP 请求会更简单。

        【讨论】:

          【解决方案6】:

          使用播放!做这一切。 在 Play 中编写 REST 服务非常简单。

          首先,路由文件使编写符合 REST 方法的路由变得简单。

          然后,您在控制器中为要创建的每个 API 方法编写操作。

          根据您想要返回结果的方式(XML、JSON 等),您可以使用几种方法。例如,使用 renderJSON 方法,可以很容易地呈现结果。如果你想呈现 XML,那么你可以像在你的视图中构建一个 HTML 文档一样这样做。

          这是一个简洁的例子。

          路由文件

          GET     /user/{id}            Application.getUser(format:'xml')
          GET     /user/{id}/json       Application.getUserJSON
          POST    /user/                Application.createUser
          PUT     /user/{id}            Application.updateUser
          DELETE  /user/{id}            Application.deleteUser
          

          申请文件

          public static void createUser(User newUser) {
              newUser.save();
              renderText("success");
          }
          
          public static void updateUser(Long id, User user) {
              User dbUser = User.findById(id);
              dbUser.updateDetails(user); // some model logic you would write to do a safe merge
              dbUser.save();
              renderText("success");
          }
          
          public static void deleteUser(Long id) {
              // first check authority
              User.findById(id).delete();
              renderText("success");
          }
          
          public static void getUser(Long id)  {
              User user = User.findById(id)
              renderJSON(user);
          }
          
          public static void getUserJSON(Long id) {
              User user = User.findById(id)
              renderJSON(user);
          }
          

          getUser.xml 文件

          <user>
             <name>${user.name}</name>
             <dob>${user.dob}</dob>
             .... etc etc
          </user>
          

          【讨论】:

          • 是否可以根据 Accept 标头选择正确的 getUser 方法?
          • 确实如此,但并不完全可靠。如果 play 知道 header 是一个 JSON 请求,那么它将尝试渲染一个 getuser.json 文件。如果标头是 xml,那么它将尝试 getuser.xml。但是,对于用户 /User/{id}/type 来说,它更容易理解,并且更像 REST
          • 我不认为在 URI 中明确指定表示类型更像 REST。最好直接使用 Accept 标头,不要更改 URI,因为您要查看的资源保持不变。上面的示例可以重写为只有一个 getUser(Long id) 方法,该方法的功能与其当前实现完全相同,但不是定义 getUserJSON、getUserXML 等,而是定义一个 getUser.json 和 getUser.xml 模板。虽然我也将其重命名为 user.json/user.xml
          • 谢谢,这很有帮助。欣赏!
          • @seb - 您可以将您的评论扩展为答案吗?我很想看看你描述的技术的一个例子
          猜你喜欢
          • 2012-12-17
          • 2015-07-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-06
          • 2012-08-11
          • 2015-10-02
          • 1970-01-01
          相关资源
          最近更新 更多