How to provide a message of my choosing on form validation failure - validation

I am using spring mvc 3.0.Here is my controller class:
#Controller
#RequestMapping("/author")
public class AuthorController {
#Autowired
private IAuthorDao authorDao;
#InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(
dateFormat, true));
}
#RequestMapping(method = RequestMethod.GET)
public String get(Model model) {
return "author-list";
}
#RequestMapping(value = "/new", method = RequestMethod.GET)
public String create(Model model) {
model.addAttribute("author", new Author());
return "author-form";
}
#RequestMapping(value = "/new", method = RequestMethod.POST)
public String createPost(#ModelAttribute("author") Author author,
BindingResult result) {
new AuthorValidator().validate(author, result);
if (result.hasErrors()) {
return "author-form";
} else {
authorDao.persist(author);
return "redirect:/author/" + author.getId();
}
}
#RequestMapping(value = "/{authorId}", method = RequestMethod.GET)
public String view(#PathVariable("authorId") int authorId) {
return "author-view";
}
}
I am trying to validate author object. it has dob attr which type is Date.
I am using following class for validation:
public class AuthorValidator {
public void validate(Author author, Errors errors) {
if(author.getfName()==null)
errors.rejectValue("fName", "required", "required");
else if (!StringUtils.hasLength(author.getfName())) {
errors.rejectValue("fName", "required", "required");
}
if(author.getfName()==null)
errors.rejectValue("lName", "required", "required");
else if (!StringUtils.hasLength(author.getlName())) {
errors.rejectValue("lName", "required", "required");
}
if(author.getDob()==null)
errors.rejectValue("dob", "required", "required");
else if (!StringUtils.hasLength(author.getDob().toString())) {
errors.rejectValue("dob", "required", "required");
}
}
}
when i do no enter anything to the form it gives required message, it is correct, but when i give the incorrect format then it gives writes Failed to convert property value of type java.lang.String to required type java.util.Date for property dob; nested exception is java.lang.IllegalArgumentException: Could not parse date: Unparseable date: "asdads"
required as a message. how to make it like "Invalid date".
thanks.

If you use standard Spring facilities, all you need to do is:
Add messageSource:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="com.example.messages" />
</bean>
Add properties file com/example/messages.properties containing one of:
typeMismatch.author.date = Invalid date
typeMismatch.date = Invalid date
typeMismatch.java.util.Date = Invalid date
typeMismatch = Invalid date
first lets you configure error message for particular field (date) in particular command object (author), second - a date field in any command object, third - a message for binding error of a field of java.util.Date class, and the final - a general message for an error resulting from any conversion.
Here's my JSP page:
<%# taglib uri="http://www.springframework.org/tags" prefix="s" %>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<sf:form commandName="author">
<sf:errors path="date" /><br />
<sf:input path="name"/><br />
<sf:input path="date"/><br />
<input type="submit" value="ok" />
</sf:form>
</body>
</html>

Related

Getting Error while bootstraping the Spring-boot Application

