Pergunta

I have a rest application that returns json/xml. I use jackson and jaxb for conversion. Some methods need to accept a query_string. I've used @ModelAttribute to map the query_string into an object, but this forces the object into my view. I do not want the object to appear in the view.

I think I need to use something other than @ModelAttribute, but I can't figure out how to do the binding, but not modify the view. If I omit @ModelAttribute annotation, the object appears in the view as the variable name (eg: "sourceBundleRequest").

Example Url:

http://localhost:8080/rest/sourcebundles/?updateDate=20100501&label=urgent

Controller Method:

@RequestMapping(value = {"", "/"}, method = RequestMethod.GET)
public String getAll(@ModelAttribute("form") SourceBundleRequest sourceBundleRequest, BindingResult result, ModelMap model) throws ApiException {
    // Detect and report errors.
    if (result.hasErrors()) {
       // (omitted for clarity)
    }

    // Fetch matching data.
    PaginatedResponse<SourceBundle> sourceBundleResponse = null;
    try {
        int clientId = getRequestClientId();
        sourceBundleResponse = sourceBundleService.get(clientId, sourceBundleRequest);
    } catch (ApiServiceException e) {
        throw new ApiException(ApiErrorType.INTERNAL_ERROR, "sourceBundle fetch failed");
    }

    // Return the response.
    RestResponse<PaginatedResponse> restResponse = new RestResponse<PaginatedResponse>(200, "OK");
    restResponse.setData(sourceBundleResponse);
    model.addAttribute("resp", restResponse);
    // XXX - how do I prevent "form" from appearing in the view?
    return "restResponse";
}

Example Output:

"form": {
    "label": "urgent",
    "updateDate": 1272697200000,
    "sort": null,
    "results": 5,
    "skip": 0
},
"resp": {
    "code": 200,
    "status": "OK",
    "data": {
        "totalAvailable": 0,
        "resultList": [ ]
    }
}

Desired Output:

"resp": {
    "code": 200,
    "status": "OK",
    "data": {
        "totalAvailable": 0,
        "resultList": [ ]
    }
}

Omitting @ModelAttribute("form")

If I simply omit @ModelAttribute("form"), I still get the undesirable response but the incoming form is named by the object name. The response looks like this:

"resp": {
    "code": 200,
    "status": "OK",
    "data": {
        "totalAvailable": 0,
        "resultList": [ ]
    }
},
"sourceBundleRequest": {
    "label": "urgent",
    "updateDate": 1272697200000,
    "sort": null,
    "results": 5,
    "skip": 0
}
Foi útil?

Solução 2

Somehow I missed the most obvious way to fix this. I was focused on the Attributes and forgot that I can just modify the underlying Map.

  // Remove the form object from the model map.
  model.remove("form");

It might be a little more efficient to omit @ModelAttribute as Biju suggested and then remove the sourceBundleRequest object. I suspect @ModelAttribute has some additional overhead.

Outras dicas

You need not annotate the form with @ModelAttribute if you don't want the form to come back to the view, it will cleanly get bound to SourceBundleRequest even without the @ModelAttribute annotation.

Now, a standard way to return a JSON/XML response using Spring MVC is to return the type directly (in your case the PaginatedResponse) and then annotate the method with @ResponseBody , an underlying HttpMessageConverter would then transform the response into a XML/JSON based on the Accept header from the client.

@ResponseBody
public RestResponse<PaginatedResponse> getAll(SourceBundleRequest sourceBundleRequest, BindingResult result, ModelMap model)
...

How about using @JsonIgnore?

@ModelAttribute("foo")
@JsonIgnore
public Bar getBar(){}

Haven't tested this

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top