Skip to content

2 User Registration Implementation

2 User Registration Implementation

Goal

  • Implement the user registration function.

Screenshot 2024-07-07 at 03.21.38

User Registration Implementation

Maven Dependency Update

  1. Open staybooking project in Intellij and find the pom.xml file

  2. Copy the following dependencies into your pom.xml file. Could you figure out what each dependency does in the project?

<dependencies> 
  <!-- ... existing dependencies -->
  <!-- Only insert the following, do not change or touch other lines -->
            <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.18</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    <!-- Only insert the above, do not change or touch other lines -->
 </dependencies>

Screenshot 2024-07-07 at 03.51.07

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.eve</groupId>
    <artifactId>staybooking</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>staybooking</name>
    <description>staybooking</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.18</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${project.parent.version}</version>
            </plugin>
        </plugins>
    </build>
</project>

If problem: you might find the solution: https://stackoverflow.com/questions/64639836/plugin-org-springframework-bootspring-boot-maven-plugin-not-found

  1. Open the application.properties file and add the following content. Make sure to see your own values for MySQL_INSTANCE_ADDRESS, MySQL_ADMIN_USERNAME, MySQL_ADMIN_USER_PASSWORD. So instead of creating your own Java class to configure DataSource and Hibernate setups, you can simply put all the configurations in this property file and Spring Boot will handle the rest for you.

application.properties:

spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql = true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.datasource.url = jdbc:mysql://staybooking.ck24ovxbozz2.us-east-1.rds.amazonaws.com:3306/staybooking?createDatabaseIfNotExist=true&serverTimezone=UTC
spring.datasource.username = admin
spring.datasource.password = ererqq434311
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql = true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.datasource.url = jdbc:mysql://localhost:3306/staybooking?createDatabaseIfNotExist=true&serverTimezone=UTC
spring.datasource.username = root
spring.datasource.password = Eve123456

Screenshot 2024-07-08 at 17.58.03

  1. Save your changes in pom.xml and run Maven Install to download the java libraries. Make sure you see the BUILD SUCCESS information from the console output.

Screenshot 2024-07-08 at 18.09.49

  1. Open the external libraries folder under your project, you can see a lot of useful libraries including Jackson, Tomcat, Hibernate, etc. The Spring Boot Starter dependency can help you significantly simplify the dependency management configs.

Screenshot 2024-07-08 at 18.11.15

Model Class Creation

  1. Go to the com.eve.staybooking and create a new Enum Class called UserRole. Since we mentioned we’ll support two kinds of users in the application, we need to add ROLE_HOST and ROLE_GUEST here.
package com.eve.staybooking.model;

public enum UserRole {
    ROLE_HOST, ROLE_GUEST
}

Screenshot 2024-07-08 at 18.15.29

  1. Create a User class under the same package. Similar to the first project, we need some basic information of a user like username, password and enabled.
package com.eve.staybooking.model;

public class User {
    private String username;
    private String password;
    private boolean enabled;
}

Screenshot 2024-07-08 at 18.26.04

  1. Since we'll use Hibernate to support database operation, we need to mark the class as Entity and pick the username as ID.
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;

@Entity
@Table(name = "user")
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    private String username;
    private String password;
    private boolean enabled;
}

Screenshot 2024-07-08 at 18.28.21

Hibernate is an object-relational mapping (ORM) tool for Java. It allows developers to map Java classes to database tables and vice versa, making database interactions more seamless and reducing the need for boilerplate SQL code.

  • By marking the class with the @Entity annotation, we tell Hibernate that this class should be treated as a database entity. This means that Hibernate will create a table in the database that corresponds to this class, where each instance of the class represents a row in that table.
  • The @Id annotation is used to specify the primary key of the entity. In this case, we are designating the username field as the primary key. This means that each User object will be uniquely identified by its username in the database.
  • @Table(name = "user"): This annotation specifies the name of the table in the database that this entity will be mapped to. In this case, the table will be named "user".
  • The Serializable interface in Java is used to enable the serialization of an object, which is the process of converting an object's state into a byte stream. This allows the object's state to be saved to a file, sent over a network, or stored in a database, and later reconstructed back into an object.
  • The serialVersionUID is a unique identifier for each class that implements Serializable. It is used during the deserialization process to ensure that a loaded class corresponds exactly to a serialized object. If the serialVersionUID of the class does not match that of the serialized object, an InvalidClassException is thrown.
  1. Add the public Getter and Setter for each private field.

