Отображать формат вывода (HTML, JSON, XML) в зависимости от параметра?
Есть ли хороший или правильный способ рендеринга вывода в Play Framework в зависимости от параметра? Пример:
Для HTML:
http://localhost:9000/user/get/5?v=HTML // should render HTML template
Для JSON:
http://localhost:9000/user/get/5?v=JSON // should render JSON template
Я думаю, что перехватчик запросов мог бы иметь возможность достичь этого, но я не знаю, как начать или с чего начать: - (
Или, может быть, напишите общий render method
, который читает параметры и выводит их по запросу, но это кажется мне излишним?
Ответы
Ответ 1
Если /user/5?v=html
и /user/5?v=json
возвращают два представления одного и того же ресурса, они должны быть одного и того же URL-адреса, например. /user/5
, в соответствии с принципами REST.
На стороне клиента вы можете использовать заголовок Accept
в своих запросах, чтобы указать, какое представление вы хотите отправить серверу.
На стороне сервера вы можете записать следующее с Play 2.1, чтобы проверить значение заголовка Accept
:
public static Result user(Long id) {
User user = User.find.byId(id);
if (user == null) {
return notFound();
}
if (request().accepts("text/html")) {
return ok(views.html.user(user));
} else if (request().accepts("application/json")) {
return ok(Json.toJson(user));
} else {
return badRequest();
}
}
Обратите внимание, что тест с "text/html"
всегда должен быть написан до любого другого типа содержимого, поскольку браузеры устанавливают заголовок Accept
своих запросов на */*
, который соответствует всем типам.
Если вы не хотите писать if (request().accepts(…))
в каждом действии, вы можете его исключить, например. например:
public static Result user(Long id) {
User user = User.find.byId(id);
return representation(user, views.html.user.ref);
}
public static Result users() {
List<User> users = User.find.all();
return representation(users, views.html.users.ref);
}
private <T> Result representation(T resource, Template1<T, Html> html) {
if (resource == null) {
return notFound();
}
if (request().accepts("text/html")) {
return ok(html.apply(resource));
} else if (request().accepts("application/json")) {
return ok(Json.toJson(resource));
} else {
return badRequest();
}
}
Ответ 2
Напишите 2 метода, используйте 2 маршрута (поскольку вы не укажете, я буду использовать образцы Java:
public static Result userAsHtml(Long id) {
return ok(someView.render(User.find.byId(id)));
}
public static Result userAsJson(Long id) {
return play.libs.Json.toJson(User.find.byId(id));
}
маршруты:
/GET /user/get/:id/html controllers.YourController.userAsHtml(id:Long)
/GET /user/get/:id/json controllers.YourController.userAsJson(id:Long)
Далее вы можете просто сделать ссылку в другом представлении для отображения пользовательских данных.
<a href="@routes.YourController.userAsHtml(user.id)">Show details</a>
<a href="@routes.YourController.userAsJson(user.id)">Get JSON</a>
или что-то еще...
изменить # 1
вы также можете использовать общие if
или case
для определения окончательного вывода
public static Result userAsV() {
String vType = form().bindFromRequest().get("v");
if (vTtype.equals("HTML")){
return ok(someView.render(User.find.byId(id)));
}
return play.libs.Json.toJson(User.find.byId(id));
}
Ответ 3
Я хотел, чтобы пользователь мог быть просмотрен в браузере как html или как json, поэтому метод accepts не работал у меня.
Я решил его, поместив общий рендеринговый метод в базовый класс со следующим синтаксисом стиля
public static Result requestType( )
{
if( request().uri().indexOf("json") != -1)
{
return ok(Json.toJson(request()));
}
else
{
return ok("Got HTML request " + request() );
}
}