mirror of
https://github.com/mrfluffy-dev/PRG381.git
synced 2026-01-17 02:10:33 +00:00
First commit
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package net.javaguides.springboot;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class RegistrationLoginSpringBootSecurityThymeleafApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(RegistrationLoginSpringBootSecurityThymeleafApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package net.javaguides.springboot.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
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.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
import net.javaguides.springboot.service.UserService;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Bean
|
||||
public BCryptPasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DaoAuthenticationProvider authenticationProvider() {
|
||||
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
|
||||
auth.setUserDetailsService(userService);
|
||||
auth.setPasswordEncoder(passwordEncoder());
|
||||
return auth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.authenticationProvider(authenticationProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().antMatchers(
|
||||
"/registration**",
|
||||
"/js/**",
|
||||
"/css/**",
|
||||
"/img/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
.permitAll()
|
||||
.and()
|
||||
.logout()
|
||||
.invalidateHttpSession(true)
|
||||
.clearAuthentication(true)
|
||||
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
|
||||
.logoutSuccessUrl("/login?logout")
|
||||
.permitAll();
|
||||
}
|
||||
|
||||
}
|
||||
39
src/main/java/net/javaguides/springboot/model/Role.java
Normal file
39
src/main/java/net/javaguides/springboot/model/Role.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package net.javaguides.springboot.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "role")
|
||||
public class Role {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
public Role() {
|
||||
|
||||
}
|
||||
|
||||
public Role(String name) {
|
||||
super();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
95
src/main/java/net/javaguides/springboot/model/User.java
Normal file
95
src/main/java/net/javaguides/springboot/model/User.java
Normal file
@@ -0,0 +1,95 @@
|
||||
package net.javaguides.springboot.model;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import javax.persistence.JoinColumn;
|
||||
|
||||
@Entity
|
||||
@Table(name = "user", uniqueConstraints = @UniqueConstraint(columnNames = "email"))
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "first_name")
|
||||
private String firstName;
|
||||
|
||||
@Column(name = "last_name")
|
||||
private String lastName;
|
||||
|
||||
private String email;
|
||||
|
||||
private String password;
|
||||
|
||||
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
@JoinTable(
|
||||
name = "users_roles",
|
||||
joinColumns = @JoinColumn(
|
||||
name = "user_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(
|
||||
name = "role_id", referencedColumnName = "id"))
|
||||
|
||||
private Collection<Role> roles;
|
||||
|
||||
public User() {
|
||||
|
||||
}
|
||||
|
||||
public User(String firstName, String lastName, String email, String password, Collection<Role> roles) {
|
||||
super();
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
this.roles = roles;
|
||||
}
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
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 String getEmail() {
|
||||
return email;
|
||||
}
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
public Collection<Role> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
public void setRoles(Collection<Role> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.javaguides.springboot.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import net.javaguides.springboot.model.User;
|
||||
|
||||
@Repository
|
||||
public interface UserRepository extends JpaRepository<User, Long>{
|
||||
User findByEmail(String email);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package net.javaguides.springboot.service;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
import net.javaguides.springboot.model.User;
|
||||
import net.javaguides.springboot.web.dto.UserRegistrationDto;
|
||||
|
||||
public interface UserService extends UserDetailsService{
|
||||
User save(UserRegistrationDto registrationDto);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package net.javaguides.springboot.service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import net.javaguides.springboot.model.Role;
|
||||
import net.javaguides.springboot.model.User;
|
||||
import net.javaguides.springboot.repository.UserRepository;
|
||||
import net.javaguides.springboot.web.dto.UserRegistrationDto;
|
||||
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService{
|
||||
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private BCryptPasswordEncoder passwordEncoder;
|
||||
|
||||
public UserServiceImpl(UserRepository userRepository) {
|
||||
super();
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User save(UserRegistrationDto registrationDto) {
|
||||
User user = new User(registrationDto.getFirstName(),
|
||||
registrationDto.getLastName(), registrationDto.getEmail(),
|
||||
passwordEncoder.encode(registrationDto.getPassword()), Arrays.asList(new Role("ROLE_USER")));
|
||||
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
|
||||
User user = userRepository.findByEmail(username);
|
||||
if(user == null) {
|
||||
throw new UsernameNotFoundException("Invalid username or password.");
|
||||
}
|
||||
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), mapRolesToAuthorities(user.getRoles()));
|
||||
}
|
||||
|
||||
private Collection<? extends GrantedAuthority> mapRolesToAuthorities(Collection<Role> roles){
|
||||
return roles.stream().map(role -> new SimpleGrantedAuthority(role.getName())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.javaguides.springboot.web;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Controller
|
||||
public class MainController {
|
||||
|
||||
@GetMapping("/login")
|
||||
public String login() {
|
||||
return "login";
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String home() {
|
||||
return "index";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package net.javaguides.springboot.web;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import net.javaguides.springboot.service.UserService;
|
||||
import net.javaguides.springboot.web.dto.UserRegistrationDto;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/registration")
|
||||
public class UserRegistrationController {
|
||||
|
||||
private UserService userService;
|
||||
|
||||
public UserRegistrationController(UserService userService) {
|
||||
super();
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@ModelAttribute("user")
|
||||
public UserRegistrationDto userRegistrationDto() {
|
||||
return new UserRegistrationDto();
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String showRegistrationForm() {
|
||||
return "registration";
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public String registerUserAccount(@ModelAttribute("user") UserRegistrationDto registrationDto) {
|
||||
userService.save(registrationDto);
|
||||
return "redirect:/registration?success";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package net.javaguides.springboot.web.dto;
|
||||
|
||||
public class UserRegistrationDto {
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private String email;
|
||||
private String password;
|
||||
|
||||
public UserRegistrationDto(){
|
||||
|
||||
}
|
||||
|
||||
public UserRegistrationDto(String firstName, String lastName, String email, String password) {
|
||||
super();
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
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 String getEmail() {
|
||||
return email;
|
||||
}
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
15
src/main/resources/application.properties
Normal file
15
src/main/resources/application.properties
Normal file
@@ -0,0 +1,15 @@
|
||||
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
|
||||
spring.datasource.url = jdbc:mysql://localhost:3306/PRG381?useSSL=false
|
||||
spring.datasource.username = mrfluffy
|
||||
spring.datasource.password = 0814661902
|
||||
|
||||
## Hibernate Properties
|
||||
# The SQL dialect makes Hibernate generate better SQL for the chosen database
|
||||
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
|
||||
|
||||
# Hibernate ddl auto (create, create-drop, validate, update)
|
||||
spring.jpa.hibernate.ddl-auto = update
|
||||
|
||||
logging.level.org.hibernate.SQL=DEBUG
|
||||
logging.level.org.hibernate.type=TRACE
|
||||
|
||||
46
src/main/resources/templates/index.html
Normal file
46
src/main/resources/templates/index.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
|
||||
<head>
|
||||
<meta charset="ISO-8859-1">
|
||||
<title>Registration and Login App</title>
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
|
||||
crossorigin="anonymous">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<!-- create navigation bar ( header) -->
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed"
|
||||
data-toggle="collapse" data-target="#navbar" aria-expanded="false"
|
||||
aria-controls="navbar">
|
||||
<span class="sr-only">Toggle navigation</span> <span
|
||||
class="icon-bar"></span> <span class="icon-bar"></span> <span
|
||||
class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#" th:href="@{/}">Registration and
|
||||
Login Module</a>
|
||||
</div>
|
||||
<div id="navbar" class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li sec:authorize="isAuthenticated()"><a th:href="@{/logout}">Logout</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div class="container">
|
||||
<h1>Registration and Login with Spring Boot, Spring Security,
|
||||
Thymeleaf, Hibernate and MySQL</h1>
|
||||
Welcome <span sec:authentication="principal.username"> User</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
81
src/main/resources/templates/login.html
Normal file
81
src/main/resources/templates/login.html
Normal file
@@ -0,0 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="ISO-8859-1">
|
||||
<title>Registration and Login App</title>
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
|
||||
crossorigin="anonymous">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- create navigation bar ( header) -->
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed"
|
||||
data-toggle="collapse" data-target="#navbar" aria-expanded="false"
|
||||
aria-controls="navbar">
|
||||
<span class="sr-only">Toggle navigation</span> <span
|
||||
class="icon-bar"></span> <span class="icon-bar"></span> <span
|
||||
class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#" th:href="@{/}">Registration and
|
||||
Login Module</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<div class = "container">
|
||||
<div class = "row">
|
||||
<div class = "col-md-6 col-md-offset-3">
|
||||
|
||||
<h1> User Login Page </h1>
|
||||
<form th:action="@{/login}" method="post">
|
||||
|
||||
<!-- error message -->
|
||||
<div th:if="${param.error}">
|
||||
<div class="alert alert-danger">Invalid username or
|
||||
password.</div>
|
||||
</div>
|
||||
|
||||
<!-- logout message -->
|
||||
<div th:if="${param.logout}">
|
||||
<div class="alert alert-info">You have been logged out.</div>
|
||||
</div>
|
||||
|
||||
<div class = "form-group">
|
||||
<label for ="username"> Username </label> :
|
||||
<input type="text" class = "form-control" id ="username" name = "username"
|
||||
placeholder="Enter Email ID" autofocus="autofocus">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>: <input type="password"
|
||||
id="password" name="password" class="form-control"
|
||||
placeholder="Enter Password" />
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-sm-offset-3">
|
||||
<input type="submit" name="login-submit" id="login-submit"
|
||||
class="form-control btn btn-primary" value="Log In" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="form-group">
|
||||
<span>New user? <a href="/" th:href="@{/registration}">Register
|
||||
here</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
80
src/main/resources/templates/registration.html
Normal file
80
src/main/resources/templates/registration.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="ISO-8859-1">
|
||||
<title>Registration</title>
|
||||
<link rel="stylesheet"
|
||||
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
|
||||
crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- create navigation bar ( header) -->
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed"
|
||||
data-toggle="collapse" data-target="#navbar" aria-expanded="false"
|
||||
aria-controls="navbar">
|
||||
<span class="sr-only">Toggle navigation</span> <span
|
||||
class="icon-bar"></span> <span class="icon-bar"></span> <span
|
||||
class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#" th:href="@{/}">Registration and
|
||||
Login Module</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<!-- Create HTML registration form -->
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-3">
|
||||
|
||||
<!-- success message -->
|
||||
<div th:if="${param.success}">
|
||||
<div class="alert alert-info">You've successfully registered
|
||||
to our awesome app!</div>
|
||||
</div>
|
||||
|
||||
<h1>Registration</h1>
|
||||
|
||||
<form th:action="@{/registration}" method="post" th:object="${user}">
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="firstName"> First Name </label>
|
||||
<input id="firstName" class="form-control" th:field="*{firstName}"
|
||||
required autofocus="autofocus" />
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="lastName"> Last Name </label> <input
|
||||
id="lastName" class="form-control" th:field="*{lastName}"
|
||||
required autofocus="autofocus" />
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="email"> Email </label> <input
|
||||
id="email" class="form-control" th:field="*{email}" required
|
||||
autofocus="autofocus" />
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="password"> Password </label> <input
|
||||
id="password" class="form-control" type="password"
|
||||
th:field="*{password}" required autofocus="autofocus" />
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-success">Register</button>
|
||||
<span>Already registered? <a href="/" th:href="@{/login}">Login
|
||||
here</a></span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
package net.javaguides.springboot;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class RegistrationLoginSpringBootSecurityThymeleafApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user