--The following items need to be installed in advance. - Java11 --IDE (Here we will explain in Intellij. Other IDEs are also possible.)
--From Intellij, go to File → New → Project and select Spring Initilizr.

--Select Java 11. (Maybe Java 8 is fine)

--Check DevTools, Web, Thymeleaf, H2, MyBatis.

--Enter the project name and you're done.

--In order to improve development efficiency, set hot deploy to build automatically when the source is changed.
--If there are major changes or the changes are not reflected, you should stop the server → start it.
--From Intellij settings, from Build, Run, Deploy → Compiler, check □ Build project automatically.

--Enter ctrl + shift + a → Registry and click Registry .... (If you haven't translated Intellij into Japanese, type registry and clickRegistry ...)

--compiler. ... .running Check ☑.

--If you want to use the layout function of tymeleaf, put thymeleaf-layout-dialect in<dependencies> </ dependencies>of pom.xml as follows. (Here, we will proceed on the assumption that it will be included.)
--Incorporate Bootstrap and JQuery to improve the look of your design.
--Right-click pom.xml → Re-import.
pom.xml
    <dependency>
      <groupId>nz.net.ultraq.thymeleaf</groupId>
      <artifactId>thymeleaf-layout-dialect</artifactId>
      <version>2.3.0</version>
    </dependency>
    <dependency>
      <groupId>org.webjars</groupId>
      <artifactId>jquery</artifactId>
      <version>1.11.1</version>
    </dependency>
    <dependency>
      <groupId>org.webjars</groupId>
      <artifactId>bootstrap</artifactId>
      <version>3.3.7-1</version>
    </dependency>
--If you create schema.sql and data.sql, test data will be automatically input to DB at the start of project execution. --Create under the project name / src / main / resources.
schema.sql
CREATE TABLE IF NOT EXISTS user (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name varchar (50) NOT NULL
);
data.sql
INSERT INTO user (name) VALUES ('tanaka');
INSERT INTO user (name) VALUES ('suzuki');
INSERT INTO user (name) VALUES ('sato');
--Create an entity package and create a User class under it. --Create a class to hold User data. No annotations needed to use MyBatis. --Add required input validation to name.
java:com.example.demo.entity.User.java
package com.example.demo.entity;
import org.hibernate.validator.constraints.NotBlank;
public class User {
  private int id;
  @NotBlank(message = "{require_check}")
  private String name;
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}
--Create a mapper package and create a UserMapper interface under it.
--Add @Mapper to the annotation. If this is left as it is, Autowired cannot be done, so add @Repository as well.
java:src/main/java/com.example.demo.mapper.UserMapper.java
package com.example.demo.mapper;
import com.example.demo.entity.User;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Repository
@Mapper
public interface UserMapper {
  List<User> selectAll();
  User select(int id);
  int insert(User user);
  int update(User user);
  int delete(int id);
}
--The mapping file in XML will be read automatically if you create it in the same directory hierarchy as Java under resouces. --namespace: package name in (java) above --id: Method name specified in (java) above --resultType: Return type
src/main/resouces/com/example/demo/mapper/UserMapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <select id="selectAll" resultType="com.example.demo.entity.User">
        select * from user
    </select>
    <select id="select" resultType="com.example.demo.entity.User">
        select * from user where id = #{id}
    </select>
    <insert id="insert">
        insert into user (name) values (#{name})
    </insert>
    <update id="update">
        update user set name = #{name} where id = #{id}
    </update>
    <delete id="delete">
        delete from user where id = #{id}
    </delete>
</mapper>
--Add 7 actions.
| HTTP method | URL | controller method | Description | 
|---|---|---|---|
| GET | /users | getUsers() | Display of list screen | 
| GET | /users/1 | getUser() | Display details screen | 
| GET | /users/new | getUserNew() | Display of new creation screen | 
| POST | /users | postUserCreate() | Insertion process of new screen | 
| GET | /users/1/edit | getUserEdit() | Display of edit screen | 
| PUT | /users/1 | putUserEdit() | Edit screen update process | 
| DELETE | /users/1 | deleteUser() | Delete process | 
java:com.example.demo.controller.UserController
package com.example.demo.controller;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/users")
public class UserController {
  private final UserMapper userMapper;
  @Autowired
  public UserController(UserMapper userMapper) {
    this.userMapper = userMapper;
  }
  /**
   *Display of list screen
   */
  @GetMapping
  public String getUsers(Model model) {
    List<User> users = userMapper.selectAll();
    model.addAttribute("users", users);
    return "users/list";
  }
  /**
   *Display details screen
   */
  @GetMapping("{id}")
  public String getUser(@PathVariable int id, Model model) {
    User user = userMapper.select(id);
    model.addAttribute("user", user);
    return "users/show";
  }
  /**
   *Display of new creation screen
   */
  @GetMapping("new")
  public String getUserNew(Model model) {
    User user = new User();
    model.addAttribute("user", user);
    return "users/new";
  }
  /**
   *Insertion process of new screen
   */
  @PostMapping
  public String postUserCreate(@ModelAttribute @Valid User user,
      BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
      return "users/new";
    }
    userMapper.insert(user);
    return "redirect:/users";
  }
  /**
   *Display of edit screen
   */
  @GetMapping("{id}/edit")
  public String getUserEdit(@PathVariable int id, Model model) {
    User user = userMapper.select(id);
    model.addAttribute("user", user);
    return "users/edit";
  }
  /**
   *Edit screen update process
   */
  @PutMapping("{id}")
  public String putUserEdit(@PathVariable int id, @ModelAttribute @Valid User user,
      BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
      return "users/edit";
    }
    user.setId(id);
    userMapper.update(user);
    return "redirect:/users";
  }
  /**
   *Delete process
   */
  @DeleteMapping("{id}")
  public String deleteUser(@PathVariable int id, Model model) {
    userMapper.delete(id);
    return "redirect:/users";
  }
}
--Create messages.properties to set validation messages.
src/main/resources/messages.properties
name=username
require_check={0}Is a required entry
--The magic of creating the following configuration Java file to use the above property file.
java:com.example.demo/WebConfig.java
package com.example.demo;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@Configuration
public class WebConfig {
  @Bean
  public MessageSource messageSource() {
    ReloadableResourceBundleMessageSource bean = new ReloadableResourceBundleMessageSource();
    bean.setBasename("classpath:messages");
    bean.setDefaultEncoding("UTF-8");
    return bean;
  }
  @Bean
  public LocalValidatorFactoryBean localValidatorFactoryBean() {
    LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
    localValidatorFactoryBean.setValidationMessageSource(messageSource());
    return localValidatorFactoryBean;
  }
}
--Contents are displayed in <div layout: fragment =" contents "> </ div>.
src/main/resources/templates/commons/layout.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" >
<head>
    <meta charset="UTF-8">
    <link th:href="@{/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css}" rel="stylesheet"/>
    <script th:src="@{/webjars/jquery/1.11.1/jquery.min.js}"></script>
    <script th:src="@{/webjars/bootstrap/3.3.7-1/js/bootstrap.min.js}"></script>
    <link th:href="@{/css/home.css}" rel="stylesheet"/>
    <title>Home</title>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container-fluid">
        <div class="navbar-header">
            <a class="navbar-brand" href="#">SpringMyBatisDemo</a>
        </div>
    </div>
