Доступ к RequestBody внутри Spring Portlet Controller с использованием @ResourceMapping и @ModelAttribute
Моя проблема похожа на следующие сообщения: JSON ajax POST в Spring Portlet Controller @ResourceMapping проблема преобразования и @ResourceMapping, который принимает JSON от Ajax-запроса
Я попробовал Типпс там, но безуспешно. У меня есть следующие технологии:
- liferay-портал 6.2 CE
- пользовательский портлет-плагин для liferay на основе Spring 3.0.7
- кендо-интерфейс для JSP
На стороне клиента я создаю строковый json-Object с функциональностью kendo-ui для jsp, который передается в теле запроса. В настоящее время он содержит только некоторые параметры фильтра (но он также может содержать дополнительные параметры для подкачки на стороне сервера, сортировки, группировки и т. Д.).
В инструментах разработчика Firefox тело запроса (полезная нагрузка) выглядит следующим образом:
{
"filter" : {
"logic" : "and",
"filters" : [{
"field" : "name",
"value" : ""
}, {
"field" : "city",
"value" : ""
}, {
"field" : "zip",
"value" : ""
}, {
"field" : "country",
"value" : ""
}
]
}
}
На стороне сервера у меня есть POJO для этой структуры. Я успешно проверил это в среде сервлета Spring Web MVC. Используя @RequestBody и Джексона, десериализация объекта JSON работает.
Работая в среде liferay-портлета, я не могу использовать @RequestBody и httpServletRequest.
Контроллер выглядит следующим образом:
@ResourceMapping(value = "test")
public void searchProviderTest(ResourceRequest request, ResourceResponse response,
@ModelAttribute("filter") DataSourceRequest dataSourceRequest) {
LOGGER.info(">>>>>> JsonOjekt per Parameter übergeben: " + request.getParameter("filter"));
LOGGER.info(">>>>>>>> DatasourceRequest: " + dataSourceRequest);
}
DataRequestObject не имеет значений. Я вижу все атрибуты, но они пусты. И нет параметра запроса "фильтр" (как ожидается)
Вот мой DataSourceRequest-Object (аннотация):
public class DataSourceRequest {
private int page;
private int pageSize;
private int take;
private int skip;
private List<SortDescriptor> sort;
private List<GroupDescriptor> group;
private List<AggregateDescriptor> aggregate;
private HashMap<String, Object> data;
private FilterDescriptor filter;
public DataSourceRequest() {
filter = new FilterDescriptor();
data = new HashMap<String, Object>();
}
...(getters and setters)
public static class FilterDescriptor {
private String logic;
private List<FilterDescriptor> filters;
private String field;
private Object value;
private String operator;
private boolean ignoreCase = true;
public FilterDescriptor() {
filters = new ArrayList<FilterDescriptor>();
}
...(getters and setters)
Я ищу решение с нескольких недель, но я не получаю JSON-объект, преобразованный (десериализованный?) В DataSourceRequest-объект с помощью контроллера портлета. У меня даже нет идеи, как получить доступ к JSON-String в теле запроса (полезная нагрузка) из контроллера портлета.
После второго упомянутого поста могут быть проблемы с вложенными объектами. Я связался со службой поддержки kendo-ui с вопросом, как я могу отправить запрос, чтобы получить формат, описанный в посте. Но они сказали мне, что это невозможно (например, с помощью attributeMap-атрибута объекта источника данных), и я должен решить это на стороне сервера.
В первом посте описывается решение с помощью @ModelAttribute, но затем я получаю только пустой объект - и когда я пытаюсь получить JSON с @RequestParam, я получаю сообщение об ошибке, что параметр отсутствует в запросе (я думаю, потому что он находится в тело)
Я думал о настройке дополнительного API RESTFul, основанного на Spring Web MVC Servlet - я даже попробовал это, и это работает - но я не уверен, что это действительно имеет смысл, потому что у liferay уже есть RESTFul -API.
Есть ли способ преобразовать объект JSON в объект JAVA внутри контроллера портлета? или мне нужен дополнительный API?
Любые советы приветствуются!
2 ответа
У меня была такая же проблема при сериализации и десериализации Json с Liferay. Решением для меня было отправить JSON в качестве параметра в форме данных. Таким образом, я смог получить Json с помощью следующего метода:
String paramJson = ParamUtil.getString(request, "myJson");
А затем использовать Gson API для десериализации:
new Gson().fromJson(paramJson, MyPOJO.class);
У вас не будет столько проблем с Gson. Вы также можете использовать Gson для сериализации объектов при возврате ваших сервисов, это позволит избежать проблем с вложенными объектами, которые Liferay не сериализует должным образом.
Этот код показывает, как отправить Json как тело запроса:
Запрос будет обработан методом serveResource в MVCPortlet.
var portletUrl = Liferay.PortletURL.createResourceURL();
portletUrl.setPortletId(<portletId>);
portletUrl.setResourceId('publicar'); // Any identifier
var formData = new FormData();
formData.append(<portlet-namespace> + 'myJson', JSON.stringify(object));
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', callbackSuccess, false);
xhr.open('POST', urlPortlet);
xhr.send(formData);
Чтобы поделиться своим опытом, вот шаги:
в JS установите для contentType application / x-www-form-urlencoded. Вот код для кендо-пользовательского интерфейса (использует JQuery Ajax в фоновом режиме)
<kendo:dataSource-transport-parameterMap> function parameterMap(options,type) { if(type==="read"){ return "osdeFilter=" + encodeURIComponent(JSON.stringify(options)); } else { return "osdeModels=" + encodeURIComponent(JSON.stringify(options.models)); } } </kendo:dataSource-transport-parameterMap>
Получите параметр и в моем случае используйте Джексона вручную для десериализации строки JSON
@ResourceMapping(value = "test") public void searchProviderTest(ResourceRequest request, ResourceResponse response) throws JsonParseException, JsonMappingException, IOException { String osdeFilter = URLDecoder.decode(request.getParameter("osdeFilter"),"UTF-8"); LOGGER.info(">>>>>> JsonOjekt per Parameter übergeben: " + request.getParameter("osdeFilter")); ObjectMapper objectMapper = new ObjectMapper(); DataSourceRequest dataSourceRequest = objectMapper.readValue(osdeFilter, DataSourceRequest.class); LOGGER.info(">>>>>>>> DatasourceRequest: " + dataSourceRequest); }
В отличие от @giovani мне не нужно отправлять пространство имен портлета. Для этого вы должны добавить следующую конфигурацию в файл liferay-portlet.xml
<requires-namespaced-parameters>false</requires-namespaced-parameters>