使用@ResourceMapping 和@ModelAttribute 访问 Spring Portlet Controller 内的 RequestBody

Access RequestBody inside Spring Portlet Controller using @ResourceMapping and @ModelAttribute

我的问题类似于下面的post: JSON ajax POST to Spring Portlet Controller @ResourceMapping conversion issue and

我在那里尝试过Tipps,但没有成功。 我有以下技术:

  1. liferay-门户 6.2 CE
  2. 基于 spring 3.0.7
  3. 的 liferay 自定义 portlet 插件
  4. kendo-ui 对于 jsp

在客户端,我为 jsp 生成了一个字符串化的 json-Object,它具有 kendo-ui 的功能,并在请求正文中提交.目前它只包含一些过滤器参数(但它也可以包含用于服务器端分页、排序、分组等的其他参数)。

在 Firefox 开发人员工具中,请求正文(有效负载)如下所示:

{
"filter" : {
    "logic" : "and",
    "filters" : [{
            "field" : "name",
            "value" : ""
        }, {
            "field" : "city",
            "value" : ""
        }, {
            "field" : "zip",
            "value" : ""
        }, {
            "field" : "country",
            "value" : ""
        }
    ]
  }
}

在服务器端,我有一个用于该结构的 POJO。我在 Spring Web MVC Servlet 环境中测试成功。使用 @RequestBodyJackson 可以反序列化 JSON 对象。

liferay-portlet 环境中工作 我不能使用 @RequestBodyhttpServletRequest

控制器如下所示:

@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 没有值。我看到了所有属性,但它们是空的。并且没有请求参数"filter"(如预期的那样)

这是我的 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)

几周以来我一直在寻找解决方案,但我没有使用 portlet 控制器将 JSON-Object 转换(反序列化?)为 DataSourceRequest-Object。我什至不知道如何从 portlet 控制器访问请求正文(有效负载)中的 JSON-String。

第二次提到 post 之后,嵌套对象 可能是问题所在。我联系了 kendo-ui 支持人员,询问如何提交请求以获取 post 中描述的格式。但是他们告诉我,这是不可能的(例如使用数据源对象的参数映射属性),我必须在服务器端解决它。

首先post描述了一个解决方案@ModelAttribute,但后来我只得到了空对象——当我尝试使用 @RequestParam 获取 JSON 我收到一个错误,该参数不在请求中(我认为是因为它在正文中)

我正在考虑基于 Spring Web MVC Servlet 设置一个 额外的 RESTFul API - 我什至试过了它有效-但我不确定这是否真的有意义,因为 liferay 已经有一个 RESTFul -API.

有没有办法将 JSON 对象转换为 Portlet 控制器内的 JAVA 对象? 我需要额外的 API?

欢迎任何提示!!

我在使用 Liferay 序列化和反序列化 Json 时遇到了同样的问题。我的解决方案是将 json 作为表单数据中的参数发送。这样我就可以使用以下方法检索 Json:

String paramJson = ParamUtil.getString(request, "myJson");

然后利用Gsonapi反序列化:

new Gson().fromJson(paramJson, MyPOJO.class);

有了Gson你就不会有那么多烦恼了。 您还可以使用 Gson 序列化服务 return 中的对象,这将避免嵌套对象出现问题 Liferay 无法正确序列化。

此代码显示如何发送 Json 作为请求正文:

请求将由 MVCPortlet 中的方法 'serveResource' 处理。

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。那是 kendo-ui 的代码(在后台使用 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. 获取参数,在我的例子中使用 Jackson 手动反序列化 JSON String

    @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 不同,我不需要提交 portlet 命名空间。为此,您必须将以下配置添加到 liferay-portlet.xml

<requires-namespaced-parameters>false</requires-namespaced-parameters>