GitEngHar / WorkUp

LearnJava
0 stars 0 forks source link

Springフレームワーク本を制覇したい #2

Closed GitEngHar closed 2 months ago

GitEngHar commented 6 months ago

達成したいこと

5/22までにSQLの基本利用 join like ..etc 及び SpringFrameWorkを習得し、仕事の土俵に立つこと

期間と段取り

5/14 簡単なSpringフレームワークの利用 (超入門spring本完了)
5/18 オリジナル簡易Webアプリの作成 または EnglishManager をSpringに移行とバージョンアップ

重要なこと

目標に向けた段取りに齟齬がないことを知っておく

GitEngHar commented 6 months ago

Data アノテーション利用で生成されたメソッド
image

GitEngHar commented 6 months ago

DI(依存性の注入)

簡単に言うとクラス依存している部分を外部から呼び込んでくる
SpringFrameworkは任意で実装したクラスをインスタンス化する機能を持っている
インスタンスの生成はDIコンテナに任せる
以下を守ることでクラスの修正をなくすことができる??

@Componentによるインスタンス生成はステレオタイプアノテーションとよぶ 用途別に4種類ある。

DDD観点でのアノテーション説明

上記には属さないが、@Componentは再利用されるクラスに付与される サブ処理に用いられる

@Component を付け替えると 普段呼び出していた 実装クラスを切り替えることができる
@Autowired でSpringスキャン時に生成されたインスタンを呼び出す

呼び出す側のコードを全く変更せずに、改修できる

AOP(アスペクト指向プログラミング)

これは「中心的な機能」と「横断的な機能」の2種類の考え方が存在する
横断的な機能は 共通する機能 ココでの考え方は共通する機能は呼び出して再利用することで開発者は中心的な機能に集中するということである

クラス間の結合度を疎にするということ

GitEngHar commented 6 months ago

DIの注入パターン

フィールドインジェクション

フィールドで注入を行う

セッターインジェクション

セッターメソッドで注入を行う

コンストラクタインジェクション

コンストラクタで注入する
この場合、 @Autowired のアノテーションを省略することができる

GitEngHar commented 6 months ago

つまりDIとは

DIとは必要なものを用意して起き、必要なタイミングで利用する仕組みである

DIの注入パターンは前述の通り3パターンほど存在するが、推奨はコンストラクタインジェクションとなっている
コンストラクタでは final 宣言が主となっているため、 オブジェクトの不変性 が保たれ予測が容易いコードとなる
1クラスは1責任というが、コンストラクタパターンで注入をしているとこれに違反しているかどうかを発見しやすくなる
責任が混在するということはインスタンス化するオブジェクトが多くなることと同義であるため

重要なのは、プログラムの可読性 / 保守性 / 拡張性である
SOLID原則を意識するとわかりやすい

コンストラクタインジェクション

case 1

package com.example.demo.example.impl;

import org.springframework.stereotype.Component;

import com.example.demo.example.Example;
import com.example.demo.service.SomeService;

import lombok.RequiredArgsConstructor;

@Component
@RequiredArgsConstructor
public class ConstructorInjectionOmitExample implements Example {
    private final SomeService someService;//finalを引数としたコンストラクタが自動で生成される
    @Override
    public void run() {
        // TODO 自動生成されたメソッド・スタブ
        someService.doService();
    }

}

case2

package com.example.demo.example.impl;

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

import com.example.demo.example.Example;
import com.example.demo.service.SomeService;

@Component
public class ConstructorInjectionExample implements Example {
    private final SomeService someService;

    @Autowired
    public ConstructorInjectionExample(SomeService someService) {
        this.someService = someService;
    }
    @Override
    public void run() {
        // TODO 自動生成されたメソッド・スタブ
        someService.doService();
    }

}
GitEngHar commented 6 months ago

いざAOP指向プログラミングへ

用語を図化

image

処理詳細

Aspect (横断的な機能の処理) は必要になった際にSpringFrameworkによって実行する
クラスにAspectを含めるのではなく、SpringFramework が生成した AOPProxy が横断的な処理が発生した際に、Aspectに処理を流す

処理の種類

GitEngHar commented 5 months ago

Target


@Component
public class Target {
    public void sayHelo() {
        System.out.println( "Hello");
    }
    public void sayBay() {
        System.out.println("Bay");
    }
}

