This question already has an answer here:
Why I can't handle multipart upload in this Spring Boot application? I obtain "no matching editors or conversion strategy found"
(1 answer)
Closed 3 years ago.
Technology: Spring Boot
Hello Developers, Can sombody tell me what is wrong with my code?
Why i'm unable to send attachment in email?
Exception:
There was an unexpected error (type=Internal Server Error, status=500).
Failed to convert value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'org.springframework.web.multipart.commons.CommonsMultipartFile'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'org.springframework.web.multipart.commons.CommonsMultipartFile': no matching editors or conversion strategy found
My jsp page
<pre>
<form:form modelAttribute="attachmentEmail" method="POST" action="/email-app/sendAttachmentEmail" cssClass="register-form"
id="register-form" enctype="multipart/form-data">
<div class="form-group">
<label for="fname"><i class="zmdi zmdi-account material-icons-name"></i></label>
<form:input path="name" name="name" id="name" placeholder="Name" required="required" />
<form:errors path="name" cssStyle="color:red;" cssClass="error" />
</div>
<div class="form-group">
<label for="phone"><i class="zmdi zmdi-phone"></i></label>
<form:input path="phone" name="phone" id="phone" placeholder="Phone" required="required" />
<form:errors path="phone" cssStyle="color:red;" cssClass="error" />
</div>
<div class="form-group">
<label for="email"><i class="zmdi zmdi-email"></i></label>
<form:input type="email" path="email" name="email" id="email" placeholder="Email" required="required" />
<form:errors path="email" cssStyle="color:red;" cssClass="error" />
</div>
<div class="form-group">
<label for="subject"><i class="zmdi zmdi-account material-icons-name"></i></label>
<form:input path="subject" name="subject" id="subject" placeholder="Subject" required="required" />
<form:errors path="subject" cssStyle="color:red;" cssClass="error" />
</div>
<div class="form-group">
<form:textarea path="comment" name="comment" id="comment" placeholder="Comment" rows="5" cols="35" required="required" />
<form:errors path="comment" cssStyle="color:red;" cssClass="error" />
</div>
<div class="form-group">
<label for="attachment"><i class="zmdi zmdi-file"></i></label>
<form:input path="attachment" type="file" name="attachment" id="attachment" required="required" />
<form:errors path="attachment" cssStyle="color:red;" cssClass="error" />
</div>
<div class="form-group form-button">
<input type="submit" id="signup" class="form-submit" value="Send" />
</div>
</form:form>
</pre>
My Contact.java & EmailController.java
<pre>
public class Contact {
#NotNull(message = "Name can't be blank.")
private String name;
#NotNull(message = "Name can't be blank.")
private String phone;
#NotNull(message = "Email can't be blank.")
private String email;
#NotNull(message = "Subject can't be blank.")
private String subject;
#NotNull(message = "Comment can't be blank.")
private String comment;
private CommonsMultipartFile attachment;
//getters
//setters
}
</pre>
My EmailController.java
<pre>
#RequestMapping(value ="/sendAttachmentEmail", consumes = "multipart/form-data", method = RequestMethod.POST)
public ModelAndView sendEmailWithAttachment(HttpServletRequest request, final #RequestParam("attachment") CommonsMultipartFile attachFile) throws MessagingException {
try {
ModelAndView mav =new ModelAndView("success");
log.info("Spring Boot - Sending Attachment Email...");
// reads form input
final String email = request.getParameter("mailTo");
final String phone = request.getParameter("phone");
final String name = request.getParameter("name");
final String subject = request.getParameter("subject");
final String comment = request.getParameter("comment");
log.info(name+" "+phone+" "+email+" "+subject+" "+comment);
if ((attachFile != null) && (attachFile.getSize() > 0) && (!attachFile.equals(""))) {
log.info("FileName====="+attachFile.getOriginalFilename());
} else {
log.info("FileName====="+attachFile.getOriginalFilename()+" "+attachFile);
}
Contact contact = new Contact();
contact.setName(name);
contact.setPhone(phone);
contact.setEmail(email);
contact.setSubject(subject);
contact.setComment(comment);
mav.addObject("name", contact.getName());
log.info("Sening Attachment Email...");
emailService.sendAttachmentEmail(contact, attachFile);
log.info("Done...");
return mav;
} catch (Exception e) {
log.error(e.getMessage());
return new ModelAndView("attachment-email");
}
}
</pre>
My EmailServiceImpl.java
<pre>
#Override
public void sendAttachmentEmail(Contact contact, CommonsMultipartFile attachfile) throws MessagingException {
emailSender.send(new MimeMessagePreparator() {
public void prepare(MimeMessage mimeMessage) throws Exception {
MimeMessage message = emailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); // Enable the multipart flag!
String content = "Hi, <b>"+contact.getName()+"</b> Thank you for Contacting Us. PFB attachment.<br>";
helper.setSubject(contact.getSubject());
helper.setText(content+" <b>Comment:</b> "+ contact.getComment(), true);
helper.setTo(contact.getEmail());
helper.setFrom(env.getProperty("spring.mail.username"));
// Determine If There Is An File Upload. If Yes, Attach It To The Client Email
if ((attachfile != null) && (attachfile.getSize() > 0) && (!attachfile.equals(""))) {
System.out.println("\nAttachment Name?= " + attachfile.getOriginalFilename() + "\n");
helper.addAttachment(attachfile.getOriginalFilename(), new InputStreamSource() {
public InputStream getInputStream() throws IOException {
return attachfile.getInputStream();
}
});
} else {
System.out.println("No Attachment Is Selected By The User. Sending Text Email.");
}
}
});
}
</pre>
After submitting the button i am getting above mentioned error, Kindly help.
The essential is here: Cannot convert value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'org.springframework.web.multipart.commons.CommonsMultipartFile': no matching editors or conversion strategy found
By the other words try to change signature of your controller's method sendEmailWithAtachment on:
public ModelAndView sendEmailWithAttachment(HttpServletRequest request, final #RequestParam("attachment") StandardMultipartFile attachFile)
Related
I'm trying to implement a login form in a Spring boot application. It has an email and a password field. The email field failed to get user input, here is the form:
<form th:action="#{/login}" method="get" th:object="${loginForm}" style="max-width: 600px; margin: 0 auto;">
<div class="m-3">
<div class="form-group row">
<label class="col-4 col-form-label">E-mail: </label>
<div class="col-8">
<input type="text" th:field="*{email}" name="q" class="form-control" required />
</div>
</div>
<div class="form-group row">
<label class="col-4 col-form-label">Password: </label>
<div class="col-8">
<input type="password" th:field="*{password}" class="form-control" required/>
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">Log in</button>
</div>
</div>
</form>
Here is the controller:
#GetMapping("login")
public ModelAndView login(Model model, #RequestParam(name = "q", required = false) Optional<String> email) {
Optional<UserDto> aUser;
System.out.println(email);
if (email.isPresent()) {
aUser = userService.getAUserByEmail(email.get());
model.addAttribute("user", aUser);
var mv = new ModelAndView("user/user-list", model.asMap());
return mv;
} else {
model.addAttribute("loginForm", new LoginForm());
return new ModelAndView("/login/login-form", model.asMap());
}
}
I thought the #RequestParam(name = "q") and name="q" in html would do the job, but I always get Optional.empty for email. Any idea what's wrong here?
UPDATE:
From the answers I changed controller to this:
#GetMapping("login")
public ModelAndView login(Model model, LoginForm loginForm) {
Optional<UserDto> aUser;
if (loginForm.getEmail() != null) {
aUser = userService.getAUserByEmail(loginForm.getEmail());
model.addAttribute("user", aUser);
var mv = new ModelAndView("user/user-list", model.asMap());
return mv;
} else {
model.addAttribute("loginForm", new LoginForm());
return new ModelAndView("/login/login-form", model.asMap());
}
}
login-form.html to this:
<form th:action="#{/login}" method="get" th:object="${loginForm}" style="max-width: 600px; margin: 0 auto;">
<div class="m-3">
<div class="form-group row">
<label class="col-4 col-form-label">E-mail: </label>
<div class="col-8">
<input type="text" th:field="*{email}" class="form-control" required />
</div>
</div>
<div class="form-group row">
<label class="col-4 col-form-label">Password: </label>
<div class="col-8">
<input type="password" th:field="*{password}" class="form-control" required/>
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">Log in</button>
</div>
</div>
</form>
I also have LoginForm.java like this
#Data
#AllArgsConstructor
#NoArgsConstructor
public class LoginForm {
private String email;
private String password;
}
but still not getting user email field input?
The way you have set up your form, it's mapping the value of your email input field to the property email (that's what th:field="*{email}" means) of an object called loginForm (that's what th:object="${loginForm}" means). Neither of these seem to be used or even exist in your login() method. You need to either change what you use in your controller to match what you have in your Thymeleaf template, or change your Thymeleaf template to actually reference what you are using in your controller.
The problem in your code is located under th:object="${loginForm}"
With this you inform spring to bind the data sent from the form into an object named loginForm.
So Spring actually expects the controller to be
#GetMapping("login")
public ModelAndView login(Model model, LoginForm loginForm) {
....
and inside LoginForm a field named email will contain the value sent from the form, as you have declared with <input type="text" th:field="*{email}" .... >
If you don't want the data to be bound into an object from Spring Mvc then
remove the th:object="${loginForm}"
use the
<input type="text" th:name="q" class="form-control" required />
and then the controller will receive the sent value as a query parameter
#GetMapping("login")
public ModelAndView login(Model model, #RequestParam(name =
"q", required = false) Optional<String> email) {
I'm trying to create new user. i want to send user information with image to mysql database. I'm sending a user object with form data .
this is my component.ts
subscribeUser() {
this.errorMessage = "";
if (this.subscribeForm.invalid) {
this.errorMessage = "cannot create user with empty fields";
return;
}
this.userService.createUser(this.user, this.selectedFile)
.subscribe(data => {
console.log(data);
this.router.navigate(['/login']);
}, error => {
console.log(error);
});
}
public onFileChanged(event) {
console.log(event);
this.selectedFile = event.target.files[0];
console.log(this.selectedFile);
}
this my service.ts
createUser(user: User,file : File) { let formdata: FormData = new FormData(); const userBlob = new Blob([JSON.stringify({"firstname":user.firstname,"lastname":user.lastname,"mail":user.mail,"password":user.password})],{ type: "application/json"});formData.append('file', file); formData.append('user', userBlob);return this.http.post<User>(AppSettings.APP_URL + "/users/new", formData,{responseType:'text' as 'json'});}
this is my controller.java
#PostMapping(value="/",
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE,"multipart/form-data"}))
public ResponseEntity createUser(#RequestPart("file") MultipartFile file, #RequestPart("user") User user) throws IOException {
if(user == null){
return ResponseEntity.badRequest().body("cannot create user with empty fields");
}
User createdUser = userRepository.save(user);
return ResponseEntity.ok(createdUser);
}
this is my component.html
<form [formGroup]="subscribeForm" (ngSubmit)="subscribeUser()" novalidate>
<div class="form-group">
<label for="formGroupExampleInput">Nom</label>
<input type="text" class="form-control" id="firstname" [(ngModel)]="user.firstname" name="firstname" placeholder="Nom" formControlName="nom">
</div>
<div class="form-group">
<label for="formGroupExampleInput2">Prénom</label>
<input type="text" class="form-control" id="lastname" [(ngModel)]="user.lastname" name="lastname" placeholder="Prenom" formControlName="prenom">
</div>
<div class="form-group">
<label for="formGroupExampleInput3">Email</label>
<input type="text" class="form-control" id="mail" [(ngModel)]="user.mail" placeholder="Email" name="mail" formControlName="mail" >
</div>
<div class="form-group">
<label for="formGroupExampleInput4">Password</label>
<input type="text" class="form-control" id="password" [(ngModel)]="user.password" placeholder="Password" formControlName="password" >
</div>
<div class="form-group">
<input type="file" [(ngModel)]="user.photo" (change)="onFileChanged($event)"></div>
<button class="btn btn-primary" type="submit">Register</button>
</form>
I get this error
"Content type 'application/octet-stream' not supported"
Thank you
Have you consider changing image type from File to BLOB.
And in REST Controller you can treat it as MultipartFile
Edit: the error you get
"Content type 'application/octet-stream' not supported"
I think it's your header mime type (see this mime type )
I am trying to develop a AMP form in AEM 6.1 and trying to submit data to back end sling servlet to save the data into database.But I am getting error in return:
<body>
<form class="sample-form"
method="post"
action-xhr="/bin/rating.rest"
target="_top">
<input type="text"
name="name"
placeholder="Name..."
required>
<input type="email"
name="email"
placeholder="Email..."
required>
<input type="text"
name="title"
placeholder="Title..."
required>
<input type="textarea"
name="textarea"
placeholder="Feedback..."
required>
<fieldset class="rating">
<input name="rating" type="radio" id="rating5" value="5" on="change:rating.submit">
<label for="rating5" title="5 stars">☆</label>
<input name="rating" type="radio" id="rating4" value="4" on="change:rating.submit">
<label for="rating4" title="4 stars">☆</label>
<input name="rating" type="radio" id="rating3" value="3" on="change:rating.submit" checked="checked">
<label for="rating3" title="3 stars">☆</label>
<input name="rating" type="radio" id="rating2" value="2" on="change:rating.submit" >
<label for="rating2" title="2 stars">☆</label>
<input name="rating" type="radio" id="rating1" value="1" on="change:rating.submit">
<label for="rating1" title="1 stars">☆</label>
</fieldset>
<input type="submit"
value="Submit Feedback">
<div submit-success>
<template type="amp-mustache">
Success! Thanks {{name}} for trying the <code>amp-form</code> demo! Try to insert the word "error" as a name input in the form to see how <code>amp-form</code> handles errors.
</template>
</div>
<div submit-error>
<template type="amp-mustache">
Error! Thanks {{name}} for trying the <code>amp-form</code> demo with an error response.
</template>
</div>
</form>
</body>
Back End Code::::
#SlingServlet(paths="/bin/rating.rest", methods = "POST", metatype=true)
public class AmpRatingActionServlet extends SlingAllMethodsServlet {
protected void doPost(SlingHttpServletRequest request,SlingHttpServletResponse response) throws ServletException,
IOException {
String jsonData = null;
String name;
String email;
String title;
String textarea;
String rating;
try
{
name = request.getParameter("name");
email = request.getParameter("email");
title = request.getParameter("title");
textarea = request.getParameter("textarea");
rating = request.getParameter("rating");
log.info(CLASSNAME+"::Inside Try Block:::::::name::::"+name+":::::email:::::"+email+":::::title:::::"+title+":::::textarea:::::"+textarea+":::::rating:::::"+rating);
}
}catch(Exception e) {
log.error(Error occurred in Servlet", e);
}
}
500
Message
javax.jcr.nodetype.ConstraintViolationException: No matching property definition: name = Test
I'm sort-of shocked that I can't find an example of how to do this. Every time I google it, I get info on how to post a collection of objects, or other unrelated stuff. The thymeleaf documentation (what I can find of it) seems to not explain much either, like there is a lot of assumed knowledge.
Getting back to my question, I just want to post a single object (bean) from a form. I would like my controller mapping method to bind to this "pojo" bean and not to a bunch of strings/integers.
The only thing that I have found that comes close is stuff on StackOverflow where half of the code is in the question, the other half is in the answer, and there are always a few comments from people saying it didn't work for them.
Can anyone offer any relief here with a plain old boring example?
Can find the below code snippet might helpful for you.
Controller GET/POST mapping:
#RequestMapping(value = "/registration", method = RequestMethod.GET)
public String registartionPage(Model model) {
Registration registration = new Registration();
model.addAttribute("registration", registration);
return "registarion/registarion";
}
#RequestMapping(value = "/user/new-user-registrn", method = RequestMethod.POST)
public String newUserRegistrn(Model model, #ModelAttribute("registration")
Registration registration, RedirectAttributes redirectAttributes) {
try {
StarUser user = starSecurityService.findSysUserName(registration.getUserName());
if (user != null) {
throw new Exception("User Already Exist. Please try with different User Name");
}
user = (StarUser) starUtilService.save(setStarUser(registration));
model.addAttribute("registration", registration);
if (user != null) {
redirectAttributes.addAttribute("starMessage",
"Your Account is successfully created !! Login to Access the Application");
return "redirect:/";
}
} catch (Exception e) {
model.addAttribute(STAR_MESSAGE, e.getMessage());
}
return "registarion/registarion";
}
Thymeleaf Content:
<form class="form-horizontal col-sm-12" method="POST" th:action="#{/user/new-user-registrn}" th:object="${registration}">
<div class="row">
<div class="form-group col-md-12">
<div class="star-reg-header">New User Registration</div>
</div>
<div class="star-reg-body">
<div class="form-group col-sm-4">
<label class="required">First Name: </label>
<input type="text" class="form-control required" th:field="*{firstName}" required="required" />
</div>
<div class="form-group col-sm-4">
<label class="required">Last Name: </label>
<input type="text" class="form-control" th:field="*{lastName}" required="required" />
</div>
<div class="form-group col-sm-4">
<label class="required">User Name: </label>
<input type="text" class="form-control" th:field="*{userName}" required="required" />
</div>
<div class="form-group col-sm-4">
<label class="required">Password: </label>
<input type="password" class="form-control" th:field="*{password}" required="required" />
</div>
<div class="form-group col-sm-4">
<label class="required">Email: </label>
<input type="text" class="form-control" th:field="*{email}" required="required" />
</div>
</div>
</div>
<div class="form-group col-md-12">
<label class="col-sm-2"></label>
<div class="col-sm-10">
<button type="submit" class="btn btn-info">Submit</button>
</div>
</div>
Java Bean class
public class Registration {
protected String firstName;
protected String lastName;
protected String userName;
protected String password;
protected String email;
//Setter and Getter
}
Use #ModelAttribute annotation in the parameter.
Something like this.
#RequestMapping(value = "/someurl", method = RequestMethod.POST)
public String savePojo(#ModelAttribute PojoClass pojo, Model model) {
//Code
}
Edit: This answer has very good info on this.
What is #ModelAttribute in Spring MVC?
I have this input:
Masa: <input type="number" class="form-control form-text" name="masa"/>
<div class="text col-sm-12 error" th:if="${wzrost}" >
<p class="text text-center">
To pole jest wymagane
</p>
</div>
Wzrost: <input type="number" class="form-control form-text " name="wzrost"/>
<div class="text col-sm-12 error" th:if="${wzrost}" >
<p class="text text-center">
To pole jest wymagane
</p>
</div>
And this controller;
String x = String.valueOf(masa);
String y = String.valueOf(wzrost);
if(x==null ){
model.addAttribute("wzrost",true);
return"views/success";
}
if(y==null ){
model.addAttribute("wzrost",true);
return"views/success";
}
When I click form submit button I always get error nullpointerexception.
How do I validate input, so that when it is empty the message pops up
#PostMapping("/cal-bmi")
public String calculateBmiForm(Model model, Integer masa, Integer wzrost) {
String x = String.valueOf(masa);
String y = String.valueOf(wzrost);
if(x==null ){
model.addAttribute("wzrost",true);
return"views/success";
}
if(y==null ){
model.addAttribute("wzrost",true);
return"views/success";
}
}
ANd when i get a valu form masa and wzrost i check from null, i click submit alwas nullpointerexception
<form th:action="#{/cal-bmi}" method="post">
<ul class="gender-options">
<input id="man" type="radio" name="gender" value="male" required />
<label for="man">mężczyzna</label> ⁄
<input id="woman" type="radio" name="gender" value="female"/>
<label for="woman">kobieta</label>
</ul>
Masa: <input type="number" class="form-control form-text" required placeholder="(kg)" name="masa"/>
<!--<div class="text col-sm-12 error" th:if="${wzrost}">-->
<!--<p class="text text-center">-->
<!--To pole jest wymagane-->
<!--</p>-->
<!--</div>-->
Wzrost: <input type="number" class="form-control form-text " required placeholder="(cm)" name="wzrost"/>
<!--<div class="text col-sm-12 error" th:if="${wzrost}">-->
<!--<p class="text text-center">-->
<!--To pole jest wymagane-->
<!--</p>-->
<!--</div>-->
<input type="submit" class="col-lg-10 btn btn-primary" value="Oblicz"/>
</form>
Now i used required but is not good solution
It seems like you want to implement server side validation. For this the best approach is to use validators and its bindingResult. Steps to implement server side validation is
Have for model
public class PersonForm {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
Use form model in html
<form action="#" th:action="#{/personForm}" th:object="${personForm}" method="post">
<table>
<tr>
<td><label th:text="#{label.name}+' :'"></label></td>
<td><input type="text" th:field="*{name}" /></td>
<td th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Generic Error</td>
</tr>
<tr>
<td><button type="submit">Submit</button></td>
</tr>
</table>
</form>
Have validator class
#Component
public class PersonFormValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return PersonForm.class.equals(clazz);
}
#Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "name", "field.name.empty");
PersonForm p = (PersonForm) target;
if (p.getName().equalsIgnoreCase("XXX")) {
errors.rejectValue("name", "Name cannot be XXX");
}
}}
Bind validator to controller and let spring do the magic.
#Controller
public class WebController {
#Autowired
PersonFormValidator personFormValidator;
#InitBinder("personForm")
protected void initPersonFormBinder(WebDataBinder binder) {
binder.addValidators(personFormValidator);
}
#PostMapping("/personForm")
public String checkPersonInfo(#Validated PersonForm personForm, BindingResult bindingResult, final RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) {
return "personForm";
}
redirectAttributes.addFlashAttribute("personResult", apiClientService.getPersonResult(personForm));
return "redirect:/spouseForm";
}
}