Displaying file in web page using AJAX and Spring Boot - ajax

I am building a REST API in Spring Boot for uploading and fetching file from the server, I want to upload various types of file that can either be text,image,audio,video,etc..
While uploading there is no problem, but when I want to display the file on my web page, on content is appearing, but I am getting the data from the server as a raw data.
I want to put that data into URL.createObjectURL() and then redirect to the URL which is generated.
There are some screenshots which I am uploading.
This is the data when I do console.log(response);
The code which I am using for AJAX
var form = new FormData();
form.append("qualifiedFilePath", "E://files/test.png");
var settings = {
"async": true,
"crossDomain": true,
"url": "http://localhost:8081/callTransaction/file",
"method": "POST",
"timeout": 0,
"processData": false,
"mimeType": "multipart/form-data",
"contentType": false,
"Accept": "image/png",
"data": form
};
$.ajax(settings).done(function(response) {
console.log(response);
const objectURL = URL.createObjectURL(new Blob([response], {
"type": "image/png"
}));
console.log(objectURL);
});
I get the URL:
blob:http://localhost:8080/81c9fbde-5e84-400e-8d92-5da6fc02c7ef
Output:
The Source Code in Spring Boot:
Controller:
#PostMapping(path="/file")
#CrossOrigin(origins = "http://localhost:8080")
public ResponseEntity<Resource> loadFile(#RequestPart("qualifiedFilePath") String qualifiedFilePath, HttpServletRequest request)
{
return ctbl.loadFile(qualifiedFilePath,request);
}
BusinessLogic:
public ResponseEntity<Resource> loadFile(String qualifiedFilePath, HttpServletRequest request)
{
Resource file=null;
if(qualifiedFilePath==null)
{
return new ResponseEntity<Resource>(file,HttpStatus.BAD_REQUEST);
}
try {
file=ctdi.loadFile(qualifiedFilePath);
} catch (MalformedURLException e) {
return new ResponseEntity<Resource>(file,HttpStatus.INTERNAL_SERVER_ERROR);
}
if(file==null)
{
return new ResponseEntity<Resource>(file,HttpStatus.NO_CONTENT);
}
String contentType = null;
try {
contentType = request.getServletContext().getMimeType(file.getFile().getAbsolutePath());
} catch (IOException ex) {
return new ResponseEntity<Resource>(file,HttpStatus.INTERNAL_SERVER_ERROR);
}
if(contentType == null) {
contentType = "application/octet-stream";
}
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(contentType))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"")
.body(file);
}
DAO:
#Override
public Resource loadFile(String qualifiedFilePath) throws MalformedURLException {
Path filePath = Paths.get(qualifiedFilePath);
Resource resource = new UrlResource(filePath.toUri());
return resource;
}

It has been a long time to answer since the question was posted, but the solution to it has been discovered.
It has a very simple solution.
I used the program logic from the CalliCoder webiste[the link is attached below], by using this I was able to store files, view files and download them too, they have given a very nice explanation of the program and how to do it.
By using this we can make a URL(endpoint) by which we can access the file we are approaching for, they too have given an example for accessing the file.
They have made a web-based front-end in which they are trying to upload files, but the module for displaying the file/downloading the file in front-end is missing.
Yes, We can just copy the URL(endpoint) in the browser and it starts displaying/playing the file.
If we want to use URL.createObjectURL() for making a temporary and local URL for the same source, then we can do like this:
URL.createObjectURL(await fetch("URL(endpoint)").then(r => r.blob()));
This example is taken from Stackoverflow[The link is attached bellow]
References:
CalliCoder
StackOverflow

Related

Expo & SpringBoot Multipart Upload Problem