Screenshot 2024-07-08 at 18.41.03

package com.eve.staybooking.model;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

import java.io.Serializable;

@Entity
@Table(name = "user")
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    private String username;
    private String password;
    private boolean enabled;
  public String getUsername() {
        return username;
    }

    public User setUsername(String username) {
        this.username = username;
        return this;
    }

    public String getPassword() {
        return password;
    }

    public User setPassword(String password) {
        this.password = password;
        return this;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public User setEnabled(boolean enabled) {
        this.enabled = enabled;
        return this;
    }
}
  1. If you want to use the builder pattern to create a User object in the future, you can add a static inner class Builder to the User class and provide a private constructor for it.
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@Entity
@Table(name = "user")
@JsonDeserialize(builder = User.Builder.class)
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    private String username;
    private String password;
    private boolean enabled;

    public User() {}

    private User(Builder builder) {
        this.username = builder.username;
        this.password = builder.password;
        this.enabled = builder.enabled;
    }

    public String getUsername() {
        return username;
    }

    public User setUsername(String username) {
        this.username = username;
        return this;
    }

    public String getPassword() {
        return password;
    }

    public User setPassword(String password) {
        this.password = password;
        return this;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public User setEnabled(boolean enabled) {
        this.enabled = enabled;
        return this;
    }

    public static class Builder {
        @JsonProperty("username")
        private String username;

        @JsonProperty("password")
        private String password;

        @JsonProperty("enabled")
        private boolean enabled;

        public Builder setUsername(String username) {
            this.username = username;
            return this;
        }

        public Builder setPassword(String password) {
            this.password = password;
            return this;
        }

        public Builder setEnabled(boolean enabled) {
            this.enabled = enabled;
            return this;
        }

        public User build() {
            return new User(this);
        }
    }
}

Screenshot 2024-07-08 at 22.27.11

  1. Finally add @JsonIgnore annotation to the password and enabled field. Because in some services, like stay list and reservation list, we want to show the host information or guest information, but we only want to show the username, not password or enabled.

Screenshot 2024-07-08 at 22.28.25

    import com.fasterxml.jackson.annotation.JsonIgnore;

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    private String username;

    @JsonIgnore
    private String password;

    @JsonIgnore
    private boolean enabled;

    public User() {}

    private User(Builder builder) {
        this.username = builder.username;
        this.password = builder.password;
        this.enabled = builder.enabled;
    }

    ...

    public static class Builder {
        ...
    }
}
  1. Next to the User class, create another class called Authority, which will be used by the Spring Security framework for user authorization

Screenshot 2024-07-08 at 22.29.25

  1. The code in Authority class is simple, just need username and authority

Screenshot 2024-07-08 at 22.32.14

     package com.laioffer.staybooking.model;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;

@Entity
@Table(name = "authority")
public class Authority implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    private String username;
    private String authority;

    public Authority() {}

    public Authority(String username, String authority) {
        this.username = username;
        this.authority = authority;
    }

    public String getUsername() {
        return username;
    }

    public Authority setUsername(String username) {
        this.username = username;
        return this;
    }

    public String getAuthority() {
        return authority;
    }

    public Authority setAuthority(String authority) {
        this.authority = authority;
        return this;
    }
}

Add User Repository

  1. Create an interface named UserRepository under the com.eve.staybooking.repository package.
package com.eve.staybooking.repository;

import com.eve.staybooking.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, String> {

}

Screenshot 2024-07-08 at 22.50.48

As you can see, we created the UserRepository interface to extend the JpaRepository interface provided by Spring. There are several points here:

  • The type parameters for JpaRepository are User and String, the first one corresponding to the name of the model class, the second one corresponding to the ID type of the model class. By default, Spring Boot enables the JPA repository support and looks in the package (and its subpackages) where @SpringBootApplication is located.

  • By extending the JpaRepository, Spring can help provide some default implementations of common database operations. You can expose any of them and Spring will take care of the real implementation. The full list of default operations could be found at https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html

  • Besides the default operations, you can also define custom operations. As long as you follow the naming convention provided by Spring, you can only define the method in your @Repository interface and Spring can help you with the real implementation: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation

