Current request is not a multipart request - Angular and Spring - java

I'm using angular and spring and i face issue in the backend :
org.springframework.web.multipart.MultipartException: Current request is not a multipart request
I try to send a xlsx or xlsm file to the backend.
I already tried to add enctype="multipart/form-data" and "Content-Type": "multipart/form-data" in headers.
What should i add to accept multipart request ?
Thank you.
upload-file.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpRequest, HttpHeaders, HttpEvent, HttpParams } from '#angular/common/http';
import { Observable } from 'rxjs';
import { environment } from 'src/environments/environment';
import { CommonData } from '#arom/arom-platform-auth-lib';
#Injectable({
providedIn: 'root'
})
export class UploadFileService {
private headers: HttpHeaders;
private commonData: CommonData;
constructor(private http: HttpClient) {
this.commonData = new CommonData();
this.headers = new HttpHeaders(this.commonData.getCommonHeaders());
}
upload(fichier: File, idAffaire: string): Observable<Object> {
console.log('Appel du webservice insererFichierExportGTI');
let url = this.getPqiPath();
url += environment.services.pqi.endpoints.postgtiservice;
let params: HttpParams = new HttpParams().set('idAffaire', idAffaire);
const formData: FormData = new FormData();
formData.append('fichier', fichier);
return this.http.post(url, { headers: this.headers, "Content-Type": "multipart/form-data", "fichier": formData, "idAffaire": idAffaire });
}
private getPqiPath(): string {
let url: string = environment.services.protocol;
url += '://';
url += environment.services.hostname;
url += ':';
url += environment.services.gateway.port;
url += environment.services.pqi.route;
return url;
}
}
gti-rechercher.component.html
<div class="container">
<form method="post" action="/" enctype="multipart/form-data">
<div class="form-row">
<div class="col-md-8">
<label for="parcourir_bouton">Fichier GTI :</label>
<input pfmButton type="file" class="form-control-file" id="parcourir_bouton" name="import"
formControlName="import" ngModel accept=".xlsx, .xlsm" (change)="selectFile($event)">
</div>
<div class="col-md-6">
<button pfmButton type="submit" id="importer_bouton" class="btn btn-primary mb-2"
(click)='two.startTimer(); upload()'>Importer</button>
</div>
</div>
</form>
<app-gti-timer #two></app-gti-timer>
</div>
AffaireController.java
#RequestMapping(value=("/api"),headers=("content-type=multipart/*"))
public class AffaireController extends AromController {
#Autowired
ServiceAffaire serviceAffaire;
#PreAuthorize("#oauth2.hasScope('ma_tsc_insertion-export-fichier-gti')")
#PostMapping(value = "/insererFichierExportGTI")
#HystrixCommand(threadPoolKey = "domainThreadPool")
public ResponseEntity<ApiResponse<JsonMessage>> insererFichierExportGTI(Long idAffaire,
#RequestParam("file") MultipartFile fichier) {
JsonMessage retour = new JsonMessage();
retour.setMessage(serviceAffaire.insererFichierExportGTI(idAffaire, fichier));
return getResponse(retour);
}
}

The answer :
let retour = this.http.post<any>(url, formData, { headers: this.headers, params: params });
Thank You

Related

Angular Login Authentication: When submit button is pressed twice with invalid credentials, automatically login

I have created a simple login function in Angular with Spring Boot. Here are my Angular controllers. My backend function returns a boolean true or false and It returns correctly. The mystery is, the first click on the login button, for both correct and wrong credentials it goes to the else block in the autheticate() method (makes it a invalid login). But when again click on the login button (with any data for username n password), even though the response from the backend is "false" it goes inside the if block and authenticate the login. Can someone help me to tell why this happens and how to correct it? (is my logic here and code is correct?. Spent days now looking where is the error)
Login.component.html
<div class="content-header">
<div class="container-fluid">
<div class="row">
<div class="col-lg-4"></div>
<div class="col-lg-4" style="margin-top: 50px;">
<form>
<div class="imgcontainer">
<img src="assets/dist/img/logo.jpg" alt="Avatar" class="avatar" style="width: 218px;height: 218px;">
</div>
<div class="imgcontainer" *ngIf=message>
{{message}}
</div>
<div class="container">
<label for="uname"><b>Username</b></label>
<input type="text" placeholder="Enter Username" [(ngModel)]="authObjModel.username" name="uname" required>
<label for="psw"><b>Password</b></label>
<input type="password" placeholder="Enter Password" [(ngModel)]="authObjModel.password" name="psw" required>
<button type="button" (click)=checkLogin()>Login</button>
</div>
</form>
</div>
<div class="col-lg-4"></div>
</div>
</div>
Login.component.ts
import { AuthService } from "./../auth.service";
import { AuthObj } from "./../auth-obj";
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Router } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
message:string;
invalidLogin = false;
authObjModel = new AuthObj("","");
constructor(private loginservice:AuthService, private router: Router) { }
ngOnInit(): void {
}
checkLogin() {
if (this.loginservice.authenticate(this.authObjModel)) {
this.router.navigate(['']);
this.invalidLogin = false;
} else {
this.invalidLogin = true;
this.message = 'Invalid Credentials';
}
}
}
Auth.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class AuthService {
status:any;
constructor(private http: HttpClient) { }
authenticate(credentials) {
const response = this.http.post('http://localhost:8080/login', credentials, { responseType: 'text' as 'json'})
.subscribe((data) => this.status = data);
if ( this.status ) {
sessionStorage.setItem('username', credentials.username);
return true;
} else {
return false;
}
}
isUserLoggedIn() {
let user = sessionStorage.getItem('username');
return !(user === null);
}
logOut() {
sessionStorage.removeItem('username');
}
}

