Spring 08

public List<T> getAll();
エンティティを取得します。

public T findById(long id);
ID番号を引数に指定してエンティティを検索し、返します。

public List<T> findByName(String name);
名前からエンティティを検索します。

getSingleResult()
1つの結果しか検索されません。

 

Query(Interface)
選択したクエリーを実行して、結果を戻ります。

entityManager.createQuery
基準のクエリを実行するために、TypedQueryのインスタンスを作成します。


Long.parseLong
Stringの型がLongに変更します。

Spring 07

・useridの保存機能を修正しました。
問題点:UserEntityが値をもらえません。
解決方法:Controllerで値をもらって、保存します。

public ModelAndView form(
            @ModelAttribute("formModel") @RequestParam(value = "userid", required = true) String userid,
            UserEntity user, ModelAndView mav) {

        user.setUserId(userid);
        repository.saveAndFlush(user);
        return mav;
    }

Controllerで値をもらうのは、Controllerの役割じゃないと思います。
他の解決方法がないので、Controllerで値をもらいます。

 

・エラーメッセージを出力しました。
<li th:each="error : ${#fields.detailedErrors()}"
class="err" th:text="${error.message}" />

#fields
エンティティの各フィールドをバリデーションチェックした結果などがまとめられたオブジェクトです。

detailedErrors
発生したエラーに関する情報をひとまとめのリストとして返すメソッドです。


・各入力フィールドにエラーを表示
<input type="text" name="name" th:value="*{name}" th:errorclass="err" />
エラーが発生した際に適用されるクラス名を指定します。
エラーが起きたらテキストを赤い表示に変えます。

<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}" th:errorclass="err">
エラーが発生している時だけ表示します。
このフィールドのエラーだけを表示します。


・エラーメッセージの日本語化
新しいプロパティファイルを追加しました。
org.hibernate.validator.constraints.NotBlank.message = 空白は不可です。
org.hibernate.validator.constraints.NotEmpty.message = 空白は不可です。
javax.validation.constraints.Max.message = {value} より小さくして下さい。
javax.validation.constraints.Min.message = {value} より大きくして下さい。
org.hibernate.validator.constraints.Email.message = メールアドレスではありません。


・オリジナルのバリデータを作成しました。

下記のクラスは入力したデータ型を確認する機能です。
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()-]*");
    }

}


下記のインターフェースは新しいアノテーションを使えるようになるものです。
@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() default {};

}

補充:
インターフェースとは、クラスに含まれるメソッドの具体的な処理内容を記述せず、変数とメソッドの型のみを定義したものです。
抽象メソッドは具体的な処理内容を記述せず、メソッド名や引数などの定義だけを宣言するメソッドです。


・Serializable(シリアライズ・直列化)
この機能を使うと、簡単にインスタンスを外部記憶装置などに保存し、インスタンスの情報を永続化することができます。


・@Controller、@Service、@Repository、@Componentの違い

@Controller
Spring MVCでコントローラー層のクラスに付与します。
Controller は、主に以下の役割を担います。
1.画面遷移の制御
2.ドメイン層の Service の呼出 (主処理を実行します。)

@Service
Sping MVCでサービス層のクラス(ビジネスロジック等)に付与します。
Service は業務処理を提供します。

@Repository
Spring MVCでデータ層のクラス(DAO等のDBアクセスを行うクラス)に付与します。

@Component
Spring MVCに限らず、SpringのDIコンテナにbeanとして登録したいクラスへ付与します。

 


@SuppressWarning
コンパイル・ユニットのサブセットに関するコンパイル警告を無効にできます。

@SuppressWarnings("unchecked")
unchecked : 未検査のオペレーションに関連する警告の抑止

@PersistenceContext
EntityManagerのbeanを取得してフィールドに設定します。

Spring 06


・Thymeleaf
エスケープ処理機能が内蔵しています。

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

 

