Создайте приложение регистрации пользователей с помощью Spring Boot, Spring Form Validation
1. Цель примера
Статья основана на:
Eclipse 3.7 (Oxygen)
Spring Boot 2.x
Spring Validation
Thymeleaf
В данной статье я покажу вам как создать приложение регистрации пользователя, используя Spring Boot + Spring Validation + Thymeleaf. Темы упомянутые в данной статье включают:
- Создать Form регистрации на Spring.
- Использовать Spring Validator для подтверждения (validate) информации, которую ввел пользователь.
- Объявнить принцип работы Spring Validator.
Просмотр приложения:
2. Создать Spring Boot project
На Eclipse создать проект Spring Boot.
Ввести:
- Name: SbRegistrationFormValidationThymeleaf
- Group: org.o7planning
- Description: Spring Boot + Form Validation + Thymeleaf
- Package: org.o7planning.sbformvalidation
Выбрать технологии и библиотеки для использования:
- Security
- Validation
- Web
- Thymeleaf
OK, Project создан.
SbRegistrationFormValidationThymeleafApplication.java
package org.o7planning.sbformvalidation;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SbRegistrationFormValidationThymeleafApplication {
public static void main(String[] args) {
SpringApplication.run(SbRegistrationFormValidationThymeleafApplication.class, args);
}
}
3. Конфигурация pom.xml
В данном примере мы используем библиотеку Commons Validation чтобы проверить точность электронную почту, которую ввел пользователь. поэтому нужно объявить данную библиотеку в pom.xml.
** Commons Validation **
<dependencies>
.....
<!-- https://mvnrepository.com/artifact/commons-validator/commons-validator -->
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.6</version>
</dependency>
.....
</dependencies>
Полное содержание файла pom.xml:
pom.xml
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.o7planning</groupId>
<artifactId>SbRegistrationFormValidationThymeleaf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SbRegistrationFormValidationThymeleaf</name>
<description>Spring Boot + Form Validation + Thymeleaf</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-validator/commons-validator -->
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4. Security, MessageSource
В данном примере мы не концентрируемся на вопрос безопасности приложения. Но нам понадобится библиотека Spring Security, чтобы кодировать (encode) пароль пользователя, перед тем как сохранить в базу данных. И вам нужно объявить Spring BEAN для кодирования пароля.
WebSecurityConfig.java
package org.o7planning.sbformvalidation.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder;
}
// In this example we do not use Security.
// Override this method with empty code
// to disable the default Spring Boot security.
@Override
protected void configure(HttpSecurity http) throws Exception {
// Empty code!
}
}
В данном примере мы имеет файл validation.properties. Данный файл содержит коды ошибок (Error code), используются для оповещения пользователя когда они вводят неправильную информацию.
validation.properties
NotEmpty.appUserForm.userName=User name is required
NotEmpty.appUserForm.firstName=First Name is required
NotEmpty.appUserForm.lastName=Last name is required
NotEmpty.appUserForm.email=Email is required
NotEmpty.appUserForm.password=Password is required
NotEmpty.appUserForm.confirmPassword=Confirm Password is required
NotEmpty.appUserForm.gender=Gender is required
NotEmpty.appUserForm.countryCode=Country is required
Pattern.appUserForm.email=Invalid email
Duplicate.appUserForm.email=Email has been used by another account
Duplicate.appUserForm.userName=Username is not available
Match.appUserForm.confirmPassword=Password does not match the confirm password
Вам нужно объявить MessageResource Spring Bean, чтобы Spring автоматически скачал (load) содержание файла validation.properties в память.
WebConfiguration.java
package org.o7planning.sbformvalidation.config;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
// Load file: validation.properties
messageSource.setBasename("classpath:validation");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
}
5. Model, DAO
Класс AppUser представляет запись (record) таблицы APP_USER. Он является пользователем (user) успешно зарегистрированный в систему.
AppUser.java
package org.o7planning.sbformvalidation.model;
public class AppUser {
private Long userId;
private String userName;
private String firstName;
private String lastName;
private boolean enabled;
private String gender;
private String email;
private String encrytedPassword;
private String countryCode;
public AppUser() {
}
public AppUser(Long userId, String userName, String firstName, String lastName, //
boolean enabled, String gender, //
String email,String countryCode, String encrytedPassword) {
super();
this.userId = userId;
this.userName = userName;
this.firstName = firstName;
this.lastName = lastName;
this.enabled = enabled;
this.gender = gender;
this.email = email;
this.countryCode= countryCode;
this.encrytedPassword = encrytedPassword;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getEncrytedPassword() {
return encrytedPassword;
}
public void setEncrytedPassword(String encrytedPassword) {
this.encrytedPassword = encrytedPassword;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
}
Country.java
package org.o7planning.sbformvalidation.model;
public class Country {
private String countryCode;
private String countryName;
public Country() {
}
public Country(String countryCode, String countryName) {
this.countryCode = countryCode;
this.countryName = countryName;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
}
Gender.java
package org.o7planning.sbformvalidation.model;
public class Gender {
public static final String MALE = "M";
public static final String FEMALE = "F";
}
Классы DAO (Data Access Object) используются для манипуляции с ресурсами данных, как например query, insert, update, delete. Данные классы обычно аннотированы (annotate) с помощью @Repository чтобы Spring управлял ими как Spring BEAN.
AppUserDAO.java
package org.o7planning.sbformvalidation.dao;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.o7planning.sbformvalidation.formbean.AppUserForm;
import org.o7planning.sbformvalidation.model.AppUser;
import org.o7planning.sbformvalidation.model.Gender;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Repository;
@Repository
public class AppUserDAO {
// Config in WebSecurityConfig
@Autowired
private PasswordEncoder passwordEncoder;
private static final Map<Long, AppUser> USERS_MAP = new HashMap<>();
static {
initDATA();
}
private static void initDATA() {
String encrytedPassword = "";
AppUser tom = new AppUser(1L, "tom", "Tom", "Tom", //
true, Gender.MALE, "tom@waltdisney.com", encrytedPassword, "US");
AppUser jerry = new AppUser(2L, "jerry", "Jerry", "Jerry", //
true, Gender.MALE, "jerry@waltdisney.com", encrytedPassword, "US");
USERS_MAP.put(tom.getUserId(), tom);
USERS_MAP.put(jerry.getUserId(), jerry);
}
public Long getMaxUserId() {
long max = 0;
for (Long id : USERS_MAP.keySet()) {
if (id > max) {
max = id;
}
}
return max;
}
//
public AppUser findAppUserByUserName(String userName) {
Collection<AppUser> appUsers = USERS_MAP.values();
for (AppUser u : appUsers) {
if (u.getUserName().equals(userName)) {
return u;
}
}
return null;
}
public AppUser findAppUserByEmail(String email) {
Collection<AppUser> appUsers = USERS_MAP.values();
for (AppUser u : appUsers) {
if (u.getEmail().equals(email)) {
return u;
}
}
return null;
}
public List<AppUser> getAppUsers() {
List<AppUser> list = new ArrayList<>();
list.addAll(USERS_MAP.values());
return list;
}
public AppUser createAppUser(AppUserForm form) {
Long userId = this.getMaxUserId() + 1;
String encrytedPassword = this.passwordEncoder.encode(form.getPassword());
AppUser user = new AppUser(userId, form.getUserName(), //
form.getFirstName(), form.getLastName(), false, //
form.getGender(), form.getEmail(), form.getCountryCode(), //
encrytedPassword);
USERS_MAP.put(userId, user);
return user;
}
}
CountryDAO.java
package org.o7planning.sbformvalidation.dao;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.o7planning.sbformvalidation.model.Country;
import org.springframework.stereotype.Repository;
@Repository
public class CountryDAO {
private static final Map<String, Country> COUNTRIES_MAP = new HashMap<>();
static {
initDATA();
}
private static void initDATA() {
Country vn = new Country("VN", "Vietnam");
Country en = new Country("EN", "England");
Country fr = new Country("FR", "France");
Country us = new Country("US", "US");
Country ru = new Country("RU", "Russia");
COUNTRIES_MAP.put(vn.getCountryCode(), vn);
COUNTRIES_MAP.put(en.getCountryCode(), en);
COUNTRIES_MAP.put(fr.getCountryCode(), fr);
COUNTRIES_MAP.put(us.getCountryCode(), us);
COUNTRIES_MAP.put(ru.getCountryCode(), ru);
}
public Country findCountryByCode(String countryCode) {
return COUNTRIES_MAP.get(countryCode);
}
public List<Country> getCountries() {
List<Country> list = new ArrayList<>();
list.addAll(COUNTRIES_MAP.values());
return list;
}
}
6. Form Bean, Validator
Класс AppUserForm представляет данные, которые пользователь должен ввести на Form регистрации.
AppUserForm.java
package org.o7planning.sbformvalidation.formbean;
public class AppUserForm {
private Long userId;
private String userName;
private String firstName;
private String lastName;
private boolean enabled;
private String gender;
private String email;
private String password;
private String confirmPassword;
private String countryCode;
public AppUserForm() {
}
public AppUserForm(Long userId, String userName, //
String firstName, String lastName, boolean enabled, //
String gender, String email, String countryCode, //
String password, String confirmPassword) {
this.userId = userId;
this.userName = userName;
this.firstName = firstName;
this.lastName = lastName;
this.enabled = enabled;
this.gender = gender;
this.email = email;
this.countryCode = countryCode;
this.password = password;
this.confirmPassword = confirmPassword;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getConfirmPassword() {
return confirmPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
}
Класс AppUserValidator используется для валидации (validate) информации, которую ввел пользовтель в Form. Таким образом AppUserValidator валидирует (validate) значения полей (field) объектов AppUserForm.
AppUserValidator.java
package org.o7planning.sbformvalidation.validator;
import org.apache.commons.validator.routines.EmailValidator;
import org.o7planning.sbformvalidation.dao.AppUserDAO;
import org.o7planning.sbformvalidation.formbean.AppUserForm;
import org.o7planning.sbformvalidation.model.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
@Component
public class AppUserValidator implements Validator {
// common-validator library.
private EmailValidator emailValidator = EmailValidator.getInstance();
@Autowired
private AppUserDAO appUserDAO;
// The classes are supported by this validator.
@Override
public boolean supports(Class<?> clazz) {
return clazz == AppUserForm.class;
}
@Override
public void validate(Object target, Errors errors) {
AppUserForm appUserForm = (AppUserForm) target;
// Check the fields of AppUserForm.
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName", "NotEmpty.appUserForm.userName");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "NotEmpty.appUserForm.firstName");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "NotEmpty.appUserForm.lastName");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "email", "NotEmpty.appUserForm.email");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "NotEmpty.appUserForm.password");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "confirmPassword", "NotEmpty.appUserForm.confirmPassword");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "gender", "NotEmpty.appUserForm.gender");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "countryCode", "NotEmpty.appUserForm.countryCode");
if (!this.emailValidator.isValid(appUserForm.getEmail())) {
// Invalid email.
errors.rejectValue("email", "Pattern.appUserForm.email");
} else if (appUserForm.getUserId() == null) {
AppUser dbUser = appUserDAO.findAppUserByEmail(appUserForm.getEmail());
if (dbUser != null) {
// Email has been used by another account.
errors.rejectValue("email", "Duplicate.appUserForm.email");
}
}
if (!errors.hasFieldErrors("userName")) {
AppUser dbUser = appUserDAO.findAppUserByUserName(appUserForm.getUserName());
if (dbUser != null) {
// Username is not available.
errors.rejectValue("userName", "Duplicate.appUserForm.userName");
}
}
if (!errors.hasErrors()) {
if (!appUserForm.getConfirmPassword().equals(appUserForm.getPassword())) {
errors.rejectValue("confirmPassword", "Match.appUserForm.confirmPassword");
}
}
}
}
7. Controller
MainController.java
package org.o7planning.sbformvalidation.controller;
import java.util.List;
import org.o7planning.sbformvalidation.dao.AppUserDAO;
import org.o7planning.sbformvalidation.dao.CountryDAO;
import org.o7planning.sbformvalidation.formbean.AppUserForm;
import org.o7planning.sbformvalidation.model.AppUser;
import org.o7planning.sbformvalidation.model.Country;
import org.o7planning.sbformvalidation.validator.AppUserValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
// import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller
public class MainController {
@Autowired
private AppUserDAO appUserDAO;
@Autowired
private CountryDAO countryDAO;
@Autowired
private AppUserValidator appUserValidator;
// Set a form validator
@InitBinder
protected void initBinder(WebDataBinder dataBinder) {
// Form target
Object target = dataBinder.getTarget();
if (target == null) {
return;
}
System.out.println("Target=" + target);
if (target.getClass() == AppUserForm.class) {
dataBinder.setValidator(appUserValidator);
}
// ...
}
@RequestMapping("/")
public String viewHome(Model model) {
return "welcomePage";
}
@RequestMapping("/members")
public String viewMembers(Model model) {
List<AppUser> list = appUserDAO.getAppUsers();
model.addAttribute("members", list);
return "membersPage";
}
@RequestMapping("/registerSuccessful")
public String viewRegisterSuccessful(Model model) {
return "registerSuccessfulPage";
}
// Show Register page.
@RequestMapping(value = "/register", method = RequestMethod.GET)
public String viewRegister(Model model) {
AppUserForm form = new AppUserForm();
List<Country> countries = countryDAO.getCountries();
model.addAttribute("appUserForm", form);
model.addAttribute("countries", countries);
return "registerPage";
}
// This method is called to save the registration information.
// @Validated: To ensure that this Form
// has been Validated before this method is invoked.
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String saveRegister(Model model, //
@ModelAttribute("appUserForm") @Validated AppUserForm appUserForm, //
BindingResult result, //
final RedirectAttributes redirectAttributes) {
// Validate result
if (result.hasErrors()) {
List<Country> countries = countryDAO.getCountries();
model.addAttribute("countries", countries);
return "registerPage";
}
AppUser newUser= null;
try {
newUser = appUserDAO.createAppUser(appUserForm);
}
// Other error!!
catch (Exception e) {
List<Country> countries = countryDAO.getCountries();
model.addAttribute("countries", countries);
model.addAttribute("errorMessage", "Error: " + e.getMessage());
return "registerPage";
}
redirectAttributes.addFlashAttribute("flashUser", newUser);
return "redirect:/registerSuccessful";
}
}
8. Thymeleaf Template
_menu.html
<div xmlns:th="http://www.thymeleaf.org"
style="border: 1px solid #ccc;padding:5px;margin-bottom:20px;">
<a th:href="@{/}">Home</a>
|
<a th:href="@{/members}">Members</a>
|
<a th:href="@{/register}">Register</a>
</div>
membersPage.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:utext="${title}"></title>
</head>
<style>
table th, table td {
padding: 5px;
}
.message {
color: blue;
}
</style>
<body>
<!-- Include _menu.html -->
<th:block th:include="/_menu"></th:block>
<h2>Members</h2>
<table border="1">
<tr>
<th>User Name</th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Gender</th>
</tr>
<tr th:each ="member : ${members}">
<td th:utext="${member.userName}">...</td>
<td th:utext="${member.firstName}">...</td>
<td th:utext="${member.lastName}">...</td>
<td th:utext="${member.email}">...</td>
<td th:utext="${member.gender}">...</td>
</tr>
</table>
</body>
</html>
registerPage.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:utext="${title}"></title>
<style>
th, td {
padding: 5px;
}
td span {
font-size:90%;
font-style: italic;
color: red;
}
.error {
color: red;
font-style: italic;
}
</style>
</head>
<body>
<!-- Include _menu.html -->
<th:block th:include="/_menu"></th:block>
<h2>Register</h2>
<div th:if="${errorMessage != null}"
th:utext="${errorMessage}" class="error">...</div>
<form th:action="@{/register}" th:object="${appUserForm}" method="POST">
<table>
<tr>
<td>User Name</td>
<td><input type="text" th:field="*{userName}" /></td>
<td>
<span th:if="${#fields.hasErrors('userName')}" th:errors="*{userName}">..</span>
</td>
</tr>
<tr>
<td>Password</td>
<td><input type="password" th:field="*{password}" /> </td>
<td>
<span th:if="${#fields.hasErrors('password')}" th:errors="*{password}">..</span>
</td>
</tr>
<tr>
<td>Confirm</td>
<td><input type="password" th:field="*{confirmPassword}" /> </td>
<td>
<span th:if="${#fields.hasErrors('confirmPassword')}" th:errors="*{confirmPassword}">..</span>
</td>
</tr>
<tr>
<td>Email</td>
<td><input type="text" th:field="*{email}" /> </td>
<td>
<span th:if="${#fields.hasErrors('email')}" th:errors="*{email}">..</span>
</td>
</tr>
<tr>
<td>First Name</td>
<td><input type="text" th:field="*{firstName}" /> </td>
<td>
<span th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}">..</span>
</td>
</tr>
<tr>
<td>Last Name</td>
<td><input type="text" th:field="*{lastName}" /> </td>
<td>
<span th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}">..</span>
</td>
</tr>
<tr>
<td>Gender</td>
<td>
<select th:field="*{gender}">
<option value=""> -- </option>
<option value="M">Male</option>
<option value="F">Female</option>
</select>
</td>
<td>
<span th:if="${#fields.hasErrors('gender')}" th:errors="*{gender}">..</span>
</td>
</tr>
<tr>
<td>Country</td>
<td>
<select th:field="*{countryCode}">
<option value=""> -- </option>
<option th:each="country : ${countries}"
th:value="${country.countryCode}"
th:utext="${country.countryName}"/>
</select>
<td><span th:if="${#fields.hasErrors('countryCode')}" th:errors="*{countryCode}">..</span></td>
</tr>
<tr>
<td> </td>
<td>
<input type="submit" value="Submit" />
<a th:href="@{/}">Cancel</a>
</td>
<td> </td>
</tr>
</table>
</form>
</body>
</html>
registerSuccessfulPage.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Successfully registered</title>
<style>
span {color: blue;}
</style>
</head>
<body>
<!-- Include _menu.html -->
<th:block th:include="/_menu"></th:block>
<h2>You have successfully registered!</h2>
<div th:if="${flashUser != null}">
<ul>
<li>User Name: <span th:utext="${flashUser.userName}">..</span></li>
<li>Email: <span th:utext="${flashUser.email}">..</span></li>
</ul>
</div>
</body>
</html>
welcomePage.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:utext="${title}"></title>
</head>
<body>
<!-- Include _menu.html -->
<th:block th:include="/_menu"></th:block>
<h2>Home Page!</h2>
</body>
</html>
Руководства Spring Boot
- Установите Spring Tool Suite для Eclipse
- Руководство Spring для начинающих
- Руководство Spring Boot для начинающих
- Общие свойства Spring Boot
- Руководство Spring Boot и Thymeleaf
- Руководство Spring Boot и FreeMarker
- Руководство Spring Boot и Groovy
- Руководство Spring Boot и Mustache
- Руководство Spring Boot и JSP
- Руководство Spring Boot, Apache Tiles, JSP
- Используйте Logging в Spring Boot
- Мониторинг приложений с помощью Spring Boot Actuator
- Создание веб-приложения с несколькими языками с помощью Spring Boot
- Используйте несколько ViewResolver в Spring Boot
- Используйте Twitter Bootstrap в Spring Boot
- Руководство Spring Boot Interceptor
- Руководство Spring Boot, Spring JDBC и Spring Transaction
- Руководство Spring JDBC
- Руководство Spring Boot, JPA и Spring Transaction
- Руководство Spring Boot и Spring Data JPA
- Руководство Spring Boot, Hibernate и Spring Transaction
- Интеграция Spring Boot, JPA и H2 Database
- Руководство Spring Boot и MongoDB
- Используйте несколько DataSources с Spring Boot и JPA
- Используйте несколько DataSource с Spring Boot и RoutingDataSource
- Создайте приложение для входа с Spring Boot, Spring Security, Spring JDBC
- Создайте приложение для входа с Spring Boot, Spring Security, JPA
- Создайте приложение регистрации пользователей с помощью Spring Boot, Spring Form Validation
- Пример OAuth2 Social Login в Spring Boot.
- Запускать фоновые запланированные задачи в Spring
- Пример CRUD Restful Web Service c Spring Boot
- Пример Spring Boot Restful Client c RestTemplate
- Пример CRUD с Spring Boot, REST и AngularJS
- Защита Spring Boot RESTful Service используя Basic Authentication
- Защита Spring Boot RESTful Service используя Auth0 JWT
- Пример Upload file c Spring Boot
- Пример Download file c Spring Boot
- Пример Upload file c Spring Boot и jQuery Ajax
- Пример Upload file c Spring Boot и AngularJS
- Создание веб-приложения для корзины покупок с помощью Spring Boot, Hibernate
- Руководство Spring Email
- Создайте простое приложение Chat с Spring Boot и Websocket
- Разверните приложение Spring Boot на Tomcat Server
- Развертывание приложения Spring Boot на Oracle WebLogic Server
- Установите бесплатный сертификат Let's Encrypt SSL для Spring Boot
- Настройте Spring Boot для перенаправления HTTP на HTTPS
Show More