I am new at Java. Using Thymeleaf and Spring-Boot.
Trying to show validation message on wrong input.
"Phone" property must be between 7 to 13 character long. Validation message will be shown if rules are not followed.
Please note, validation works but message is not shown.
Here is the Model
#Entity
public class Author {
#Column(name = "phone")
#Size(min=7, max = 13, message = "The category name must be {min} to {max} characters in length.")
private String phone;
}
the Controller
#Controller
#RequestMapping("/author")
public class AuthorController extends WebMvcConfigurerAdapter {
#Autowired
AuthorService authorService;
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/new-author").setViewName("newauthor");
}
#RequestMapping(value="/new-author", method = RequestMethod.GET)
public String newAuthor(Model model){
Author author = new Author();
model.addAttribute("addNewAuthor", author);
return "newauthor";
}
#RequestMapping(value="/new-author", method = RequestMethod.POST)
public String newAuthor(#Valid Author author, BindingResult bindingResult, Model model){
model.addAttribute("addNewAuthor", author);
if (bindingResult.hasErrors()) {
return "newauthor";
}
try{
authorService.createAuthor(author);
model.addAttribute("statusReport", "Author Saved");
}
catch (Exception e){
model.addAttribute("statusReport", "Author not Saved");
}
return "newauthor";
}
}
here is the View
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Add Author</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="../public/bootstrap-3.3.6- dist/css/bootstrap.css" th:href="#{/bootstrap-3.3.6-dist/css/bootstrap.css}"/>
</head>
<body>
<h1>Add New Author</h1>
<div class="col-lg-3" >
<form role="form" action="#" th:action="#{/author/new-author}" th:object="${addNewAuthor}" method="post">
<div th:class="form-group" th:classappend="${#fields.hasErrors('phone')}? 'has-error'">
<label>Phone</label>
<input class="form-control" type="text" th:field="*{phone}" placeholder="Enter author's phone number"/>
<p th:if="${#fields.hasErrors('phone')}" class="label label-danger" th:errors="*{phone}">Phone Error</p>
</div>
<button type="submit" class="btn btn-default">Add</button>
<button type="reset" class="btn btn-default">Reset</button>
<p th:text="${statusReport}" > </p>
</form>
</div>
</body>
</html>
Your addNewAuthor should have the #ModelAttribute annotation.
It should be :
public String newAuthor(
#Valid #ModelAttribute("addNewAuthor") Author author,
BindingResult bindingResult,
Model model) {
// ...
}
I suppose it's better to do it this way,
first, remove message from Size constraint
#Column(name = "phone")
#Size(min=7, max = 13)
private String phone;
Second, add message to the localization file (message.properties).
Size.author.phone=The category name must be {1} to {2} characters in length.
Another way :
#Column(name = "phone")
#Size(min=7, max = 13, message="{phone.size}")
private String phone;
In message.properties :
phone.size=The category name must be {1} to {2} characters in length.
Related
**Hi everyone. I ran into a problem while developing a web application. The saveEmployee method does not work properly and throws the corresponding error. In the project I use Spring-boot + Thymeleaf. I think there is an error in these two files or a problem in the configuration. But so far I haven't found anything.
**
myRestController.java
#Controller
#RequestMapping("/shop")
public class myRestController {
#Autowired
private EmployeeService employeeService;
#GetMapping("/allEmployees")
public String allEmployees(Model model) {
List<Employee> employees = employeeService.getAllEmployees();
model.addAttribute("employeesList", employees);
return "allEmployees";
}
#GetMapping("/allEmployees/{name}")
public String getEmployeeByName(#PathVariable String name, Model model) {
List<Employee> employees = employeeService.findAllByName(name);
model.addAttribute("employeesList", employees);
return "allEmployees";
}
#GetMapping("/newEmployee")
public String addEmployee(Model model) {
Employee employee = new Employee();
model.addAttribute("employee", employee);
return "addNewEmployee";
}
#RequestMapping()
public String saveEmployee(#ModelAttribute("employee") Employee employee){
employeeService.saveEmployee(employee);
return "index";
}
addNewEmployee.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Add Employee</h1>
<form th:method="POST" th:action="#{shop/allEmployees}" th:object="${employee}">
<label for="name">Enter name:</label>
<input type="text" th:field="*{name}" id="name"/>
<br/>
<label for="surname">Enter surname:</label>
<input type="text" th:field="*{surname}" id="surname"/>
<br/>
<label for="department">Enter department:</label>
<input type="text" th:field="*{department}" id="department"/>
<br/>
<label for="salary">Enter salary:</label>
<input type="text" th:field="*{salary}" id="salary"/>
<br/>
<input type="submit" value="Create!">
</form>
<br><br>
</body>
</html>
In your myRestController.java, I am not seeing any #PostMapping defined. In addNewEmployee.html, it appears you are attempting to call shop/allEmployees with a POST rather than the GET method. If your intention is to pass a body or form to the shop/allEmployees endpoint, you may want to consider either changing your #GetMapping to a #PostMapping that accepts a #RequestBody or creating an entirely new #PostMapping that accepts a #RequestBody.
Edit: The page is working exactly as intended now and I've updated the below code to reflect my changes. The problem was that I needed to add the Booking attribute to the model in the GetMapping for the webpage. I also needed to correct the form tag on the webpage.
I have a demo web application that I'm attempting to add error checking on the form to with error messages that will display next the the related inputs. However, after implementing a method that I found here, I get a Whitelabel Error Page when I attempt to navigate to the web page with the form that I'm attempting to implement validation for. It says "Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'Booking' available as request attribute".
Here is the problematic web page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Reserve Booking</title>
</head>
<body>
<h1>Reserve Booking</h1>
<form th:object="${Booking}">
<label for="flightId">Flight ID</label>
<input name="flightId" type="text" th:field="*{flightId}"/>
<label th:if="${#fields.hasErrors('flightId')}" th:errors="*{flightId}">Flight ID Error</label>
</br>
<label for="seatNum">Seat Number</label>
<input name="seatNum" type="text" th:field="*{seatNum}"/>
<label th:if="${#fields.hasErrors('seatNum')}" th:errors="*{seatNum}">Seat Number Error</label>
</br>
<input type="submit" formmethod="post" value="Submit"/>
</br>
<button formaction="/index.html">Back to Index</button>
</form >
</body>
</html>
Here's the Booking class which uses Lombok for the getters and setters:
#Data
public class Booking {
String confNum;
#NotBlank(message = "Must enter a flight ID")
#Size(min = 3, max = 3, message = "Flight ID must be 3 digits in length")
String flightId;
#NotBlank(message = "Must select a seat number")
#Size(min = 1, max = 2)
String seatNum;
public Booking(){
UUID uuid = UUID.randomUUID();
confNum = uuid.toString().substring(0,5);
}
}
Here's the related code for the controller:
#Controller
#RequestMapping(value = "/booking")
public class BookingController{
#Autowired
BookingData bookingData;
#GetMapping(value = "/reserve")
public String ReserveHandler(Model model){
if(!model.containsAttribute("Booking")){
model.addAttribute("Booking", new Booking());
}
return "booking/reserve";
}
#PostMapping(value = "/reserve")
public String ReserveSeat(
#Valid #ModelAttribute("Booking") Booking booking,
BindingResult bindingResult,
Model model
){
String redirect;
if(bindingResult.hasErrors()){
redirect = "booking/reserve";
}else{
model.addAttribute("bookingList", bookingData.getAllBookings());
bookingData.addNewBooking(booking);
redirect = "booking/show";
}
return redirect;
}
}
Everything worked great before trying to implement the error checking on the form. The error checking has nothing to do with BookingData which is why I haven't included it. It simply has an array list of booked seats and methods for returning the list, as well as adding and removing from it.
You're not adding the model in the controller, to match the th:Object in the form. In your ReserveHandler you need to add the model attribute. I'm not sure how things have changed (if at all) recently, but I've done this before (using some of your model names in this case):
public String myGetRequest(Model model) {
if (!model.containsAttribute("Booking")) {
// Add the named model attribute here
model.addAttribute("Booking", new Booking());
}
return "booking/reserve";
}
#PostMapping(...)
public String myPostRequest(
#Valid #ModelAttribute Booking booking,
final BindingResult bindingResult,
final RedirectAttributes redirectAttributes
) {
if (bindingResult.hasErrors()) {
// Adds the validation errors
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.Booking", bindingResult);
// Set the model attribute
redirectAttributes.addFlashAttribute("Booking", booking);
return "redirect:/booking/reserve";
}
// Otherwise...
return "redirect:/booking/show";
}
I'm having trouble rendering a HTML page using Thymeleaf and Spring Boot. I get an error while it's trying to tag the fields in the html file to the ones in the class.
The error is: org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor' (template: "userPreview" - line 10, col 32)
HTML template:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Email User Preview</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Send E-mail:</h1>
<form action="#" th:action="#{/sendmail}" th:object="${message}" method="post">
<p>To:: <input type="text" th:field="*{receiverEmail}" /></p>
<p>Subject: <input type="text" th:field="*{subject}" /></p>
<p>Message: <input type="text" th:field="*{message}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
Controller:
#Controller
public class TestController {
#GetMapping("/test")
public String send() {
user.setEmailAddress("yasseen.salama#gmail.com");
try {
emailService.sendMail(user, "Hello", "Test");
} catch (MailException mailException) {
System.out.println(mailException);
}
return "Email sent.";
}
#GetMapping("/sendmail")
public String sendingMail(Model model) {
Message message = new Message();
model.addAttribute("userPreview", message);
return "userPreview";
}
#PostMapping("/sendmail")
public String mailSubmit(#ModelAttribute Message message) {
return "Result";
}
}
class Message:
public class Message {
String receiverEmail;
String subject;
String message;
public String getReceiverEmail() {
return receiverEmail;
}
public void setReceiverEmail(String receiverEmail) {
this.receiverEmail = receiverEmail;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
The object or the variable name to be used in template is userPreview and not message because that's the key in your Model object
My application is not able to bind a form value from an Thymeleaf + HTML based UI to a Spring Boot controller.
I am getting that value as null when I do a System.out.println into the controller.
index.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<p>Get your greeting here</p>
<form action="/publishMessage" method="post">
<table>
<tr>
<th>CHARGE</th>
</tr>
<tr>
<td>
<textarea th:field="*{messageBody}" name="" cols="90" rows="40">
{
"firstname": "Jose",
"lastname": "Long"
}
</textarea>
</td>
</tr>
<tr>
<td><input type="submit" name="btnSubmit" value="Publish CHARGE message"></td>
</tr>
</table>
</form>
</body>
</html>
PublishMessageController.java
#Controller
public class PublishMessageController {
#PostMapping("/publishMessage")
public String publishMessage(Message message, BindingResult bindingResult, Model model) {
System.out.println("into the publishMessage method..........");
String messageBody = message.getMessageBody();
System.out.println("messageBody: " + messageBody);
return "result";
}
}
Message.java
import lombok.*;
#Data
#Getter
#Setter
#NoArgsConstructor
public class Message {
private String messageBody;
}
Output:
into the publishMessage method..........
messageBody: null
Your message never gets put into the model, so you can't use it as variable in your controller.
Spring model attributes
Handling the command object
BTW: The method shouldn't return "result" but the String of the message body.
Put your messageBody to model where you show your form:
#RequestMapping(value = "/showForm", method=RequestMethod.GET)
public String showForm(Model model) {
...
String messageBody = ...
model.addAttribute("messageBody", messageBody);
...
}
To use this in your view, add th:action and th:object to your form:
<form action="#" th:action="#{/publishMessage}" th:object="${messageBody}" method="post">
...
</form>
Now you're able to use it in your controller method via annotation in the parameters:
#PostMapping("/publishMessage")
public String publishMessage(#ModelAttribute(value="messageBody") String messageBody, BindingResult bindingResult, Model model) {
...
return messageBody;
}
You could do this with the whole message instead of the body, of course.
Based on the above input from SHEIX made some changes and it worked.
ShowFormController.java
#Controller
public class ShowFormController {
#RequestMapping(value = "/showForm", method = RequestMethod.GET)
public String showForm(Model model) {
model.addAttribute("message", new Message());
return "show";
}
}
show.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>
Go Back
</h3>
<form action="#" th:action="#{/publishMessage}" th:object="${message}" method="post">
<table>
<tr>
<th>CHARGE</th>
</tr>
<tr>
<td>
<textarea th:field="*{messageBody}" name="" cols="90" rows="40" style="background-color: beige">
</textarea>
</td>
</tr>
<tr>
<td><input type="submit" name="btnSubmit" value="Publish CHARGE message"></td>
</tr>
</table>
</form>
</body>
</html>
Message.java
import lombok.*;
#Data
#Getter
#Setter
#NoArgsConstructor
public class Message {
private String messageBody = "{\n" +
"\t\t\t\t\t\t\"name\": \"John\"\n" +
" }";
}
PublishMessageController.java
#PostMapping("/publishMessage")
public String publishMessage(#ModelAttribute(value = "messageBody") String messageBody, BindingResult bindingResult, Model model) {
System.out.println("into the publishMessage method..........");
System.out.println("messageBody: " + messageBody);
return "result";
result.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>
Thanks !!!
Go Back
</h3>
</body>
</html>
I have an issue with form processing using Thymeleaf and Spring-MVC.
This is my view:
<html xmlns:th="http://www.thymeleaf.org">
<head>
</head>
<body>
<div class="container" id="containerFragment" th:fragment="containerFragment">
<form
action="#"
th:action="#{/search}"
th:object="${searchInfo}"
method="post" >
<fieldset id="search-query">
<input
type="text"
name="search"
value=""
id="search"
placeholder="Search for user"
required="required"
th:value="*{searchQuery}" />
<input
type="submit"
value="Search"
name="submit"
class="submit"/>
</fieldset>
</form>
</div>
</body>
</html>
this is my controller:
/** Search form */
#RequestMapping(value = "/search", method = RequestMethod.GET)
public String search(Model model) {
model.addAttribute("searchInfo", new SearchForm());
return "search";
}
/** Search form */
#RequestMapping(value = "/search", method = RequestMethod.POST)
public ModelAndView search(BindingResult result,
#Valid #ModelAttribute("searchInfo") SearchForm searchForm) {
String login = searchForm.getSearchQuery();
User user = userService.findUserByLogin(login);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("search-results");
modelAndView.addObject("user", user);
return modelAndView;
}
and the search form is:
public class SearchForm {
String searchQuery;
public String getSearchQuery() {
return searchQuery;
}
public void setSearchQuery(String searchQuery) {
this.searchQuery = searchQuery;
}
#Override
public String toString() {
return "SearchForm [searchQuery=" + searchQuery + "]";
}
}
The issue is that login is null at this point of controller:
String login = searchForm.getSearchQuery();
It looks like a new SearchForm object created for POST method, but there are already one, which was created at GET step and should contains the search query.
I can't understand such behaviour.
Spring should map HTML form attributes to your model: SearchForm.
Spring MVC build accordions with request parameters and your model object properties and set matching properties into your model Object before pass object into your controller method.
You named HTML property(and request parameter name automatically) as id="search". But SearchForm hasn't such property. Instead it has searchQuery property. So after Spring MVC unable to set searchQuery value into your SearchForm it pass model with null attribute.
Please Change th:value="{searchQuery}" to th:field="{searchQuery}".
I hope it'll work.
It worked for me:
FormTestController.java
#Controller
public class FormTestController {
#RequestMapping(value = "/form-test-1.jhtml", method = RequestMethod.GET)
public String formTest1(#ModelAttribute("form1") Form1TestVO form1TestVO, Model model){
System.out.println("You've submited: " + form1TestVO.getName())
model.addAttribute("form1", new Form1TestVO("Form 1 test"));
return "form-test-1";
}
}
form-test-1.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.thymeleaf.org" >
<head>
<title>Form test 1</title>
</head>
<body >
<form th:object="${form1}" th:action="#{/form-test-1.jhtml}" >
<input th:field="*{name}" />
<button>Send</button>
</form>
</body>
</html>
Form1TestVO
public class Form1TestVO {
private String name;
public Form1TestVO() {
}
public Form1TestVO(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Reference