(index)
<body>
    <h1 th:text="#{content.title}">Helo page</h1>
    <p th:text="${msg}">message.</p>
</body>


使いたくない場合は、utextに変わります。   
<body>
    <h1 th:text="#{content.title}">Helo page</h1>
    <p th:utext="${msg}">message.</p>
</body>


・GenerationType
問題点:AUTOで生成することができません。
解決方法:IDENTITYに変更しました。

@GeneratedValue(strategy = GenerationType.AUTO)
データベースごとに異なる方法を選択し,主キー値を生成します。
@GeneratedValue(strategy = GenerationType.IDENTITY)
テーブルのidentity列を利用して,主キー値を生成します。

(ブラウザのエラー)
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Tue May 28 14:03:31 JST 2019
There was an unexpected error (type=Internal Server Error, status=500).
error performing isolated work; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: error performing isolated work

(Consoleのエラー)
Hibernate: select mydata0_.id as id1_0_, mydata0_.age as age2_0_, mydata0_.mail as mail3_0_, mydata0_.memo as memo4_0_, mydata0_.name as name5_0_ from mydata mydata0_
Hibernate: select next_val as id_val from hibernate_sequence for update
2019-05-28 14:03:31.119 ERROR 1364 --- [nio-8080-exec-3] o.hibernate.id.enhanced.TableStructure   : could not read a hi value

java.sql.SQLSyntaxErrorException: Table 'test_01.hibernate_sequence' doesn't exist


@PostConstruct
データの初期化処理
保存したデータは、アプリケーションを終了し、再度起動すると消えてしまっています。

問題点:初期化が成功しましたが、終了の時、データが残っています。
解決方法:IDを指定して、データを初期化処理します。
@PostConstruct
    public void init(){
        MyData d1 = new MyData();
        d1.setId(1);
        d1.setName("tuyano");
        d1.setAge(123);
        d1.setMail("syoda@tuyano.com");
        d1.setMemo("this is my data!");
        repository.saveAndFlush(d1);
    }

この解決方法はよくないと思います。
DatabaseにIDは1のデータがいないなら、新しいデータを作成しまいました。
そして、データを削除するのはいけません。削除したら、上記の状況が発生します。
Columnにunique keyを追加する場合は、重複のデータを作成すると、バグになってしまいます。

・Optional
nullかもしれないオブジェクトをラップするためのクラス。

Spring 05

・JpaRepository
databaseの操作というクラスです。

CrudRepositoryは、CRUD機能を提供しています。
PagingAndSortingRepositoryは、ページングおよびソートレコードを行うためのメソッドを提供しています。
JpaRepositoryは、永続コンテキストの更新やレコードの一括削除など、JPA関連のメソッドを提供しています。

@Autowired
userRepositoryというBeanを取得することです。
Springによって自動生成されます。
データを処理するために使用します。


・Thymeleaf属性
th:value  th:value="${msg}"
th:object th:object="${loginBean}"
th:field  th:field="*{username}"

@readOnly
boolean読み取り専用かどうかを指定する。デフォルトはfalse。


・Interable
もらった配列の文字
com.example.demo.entity.UserEntity@2d0716be

問題点:配列が表示されませんでした。
<th:each="obj : ${data}">
<th:text="${obj}">        <----使えます。
<th:text="${obj.userid}"> <----使えません。

解決方法:privateがpublicに変更します。
(UserEntity)

以前
@Column(name = "t_user")
private String userid;

現在
@Column(name = "t_user")
public String userid;

Spring 04

・Buttonで画面の遷移
@Controller
public class NewController {
    @RequestMapping("/")
    public ModelAndView index (ModelAndView mav){
        mav.setViewName("index");
        return mav;
    }   
    @RequestMapping("/other")
    public String other (){

        return "redirect:/";
    }   
    @RequestMapping("/new")
    public String user(){

        return "forward:/";
    }   
}