https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa

  1. Similar to UserRepository, we can create another interface called AuthorityRepository to handle database operations for authority management. Again, we don’t need to create a real implementation of this interface, as Spring will help with that.
package com.eve.staybooking.repository;

import com.eve.staybooking.model.Authority;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AuthorityRepository extends JpaRepository<Authority, String> {
}

Screenshot 2024-07-08 at 22.54.56

Implement Registration Service

  1. Go to com.eve.staybooking.service package. Create a new class called RegisterService.
package com.eve.staybooking.service;

import org.springframework.stereotype.Service;

@Service
public class RegisterService {
}

Screenshot 2024-07-08 at 22.55.10

  1. Add both UserRepository and AuthorityRepository as the private field of the RegisterService.
package com.eve.staybooking.service;

import com.eve.staybooking.repository.AuthorityRepository;
import com.eve.staybooking.repository.UserRepository;
import org.springframework.stereotype.Service;

@Service
public class RegisterService {
    private UserRepository userRepository;
    private AuthorityRepository authorityRepository;
}

Screenshot 2024-07-08 at 22.56.02

  1. Add a constructor for RegisterService. Don’t forget to add the @Autowire annotation to the constructor, otherwise Spring won’t help you find the correct implementation of UserRepository and AuthorityRepository.

Screenshot 2024-07-08 at 23.03.39

    public class RegisterService {
    ...

    @Autowired
    public RegisterService(UserRepository userRepository, AuthorityRepository authorityRepository) {
        this.userRepository = userRepository;
        this.authorityRepository = authorityRepository;
    }
}

The @Autowired annotation is part of Spring Framework’s dependency injection mechanism. It is used to automatically inject beans (objects) into your application context. This helps in achieving Inversion of Control (IoC), where the control of object creation and management is transferred from the application code to the Spring container.

  1. Now add a simple method to insert new user and authority records to the database. Pay attention to the@Transactional annotation, it will make the insert operations to user and authority tables will succeed together, or fail together.

Screenshot 2024-07-08 at 23.20.10

package com.eve.staybooking.service;

import com.eve.staybooking.model.Authority;
import com.eve.staybooking.model.User;
import com.eve.staybooking.model.UserRole;
import com.eve.staybooking.repository.AuthorityRepository;
import com.eve.staybooking.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;


@Service
public class RegisterService {
    private UserRepository userRepository;
    private AuthorityRepository authorityRepository;

    @Autowired
    public RegisterService(UserRepository userRepository, AuthorityRepository authorityRepository) {
        this.userRepository = userRepository;
        this.authorityRepository = authorityRepository;
    }

    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void add(User user, UserRole role) {
        userRepository.save(user);
        authorityRepository.save(new Authority(user.getUsername(), role.name()));
    }
}
  1. Now let’s take a deeper look at the add() method. How could you deal with duplicate usernames? We need to throw an exception when a user tries to reuse an existing username. So let’s create a new package called com.eve.staybooking.exception and add a new class called UserAlreadyExistException into it.
package com.eve.staybooking.exception;

public class UserAlreadyExistException extends RuntimeException{
    public UserAlreadyExistException(String message) {
        super(message);
    }
}

Screenshot 2024-07-09 at 14.33.45

  1. Add the duplication check in the RegisterService and throw UserAlreadyExistException properly.

Screenshot 2024-07-09 at 15.28.04

package com.eve.staybooking.service;

import com.eve.staybooking.exception.UserAlreadyExistException;
import com.eve.staybooking.model.Authority;
import com.eve.staybooking.model.User;
import com.eve.staybooking.model.UserRole;
import com.eve.staybooking.repository.AuthorityRepository;
import com.eve.staybooking.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;


@Service
public class RegisterService {
    private UserRepository userRepository;
    private AuthorityRepository authorityRepository;

