休息愉快!构架


117

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

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

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

Answers:


112

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

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

您在此处未指定任何内容类型。仅当您希望某些资源具有“特殊” URI时,才需要IMHO这样做。就像/users/feed/在Atom / RSS中声明始终返回的路线。

Application控制器如下所示:

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>

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

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

哪个应该为您获取有关ID为1的JSON格式用户的详细信息。Play当前本地支持HTML,JSON和XML,但是您可以通过遵循官方文档或使用内容协商模块轻松使用其他类型。

如果您使用Eclipse进行开发,建议您使用REST客户端插件,该插件可让您测试路线及其相应的内容类型。


2
感谢您发布此信息。表演!docs是我所见过的解释事物基本结构的最佳工具,但有时缺少详细的示例。在同一个示例中演示两种方法确实可以解决问题。
布拉德·梅斯

我正在尝试您的示例,我很好奇在哪里将发布的JSON数据转换为User类。例如,在createUser函数内部,我发现newUser为null。
加里2010年

2
@加里:也许您使用的是“用户”而不是“ newUser”?控制器的名称和form参数必须匹配。我创建了一个简单的项目,显示了上面的方法,包括HTML / XML / JSON输出在所有用户github.com/sebhoss/play-user-sample
SEB

谢谢,我通过使用curl发送JSON字符串进行了测试,看来那部戏的框架不承认的应用程序/ JSON内容类型:groups.google.com/group/play-framework/browse_thread/thread/...
加里

@加里:谢谢你的提示!看来它是固定在主分支,你可以尝试自己建立它,然后再次测试..
SEB

68

这仍然是一个受欢迎的问题,但是投票最高的答案与当前版本的游戏不是最新的。这是一个带有播放2.2.1的有效REST示例:

conf /路由:

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魔术。:-(
flaschenpost 2014年

26

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

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

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

根据您希望如何返回结果(XML,JSON等),可以使用几种方法。例如,使用renderJSON方法可以非常轻松地呈现结果。如果要呈现XML,则可以按照与在View中构建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方法?
TimoWestkämper2010年

是的,但并不完全可靠。如果play知道标头是JSON请求,则它将尝试呈现getuser.json文件。如果标头是xml,则它将尝试getuser.xml。但是,对于用户/ User / {id} / type来说,它更容易理解,并且更像REST
Codemwnci 2010年

29
我不认为在URI中显式指定表示形式更像REST。最好直接使用Accept标头,不要更改URI,因为要查看的资源保持不变。可以将上面的示例重写为仅具有一个getUser(Long id)方法,该方法与当前的实现完全相同,但是不必定义getUserJSON,getUserXML等,而是定义getUser.json和getUser.xml模板。虽然我会重命名以user.json / user.xml太
SEB

谢谢,这是非常有帮助的。欣赏它!
加里2010年

1
@seb-您可以将评论扩展为答案吗?我希望看到您描述的技术的一个示例
Brad Mace 2010年

5

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

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



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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.