Как получить доступ к параметрам в методе POST RESTful

Мой метод POST выглядит следующим образом:

@POST
@Consumes({"application/json"})
@Path("create/")
public void create(String param1, String param2){
    System.out.println("param1 = " + param1);
    System.out.println("param2 = " + param2);
}

Когда я создаю Джерси-клиента в Netbeans, метод, который вызывает метод post, выглядит следующим образом:

public void create(Object requestEntity){
    webResource.path("create").type(MediaType.APPLICATION_JSON).post(requestEntity);
}

При выполнении этого теста:

@Test
public void hello(){
    String json = "{param1=\"hello\",param2=\"hello2\"}";
    this.client.create(json);
}

Он выводит на сервер следующий вывод:

INFO: param1 = {param1="hello",param2="hello2"}
INFO: param2 = 

Что мне нужно изменить, чтобы параметры дали правильное значение?

Ответ 1

Ваш метод @POST должен принимать объект JSON вместо строки. Джерси использует JAXB для поддержки marshaling и unmarshaling объектов JSON (см. подробные сведения о джерси). Создайте класс вроде:

@XmlRootElement
public class MyJaxBean {
    @XmlElement public String param1;
    @XmlElement public String param2;
}

Тогда ваш метод @POST будет выглядеть следующим образом:

@POST @Consumes("application/json")
@Path("/create")
public void create(final MyJaxBean input) {
    System.out.println("param1 = " + input.param1);
    System.out.println("param2 = " + input.param2);
}

Этот метод ожидает получения объекта JSON в качестве тела HTTP POST. В этом случае JAX-RS передает тело содержимого HTTP-сообщения как unannotated параметр - input. Фактическое сообщение будет выглядеть примерно так:

POST /create HTTP/1.1
Content-Type: application/json
Content-Length: 35
Host: www.example.com

{"param1":"hello","param2":"world"}

Использование JSON таким образом довольно распространено по очевидным причинам. Однако, если вы генерируете или потребляете его в чем-то, отличном от JavaScript, тогда вам нужно быть осторожным, чтобы должным образом избежать данных. В JAX-RS вы должны использовать MessageBodyReader и MessageBodyWriter для реализации этого. Я считаю, что у Джерси уже есть реализации для требуемых типов (например, Java-примитивов и JAXB-упакованных классов), а также для JSON. JAX-RS поддерживает ряд других методов передачи данных. Это не требует создания нового класса, поскольку данные передаются с использованием простой передачи аргументов.


HTML <FORM>

Параметры будут аннотированы с помощью @FormParam:

@POST
@Path("/create")
public void create(@FormParam("param1") String param1,
                   @FormParam("param2") String param2) {
    ...
}

Браузер будет кодировать форму с помощью "application/x-www-form-urlencoded" . Время выполнения JAX-RS позаботится об декодировании тела и передаче его методу. Вот что вы должны увидеть на проводе:

POST /create HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 25

param1=hello&param2=world

Содержимое URL-код в этом случае.

Если вы не знаете имена FormParam, вы можете сделать следующее:

@POST @Consumes("application/x-www-form-urlencoded")
@Path("/create")
public void create(final MultivaluedMap<String, String> formParams) {
    ...
}

Заголовки HTTP

Вы можете использовать аннотацию @HeaderParam, если вы хотите передавать параметры через HTTP-заголовки:

@POST
@Path("/create")
public void create(@HeaderParam("param1") String param1,
                   @HeaderParam("param2") String param2) {
    ...
}

Здесь будет выглядеть HTTP-сообщение. Обратите внимание, что этот POST не имеет тела.

POST /create HTTP/1.1
Content-Length: 0
Host: www.example.com
param1: hello
param2: world

Я бы не использовал этот метод для обобщенной передачи параметров. Это действительно удобно, если вам нужно получить доступ к значению определенного HTTP-заголовка.


Параметры запроса HTTP

Этот метод в основном используется с HTTP GET, но он в равной степени применим к POST. Он использует аннотацию @QueryParam.

@POST
@Path("/create")
public void create(@QueryParam("param1") String param1,
                   @QueryParam("param2") String param2) {
    ...
}

Как и предыдущий метод, передача параметров через строку запроса не требует тела сообщения. Здесь HTTP-сообщение:

POST /create?param1=hello&param2=world HTTP/1.1
Content-Length: 0
Host: www.example.com

Вам нужно быть особенно осторожным, чтобы кодировать параметры запроса на стороне клиента. Использование параметров запроса может быть проблематичным из-за ограничений длины URL, применяемых некоторыми прокси, а также проблем, связанных с их кодированием.


Параметры пути HTTP

Параметры пути аналогичны параметрам запроса, за исключением того, что они встроены в путь HTTP-ресурса. Этот метод, похоже, сегодня в пользу. В отношении кеширования HTTP есть последствия, поскольку путь - это то, что действительно определяет ресурс HTTP. Код выглядит несколько иначе, чем другие, поскольку аннотация @Path изменена и использует @PathParam:

@POST
@Path("/create/{param1}/{param2}")
public void create(@PathParam("param1") String param1,
                   @PathParam("param2") String param2) {
    ...
}

Сообщение похоже на версию параметра запроса, за исключением того, что имена параметров не включены нигде в сообщении.

POST /create/hello/world HTTP/1.1
Content-Length: 0
Host: www.example.com

Этот метод разделяет те же ошибки кодирования, что и версия параметра запроса. Отрезки маршрута кодируются по-разному, поэтому вам также нужно быть осторожным.


Как вы можете видеть, для каждого метода есть плюсы и минусы. Выбор обычно определяется вашими клиентами. Если вы используете HTML-страницы на основе FORM, используйте @FormParam. Если вашими клиентами являются JavaScript + HTML5, вы, вероятно, захотите использовать JAXB-сериализацию и объекты JSON. Реализации MessageBodyReader/Writer должны позаботиться о том, чтобы вы могли ускользнуть от вас, так что это меньше, что может пойти не так. Если ваш клиент основан на Java, но не имеет хорошего XML-процессора (например, Android), то я бы, вероятно, использовал кодировку FORM, так как тело содержимого легче создавать и кодировать правильно, чем URL-адреса. Надеемся, что эта запись в мини-вики проливает свет на различные методы, поддерживаемые JAX-RS.

Примечание:в интересах полного раскрытия, я пока не использовал эту особенность Джерси. Мы занимались этим, так как у нас есть несколько приложений JAXB + JAX-RS, развернутых и перемещающихся в мобильное клиентское пространство. JSON намного лучше подходит для XML на основе HTML5 или jQuery-решений.