[JAVA] Let's make a book management web application with Spring Boot part2

Introduction

Hi, my name is @ Ikuto19, a college student studying programming. This time, I will start from Continued from last time (part1). After briefly explaining the previous review, I will explain the creation procedure and actually make the application.

Last review and commentary

About the last time

In part1, we created and released a test app to help you understand the flow and preparation for creating a book management app. Specifically, I installed tools to use the Spring Framework and registered an account on Heroku.

Precautions after this! !!

I will explain the role of code and annotation from this part, but this is my first time to touch Spring Framework. In short, I'm a beginner, so I can't explain in detail. It's just a rough explanation of my interpretation, so don't take it for the same beginners who are looking at this article. It fits roughly, but I think it may be different, so please check it yourself. On the contrary, if you are an advanced person, please point out more and more as I said last time.

Explanation of the previous code

App.java This App.java runs the web app. So, if you don't include this main function, the app won't start. The class name can be anything, but I named it App. If you want to change the class name, please change the content "App.class" to "class name.class".

About @SpringBootApplication, [Spring document Japanese translation](https://spring.pleiades.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-using- In "6. @SpringBootApplication annotation use "of springbootapplication-annotation), it was written as follows.

@EnableAutoConfiguration: Enable Spring Boot autoconfiguration mechanism @ComponentScan: Enable @Component Scan on the package where your application is located (see best practices) @Configuration: You can register additional beans in the context and import additional configuration classes.

When I interpreted it all together, I thought it would look like this.

App.java


package com.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {
	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}
}

IndexController.java IndexController.java is the Controller in the MVC model. Controller controls Model and View based on user input, but this time I am trying to display index.html when the URL is "/". With "model.setAttribute (" message ", message)", you can handle the character string stored in message in the called html file.

IndexController.java


package com.app.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {
	
	@GetMapping("/")
	public String getIndexPage(Model model) {
		String message = "Hello, World!!";
		model.addAttribute("message",message);
		return "index";
	}
}

index.html

I interpreted the "xmlns: th = ~" part to use the template engine Thymeleaf. This makes it possible to handle values and strings from the controller even on HTML. The contents (character string) of the message stored in "th: text =" $ {message} "can be displayed.

index.html


<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8">
<head>
<title>Test app</title>
</head>
<body>
	<p th:text="${message}"></p>
</body>
</html>

Procfile

Java: I tried Heroku deployment of Spring Boot app I imitated this person's writing style as it is. I searched for \ $ JAVA_OPTS and --server.port = $ PORT, but didn't get a lot of hits. Roughly speaking, as far as I can see The Procfile on Heroku Dev Center, I think that I should write "App type: Execution command". I will.

Procfile


