Inquiry application creation with Spring Boot

This time as well, I created an app with Spring Boot for studying. We plan to add functions at any time.

2020/06/06: Addition of deletion function

usage environment

・ Windows10 (64bit) ・ Spring-boot: 2.2.6 -Eclipse: 4.9.0 ・ H2 ・ Bootstrap

Completion drawing

It is a simple inquiry application.

image.png

Entity

Inquiry.java


import java.time.LocalDateTime;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.springframework.format.annotation.DateTimeFormat;

@Entity
public class Inquiry {

	@Id
	@GeneratedValue
	private int id;

	private String name;
	private String email;
	private String contents;

	@DateTimeFormat(pattern="yyyy-MM-dd")
	private LocalDateTime created;

	public Inquiry() {
	}

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

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getContents() {
		return contents;
	}

	public void setContents(String contents) {
		this.contents = contents;
	}

	public LocalDateTime getCreated() {
		return created;
	}

	public void setCreated(LocalDateTime created) {
		this.created = created;
	}
}

Repository

InquiryDao.java


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

@Repository
public interface InquiryDao extends JpaRepository<Inquiry, Integer> {

}

Service

InquiryService.java


import java.util.List;

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

@Service
public class InquiryService {

	@Autowired
	InquiryDao inquiryDao;

	//Save process
	public Inquiry save(Inquiry inquiry) {

		return inquiryDao.saveAndFlush(inquiry);
	}

	//Search process
	public List<Inquiry> find() {

		return inquiryDao.findAll();
	}

	//Delete process
	public void delete(int id) {

		inquiryDao.deleteById(id);
	}
}

Form Prepare a Form class to hold the entered value. The validation check is also set here.

InquiryForm.java


import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;

public class InquiryForm {

	@Size(min=1, max=20, message="Name input check error")
	private String name;

	@NotEmpty(message="Not entered")
	private String email;

	@NotEmpty(message="Not entered")
	private String contents;

	public  InquiryForm() {}

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getContents() {
		return contents;
	}
	public void setContents(String contents) {
		this.contents = contents;
	}
}

Controller

InquiryController.java


import java.time.LocalDateTime;
import java.util.List;

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.validation.annotation.Validated;
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.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@Controller
@RequestMapping("/inquiry")
public class InquiryController {

	@Autowired
	InquiryService inquiryService;

	//List screen processing
	@GetMapping()
	public String index(Model model) {

		//All search processing
		List<Inquiry> list = inquiryService.find();
		model.addAttribute("list", list);
		model.addAttribute("title", "List screen");
		return "index_boot";
	}

	//Inquiry input processing
	@GetMapping("form")
	public String form(@ModelAttribute("inquiryForm") InquiryForm inquiryForm, Model model, @ModelAttribute("complete") String complete) {

		model.addAttribute("title", "Inquiry form");
		return "form_boot";
	}

	//Processing that flew by pressing the "Back" button from the confirmation page
	@PostMapping("form")
	public String formGoBack(@ModelAttribute("inquiryForm") InquiryForm inquiryForm, Model model) {

		model.addAttribute("title", "Inquiry form");
		return "form_boot";
	}

	/*Processing when you type in the input contents and press the "confirmation page"
	 * @Perform input check of form class with Validated,
	 *Store the check result in BindingResult
	*/
	@PostMapping("confirm")
	public String confirm(@ModelAttribute("inquiryForm") @Validated InquiryForm inquiryForm, BindingResult res, Model model) {

		//If the result of BindingResult is an error, an error message is output.
		if(res.hasErrors()) {
			model.addAttribute("title", "Inquiry form");
			return "form_boot";
		}
		model.addAttribute("title", "Confirmation page");
		return "confirm_boot";
	}

	//Processing when the "Save" button is pressed
	@PostMapping("complete")
	public String complete(@ModelAttribute("inquiryForm") @Validated InquiryForm inquiryForm, BindingResult res, Model model, RedirectAttributes redirectAttributes) {

		if(res.hasErrors()) {
			return "form_boot";
		}

		//Repacking Inquiry from the Inquiry Form container
		Inquiry inquiry = new Inquiry();
		inquiry.setName(inquiryForm.getName());
		inquiry.setEmail(inquiryForm.getEmail());
		inquiry.setContents(inquiryForm.getContents());
		inquiry.setCreated(LocalDateTime.now());

		//Save process
		inquiryService.save(inquiry);

		redirectAttributes.addFlashAttribute("complete", "Save completed");
		return "redirect:/inquiry/form";
	}

