Different encoding of an HTTP request result, depending on the Accept header - spring

I have a controller with a method to upload files, using, on the client side, the dojo Uploader class that supports ajax uploads for all browsers except IE, and uploads with an IFrame for IE.
The result is a JSON object, but when the IFrame mechanism is used, the JSON must be enclosed in a <textarea>:
#RequestMapping(value = "/documentation/{appId:.+}/", method = RequestMethod.POST)
#ResponseBody
public String uploadDocumentation(HttpServletRequest request,
#PathVariable String appId, #RequestParam("uploadedfile") MultipartFile file)
throws Exception {
// ....
String json = JsonUtils.jsonify(map);
if (accepts(request, "application/json")) {
return json;
} else if (accepts(request, "text/html")) {
return "<textarea>" + json + "</textarea>";
} else {
throw new GinaException("Type de retour non supporté");
}
I was wondering if there is a way to register this encoding mechanism in the framework, so that we would just have to return an object, and let the framework do the rest.
Thanks in advance.

For the record, I simply added a second method:
#RequestMapping(value = "/documentation/{appId:.+}/", method = RequestMethod.POST,
produces="application/json")
#ResponseBody
public UploadResult uploadDocumentation(#PathVariable String appId,
#RequestParam("uploadedfile") MultipartFile file) throws Exception {
...
return new UploadResult(filename);
}
#RequestMapping(value = "/documentation/{appId:.+}/", method = RequestMethod.POST,
produces="text/html")
#ResponseBody
public String uploadDocumentationIE(#PathVariable String appId,
#RequestParam("uploadedfile") MultipartFile file) throws Exception {
UploadResult obj = uploadDocumentation(appId, file);
String json = JsonUtils.jsonify(obj);
return "<textarea>" + json + "</textarea>";
}

Related

How test Post request with custom object in content type application/x-www-form-urlencoded?

I have controller:
#PostMapping(value = "/value/", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String updateSettings(final Dto dto) {
System.out.println(">>> " + dto);
return "template";
}
Controller works if I send request across chrome window. But when I write test for this method I get problem. Not converted object, value not inserted.
Test:
#Test
#WithMockUser(username = FAKE_VALID_USER, password = FAKE_VALID_PASSWORD)
public void test_B_CreateDtoWithValidForm() throws Exception {
final Dto dto = new Dto();
dto.setId("value");
dto.setEnabled("true");
this.mockMvc.perform(post(URL_SET_PROVIDER_SETTINGS)
.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.content(dto.toString()))
.andDo(print());
}
Output is >>> Dto{id=null, enabled=false}
How test Post request with custom object in content type application/x-www-form-urlencoded?
In this case you don't need to use content, but instead you need to use param in this way:
this.mockMvc.perform(post(URL_SET_PROVIDER_SETTINGS)
.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.param("id", "value")
.param("enabled", "true"))
.andDo(print());

Angular 4 and Spring Rest: How to post FormData containing File and model object in a single request