web: java $JAVA_OPTS -jar target/*.jar --server.port=$PORT

Creation procedure

  1. Create a project
  2. Home screen implementation
  3. Implementation of login screen and screen transition by DB authentication
  4. Implementation of screen transition from the home screen to the book search / book information display / call shadow display page
  5. Implementation of function to register / delete from DB after searching books
  6. Apply CSS
  7. Operation check

Project creation

Create the project as you did last time. The project name is "BookManagement-webapp", and other than that, create with the same settings as last time. However, please delete BookManagementWebappApplication.java.

Home screen implementation

Create new file

App.java Create and place the following App.java in the com.app package. As explained earlier, the execution of this class launches the Spring application.

App.java


package com.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class App {
	public static void main(String[] args) {
		SpringApplication.run(App.class, args);
	}
}

index.html Create index.html, which will be the home screen, in the templates folder. The home screen has the following functions.

indexhtml


<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8">
<head>
<title>Book management app</title>
</head>
<body>
	<div class="main_container">
		<div class=title>
			<h1>Book Management Web Application</h1>
		</div>
		<div class="middle_container">
			<div class="contains collate">
				<form method="get" action="operateCollate">
					<input type="text" class="texts" name="isbn" value=""
						placeholder="ISBN code"> <input class="submit"
						type="submit" value="Book matching">
				</form>
			</div>
			<div class="contains flexbox">
				<form method="get" action="operateCheck">
					<input class="submit" type="submit" value="Book information display">
				</form>
				<form method="get" action="operateCover">
					<input class="submit" type="submit" value="Book cover display">
				</form>
			</div>
		</div>
	</div>
</body>
</html>

Execution confirmation

You should see something like the following. スクリーンショット 2020-07-29 16.49.38.png

Login implementation using DB authentication of Spring Security

Next, we will implement login by DB authentication of Spring Security. The files to be modified (blue) and the files to be added (red) are as follows. This login authentication is Implementation of authentication function in Spring Security ① ~ Implementation of authentication function in Spring Security ③ / 3047949cb6018d2453dc) will be referred to, and it will be changed and created as necessary. So I think the code is almost the same. Also, the comments in each file belong to the person who wrote this article, so I deleted them. So read this article if you want to see the comments. スクリーンショット 2020-07-29 23.24.43.png

Create new file / modify existing file

WebSecurityConfig.java Security settings are made in this class. configure-The WebSecurity configure method excludes required files and folders from authentication. In the configure method of configure-HttpSecurity, screen transitions and accessible users are set when authentication succeeds or fails. The last configure-AuthenticationManagerBuilder's configure method is used to configure authentication.

WebSecurityConfig.java


package com.app.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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

import com.app.service.UserDetailsServiceImpl;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private UserDetailsServiceImpl userDetailsService;

	//Password encryption
	@Bean
	public BCryptPasswordEncoder passwordEncoder() {
		BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
		return bCryptPasswordEncoder;
	}

	//It is possible to handle CSS, Javascript, etc. and external image files
	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers(
				"/images/**",
				"/css/**",
				"/js/**"
				);
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception{
			http
				.authorizeRequests()
				.anyRequest().authenticated()
				.and()
			.formLogin()
				.loginPage("/login") //Login page URL
				.loginProcessingUrl("/login")
				.usernameParameter("username")
				.passwordParameter("password")
				.defaultSuccessUrl("/index", true) //URL transitioned by successful authentication
				.failureUrl("/login?error") //URL that transitions due to authentication failure
				.permitAll() //All users can connect
				.and()
			.logout()
				.logoutUrl("/logout") //URL of the logout page
				.logoutSuccessUrl("/login?logout") //URL after successful logout
				.permitAll();
	}
	
	@Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
}

LoginController.java When the URL is "/ login", login.html is displayed.

LoginController.java


package com.app.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class LoginController {
	@GetMapping("/login")
	public String getSignUp(Model model) {
		return "login";
	}
}

LoginUser.java

LoginUser.java


package com.app.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "user")
public class LoginUser {

    @Column(name = "user_id")
    @Id
    private Long userId;

    @Column(name = "user_name")
    private String userName;

    @Column(name = "password")
    private String password;

    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;
    }

	public Long getUserId() {
		return userId;
	}

	public void setUserId(Long userId) {
		this.userId = userId;
	}
}

LoginUserDao.java Access the database with the findUser method and return the user object with the user name.

LoginUserDao.java


package com.app.repository;

import javax.persistence.EntityManager;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.app.entity.LoginUser;

@Repository
public class LoginUserDao {

    @Autowired
    EntityManager em;

    public LoginUser findUser(String userName) {

        String query = "";
        query += "SELECT * ";
        query += "FROM user ";
        query += "WHERE user_name = :userName ";

        return (LoginUser)em.createNativeQuery(query, LoginUser.class).setParameter("userName", userName).getSingleResult();
    }
}

UserRepository.java

UserRepository.java


package com.app.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.app.entity.LoginUser;

/*
 *<Something class,ID type>
 */
@Repository
public interface UserRepository extends JpaRepository<LoginUser, Integer>{}

UserDetailsServiceImpl.java

UserDetailsServiceImpl.java


package com.app.service;

import java.util.ArrayList;
import java.util.List;

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.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import com.app.repository.LoginUserDao;
import com.app.entity.LoginUser;

@Service
public class UserDetailsServiceImpl implements UserDetailsService{

    @Autowired
    private LoginUserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {

        LoginUser user = userDao.findUser(userName);
        if (user == null) throw new UsernameNotFoundException(userName + "Does not exist in the database.");

        List<GrantedAuthority> grantList = new ArrayList<GrantedAuthority>();
        GrantedAuthority authority = new SimpleGrantedAuthority("USER");
        grantList.add(authority);
        
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        UserDetails userDetails = (UserDetails)new User(user.getUserName(), encoder.encode(user.getPassword()),grantList);

        return userDetails;
    }
}

index.html Place the following at the bottom of the "class =" contains flexbox "" div tag.

index.html


<form  method="post" id="logout" th:action="@{/logout}">
		<button type="submit">Log out</button>
</form>

login.html

login.html


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title>LoginPage</title>
</head>
<body>
	<div class="main_container">
		<p th:if="${param.error}" class="message">* The user name or password is different.</p>
		<p th:if="${param.logout}" class="message">* Logped out</p>
		<div class="login_container">
			<form th:action="@{/login}" method="post">
				<div class="buttons username">
					<i class="fas fa-users"></i> <input class="texts" type="text" name="username"
						placeholder="username" />
				</div>
				<div class="buttons pass">
					<i class="fas fa-lock"></i> <input class="texts" type="password" name="password"
						placeholder="password" />
				</div>
				<div class="submitButton">
					<input class="submit" type="submit" value="Login" />
				</div>
			</form>
		</div>
	</div>
</body>
</html>

application.properties

application.properties


spring.datasource.url=jdbc:mysql://localhost:3306/manageBook
spring.datasource.username=(mysql username)
spring.datasource.password=(mysql password)
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto=update

pom.xml The following is additionally described.

pom.xml


<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>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<scope>runtime</scope>
</dependency>

Database construction

Execute the following command on the installed MySQL.