	//Delete process
	@GetMapping("delete")
	public String delete(Model model) {

		List<Inquiry> deleteList = inquiryService.find();
		model.addAttribute("title", "Delete page");
		model.addAttribute("list", deleteList);
		return "delete_boot";
	}

	//URL id@Receive with PathVariable and use as an argument
	@GetMapping("dell/{id}")
	public String deletes(@PathVariable("id") int id, Model model) {

		inquiryService.delete(id);
		return "redirect:/inquiry";
	}

}

index_boot.html

index_boot.html


<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
    <meta name="generator" content="Jekyll v4.0.1">
    <title th:text="${title}">Starter Template · Bootstrap</title>

    <link rel="canonical" href="https://getbootstrap.com/docs/4.5/examples/starter-template/">

    <!-- Bootstrap core CSS -->
<link href="/docs/4.5/dist/css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" rel="stylesheet" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">

    <!-- Favicons -->
<link rel="apple-touch-icon" href="/docs/4.5/assets/img/favicons/apple-touch-icon.png " sizes="180x180">
<link rel="icon" href="/docs/4.5/assets/img/favicons/favicon-32x32.png " sizes="32x32" type="image/png">
<link rel="icon" href="/docs/4.5/assets/img/favicons/favicon-16x16.png " sizes="16x16" type="image/png">
<link rel="manifest" href="/docs/4.5/assets/img/favicons/manifest.json">
<link rel="mask-icon" href="/docs/4.5/assets/img/favicons/safari-pinned-tab.svg" color="#563d7c">
<link rel="icon" href="/docs/4.5/assets/img/favicons/favicon.ico">
<meta name="msapplication-config" content="/docs/4.5/assets/img/favicons/browserconfig.xml">
<meta name="theme-color" content="#563d7c">


    <style>
      .bd-placeholder-img {
        font-size: 1.125rem;
        text-anchor: middle;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
      }

      @media (min-width: 768px) {
        .bd-placeholder-img-lg {
          font-size: 3.5rem;
        }
      }
    </style>
    <!-- Custom styles for this template -->
    <link href="starter-template.css" rel="stylesheet" th:href="@{/css/starter-template.css}">
  </head>
  <body>
    <div th:replace="~{header::headerA}"></div>

<main role="main" class="container">

  <div class="starter-template">
    <h1 th:text="${title}"></h1>
    <p class="lead">The inquiry list screen will be displayed.</p>
  </div>
<!--List items in the table-->
<table class="table table-striped">
  <thead>
    <tr>
      <th scope="col">id</th>
      <th scope="col">Full name</th>
      <th scope="col">Email</th>
      <th scope="col">Contents</th>
      <th scope="col">date</th>
    </tr>
  </thead>
  <tbody>
  <!--th:Output the value repeatedly with each-->
    <tr th:each="list:${list}">
      <th scope="row" th:text="${list.id}">1</th>
	  <td th:text="${list.name}">
	  <td th:text="${list.email}">
	  <td th:text="${list.contents}">
      <td th:text="${list.created}">
    </tr>
  </tbody>
</table>
</main><!-- /.container -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
      <script>window.jQuery || document.write('<script src="/docs/4.5/assets/js/vendor/jquery.slim.min.js"><\/script>')</script><script src="/docs/4.5/dist/js/bootstrap.bundle.min.js" th:src="@{/js/bootstrap.bundle.min.js}" integrity="sha384-1CmrxMRARb6aLqgBO7yyAxTOQE2AKb9GfXnEo760AUcUmFx3ibVJJAzGytlQcNXd" crossorigin="anonymous"></script></body>
</html>

form_boot.html

form_boot.html