Well i am developing a spring boot application by choosing view technology as jsp.But when am trying to bootstraping the spring-boot application i am getting white level error page.
Model Class
public class Person {
private String p_first_name;
private String p_last_name;
private int age;
private String city;
private String state;
private String country;
public Person(String p_first_name, String p_last_name, int age, String city, String state, String country) {
super();
this.p_first_name = p_first_name;
this.p_last_name = p_last_name;
this.age = age;
this.city = city;
this.state = state;
this.country = country;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
public String getP_first_name() {
return p_first_name;
}
public void setP_first_name(String p_first_name) {
this.p_first_name = p_first_name;
}
public String getP_last_name() {
return p_last_name;
}
public void setP_last_name(String p_last_name) {
this.p_last_name = p_last_name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
Controller Class
#Controller
public class PersonController {
private static ArrayList<Person> persons = new ArrayList<Person>();
static {
persons.add(new Person("kumar", "bikash", 28, "bangalore", "karnataka", "india"));
persons.add(new Person("kumar", "pratap", 24, "delhi", "delhi", "india"));
persons.add(new Person("kumar", "ravi", 29, "delhi", "delhi", "india"));
persons.add(new Person("kumar", "mangalam", 65, "delhi", "delhi", "india"));
}
#RequestMapping(value = { "/", "/index" }, method = RequestMethod.GET)
public String index(Model model) {
String message = "Hello" + "Spring Boot implementation with jsp Page";
model.addAttribute("message", message);
return "index";
}
#RequestMapping(value = "/personList", method = RequestMethod.GET)
public String getPersonList(Model model) {
model.addAttribute("persons", persons);
return "personList";
}
}
application.properties
# VIEW RESOLVER CONFIGURATION
spring.mvc.view.prefix=/WEB-INF/jsp
spring.mvc.view.suffix=.jsp
jsp file
index.jsp
=========
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Integration of Spring Boot with jsp page</title>
</head>
<body>
<h1>Welcome to Spring boot</h1>
<p>This project is an Example of how to integrate Spring Boot with
jsp page.</p>
<h2>${message} </h2>
</body>
</html>
personList.jsp
==============
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Person List content Present here</title>
</head>
<body>
<h1>Person List</h1>
<div>
<table border="1">
<tr>
<th>FirstName:</th>
<th>LasttName:</th>
<th>Age:</th>
<th>city:</th>
<th>State:</th>
<th>Country:</th>
</tr>
<c:forEach items="${persons}" var=person>
<tr>
<td>${person.firstname}</td>
<td>${person.lastname}</td>
<td>${person.age }</td>
<td>${person.city }</td>
<td>${person.state }</td>
<td>${person.country }</td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>
Error page
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri Jun 07 23:41:57 IST 2019
There was an unexpected error (type=Not Found, status=404).
No message available
well please review the below code.Help me to resolve thing where i am
getting wrong?
Are you looking to enable your own errorpage disabling the white level error page? May be this can help you.
If you do not specify any custom implementation in the configuration,
BasicErrorController bean is automatically registered in Spring Boot. You can add your implementation of ErrorController.
#Controller
public class MyErrorController implements ErrorController {
#RequestMapping("/error")
public String handleError() {
//do something like logging
return "error";
}
#Override
public String getErrorPath() {
return "/error";
}
}
1) I would suggest trying the #RestController annotation to make sure that you get at least the JSON response. (Only for Debugging)
2) After the first part is figured out, you can go back to your #Controller annotation and make sure that the string you return in the request mapping method is available as a jsp file. I would recommend trying with a single endpoint initially ("/") and having the appropriate jsp page for it.
3) If it still produces the same issue, you can refer to this post
Spring Boot JSP 404.Whitelabel Error Page
4) You can also disable and customize the default error page by following this link https://www.baeldung.com/spring-boot-custom-error-page

Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor'

