It is always good to check the validity and integrity of form data before passing to business logic, let's see how to do it.
1.TOOLS AND ENV
IDE : Spring Tool Suite 3.7.3
JDK : 1.8
Tomcat : 8.0.18
Spring : 4.2.6.RELEASE
2. POM.XML
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>org.junjun.spring.tutorials</groupId> | |
<artifactId>spring-mvc-bean-validation</artifactId> | |
<packaging>war</packaging> | |
<version>1.0.0</version> | |
<properties> | |
<java.version>1.8</java.version> | |
<org.springframework.version>4.2.6.RELEASE</org.springframework.version> | |
<slf4j.version>1.7.10</slf4j.version> | |
</properties> | |
<dependencies> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-context</artifactId> | |
<version>${org.springframework.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-webmvc</artifactId> | |
<version>${org.springframework.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>javax.validation</groupId> | |
<artifactId>validation-api</artifactId> | |
<version>1.1.0.Final</version> | |
</dependency> | |
<dependency> | |
<groupId>org.hibernate</groupId> | |
<artifactId>hibernate-validator</artifactId> | |
<version>5.1.2.Final</version> | |
</dependency> | |
<dependency> | |
<groupId>org.slf4j</groupId> | |
<artifactId>slf4j-log4j12</artifactId> | |
<version>1.7.5</version> | |
</dependency> | |
<dependency> | |
<groupId>javax.servlet</groupId> | |
<artifactId>javax.servlet-api</artifactId> | |
<version>3.1.0</version> | |
<scope>provided</scope> | |
</dependency> | |
<!-- http://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --> | |
<dependency> | |
<groupId>javax.servlet.jsp</groupId> | |
<artifactId>javax.servlet.jsp-api</artifactId> | |
<version>2.3.1</version> | |
<scope>provided</scope> | |
</dependency> | |
<dependency> | |
<groupId>javax.servlet</groupId> | |
<artifactId>jstl</artifactId> | |
<version>1.2</version> | |
</dependency> | |
</dependencies> | |
<build> | |
<plugins> | |
<plugin> | |
<groupId>org.apache.maven.plugins</groupId> | |
<artifactId>maven-war-plugin</artifactId> | |
<configuration> | |
<failOnMissingWebXml>false</failOnMissingWebXml> | |
</configuration> | |
</plugin> | |
<plugin> | |
<groupId>org.apache.maven.plugins</groupId> | |
<artifactId>maven-compiler-plugin</artifactId> | |
<configuration> | |
<source>${java.version}</source> | |
<target>${java.version}</target> | |
<compilerArgument>-Xlint:all</compilerArgument> | |
<showWarnings>true</showWarnings> | |
<showDeprecation>true</showDeprecation> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
3. SEPARATE ROOT AND WEB CONFIG
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.spring.tutorials.config; | |
import org.springframework.web.context.WebApplicationContext; | |
import org.springframework.web.servlet.DispatcherServlet; | |
import org.springframework.web.servlet.FrameworkServlet; | |
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; | |
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { | |
@Override | |
protected Class<?>[] getRootConfigClasses() { | |
return new Class[] { RootConfig.class }; | |
} | |
@Override | |
protected Class<?>[] getServletConfigClasses() { | |
return new Class<?>[] { WebConfig.class }; | |
} | |
@Override | |
protected String[] getServletMappings() { | |
return new String[] { "/" }; | |
} | |
@Override | |
protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) { | |
DispatcherServlet dispatcherServlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext); | |
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true); | |
return dispatcherServlet; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.spring.tutorials.config; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.context.annotation.Import; | |
@Configuration | |
@Import({ AppConfig.class }) | |
public class RootConfig { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.spring.tutorials.config; | |
import org.springframework.context.annotation.ComponentScan; | |
import org.springframework.context.annotation.Configuration; | |
@Configuration | |
@ComponentScan({ "org.junjun.spring.tutorials.service", "org.junjun.spring.tutorials.dao" }) | |
public class AppConfig { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.spring.tutorials.config; | |
import org.springframework.context.MessageSource; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.ComponentScan; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.context.support.ResourceBundleMessageSource; | |
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; | |
import org.springframework.web.servlet.config.annotation.EnableWebMvc; | |
import org.springframework.web.servlet.view.InternalResourceViewResolver; | |
import org.springframework.web.servlet.view.JstlView; | |
@Configuration | |
@EnableWebMvc | |
@ComponentScan({ "org.junjun.spring.tutorials.web" }) | |
public class WebConfig { | |
/** | |
* Register Bean Validator. | |
* | |
* @return | |
*/ | |
@Bean | |
public javax.validation.Validator localValidatorFactoryBean() { | |
return new LocalValidatorFactoryBean(); | |
} | |
/** | |
* Configure MessageSource to provide internationalized messages | |
* | |
*/ | |
@Bean | |
public MessageSource messageSource() { | |
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); | |
messageSource.setBasename("messages"); | |
return messageSource; | |
} | |
/** | |
* Configure View Resolver | |
*/ | |
@Bean | |
public InternalResourceViewResolver viewResolver() { | |
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); | |
viewResolver.setViewClass(JstlView.class); | |
viewResolver.setPrefix("/WEB-INF/jsp/"); | |
viewResolver.setSuffix(".jsp"); | |
return viewResolver; | |
} | |
} |
4. POJO
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.spring.tutorials.bean; | |
import static org.junjun.spring.tutorials.common.Const.DF_DD_MMM_YYYY; | |
import java.io.Serializable; | |
import java.util.Date; | |
import org.hibernate.validator.constraints.NotEmpty; | |
public class ToDoEntity implements Serializable { | |
@NotEmpty | |
String content; | |
Date createdDate; | |
public String getContent() { | |
return content; | |
} | |
public void setContent(String content) { | |
this.content = content; | |
} | |
public Date getCreatedDate() { | |
return createdDate; | |
} | |
public String getCreatedDateDisplay() { | |
return DF_DD_MMM_YYYY.format(createdDate); | |
} | |
public void setCreatedDate(Date createdDate) { | |
this.createdDate = createdDate; | |
} | |
} |
We would make this POJO a JPA entity class in following posts when persistence is introduced.
5. DAO
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.spring.tutorials.dao; | |
import java.util.List; | |
import org.junjun.spring.tutorials.bean.ToDoEntity; | |
public interface ToDoDao { | |
List<ToDoEntity> getAll(); | |
ToDoEntity create(ToDoEntity toDoEntity); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.spring.tutorials.dao.impl; | |
import java.util.ArrayList; | |
import java.util.Date; | |
import java.util.List; | |
import org.junjun.spring.tutorials.bean.ToDoEntity; | |
import org.junjun.spring.tutorials.dao.ToDoDao; | |
import org.springframework.stereotype.Repository; | |
@Repository | |
public class ToDoDaoImpl implements ToDoDao { | |
private List<ToDoEntity> list = new ArrayList<>(); | |
public ToDoDaoImpl() { | |
ToDoEntity defaultToDo = new ToDoEntity(); | |
defaultToDo.setContent("default"); | |
defaultToDo.setCreatedDate(new Date()); | |
list.add(defaultToDo); | |
} | |
@Override | |
public List<ToDoEntity> getAll() { | |
return list; | |
} | |
@Override | |
public ToDoEntity create(ToDoEntity toDoEntity) { | |
list.add(toDoEntity); | |
return toDoEntity; | |
} | |
} |
We would have DAO talk to database in the following posts.
6. BUSINESS LOGIC LAYER
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.spring.tutorials.service; | |
import java.util.List; | |
import org.junjun.spring.tutorials.bean.ToDoEntity; | |
public interface ToDoService { | |
List<ToDoEntity> getAll(); | |
ToDoEntity create(ToDoEntity todo); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.spring.tutorials.service.impl; | |
import java.util.Date; | |
import java.util.List; | |
import org.junjun.spring.tutorials.bean.ToDoEntity; | |
import org.junjun.spring.tutorials.dao.ToDoDao; | |
import org.junjun.spring.tutorials.service.ToDoService; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.stereotype.Service; | |
@Service | |
public class ToDoServiceImpl implements ToDoService { | |
@Autowired | |
private ToDoDao toDoDao; | |
@Override | |
public List<ToDoEntity> getAll() { | |
return toDoDao.getAll(); | |
} | |
@Override | |
public ToDoEntity create(ToDoEntity toDoEntity) { | |
toDoEntity.setCreatedDate(new Date()); | |
return toDoDao.create(toDoEntity); | |
} | |
} |
7. TODO CONTROLLER
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.spring.tutorials.web.controller; | |
import java.util.List; | |
import javax.validation.Valid; | |
import org.apache.log4j.Logger; | |
import org.junjun.spring.tutorials.bean.ToDoEntity; | |
import org.junjun.spring.tutorials.service.ToDoService; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.stereotype.Controller; | |
import org.springframework.ui.Model; | |
import org.springframework.validation.BindingResult; | |
import org.springframework.validation.ObjectError; | |
import org.springframework.web.bind.annotation.ModelAttribute; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.bind.annotation.RequestMethod; | |
@Controller | |
@RequestMapping("todo") | |
public class ToDoController { | |
private static final Logger logger = Logger.getLogger(ToDoController.class); | |
@Autowired | |
private ToDoService toDoService; | |
@RequestMapping(value = "list", method = RequestMethod.GET) | |
public String list(Model model) { | |
String page = "todo/list"; | |
List<ToDoEntity> toDoList = toDoService.getAll(); | |
model.addAttribute("toDoList", toDoList); | |
model.addAttribute("newToDo", new ToDoEntity()); | |
return page; | |
} | |
@RequestMapping(value = "create", method = RequestMethod.POST) | |
public String create(@Valid @ModelAttribute("newToDo") ToDoEntity toDoEntity, BindingResult result, Model model) { | |
String page = "todo/list"; | |
if (result.hasErrors()) { | |
for (ObjectError error : result.getAllErrors()) { | |
logger.debug(error.getDefaultMessage()); | |
} | |
} else { | |
toDoService.create(toDoEntity); | |
} | |
List<ToDoEntity> toDoList = toDoService.getAll(); | |
model.addAttribute("toDoList", toDoList); | |
model.addAttribute("newToDo", toDoEntity); | |
return page; | |
} | |
@RequestMapping(value = "error", method = RequestMethod.GET) | |
public String error(Model model) { | |
String page = "todo/list"; | |
String[] data = new String[] { "1" }; | |
logger.error(data[2]); | |
return page; | |
} | |
} |
1. Container will do bean validation on model attribute that marked with @Valid
2. BindingResult must be declared right after @Valid
8. EXCEPTION HANDLER
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.junjun.spring.tutorials.web.advice; | |
import javax.servlet.http.HttpServletRequest; | |
import org.springframework.core.annotation.AnnotationUtils; | |
import org.springframework.web.bind.annotation.ControllerAdvice; | |
import org.springframework.web.bind.annotation.ExceptionHandler; | |
import org.springframework.web.bind.annotation.ResponseStatus; | |
import org.springframework.web.servlet.ModelAndView; | |
import org.springframework.web.servlet.NoHandlerFoundException; | |
@ControllerAdvice | |
public class ExceptionAdviceController { | |
@ExceptionHandler(NoHandlerFoundException.class) | |
public String dealWithNoHandlerFoundException(HttpServletRequest httpServletRequest) { | |
return "not-found"; | |
} | |
@ExceptionHandler(value = Exception.class) | |
public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception { | |
// If the exception is annotated with @ResponseStatus rethrow it and let | |
// the framework handle it | |
if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) | |
throw e; | |
// Otherwise setup and send the user to a default error-view. | |
ModelAndView mav = new ModelAndView(); | |
mav.addObject("exception", e); | |
mav.addObject("url", req.getRequestURL()); | |
mav.setViewName("error"); | |
return mav; | |
} | |
} |
@ControllerAdvice is typically used to define ExceptionHandler , InitBinder and ModelAttribute methods that apply to all RequestMapping methods.
9. WEB PAGE
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%@ page language="java" contentType="text/html; charset=UTF-8" | |
pageEncoding="UTF-8"%> | |
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> | |
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> | |
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<meta name="description" content="spring"> | |
<meta name="keywords" content="spring"> | |
<title></title> | |
<link rel="stylesheet" | |
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> | |
</head> | |
<body> | |
<div class="container" style="padding-top: 10%"> | |
<div class="row"> | |
<form:form class="form-horizontal" role="form" | |
modelAttribute="newToDo" method="post" | |
action="${pageContext.request.contextPath}/todo/create"> | |
<div class="form-group"> | |
<div class="col-md-offset-2 col-md-6"> | |
<form:input id="todoContent" class="form-control" path="content" | |
placeholder="" /> | |
</div> | |
<label for="todoContent" class="col-md-4 control-label" | |
style="text-align: left;"><spring:bind path="content"> | |
<c:if test="${status.error}"> | |
<form:errors path="content" class="text-danger" /> | |
</c:if> | |
</spring:bind></label> | |
</div> | |
</form:form> | |
</div> | |
<div class="row"> | |
<div class="col-md-offset-2 col-md-10"> | |
<ul> | |
<c:forEach items="${toDoList}" var="toDo"> | |
<li>${toDo.createdDateDisplay} : ${toDo.content}</li> | |
</c:forEach> | |
</ul> | |
</div> | |
</div> | |
</div> | |
<script src="http://code.jquery.com/jquery-latest.min.js"></script> | |
<script | |
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%@ page language="java" contentType="text/html; charset=UTF-8" | |
pageEncoding="UTF-8"%> | |
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> | |
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> | |
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<meta name="description" content="spring"> | |
<meta name="keywords" content="spring"> | |
<title></title> | |
<link rel="stylesheet" | |
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> | |
</head> | |
<body> | |
<div class="container" style="padding-top: 10%; height: 100%"> | |
<div class="text-center col-md-12"> | |
<h1>NOT FOUND</h1> | |
</div> | |
</div> | |
</body> | |
</html> |
10. Messages for Validation Error
11. TEST
12. SOURCE CODE
https://github.com/junjun-dachi/spring-tutorials/tree/master/spring-mvc-bean-validation
No comments:
Post a Comment