<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="../../../../favicon.ico">

    <title>Starter Template for Bootstrap</title>

    <!-- Bootstrap core CSS -->
    <link href="/css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="starter-template.css"  th:href="@{/css/starter-template.css}" rel="stylesheet">
  </head>

  <body>


	<div th:replace="~{header::headerA}"></div>
    <main role="main" class="container">

      <div class="starter-template">
        <h1 th:text="${title}">Bootstrap starter template</h1>
        <p class="lead">You can enter your inquiry here</p>
      </div>


	<div th:unless="${#strings.isEmpty(complete)}" >
		<div th:text="${complete}" class="alert alert-success" role="alert">
		  A simple success alert?check it out!
		</div>
	</div>
	<!--To retain the value entered on this input screen when the "Back" button is pressed
			th:Use value-->
	<!--th:If the result of if is true, th:errors apply(The validation set for each item is output)  -->
	<form method="post" action="#" th:action="@{/inquiry/confirm}" th:object="${inquiryForm}">
	  <div class="form-group">
	    <label for="name">Name</label>
	    <input type="text" name="name" class="form-control" id="name" th:value="*{name}">
	  </div>
	  <div class="text-danger mb-4" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
	  <div class="form-group">
	    <label for="email">Email</label>
	    <input type="text" name="email" class="form-control" id="email"  th:value="*{email}">
	  </div>
	  <div class="text-danger mb-4" th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></div>
	  <div class="form-group">
	    <label for="contents">Inquiry</label>
	    <textarea  name="contents" class="form-control" id="detail" rows="3" th:field="*{contents}"></textarea>
	  </div>
	  <div class="text-danger mb-4" th:if="${#fields.hasErrors('contents')}" th:errors="*{contents}"></div>
	  <button type="submit" class="btn btn-primary">Verification</button>
	</form>
    </main><!-- /.container -->

    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script>window.jQuery || document.write('<script src="@{/js/jquery-slim.min.js}"><\/script>')</script>
    <script src="../../assets/js/vendor/popper.min.js"  th:src="@{/js/popper.min.js}"></script>
    <script src="../../dist/js/bootstrap.min.js"  th:src="@{/js/bootstrap.min.js}"></script>
  </body>

confirm_boot.html

confirm_boot.html


<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="../../../../favicon.ico">

    <title>Starter Template for Bootstrap</title>

    <!-- Bootstrap core CSS -->
    <link href="/css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="starter-template.css"  th:href="@{/css/starter-template.css}" rel="stylesheet">
  </head>

  <body>

	<div th:replace="~{header::headerA}"></div>
    <main role="main" class="container">

      <div class="starter-template">
        <h1 th:text="${title}">Bootstrap starter template</h1>
        <p class="lead">You can check the input contents on this screen.</p>
      </div>

<!--Extract each value packed in the inquiryForm-->
<div th:object="${inquiryForm}">
<div class="mb-5">
<ul class="list-group">
  <li th:text="*{name}" class="list-group-item"></li>
  <li th:text="*{email}" class="list-group-item"></li>
  <li th:text="*{contents}"class="list-group-item"></li>
</ul>
</div>
<!--With hidden, you can send a value by pressing a button-->
<form method="post" th:action="@{/inquiry/form}">
	<input type="hidden" name="name" th:value="*{name}">
	<input type="hidden" name="email" th:value="*{email}">
	<input type="hidden" name="contents" th:value="*{contents}">
	<button type="submit" class="btn btn-primary">Return</button>
</form>
<form method="post" th:action="@{/inquiry/complete}" th:object="${inquiryForm}">
	<input type="hidden" name="name" th:value="*{name}">
	<input type="hidden" name="email" th:value="*{email}">
	<input type="hidden" name="contents" th:value="*{contents}">
	<button type="submit" class="btn btn-primary">Post</button>
</form>
</div>

    </main><!-- /.container -->

    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script>window.jQuery || document.write('<script src="@{/js/jquery-slim.min.js}"><\/script>')</script>
    <script src="../../assets/js/vendor/popper.min.js"  th:src="@{/js/popper.min.js}"></script>
    <script src="../../dist/js/bootstrap.min.js"  th:src="@{/js/bootstrap.min.js}"></script>
  </body>
</html>

delete_boot.html

html.delete_boot.html