I have been trying for hours now, to upload a file and a JSON using multipart file upload. I use Expo React Native as the client and SpringBoot as the server.
I already tried many different versions. After reading into this a lot, this is how it should work:
In my Expo app I have this:
const formData = new FormData();
formData.append(
'document',
new Blob([JSON.stringify(json)], {
type: 'application/json'
}));
formData.append('file', {
uri: url,
type: data.type,
name
});
const xhr = new XMLHttpRequest();
xhr.open('POST', API_URL);
xhr.setRequestHeader('Authorization', 'Bearer ' + jwt);
xhr.onload = () => {
const response = JSON.parse(xhr.response);
console.log(response);
// ... do something with the successful response
};
xhr.onerror = e => {
console.log(e, 'upload failed');
};
xhr.ontimeout = e => {
console.log(e, 'upload timeout');
};
xhr.send(formData);
In my SpringBoot Backend I have this:
#PostMapping(value = "/api/upload")
public ResponseEntity<Void> uploadDocument(
#RequestPart("document") DocumentDTO document,
#RequestPart("file") MultipartFile file) {
// ... my business logic
}
Now without the document it would work, but as soon as I add the document I get this error:
o.z.problem.spring.common.AdviceTraits : Bad Request: Required request part 'document' is not present
As a workaround I will upload files as base64 encoded strings for now ... But I really don't understand why this doesn't work, because it should.
Similar issue I think:
https://github.com/facebook/react-native/issues/30623
Any help would be greatly appreciated.
Try your backend with this approach. (May try removing Blob in FE, just leave it as
json string)
Create a class to wrap both document and file.
#Data
public class FormDataModel {
private MultipartFile file;
private DocumentDTO document;
public void setDocument(String document) {
ObjectMapper mapper = new ObjectMapper();
// this requires try-catch block in fact
this.document = mapper.readValue(document, DocumentDTO.class);
}
}
Use #ModelAttribute at Controller
#PostMapping(value = "/api/upload", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<Void> uploadDocument(#ModelAttribute FormDataModel wrapper) {
// ... my business logic
}

SpringMVC change JSP with post

I'm trying to update the user's current JSP on a post request. I am using #Controller annotation right now (I've also tried RestController)
Controller:
#PostMapping(value = { "postHome" })
public ModelAndView postHome(#RequestBody String body, ModelAndView model) {
JSONObject jsonObject = new JSONObject(body);
String customerName = jsonObject.getString("customerName");
model.setViewName("feasibility");
model.addObject("customerName", customerName);
return model;
}
JavaScript:
function postCustomer() {
var custName = {
"customerName": document.getElementById("customerName").value
};
fetch(sendURL, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(custName)
});
}
It's posting to the server just fine (I've printed out the body), but nothing happens after that. No errors or anything. The JSP I am trying to update the client with is feasibility.jsp. I tried something earlier and it was trying to force my client to run a GET on localhost:8080/feasibility?customerName=Name but that's not what I was trying to do.
In the past I was able to just return "feasibility" as a String, but that doesn't work with this project (could be the versions I was using before).
Thanks!

react can't get restController response

