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.
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.
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.
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.
@SpringBootApplication
→ A summary of the following three functions@EnableAutoConfiguration
→ Whether to configure automatically@ComponentScan
→ Perform component scan@ Configuration
→ Register to Bean or import classApp.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.
@Controller
→ Granted to the class that becomes Controller@GetMapping ("(URL) ")
→ "(URL)"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
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.
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>
You should see something like the following.
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.
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.
Annotation
@EnableWebSecurity
→ Enable Spring Security
@Autowired
→ Automatically store objects
@Bean
→ Register in DI container
@Override
→ Indicates override
Signature of each method
configure-WebSecurity → Web-wide security settings
configure-HttpSecurity → Security settings for each URL
configure-AuthenticationManagerBuilder → Authentication related settings
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
@ Entity
→ Granted to entity class@Table (name =" (table name) ")
→ Specify the table name of the database to access@Column (name =" column name ")
→ Specify the column name of the table@ Id
→ Primary key (Integer type this time)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.
@ Repository
→ Grant to class accessing DBLoginUserDao.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
@Service
→ Granted to the class that performs business logicUserDetailsServiceImpl.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>
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
After running the Spring application, go to http: // localhost: 8080 / login to check. You're probably able to log in.
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
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
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