    @Autowired
    public RegisterService(UserRepository userRepository, AuthorityRepository authorityRepository) {
        this.userRepository = userRepository;
        this.authorityRepository = authorityRepository;
    }

    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void add(User user, UserRole role) throws UserAlreadyExistException {
        if (userRepository.existsById(user.getUsername())) {
            throw new UserAlreadyExistException("User already exists");
        }
        userRepository.save(user);
        authorityRepository.save(new Authority(user.getUsername(), role.name()));
    }
}
  1. Besides the duplicated username checking, we also need to take care of the password management. For security reasons, storing unencrypted passwords directly in the database is not recommended. We should do the encryption before saving the data. Create a new package named com.eve.staybooking.config and add a new class called SecurityConfig to it.
package com.eve.staybooking.config;

import jdk.jfr.Enabled;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@EnableWebSecurity
public class SecurityConfig{
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

}

Screenshot 2024-07-09 at 15.40.45

  1. Go back to the RegisterService class, and use the passwordEncoder to do the encryption.
package com.eve.staybooking.service;

import com.eve.staybooking.exception.UserAlreadyExistException;
import com.eve.staybooking.model.Authority;
import com.eve.staybooking.model.User;
import com.eve.staybooking.model.UserRole;
import com.eve.staybooking.repository.AuthorityRepository;
import com.eve.staybooking.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;


@Service
public class RegisterService {
    private UserRepository userRepository;
    private AuthorityRepository authorityRepository;

    private PasswordEncoder passwordEncoder;

    @Autowired
    public RegisterService(UserRepository userRepository, AuthorityRepository authorityRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.authorityRepository = authorityRepository;
        this.passwordEncoder = passwordEncoder;
    }

    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void add(User user, UserRole role) throws UserAlreadyExistException {
        if (userRepository.existsById(user.getUsername())) {
            throw new UserAlreadyExistException("User already exists");
        }

        user.setPassword(passwordEncoder.encode(user.getPassword()));
        user.setEnabled(true);
        userRepository.save(user);
        authorityRepository.save(new Authority(user.getUsername(), role.name()));
    }
}

Screenshot 2024-07-09 at 15.50.06

Implement Register Controller

  1. Go to the com.eve.staybooking.controller package and create the RegisterController.class

Screenshot 2024-07-09 at 16.12.05

package com.eve.staybooking.controller;

import org.springframework.web.bind.annotation.RestController;

@RestController
public class RegisterController {

}

@RestController 是 Spring Framework 中的一个注解,用于标记一个类作为 RESTful web 服务的控制器。这个注解是 @Controller@ResponseBody 注解的结合,使得控制器中的每个方法的返回值会直接写入 HTTP 响应体中,而不通过视图解析器进行解析。

具体来说,@RestController 有以下几个作用:

  1. 标识控制器@RestController 将类标记为一个控制器,使 Spring 能够扫描并检测到这个类,并将其作为 Spring MVC 的控制器进行管理。
  2. 简化开发:由于 @RestController 自动包含了 @ResponseBody,所以控制器中的每个方法默认会直接将返回值写入 HTTP 响应体。这使得开发 RESTful API 时更加简洁,不需要在每个方法上添加 @ResponseBody 注解。
  3. 返回 JSON 或 XML:典型的 RESTful 服务会返回 JSON 或 XML 格式的数据。使用 @RestController 时,Spring 会根据请求的内容类型(Content-Type)自动将返回值序列化为相应的格式(例如,JSON)。
  1. Add the RegisterService as a private field and a constructor for initialization.

Screenshot 2024-07-09 at 16.43.27

package com.eve.staybooking.controller;

import com.eve.staybooking.service.RegisterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RegisterController {
    private RegisterService registerService;

    @Autowired
    public RegisterController(RegisterService registerService) {
        this.registerService = registerService;
    }

}
  1. Add the two RESTful API we will support on the backend for registration: addHost and addGuest.

Screenshot 2024-07-09 at 16.45.40

package com.eve.staybooking.controller;

import com.eve.staybooking.model.User;
import com.eve.staybooking.model.UserRole;
import com.eve.staybooking.service.RegisterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RegisterController {
    private RegisterService registerService;

    @Autowired
    public RegisterController(RegisterService registerService) {
        this.registerService = registerService;
    }

    @PostMapping("/register/guest")
    public void addGuest(@RequestBody User user){
        registerService.add(user, UserRole.ROLE_GUEST);
    }

    @PostMapping("/register/host")
    public void addHost(@RequestBody User user){
        registerService.add(user, UserRole.ROLE_HOST);
    }

}

