I'm attempting to post a simple HTML form to Spring RestController using #ModelAttribute and MediaType.APPLICATION_FORM_URLENCODED_VALUE as consumed data type. I've double checked all of my forms fields which match my request bean.
When the request enters the mapped method, all of the request beans fields are null.
#RestController
#EnableWebMvc
public class WebServiceController {
#RequestMapping(
value = "/test",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ResponseEntity<?> post(#ModelAttribute FormBean request){
// request.getParam() == null
return ResponseEntity.ok().build();
}
}
public class FormBean {
private String param1;
public String getParam1() {
return param1;
}
public void setParam1(String param1) {
this.param1 = param1;
}
}
<html>
<head>
<title>Test Form</title>
</head>
<body>
<form action="/test" method="POST">
<input type="text" id="param1">
<button type="submit">Submit</button>
</form>
</body>
</html>
You are missing the name attribute in your HTML inputs, id attribute is meaningless when posting an HTML form
<input type="text" name="param1">
Related
I am trying to create a custom error message in my controller and then pass it into the HTML template if the email is already found in the database.
The controller method does work and it will redirect the user to "registration-form" if a duplicate email is used, but the error message is not displayed on the web page as I intend it to be.
I basically want the error message to appear on the screen when the user cannot register with that email.
In HTML form:
<p th:text="*{errorMessage}"></p>
In Controller:
#PostMapping("/process-register")
private String processRegistrationForm(Model model, WebUser webUser) {
String email = webUser.getEmail();
if(webUserRepo.findByEmail(email) == null) {
webUser.setRole("user");
WebUser savedWebuser = webUserRepo.save(webUser);
model.addAttribute("userID", savedWebuser.getUserID());
String userID = String.valueOf(savedWebuser.getUserID());
return "redirect:/welcome/" + userID;
}
else {
String errorMessage = "This email address is already registered, please login to your existing account.";
model.addAttribute(errorMessage);
return "registration-form";
}
}
}
When your original request is not cached (i.e. is a POST, DELETE, PUT, ... operation) you can respond with any MVC flow, simply be sure to not use the path for "weird" things (neither server nor client side).
Then, if the email exists put the message into the model and redirect to the remember password (or login ...).
So, you can prepare your RememberController to be called from others controllers decoupling internal state and logic:
#Controller
#RequestMapping("/remember")
public class RememberController {
#Getter
#Setter
#AllArgsConstructor
public static class RememberModel {
private String email;
}
// this method decouple the RememberController knowledge (i.e. merge, remove, get messages, ... needed by this view)
public String redirect(Model model, String email) {
model.addAttribute("form", new RememberModel(email));
return get(model);
}
#GetMapping
public String get(Model model) {
if (model.getAttribute("form") == null)
model.addAttribute("form", new RememberModel(""));
return "remember";
}
#PostMapping
public String post(#ModelAttribute(name = "form") RememberModel form, Model model) {
model.addAttribute("info", "password sent to " + form.getEmail() + "!");
return "remember";
}
}
Now, your RegisterController can redirect with any required information (i.e. the error message and the user email to not to rewrite twice):
#Controller
#RequestMapping("/register")
public class RegisterController {
#Getter
#Setter
#AllArgsConstructor
public static class RegisterModel {
private String email;
}
#Autowired
protected RememberController rememberController;
#GetMapping
public String get(Model model) {
if(model.getAttribute("form") == null)
model.addAttribute("form", new RegisterModel(""));
return "register";
}
#PostMapping
public String post(#ModelAttribute(name = "form") RegisterModel form, Model model) {
// ... when email exists ...
model.addAttribute("error", "e-mail `" + form.getEmail() + "` exists!");
return rememberController.redirect(model, form.getEmail());
}
}
Then, the user UI works as expected:
GET
POST and server redirecto to remember controller
Then user simply click:
The views are:
<!doctype html>
<html th:attr="lang=en" xmlns:th="http://www.w3.org/1999/xhtml">
<body>
<h1>REGISTER FORM</h1>
<div style="color: red" th:if="${error != null}" th:text="${error}"></div>
<div style="color: green" th:if="${info != null}" th:text="${info}"></div>
<form method="post" th:object="${form}">
<input th:field="*{email}" type="text"/>
<input type="submit" value="register"/>
</form>
</body>
</html>
and
<!doctype html>
<html th:attr="lang=en" xmlns:th="http://www.w3.org/1999/xhtml">
<body>
<h1>REMEMBER FORM</h1>
<div style="color: red" th:if="${error != null}" th:text="${error}"></div>
<div style="color: green" th:if="${info != null}" th:text="${info}"></div>
<form method="post" th:action="#{/remember}" th:object="${form}">
<input th:field="*{email}" type="text"/>
<input type="submit" value="remember"/>
</form>
</body>
</html>
NOTE: for a better user experience, you can change the url when the remember view is redirected on server using window.history.pushState or so.
I'm sending an object to spring controller via jsp form.
JSP:
<form:form modelAttribute="uploadItem" action="/uploadObject" method="post" enctype="multipart/form-data">
<form:input path="fileData" accept="audio/mpeg" type="file" id="file-upload" name="file-upload" />
<form:input type="text" path="title" id="upload-title" name="upload-title"/>
<input type="image" src="..." alt="Upload"/>
</form:form>
ModelService:
public void fillUploadMelodyModel(Model model) {
fillAdminRootModel(model);
model.addAttribute("uploadItem", new UploadedItem());
}
UploadedItem:
public class UploadedItem {
private CommonsMultipartFile fileData;
private String title;
}
Controller:
#RequestMapping(value = "/uploadObject", method = RequestMethod.POST)
public String doUpload(UploadedItem uploadItem, BindingResult result, Principal principal) {
//at this point I get an empty object (null null values)
}
What is the problem? How to pass object to controller in jsp?
Try changing then your controller like this
#RequestMapping(value = "/uploadObject", method = RequestMethod.POST)
public String doUpload(UploadedItem uploadItem,
BindingResult result,
#RequestParam("fileData") MultipartFile file,
#RequestParam("title") String title,
Principal principal) {
//Here you should receive your parameters
}
I think the names you have used for the file (file-upload) and title (upload-title) are not in sync with your domain object attribute names. Change your names to fileData and title in your Jsp page.
In Spring boot who receive post model and in same time send vars to thymeleaf template?
#Controller
public class ProfilingController {
#GetMapping("/")
public String main(Model model){
FormModel form_model = new FormModel();
model.addAttribute("form_model", form_model);
model.addAttribute("demo", "abc");
return "main_template";
}
#PostMapping("/")
public String receive(#ModelAttribute ModelForm form_model){
FormModel form_model = new FormModel();
// How to set model to send the var to thymeleaf template?
model.addAttribute("form_model", form_model);
model.addAttribute("demo", "abc");
return "main_template";
}
}
If in post method receibe the model, how set the model to send vars to template?, if send two params does not works:
#PostMapping("/")
public String receive(Model model, #ModelAttribute ModelForm form_model){
The model_form is empty.
The template:
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
</head>
<body>
<form class="form-signin" action="#" method="post" th:action="#{/}" th:object="${form_model}">
<input th:field="*{email}" required="required" type="email" />
<input th:field="*{password}" type="password" />
<p th:text="${demo}"></p>
<button type="submit">Submit</button>
</form>
</body>
</html>
You can do this with ModelMap as below:
I have commented new form_model object creation assuming that you need to keep the received data to send back to the user.
#PostMapping("/")
public String receive(#ModelAttribute ModelForm form_model, ModelMap modelMap){
//other code to call service layer & save the data
//Commented new object creation for FormModel
//FormModel form_model = new FormModel();
modelMap.addAttribute("form_model", form_model);
modelMap.addAttribute("demo", "abc");
return "main_template";
}
hi i have a problem i am learnig how to pass values with PathVariable, i have a form with a input text and a button when you press the buttom it takes you to other page and show the value but it dont work when i press the buttom it takes me to this URL:
http://localhost:8080/appThyme/shoForm1.html?firstname=MyName&submit=
and i get this error HTTP 404 - /appThyme/showForm1.html
but if i put this URL: http://localhost:8080/appThyme/respuesta/Myname it works it shows me my page with my name, how can i make that work with only pressing the buttom, why when i press the buttom it add question marks and equals symbols to my URI
#Controller
public class HomeController {
#RequestMapping(value = "/form1", method = RequestMethod.GET)
public String showFormulario2(Model model) {
logger.info("***PAG formulario***");
return "form1.html";
}
#RequestMapping(value = "/showForm1/{id}", method = RequestMethod.GET)
public String showForm(Model model, #PathVariable("id") String id)
{
String theId= id;
model.addAttribute("TheID", theId);
return "showForm1.html";
}
my form1.html page
<form id="guestForm" th:action="#{/showForm1.html}" method="get">
<div>
<input type="text" name="firstname" id="firstname"></input>
</div>
<div>
<button type="submit" name="submit">Submit</button>
</div>
</form>
my showForm1.html page
enter code here
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>
Hello world!
</h1>
<P> The value is ${nombre} </P>
</body>
</html>
Form submissions are not intended to work with the #PathVariable construct you are using here. #PathVariable is intended for use with REST-style URI's, and that is not what is generated on a form submit.
If you change your controller signature to look like this:
#RequestMapping("/showForm1.html", method = RequestMethod.GET)
public String showForm(Model model, #RequestParam("firstname") String id)
{
String theId= id;
model.addAttribute("TheID", theId);
return "showForm1.html";
}
then the method should be called correctly on form submission.
Is there an easy way in Spring MVC 3.x to display form error messages (obtained by JSR303 validation), before submiting the form ?
Consider the example code at the end of this post.
The end-user is supposed to edit forms in which the initial data is already invalid.
Errors are properly displayed when the form is submitted (POST method), but not on initial form display (GET method).
Is there an easy way to display the errors on initial form display (GET method) ? (Is there a way to re-use the form:errors tag for this purpose?)
JSP View form1.jsp:
<%# page session="true" %>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib uri="http://www.springframework.org/tags" prefix="s" %>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<html><body>
<form:form commandName="form1" method="post">
<s:bind path="*">
<c:if test="${status.error}">
<div style="color: red;">There are errors:</div>
<form:errors /><br />
</c:if>
</s:bind>
<form:label path="field1" >Field1:</form:label>
<form:input path="field1" />
<form:errors path="field1" cssStyle="color: red;"/>
<br />
<form:label path="field2" >Field2:</form:label>
<form:input path="field2" />
<form:errors path="field2" cssStyle="color: red;"/>
<br />
<form:button name="submit">Ok</form:button>
</form:form>
</body></html>
Controller:
#Controller #SessionAttributes("form1")
public class Form1Controller {
#ModelAttribute("form1") public Form1Bean createForm1() { return new Form1Bean(); }
#RequestMapping(value = "/form1/edit", method = RequestMethod.GET)
public String getEdit(Model model) {
// here we pretend to get form1 from database, and store it in session.
// form1 in database may have invalid field values.
// Perform a JSR-303 validation here ?
// MAIN QUESTION: What's the easy way to add errors to model and display them ?
return "/form1";
}
#RequestMapping(value = "/form1/edit", method = RequestMethod.POST)
public String postEdit(#Valid #ModelAttribute("form1") Form1Bean form1, BindingResult result, Model model) {
if (result.hasErrors()) {
return "/form1";
} else {
return "redirect:/done";
}
}
}
Backing Bean:
public class Form1Bean {
#Size(min=4,max=10) private String field1; // getters and setters ommited for brevity
#Size(min=4,max=10) private String field2;
public Form1Bean() {
this.field1 = "bad"; this.field2="good"; // start with an invalid field1
}
//...
}
Edit: After the interpreting the answer from #jb-nizet, here is the complete controller source:
#Controller #SessionAttributes("form1")
public class Form1Controller {
#Autowired org.springframework.validation.Validator validator;
#ModelAttribute("form1") public Form1Bean createForm1() { return new Form1Bean(); }
#RequestMapping(value = "/form1/edit", method = RequestMethod.GET)
public String getEdit(#ModelAttribute("form1") Form1Bean form1, Errors errors, Model model) {
// here we pretend to get form1 from database, and store it in session.
// form1 in database may have invalid field values.
validator.validate(form1, errors);
return "/form1";
}
#RequestMapping(value = "/form1/edit", method = RequestMethod.POST)
public String postEdit(#Valid #ModelAttribute("form1") Form1Bean form1, BindingResult result, Model model) {
if (result.hasErrors()) {
return "/form1";
} else {
return "redirect:/done";
}
}
}
Made a few tests, and it seems to work! Than you #jb-nizet
Not tested, but as I understand the documentation, you would just have to inject an object of type org.springframework.validation.Validator in your controller, create and bind an Errors instance as explained in Add Error on GET METHOD Spring annotated controller, and invoke the validator's validate() method, passing the form and the Errors as argument.