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

时间:2017-10-04 14:34:01

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

我的问题类似于以下帖子: 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. kendo-ui for jsp
  4. 在客户端,我生成一个字符串化的json-Object,其功能为jndo的kendo-ui,它在请求体中提交。目前它只包含一些filter-parameters(但它也可以包含服务器端分页,排序,分组等的附加参数。)。

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

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

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

    liferay-portlet环境中工作我无法使用 @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)
    

    我正在寻找一个解决方案,因为一些weecks,但我没有使用portlet-controller将JSON-Object转换(反序列化?)到DataSourceRequest-Object。我甚至不知道如何从portlet-controller访问请求体(有效负载)中的JSON-String。

    第二篇文章之后,嵌套对象可能是问题所在。我联系了kendo-ui支持的问题,我如何提交请求以获得帖子中描述的格式。但他们告诉我,这是不可能的(例如使用数据源对象的parameterMap-attribute),我必须在服务器端解决它。

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

    我正在考虑基于Spring Web MVC Servlet建立一个额外的RESTFul API - 我甚至试过它并且它有效 - 但我不确定这是否真的有意义,因为liferay已经有一个RESTFul -API。

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

    欢迎任何提示!!

2 个答案:

答案 0 :(得分:3)

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

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

然后使用Gson api反序列化:

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

你不会在Gson身上遇到这么多麻烦。 您还可以使用Gson在返回服务时序列化对象,这样可以避免Liferay没有正确序列化的嵌套对象问题。

此代码显示如何将Json作为请求体发送:

请求将由方法&#39; serveResource&#39;处理。在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 :(得分: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 manualy反序列化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);
    
    }
    
  3. 与@giovani不同我不需要提交portlet-namespace。为此,您必须将以下配置添加到 liferay-portlet.xml

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