I am posting a form of type file and I am handling that POST request in spring-boot controller by returning JSON data. I checked that request with postman its working fine, But when I am using onreadystatechange method in react it is giving xhr status =0
onSubmitForm(){
console.log("entered");
var xhr = new XMLHttpRequest();
xhr.open('POST', '/images', true);
//xhr.responseType = 'text';
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
var data = new FormData();
var imageFile = document.querySelector('input[type="file"]').files[0];
console.log( imageFile);
data.append("imageFile", imageFile);
xhr.onreadystatechange = function () {
if(xhr.readyState === XMLHttpRequest.DONE ){
alert(xhr.status);
if(xhr.status === 200){
alert('hi there');
}
}
}
xhr.send( data );
}
render() {
return (
<div>
<form encType="multipart/form-data" action="">
File to upload:
<input type="file" name="imageFile" accept="image/*" />
<input type="submit" value="Upload" onClick={ this.onSubmitForm.bind(this) } />
</form>
</div>
)
}
I am receiving the correct data in controller, But I am not getting JSON from POST request ??
controller
#PostMapping("/images")
public #ResponseBody JSONModel addContent( #RequestParam("imageFile") MultipartFile file,
imageApp content ) {
String encodedfile = null ;
double fileSize = file.getSize();
try {
byte[] bytes=file.getBytes();
System.out.println(fileSize/(1024*1024));
encodedfile = Base64.getMimeEncoder().encodeToString(bytes);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
content.setDate(LocalDateTime.now());
content.setLocation(UUID.randomUUID().toString() );
content.setId(UUID.randomUUID().toString() );
content.setContent(encodedfile);
return service.addContent(content);
}
service
public #ResponseBody JSONModel addContent(imageApp content) {
return new JSONModel(1, respository.save(content).getLocation());
}
Make <input type="submit" to type="button", keeping type="submit" tells the browser that page/form has to be submitted and it causing conflicting behavior which we need to prevent. So either change the type="button" or you can prevent the default behavior by taking the event in your handler and calling e.preventDefault();
Related
Im trying to fetch photo of a particular userId which is stored in the database,
Im able to generate response from the API as shown:
but it is received in the error part of the getPhotopath() method of controller as shown:
HTML:
<div class="col-md-3 " ng-init="modifyphoto()" >
<img class="smaller" ng-src="fetchedimg" ng-model="fetchedimg"><br>
<p>{{userName}}</p>
<div ng-model="userType">
<p>{{userType | UserFilter}}</p>
</div>
<div ng-controller="AskController">
<button class="btn btn-default" ng-click="gotouserdetails()">View
My Details</button>
</div>
</div>
Controller:
$scope.modifyphoto = function() {
$scope.getPhotoPath();
if($scope.userPhoto==null){
$scope.fetchedimg=$scope.defaultimg;
}
else{
$scope.fetchedimg=$scope.userPhoto;
}
};
$scope.getPhotoPath = function() {
var obj = JSON.parse($cookies.get('user'));
$scope.passUserId = obj.userId;
$http.get(URI + "user/getphoto"+"/"+$scope.passUserId).then(
function(response) {
alert("hifrsegfsfgv");
alert(response.data.message);
$scope.userPhoto=response.data.userPhoto;
}, function(response) {
alert("hi");
alert(response.data);
$scope.userPhoto =null;
alert("danger"+response.data.userPhoto);
});
};
API:
#Path("getphoto/{an}")
#GET
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response getPhoto(#PathParam("an") String userId) throws Exception {
String returnValue = null;
Response response = null;
User user = null;
try {
System.out.println(userId);
UserService userService = Factory.createUserService();
String photoPath=userService.getPhotoPath(userId);
user = new User();
user.setUserPhoto(photoPath);
System.out.println(photoPath);
returnValue = JSONParser.toJson(user);
System.out.println(returnValue);
response = Response.status(Status.OK).entity(returnValue).build();
} catch (Exception e) {
String errorMessage = AppConfig.PROPERTIES.getProperty(e.getMessage());
User user1 = new User();
user1.setMessage(errorMessage);
String returnString = JSONParser.toJson(user1);
response = Response.status(Status.SERVICE_UNAVAILABLE).entity(returnString).build();
}
return response;
}
Im not understanding if the status is OK in backend then why it is recieved in the error part?
Try returning your image in base64 format to avoid JSON Parse errors. and bind that image to the img tag
Hello i will tell you step by step,what i did,
1.I have HTML page named ManualChargesListV2.html,when page loads need to load the data in the Dropdown,so i use thymeleaf to show...
Here is #Controller Code
#GetMapping(value="/manualbillentry")
public ModelAndView doFetchUnitCharges(HttpSession session)
{
ModelAndView model = new ModelAndView();
WrpSession wrpsession = new WrpSession();
wrpsession = (WrpSession) session.getAttribute("totalObj");
try {
model.setViewName("ManualChargesListV2");
List<EntSetCharges> flatBillsManualList = new ArrayList<>();
flatBillsManualList = serbilldetails.doFetchUnitCharges(wrpsession);
model.addObject("manuallist",flatBillsManualList);
}
catch (Exception e){
e.printStackTrace();
}
return model;
}
2.The html page loads the data in dropdown perfectly,when choosing dropdown again need to hit the controller to show the data regarding selected dropdown value so i use to code like
<div class="form-group col-md-6">
<label for="chargelist">Select Charge *</label>
<select id="chargelist" class="form-control"
ng-model="selectedcharge"
ng-change="getChargeDetails(selectedcharge)">
<option> Select</option>
<option th:each="manualunitcharge:${manuallist}"
th:value="${manualunitcharge.pkSetCharges}"
th:text="${manualunitcharge.fkAssignCharges.chargeName}"></option>
</select>
</div>
it will call AngularJS ng-change="getChargeDetails(selectedcharge) method,it successfully hits the controller incl selected data.And Sends the data
#GetMapping(value = "manualbillentry/showmanuallist/{chargeid}")
private ResponseMsg doFetchManualChargesList(#PathVariable("chargeid")int chargeid,HttpSession session)
{
ResponseMsg response = new ResponseMsg();
WrpSession wrpsession = new WrpSession();
wrpsession = (WrpSession) session.getAttribute("totalObj");
try {
List<EntFlatIncome> unitChargesList = new ArrayList<>();
unitChargesList = serbilldetails.doFetchManualChargesList(chargeid,wrpsession);
response.setStatus("success");
response.setDataObj(unitChargesList);
}
catch (Exception e){
e.printStackTrace();
response.setStatus("failed");
}
return response;
}
var app = angular.module('ngapppmanual', []);
app.controller('ngctrlmanual', function($scope, $http, $location) {
$scope.ngshowchargelist = false;
$scope.getChargeDetails = function()
{
var url = $location.absUrl() + "/showmanuallist/" + $scope.selectedcharge;
var config = {
headers : {
'Content-Type' : 'application/json;charset=utf-8;'
}
}
$http.get(url, config).then(function(response)
{
if (response.data.status == "success")
{
$scope.manualresult = response.data.dataObj;
$scope.ngshowchargelist = true;
} else
{
$scope.getResultMessage = "Customer Data Error!";
}
},
function(response)
{
$scope.getResultMessage = "Fail!";
});
}
});
I need to Load the Data in in same HTML page But the issue is while responding result as incl Error code 500
org.thymeleaf.exceptions.TemplateInputException: Error resolving template "manualbillentry/showmanuallist/1", template might not exist or might not be accessible by any of the configured Template Resolvers.
i cant understand the issue ,please someone helpme out...
you are using #Controller which returns html, instead you can use #RestController that returns JSON which angularJS is expecting
I am trying to make a simple file upload possible but Spring does not want to play with me.
This is the endpoint for file uploads - currently not doing a lot:
#PostMapping(WordEmbeddingApiPaths.UPLOAD_MODEL)
#RequestMapping(method=RequestMethod.POST, consumes = {"multipart/form-data"})
public ResponseEntity<WordVectorListDto> uploadModel(
#ModelAttribute("file") MultipartFile file,
// #RequestBody Object obj,
RedirectAttributes redirectAttributes) {
LOGGER.debug("POST uploadModel");
return new ResponseEntity<WordVectorListDto>((WordVectorListDto)null, HttpStatus.OK);
}
I've tried several things but it all ends up in different errors. I've just tried to use #RequestBody because I thought maybe that's the trick but then I get an exception saying:
Content type 'multipart/form-data;boundary=----WebKitFormBoundarycV8dFSvDV6U9OwJq' not supported
or
Content type 'multipart/form-data' not supported
depending on what I just tried.
If I go with #RequestPart("file") MultipartFile file I see
Required request part 'file' is not present
which is similar for #RequestParam("file").
I have no idea what's so hard on this but I hope somebody can tell me how I can get that file from the client.
Below you can see the request I've sent to the endpoint:
Is this request okay?
Web Client:
var uploader = $scope.uploader = new FileUploader({
url: 'http://localhost:8080/rest-api/dl4j/we/uploadModel'
});
uploader.onAfterAddingFile = function($modelFile) {
console.info('onAfterAddingFile', $modelFile);
var fd = new FormData();
fd.append('file', $modelFile.file);
$http.post($modelFile.url, fd, {
headers: {
'Content-Type': undefined
},
transformRequest: angular.identity
})
.then(
function (data) {
alert("upload success");
},
function (data, status) {
alert("upload error");
}
);
};
index.html
<label class="btn btn-default btn-file" style="float:right;">
Upload
<input
type="file"
style="display: none;"
name="file"
multiple
nv-file-select
uploader="uploader">
</label>
Here is how i didi it:
#RequestMapping(value="/uploadFile", method=RequestMethod.POST)
public #ResponseBody String handleFileUpload(
#RequestParam("file") MultipartFile file){
String name = "test11";
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
BufferedOutputStream stream =
new BufferedOutputStream(new FileOutputStream(new File(name + "-uploaded")));
stream.write(bytes);
stream.close();
return "You successfully uploaded " + name + " into " + name + "-uploaded !";
} catch (Exception e) {
return "You failed to upload " + name + " => " + e.getMessage();
}
} else {
return "You failed to upload " + name + " because the file was empty.";
}
}
and dont forget to register the multipart resolver:
#Bean
public MultipartResolver multipartResolver() {
org.springframework.web.multipart.commons.CommonsMultipartResolver multipartResolver = new org.springframework.web.multipart.commons.CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(10000000);
return multipartResolver;
}
here is the html code ... take a look at the name/id of the input fields ..
File1 to upload:
Name1: <input type="text" name="name">
File2 to upload: <input type="file" name="file">
Name2: <input type="text" name="name">
<input type="submit" value="Upload"> Press here to upload the file!
</form>
I'm editing this post to show my latest attempt per suggestions below.
I have been searching the forums trying to find a solution. I have an ASP.NET MVC Application in which I use Angular. I am trying to use danialfarid/ng-file-upload to allow users to upload PDFs which then get saved to the database as binary data (not my idea, but I have to do it that way).
I have the following (taken from the examples) in my HTML:
File:<input type="file" ngf-select ng-model="picFile" name="file" accept="image/*" ngf-max-size="2MB" required ngf-model-invalid="errorFile"><br />
<img ngf-thumbnail="picFile" class="thumb"> <button ng-click="picFile = null" ng-show="picFile">Remove</button><br />
<button type="button" class="btn btn-primary" ng-click="uploadPic(picFile)">Upload</button>
And this in my Angular controller:
$scope.uploadPic = function (files) {
file.upload = Upload.upload({
url: '/SSQV4/SSQV5/Document/UploadEMRDocument',
data: {file: files}
})
}
My MVC Controller:
namespace SSQV5.Controllers
{
public class DocumentController : ApiController
{
public async Task<IHttpActionResult> UploadEMRDocument()
{
try
{
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
var f = provider.Contents.First(); // assumes that the file is the only data
if (f != null)
{
var filename = f.Headers.ContentDisposition.FileName.Trim('\"');
filename = Path.GetFileName(filename);
var buffer = await f.ReadAsByteArrayAsync();
//buffer now contains the file content,
//and filename has the original filename that was uploaded
//do some processing with it (e.g. save to database)
}
else
{
return BadRequest("Attachment failed to upload");
}
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
return Ok();
}
}
}
This code never hits the MVC Controller at all. I'm obviously missing something, but I haven't the slightest clue as to what it could be. Any assistance is greatly appreciated!
You need to extract the file content out of the form data.
Below is how I do this (using ng-file-upload in the same manner as you from the front end) to upload attachments in my application.
public async Task<IHttpActionResult> UploadAttachment()
{
// Check if the request contains multipart/form-data.
try
{
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
var f = provider.Contents.First(); // assumes that the file is the only data
if (f != null)
{
var filename = f.Headers.ContentDisposition.FileName.Trim('\"');
filename = Path.GetFileName(filename);
var buffer = await f.ReadAsByteArrayAsync();
//buffer now contains the file content,
//and filename has the original filename that was uploaded
//do some processing with it (e.g. save to database)
}
else
{
return BadRequest("Attachment failed to upload");
}
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
return Ok();
}
When you configure the upload, you specify the URL where the file will be posted to:
file.upload = Upload.upload({
url: 'myMVC/MyMethod',
data: {file: file}
})
This is part of my servlet:
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
#SuppressWarnings("deprecation")
Map<String, BlobKey> blobs = blobstoreService.getUploadedBlobs(req);
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iterator;
try {
iterator = upload.getItemIterator(req);
Picture pic = null;
PictureAccess access = null;
while(iterator.hasNext()){
FileItemStream item = iterator.next();
pic = new Picture( blobs.get(item.getFieldName()).getKeyString() );
access = new PictureAccess();
access.addPictures(pic, user.getEmail() );
}
} catch (FileUploadException e) {
e.printStackTrace();
}
res.sendRedirect("/user/picture/upload.jsp");
}
In my client side, I used JavaScript to change the names of the file:
<script type="text/javascript">
function uploadFile() {
if (window.File && window.FileList) {
var fd = new FormData();
var files = document.getElementById('fileToUpload').files;
for ( var i = 0; i < files.length; i++) {
fd.append("file" + i, files[i]);
}
var xhr = new XMLHttpRequest();
xhr.open("POST", document.getElementById('uploadForm').action);
xhr.send(fd);
alert('already saved');
document.getElementById('uploadForm').value = '';
} else {
document.getElementById('uploadForm').submit(); //no html5
}
}
</script>
In my html/jsp:
<form id="uploadForm" enctype="multipart/form-data" method="post" action="<%= blobstoreService.createUploadUrl("/user/uploadPics") %>">
<input type="file" name="fileToUpload" id="fileToUpload" multiple="multiple" size="5"/>
<input type="button" onclick="uploadFile();" value="Upload" />
</form>
The above codes works in development machine but not working when deployed. What are the possible error and solution to the problem? How can I see the error in appengine?
Deprecated method getUploadedBlobs(..) does not support multiple='true'. Try using getUploads(..) instead.