[JAVA] Spring Boot2 cheat sheet

Introduction

The author who uses Spring for business studied "[Introduction to Spring Boot2 Programming](https://www.amazon.co.jp/Spring-Boot-2-Introduction to Programming-Yano Palm Tatsu / dp / 4798053473)" It's like a cheat sheet or reading memo. The target audience is those who have learned the basics of Java and have no experience with Spring Boot-the level who have begun to study the basics. Language is Java, Build tool is Maven, The template engine is Thymeleaf.

What is Spring Boot?

A framework (group) created by combining the library provided by Spring Framework and Spring MVC (framework) for high-speed WEB application development.

1. 1. Spring development setup

Since this article is used as a cheat sheet, it is omitted here.

2. Super easy application development with Groovy

Groovy is a language that is suitable for prototyping in a short time before full-scale development in Java. Groovy is omitted here. @ RestController It is used to build a system that can be accessed from the outside to retrieve necessary information. Uses such as sending back necessary information in text or XML format when accessed. @ RequestMapping It means to execute this method when this address is accessed. Write as @RequestMapping ("/ ") and specify the path as an argument. When the specified path is accessed, the method with this annotation will be executed.

SampleController.java


@RestController
public class SampleController {

  @RequestMapping("/")
  public String index() {
    return "Hello SpringBoot World";
  }
}

Use Thymeleaf

A template engine that can be used by adding to HTML tags. feature is,

--Prepared a unique attribute of "th: ◯◯" in the tag --Write the variable name in the form of "$ {}" and embed the value in that place

home.html


<body>
  <h1>Hello!</h1>
  <p class="msg" th:text="${msg}">this is sample.</p>
</body>

It is possible to write HTML with Groovy as a template engine, but it is omitted here for convenience of use.