There are a few annotations to support a RESTful API:

  • @PostMapping("/register/guest") annotation to indicate the API supports POST method and maps to the /register/guest path.
  • @RequestBody annotation to help convert the request body from JSON format to a Java object.
  1. As you may wonder, how does the controller handle the UserAlreadyExist exception here? We can definitely handle that inside of addGuest and addHost. But a cleaner way is to have a dedicated exception handler to handle all kinds of exceptions for every controller. Now let’s create a CustomExceptionHandler class in the com.eve.staybooking.controller package.
package com.eve.staybooking.controller;

public class CustomExceptionHandler {
}

Screenshot 2024-07-09 at 16.55.28

  1. Add the handler function to handle UserAlreadyExistException.

Screenshot 2024-07-09 at 17.06.15

package com.eve.staybooking.controller;

import com.eve.staybooking.exception.UserAlreadyExistException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;

@ControllerAdvice
public class CustomExceptionHandler {
    @ExceptionHandler(UserAlreadyExistException.class)
    public final ResponseEntity<String> handleUserAlreadyExistExceptions(Exception ex, WebRequest request){
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.CONFLICT);
    }

}

A few explanation for the annotation in the exception handler:

  • @ControllerAdvice to make Spring use CustomExceptionHandler when there’s any exceptions in the Controller code.

  • @ExceptionHandler to match each exception to the corresponding handler function.

  1. Finally, go back to SecurityConfig.class and make sure /register/host and /register/guest URLs are allowed without user authentication.

Screenshot 2024-07-09 at 17.40.09

package com.eve.staybooking.config;

import jdk.jfr.Enabled;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
 @Bean
 public PasswordEncoder passwordEncoder(){
     return new BCryptPasswordEncoder();
 }

 @Override
 protected void configure(HttpSecurity http) throws Exception{
     http
             .authorizeRequests()
             .antMatchers(HttpMethod.POST, "/register").permitAll()
             .anyRequest().authenticated()
             .and()
             .csrf()
             .disable();
 }


}

Given that WebSecurityConfigurerAdapter is deprecated, you can refactor your configuration to use SecurityFilterChain and @Bean methods.

Screenshot 2024-07-09 at 18.05.32

package com.eve.staybooking.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@EnableWebSecurity
@Configuration
public class SecurityConfig {
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeRequests(authorizeRequests ->
                        authorizeRequests
                                .requestMatchers(HttpMethod.POST, "/register").permitAll()
                                .anyRequest().authenticated()
                )
                .csrf(csrf -> csrf.disable());

        return http.build();
    }

}

Test Your Code

  1. Save your changes and start your application. Make sure there’s no error in the log.

The error message indicates that the class org.hibernate.dialect.MySQL5InnoDBDialect could not be found. This likely means that the dialect class name is incorrect or has been deprecated/removed in the version of Hibernate you are using.

In Hibernate 6.x, the class org.hibernate.dialect.MySQL5InnoDBDialect has been removed. Instead, you should use org.hibernate.dialect.MySQLDialect.

Replace org.hibernate.dialect.MySQL5InnoDBDialect with org.hibernate.dialect.MySQLDialect.

spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql = true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect
spring.datasource.url = jdbc:mysql://localhost:3306/staybooking?createDatabaseIfNotExist=true&serverTimezone=UTC
spring.datasource.username = root
spring.datasource.password = Eve123456

Screenshot 2024-07-09 at 18.14.49

Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

Screenshot 2024-07-09 at 18.43.21

  1. Use the test request from the Postman collection. Make sure both the host register and guest register are OK.

Screenshot 2024-07-09 at 18.47.23

Screenshot 2024-07-09 at 18.47.36

  1. (Optional) Go back to your Intellij, and use the Database window to verify both User and Authority tables are created, and new users are added to the table.

AWZ inbound he outbound都要用注意 不然连不上数据库

Screenshot 2024-07-09 at 18.48.57