</nav>
<div class="container-fluid">
    <div class="row">
        <div class="col-sm-2 sidebar">
            <ul class="nav nav-pills nav-stacked">
                <li role="presentation"><a th:href="@{/users}">User management</a></li>
            </ul>
        </div>
    </div>
</div>
<div class="container-fluid">
    <div class="row">
        <div class="col-sm-10 col-sm-offset-2 main">
            <div layout:fragment="contents">
            </div>
        </div>
    </div>
</div>
</body>
</html>
--Layout is used with layout: decorate =" ~ {commons / layout} ".
--The part enclosed by <div layout: fragment =" contents "> </ div> is displayed in the layout.
src/main/resources/templates/users/list.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{commons/layout}">
<head>
  <meta charset="UTF-8">
  <link th:href="@{/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css}" rel="stylesheet"/>
  <script th:src="@{/webjars/jquery/1.11.1/jquery.min.js}"></script>
  <script th:src="@{/webjars/bootstrap/3.3.7-1/js/bootstrap.min.js}"></script>
  <link th:href="@{/css/home.css}" rel="stylesheet"/>
  <title>Home</title>
</head>
<body>
<div layout:fragment="contents">
  <div class="page-header">
    <h1>User list</h1>
  </div>
  <table class="table table-bordered table-hover table-striped">
    <tr>
      <th class="info col-sm-2">User ID</th>
      <th class="info col-sm-2">username</th>
      <th class="info col-sm-2"></th>
    </tr>
    <tr th:each="user:${users}">
      <td th:text="${user.id}"></td>
      <td th:text="${user.name}"></td>
      <td>
        <a class="btn btn-primary" th:href="@{'/users/' + ${user.id}}">Details</a>
        <a class="btn btn-primary" th:href="@{'/users/' + ${user.id} + '/edit'}">Edit</a>
      </td>
    </tr>
  </table>
  <label class="text-info" th:text="${result}">Result display</label><br/>
  <a class="btn btn-primary" th:href="${'/users/new'}">Create New</a>
</div>
</body>
</html>
--Layout is used with layout: decorate =" ~ {commons / layout} ".
--The part enclosed by <div layout: fragment =" contents "> </ div> is displayed in the layout.
--The common form is displayed in <div th: include =" users / form :: form_contents "> </ div>.
src/main/resources/templates/users/show.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{commons/layout}">
<head>
  <meta charset="UTF-8"/>
  <title></title>
