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

123

Мой метод POST выглядит так:

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

Когда я создаю клиент Jersey в 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 = 

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

Klaasvaak
источник
вы используете это в приложении для Android или нет?
Android-Droid
Наконец-то я хочу вызвать этот метод публикации в приложении для Android. Почему-то веб-сервис не знает, как подписать значения параметров. Я хочу знать, как это сделать.
Klaasvaak

Ответы:

356

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

@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-сообщения как неаннотированный параметр - 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

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


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

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

D.Shawley
источник
4
Я тестировал эту функцию вчера, аннотации @XmlElement не нужны
mmatloka
Спасибо за это. Если я все еще хочу отправить 2 строки, то что нужно для использования restfull? Или несколько параметров работают только с @PathParm?
Klaasvaak
1
@Klaasvaak - вам нужно указать, откуда должен быть извлечен каждый параметр. Поскольку у вас есть кое-что, Jersey / NetBeans принимает сообщение формы и извлекает данные, отправленные как FormParm. Добавьте аннотации к каждому из ваших дополнений метода с указанием того, откуда вы хотите получать данные (PathParam, FormParam, CookieParam и т. Д.)
Perception
1
@Klaasvaak - Я добавил кучу примеров с использованием различных аннотаций
Д.Шоули
2
Спасибо тебе большое за это! Это было действительно то, что я искал. Вы сделали мой день;) Я использую FormParams сейчас, и он работает!
Klaasvaak