Spring Multipart File with #RequestBody - spring

I am trying to upload data from an app to a spring backend service.
Things to upload are a DataModel containing data of the object to create and several images linked to the data.
Therefore I am using this method signature:
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public Survey createSurvey(#RequestBody SurveyPostHelper helper, #RequestParam(value="file", required = true) MultipartFile[] images)
I tried to play with the annotations, but either I get a blank images array or my helper is empty.
How would you solve this?
Thanks in advance.

I found out, that this method signature could do the job:
#ResponseBody
public Survey createSurvey(#RequestPart(required=true) SurveyPostHelper helper, #RequestPart(value="file", required = true) final MultipartFile[] images)
Important in my case was to set the MimeType in the client app. The files MimeType should be image/jpg and the SurveyPostHelpers to application/json to allow Spring to parse the json and bind it to my Object.

see an example of the client code working for me images is the list of files I want to save
var formData = new FormData();
for (var i = 0; i < images.length ; i++) {
formData.append('images', images[i]);
}
formData.append('adData', new Blob([JSON.stringify(adData)], {
type: "application/json"
}));

Related

How to mock a multipart file upload when using Spring and Apache File Upload

The project I'm working on needs to support large file uploads and know the time taken during their upload.
To handle the large files I'm using the streaming API of Apache FileUpload, this also allows me to measure the time taken for the complete stream to be saved.
The problem I'm having is that I cannot seem to be able to utilise MockMvc in an Integration Test on this controller. I know that the controller works as I've successfully uploaded files using postman.
Simplified Controller Code:
#PostMapping("/upload")
public String handleUpload(HttpServletRequest request) throws Exception {
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iterStream = upload.getItemIterator(request);
while (iterStream.hasNext()) {
FileItemStream item = iterStream.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (!item.isFormField()) {
// Process the InputStream
} else {
String formFieldValue = Streams.asString(stream);
}
}
}
Simplified Test Code:
private fun uploadFile(tfr: TestFileContainer) {
val mockFile = MockMultipartFile("file", tfr.getData()) // .getData*() returns a ByteArray
val receiveFileRequest = MockMvcRequestBuilders.multipart("/upload")
.file(mockFile)
.contentType(MediaType.MULTIPART_FORM_DATA)
val result = mockMvc.perform(receiveFileRequest)
.andExpect(status().isCreated)
.andExpect(header().exists(LOCATION))
.andReturn(
}
This is the error I'm currently getting
org.apache.tomcat.util.http.fileupload.FileUploadException: the
request was rejected because no multipart boundary was found
Can anyone help?
The MockMultipartFile approach won't work as Spring does work behind the scenes and simply passes the file around.
Ended up using RestTemplate instead as it actually constructs requests.

ASP.NET MVC - ajax call to server side for pdf files?

I am trying to make an Ajax call to my app's controller to get some PDF files as follows:
function AjaxCallImages(URL) {
var result = $.ajax({
type: "GET",
url: URL,
success: SuccessFunctionImages,
error: ErrorFunction
});
return result;
}
On the server side of my web app (in the model), I am reading files from a remote server:
public static List<byte[]> GetFiles()
{
List<byte[]> files = new List<byte[]>();
string uri = #"\\REMOTER_SERVER_IP\Users\Public\myfolder";
string[] filesInfo = Directory.GetFiles(uri);
foreach (string fPath in filesInfo)
{
string fileName = MYPATH;
using (var webClient = new WebClientNoKeepAlive())
{
byte[] filedata = webClient.DownloadData(fPath);
files.Add(filedata);
}
}
return files;
}
and the result (List) is sent back to the controller in the ajax call.
What I receive is arrays of strings.
I need to show these pdf files in the browser but I am not sure how could I do this and if using Ajax is a good idea. But since I want to show images without reloading the page, I opted for Ajax. It there a good solution to do so? I would appreciate if someone kindly guide me about that. Thank you

spring social facebook accessToken with 400 error

Hi please help am new to spring social,i am getting the 400 error while getting the access token from the AUTHORIZATION_CODE..
my code is as follows
#RequestMapping(value = "/facebook", method = RequestMethod.POST, produces = "application/json")
#ResponseBody
public Object getFacebookLoginPage(#RequestBody SocialCommand socialCommand) throws Exception {
loggerService.debug("In ShareController", "getFacebookLoginPage method for facebook", "returns the JSON response for the input socialCommand");
Result result = new Result();
result.status = "OK";
dataObject = socialCommand;
FacebookConnectionFactory connectionFactory = new FacebookConnectionFactory(msgprop.getProperty("facebook.appId"), msgprop.getProperty("facebook.appSecrete"), msgprop.getProperty("facebook.namespace"));
oAuth2Operations = connectionFactory.getOAuthOperations();
OAuth2Parameters params = new OAuth2Parameters();
params.setScope(msgprop.getProperty("facebook.scope"));
params.setRedirectUri(msgprop.getProperty("facebook.redirectURI"));
// params.set("Content-Type", MediaType.MULTIPART_FORM_DATA.getType());
String authorizeUrl = oAuth2Operations.buildAuthorizeUrl(GrantType.AUTHORIZATION_CODE, params);
System.out.println(authorizeUrl);
SuccessResponse successResponse = new SuccessResponse();
successResponse.resultObj = authorizeUrl;
result.response = successResponse;
return result;
}
and the callback controller is as follows
#RequestMapping(value = "/facebook/callback", params = "code", method = RequestMethod.GET)
public Object faceBookCallback(#RequestParam(value = "code") String callBackCode, Model model) throws IOException {
loggerService.debug("In ShareController", "faceBookCallback method for facebook", "returns the JSON response for the input socialCommand");
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add("client_id", msgprop.getProperty("facebook.appId"));
formData.add("client_secret", msgprop.getProperty("facebook.appSecrete"));
formData.add("scope", msgprop.getProperty("facebook.scope"));
formData.add("redirect_uri", msgprop.getProperty("facebook.redirectURI"));
formData.set("grant_type", "authorization_code");
formData.set("Content-Type", MediaType.MULTIPART_FORM_DATA.getType());
AccessGrant accessGrant = oAuth2Operations.exchangeForAccess(callBackCode, msgprop.getProperty("facebook.redirectURI"), formData);
System.out.println(accessGrant.getAccessToken());
appStatus.getActivityId();
SocialCommand socialCommand = (SocialCommand) dataObject;
socialCommand.setAppType("facebook");
socialCommand.setAccessToken(accessGrant.getAccessToken());
getImageLocation(socialCommand);
model.addAttribute("activityId", appStatus.getActivityId());
return "backToViewDetails";
}
oAuth2Operations.exchangeForAccess giving the 400 bad request
A couple of things I notice...
First, why are you writing your own controller for performing the OAuth dance instead of using ConnectController that Spring Social provides? ConnectController can handle all of the redirects for you and has been part of Spring Social from the beginning. Spring Social Showcase (https://github.com/spring-projects/spring-social-samples/tree/master/spring-social-showcase) is an example of a project that uses ConnectController.
Even so, assuming you have good reason for writing your own connection controller, I see nothing in getFacebookLoginPage() that performs the actual redirect to Facebook, so I can only assume that happens in code not shown. Then when the redirect comes back from Facebook, I'm puzzled as to why you set the content type and most of those parameters before calling exchangeForAccess(). (Even then, you're setting what looks like a request header, but you're setting it as a form parameter...not necessary, but also not what you had in mind.)
Again, I encourage you to take a look at ConnectController (https://github.com/spring-projects/spring-social/blob/master/spring-social-web/src/main/java/org/springframework/social/connect/web/ConnectController.java). It will probably do what you need it to do. And even if you still feel the need to writing your own controller, you can look at how ConnectController works as a guide to how to write your own controller.

Storing a (possibly large) file between requests in Spring

I have this controller methods that depending on the parameters introduced by the user downloads a certain PDF file and shows a view with its different pages converted to PNG.
So the way I approached it works like this:
First I map a method to receive the post data sent by the user, then generate the URL of the actual PDF converter and pass it to the model:
#RequestMapping(method = RequestMethod.POST)
public String formPost(Model model, HttpServletRequest request) {
//Gather parameters and generate PDF url
Long idPdf = Long.parseLong(request.getParam("idPdf"));
//feed the jsp the url of the to-be-generated image
model.addAttribute("image", "getImage?idPdf=" + idPdf);
}
Then in getImageMethod I download the PDF and then generate a PNG out of it:
#RequestMapping("/getImage")
public HttpEntity<byte[]> getPdfToImage(#RequestParam Long idPdf) {
String url = "myPDFrepository?idPDF=" + idPdf;
URL urlUrl = new URL(url);
URLConnection urlConnection;
urlConnection = urlUrl.openConnection();
InputStream is = urlConnection.getInputStream();
return PDFtoPNGConverter.convert(is);
}
My JSP just has an img tag that refers to this url:
<img src="${image}" />
So far this work perfectly. But now I need to allow the possibility of viewing multi page PDFs, converted as PNGS, each of them in a different page. So I would add a page parameter, then feed my model with the image url including that page parameter, and in my getImage method I would convert only that page.
But the way it is implemented, I would be downloading the PDF again for each page, plus an additional time for the view, so it can find out whether this specific PDF has more pages and then show the "prev" and "next" buttons.
What would be a good way to preserve the same file during these requests, so I download it just once? I thought about using temp files but then managing its deletion might be a problem. So maybe storing the PDF in the session would be a good solution? I don't even know if this is good practice or not.
I am using Spring MVC by the way.
I think the simplest way would be using spring cache abstraction. Look at tutorial and will need to change your code a little: move logic that load pdf to separate class.
it will looks like:
interface PDFRepository {
byte[] getImage(long id);
}
#Repository
public class PDFRepositoryImpl implements PDFRepository {
#Cacheable
public byte[] getImage(long id) {
String url = "myPDFrepository?idPDF=" + idPdf;
URL urlUrl = new URL(url);
URLConnection urlConnection;
urlConnection = urlUrl.openConnection();
InputStream is = urlConnection.getInputStream();
return PDFtoPNGConverter.convert(is);
}
}
You will get pluggable cache implementation support and good cache expiration management.

Jersey:Returning a Response with a Map containing Image Files and JSON String values

I am using Jersey JAX-RS.
I want to return a Response with a Map containing Image Files and JSON String values.
Is this the right way to do this:
Map<String,Object> map = new HashMap........
GenericEntity entity = new GenericEntity<Map<String,Object>>(map) {};
return Response.ok(entity).build();
Or is this better.I plan to use JAX-RS with Jersey only.
JResponse.ok(map).build();
I am basing this on this article:
http://aruld.info/handling-generified-collections-in-jersey-jax-rs/
I am not sure what to specify for #Produces too(planning to leave it out).
TIA,
Vijay
You better produce a multipart response:
import static com.sun.jersey.multipart.MultiPartMediaTypes.MULTIPART_MIXED_TYPE;
import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE
#GET
#Produces(MULTIPART_MIXED_TYPE)
public Response get()
{
FileDataSource image = ... (gets the image file)
String info = ... (gets the xml structured information)
MultiPart multiPart = new MultiPart().
bodyPart(new BodyPart(info, APPLICATION_XML_TYPE)).
bodyPart(new BodyPart(image, new MediaType("image", "png")));
return Response.ok(multiPart, MULTIPART_MIXED_TYPE).build();
}
This example was taken from there.

Resources