redirect:/
localhost:8080/otherに遷移したら、localhost:8080/に転送します。

forward:/
localhost:8080/newに遷移します。

<form method="post" action="result">
actionで指定のページへ遷移します。

 


・POSTでボタンを押すと、データを保存します。
@RequestMapping(value = { "/result" }, method = { RequestMethod.POST })
    public ModelAndView postTest3() {

        ModelAndView mv = new ModelAndView();

        mv.setViewName("result");

        return mv;
    }

結果を保存したら、成功メッセージが表示されるページに遷移します。
   
@RequestMapping(value = "/result",method = RequestMethod.POST)
    public UserEntity create(UserEntity entity)
    {
        return userJPA.save(entity);
    }
データを保存することです。


結果:passwordの保存は成功したが、user_idの保存は失敗しました。
原因:まだわかりません。

URLで実行したら、機能は正常です。しかし、POSTで実行するのはうまくできません。

 

・あった状況

POSTとGET同じURLに移動して、違う結果をもらいます。(値をもらう問題だと思います。)

POSTはエラーページに遷移します。
GETは正常な画面に遷移します。

POSTで新しい画面に遷移して、GETと同じ画面に遷移します。(上記と矛盾しているんですが、実際に発生しまいました。)

ChromeとEdgeは配列が表示しますが、Eclipseのブラウザはダウンロードの画面が表示されます。
JSONのファイルはChromeとEdgeに表示することができると思います。ですから、この結果をもらいました。


GETとPOSTの使い方は違うので、同じ移動方法を使わないほうがいいと思います。

@RestController
@RequestMapping(value = "/user")
public class UserController {

    @Autowired
    private UserJPA userJPA;


    @RequestMapping(value ="/list" ,method = RequestMethod.GET)
    public List<UserEntity> list(){
        return userJPA.findAll();
    }

   
    @RequestMapping(value = { "/result" }, method = { RequestMethod.POST })
    public ModelAndView postTest3() {

        ModelAndView mv = new ModelAndView();

        mv.setViewName("result");

        return mv;
    }

}
赤い部分は、localhost:8080/user/listに遷移したら、DataBaseのデータが表示されます。

<form method="post" action="user/result">
青い部分は、POSTで値を渡して、GETの部分を実行できます。

これから、POSTとGETの機能を分別します。しないと、混乱するかもしれません。


Spring 03

Groovy

Javaと似てるプログラミング言語です。

使う前に、Spring Boot CLIを用意します。
ファイルの拡張子はgroovyです。

実行方法:コマンドプロンプトを起動して、Desktopに遷移して、spring run XXX.groovyを入力します。

app.groovy
@RestController
class App{
    @RequestMapping("/")
    def home(){
        "Hello!!"
    }
}

起動したら、Webブラウザhttp://localhost:8080/にアクセスします。
画面に「Hello!!」とテキストが表示されます。

流れ:Webブラウザ -> サーバー -> コントローラー -> メソッド -> 返値 -> Webブラウザ


Thymeleaf

Java XMLXHTMLHTML5 のテンプレートエンジンです。Thymeleafの目標はJSPを完全に取って代わることです。


文字化け解決方法
native2ascii -encoding utf-8 app.groovy app2.groovy


MavenとGradle
プロジェクト自動構築ツールです。MavenXMLで配置します。

GradleはGroovyで配置します。
流れ:
    1.ソースコードコンパイルします。
    2.単体テストと統合テストを実行します。
    3.スタティックコードを分析して、分析結果を生成します。
    4.リリースバージョンを作ります。
    5.ターゲット環境にデプロイします。
    6.配信プロセスをデプロイします。
    7.スモークテストおよび自動機能テストを実施します。

Maven
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
</dependency>

Gradle
dependencies {
    compile(‘org.springframework:spring-core:2.5.6’)
    compile(‘org.springframework:spring-beans:2.5.6’)
}

