【问题标题】:Access RequestBody inside Spring Portlet Controller using @ResourceMapping and @ModelAttribute使用 @ResourceMapping 和 @ModelAttribute 在 Spring Portlet Controller 中访问 RequestBody
【发布时间】:2018-03-16 00:10:15
【问题描述】:

我的问题类似于以下帖子: JSON ajax POST to Spring Portlet Controller @ResourceMapping conversion issue@ResourceMapping that accepts JSON from Ajax request

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

  1. liferay-portal 6.2 CE
  2. 基于 spring 3.0.7 的 liferay 自定义 portlet-plugin
  3. 用于 jsp 的 kendo-ui

在客户端,我生成了一个字符串化的 json-Object,它具有 jsp 的 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-controller 将 JSON-Object 转换(反序列化?)为 DataSourceRequest-Object。我什至不知道如何从 portlet 控制器访问请求正文(有效负载)中的 JSON 字符串。

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

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

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

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

欢迎任何提示!

【问题讨论】:

    标签: java json kendo-ui liferay-6 spring-portlet-mvc


    【解决方案1】:

    分享我的经验,步骤如下:

    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 字符串

      @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>
    

    【讨论】:

      【解决方案2】:

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

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

      然后利用Gson api进行反序列化:

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

      Gson 不会有这么多麻烦。 您还可以使用 Gson 在服务返回时序列化对象,这将避免 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);
      

      【讨论】:

      • 就我而言,它也是liferay!好的。我会尝试这种方法。您如何实现,将 JSON 对象作为表单数据发送。将 contentType 设置为 application/x-www-form-urlencoded 是其中的一部分 - 将其作为键/值对发送还需要什么?可以举个例子吗?
      • 那很好。刚刚编辑了答案以添加有关 js 代码的更多信息
      • 解决了一个问题带来了 2 个新问题 :-(。不,我遇到了特殊字符(尤其是 &)的问题!例如,提交对象的一个​​属性是一个类似 @ 的 URL 987654322@**&**t=12345567895。我在后端对其进行了编码,但如何在客户端进行解码。我还具有包含 GmbH & Co KG 等字符的属性。您如何/将如何解决这个问题.
      • 其实我从来没有遇到过这个问题。这可能会帮助你stackoverflow.com/questions/25466560/…
      • 好的!我刚刚为查询参数添加了 encodeURIComponent 并在服务器端使用了 URLDecoder !我将编辑我的解决方案以反映这一点。
      猜你喜欢
      • 2015-10-11
      • 1970-01-01
      • 1970-01-01
      • 2020-06-02
      • 1970-01-01
      • 2012-08-12
      • 1970-01-01
      • 2015-02-15
      • 2011-10-25
      相关资源
      最近更新 更多