Доступ к RequestBody внутри Spring Portlet Controller с использованием @ResourceMapping и @ModelAttribute

Моя проблема похожа на следующие сообщения: JSON ajax POST в Spring Portlet Controller @ResourceMapping проблема преобразования и @ResourceMapping, который принимает JSON от Ajax-запроса

Я попробовал Типпс там, но безуспешно. У меня есть следующие технологии:

  1. liferay-портал 6.2 CE
  2. пользовательский портлет-плагин для liferay на основе Spring 3.0.7
  3. кендо-интерфейс для 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);

Чтобы поделиться своим опытом, вот шаги:

  1. в 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>
    
  2. Получите параметр и в моем случае используйте Джексона вручную для десериализации строки 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>
Другие вопросы по тегам