[@Controller is described in Chapter 3](# -controller) @ ResponseBody For the method with @ResponseBody, the return value becomes the content of the response as it is. For controller methods with @ RestController, the return value will be the content without adding @ResponseBody. Methods in controller classes with @Controller often return the ModelAndView class, except when you need to return JSON or XML, you can add @ResponseBody to the controller to add content. It can return itself.

3. 3. Basics of Spring Boot development with Java

How the Spring Boot application works

Spring Boot uses the built-in Java server to run the app, so no deployment is required. It works well with things that run programs inside a server, such as cloud services. Although it has the disadvantage of increasing the file size, it is becoming the de facto standard for Web development in Java.

Spring Starter Project pom.xml

The definition of parent is as follows

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.3.0.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>

The definition of dependencies is as follows

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>      
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
</dependencies>

The definitions of build and plugin are as follows

<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
  </plugins>
</build>

Use RestController

When you create a Spring Starter project with Spring Tool Suite (STS), a file called MyBootAppApplication.java is created by default. If @SpringBootApplication is attached, it will be a class that will be called when SpringBoot starts. SpringApplication.run the annotated class will launch the app. "Run" is a method for starting an application. For the argument, prepare the Class instance of the class to be executed and the data to be passed as a parameter.

MyBootAppApplication.java


@SpringBootApplication
public class MyBootAppApplication {

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

About MVC architecture

architecture role
Model Manage the data used by the application
View Handle screen display
Controller Control the entire process

Pass parameters

By using a path variable in the form of @RequestMapping ("/ {param} "), the value passed to the path part below the address can be received as a variable. [What is @RequestMapping](# -requestmapping)

Path variables and @ PathVariable

Indicates that the value is passed by a path variable.

@RequestMapping("/{num}")
public String index(@PathVariable int num){
  int res = 0;
  for(int i = 1; i<= num; i++){
    res += i;
  }
  return "total:" + res;
}

Output object in JSON

REST services can also return a class as a return value other than String. The returned instance is converted to JSON format.

//Define DataObject class separately
public DataObject index(@PathVariable int id) {
  return new DataObject();
}

Web page creation by Controller

When using a normal web page, add @Controller before the controller class. In this article, I want to use Thymeleaf as a template, so add the dependency to pom.xml as follows.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

@ Controller Used to render and display HTML pages using templates.

SampleController.java


@Controller
public class SampleController {
  @RequestMapping("/")
  public String home(){
    return "home";
  }
}

Use of Model class

Model is a class for managing data used in web pages. Data can be passed by setting the value used in the template in this Model. Set the value with ʻaddAttribute. Specify the name of the value in the first argument and the complementary value in the second argument. Following the sample below, the value of the variable msg can be retrieved in the form of $ {msg}on the template side. The return value cannot be used asModel` (because it doesn't have template information).

@RequestMapping("/{num}")
public String home(@PathVariable int num, Model model) {
  ...
  model.addAttribute("msg", "total:" + res);
  return "home";
}

Use of ModelAndView class

Manage the data used in the template and information about the view (template name, etc.). By returning this ModelAndView as a return value, the set template will be used. Set the object as ʻaddObject (String entitySetName, Object entity)and set the name of the view to use withsetViewName (String viewName)`.

@RequestMapping("/{num}")
public ModelAndView index(@PathVariable int num, ModelAndView mav) {
  ...
  mav.addObject("msg",  "total:" + res);
  mav.setViewName("home");
  return mav;
}

Use the form

Prepare a form with <form method =" POST "action =" / ">, and send it by POST with the same " / " destination. In the ʻinput type =" text "tag, the value of $ value is displayed in the input field liketh: text =" $ {value} ". If there are multiple arguments for @RequestMapping like @RequestMapping (value = "/", method = RequestMethod.POST) , omit the argument name like value = "/" for the mapping destination. Need to write without. The sample has the same address and distinguishes between GET and POSTfor methods. The value submitted from the form is processed by the send method.@RequestParam is an annotation to specify the value submitted to the form, which passes the value entered in the form's name = "text1" to this argument str`.

[Stove Torah side]

SampleController.java


@Controller
public class SampleController {
  @RequestMapping(value="/", method=RequestMethod.GET)
  public ModelAndView index(ModelAndView mav) {
    mav.setViewName("form");
    mav.addObject("msg", "please put and send your name.");
    return mav;
  }

  @RequestMapping(value="/", method=RequestMethod.POST)
  public ModelAndView send(@RequestParam("text1")String str, ModelAndView mav) {
    mav.addObject("msg", "Hello");
    mav.addObject("value", "message");
    mav.setViewName("form");
    return mav;
}

[Template side]

form.html



<body>
    <h1>Sample Form</h1>
    <p th:text ="${msg}">This replaces msg</p>
    <form method="POST" action="/">
        <input type="text" name="text1" th:value="${value}"/>
        <input type="submit" value="Click" />
    </form>
</body>

Other form control template examples

The value submitted from the form is received by the send method. The method has four arguments with @RequestParam so that it can receive the value from the form. Specify the name of the parameter with value, and specify the null constraint of the value with required. [Controller side]

SampleController.java


@Controller
public class SampleController {
    @RequestMapping(value="/", method=RequestMethod.GET)
    public ModelAndView index(ModelAndView mav) {
    //GET request omitted
    }
  
    @RequestMapping(value="/", method=RequestMethod.POST)
    public ModelAndView send(
        //Checkbox: The value can get the selected state as a boolean value
        @RequestParam(value="check1", required=false)boolean check1,
        //Radio button: Pass the value of the selected item as a String value, but null if not selected
        @RequestParam(value="radio1",required=false)String radio1,
        //Selection list: When a single item is selected, value is passed as a String value, but if multiple items can be selected, it is passed as a String array, and if it is not selected, it is null.
        @RequestParam(value="select1", required=false)String select1,
        @RequestParam(value="select2", required=false)String[] select2, 
        ModelAndView mav) {
      String res = "";
      //Processing omitted
      ...
      //Embed res in msg
      mav.addObject("msg", res);
      mav.setViewName("form");
      return mav;
    }
}

[Template side]

<body>
    <h1>Form Controll Example</h1>
    <form method="POST" action="/">
        <div>
        <input type="checkbox" id="check1" name="check1" />
        <label for="check1">Checkbox</label>
        </div>
        <div>
        <input type="radio" id="radioA" name="radio1" value="male" />
        <label for="radioA">male</label>
        </div>
        <div>
        <input type="radio" id="radioB" name="radio1" value="female" />
        <label for="radioB">Female</label>
        </div>
        <div>
        <select id="select1" name="select1" size="4">
            <option value="Red">Red</option>
            <option value="Blue">Blue</option>
            <option value="Yellow">yellow</option>
        </select>
        <select id="select2" name="select2" size="4" multiple="multiple">
            <option value="SmartPhone">smartphone</option>
            <option value="Tablet">Tablet</option>
            <option value="Laptop">Laptop</option>
        </select>
        </div>
        <input type="submit" value="Click" />
    </form>
</body>

redirect

When accessing one address, there are ** forward ** and ** redirect ** as a method of moving to another address as needed.

[Controller side]

SampleController.java


@Controller
public class SampleController {
    @RequestMapping("/")
    public ModelAndView index(ModelAndView mav) {
        mav.setViewName("home");
        return mav;
    }
    //"/other"Is the address itself"/"It is changed to, and the displayed contents are also"/"Become a thing.
    @RequestMapping("/other")
    public String other() {
        return "redirect:/";
    }
    //"/home"When you access, the displayed content remains the same"/"Show things.
    @RequestMapping("/home")
    public String home() {
        return "forward:/";
    }
}

[Template side]

home.html


<body>
  <h1>Home Page</h1>
</body>

4. Master the template engine

Thymeleaf various

Utility object

Frequently used classes can be used by directly describing them in constant expressions as constants "** # name **". Since it is a class constant, it can be used by directly calling class methods. Like "# dates. Class methods". The following example

Utility object constant
#strings String class constant
#numbers Number class constant
#Bools Boolean class constant
#dates Date class constant
#objects Object class constant
#arrays Array class constant
#lists List class constants
#sets Constants in the Set class
#maps Map class constants

Create a Date class object in the first argument using the format method of the Date class constant # dates, and specify the format yyyy / MM / dd HH: mm: ss in the second argument.

    <p th:text="${#dates.format(new java.util.Date(), 'dd/MMM/yyyy HH:mm')}"></p>

Using the formatInteger method of the constant # numbers of the Number class, the integer is displayed as the first argument and the digits of the second argument are displayed, separated by commas by the third argument.

    <p th:text="${#numbers.formatInteger(10000000, 3, 'COMMA')}"></p>

The toUpperCase of the String class constant # strings is a method that converts the argument text to all uppercase.

    <p th:text="${#strings.toUpperCase('show uppercase')}"></p>

Access to parameters

By writing like {param.id}, you can receive the value sent in the form of "id = ○○" and use the parameters directly in the template without going through the controller. However, since the obtained value is an array, the value is taken out and used.

<!--/?id=hoge&name=Pass like fuga-->
<p th:text="'from parameter.. id=' + ${param.id[0] + ',name=' + param.name[0]}"></p>

Message expression

Extract the value from the property file and use it in the template. The description method is # {specify value}

message.properties


article.title=this is home page.
article.message=this message from properties.
<h1 th:text="#{article.title}"></h1>
<p th:text="#{article.message}"></p>

Linked and href

If you access /? Id = fuga, ** / hoge / fuga ** will be set for link.

<p><a href="home.html" th:href="@{/hoge/{id}(id=${param.id})}">link</a></p>

Variable expression to the selected object

Variable expressions can use objects as well as numbers and text. The way to do this is to specify an object and use * {value} to retrieve the value in the selected object.

  <table th:object="${object}">
    <tr><th>ID</th><td th:text="*{id}"></td></tr>
    <tr><th>NAME</th><td th:text="*{name}"></td></tr>
    <tr><th>MAIL</th><td th:text="*{value}"></td></tr>
  </table>

Literal replacement

By enclosing the text before and after it with "|", you can directly write the variable expression and concatenate the character strings.

<p th:text="|My name is *{name}. Mailaddress is *{value}.|"></p>

HTML code output

In Thymeleaf, when outputting text as a variable expression, all HTML tags are escaped for safety, so You can release the escape by using th: utext. However, if the value contains an HTML tag, it will work as it is, so if you create text based on the information sent by the user, you will be vulnerable to attacks such as XSS.

[Controller side]

@RequestMapping("/")
public ModelAndView index(ModelAndView mav) {
    mav.setViewName("home");
    mav.addObject("msg", "message 1<hr/>message 2<br/>message3");
    return mav;
} 

[Template side]

<p th:utext="${msg}">message.</p>

Syntax, inline layout

Conditional expression

Change the output contents according to the result of the boolean value prepared in advance.

[Controller side]

@RequestMapping("/{id}")
public ModelAndView index(@PathVariable int id,
		ModelAndView mav) {
	mav.setViewName("check");
	mav.addObject("id",id);
	mav.addObject("num",id % 2 == 0);
	mav.addObject("even","Even number!");
	mav.addObject("odd","Odd number...");
	return mav;
}

[Template side]

check.html


<p th:class="${num} ? 'even' : 'odd'"></p>

The value set is true (non-zero number," 0 ", In the case of (including text other than values such as "off" and "no"), this tag and the tags inside it are displayed.

Display this tag and internal tags if the value set is false (including text such as number zero," 0 "," off "," no ").

[Controller side]

@RequestMapping("/{id}")
public ModelAndView index(@PathVariable int id,
		ModelAndView mav) {
	mav.setViewName("check");
	mav.addObject("id",id);
	mav.addObject("num",id >= 0);
	mav.addObject("trueVal","POSITIVE!");
	mav.addObject("falseVal","negative...");
	return mav;
}

[Template side]

check.html


	<p th:if="${num}" th:text="${id} + ' is ' + ${trueVal}"></p>
	<p th:unless="${num}" th:text="${id} + ' is ' + ${falseVal}"></p>

Checks the value of the specified conditional expression, searches for the same value from the th: case inside it, and outputs only that tag. th: case =" * " is a wildcard that catches anything that doesn't meet any of the conditions.

[Controller side]

@RequestMapping("/{month}")
public ModelAndView index(@PathVariable int month,
		ModelAndView mav) {
	mav.setViewName("index");
	int m = Math.abs(month) % 12;
	m = m == 0 ? 12 : m;
	mav.addObject("month",m);
	mav.addObject("check",Math.floor(m / 3));
	return mav;
}

[Template side]

<div th:switch="${check}">
    <p th:case="0" th:text="|${month} - Winter|"></p>
    <p th:case="1" th:text="|${month} - Spring|"></p>
    <p th:case="2" th:text="|${month} - Summer|"></p>
    <p th:case="3" th:text="|${month} - Autumn|"></p>
    <p th:case="4" th:text="|${month} - Winter|"></p>
    <p th:case="*">...?</p>
</div>

In th: each, prepare an array or collection as a value, and describe it likevalue: $ {list}in the manner of an extended for statement. This will take the values from the list after the colon and assign them to the variable before the colon.

[Template side]

<table>
    <tr>
        <th>NAME</th>
        <th>MAIL</th>
        <th>TEL</th>
    </tr>
    <tr th:each="obj:${data}">
        <td th:text="${obj[0]}"></td>
        <td th:text="${obj[1]}"></td>
        <td th:text="${obj[2]}"></td>
    </tr>
</table>

Preprocessing

If you declare it in the form of __ $ {variable} __, it will be evaluated in advance and the variable expression will be executed.

[Controller side]

ArrayList<Pockemon> monsters = new ArrayList<>();
monsters.add(new Pockemon(0,"Hitokage","Fire"));
monsters.add(new Pockemon(1,"Fushigidane","Grass"));
monsters.add(new Pockemon(2,"Zenigame","Water"));
mav.addObject("num", 1);
mav.addObject("monsters",monsters);
return mav

[Template side]

<div th:object="${monsters.get(${num})}">
    <p th:text="*{id}"></p>
</div>

In-line processing

Even if you do not prepare it in the form of an attribute like th: text (There is a side that does not affect the page display even if Thymeleaf is not functioning), Thymeleaf directly between HTML tags Variable expression can be written. If you write th: inline =" text " in the tag, you can write a variable expression like [[$ {variable}]] inside it to enable inline processing.

[Controller side]

ArrayList<Pockemon> monsters = new ArrayList<>();
monsters.add(new Pockemon(0,"Hitokage","Fire"));
monsters.add(new Pockemon(1,"Fushigidane","Grass"));
monsters.add(new Pockemon(2,"Zenigame","Water"));
mav.addObject("monsters",monsters);
return mav

[Template side]

<tr th:inline="text" th:each="monster : ${monsters}">
    <td>[[${monster.id}]]</td>
    <td>[[${monster.name}]]</td>
    <td>[[${monster.type}]]</td>
</tr>

Inline processing with JavaScript

Specify the value <script th: inline =" javascript "> and ʻinline as "javascript" instead of "text" , and the variable expression is / * [[$ {variable expression}]] By writing] * / `in the comment-out form, it can be embedded in the script and used.

python


<script th:inline="javascript">
   console.log(/*[[$(variable)]]*/);   
</script>

Template fragment

A method called ** template fragment ** that combines multiple files to form a page. Insert the part described as a part in the file that can be cut and handled as a ** fragment ** in the specified location of another template.

[Templates that become parts]

part.html


<p th:fragment="frag_body">

[Incorporation side]

<p th:include="part::frag_body">

Other template engines

In Spring, JSP and Groovy can also be used as template engines, but they are omitted for convenience.

5. Model and database

In Java, DB is used by using JPA (Java Persistence API persistence API). DB access is also performed in Spring using SpringBootStarterDataJPA.

If you manage the project with Maven, add the following dependency to pom.xml and use it.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

When using JPA, the data part is defined as a class called ** entity **. A table is defined in the DB and data is stored there as records, but it can be considered that the entity stores each record as a Java object.

Below is a sample of the ** Entity ** class that serves as a model.

@Entity
@Table(name="mydata")
public class MyData {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	private long usrId;
	@Column(length = 50, nullable = false)
	private String usrName;
	@Column(length = 200, nullable = true)
	private String usrAddress;
	@Column(nullable = true)
	private Integer age;
	@Column(nullable = true)
	private String comment;

	public long getUsrId() { return usrId; }
    public void setUsrId(long usrId) { this.usrId = usrId; }
    
	public String getUsrName() { return usrName; }
    public void setUsrName(String usrName) { this.usrName = usrName; }
    
    public String getUsrAddress() { return usrAddress; }
    public void setUsrAddress(String usrAddress) { this.usrAddress = usrAddress; }
    
	public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    
	public String getComment() { return comment; }
	public void setComment(String comment) { this.comment = comment; }
}

@ Entity Annotation indicating that it is an entity class @ Table(name="mydata") Specifies the table assigned to this entity class. If name is omitted, the class name will be used as the table name. @ Id Specifying the primary key @ GeneratedValue(strategy = GenerationType.AUTO) Automatically generate a value for the primary key field. The generation method is specified in strategy, and in the sample, GenerationType.AUTO and the value of enumeration type are specified to be automatically assigned. @ Column Specify the column name assigned to the field. If name is omitted, the field name is used as it is as the column name.

@Column argument Description
name Specify column name
length Maximum length(Number of characters in String)Specify
nullable Specify whether to allow null

About the repository

Entity-> Class that allows the data stored in the table to be treated as an object in Java Prepared as repository-> interface, general-purpose DB access processing is automatically generated and implemented, so there is almost no need to write code.

Created by inheriting JpaRepository @ Repository Indicates that this class is a data access class.

@Repository
public interface MyDataRepository extends JpaRepository<MyData, Long> {

}

@ Autowired In the sample, @Autowired is used to inject the MyDataRepository instance into the field. If you put @Autowired in front of the instance variable, it will search for the corresponding class from the classes with @Component, new it, and plunge it into the field. Although it says @ Component, @ Controller, @ Repository, @ Service are used properly depending on the layer.

findAll method

All entities can be automatically retrieved by the method provided in JpaRepository, which is the inheritance source.

@Controller
public class SampleController {

  @Autowired
  MyDataRepository repository;

  @RequestMapping("/")
  public ModelAndView home(ModelAndView mav) {
    mav.setViewName("home");
    Iterable<MyData> list = repository.findAll();
    mav.addObject("data", list);
    return mav;
  }
}

Entity CRUD

「Create」「Read」「Update」「Delete」 @ ModelAttribute It is used to automatically prepare an instance of the entity class. Specify the instance name in the argument. In the index method at the time of GET access, a new instance is created and assigned to the argument of MyData (all values etc. are initial values) In the form method called by POST access, the value of the submitted form is automatically collected and passed to the MyData instance.

Save with SaveAndFlush

repository.saveAndFlush(mydata);

The prepared entity is specified in the argument of the saveAndFlush method provided in JpaRepository and is made persistent. @ Transactional The @Transactional annotation is for the transaction function, and by attaching it to the method, the DB access executed in the method will be executed in a batch. In the case of processing that rewrites data, transactions are important processing, such as preventing the DB from being accessed from the outside and causing problems with data integrity.

The argument readOnly = false literally indicates that it is" read only (non-rewritable) ". When readOnly = false is set, the transaction changes from a read-only transaction to a transaction that allows data update such as saving.

SampleController.java


@Controller
public class SampleController {
  @Autowired
  MyDataRepository repository;

  @RequestMapping(value = "/", method = RequestMethod.GET)
  public ModelAndView index(@ModelAttribute("formModel") MyData mydata,
      ModelAndView mav) {
    mav.setViewName("index");
    mav.addObject("msg", "this is sample content.");
    Iterable<MyData> list = repository.findAll();
    mav.addObject("datalist", list);
  }

  @RequestMapping(value = "/", method = RequestMethod.POST)
  @Transactional(readonly = false)
  public ModelAndView form(@ModelAttribute("formModel") MyData mydata,
      ModelAndView mav){
    repository.saveAndFlush(mydata);
    return new ModelAndView("redirect:/");        
  }
}
<body>
  <table>
  <form method="post" action="/" th:object="${formModel}">
    <tr>
      <td><label for="name>name</label></td>
      <td><input type="text" name="name" th:value="*{name}" /></td>
    </tr>
    <tr>
      <td><label for="name>age</label></td>
      <td><input type="text" name="age" th:value="*{age}" /></td>
    </tr>
    <tr>
      <td><label for="name>Email</label></td>
      <td><input type="text" name="mail" th:value="*{mail}" /></td>
    </tr>
    <tr>
      <td><label for="name>Note</label></td>
      <td><textarea name="memo" th:value="*{memo}" cols="20" rows="5"></textarea></td>
    </tr>
  </form>
  </table>
  <hr/>
  <table>
    <tr>
      <th>ID</th>
      <th>name</th>
    </tr>
    <tr th:each="obj : ${datalist}">
      <td>${obj.id}</td>
      <td>${obj.name}</td>
    </tr>
  <table>
</body>

@ PostConstruct Indicates that the method is called after the constructor creates an instance. The controller is instantiated only once at the beginning, and the instance is retained thereafter.

SampleComtroller.java


@PostConstruct
public void init(){
	MyData d1 = new MyData();
	d1.setName("tuyano");
	d1.setAge(123);
	d1.setMail("[email protected]");
	d1.setMemo("this is my data!");
	repository.saveAndFlush(d1);
	MyData d2 = new MyData();
	d2.setName("hanako");
	d2.setAge(15);
	d2.setMail("hanako@flower");
	d2.setMemo("my girl friend.");
	repository.saveAndFlush(d2);
	MyData d3 = new MyData();
	d3.setName("sachiko");
	d3.setAge(37);
	d3.setMail("sachico@happy");
	d3.setMemo("my work friend...");
	repository.saveAndFlush(d3);
}

Data update

【template】 Th: object =" $ {formModel} " is specified in <form>, but if the entity to be edited is set in this formModel, it is done bytype = "hidden". The ID is stored in the hidden field.

<body>
	<h1 th:text="${title}">Edit page</h1>
	<table>
	<form method="post" action="/edit" th:object="${formModel}">
		<input type="hidden" name="id" th:value="*{id}" />
		<tr><td><label for="name">name</label></td>
			<td><input type="text" name="name" th:value="*{name}" /></td></tr>
		<tr><td><label for="age">age</label></td>
			<td><input type="text" name="age"  th:value="*{age}" /></td></tr>
		<tr><td><label for="mail">Email</label></td>
			<td><input type="text" name="mail"  th:value="*{mail}" /></td></tr>
		<tr><td><label for="memo">Note</label></td>
			<td><textarea name="memo"  th:text="*{memo}" 
			cols="20" rows="5"></textarea></td></tr>
		<tr><td></td><td><input type="submit" /></td></tr>
	</form>
	</table>
</body>

Implement the process of searching and retrieving entities by ID in the repository. findById is a method to retrieve a MyData instance with an ID number as an argument.

MyDataRepository.java


@Repository
public interface MyDataRepository extends JpaRepository<MyData, Long> {
    public MyData findById(Long name):
}

In the edit method called at the time of GET access, the entity is acquired by findById with the ID sent in the query as an argument, and the get is used to specify the name formModel and ʻaddObject. .. The update method is called when the form is submitted to / edit. When saving an entity based on the sent form data, update it with the same saveAndFlush` as when saving new data. The difference between new save and update is whether the ID is specified for the argument entity.

SampleController.java


@RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
public ModelAndView edit(@ModelAttribute MyData mydata, @PathVariable int id, ModelAndView mav) {
	mav.setViewName("edit");
	mav.addObject("title","edit mydata.");
	MyData data = repository.findById((long)id);
	mav.addObject("formModel",data.get());
	return mav;
}
@RequestMapping(value = "/edit", method = RequestMethod.POST)
@Transactional(readOnly=false)
public ModelAndView update(@ModelAttribute MyData mydata, ModelAndView mav) {
	repository.saveAndFlush(mydata);
	return new ModelAndView("redirect:/");
}

Delete entity

There is a delete method for GET access to / delete and a remove method for handling POST access. In the delete method, the entity with the specified ID is searched by findById and displayed. After that, the entity sent by the remove method sent by POST is deleted. Don't forget to annotate the method with @Transactional because delete also involves changing the DB.

@RequestMapping(value = "/delete/{id}", method = RequestMethod.GET)
public ModelAndView delete(@PathVariable int id, ModelAndView mav) {
  mav.setViewName("delete");
  mav.addObject("title", "delete mydata.");
  MyData data = repository.findById((long)id);
  mav.addObject("formModel", data);
  return mav;
}
@RequestMapping(value = "/delete", method = RequestMethod.POST)
@Transactional(readOnly = false)
public ModelAndView remove(@RequestParam long id, ModelAndView mav){
  repository.delete(id);
  return new ModelAndView("redirect:/");
}

Automatic repository method generation

JpaRepository has a built-in automatic code generation function using a dictionary. JpaRepository generates and executes query text by JPQL.

findById(argument)
   ↓
"find" "by" "id"argument
   ↓
"select *from table where id=argument"Execution of the query

How to use JPQL

And It is used when searching for an element that matches both the values of two items. Prepare two arguments as the value of each item.

findByIdAndName
   ↓
from MyDataEntity where id = ?1 and name = ?2

Or It is used when searching for an element that matches either of the values of two items. Prepare two arguments as the value of each item.

findByIdOrName
    ↓
from MyDataEntity where id = ?1 or name = ?2

Between It is used when passing two arguments as values and searching for a value between them. Searches for elements within a certain range of specified items.

findByAgeBetween
   ↓
from MyDataEntity where age between ?1 and ?2

LessThan Search for numerical items that are smaller than the value specified in the argument.

findByAgeLessThan
   ↓
from MyDataEntity where age < ?1

GreaterThan Search for a numeric item that is larger than the value specified in the argument.

findByAgeGreaterThan
   ↓
from MyDataEntity where age > ?1

IsNull Searches for the value of the specified item to be null.

findCommentIsNull
   ↓
from MyDataEntity where comment is null

IsNotNull, NotNull Searches for the value of the specified item that is not null. Understand even Not Null

findByCommentNotNull,
findByCommentIsNotNull
   ↓
from MyDataEntity where comment not null

Like Perform a LIKE search of the text. Ambiguous search for a value from a specified item. You can use it with a wildcard attached to the value passed to the argument.

findByNameLike
   ↓
from MyDataEntity where name like ?1

NotLike Ambiguous search for things that do not include the search string. You can use it with a wildcard attached to the value passed to the argument.

findByNameNotLike
   ↓
from MyDataEntity where name not like ?1

OrderBy Specify the order. It is added after the normal search method name. You can specify ascending or descending order by adding ʻAsc or Desc` after the item name.

findByNameOrderByAgeAsc
   ↓
from MyDataEntity where name = ?1 order by age Asc

Not Searches for the specified item that is not equal to the value of the argument.

findByNameNot
   ↓
from MyDataEntity where name <> ?1

In Search if the value of the specified item matches any of the values provided in the argument collection

findByNameIn(Collection<String> name)
   ↓
from MyDataEntity where name in ?1

NotIn Finds the value of the specified item that does not match any of the values provided in the argument collection

findByNameNotIn(Collection<String> name)
   ↓
from MyDataEntity where name not in ?1

JpaRepository method implementation example

@Repository
public interface MyDataRepository  extends JpaRepository<MyData, Long> {

	// "%" + str + "%"You need to specify a wildcard like
	public List<MyData> findById(Long name);
	public List<MyData> findByNameLike(String name);
	public List<MyData> findByIdIsNotNullOrderByIdDesc();
	public List<MyData> findByAgeGreaterThan(Integer age);
	public List<MyData> findByAgeBetween(Integer age1, Integer age2);

}

** All simple searches are auto-generated methods. Only complicated search processing is defined and used in DAO **

Entity validation

By preparing validation in the model in advance, rules are set for each input item, and it is possible to check whether the input value is violated. @ Validated This will check the value of the entity for variation. By adding this, each value of the entity will be checked automatically.

@ BindingResult The result of the validation check is received by the next argument, BindingResult. The hasErrors method can be used to check if an error has occurred. If it is true, there is an error, and if it is false, there is no error. ..

if(!result.hasErrors()) {...}

Output error message

The variable expression is set in $ {# fields.detailedErrors ()} in th: each is an object that summarizes the results of validation check of each field of the entity in # fields, anddetailedErrors Themethod returns information about the error that occurred as a collective list. In th: each, the error objects are taken out from the list and set in the variable ʻerror`.

<li th:each="error : ${#fields.detailedErrors}" class="err" th:text="${error.message}">

ʻError has a property called message, which gives you the message of the error that occurred. It is output in the form of th: text =" $ {error.message} "`.

【template】

<form method="post" action="/" th:object="${formModel}">
	<ul>
		<li th:each="error : ${#fields.detailedErrors()}"
			class="err" th:text="${error.message}" />
	</ul>
	<tr><td><label for="name">name</label></td>
		<td><input type="text" name="name" 
			th:field="*{name}" /></td></tr>
	<tr><td><label for="age">age</label></td>
		<td><input type="text" name="age"
			th:field="*{age}" /></td></tr>
	<tr><td><label for="mail">Email</label></td>
		<td><input type="text" name="mail" 
				th:field="*{mail}" /></td></tr>
	<tr><td><label for="memo">Note</label></td>
		<td><textarea name="memo" th:field="*{memo}" 
			cols="20" rows="5" ></textarea></td></tr>
	<tr><td></td><td><input type="submit" /></td></tr>
</form>

【entity】

@Entity
@Table(name = "mydata")
public class MyData {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column
	@NotNull
	private long id;

	@Column(length = 50, nullable = false)
	@NotEmpty
	private String name;

	@Column(length = 200, nullable = true)
	@Email
	private String mail;

	@Column(nullable = true)
	@Min(0)
	@Max(200)
	private Integer age;

	@Column(nullable = true)
	private String memo;

	//…… Accessor omitted ……
}

【controller】 A sample that checks whether the input value violates the validation set in the entity and allows the value to be stored only when the rule is satisfied.

@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(
	@ModelAttribute("formModel") MyData mydata, 
		ModelAndView mav) {
	mav.setViewName("index");
	mav.addObject("msg","this is sample content.");
	mav.addObject("formModel",mydata);
	Iterable<MyData> list = repository.findAll();
	mav.addObject("datalist",list);
	return mav;
}

@RequestMapping(value = "/", method = RequestMethod.POST)
@Transactional(readOnly=false)
public ModelAndView form(
    @ModelAttribute("formModel") @Validated MyData mydata, 
    BindingResult result,
    ModelAndView mov) {

	ModelAndView res = null;
	if (!result.hasErrors()){
		repository.saveAndFlush(mydata);
		res = new ModelAndView("redirect:/");
	} else {
		mov.setViewName("index");
		mov.addObject("msg","sorry, error is occured...");
		Iterable<MyData> list = repository.findAll();
		mov.addObject("datalist",list);
		res = mov;
	}
	return res;
}

Show error in each input field

<input type="text" name="name" th:value="*{name}" th:errorclass="err" />

The object's name property is set to a value asth: value = "* {name}". An attribute called th: errorclass is provided to specify the class name to be applied when an error occurs. As a result, the processing is applied only when an error occurs.

<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}" th:errorclass="err">

hasErrors uses th: if to display a dug only when true, whether or not an error has occurred in the field specified in the argument.

The error message is displayed using the attribute th: errors, and in the sample,* {name}is specified.

【template】

<form method="post" action="/" th:object="${formModel}">
		<tr><td><label for="name">name</label></td>
			<td><input type="text" name="name"
				th:value="*{name}" th:errorclass="err" />
			<div th:if="${#fields.hasErrors('name')}" 
				th:errors="*{name}" th:errorclass="err">
				</div></td></tr>
		<tr><td><label for="age">age</label></td>
			<td><input type="text" name="age"
				th:value="*{age}" th:errorclass="err" />
			<div th:if="${#fields.hasErrors('age')}" 
				th:errors="*{age}" th:errorclass="err">
				</div></td></tr>
		<tr><td><label for="mail">Email</label></td>
			<td><input type="text" name="mail" 
				th:value="*{mail}" th:errorclass="err" />
			<div th:if="${#fields.hasErrors('mail')}" 
				th:errors="*{mail}" th:errorclass="err">
				</div></td></tr>
		<tr><td><label for="memo">Note</label></td>
			<td><textarea name="memo" th:text="*{memo}" 
				cols="20" rows="5" ></textarea></td></tr>
		<tr><td></td><td><input type="submit" /></td></tr>
	</form>

Annotation by javax.validation

Validation annotation Contents
@ Null Check that the value is null
@ NotNull Do not allow the value to be null
@ Min(int num) Specify the minimum value that can be entered in the item for entering a numerical value (integer)
@ Max(int num) Specify the maximum value that can be entered in the item for entering a numerical value (integer)
@ DecimalMin(String num) BigDecimal,BigInteger,Specifying the minimum value when setting a value with a String value int is also OK
@ DecimalMax(String num) BigDecimal,BigInteger,Specifying the maximum value when setting the value with the String value int is also OK
@ Degits(integer=5, fraction=10) Limitation on the number of digits in the integer part and the decimal part
@ Future Accept only future dates and times from the present
@ Past Accept only past roads from the present
@ Size(min=1, max=10) Specify the number of stored elements of objects such as arrays and collection classes in addition to String
@ Pattern(regexp="[a-zA-Z]+") Check the input by specifying the regular expression pattern

Annotation by HiberinateValidator

Validation annotation Contents
@ NotEmpty Null and empty string are not allowed
@ Length(min=5, max=10) Annotation that specifies the range of string lengths used for Stringt
@ Range Used in numeric items to specify the range of minimum and maximum values.@With Min@Max can be put together
@ Email Check if the value entered is an email address
@ CreditCardNumber It is used for items that are entered numerically as numerical values or String values to check whether the credit card number format is used.
@ EAN Bar code identification number standard

About error messages

How to customize the error message displayed in English Specify the display message using the value message when preparing annotations for validation in the entity class

@NotEmpty(message="No white space")

@Email(message="Email address only")

@Min(value=0, message="Zero or above")
@Max(value=200, message="200 or less")

Use of property files

Since maintainability is poor in actual development, messages should be managed by preparing a property file. It can be handled by creating a text file with the name "ValidationMessages.properties" in the resource folder.

Create an original validator

For your own validator

Annotation class is Create an annotation type class that describes the name after @ interface The validator class is defined by implementing the javax.validation.ConstraintValidator interface. ConstraintValidator has two methods, ʻinitialize and ʻisValid, and implement these to describe the necessary processing.

Initialization method Annotation class specified by generic type is passed as an argument Get information about annotations as needed

The part to be validated The input value (String) and the ConstraintValidator instance are passed as arguments. Check the value here and return the boolean value depending on whether the validation is correct or not.

[Annotation class]

@Documented
@Constraint(validatedBy = PhoneValidator.class)
@Target({ ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@ReportAsSingleViolation
public @interface Phone {
  String message() default "Please input a phone number.";
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() dedault {};
}

[Validation class]

public class PhoneValidator implements ConstraintValidator<Phone, String> {

  @Override
  public void initialize(Phone phone){
  }

  @Override
  public boolean isValid(String input, ConstraintValidatorContext cxt){
    if(input == null){
      return false;
    }
    return input.matches("[0-9()-]*");
  }

}

6. Delve into database access

By preparing a repository, DB access is possible with almost no code writing, but there are limits, so consider how to use the DB access function provided by SpringDataJPA from within the Spring Boot application.

DataAccessObject When using DB, when you access the page to display the data, prepare the process to retrieve the data in the request handler of the controller and display it in the view. In other words, prepare the necessary DB access processing for each request handler of the controller.

If you write a process for each request, the controller will become bloated, so separate data access and logic. Therefore, prepare an object called DAO (Data Access Object) that provides a means to access the DB. Call these from the controller and perform the necessary processing.

ʻBy preparing a field for storing the EntityManager` class, it provides the functions required to use the entity.

Creating a query with createQuery

Query is an object that has a function equivalent to a single query sentence for querying data in SQL. The query by JPQL is the Query instance When createQuery of EntityManager is called by specifying a query sentence by JPQL as an argument, a Query instance for executing the query is generated. What is the sample from MyData? A JPQL query sentence equivalent to select * from mydata.

Query query = entityManager.createQuery("from MyData");

Get results from Query

By the getResultList method of the created Query, the execution result can be obtained as an instance in the query.

List<MyData> list = query.getResultList();

@ SuppressWarnings In the sample, the annotation attached to the list variable suppresses the compile-time warning. By using ʻunchecked` as an argument, it is checked whether the return value of the method is obtained as the value of the type of the storage destination variable. It has nothing to do with the behavior itself, ** to prevent warnings at build time **

@SuppressWarnings("unchecked")

[DAO interface]

public interface MyDataDao <T> extends Serializable {	
	public List<T> getAll();	
}

[DAO implementation class]

@Repository
public class MyDataDaoImpl implements MyDataDao<MyData> {
	private static final long serialVersionUID = 1L;
	
	private EntityManager entityManager;
	
	public MyDataDaoImpl(){
		super();
	}
	public MyDataDaoImpl(EntityManager manager){
		this();
		entityManager = manager;
	}
	
	@Override
	public List<MyData> getAll() {
		Query query = entityManager.createQuery("from MyData");
		@SuppressWarnings("unchecked")
		List<MyData> list = query.getResultList();
		entityManager.close();
		return list;
	}
	
}

Controller implementation

Create a controller that uses entities in DAO.

@ PersistenceContext @PersistenceContext gets the Bean of ʻEntityManager and sets it in the field. In Spring Boot, ʻEntityManager is automatically registered as a bean, so assign this to the controller field with @PersistenceContext. Bean binding using @PersistenceContext can only be placed up to" ** 1 instance per class ** "

@PersistenceContext
EntityManager entityManager;

The list is fetched from the entity via DAO and the list object is passed to the template side at the same time as setting the template name of the view. If you summarize the access process to the entity in DAO, you can easily call the access process on the controller side.

Iterable<MyData> list = dao.getAll();
mav.addObject("datalist", list);
public class SampleController {
  //Repository
  @Autowired
  MyDataRepository repository;

  //entity
  @PersistenceContext
  EntityManager entityManager;

  // DAO
  MyDataDaoImpl dao;

  @PostConstruct
  public void init() {
    dao = new MyDataDaoImpl(entityManager);
    MyData md = new MyData():
    md.setHoge("fuga");
    md.setNumber(123);
    repository.saveAndFlush(md);
  }

  @RequestMapping(value = "/", method = RequestMethod.GET)
  public ModelAndView index() {
    mav.setViewName("index");
    mav.addObject("msg", "This is a sample of MyData.");
    Iterable<MyData> list = dao.getAll();
    mav.addObject("datalist", list);
    return mav;
  }
}

Add search method to DAO

[DAO interface]

public interface MyDataDao<T> extends Serializable {
	
    public List<T> getAll();
    //Finds and returns an entity with an ID as an argument
    public T findById(long id);
    //Find and return an entity by name
    public List<T> findByName(String name);
}

[DAO implementation class]

" from MyData where id = "-> JPQL query (get entity with id as argument) getSingleResult retrieves and returns only one entity obtained from Query For things like ** only one entity is searched ** (such as ID), it is better to return the obtained entity as it is rather than returning it as a List.

@Override
public MyData findById(long id) {
	return (MyData)entityManager.createQuery("from MyData where id = " 
		+ id).getSingleResult();
}

" from MyData where name = "-> JPQL query (get entity with name as argument) getResultList returns a List, so findByName has List <MyData> as the return type.

@SuppressWarnings("unchecked")
@Override
public List<MyData> findByName(String name) {
	return (List<MyData>)entityManager.createQuery("from MyData where name = " 
		+ name).getResultList();
}

Use JPQL

JPQL is a simple language that allows JPA to generate SQL queries and operate the DB by executing query statements similar to SQL queries.

HttpServletRequest

We have used @RequestParam as an argument when receiving and processing the submitted value, such as a method that receives a form with POST, but you can also use HttpServletRequest as an argument. Actually, the parameter of @RequestParam is the one that calls getParameter of HttpServletRequest and automatically performs the operation to receive the parameter and sets the result as an argument. HttpServletResponse can also be specified as an argument

@RequestMapping(value = "/find", method = RequestMethod.POST)
public ModelAndView search(HttpServletRequest request,
		ModelAndView mav) {
	mav.setViewName("find");
	String param = request.getParameter("fstr");
	if (param == ""){
		mav = new ModelAndView("redirect:/find");
	} else {
		mav.addObject("title","Find result");
		mav.addObject("msg","「" + param + "Search results");
		mav.addObject("value",param);
		List<MyData> list = dao.find(param);
		mav.addObject("datalist", list);
	}
	return mav;
}

Add find method to DAO (use named parameter)

What is written in the JPQL query statement in the form of : fstr of the query" " from MyData where id =: fstr " "is treated as a ** variable for parameters **. Subsequent setParameter of the Query instance sets the value of the second argument to the variable of the first argument and assigns the value to the previous : fstr to create a query.   [DAO interface]

public List<T> find(String fstr);

[DAO implementation class]

@Override
public List<MyData> find(String fstr){
	List<MyData> list = null;
	String qstr = "from MyData where id = :fstr";
	Query query = entityManager.createQuery(qstr)
		.setParameter("fstr", Long.parseLong(fstr));
	list = query.getResultList();
	return list;
}

You can embed any number of parameters in a query

You can set many parameters in one query by connecting setParameter (returning Query instance with parameters set) in a method chain.

String qstr = "from MyData where id = :fid or name like :fname or mail like :fmail";
Long fid = 0L;
Query query =
    entityManager.createQuery(qstr).setParameter("fid", fid)
			.setParameter("fname", "%" + fstr + "%")
			.setParameter("fmail", fstr + "@%");

Parameter for specifying the number by "?"

Some parameter variables to be embedded in the query are set by numbering. Set the parameter embedding by specifying a number after "**? **" like ? 1.

String qstr = "from MyData where id = ?1 or name like ?2 or mail like ?3";
Long fid = 0L;
    Query query = entityManager.createQuery(qstr).setParameter(1, fid)
		.setParameter(2, "%" + fstr + "%")
		.setParameter(3, fstr + "@%");

Query annotation

Named queries can be created using @NamedQuery. Prepend to the entity class declaration Name and set the query string

@Entity
@NamedQuery(
  name = "findWithName",
  query = "from MyData where name like :fname"
)
@Table(name = "mydata")
public class MyData {
  ...
}

Use @NamedQueries to combine multiple queries You can add @NamedQuery as many times as you like, separated by commas.

@NamedQueries (
    @NamedQuery(
        name="findWithName",
        query="from MyData where name like :fname"
    )
)

createNamedQuery gets a query with that name by specifying the name of the query annotation in the argument, and creates aQuery instance. Put the query in the entity class, detached from the DAO code by using a named query -> When dealing with multiple entities, it is easy to understand by putting queries with the same function in each with the same name

Query query = entityManager
    .createQuery("findWithName")
    .setParameter("fname", "%" + fstr + "%");

Repository and @ Query

Since it is nonsense to rewrite the entity every time the search function is expanded, I want to prepare a query on the side that actually executes DB access. Queries can be declared with @Query in the repository interface @Query will use the specified query when calling the method that describes the annotation.

@Repository
public interface MyDataRepository  extends JpaRepository<MyData, Long> {
	
	@Query("SELECT d FROM MyData d ORDER BY d.name")
	List<MyData> findAllOrderByName();
}

Try calling the repository to execute the query from the controller There is no internal difference because the place to prepare the query is DAO or repository

@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(ModelAndView mav) {
	mav.setViewName("index");
	mav.addObject("title","Find Page");
	mav.addObject("msg","This is a sample of MyData.");
	Iterable<MyData> list = repository.findAllOrderByName(); //dao.getAll();
	mav.addObject("datalist", list);
	return mav;
}

@ NamedQuery parameters

If you want to do a detailed search, you will need to include the value for the search condition in the query. In such a case, parameters can be prepared in the query text to be set in the query annotation.

@NamedQuery (
    name = "findByAge",
    query = "from MyData where age > :min and age < :max"
)

Prepare @NamedQuery in this way before the entity class and call it from DAO by passing the value to the parameter embedded in the query. Try to actually call findByAge from DAO To create a Query instance, use createNamedQuery as an argument and specify the name of the query. Then use setParameter to pass the value to the parameter of the query text prepared in @ NamedQuery. Then search for the entity with getResultList

public List<MyData> findByAge(int min, int max);
@suppresswarning
@Override
public List<MyData> findByAge(int min, int max) {
    return (List<MyData>) entityManager
        .createNamedQuery("findByAge")
        .setParameter("min", min)
        .setParameter("max", max)
        .getResultList();
}

Use @Query

When using @Query, the method of embedding a variable in the query text and specifying it with the method argument is the same. However, use @ Param to specify which variable is associated with which parameter Below is a sample when the findByAge added to @ NamedQuery is printed in the repository.   [Repository interface]

@Query("from MyData where age > :min and age < :max")
public List<MyData> findByAge(@Param("min") int min, @Param("max") int max);

Whether to have the query in the entity itself or to prepare it in the repository depends on the design of the application.

Search by Criteria API

There is also a function to access DB by method chain without using a language like JPQL-> Criteria API Criteria API uses a combination of three classes

class What you can do
CriteriaBuilder Manage query generation
CriteriaQuery Query execution
Root You can narrow down the entities from here by the root of the searched entity

① Acquisition of Criteria Builder Prepare an instance of CriteriaBuilder and call ʻEntityManager # getCriteriaBuilder`

CriteriaBuilder builder = entityManager.getCriteriaBuilder();

② Creation of Criteria Query Do not take a query statement as an argument Specify the class property of a specific entity as an argument to access it

CriteriaQuery <Entity> query = builder.createQuery(Entity.class);

③ Acquisition of Root Get Root with CriteriaQuery from method Specify the Class property of the entity to be searched in the argument

Root <Entity> root = query.from(Entity.class);

④ Execution of CriteriaQuery method Calling a method to narrow down entities with CriteriaQuery Call in the method chain as needed

query.select(root);

⑤ Create Query to get the result Finally, generate a Query with createQuery and get the result List with getResultList. Specifying QriteriaQuery as the argument of createQuery is different from the search process by normal Query.

List<Entity> list = (List<MyData>)entityManager
    .createQuery(query)
    .getResultList();
return list;

Below is a sample to get all entities by getAll method

Specify MyData.class as an argument of from method to get Root You can get a Root instance that holds all MyData as information After getting Root, to get all MyData, call with CriteriaQuery # select as an argument and specify MyData.class. After that, if you createQuery this CriteriaQuery and getResult, you can get all Mydata.

@Override
public List<MyData> getAll() {
	List<MyData> list = null;		
	CriteriaBuilder builder = 
			entityManager.getCriteriaBuilder();
	CriteriaQuery<MyData> query = 
			builder.createQuery(MyData.class);
	Root<MyData> root = query.from(MyData.class);
	query.select(root);
	list = (List<MyData>)entityManager
			.createQuery(query)
			.getResultList();
	return list;
}

Name search using Criteria API

Only the entities whose argument text and name value match are searched. After acquiring the Root instance, perform the process to narrow down the entities to be fetched.   After select (root), use the method chain to narrow down the entities using the where method with Expression (which handles the evaluation of various expressions) as an argument. Check if they are equal by Expression and Object specified in the argument to ʻequalmethod, and return the result as an instance ofPredicateclass. SincePredicate has the role of expressing the conditions and expressions specified in the method as objects, for example, in the case of ʻequal, Predicate indicating the conditions that are the same as those specified in the argument is prepared, and the entities that match the conditions are narrowed down.

// where(Expression<boolen>)
// equal(Expression, Object)
query.select(root)
		.where(builder.equal(root.get("name"), fstr));

CriteriaBuilder methods

Method Format Description
equal equal(Expression x, Expression y) Make a predicate to verify that the arguments are equal.
gt gt(Expression<? extends java.lang.Number> x, Expression<? extends java.lang.Number> y) Make a predicate to verify if the first argument is greater than the second argument.
greaterThan greaterThan(Expression<? extends Y> x, Expression<? extends Y> y) Make a predicate to verify if the first argument is greater than the second argument.
ge ge(Expression<? extends java.lang.Number> x, Expression<? extends java.lang.Number> y) Make a predicate to verify if the first argument is greater than or equal to the second argument.
greaterThanOrEqualTo greaterThanOrEqualTo(Expression<? extends Y> x, Expression<? extends Y> y) Make a predicate to verify if the first argument is greater than or equal to the second argument.
lt lt(Expression<? extends java.lang.Number> x, Expression<? extends java.lang.Number> y) Make a predicate to verify if the first argument is less than the second argument.
lessThan Predicate lessThan(Expression<? extends Y> x, Y y)
le le(Expression<? extends java.lang.Number> x, java.lang.Number y) Make a predicate to verify if the first argument is less than or equal to the second argument.
lessThanOrEqualTo lessThanOrEqualTo(Expression<? extends Y> x, Y y) Make a predicate to verify if the first argument is less than or equal to the second argument.
between between(Expression<? extends Y> v, Expression<? extends Y> x, Expression<? extends Y> y) Make a predicate to verify that the first argument is a value between the second and third arguments.
isNull isNull(Expression<?> x) Make a predicate to check if the expression is null.
isNotNull isNotNull(Expression<?> x) Make a predicate that checks if the expression is not null.
isEmpty isEmpty(Expression collection) Make a predicate to verify if the collection is empty.
isNotEmpty isNotEmpty(Expression collection) Make a predicate to verify that the collection is not empty.
like like(Expression<java.lang.String> x, Expression<java.lang.String> pattern) Create a predicate that verifies that the expression satisfies the given pattern.
and and(Expression<java.lang.Boolean> x, Expression<java.lang.Boolean> y) Creates the logical product of a given Boolean expression.
or or(Expression<java.lang.Boolean> x, Expression<java.lang.Boolean> y) Creates the OR of the given Boolean expressions.
not not(Expression<java.lang.Boolean> restriction) Make a denial of the given limitation.

Sorting entities by orderBy

The retrieved result uses the ʻorderBy method to get the entity as List The argument ʻExpression uses CriteriaBuilder # get to specify the Path that indicates the property of the entity. The argument of ʻorderBy` in the sample sets Predicate to sort the element of name in ascending order.

query.select(root).orderBy(builder.asc(root.get("name")));

Setting of acquisition position and number of acquisitions

The entity get method of Query is [getSingleResult](adds a search method to ### DAO) that returns only one entity and [getResultList](gets the result from ### Query) that returns all entities as List. is there When actually using the DB, you can also specify the position and number to get it.

Specify an integer value as an argument The acquisition position starts with 0 in the list.

 query.setFirstResult(int pos);

Specify the number to acquire Only the maximum number that can be obtained is set, so if there are not enough entities, only some will be retrieved.

@Override
public List<MyData> getAll() {
	int offset = 1; //Specifying the extraction position
	int limit = 2;  //Specify the number to be taken out
	List<MyData> list = null;
	CriteriaBuilder builder = 
			entityManager.getCriteriaBuilder();
	CriteriaQuery<MyData> query = 
			builder.createQuery(MyData.class);
	Root<MyData> root = 
			query.from(MyData.class);
	query.select(root);
	list = (List<MyData>)entityManager
			.createQuery(query)
			.setFirstResult(offset)
			.setMaxResults(limit)
			.getResultList();
	return list;
}

Entity integration

In a DB where multiple tables work in relation to each other, entities are linked and processed by a function called "association". -> Have another entity as a property of the class

@ OneToOne Indicates a one-to-one correspondence between two entities @ OneToMany Multiple of the other entity correspond to one entity @ ManyToOne For multiple entities, only one of the other entities corresponds @ ManyToMany Relationships in which multiple other entities correspond to multiple entities

The sample MsgData allows one member to post any number of messages, so Associated with MyData in @ManyToOne

[Associating entity]

@Entity
@Table(name = "msgdata")
@Getter
@Setter
public class MsgData {
  @Id
  @Column
  @NotNull
  private long id;

  @Column
  private String title;

  @Column(nullable = false)
  @NotEmpty
  private String message;

  @ManyToOne
  private MyData mydata;

  //Below, the constructor and accessor are omitted.
}

[Associated entity] Add msgdatas property to associate with MsgData

@Entity
@Table(name = "mydata")
@Getter
@Setter
public class MyData {
  @OneToMany(cascade = CascadeType.ALL)
  @Column(nullable = true)
  private List<MsgData> msgdatas;
}

In the repository save, when saving, if there is a field associated with another entity, it will get an instance based on the sent information and set it automatically. Therefore, it is not necessary for the programmer to implement the registration process of related records in consideration of the linkage of entities.

repository.saveAndFlush(msgdata);
  • Annotate the model properly
  • Prepare the item of the entity correctly associated with the form

7. Make more use of Spring Boot

What is a service?

In business logic, the part that is componentized so that it can be accessed from the application is generally called "** service layer **", and unlike DAO that uses a controller or model, it is a class that can be called and used from anywhere.

What can be freely called from both the controller and business logic (model) is ** service **

Spring Framework can be used at any time simply by registering this service as a bean and writing annotations.

○ Application layer
·controller
Request handler
·model
Business logic
entity
○ Domain layer
·service
・ Repository

@ Service Annotation for registering this class as a service, and the service class puts this annotation before the class name.

@ PersisitenceContext It is for automatically assigning the Bean of ʻEntityManager, and it is also possible to prepare and use ʻEntityManager in the service instead of on the controller class side.

@Service
public class MyDataService {

	@PersistenceContext
	private EntityManager entityManager;

	@SuppressWarnings("unchecked")
	public List<MyData> getAll() {
		return (List<MyData>) entityManager
			.createQuery("from MyData").getResultList();
	}

	public MyData get(int num) {
		return (MyData)entityManager
				.createQuery("from MyData where id = " + num)
				.getSingleResult();
	}

	public List<MyData> find(String fstr) {
		CriteriaBuilder builder = entityManager.getCriteriaBuilder();
		CriteriaQuery<MyData> query = builder.createQuery(MyData.class);
		Root<MyData> root = query.from(MyData.class);
		query.select(root).where(builder.equal(root.get("name"), fstr));
		List<MyData> list = null;
		list = (List<MyData>) entityManager.createQuery(query).getResultList();
		return list;
	}

}

Use the service bean in the controller

DB access using service bean from DAO The created service is used as a bean by associating it with the controller with @Autowired.

The service class in which @Service is described is beanized in the application and it is assigned to the field by @ Autowired.

@Controller
public class SampleController  {

	@Autowired
	MyDataRepository repository;

        //Associate a service bean with a field
	@Autowired
	private MyDataService service;
	
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public ModelAndView index(ModelAndView mav) {
		mav.setViewName("index");
		mav.addObject("title","Find Page");
		mav.addObject("msg","This is a sample of MyData.");
                //Get all entities
		List<MyData> list = service.getAll(); 
		mav.addObject("datalist", list);
		return mav;
	}

        // "/find"GET request handler omitted

        @RequestMapping(value = "/find", method = RequestMethod.POST)
        public ModelAndView search(HttpServletRequest request,
            ModelAndView mav) {
        mav.setViewName("find");
        String param = request.getParameter("fstr");
        if(param == "") {
            mav = new ModelAndView("redirect:/find");
        } else {
            mav.addObject("title", "Find result");
            mav.addObject("msg", "「" + param + "Search results");
            mav.addObject("value", param);
            //Search for entities
            List<MyData> list = service.find(param);
            mav.addObject("datalist", list);
        }
        return mav;
    }
    
    //The constructor, accessor, etc. are omitted below.

}

Create a RestController

"** Service " in Web application development generally means " Web program that can be accessed from the outside and receive necessary information **". There are JSON format and XML format REST services as services that can be used from the outside.

@RestController
public class MyDataRestController {

	@Autowired
	private MyDataService service;

	@RequestMapping("/rest")
	public List<MyData> restAll() {
		return service.getAll();
	}

	@RequestMapping("/rest/{num}")
	public MyData restBy(@PathVariable int num) {
		return service.get(num);
	}
}

Get data in XML

When handling with XML in RestController, prepare a library "Jackson DataFormat XML" that analyzes and processes the data format.

@ XmlRootElement Indicates that it is the root element in XML data. Request handler restAll The only difference is that it returns an object with or restBy and is normally converted to JSON format, and with @XmlRootElement it is converted to XML format. If you are using Maven

pom.xml


<dependency>
	<groupId>com.fasterxml.jackson.dataformat</groupId>
	<artifactId>jackson-dataformat-xml</artifactId>
</dependency>

Components and beans

** Components ** are beans that are automatically generated in your application, and bean instances can be used by binding with @Autowired. A service is a type of component-> a component of the service layer is called a ** service **

@ Component Annotation makes the class to which it is attached recognized by the application as a component. Class instance is now registered as a bean

@ Autowired constructor

If @Autowired is attached to the constructor, the constructor with this @ Autowired will create the instance when the instance of that class is registered as a bean. If the constructor with @ Autowired is not prepared in the component class, an error will occur when the application is executed and the startup will fail, so be sure to prepare it.

The instance argument of MySampleBean (ApplicationArguments args) is an object that manages the argument passed when the application is executed, that is, when SpringApplication.run is executed in the class with @ SpringBootApplication specified. Prepare this instance as an argument when using the argument passed at runtime In the sample method, use ʻApplicationArgments # getNonOptionArgs to extract the application runtime argument as List`.

@Component
public class MySampleBean {

	private int max = 10;

	@Autowired
	public MySampleBean(ApplicationArguments args) {
		List<String> files = args.getNonOptionArgs();
		try {
			max = Integer.parseInt(files.get(0));
		} catch (NumberFormatException e) {
			e.printStackTrace();
		}
	}
        
        public int count() {
		counter++;
		counter = counter > max ? 0 : counter;
		return counter;
	}
}

Use of components

Add a request handler to the controller class to use the component If you associate it with a field with @ Autowired, it will be automatically bound, so you can execute bean.count in the request handler. Components can be freely used from anywhere by associating them with fields with @ Autowired. If there is a general-purpose function to be called from several request handlers, it is good to summarize it for the time being

@Autowired
MySampleBean bean;

@RequestMapping("/count")
public int count() {
	return bean.count();
}

Also, @ Controller is a component that acts as a controller, @ Repository is a type of component that has a special role for data access, and @ Component has such a special role. Can be attached to something that is not

Other features to remember

In Spring, you can bind a bean prepared as standard using annotations such as @Autowired, or create your own ** component ** or ** service ** and use it as a bean. Bean can be used in various places such as controller by using ** configuration class ** Actually, due to Spring Boot's idea of ** from configuration file to annotation **, the method of ** creating a configuration file ** is not recommended.

Creating a configuration class

If you add @Configuration even to a general class that does not inherit a special class, this class will be instantiated as a configuration class when the application is started, and the beans etc. described there will be registered in the application.

[Configuration class with beans registered in the field]

@Configuration
public class MyBootAppConfig {

	@Bean
	MyDataBean myDataBean(){
		return new MyDataBean();
	}
}

If you prepare a method that returns an instance of the class with @Bean in the configuration class, it will be registered as a bean.

[Original Bean class]

public class MyDataBean {
	
	@Autowired
	MyDataRepository repository;
	
	public String getTableTagById(Long id){
		Optional<MyData> opt = repository.findById(id);
		MyData data = opt.get();
		String result = "<tr><td>" + data.getName()
				+ "</td><td>" + data.getMail() + 
				"</td><td>" + data.getAge() + 
				"</td><td>" + data.getMemo() + 
				"</td></tr>";
		return result;
	}

}

With the bean ready in your application, @Autowired will automatically bind that instance.

[Controller associated with the field to use the bean]

@Autowired
MyDataBean myDataBean;

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ModelAndView indexById(@PathVariable long id,
		ModelAndView mav) {
	mav.setViewName("pickup");
	mav.addObject("title","Pickup Page");
	String table = "<table>"
			+ myDataBean.getTableTagById(id)
			+ "</table>";
	mav.addObject("msg","pickup data id = " + id);
	mav.addObject("data",table);
	return mav;
}

Pagination

Spring Framework provides ** Page ** class for page division, and by using this, pagination, which is a function to handle data for each page, can be realized.

By specifying parameters, you can specify the number of records on the page and the page number to be displayed (example of 2 data / page, which is the 0th page).

【how to access】

/page?size=2&page=0

The findAll method, which is a request handler, takes aPagable as an argument, fetches a Page instance, and passes it to the template with the name datalist.

[Controller with request handler that implements pagination]

@RequestMapping(value = "/page", method = RequestMethod.GET)
public ModelAndView index(ModelAndView mav, Pageable pageable) {
	mav.setViewName("index");
	mav.addObject("title","Find Page");
	mav.addObject("msg","This is a sample of MyData.");
	Page<MyData> list = repository.findAll(pageable); //●
	mav.addObject("datalist", list);
	return mav;
}

Since Page is a subclass of List, the entity passed to the template can be displayed in the table in the same way as List.

【template】

<table>
<tr><th>ID</th><th>name</th><th>Email</th><th>age</th><th>Note(tel)</th></tr>
<tr th:each="obj : ${datalist}">
	<td th:text="${obj.id}"></td>
	<td th:text="${obj.name}"></td>
	<td th:text="${obj.mail}"></td>
	<td th:text="${obj.age}"></td>
	<td th:text="${obj.memo}"></td>
</tr>
</table>

Pageable class methods

Method return
Pageable#getPageNumber() Current page number
Pageable#getPageSize() Number of records to display on the page
Pageable#first() First Pageable
Pageable#previousOrFirst() Previous or first Pageable
Pageable#next() Next Pageable

Thymeleaf original tag creation

If you take the entities separated by pagination, you need to move to the front and back of the page and prepare functions related to page display, so define it as a Java class using ** utility object ** You can call the internal method from within Thymeleaf to output the result. To use utility objects, prepare a ʻAttributeTagProcessor class that processes Thymeleaf attributes and aDialectclass to combine this class.   Whenth: text =" name "and Thymeleaf's unique attribute are described, the valuename` is received and processed as the processing of the attribute called text, so prepare the specific processing.

ʻThe constructor and doProcess are prepared in the class created by inheriting AbstractAttributeTagProcessor`. The arguments passed to this method are as follows

Argument type Description
ITemplatecontext Handle template context. Extract template information such as template engine and setting information from here.
IProcessableElementTag Information such as attributes embedded in tags can be retrieved in the class that handles element tags.
AttributeName Handles attribute names and prefixes (text that precedes values)
String Attribute value
IElementTagStructureHandler A class that handles structures such as incorporating attributes into elements

When Thymeleaf variable expression etc. is described in the value Process the variable expression using the function to evaluate the value ** resolver ** built in the template engine, and then obtain the resulting value. Since it is necessary to perform the actual attribute processing, the sample below is performed with doProcess.

[Inheritance class of AbstractAttributeTagProcessor]

public class MyPageAttributeTagProcessor extends AbstractAttributeTagProcessor {
	
	private static final String ATTR_NAME = "mypage";
	private static final int PRECEDENCE = 10000;
	public static int size = 2;

	public MyPageAttributeTagProcessor(final String dialectPrefix) {
		super(TemplateMode.HTML, dialectPrefix, null,
				false, ATTR_NAME, true, PRECEDENCE, true);
    }
	 
	protected MyPageAttributeTagProcessor(TemplateMode templateMode, 
			String dialectPrefix, String elementName,
			boolean prefixElementName, 
			String attributeName, 
			boolean prefixAttributeName, 
			int precedence,
			boolean removeAttribute) {
		super(templateMode, dialectPrefix, elementName, 
				prefixElementName, attributeName, prefixAttributeName, 
				precedence,removeAttribute);
	}

	@Override
	protected void doProcess(ITemplateContext context, 
			IProcessableElementTag tag, 
			AttributeName attrName, 
			String attrValue,
			IElementTagStructureHandler handler) {
		
		final IEngineConfiguration configuration = context.getConfiguration();
		final IStandardExpressionParser parser =
				StandardExpressions.getExpressionParser(configuration);
		final IStandardExpression expression = 
				parser.parseExpression(context, attrValue);
		int value = (int)expression.execute(context);
		value = value < 0 ? 0 : value;
		handler.setAttribute("href", "/page?size=" + size + "&page=" + value);
	}

}

ʻAbstractProcessorDialect has a method called getProcessors that gets a set that summarizes ʻIProcessor. ʻIProcessoris a class that processes Thymeleaf attributes, etc. The sample creates aSet instance, incorporates the ʻI Processor, and performs a return process.

[Summary as an attribute as a Dialect class]

public class MyDialect extends AbstractProcessorDialect {
	
	private static final String DIALECT_NAME = "My Dialect";
	
	public MyDialect() {
		super(DIALECT_NAME, "my", StandardDialect.PROCESSOR_PRECEDENCE);
	}
	protected MyDialect(String name, String prefix, 
			int processorPrecedence) {
		super(name, prefix, processorPrecedence);
	}

	@Override
	public Set<IProcessor> getProcessors(String dialectPrefix) {
		final Set<IProcessor> processors = new HashSet<IProcessor>();
		processors.add(new MyPageAttributeTagProcessor(dialectPrefix));
		return processors;
	}

}

Register and use Bean to use ʻAttributeTagProcessor and Dialect`

① Create template Engine

After creating the SpringTemplateEngine instance, set the template resolver with setTemplateResolver. This sets the template resolver created by templateResolver If you embed the instance of MyDialect created in the prepared template engine with ʻaddDialect and return` the template engine, it will be used for rendering.

② Create templateResolver

Create an instance of ClassLoaderTemplateResolver and set the prefix, set whether to enable caching, set the suffix, set the template mode, etc.

[Structure class]

@Configuration
public class MyBootAppConfig {

	...

    @Bean
	public ClassLoaderTemplateResolver templateResolver() {
		ClassLoaderTemplateResolver templateResolver = 
			new ClassLoaderTemplateResolver();
		templateResolver.setPrefix("templates/");
		templateResolver.setCacheable(false);
		templateResolver.setSuffix(".html");        
		templateResolver.setTemplateMode("HTML5");
		templateResolver.setCharacterEncoding("UTF-8");
		return templateResolver;
	}
 
	@Bean
	public SpringTemplateEngine templateEngine(){
		SpringTemplateEngine templateEngine = new SpringTemplateEngine();
		templateEngine.setTemplateResolver(templateResolver());
		templateEngine.addDialect(new MyDialect());
		return templateEngine;
	}
}

【template】

<div>
<a my:mypage="${datalist.getNumber() - 1}">&lt;&lt;prev</a>
|
<a my:mypage="${datalist.getNumber() + 1}">next&gt;&gt;</a>
</div>

Using MongoDB

The basic usage of NoSQL MongoDB is almost the same as SQL database because Mongo Repository is designed in the same way as Jpa Repository-> ** Write and call repository **

8. SpringToolSuite Reference

Omitted

reference

-[Introduction to SpringBoot2 Programming](https://www.amazon.co.jp/Spring-Boot-2-Introduction to Programming-Yano Palm Tatsu / dp / 4798053473)

Recommended Posts

Spring Boot2 cheat sheet
JMeter cheat sheet
Challenge Spring Boot
Spring Boot Form
Kotlin cheat sheet
Spring Boot Memorandum
gae + spring boot
[Docker cheat sheet]
Mockito + PowerMock cheat sheet
SPRING BOOT learning record 01
Spring Boot + Heroku Postgres
Spring boot memo writing (1)
Eclipse Collections cheat sheet
Rails Tutorial cheat sheet
First Spring Boot (DI)
SPRING BOOT learning record 02
Spring Boot exception handling
Spring Boot Servlet mapping
Spring boot development-development environment-
Spring Boot learning procedure
SCSS notation cheat sheet
Learning Spring Boot [Beginning]
Spring boot memo writing (2)
Spring Boot 2.2 Document Summary
[Spring Boot] DataSourceProperties $ DataSourceBeanCreationException
Spring Boot 2.3 Application Availability
Spring boot tutorials Topics
Oreshiki docker-compose cheat sheet
Docker command cheat sheet
Download with Spring Boot
[Spring Boot] Environment construction (macOS)
Try Spring Boot from 0 to 100.
Generate barcode with Spring Boot
Hello World with Spring Boot
Spring Boot on Microsoft Azure
Implement GraphQL with Spring Boot
Spring Boot tutorial task schedule
Spring 5 & Spring Boot 2 Hands-on preparation procedure
Get started with Spring boot
Spring Boot 2 multi-project in Gradle
[Spring Boot] Web application creation
spring boot port duplication problem
Run LIFF with Spring Boot
SNS login with Spring Boot
Spring Boot Hot Swapping settings
[Java] Thymeleaf Basic (Spring Boot)
Introduction to Spring Boot ① ~ DI ~
File upload with Spring Boot
Spring Boot starting with copy
[Eclipse] Shortcut key cheat sheet
Introduction to Spring Boot ② ~ AOP ~
CICS-Run Java application-(4) Spring Boot application
Spring Boot starting with Docker
Spring Boot + Springfox springfox-boot-starter 3.0.0 Use
Spring Boot DB related tips
Hello World with Spring Boot
Set cookies with Spring Boot
[Spring Boot] Easy paging recipe
Use Spring JDBC with Spring Boot
Docker × Spring Boot environment construction
Major changes in Spring Boot 1.5