在本教程中,我们将逐步学习如何 使用 Spring Boot、Spring Security、Spring Data JPA、Hibernate、MysqL、JSP 和 Bootstrap创建用户帐户注册和登录模块。
您可以从我的 GitHub 存储库(本教程末尾提供的链接)下载本教程的源代码。使用的工具和技术
- Spring Boot
- JDK - 1.8 or later
- Hibernate
- Maven
- Spring Data JPA
- IDE - Eclipse or Spring Tool Suite (STS)
- MysqL
- Spring Security
- JSP
1. 创建一个 Spring Boot 应用程序
有很多方法可以创建 Spring Boot 应用程序。您可以参考以下文章来创建 Spring Boot 应用程序。 >> 使用 Spring Initializer创建 Spring Boot 项目>> 在 Spring Tool Suite [STS] 中创建 Spring Boot 项目 参考下一步创建项目打包结构。
2、包装结构
以下是包装结构供您参考├─src
│ ├─main
│ │ ├─java
│ │ │ └─net
│ │ │ └─guides
│ │ │ └─springboot
│ │ │ └─loginregistrationspringbootauthjsp
│ │ │ │ Application.java
│ │ │ │
│ │ │ ├─config
│ │ │ │ WebSecurityConfig.java
│ │ │ │
│ │ │ ├─model
│ │ │ │ Role.java
│ │ │ │ User.java
│ │ │ │
│ │ │ ├─repository
│ │ │ │ RoleRepository.java
│ │ │ │ UserRepository.java
│ │ │ │
│ │ │ ├─service
│ │ │ │ UserDetailsServiceImpl.java
│ │ │ │ UserService.java
│ │ │ │ UserServiceImpl.java
│ │ │ │
│ │ │ ├─validator
│ │ │ │ UserValidator.java
│ │ │ │
│ │ │ └─web
│ │ │ UserController.java
│ │ │
│ │ ├─resources
│ │ │ application.properties
│ │ │ validation.properties
│ │ │
│ │ └─webapp
│ │ │ index.jsp
│ │ │
│ │ ├─resources
│ │ │ ├─css
│ │ │ │ bootstrap.min.css
│ │ │ │ common.css
│ │ │ │
│ │ │ └─js
│ │ │ bootstrap.min.js
│ │ │
│ │ └─WEB-INF
│ │ │ web.xml
│ │ │
│ │ └─jsp
│ │ login.jsp
│ │ registration.jsp
│ │ welcome.jsp
3. pom.xml 文件
这是 pom.xml 文件供您参考:<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>springboot.javaguides</groupId>
<artifactId>login-registration-springboot-hibernate-jsp-auth</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>login-registration-springboot-hibernate-jsp-auth Maven Webapp</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.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-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>MysqL</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</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>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.6</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap-datepicker</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>1.9.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.领域或模型层
在这一步中,我们将创建用户和角色JPA 实体并在它们之间建立多对多关系。 让我们使用 JPA 注释在用户和角色实体 之间建立多对多关系。用户 JPA 实体
package net.guides.springboot.loginregistrationspringbootauthjsp.model;
import javax.persistence.*;
import java.util.Set;
@Entity
@Table(name = "user")
public class User {
private Long id;
private String username;
private String password;
private String passwordConfirm;
private Set<Role> roles;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getpassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Transient
public String getpasswordConfirm() {
return passwordConfirm;
}
public void setPasswordConfirm(String passwordConfirm) {
this.passwordConfirm = passwordConfirm;
}
@ManyToMany
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
角色 JPA 实体
package net.guides.springboot.loginregistrationspringbootauthjsp.model;
import javax.persistence.*;
import java.util.Set;
@Entity
@Table(name = "role")
public class Role {
private Long id;
private String name;
private Set<User> users;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToMany(mappedBy = "roles")
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
}
- @Table将实体与表映射。如果没有定义@Table,则使用默认值:实体的类名。
- @Id声明实体的标识符属性。
- @ManyToMany定义了 2 个实体之间的多对多关系。
- mappedBy表示实体是关系的逆。
5. 存储层
让我们创建一个 UserRepository 来从数据库中访问用户的数据。 嗯,Spring Data JPA 带有一个 JpaRepository 接口,它定义了实体上所有 CRUD 操作的方法,以及一个 名为 SimpleJpaRepository的JpaRepository的默认实现。用户存储库.java
package net.guides.springboot.loginregistrationspringbootauthjsp.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import net.guides.springboot.loginregistrationspringbootauthjsp.model.User;
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
RoleRepository.java
package net.guides.springboot.loginregistrationspringbootauthjsp.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import net.guides.springboot.loginregistrationspringbootauthjsp.model.Role;
public interface RoleRepository extends JpaRepository<Role, Long>{
}
6.服务层
UserDetailsServiceImpl.java
要使用 Spring Security 实现登录/身份验证,我们需要实现org.springframework.security.core.userdetails.UserDetailsService接口并从数据库中加载用户详细信息。package net.guides.springboot.loginregistrationspringbootauthjsp.service;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import net.guides.springboot.loginregistrationspringbootauthjsp.model.Role;
import net.guides.springboot.loginregistrationspringbootauthjsp.model.User;
import net.guides.springboot.loginregistrationspringbootauthjsp.repository.UserRepository;
@Service
public class UserDetailsServiceImpl implements UserDetailsService{
@Autowired
private UserRepository userRepository;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
for (Role role : user.getRoles()){
grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getpassword(), grantedAuthorities);
}
}
用户服务.java
package net.guides.springboot.loginregistrationspringbootauthjsp.service;
import net.guides.springboot.loginregistrationspringbootauthjsp.model.User;
public interface UserService {
void save(User user);
User findByUsername(String username);
}
UserServiceImpl.java
package net.guides.springboot.loginregistrationspringbootauthjsp.service;
import java.util.HashSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import net.guides.springboot.loginregistrationspringbootauthjsp.model.User;
import net.guides.springboot.loginregistrationspringbootauthjsp.repository.RoleRepository;
import net.guides.springboot.loginregistrationspringbootauthjsp.repository.UserRepository;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
public void save(User user) {
user.setPassword(bCryptPasswordEncoder.encode(user.getpassword()));
user.setRoles(new HashSet<>(roleRepository.findAll()));
userRepository.save(user);
}
@Override
public User findByUsername(String username) {
return userRepository.findByUsername(username);
}
}
7. 弹簧验证器
为了使用 Spring Validator 为 /registration 控制器提供输入数据验证,我们实现了org.springframework.validation.Validator:用户验证器.java
package net.guides.springboot.loginregistrationspringbootauthjsp.validator;
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;
import net.guides.springboot.loginregistrationspringbootauthjsp.model.User;
import net.guides.springboot.loginregistrationspringbootauthjsp.service.UserService;
@Component
public class UserValidator implements Validator {
@Autowired
private UserService userService;
@Override
public boolean supports(Class<?> aClass) {
return User.class.equals(aClass);
}
@Override
public void validate(Object o, Errors errors) {
User user = (User) o;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username", "NotEmpty");
if (user.getUsername().length() < 6 || user.getUsername().length() > 32) {
errors.rejectValue("username", "Size.userForm.username");
}
if (userService.findByUsername(user.getUsername()) != null) {
errors.rejectValue("username", "Duplicate.userForm.username");
}
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "NotEmpty");
if (user.getpassword().length() < 8 || user.getpassword().length() > 32) {
errors.rejectValue("password", "Size.userForm.password");
}
if (!user.getpasswordConfirm().equals(user.getpassword())) {
errors.rejectValue("passwordConfirm", "Diff.userForm.passwordConfirm");
}
}
}
8.控制器层
控制器层充当 View 和 Model之间的接口。它接收来自 视图 层的请求并处理它们,包括必要的验证。用户控制器.java
让我们使用以下方法处理程序创建 Spring MVC 控制器 - UserController 来处理请求和返回视图:package net.guides.springboot.loginregistrationspringbootauthjsp.web;
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.web.bind.annotation.modelattribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import net.guides.springboot.loginregistrationspringbootauthjsp.model.User;
import net.guides.springboot.loginregistrationspringbootauthjsp.service.UserService;
import net.guides.springboot.loginregistrationspringbootauthjsp.validator.UserValidator;
@Controller
public class UserController {
@Autowired
private UserService userService;
@Autowired
private UserValidator userValidator;
@RequestMapping(value = "/registration", method = RequestMethod.GET)
public String registration(Model model) {
model.addAttribute("userForm", new User());
return "registration";
}
@RequestMapping(value = "/registration", method = RequestMethod.POST)
public String registration(@modelattribute("userForm") User userForm, BindingResult bindingResult, Model model) {
userValidator.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
return "registration";
}
userService.save(userForm);
return "redirect:/welcome";
}
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(Model model, String error, String logout) {
if (error != null)
model.addAttribute("error", "Your username and password is invalid.");
if (logout != null)
model.addAttribute("message", "You have been logged out successfully.");
return "login";
}
@RequestMapping(value = {"/", "/welcome"}, method = RequestMethod.GET)
public String welcome(Model model) {
return "welcome";
}
}
9.查看图层
该层代表应用程序的输出,通常是某种形式的 UI。表示层用于显示 Controller获取的Model 数据 。 在本例中,我们使用 JSP 作为视图层。注册.jsp
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<c:set var="contextpath" value="${pageContext.request.contextpath}"/>
<!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">
<!-- The above 3 Meta tags *must* come first in the head; any other head content must come *after* these tags -->
<Meta name="description" content="">
<Meta name="author" content="">
<title>Create an account</title>
<link href="${contextpath}/resources/css/bootstrap.min.css" rel="stylesheet">
<link href="${contextpath}/resources/css/common.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<form:form method="POST" modelattribute="userForm" class="form-signin">
<h2 class="form-signin-heading">Create your account</h2>
<spring:bind path="username">
<div class="form-group ${status.error ? 'has-error' : ''}">
<form:input type="text" path="username" class="form-control" placeholder="Username"
autofocus="true"></form:input>
<form:errors path="username"></form:errors>
</div>
</spring:bind>
<spring:bind path="password">
<div class="form-group ${status.error ? 'has-error' : ''}">
<form:input type="password" path="password" class="form-control" placeholder="Password"></form:input>
<form:errors path="password"></form:errors>
</div>
</spring:bind>
<spring:bind path="passwordConfirm">
<div class="form-group ${status.error ? 'has-error' : ''}">
<form:input type="password" path="passwordConfirm" class="form-control"
placeholder="Confirm your password"></form:input>
<form:errors path="passwordConfirm"></form:errors>
</div>
</spring:bind>
<button class="btn btn-lg btn-primary btn-block" type="submit">Submit</button>
</form:form>
</div>
<!-- /container -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="${contextpath}/resources/js/bootstrap.min.js"></script>
</body>
</html>
登录.jsp
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<c:set var="contextpath" value="${pageContext.request.contextpath}"/>
<!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">
<!-- The above 3 Meta tags *must* come first in the head; any other head content must come *after* these tags -->
<Meta name="description" content="">
<Meta name="author" content="">
<title>Log in with your account</title>
<link href="${contextpath}/resources/css/bootstrap.min.css" rel="stylesheet">
<link href="${contextpath}/resources/css/common.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<form method="POST" action="${contextpath}/login" class="form-signin">
<h2 class="form-heading">Log in</h2>
<div class="form-group ${error != null ? 'has-error' : ''}">
<span>${message}</span>
<input name="username" type="text" class="form-control" placeholder="Username"
autofocus="true"/>
<input name="password" type="password" class="form-control" placeholder="Password"/>
<span>${error}</span>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<button class="btn btn-lg btn-primary btn-block" type="submit">Log In</button>
<h4 class="text-center"><a href="${contextpath}/registration">Create an account</a></h4>
</div>
</form>
</div>
<!-- /container -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="${contextpath}/resources/js/bootstrap.min.js"></script>
</body>
</html>
欢迎.jsp
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="contextpath" value="${pageContext.request.contextpath}"/>
<!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">
<!-- The above 3 Meta tags *must* come first in the head; any other head content must come *after* these tags -->
<Meta name="description" content="">
<Meta name="author" content="">
<title>Create an account</title>
<link href="${contextpath}/resources/css/bootstrap.min.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<c:if test="${pageContext.request.userPrincipal.name != null}">
<form id="logoutForm" method="POST" action="${contextpath}/logout">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>
<h2>Welcome ${pageContext.request.userPrincipal.name} | <a onclick="document.forms['logoutForm'].submit()">logout</a></h2>
</c:if>
</div>
<!-- /container -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="${contextpath}/resources/js/bootstrap.min.js"></script>
</body>
</html>
10.配置属性文件
配置 JSP 视图解析器
## Spring view resolver set up
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
配置 MysqL 数据库
由于我们使用 MysqL 作为我们的数据库,我们需要配置数据库 URL 、 用户名和 密码 ,以便 Spring 可以在启动时与数据库建立连接。打开 src/main/resources/application.properties 文件并向其中添加以下属性:spring.datasource.url=jdbc:MysqL://localhost:3306/loginregistration?autoReconnect=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MysqL5InnoDBDialect
spring.jpa.hibernate.ddl-auto = update
不要忘记 根据您的 MysqL 安装更改spring.datasource.username 和 spring.datasource.password 。 此外,在继续下一节之前,在 MysqL 中创建一个名为 demo的数据库。
您不需要创建任何表。这些表将由 Hibernate 从 我们将在下一步中定义的Employee 实体自动创建。这可以通过属性 spring.jpa.hibernate.ddl-auto = update 实现。
Validation.properties 文件
在资源文件夹下创建validation.properties文件,并添加以下内容:NotEmpty=This field is required.
Size.userForm.username=Please use between 6 and 32 characters.
Duplicate.userForm.username=Someone already has that username.
Size.userForm.password=Try one with at least 8 characters.
Diff.userForm.passwordConfirm=These passwords don't match.
11. 网络安全配置
WebSecurityConfig.java
package net.guides.springboot.loginregistrationspringbootauthjsp.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, proxyTargetClass = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/registration").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}
12. 运行应用程序
package net.guides.springboot.loginregistrationspringbootauthjsp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
13. 演示
注册页面
注册页面验证
登录页面
登出页面
14. GitHub存储库上的源代码
本教程的源代码位于我的 GitHub 存储库 login-registration-spring-boot-hibernate-jsp-auth上。