terminal


$ mysql -u (mysql username) -p
Enter password: (mysql password)
mysql> create database manageBook;
mysql> use manageBook
mysql> create table user(user_id int auto_increment,user_name varchar(256),password varchar(256),PRIMARY KEY(user_id));
mysql> insert user value(1,"(Favorite name)","(Favorite password)");
mysql> select * from user;

If you check the contents of the table with the last "select * from user;", you will see the following. If you can confirm it, log out with the quit command.

terminal


mysql> select * from user;
+---------+-----------+---------------+
| user_id | user_name | password      |
+---------+-----------+---------------+
|       1 |(Favorite name) | (Favorite password)|
+---------+-----------+---------------+
1 row in set (0.04 sec)

mysql> quit;
Bye

Execution confirmation

After running the Spring application, go to http: // localhost: 8080 / login to check. You're probably able to log in.

At the end

That's all for this time. Next time, at the end, we will implement the transition from the home screen and the functions related to DB access. Continue to next time (part3)> Post soon

Reference site

A rudimentary mistake that could not be scanned with Spring Boot | Engineer 2 Nensei no Kiroku

Implemented authentication function with Spring Security ① --Qiita

Notes on touching Spring Boot-Qiita

Spring Boot Annotations

How to define a bean using Configuration class in Spring Boot --Reasonable Code

Spring Security usage memo basic / mechanism --Qiita

Set Web Security with Spring Boot (1/2): CodeZine

JPA (Java Persistence API) annotation

Recommended Posts

Let's make a book management web application with Spring Boot part1
Let's make a book management web application with Spring Boot part2
Let's make a simple API with EC2 + RDS + Spring boot ①
Start web application development with Spring Boot
Run WEB application with Spring Boot + Thymeleaf
Create a web api server with spring boot
Java beginner tried to make a simple web application using Spring Boot
Let's make a LINE Bot with Ruby + Sinatra --Part 2
[Spring Boot] Web application creation
Let's make a LINE Bot with Ruby + Sinatra --Part 1
I tried to clone a web application full of bugs with Spring Boot
Build a WEB system with Spring + Doma + H2DB Part 2
Let's make a circuit breaker for back-end service using Actuator of Spring Boot (Part 1)
A story that stumbled when deploying a web application created with Spring Boot to EC2
The first WEB application with Spring Boot-Making a Pomodoro timer-
Until you create a Web application with Servlet / JSP (Part 1)
Inquiry application creation with Spring Boot
Build a web application with Javalin
Implement a simple Web REST API server with Spring Boot + MySQL
[Beginner] Let's write REST API of Todo application with Spring Boot
Processing at application startup with Spring Boot
Let's make a Christmas card with Processing!
Create a simple web application with Dropwizard
HTTPS with Spring Boot and Let's Encrypt
Launch Nginx + Spring Boot application with docker-compose
Let's make a smart home with Ruby!
Spring Boot2 Web application development with Visual Studio Code SQL Server connection
Creating a java web application development environment with docker for mac part1
Spring Boot2 Web application development with Visual Studio Code Hello World creation
Automatically deploy a web application developed in Java using Jenkins [Spring Boot application]
Create a java web application development environment with docker for mac part2
Create a website with Spring Boot + Gradle (jdk1.8.x)
Create a simple search app with Spring Boot
Create a Spring Boot application using IntelliJ IDEA
Let's make a search function with Rails (ransack)
Deploy a Spring Boot application on Elastic Beanstalk
Build a WEB system with Spring + Doma + H2DB
Create a Spring Boot development environment with docker
I tried to make a machine learning application with Dash (+ Docker) part3 ~ Practice ~
Let's make a calculator application with Java ~ Create a display area in the window
Sign in to a Spring Boot web application on the Microsoft ID platform
From creating a Spring Boot project to running an application with VS Code
Let's create a TODO application in Java 2 I want to create a template with Spring Initializr and make a Hello world
Build a WEB system with Spring + Doma + H2DB + Thymeleaf
Try using OpenID Connect with Keycloak (Spring Boot application)
[JUnit 5 compatible] Write a test using JUnit 5 with Spring boot 2.2, 2.3
[Java basics] Let's make a triangle with a for statement
Implement a simple Rest API with Spring Security with Spring Boot 2.0
[Personal application work memo] Make a calendar with simple_calendar
Customize REST API error response with Spring Boot (Part 2)
[JUnit 5] Write a validation test with Spring Boot! [Parameterization test]
A memorandum when creating a REST service with Spring Boot
Create a simple demo site with Spring Security with Spring Boot 2.1
Spring Boot 2.3 Application Availability
Customize REST API error response with Spring Boot (Part 1)
I wrote a test with Spring Boot + JUnit 5 now
[Introduction to Android application development] Let's make a counter
Download with Spring Boot
Let's make a calculator application in Java ~ Display the application window
Implement REST API with Spring Boot and JPA (Application Layer)
A story packed with the basics of Spring Boot (solved)