</head>
<body>
<div layout:fragment="contents">
  <div class="row">
    <div class="col-sm-5">
      <div class="page-header">
        <div>
          <h1>User details</h1>
        </div>
          <table class="table table-bordered table-hover">
            <tr>
              <th class="active col-sm-3">username</th>
              <td>
                <div class="form-group" th:object="${user}">
                  <label class="media-body" th:text="*{name}">
                  </label>
                </div>
              </td>
            </tr>
          </table>
        <form th:action="@{/users}" th:method="get">
          <button class="btn btn-primary btn-lg pull-right" type="submit">List</button>
        </form>
      </div>
    </div>
  </div>
</div>
</body>
</html>
--Layout is used with layout: decorate =" ~ {commons / layout} ".
--The part enclosed by <div layout: fragment =" contents "> </ div> is displayed in the layout.
--The common form is displayed in <div th: include =" users / form :: form_contents "> </ div>.
src/main/resources/templates/users/edit.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{commons/layout}">
<head>
  <meta charset="UTF-8"/>
  <title></title>
</head>
<body>
<div layout:fragment="contents">
  <div class="row">
    <div class="col-sm-5">
      <div class="page-header">
        <div>
          <h1>User details</h1>
        </div>
        <form th:action="@{/users/{id}(id=*{id})}" th:method="put" th:object="${user}">
          <div th:include="users/form :: form_contents"></div>
          <button class="btn btn-primary btn-lg pull-right" type="submit">update</button>
        </form>
        <form th:action="@{/users/{id}(id=*{id})}" th:method="delete" th:object="${user}">
          <button class="btn btn-danger btn-lg" type="submit">Delete</button>
        </form>
      </div>
    </div>
  </div>
</div>
</body>
</html>
--Layout is used with layout: decorate =" ~ {commons / layout} ".
--The part enclosed by <div layout: fragment =" contents "> </ div> is displayed in the layout.
--The common form is displayed in <div th: include =" users / form :: form_contents "> </ div>.
src/main/resources/templates/users/new.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{commons/layout}">
<head>
  <meta charset="UTF-8"/>
  <title></title>
</head>
<body>
<div layout:fragment="contents">
  <div class="row">
    <div class="col-sm-5">
      <div class="page-header">
        <div>
          <h1>Create new user</h1>
        </div>
        <form method="post" th:action="@{/users}" th:object="${user}">
          <div th:include="users/form :: form_contents"></div>
          <button class="btn btn-primary btn-lg pull-right" type="submit" name="update">Create</button>
        </form>
      </div>
    </div>
  </div>
</div>
</body>
</html>
--The common form is inside <div th: fragment =" form_contents "> </ div> and can be embedded with <div th: include =" users / form :: form_contents "> </ div>.
src/main/resources/templates/users/form.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8"/>
  <title></title>
</head>
<body>
<div th:fragment="form_contents">
  <table class="table table-bordered table-hover">
    <tr>
      <th class="active col-sm-3">username</th>
      <td>
        <div class="form-group" th:classappend="${#fields.hasErrors('name')} ? 'has-error'">
          <label>
            <input type="text" class="form-control" th:field="*{name}"/>
          </label>
          <span class="text-danger" th:if="${#fields.hasErrors('name')}"
                th:errors="*{name}">Name error</span>
        </div>
      </td>
    </tr>
  </table>
</div>
</body>
</html>
css
src/main/resources/static/css/home.css
body {
    padding-top: 50px;
}
.sidebar {
    position: fixed;
    display: block;
    top: 50px;
    bottom: 0;
    background-color: #F4F5F7;
}
.main {
    padding-top: 50px;
    padding-left: 20px;
    position: fixed;
    display: block;
    top: 0;
    bottom: 0;
}
.page-header {
    margin-top: 0;
}
--When you open http: // localhost: 8080 / users, the following list screen will be displayed. --List screen


--Not input error display

--Reference -[Spring Dismantling New Book](https://www.amazon.co.jp/%E3%80%90%E5%BE%8C%E6%82%94%E3%81%97%E3%81%AA% E3% 81% 84% E3% 81% 9F% E3% 82% 81% E3% 81% AE% E5% 85% A5% E9% 96% 80% E6% 9B% B8% E3% 80% 91Spring% E8% A7% A3% E4% BD% 93% E6% 96% B0% E6% 9B% B8-Boot2% E3% 81% A7% E5% AE% 9F% E9% 9A% 9B% E3% 81% AB% E4% BD% 9C% E3% 81% A3% E3% 81% A6% E5% AD% A6% E3% 81% B9% E3% 82% 8B% EF% BC% 81Spring-Security% E3% 80% 81Spring-JDBC% E3% 80% 81Spring-MyBatis% E3% 81% AA% E3% 81% A9% E5% A4% 9A% E6% 95% B0% E8% A7% A3% E8% AA% AC% EF% BC% 81- ebook / dp / B07H6XLXD7) -Create a simple CRUD with SpringBoot + JPA + Thymeleaf ② ~ Creating screens and functions ~
Recommended Posts