I would like to send a File object along with custom model object in a single request.
let formData:FormData = new FormData();
let file = this.fileList[0];
formData.append('file', file, file.name);
formData.append('address', JSON.stringify(customObj));
...
this.http.post(fileServeUrl, formData)
My backend is in Spring Rest as below
#RequestMapping(value = "/fileServe",
produces = {"application/json"},
consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE},
method = RequestMethod.POST)
ResponseEntity<Image> uploadFile(#RequestPart("file") MultipartFile imageData, #RequestPart("address") Address address) throws IOException {...}
I was able to receive the data if I pass simple String along with File though.
formData.append('file', file, file.name);
formData.append('address', addressText);
Backend
#RequestMapping(value = "/fileServe",
produces = {"application/json"},
consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE},
method = RequestMethod.POST)
ResponseEntity<Image> uploadFile(#RequestPart("file") MultipartFile imageData, #RequestPart("address") String addressText) throws IOException {...}
I tried #RequestBody for my custom object but even that didn't work. Any advise please.
The problem with #Requestbody and #RequestPart annotation is that spring use the HttpMessageConverter to take convert the incoming json message into the your object. As you send form data with a file and a text value spring can not convert it into your object. I am afraid you have to pass the value of address seperatetly.
#RequestMapping(value = "/fileupload", headers = ("content-type=multipart/*"), method = RequestMethod.POST)
public ResponseEntity<AjaxResponseBody> upload(#RequestParam("file") MultipartFile file, #RequestParam String name, #RequestParam String postCode) {
AjaxResponseBody result = new AjaxResponseBody();
HttpHeaders headers = new HttpHeaders();
if (!file.isEmpty()) {
try {
Address address = new Address();
address.setName(name);
result.setMsg("ok");
return new ResponseEntity<AjaxResponseBody>(result, headers, HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<AjaxResponseBody>(HttpStatus.BAD_REQUEST);
}
} else {
return new ResponseEntity<AjaxResponseBody>(HttpStatus.BAD_REQUEST);
}
}
Expept if you find a way your client app send a file with MimeType of image/jpg and and an address of application/json which allow spring to parse the json and map to your Address object which i couldn't do it.

Download A File On click of a link using spring mvc

When I click on any link the content should be downloaded
But this is what I get.
MastercourseController.java
#RequestMapping(value = { ControllerUriConstant.download_file }, method = RequestMethod.GET)
#ResponseBody
public void downloadingAFileById(#RequestParam("id") String id, Model model, HttpServletRequest request)
throws TechnoShineException, IOException {
String filePath = "D:/dev/testFIle.txt";
long download = Long.parseLong(id);
byte[] b = masterCourseFileFormService.getAllDownloadable(download);
OutputStream outputStream = new FileOutputStream(filePath);
outputStream.write(b);
outputStream.close();
}
MasterCourseService
public byte[] getAllDownloadable(long id) throws TechnoShineException
{
return masterCourseFormUploadDao.getAllDownloadableFiles(id);
}
MasterCourseDao
public byte[] getAllDownloadableFiles(long id) throws TechnoShineException
{
return masterCourseFormUploadMapper.getAllDownloadable(id);
}
MasterCourseMapper
public byte[] getAllDownloadable(long id) throws TechnoShineException;
You are writing the data returned by getAllDownloadable(..) to a hard-coded file. Are you sure that is what you want? I think you want to write the content returned by getAllDownloadable(..) to be written into the response. That can be done by adding a method parameter of the type HttpServletResponse to your mapping and writing into the output stream returned by HttpServletResponse#getOutputStream() and flushing (not closing!) that stream at the end.
Furthermore you have to remove the #ResponseBody annotation as this is meant to be used if the value that is returned by the mapping method returns the data that should directly be sent to the client (i.e. when sending a JSON data object or a string) without passing it to the template engine. As you are not returning anything you can remove this annotation.
Furthermore you have to set the content type of your response by invoking HttpServletResponse#setContentType(contentType: String).
In your case, the invocation would be the following:
response.setContentType("text/plain");
You complete method would look like this:
#RequestMapping(
value = ControllerUriConstant.download_file,
method = RequestMethod.GET
)
public void downloadingAFileById(#RequestParam("id") String id, HttpServletResponse response)
throws TechnoShineException, IOException {
long download = Long.parseLong(id);
byte[] b = masterCourseFileFormService.getAllDownloadable(download);
response.getOutputStream().write(b);
response.getOutputStream().flush();
}

Getting 400 Bad Request during POST string in spring mvc

i have a rest api that accept a String in POST and return an object,
this is the method:
#RequestMapping(method = RequestMethod.POST, value = "/aValue", headers = "Accept=application/json")
public #ResponseBody
MyObject getMyObject(#RequestBody String string) {
MyObject response = myService.getMyObject(string);
return response;
}
now when i call the api from another service for example, if I do POST like this it gave me always 400 Bad Request:
List<Object> providers = new ArrayList<Object>();
providers.add(jsonProvider);
WebClient client = WebClient.create(baseUrl + myAPI, providers);
client.type(MediaType.APPLICATION_JSON);
client.accept(MediaType.APPLICATION_JSON);
MyObject response = client.post(userId, MyObject.class);
return response;
instead of the working solution i used which is this one:
MyObject response = client.post("\"" + userId + "\"", MyObject.class);
someone could help me ? thanks guys
You're having an issue 'cause what you're posting is not a valid JSON, yet you indicate that it is in your client-side code. As you seem to pass just a simple string property userId you can simply change your mapping to receive plain text by adding consumes = "text/plain",
#RequestMapping(method = RequestMethod.POST, value = "/aValue", headers = "Accept=application/json", consumes = "text/plain")
public #ResponseBody
MyObject getMyObject(#RequestBody String string) {
and have your client send plain text, so
client.type(MediaType.TEXT_PLAIN);

Spring MVC + GWT : Redirect Issue

I am using Spring annotated MVC framework in an app which I am developing.
Following is the issue I am facing:
I have Controller which does a redirect, after a POST:
#RequestMapping(value = "/emdm-viewer-redirect.do", method = RequestMethod.POST)
public ModelAndView getMetricKeysAndRedirect(#RequestParam Object jsonObject, Model model)
{
ModelAndView modelAndView = new ModelAndView("redirect:/mdm-viewer.do");
.....
.....
....//make some service calls and populate value1
...
modelAndView.addobject("param1", value1);
return modelAndView;
}
I have another controller which is mapped to URL mdm-viewer.do (The redirect URL mentioned above):
#RequestMapping(value = "/mdm-viewer.do", method = RequestMethod.GET)
public String getMDMViewer(Model model) {
return "mdmViewer"; //returns a mdmViewer.jsp
}
Please note that the mdmviewer.jsp is a GWT entrypoint which is in classpath.
I have my firebug window open which tells me that a GET request was made for mdm-viewer.do, but it gives me a blank response. In fact, it does not redirect to the new jsp and stays on the same page from where the POST request was made.
However, if I copy the firebug URL and open it in a new window of my browser, I see the expected results.
Any ideas what I am doing wrong here? Tried to google it a lot, but can't find a similar issue anywhere.
Eventually, I returned a ModelAndView back from the POST method using a
#ResponseBody
And in my GWT Module, I used the response.getText() output to do a
#Override
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
JSONObject jsonObject = (JSONObject) JSONParser.parse(response.getText());
String viewName = jsonObject.get("viewName").isString().stringValue();
JSONObject jsonParams = jsonObject.get("model").isObject();
Set<String> chartKeys = jsonParams.keySet();
String redirectURL = viewName + "?";
for (String keyString : chartKeys) {
redirectURL = redirectURL + keyString + "=" + jsonParams.get(keyString).isString().stringValue() + "&";
}
Window.open(GWT.getHostPageBaseURL() + redirectURL, "_self", "");
}
}

Resources