上記通り、MavenよりGradleのコードは短いです。しかし、今よく使うはMavenです。そして、Mavenの利点もあります。また、MavenとGradleが同時に存在することができます。

Githubに優秀なオープンソースは二つ依存性の注入方法が提供されています。


指定のhtmlに遷移します。
mv.setViewName("html名");

POST用のパラメータを受け取る
@RequestMapping(value = {"/formPost"}, method = {RequestMethod.POST})
   
GET用のパラメータを受け取る
@RequestMapping(value = {"/formPost"}, method = {RequestMethod.GET})
   
値の保存
mv.addObject("name", name);

Spring 02

JSPとSpring Boot

JSP maven
<!-- spring boot tomcat jsp-->
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
</dependency>

Servlet maven

<!--servlet-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
</dependency>

JSTL maven
<!-- jstl-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
</dependency>


JSPを利用するために、JSPのフォルダーを指定します。
application.properties
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

下記のは、もし/indexへ遷移したら、springmvcがJSPのフォルダーのindex.jspを探します。

@Controller
public class IndexController {
    @RequestMapping(value = "/index",method = RequestMethod.GET)
    public String index(){
        return "index";
    }
}

@Controller
使用者からもらったURLを対応のサービスに渡します。よくRequestMappingと一緒に使われています。

@RequestMapping
ルーティング情報を提供します。


・SpringBootがSpringDataJPAでCRUDを作ります。
<!--mysql-connector-java-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

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

<!--tomcat-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <!--<scope>provided</scope>-->
</dependency>

内部のtomcatで実行する場合は、scopeを削除します。

@ResponseBody
戻り値をHTTP response bodyに書き込みます。

@RestController
JsonXML等を返すWebAPI用のコントローラで使用します。


・DataBaseの接続とJPA(Java Persistence API )
下記の二つは同じ機能ですが、一つのコードは長いです。もう一つは短くて、理解やすいです。しかし、yaml形式の定義ファイルはpropertiesのルールより厳しいです。一つスペースも影響されています。

(application.properties)
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=matt
spring.datasource.password=12345
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

(application.yml)
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: matt
    password: 12345
    driver-class-name: com.mysql.cj.jdbc.Driver

Hibernate
Java のためのORM(Object-Relational Mapping) ライブラリであり、オブジェクト指向ドメインモデルを関係データベースにマッピングするためのフレームワークを提供します。

@Entity
テーブルを指定します。

@Table
よく@Entityと一緒に使われています。

@id
一つテーブルは一つprimary keyしかありません。

@GeneratedValue
primary key生成方法です。AUTO、INDENTITY、SEQUENCEとTABLE 四つ方法があります。既定値はAUTOです。

@Column
特定のデータを指定します。特定の属性を指定することができます。今回は使用しません。

@Autowired
Beanから自動的に導入します。

JpaRepository
SpringDataJPAが提供した簡単なデータ操作インターフェースです

JpaSpecificationExecutor
SpringDataJPAが提供した複雑な検査インターフェースです。

Serializable
直列化インターフェースです。

・DataBaseの接続問題
原因:mysql-connector-java の5.1.33 ~ 37 のバグでした。
詳しいページ:https://www.nakamuri.info/mw/index.php/Mysql-connector-java_%E3%81%AE%E3%83%90%E3%82%B0%E3%81%A7_Java%E3%81%8B%E3%82%89MySQL%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84
以前
url: jdbc:mysql://localhost:3306/test_01?characterEncoding=utf8
現在
url: jdbc:mysql://localhost:3306/test_01?characterEncoding=UTF-8&serverTimezone=JST


CRUDを作成しました。
バグ:Create機能は実行できません。
原因:sequenceでprimary keyを生成するのは、MySQLに対してサポートしません。MySQLはidentityを使っています。
解決方法:@GeneratedValue(strategy = javax.persistence.GenerationType.IDENTITY)