文件

§處理和提供 JSON

在 Java 中,Play 使用 Jackson 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 要求是一種 HTTP 要求,使用有效的 JSON 負載作為要求主體。其 `Content-Type` 標頭必須指定 `text/json` 或 `application/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);
  }
}

注意:這樣一來,對於內容類型設定為 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 字串,想回傳,也可以這麼做

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

§進階用法

有兩種可能的方式可自訂應用程式的 ObjectMapper

§application.conf 中的組態

由於 Play 使用 Pekko Jackson 序列化支援,您可以根據應用程式需求組態 ObjectMapperjackson-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


在這個文件找到錯誤了嗎?此頁面的原始程式碼可以在 這裡 找到。在閱讀 文件指南 後,請隨時提交 pull request。有問題或建議要分享嗎?前往 我們的社群論壇 與社群展開對話。