Trying to change value inside my model class which contains a private String name and I wanted to change the name using Thymeleaf in HTML page then see the change in another url response body.
When I try to access my ("/myname") page in localhost I got the error:
Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor'
Here is my Model:
public class Name {
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Here is my Controller
#Controller
public class MainController {
#RequestMapping("/name")
#ResponseBody
public String showName() {
Name myname = new Name();
return myname.getName();
}
#RequestMapping("/myname")
public String setName() {
return "myname";
}
#RequestMapping(value = "myname", method = RequestMethod.POST)
public String showName(#ModelAttribute Name iko, BindingResult errors, Model model) {
return "name";
}
}
Here is my html thymeleaf pages:
myname.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1"/>
<title>Insert title here</title>
</head>
<body>
<form action="#" th:action="#{/myname}" th:object="${iko}" method="post">
<label>Enter the name</label><br/>
<input type="text" th:field="*{name}"/>
<button type="submit">SUBMIT</button>
</form>
</body>
</html>

Spring Boot Freemarker status.errorMessages not populated

I am trying to get model validation working with my spring boot mvc application. I am using freemarker as view templates. My problem is now that even though model validation works as expected the model errors are not shown in my view.
Here is some example code. The Model:
public class TestModel {
#Size(min=2, max=10)
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The Controller
#Controller
#RequestMapping("/test")
public class OrderController extends BaseController {
#RequestMapping(value = "new/greenhouse", method = RequestMethod.GET)
public String get(#ModelAttribute TestModel testModel) {
testModel.setName("Hello world");
return "test.ftl";
}
#RequestMapping(value = "/test", method = RequestMethod.POST)
public String post(#ModelAttribute #Valid TestModel testModel, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
// The bindingResult contains the "correct" errors
return "test.ftl";
}
return "redirect:/";
}
}
The view:
<#import "../layout.ftl" as layout />
<#import "/spring.ftl" as spring />
<#import "../freemarker.ftl" as ftl />
<#layout.defaultLayout>
<form action="/test" method="post">
<#ftl.csrfToken />
Name:
<#spring.formInput "testModel.Name" />
<#spring.showErrors "<br>" /> <#-- Does not print the error as status.errorMessages is not populated -->
<#-- This will at least display the default Message -->
<#list spring.status.errors.allErrors as error>
<span class="has-error">${error.defaultMessage} </span>
</#list>
</form>
</#layout.defaultLayout>
Any idea why status.errorMessages does not get populated?
So I finally found the solution to this:
The property name in the Freemarker view has to be lowercase (as is the private member name in the model class). The correct view would look like this:
<#spring.formInput "testModel.name" />
<#spring.showErrors "<br>" />

Form POST submit "The request sent by the client was syntactically incorrect."

I have no idea where I've made a mistake. I've been trying to solve this problem for hours but can't figure it out...
I'm getting HTTP Status 400 The request sent by the client was syntactically incorrect. while submiting the form with list of objects with some checkboxes to each of the objects.
Heres some of the code:
Controller:
#RequestMapping(value = "/admin/panel", method = RequestMethod.GET)
public String adminPanel(Locale locale, Model model, Form form,
HttpServletRequest request) {
FormWrapper wrapper = getFormWrapper();
model.addAttribute("listOfObjects", wrapper);
model.addAttribute("allCategories", dao.getCatsList());
return "WEB-INF/views/index/admin/home";
}
#RequestMapping(value = "/admin/saveAdmin", method = RequestMethod.POST)
public String save(Model model, #ModelAttribute(value="listOfObjects") FormWrapper listOfObjects) {
return "redirect:../index.html";
}
JSP:
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<form:form modelAttribute="listOfObjects" method="POST" action="/admin/saveAdmin">
<c:forEach var="myObject" items="${listOfObjects.list}" varStatus="loop">
<form:checkboxes items="${allCategories}" path="list[${loop.index}].selectedCategories" itemLabel="name"/>
</c:forEach>
<input type="submit" value="saveTest"/>
</form:form>
FormWrapper:
public class FormWrapper {
private List<Form> list;
public List<Form> getList() {
return list;
}
public void setList(List<Form> list) {
this.list = list;
}
}
Category:
public class Category{
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Long categoryId;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getCategoryId() {
return categoryId;
}
public void setCategoryId(Long categoryId) {
this.categoryId = categoryId;
}
#Override
public boolean equals(Object obj) {
if(obj instanceof Category){
return getCategoryId().equals(((Category)obj).getCategoryId());
} else {
return false;
}
}
}
Any help is appreciated. I tried to change the model attribute adnotatnion to RequestParam , but in such case , my object is always null
Is it because, the FormWrapper class do not have a property "selectedCategories".
I tried removing the "selectedCategories"
Then the form was submitted successfully.
<form:checkboxes items="${allCategories}" path="list[${loop.index}]" itemLabel="name"/>
I'm not sure I understand your jsp correctly but this problem occurs when something in the jsp form does not match with the parameters you're handling at the controller.
Are you sure that "path" variable below is ok?
<form:checkboxes items="${allCategories}" path="list[${loop.index}].selectedCategories" itemLabel="name"/>

Spring Framework <form:errors/> tag not showing errors

I know there are many similar questions here, but none of them solved my problem.
I'm using Spring 4.0.3 and Hibernate Validator 5.1.0.
The problem occurs when I try to omit the path attribute of the <form:errors/> tag, so:
<form:errors path="contato.nome" /> works
<form:errors path="*" /> works
<form:errors /> doesn't work
I don't know why it happens. Spring javadocs (org.springframework.web.servlet.tags.form.ErrorsTag) says it should work like that:
Field only - set path to the field name (or path)
Object errors only - omit path
All errors - set path to *
Can you help me, please?
The interested code is in the 'edicao.jsp' and in the method 'confirmarEdicao' of the ContatoController.java. Sorry if my english is bad.
ContatoController.java
#Controller
#RequestMapping("/contatos")
public class ContatoController {
#Autowired
private ContatoService contatoService;
#Autowired
private MessageSource messageSource;
#RequestMapping(value = "/confirmarEdicao", method = RequestMethod.POST)
public String confirmarEdicao(#Valid Contato contato, BindingResult bindingResult) {
if(bindingResult.hasErrors()) {
return "contatos/edicao";
}
contatoService.save(contato);
return "redirect:/contatos";
}
#RequestMapping(method = RequestMethod.GET)
public ModelAndView form(HttpServletRequest request) {
String message = messageSource.getMessage("teste", null, new Locale("pt", "BR"));
System.out.println(message);
return new ModelAndView("contatos/listagem")
.addObject("contatos", contatoService.list());
}
#RequestMapping("/remover/{id}")
public String remover(Contato contato) {
contatoService.delete(contato);
return "redirect:/contatos";
}
#RequestMapping("/editar/{id}")
public ModelAndView formEdicao(Contato contato) {
contato = contatoService.find(contato.getId());
return new ModelAndView("contatos/edicao")
.addObject(contato);
}
#RequestMapping(value = "/cadastrar")
public String formCadastro() {
return "contatos/cadastro";
}
#RequestMapping(value = "/confirmarCadastro", method = RequestMethod.POST)
public String confirmarCadastro(#Valid Contato contato, BindingResult bindingResult,
RedirectAttributes redirectAttributes) {
if (bindingResult.hasFieldErrors()) {
return "contatos/cadastro";
}
contatoService.save(contato);
redirectAttributes.addFlashAttribute("mensagem", "Contato cadastrado com sucesso.");
return "redirect:/contatos";
}
#ResponseBody
#RequestMapping(value = "/pesquisar/{nome}", method = RequestMethod.GET,
produces="application/json")
public List<Contato> pesquisar(#PathVariable String nome) {
return contatoService.findByName(nome);
}
}
edicao.jsp
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Editar contato</title>
</head>
<body>
<c:set var="context">${pageContext.request.contextPath}</c:set>
<script type="text/javascript">var context = "${context}";</script>
<script src="${context}/resources/js/jquery-2.1.0.min.js"></script>
<script src="${context}/resources/js/contatos/edicao.js"></script>
<form:form commandName="contato" action="${context}/contatos/confirmarEdicao" method="post">
<form:errors/>
<table>
<form:hidden path="id"/>
<tr>
<td>Nome:</td>
<td><form:input path="nome" /></td>
</tr>
<tr>
<td>Telefone:</td>
<td><form:input path="telefone"/></td>
</tr>
<tr>
<td><input type="button" value="Voltar" id="btn_voltar"/><input type="submit" value="Salvar"/></td>
</tr>
</table>
</form:form>
</body>
</html>
Contato.java
package com.handson.model;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
public class Contato {
private Long id;
#Size(min = 3, message = "Nome deve ter no mínimo 3 caracteres")
#NotEmpty(message = "O nome deve ser preenchido")
private String nome;
private String telefone;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getTelefone() {
return telefone;
}
public void setTelefone(String telefone) {
this.telefone = telefone;
}
public Contato withId(Long id) {
setId(id);
return this;
}
public Contato withTelefone(String telefone) {
setTelefone(telefone);
return this;
}
public Contato withNome(String nome) {
setNome(nome);
return this;
}
#Override
public String toString() {
return "Contato [id=" + id + ", nome=" + nome + ", telefone="
+ telefone + "]";
}
}
There are some keywords which should be defined:
path - EL-like path to an object or to a field of an object (e.g. foo, foo.bar or foo.bar.baz)
nested path - current path context stored as nestedPath request attribute (new paths are relative to this path)
object error - error connected with object itself (e.g. path is equal to foo)
field error - error connected with object field (e.g. path is foo.bar)
The tag <form:form commandName="foo"> defines nested path as nestedPath=foo. When you write <form:errors path="bar"> it tries to find errors defined for path foo.bar.
Lets say that you have errors connected with foo (object error), foo.bar and foo.bar.baz (nested field error). What this means:
if you enter <form:errors>, only errors bound to foo path are displayed => 1 message
if you enter <form:errors path="bar">, only errors bound to foo.bar path are displayed => 1 message
if you enter <form:errors path="*">, errors bound to foo and its child paths are displayed => 3 messages
if you enter <form:errors path="bar.*">, only child errors for foo.bar are diplayed => 1 message
if you enter <form:errors path="bar*">, errors bound to foo.bar and its child paths are diplayed => 2 messages
Checking on Errors class JavaDoc might give you additional insight.

Resources