<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="../../../../favicon.ico">

    <title>Starter Template for Bootstrap</title>

    <!-- Bootstrap core CSS -->
    <link href="/css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="starter-template.css"  th:href="@{/css/starter-template.css}" rel="stylesheet">
  </head>

  <body>


	<div th:replace="~{header::headerA}"></div>
    <main role="main" class="container">

      <div class="starter-template">
        <h1 th:text="${title}">Bootstrap starter template</h1>
        <p class="lead">Select the item you want to delete</p>
      </div>


	<div th:unless="${#strings.isEmpty(complete)}" >
		<div th:text="${complete}" class="alert alert-success" role="alert">
		  A simple success alert?check it out!
		</div>
	</div>
	<table class="table table-striped">
	  <thead>
	    <tr>
	      <th scope="col">id</th>
	      <th scope="col">Full name</th>
	      <th scope="col">Email</th>
	      <th scope="col">Contents</th>
	      <th scope="col">date</th>
	      <th scope="col">Delete</th>
	    </tr>
	  </thead>
	  <tbody>
	  <!--th:Output the value repeatedly with each-->
	    <tr th:each="list:${list}">
	      <th scope="row" th:text="${list.id}"></th>
		  <td th:text="${list.name}">
		  <td th:text="${list.email}">
		  <td th:text="${list.contents}">
	      <td th:text="${list.created}">
	      <td><a th:href="@{/inquiry/dell/{id}(id=${list.id})}">Delete</a>
	    </tr>
	  </tbody>
	</table>
    </main><!-- /.container -->

    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script>window.jQuery || document.write('<script src="@{/js/jquery-slim.min.js}"><\/script>')</script>
    <script src="../../assets/js/vendor/popper.min.js"  th:src="@{/js/popper.min.js}"></script>
    <script src="../../dist/js/bootstrap.min.js"  th:src="@{/js/bootstrap.min.js}"></script>
  </body>

Processing pattern

Click "Inquiry Form" in the header to move to the form screen. Enter your name, email, and content, and click the "Confirm" button. The screen will change to the confirmation screen, but click the "Back" button to return to the previous screen. Change the contents, etc., and click the "Confirm" button again. Click the "Post" button on the confirmation screen to save the content.

image.png

image.png

image.png

image.png

image.png

Delete pattern

Click the "Delete" button of Natto. Then you can see that it has been deleted. image.png

image.png

reference

Introduction to Spring

Recommended Posts

Inquiry application creation with Spring Boot
[Spring Boot] Web application creation
Processing at application startup with Spring Boot
Start web application development with Spring Boot
Launch Nginx + Spring Boot application with docker-compose
Run WEB application with Spring Boot + Thymeleaf
Spring Boot 2.3 Application Availability
Download with Spring Boot
Configure Spring Boot application with maven multi module
Spring Boot2 Web application development with Visual Studio Code Hello World creation
Generate barcode with Spring Boot
Hello World with Spring Boot
Implement GraphQL with Spring Boot
Get started with Spring boot
Run LIFF with Spring Boot
SNS login with Spring Boot
File upload with Spring Boot
Spring Boot starting with copy
CICS-Run Java application-(4) Spring Boot application
Spring Boot starting with Docker
Hello World with Spring Boot
Set cookies with Spring Boot
Use Spring JDBC with Spring Boot
Add module with Spring Boot
Getting Started with Spring Boot
Create microservices with Spring Boot
Send email with spring boot
Try using OpenID Connect with Keycloak (Spring Boot application)
Spring Boot application development in Eclipse
Spring Boot application code review points
Create an app with Spring Boot 2
Database linkage with doma2 (Spring boot)
Implement REST API with Spring Boot and JPA (Application Layer)
Spring Boot programming with VS Code
Until "Hello World" with Spring Boot
Get validation results with Spring Boot
(Intellij) Hello World with Spring Boot
Create an app with Spring Boot
Google Cloud Platform with Spring Boot 2.0.0
Check date correlation with Spring Boot
Implement Spring Boot application in Gradle
I tried GraphQL with Spring Boot
[Java] LINE integration with Spring Boot
Web application creation with Nodejs with Docker
Spring Boot application that specifies DB connection settings with parameters
Beginning with Spring Boot 0. Use Spring CLI
I tried Flyway with Spring Boot
Message cooperation started with Spring Boot
Spring Boot gradle build with Docker
Let's make a book management web application with Spring Boot part3
Let's make a book management web application with Spring Boot part2
[Beginner] Let's write REST API of Todo application with Spring Boot
Hello World with Eclipse + Spring Boot + Maven
Send regular notifications with LineNotify + Spring Boot
Perform transaction confirmation test with Spring Boot
HTTPS with Spring Boot and Let's Encrypt
Try using Spring Boot with VS Code
I tried Lazy Initialization with Spring Boot 2.2.0
Implement CRUD with Spring Boot + Thymeleaf + MySQL
Asynchronous processing with Spring Boot using @Async
CI / CD Spring application with CircleCI (Heroku)