文档

§处理和提供 JSON

在 Java 中,Play 使用 Jackson JSON 库将对象转换为 JSON 以及从 JSON 转换对象。Play 的操作使用 JsonNode 类型,并且框架在 play.libs.Json API 中提供了用于转换的实用程序方法。

§将 Java 对象映射到 JSON

Jackson 允许您通过查看字段名称、getter 和 setter 来轻松地将 Java 对象转换为 JSON。例如,我们将使用以下简单的 Java 对象

// Note: can use getters/setters as well; here we just use public fields directly.
// if using getters/setters, you can keep the fields `protected` or `private`
public static class Person {
  public String firstName;
  public String lastName;
  public int age;
}

我们可以解析对象的 JSON 表示并创建一个新的 Person

Person person = new Person();
person.firstName = "Foo";
person.lastName = "Bar";
person.age = 30;
JsonNode personJson = Json.toJson(person); // {"firstName": "Foo", "lastName": "Bar", "age": 30}

类似地,我们可以将 Person 对象写入 JsonNode

// parse the JSON as a JsonNode
JsonNode json = Json.parse("{\"firstName\":\"Foo\", \"lastName\":\"Bar\", \"age\":13}");
// read the JsonNode as a Person
Person person = Json.fromJson(json, Person.class);

§处理 JSON 请求

JSON 请求是使用有效 JSON 负载作为请求主体进行的 HTTP 请求。其 Content-Type 标头必须指定 text/jsonapplication/json MIME 类型。

默认情况下,操作使用 任何内容 主体解析器,您可以使用它以 JSON(实际上是 Jackson JsonNode)的形式检索主体

public Result sayHello(Http.Request request) {
  JsonNode json = request.body().asJson();
  if (json == null) {
    return badRequest("Expecting Json data");
  } else {
    String name = json.findPath("name").textValue();
    if (name == null) {
      return badRequest("Missing parameter [name]");
    } else {
      return ok("Hello " + name);
    }
  }
}
public Result sayHello(Http.Request request) {
  Optional<Person> person = request.body().parseJson(Person.class);
  return person.map(p -> ok("Hello, " + p.firstName)).orElse(badRequest("Expecting Json data"));
}

当然,最好(也更简单)指定我们自己的 BodyParser 来要求 Play 直接将内容主体解析为 JSON

@BodyParser.Of(BodyParser.Json.class)
public Result sayHello(Http.Request request) {
  JsonNode json = request.body().asJson();
  String name = json.findPath("name").textValue();
  if (name == null) {
    return badRequest("Missing parameter [name]");
  } else {
    return ok("Hello " + name);
  }
}

注意: 这样,对于 Content-type 设置为 application/json 的非 JSON 请求,将自动返回 400 HTTP 响应。

您可以从命令行使用 curl 进行测试

curl
  --header "Content-type: application/json"
  --request POST
  --data '{"name": "Guillaume"}'
  https://127.0.0.1:9000/sayHello

它将回复

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 15

Hello Guillaume

§提供 JSON 响应

在我们之前的示例中,我们处理了 JSON 请求,但回复了 text/plain 响应。让我们将其更改为发送有效的 JSON HTTP 响应

public Result sayHello() {
  ObjectNode result = Json.newObject();
  result.put("exampleField1", "foobar");
  result.put("exampleField2", "Hello world!");
  return ok(result);
}

现在它将回复

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"exampleField1":"foobar","exampleField2":"Hello world!"}

您还可以返回 Java 对象,并让 Jackson 库将其自动序列化为 JSON

public Result getPeople() {
  List<Person> people = personDao.findAll();
  return ok(Json.toJson(people));
}

如果您已经拥有要返回的 JSON String,您也可以这样做

public Result sayHello() {
  String jsonString = "{\"exampleField1\": \"foobar\"}";
  return ok(jsonString).as(play.mvc.Http.MimeTypes.JSON);
}

§高级用法

有两种可能的方法可以为您的应用程序自定义 ObjectMapper

§application.conf 中的配置

由于 Play 使用 Pekko Jackson 序列化支持,您可以根据应用程序需求配置 ObjectMapper。有关 jackson-databind 特性的文档 说明了如何进一步自定义 JSON 转换过程,包括 Mapper序列化反序列化 功能。

如果您想使用 Play 的 Json API(toJson/fromJson)与自定义的 ObjectMapper,您需要在 application.conf 中添加自定义配置。例如,如果您想添加一个新的 Joda 类型模块

pekko.serialization.jackson.play.jackson-modules += "com.fasterxml.jackson.datatype.joda.JodaModule"

或者添加设置序列化配置

pekko.serialization.jackson.play.serialization-features.WRITE_NUMBERS_AS_STRINGS=true

§ObjectMapper 的自定义绑定

如果您仍然想完全接管 ObjectMapper 的创建,可以通过覆盖其绑定配置来实现。您首先需要在 application.conf 中禁用默认的 ObjectMapper 模块

play.modules.disabled += "play.core.ObjectMapperModule"

然后您可以为您的 ObjectMapper 创建一个提供者

public class JavaJsonCustomObjectMapper implements Provider<ObjectMapper> {

  @Override
  public ObjectMapper get() {
    ObjectMapper mapper =
        new ObjectMapper()
            // enable features and customize the object mapper here ...
            .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
            .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

    // Needs to set to Json helper
    Json.setObjectMapper(mapper);

    return mapper;
  }
}

并通过 Guice 将其绑定为一个急切的单例,以便 ObjectMapper 将被设置到 Json 帮助器中

public class JavaJsonCustomObjectMapperModule extends AbstractModule {

  @Override
  protected void configure() {
    bind(ObjectMapper.class).toProvider(JavaJsonCustomObjectMapper.class).asEagerSingleton();
  }
}

之后启用模块

play.modules.enabled += "path.to.JavaJsonCustomObjectMapperModule"

下一步:使用 XML


发现此文档中的错误?此页面的源代码可以在 此处 找到。在阅读了 文档指南 之后,请随时贡献一个拉取请求。有疑问或建议要分享?前往 我们的社区论坛 与社区开始对话。