HTTP Status 415 – Unsupported Media Type error

The origin server is refusing to service the request because the payload is in a format not supported by this method on the target resource.
Controller code
#RestController
public class UserController
{
#Autowired
public IretrieveService retrieveService;
#RequestMapping(value="/register", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public ModelAndView doRegister(#RequestBody UserBean userBean,BindingResult result)
{
ModelAndView view = new ModelAndView("index");
System.out.println("username "+userBean.getUsername());
if(!result.hasFieldErrors())
{
if(retrieveService.insert(userBean) != null)
{
System.out.println("done");
}
}
return view;
}
}
Angular js code
<script type="text/javascript">
var app = angular.module('myApp', []);
app.controller("UserController", ['$scope', '$http', function($scope, $http, httpPostService) {
var self=this;
self.userBean={username:''};
$scope.insertData = function()
{
alert($scope.userBean.username);
$http({
method: "POST",
url: "register",
data: $scope.userBean.username
}).then(function(response){
console.log(response.status);
console.log("in success");
}, function(response){
console.log(response.status);
console.log("in fail");
});
};
}]);
</script>
<form method="post" action="register" name="myForm">
<label for="username" class="control-label">First Name:</label>
<input type="text" data-ng-model="userBean.username" class="form-control" placeholder="Enter Firstname"/>
<button type="submit" data-ng-click="insertData()" class="btn btn-primary">Submit</button>
</form>
Error comes but didn't pass value from angular js to controller class
You are getting 415 http error because of your controller expects application/json but you are sending raw string data.
Here is a working example of how to post json data:
Javascript:
var data = { "name":"emre" }
$.ajax({
type: "POST",
url: "http://localhost:8080/yourUrl",
data: JSON.stringify(data),
contentType: "application/json",
cache: false,
timeout: 600000,
success: function (data) {
alert("success")
},
error: function (e) {
alert("ERROR : ", e);
}
});
Controller :
#CrossOrigin
#PostMapping
public ResponseEntity post(#RequestBody UserBean request) {
return ResponseEntity.status(HttpStatus.CREATED).body(request); // your response
}
UserBean class :
#Data // comes from lombok for getter setter purpose
class UserBean {
private String name;
}
You can adjust controller and javascript according to your needs.
It looks to me like the data you send to the controller is a String and not a UserBean object. Your payload is $scope.userBean.username but your controller expects #RequestBody UserBean userBean.
Changing the controller to
public ModelAndView doRegister(#RequestBody String userName, BindingResult result)
might solve the problem.

How to upload form with image file in it, AngularJS spring

I have this form
<div class="row">
<h1 class="page-header">
Create
</h1>
<form ng-submit="create()", enctype="multipart/form-data">
<div class="form-group">
<label>Name:</label>
<input type="text" ng-model="subforum.name" class="form-control" />
</div>
<div class="form-group">
<label>Desc:</label>
<input type="text" ng-model="subforum.desc" class="form-control" />
</div>
<input type="file" ngf-select ng-model="subforum.icon" name="subforum.icon"
accept="image/*" ngf-max-size="2MB" required
ngf-model-invalid="errorFile">
<img ng-show="myForm.file.$valid" ngf-thumbnail="subforum.icon" class="thumb"> <button ng-click="subforum.icon= null" ng-show="subforum.icon">Remove</button>
<button class="btn btn-success" type="submit">Create</button>
</form>
``
In my JS
.config(function($stateProvider) {
$stateProvider.state('create', {
url:'/subforum/create',
views: {
'main': {
templateUrl:'subforum/create.tpl.html',
controller: 'CreateCtrl'
}
},
data : { pageTitle : "Create Subforum" }
})
and
.factory('subforumService', function($resource) {
var service = {};
service.create = function (subforum, success, failure) {
var SubForum= $resource ("/web-prog/rest/subforums");
SubForum.save({}, subforum, success, failure) ;
};
.controller("CreateCtrl", function($scope, $state, subforumService) {
$scope.create = function() {
$scope.subforum.author = JSON.parse(localStorage.getItem ("logedUser"));
subforumService.create($scope.subforum,
function(returnedData) {
$state.go("home");
},
function() {
alert("Error creating");
});
};
I know thats not best practice to save user in LocalStorage but for now its like that.
On backend i have controller and in that controller i have methode:
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<SubForumResource> createPodforum(#RequestBody SubForumResource sentPodforum) {
}
and SubForumResource is
public class PodforumResource extends ResourceSupport {
private String name;
private String desc;
private byte[] icon;}
with geters and seters and everything i need.
So when i have form without image it works without problems. But i need icon too. Im new to angularjs but need it for this project. When i try to use FormData() i dont know how to use $resource. So if someone can help me i would be thankful. This is my first prject i need to work front end so im lost.
You can refer below code for angularjs :
this.addEmployee = function (requestData, file) {
var data = new FormData();
data.append('file', file[0]);
data.append('requestData', new Blob([JSON.stringify(requestData)], {
type: "application/json"
}));
var config = {
transformRequest: angular.identity,
transformResponse: angular.identity,
headers: {
'Content-Type': undefined
}
}
var url = "http://localhost:8080/addEmployee";
var promise1 = $http.post(url, data, config);
var promise2 = promise1.then(function (response) {
return response.data;
},
function errorCallback(response) {
alert(response.data.errorMessage);
});
return promise2;
}
And for controller :
#RequestMapping(value = "/addEmployee", method = RequestMethod.POST, consumes = {"multipart/form-data" })
#CrossOrigin
public CustomResponse addEmployee(#RequestPart("file") MultipartFile file, #RequestPart("requestData") Employee emp) {
}

How to solve MissingServletRequestPartException inSpring upload

I am having a problem uploading picture in Spring. I have encountered countless problems, which i have tried to solve. For my current error i have tried all the solution provide by spring but it still persist. According to spring the issue of MissingServletRequestPartException can be solved by including a MultipartResolver.`http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/multipart/support/MissingServletRequestPartException.html. I have done that (find below), but the issue still persist.
Error
timestamp: 1490599131962, status: 400, error: "Bad Request",…}
error:"Bad Request"
exception:"org.springframework.web.multipart.support.MissingServletRequestPartException"
message:"Required request part 'uploadfile' is not present"
path:"/uploadFile"
Config
#Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(100000);
return new CommonsMultipartResolver();
}
Controller
public ResponseEntity<?> uploadFile(#RequestParam("uploadfile") MultipartFile uploadfile, Picture picture, Principal principal, MultipartHttpServletRequest request) {
User user = (User) ((UsernamePasswordAuthenticationToken) principal).getPrincipal();
picture.setUser(user);
Iterator<String> itrator = request.getFileNames();
MultipartFile multiFile = request.getFile(itrator.next());
try {
System.out.println("File Length:" + multiFile.getBytes().length);
System.out.println("File Type:" + multiFile.getContentType());
// Crop the image (uploadfile is an object of type MultipartFile)
BufferedImage croppedImage = cropImageSquare(multiFile.getBytes());
String fileName=multiFile.getOriginalFilename();
System.out.println("File Name:" +fileName);
String path=request.getServletContext().getRealPath("/");
// Get the filename and build the local file path
File directory= new File(path+ "/uploads");
directory.mkdirs();
String filename = uploadfile.getOriginalFilename();
String ext = FilenameUtils.getExtension(filename);
File outPutFile = new File(directory.getAbsolutePath()+System.getProperty("file.separator")+picture.getUploadfile());
ImageIO.write(croppedImage, ext, outPutFile);
} catch (Exception e) {
System.out.println(e.getMessage());
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
pictureService.save(picture, uploadfile);
return new ResponseEntity<>(HttpStatus.ACCEPTED);
}
JS FILE
'use strict';
var $formUploader = $("#upload-file-input");
$formUploader.on("submit", function(e){
e.preventDefault();
var data = new FormData(this);
$.each($formUploader.serializeArray(), function(i, field) {
data[field.name] = field.value;
});*/
$.ajax({
//dataType: 'json',
url: $formUploader.prop('action'),
type: "POST",
//data: new FormData($("#upload-file-input")[0]),
data: data,
enctype: 'multipart/form-data',
processData: false,
contentType: false,
cache: false,
success: function (data) {
console.log(data);
// Handle upload success
$("#upload-file-message").text("File succesfully uploaded");
},
error: function (response) {
console.log(response);
// Handle upload error
$("#upload-file-message").text("File not uploaded (File might be big, size needed.)");
}
});
});
Form
<form id="upload-file-input" th:action="#{/uploadFile}" method="post" th:object="${picture}"
enctype="multipart/form-data" class="form-inline inline new-item">
<div th:replace="common/layout :: flash"></div>
<fieldset>
<legend> Upload Picture</legend>
<div class="row">
<div class="col s12 l8">
<div class="file-wrapper">
<input type="file" id="file" name="uploadfile" />
<span class="placeholder" data-placeholder="Choose an image...">Choose an image...</span>
<label for="file" class="button">Browse</label>
<span id="upload-file-message"></span>
</div>
</div>
<button type="submit" class="btn btn-primary">Upload</button>
</div>
</fieldset>
<div class="style16"></div>
</form>
You added all form values into the FormData, but didn't add a content of file. That's how it can be done:
...
var data = new FormData(this);
$.each($formUploader.serializeArray(), function(i, field) {
data[field.name] = field.value;
});
//next line will add content of file
data.append('fileContent', $('#file').files[0]);
$.ajax({ ...
You can use any name instead of fileContent, it doesn't matter.
In case when user enables to select multiple files at once, you have to add contents of all of this files:
...
var data = new FormData(this);
$.each($formUploader.serializeArray(), function(i, field) {
data[field.name] = field.value;
});
$.each($('#file').files, function(i, file) {
formData.append('fileContent' + i, file);
});
$.ajax({ ...

AngularJS http POST to Servlet

I went through a lot of StackOverflow answers and googled a lot but still could not find why my post request is not working.
This is my jsp:
<div class="container">
<form class="form-signin" ng-controller="MyController">
<h2 class="form-signin-heading">Please sign in</h2>
<label for="username" class="sr-only">Username</label>
<input type="text" id="username" ng-model="user.name" class="form-control" placeholder="Username" required autofocus>
<label for="password" class="sr-only">Password</label>
<input type="password" ng-model="user.password" id="password" class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" ng-click="login()" type="submit">Sign in</button>
</form>
</div>
This is my controller:
app.controller('MyController', function($scope, $http) {
$scope.login = function() {
console.log($scope.user);
$http({
method : 'POST',
url : 'login',
data : $scope.user,
headers: {
'Content-Type': 'application/json'
}
}).success(function(data) {
console.log(data);
}).error(function(data) {
console.log(data);
});
console.log("POST done");
};
});
And my servlet:
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("inside do POST");
Gson gson = new Gson();
JsonParser parser = new JsonParser();
JsonObject obj = (JsonObject) parser
.parse(request.getParameter("data"));
Iterator it = (Iterator) obj.entrySet();
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println("over");
}
I keep getting this Null pointer exception
java.lang.NullPointerException
at java.io.StringReader.<init>(StringReader.java:50)
at com.google.gson.JsonParser.parse(JsonParser.java:45)
at com.zookeeperUI.controller.Login.doPost(Login.java:40)
Please tell me what am I doing wrong here .
Your request does not contain a URL parameter named "data", therefore request.getParameter("data") returns null and you get the NullPointerException.
You try to send a Javascript object via URL parameters which does not go well with non-shallow objects.
I would recommend to send the data as request payload:
JsonObject obj = (JsonObject) parser.parse(request.getReader());
On the client you need to make sure that your data is sent as proper JSON:
$http({
method : 'POST',
url : 'login',
contentType: 'application/json',
data : JSON.stringify($scope.user),
})...
i think you should be sending data as
$http({
method : 'POST',
url : 'login',
data : {data: $scope.user},
headers: {
'Content-Type': 'application/json'
}
}).success(function(data) {
console.log(data);
});
pay attention to data : {data: $scope.user}
You are using a POST request and your data is sent in the request body - not as parameter. You need to read the content using request.getReader().
// example using the javax.json.stream package
JsonParser parser = Json.createParserFactory().createParser(request.getReader());

Categories