2 User Registration Implementation
2 User Registration Implementation
Goal
- Implement the user registration function.
User Registration Implementation
Maven Dependency Update
-
Open staybooking project in Intellij and find the
pom.xml
file -
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>
<?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
- 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
- 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.
- 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.
Model Class Creation
- 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.
- 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;
}
- 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;
}
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 theusername
field as the primary key. This means that eachUser
object will be uniquely identified by itsusername
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 implementsSerializable
. It is used during the deserialization process to ensure that a loaded class corresponds exactly to a serialized object. If theserialVersionUID
of the class does not match that of the serialized object, anInvalidClassException
is thrown.
- Add the public Getter and Setter for each private field.
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;
}
}
- 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);
}
}
}
- 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.
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 {
...
}
}
- Next to the User class, create another class called
Authority
, which will be used by the Spring Security framework for user authorization
- The code in Authority class is simple, just need username and authority
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
- 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> {
}
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
- 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> {
}
Implement Registration Service
- Go to
com.eve.staybooking.service
package. Create a new class calledRegisterService
.
package com.eve.staybooking.service;
import org.springframework.stereotype.Service;
@Service
public class RegisterService {
}
- Add both
UserRepository
andAuthorityRepository
as the private field of theRegisterService
.
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;
}
- 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.
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.
- 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.
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()));
}
}
- 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 calledcom.eve.staybooking.exception
and add a new class calledUserAlreadyExistException
into it.
package com.eve.staybooking.exception;
public class UserAlreadyExistException extends RuntimeException{
public UserAlreadyExistException(String message) {
super(message);
}
}
- Add the duplication check in the
RegisterService
and throwUserAlreadyExistException
properly.
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()));
}
}
- 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 calledSecurityConfig
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();
}
}
- 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()));
}
}
Implement Register Controller
- Go to the
com.eve.staybooking.controller
package and create theRegisterController.class
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
有以下几个作用:
- 标识控制器:
@RestController
将类标记为一个控制器,使 Spring 能够扫描并检测到这个类,并将其作为 Spring MVC 的控制器进行管理。- 简化开发:由于
@RestController
自动包含了@ResponseBody
,所以控制器中的每个方法默认会直接将返回值写入 HTTP 响应体。这使得开发 RESTful API 时更加简洁,不需要在每个方法上添加@ResponseBody
注解。- 返回 JSON 或 XML:典型的 RESTful 服务会返回 JSON 或 XML 格式的数据。使用
@RestController
时,Spring 会根据请求的内容类型(Content-Type)自动将返回值序列化为相应的格式(例如,JSON)。
- Add the
RegisterService
as a private field and a constructor for initialization.
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;
}
}
- Add the two RESTful API we will support on the backend for registration: addHost and addGuest.
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.
- As you may wonder, how does the controller handle the
UserAlreadyExist
exception here? We can definitely handle that inside ofaddGuest
andaddHost
. But a cleaner way is to have a dedicated exception handler to handle all kinds of exceptions for every controller. Now let’s create aCustomExceptionHandler
class in thecom.eve.staybooking.controller
package.
- Add the handler function to handle UserAlreadyExistException.
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 useCustomExceptionHandler
when there’s any exceptions in the Controller code. -
@ExceptionHandler
to match each exception to the corresponding handler function.
- Finally, go back to
SecurityConfig.class
and make sure/register/host and /register/guest
URLs are allowed without user authentication.
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 useSecurityFilterChain
and@Bean
methods.
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
- 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 useorg.hibernate.dialect.MySQLDialect
.Replace
org.hibernate.dialect.MySQL5InnoDBDialect
withorg.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
Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.
- Use the test request from the Postman collection. Make sure both the host register and guest register are OK.
- (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都要用注意 不然连不上数据库