I have tried to use restController generate file byte array but when i return it to react , react didn't get the byte array. front-end is using react , back-end is using spring restController and i use Http to communication both front and back. is it any wrong in my code? Thank you for your helping.
restController:
String fileName = DateUtility.dateToStr(new Date(), DateUtility.YYYYMMDD_HHMMSS) + " - "
+ reportNmaeByType.get(exportParam.getReportType()) + ".xls";
HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData("attachment", fileName);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<>(excelByte, HttpStatus.OK);
react:
createExcelFile(){
var params = {
reportResultList: this.state.reportResult,
reportType: getReportSelector().state.selectedReportType,
selectColumnMap: this.state.selectColumn,
selectCusColumnMap: this.state.selectCusColumn
}
fetch("http://localhost:8080/mark-web/file/createExcel", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params)
}).then(res => {
if (res.ok) {
console.log(res)
console.log(this)
console.log('create excel success!!')
} else {
console.log('create excel Fail!!')
}
})
}
response:
enter image description here
Update 2018/09/16:
I have added some code in react function and it finally could download excel file but the file is broken. i have checked the blob object in response. it shows blob is json object. is it because i didn't decode to the blob object?
React:
}).then(res => {
if(!res.ok){
console.log("Failed To Download File")
}else{
return res.blob()
}
}).then(blob => {
console.log(blob)
let url = URL.createObjectURL(blob)
console.log(url)
var downloadAnchorNode = document.createElement('a')
downloadAnchorNode.setAttribute("href", url)
downloadAnchorNode.setAttribute("download", "excel" + ".xls")
downloadAnchorNode.click()
downloadAnchorNode.remove()
})
response:
enter image description here
So, from your network graph, it looks like your request is completing as expected, but you are just unable to derive the ByteArray from the response.
With normal requests which return a JSON or XML for e.x. you can read them in one go, as they are part of the body. In your case however, your body contains a Stream. You will thus have to handle reading that stream on your own.
You can do that with response.blob() :
The blob() method reads the stream to completion and returns a Blob object. You can then use this blob object to embed an image or download the file. For all intent and purposes, I would recommend using this. Unless you are dealing with huge files (>500 MB), it should suffice your needs.
For example:
fetch("http://localhost:8080/mark-web/file/createExcel", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(params)
}).then(res => {
if (!res.ok) {
throw new Error(res.statusText);
} else {
return res.blob()
}
}).then(blob => {// do your thing})
.catch(err => console.log(error))
Or
You can use the experimental ReadableStream interface for a more granular control over what you want to do with it.

Required request part 'file' is not present - Angular2 Post request

I am trying to get my file upload functionality done using Angular2 and SpringBoot. I can certify that my java code for the file uploading working fine since I have tested it successfully using Postman.
However, when it comes to sending the file from Angular2 front end, I am getting the HTTP 400 response saying Required request part 'file' is not present.
This is how I send the POST request from Angular2.
savePhoto(photoToSave: File) {
let formData: FormData = new FormData();
formData.append('file', photoToSave);
// this will be used to add headers to the requests conditionally later using Custom Request Options
this._globals.setRequestFrom("save-photo");
let savedPath = this._http
.post(this._endpointUrl + "save-photo", formData)
.map(
res => {
return res.json();
}
)
.catch(handleError);
return savedPath;
}
Note that I have written a CustomRequestOptions class which extends BaseRequestOptions in order to append Authorization header and Content Type header. Content Type header will be added conditionally.
Following is the code for that.
#Injectable()
export class CustomRequestOptions extends BaseRequestOptions {
constructor(private _globals: Globals) {
super();
this.headers.set('X-Requested-By', 'Angular 2');
this.headers.append('virglk', "vigamage");
}
merge(options?: RequestOptionsArgs): RequestOptions {
var newOptions = super.merge(options);
let hdr = this._globals.getAuthorization();
newOptions.headers.set("Authorization", hdr);
if(this._globals.getRequestFrom() != "save-photo"){
newOptions.headers.set('Content-Type', 'application/json');
}else{
//request coming from save photo
console.log("request coming from save photo");
}
return newOptions;
}
}
This conditional header appending is working fine. The purpose of doing that is if I add 'Content-Type', 'application/json' header to every request, file upload method in Spring controller will not accept it. (Returns http 415)
Everything seems to be fine. But I get Required request part 'file' is not present error response. Why is that? I am adding that param to the form Data.
let formData: FormData = new FormData();
formData.append('file', photoToSave);
This is the Spring Controller method for your reference.
#RequestMapping(method = RequestMethod.POST, value = "/tender/save-new/save-photo", consumes = {"multipart/form-data"})
public ResponseEntity<?> uploadPhoto(#RequestParam("file") MultipartFile file){
if (file.isEmpty()) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage("DEBUG: Attached file is empty");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.NOT_FOUND);
}
String returnPath = null;
try {
// upload stuff
} catch (IOException e) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage(e.getMessage());
return new ResponseEntity<ErrorResponse> (errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<String>(returnPath, HttpStatus.OK);
}
EDIT - Adding the payload of the request captured by the browser
As you can see, the param "file" is available there.
Try to add
headers: {
'Content-Type': 'multipart/form-data'
},
to your
.post(this._endpointUrl + "save-photo", formData)
Change formData.append('file', photoToSave);
to              formData.append('file', this.photoToSave, this.photoToSave.name); and also add headers specifying the type of data you are passing to API, in your case it will be 'Content-Type': 'multipart/form-data'. Post the output here if it fails even after changing this.
Is there a chance that you're using zuul in a secondary app that is forwarding the request? I saw this with an update where the headers were stripped while forwarding a multi-part upload. I have a gatekeeper app which forwards requests using zuul to the actual service via a looking from eureka. I fixed it by modifying the url like this:
http://myserver.com/service/upload
to
http://myserver.com/zuul/service/upload
Suddenly the 'file' part of the upload header was no longer stripped away and discarded.
The cause, I suspect was a re-try mechanism which cached requests. On failure, it would re-submit the requests, but somehow for file uploads, it wasn't working properly.
To upload a file to the server, send your file inside a FormData and set content type as multipart/form-data.
export const uploadFile = (url, file, onUploadProgress) => {
let formData = new FormData();
formData.append("file", file);
return axios.post(url, formData, {
headers: {
'Content-Type': 'multipart/form-data;charset=UTF-8',
// other headers
},
onUploadProgress,
})
};
To handle file object, be careful with consumes attribute and #RequestPart annotation here.
#PostMapping(value = "/your-upload-path", consumes = "multipart/form-data")
public ResponseEntity<Object> uploadFile(#RequestPart("file") #Valid #NotNull #NotBlank MultipartFile file) {
// .. your service call or logic here
}

Oracle MCS Custom API call from MAF Application

I have created a custom API in Oracle MCS to get the user information and trying to call it from MAF application... As a response i am getting 200 as success code... but when i try to parse the response it shows a HTML page instead of actual responce....
Custom API
https://mobileportalsetrial1304dev-mcsdem0001.mobileenv.us2.oraclecloud.com:443/mobile/custom/rvs_ekkfetchuserinfo/fetchcontent
and userid=101 as parameter
Calling Method to get User information
#Override
public Response getUserInformation(int userId) {
System.out.println("In loginService");
String restURI = "https://mobileportalsetrial1304dev-mcsdem0001.mobileenv.us2.oraclecloud.com:443/mobile/custom/rvs_ekkfetchuserinfo/fetchcontent?userid=" + userId;
String jsonRequest = "";
Response response = new Response();
response = RestUtil.callGet(restURI, jsonRequest);
return response;
}
callGet Method
public static Response callGet(String restURI, String jsonRequest) {
String responseJson = "";
Response response = new Response();
System.out.println("restURI:" + restURI);
RestServiceAdapter restServiceAdapter = Model.createRestServiceAdapter();
restServiceAdapter.clearRequestProperties();
restServiceAdapter.setConnectionName("MiddlewareAPI");
restServiceAdapter.setRequestType(RestServiceAdapter.REQUEST_TYPE_GET);
restServiceAdapter.addRequestProperty("Content-Type", "application/json");
restServiceAdapter.addRequestProperty("Accept", "application/json; charset=UTF-8");
restServiceAdapter.addRequestProperty("Oracle-Mobile-Backend-Id", "da5c7d86-29c0-43e8-b613-53de55a7ae6c");
restServiceAdapter.addRequestProperty("Authorization", "Basic TUNTREVNMDAwMV9NT0JJTEVQT1JUQUxTRVRSSUFMMTMwNERFVl9NT0JJTEVfQU5PTllNT1VTX0FQUElEOmR5Nm91NW5wX3RnbE5r");//+new String(encodedBytes));
restServiceAdapter.setRequestURI(restURI);
restServiceAdapter.setRetryLimit(0);
try {
responseJson = restServiceAdapter.send(jsonRequest);
System.out.println("response" + responseJson);
int responseCode = restServiceAdapter.getResponseStatus();
System.out.println("responseCode" + responseCode);
response.setResponseCode(responseCode);
response.setResponseMessage(responseJson);
response.setHeader(restServiceAdapter.getResponseHeaders());
} catch (Exception e) {
System.out.println("Error in calling API" + e.getStackTrace());
int responseCode = restServiceAdapter.getResponseStatus();
response.setResponseCode(responseCode);
response.setResponseMessage(responseJson);
}
return response;
}
Json Parsing
JSONObject obj = new JSONObject(response);
JSONArray arr = obj.getJSONArray("posts");
for (int i = 0; i < arr.length(); i++)
{
String user_id = arr.getJSONObject(i).getString("UserId");
}
Here what i am getting is JSONObject["items"] is not found... when i print the responce message it gives a HTML Script file
Expected Output
{
"items": [
{
"UserId": "101",
"AgentId": null,
"Category": "Rental",
"Division": "KDR",
"Status": null,
"LocationId": null,
"Operation": "CheckOut",
"Admin": "N",
"createdBy": "mcs-demo_user09#oracleads.com",
"createdOn": "2015-09-25T11:29:10.215564+00:00",
"modifiedBy": "mcs-demo_user09#oracleads.com",
"modifiedOn": "2015-09-25T11:29:10.215564+00:00"
}
]
}
what is the content of the HTML page (it will have some JavaScript I assume but should have a HTML title as well). Anyway, a user Id in MCS is not 101 but an internal ID, so I don't know if you've chosen 101 for simplification in this question.
In MAF, the REST connection is defined through a REST connection with the root URL and the relative URI. In your example, the REST connection is referenced as "MiddlewareAPI". Unless the value of this connection is null, the restURI you provide needs to be reduced to not contain the root URL.
The HTTP 200 you get because the request is answered by the server. However, it appears to be missing either an authorized user (in case of a failed basic authorization for accessing the API) or the authenticated user is not allowed to request the user platform API (by default you can only request information about the user you re authenticated as).
Frank
Hi I got the solution...
I was trying to call customAPI through Oracle-MCS. I replaced RestServiceAdapter with HttpsURLConnection. Then it Works perfectly fine.

Resources