Around

    @Around("execution(* com.example.demo.service.Target.*(..))")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable{
        long startTime = System.currentTimeMillis();
        System.out.println("---[Around : Before]---");
        System.out.println("Target");
        System.out.println("Class : " + joinPoint.getSignature());
        System.out.println("Method : " + joinPoint.getSignature().getName());

        Object result = joinPoint.proceed();

        System.out.println("---[Around After]---");
        long elapsedTime = System.currentTimeMillis()- startTime;
        System.out.println("Method execution time:" + elapsedTime + "millseconds.");
        return result;
    }

main

@SpringBootApplication
public class AopSampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(AopSampleApplication.class, args)
        .getBean(AopSampleApplication.class).exe();

    }

    @Autowired
    private Target service; //DI
    private void exe() {
        service.sayHelo();
        System.out.println("------");
        service.sayBay();
    }

}

結果

---[Around : Before]---
Target
Class : void com.example.demo.service.Target.sayHelo()
Method : sayHelo
Hello
---[Around After]---
Method execution time:1millseconds.
------
---[Around : Before]---
Target
Class : void com.example.demo.service.Target.sayBay()
Method : sayBay
Bay
---[Around After]---
Method execution time:0millseconds.

考える

target 内に2つの簡単なメソッドが存在し、単純な実行をしている ログをみるにクラス内のメソッド単位で aspect処理は実行されている
実行単位はおそらく以下で設定すると思われる

@Around("execution(* com.example.demo.service.Target.*(..))")

横断的な処理をまとめておき、必要な時に呼び出せる機能は、コード量の削減と記述忘れとめんどくさいが故の実装すっ飛ばしを担保してくれていい

GitEngHar commented 5 months ago

image

こういうことだ!!

GitEngHar commented 5 months ago

さてMVCとは

mvnと頭の中で被ってしまうようなぁ

これは考え方です

プログラムを処理単位でわける考え方

以下のような感じ

題名 : 料理を作るシェフ

Model
 料理を作るために必要な知識や作業
  >> レシピ , 材料 など 
View 
 料理を魅力的に見せるための盛り付け
  >> 料理盛り付け
Controller
 レシピ を見て 盛り付けを行ったり料理の振る舞いを調整
 >> シェフ

それぞれに役割があるから分かりやすい!
お互いに依存関係が少ないので、あとあと追加しやすいし、テストしやすい → すぐに新しい料理も増やせるし、盛り付けパターンも増やせる

GitEngHar commented 5 months ago

噂に聞くThymeLeaf

通称テンプレートエンジン
SpringBootと一緒の利用が推奨されており、一緒に使うと データを画面に表示する機能 を簡単にしてくれる

thymeleaf のルール簡単まとめ

html内で利用できる記述技法

  1. th:text
    • "value > value" これで比較
    • "${value}" 変数取得
    • object.valueで値を取得できる (getメソッドが必要)
  2. th:switch
  3. th:case
  4. th:with (html値を代入しておける)
    • 代入値は #numbers.formatInteger(変数,整数最低桁数,"COMMA") で利用できる
      • 型等は臨機応変に変える
  5. 他表示方法や List Mapを利用した表示もできる

htmlの部品化(フラグメント)

手法は2つある

  1. 直接呼び出す手法
    • フラグメント部分
      • <div th:fragment="header">
    • 呼び出すほう (振る舞いは違うけどよくわからん)
      • th:replace="common :: footer"
      • th:insert="common :: footer"
  2. 渡したい箇所を引数にして渡す手法
    • 値を渡すほう
      • htmlタグに以下を含める
        • th:replace="~{layout ::base(~{::title}, ~{::body})}">
    • 受け取るほう
      • htmlタグに以下を含める
        • th:fragment="base(title,content)"
        • th:replace="${title}"
        • th:insert="${body}"

Form

input で 値を渡して controllerで受け取る

大体の流れ

  1. controller (以降ctlr) で view(temp/index.htmlとか)を参照し、返す
  2. index.html でformにしてctrlに値を返す (/xxx にpostでリダイレクトする)
  3. ctrl で mappingして値を取得する

ここで値の受け取り方?(一部怪しい)は3種類くらいある

@RequestParamを使う

pathからもぎとる

GitEngHar commented 5 months ago

MyBatisはお友達

バティス × キホン

ヒトツ × オオク

1つの 商品 には多くのレビューがつく
これはヒトツと多く => 1対多 の関係といえる

xml : resultMapの機能を使う オブジェクト : 商品の中にListでレビューが入ってくる

なお、別のテーブルにクエリをして結果をまとめているのは、JOINなのであしからず。

GitEngHar commented 5 months ago

Validationは検査マン