2022年03月18日(金)


DAOと表の関係


1つのDAOに複数のテーブルが含まれています
他のテーブルのデータはクエリーできますが.
データを照会できても、登録、変更、削除はできません
他のDAOが担当するテーブルを登録、変更、または削除します.
1つのDAOには1つ以上のテーブルがあります
1つのテーブルを複数のDAOに登録、変更、削除することはできません.
クエリーは可能です.
メンテナンスが難しくなる.
1つのテーブルの合計数は1つのDAOです
承認CRUD
データの登録、変更、削除は、1つのDAOが担当する必要があります.
明日サービスオブジェクトを作成します
サービス・オブジェクトが実行する作業:ビジネス処理、トランザクション制御(commit、rollback)
MemberService
BoardService
ApplyService
1つのサービス・オブジェクトは、1つ以上のDAOを使用してビジネスを処理できます.
コントローラオブジェクトコントローラオブジェクト:クライアントリクエストの処理(リクエストの応答を担当)クライアントリクエストの処理
MemberController:MemberServiceを使用してクライアント要求を処理する
BoardController
ApplyController
コントローラはDAOを使用しません
コントローラオブジェクト→サービスオブジェクト→DAO→テーブル
メンテナンスが容易な方法かメンテナンスが困難な方法か
複数のDAOアクセス用テーブル
残りのDAOはクエリーのみです.

取引



通常電話番号は複数格納
電話番号タイプ表
電話番号
携帯電話
ファクシミリ
•勤務先電話
•業務ファックス
連絡先テーブル
電話番号表
電話番号タイプ表
/Users/nana/git/bitcamp-20211108/mylist-boot/app-11.1/README.md
-- 연락처
drop table ml_contact;

create table ml_contact(
  contact_no int not null,
  name varchar(50) not null,
  email varchar(20) not null,
  company varchar(50)
);

alter table ml_contact
  add constraint primary key (contact_no),
  modify column contact_no int not null auto_increment;
-- 전화번호 유형
create table ml_tel_type(
  tt_no int not null,
  title varchar(20) not null
);

alter table ml_tel_type
  add constraint primary key (tt_no),
  modify column tt_no int not null auto_increment;
-- 연락처 전화번호
create table ml_cont_tel(
  ct_no int not null, -- 전화번호 PK
  contact_no int not null,
  tt_no int not null,
  tel varchar(20) not null
);

alter table ml_cont_tel
  add constraint primary key (ct_no),
  modify column ct_no int not null auto_increment;

alter table ml_cont_tel
  add constraint ml_cont_tel_fk1 
    foreign key (contact_no) references ml_contact(contact_no),
  add constraint ml_cont_tel_fk2 
    foreign key (tt_no) references ml_tel_type(tt_no);
連絡先テーブルにサンプルデータを挿入



連絡先データを扱うDAOの作成
ContactDao
ContactTelDao
TelTypeDao
電話番号タイプ情報を処理するDAOを作成できます.
しなくてもいい
実際の操作では、「電話番号タイプ」テーブルのように
テーブルの作成時にデータを挿入します.
DAOを単独で作成しない
管理機能に含まれている場合は、
テーブルごとにDAOを作成することもできます.
他のテーブルに関連付けられている場合:

連絡先テーブルの変更によるドメインクラスの変更


連絡先テーブルとドメインクラス

Contact    <------------------> 연락처
ContactTel <------------------> 전화번호
                                전화유형
電話タイプデータを直接処理する必要がない場合は、ドメインクラスを作成する必要はありません.
包含関係(組合せ)
このオブジェクトに含める
オブジェクトが消えると、オブジェクトも消えます.
注意!
オブジェクト(クラス)とオブジェクトの関係は一方向でなければなりません.
Aクラス-->Bクラス
class A {
  B obj;
  ...
}

class B { // No!!!!!!
  A obj;
  ...
}
双方参照しない
joinが複雑な場合はHashMapを使用します

連絡先テーブルの変更によるDAOクラスの変更


管理機能(タイプの削除または追加)に含まれている場合は、
  <select id="findByContactNo" parameterType="int">
    select
      ct_no,
      contact_no,
      tt_no,
      tel
    from
      ml_cont_tel
    where
      contact_no=#{no}
  </select>
  <select id="findByContactNo" parameterType="int" resultMap="contactTelMap">
    select
      ct_no,
      contact_no,
      tt_no,
      tel
    from
      ml_cont_tel
    where
      contact_no=#{no}
  </select>

ContactDaoの使用


ContactController ------> ContactDao

連絡先テーブルの変更によるページコントローラクラスの変更


http://localhost:8080/contact/add?name=aaa&[email protected]&tel=010-0000-0001&tel=02-0000-0002&tel=02-0000-0003
Spring Boot
new Contact()←Contactオブジェクトの作成
nameフィールド、emailフィールド、companyフィールド
各フィールドにクエリー・パラメータ値を追加
telは複数受信可能
String[]配列でtelを受信できます
new String[]
クエリパラメータ値がString[]配列の
第0項、第1項、第2項
Spring Boot呼び出しContactControllerページコントローラ
値を受信するには変数が必要ですadd(Contact contact, String[] tel) {...}名前が一致するのでtelsではなくtelを使います.
http://localhost:8080/contact/list
    System.out.println(contact);
    for (String t : tel) {
      System.out.println(t + ", ");
    }
    System.out.println();

http://localhost:8080/contact/add?name=bbb&[email protected]&tel=010-0000-0001&tel=02-0000-0002&tel=02-0000-0003


複数のデータが同じ名前で入力された場合、順番に受信します.
add(Contact contact, String[] tel) {...}
同じ名前のパラメータ値が複数を超える場合は、配列として受信できます.
add(Contact contact, String[] tel) {...}
パラメータ値はオブジェクトとして受信できます.ただし、パラメータ名に一致するpropertyが必要です.
/contact/add?name=OOO
要求パラメータと呼びます.
要求パラメータ名と値
/contact/add?name=OOO&email=OOO&tel=OOO
疑問符から終了までをクエリー文字列と呼びます
要求パラメータと同じproperty名があると仮定します.
ContactTelジェネレータの作成
オブジェクトの作成時に電話番号を直接入力
  public ContactTel() {}

  public ContactTel(String tel) {
    this.tel = tel;
  }
良いジェネレータコードを作るのも減ります↓
  @RequestMapping("/contact/add")
  public Object add(Contact contact, String[] tel) throws Exception {
    System.out.println(contact);
    for (String t : tel) {
      contactDao.insertTel(new ContactTel(t));
    }
    return 1;
  }
忘れるタイプ...
に質問
電話番号のタイプにパラメータはありません
/contact/add?name=OOO&email=OOO&company=OOO
new Contact()で受信
今まで私たちが学んだ解決策を使っています.
/contact/add?name=OOO&email=OOO&company=OOO&tel=1,010-1111-2222&tel=2,02-1111-2222&tel=3,010-1111-3333
new Stringで受信
0はtel=1、1はtel=2、2はtel=3
add(Contact contact, String[] tel) {...}
新しいContactTel(タイプ、電話番号)
split()でカットして入れます
  public ContactTel(int telTypeNo, String tel) {
    this.telTypeNo = telTypeNo;
    this.tel = tel;
  }
http://localhost:8080/contact/add?name=x1&[email protected]&tel=1,02-0000-0001&tel=2,02-0000-0002&tel=3,010-0000-0003
  @RequestMapping("/contact/add")
  public Object add(Contact contact, String[] tel) throws Exception {
    contactDao.insert(contact);
    for (int i = 0; i < tel.length; i++) {
      String[] value = tel[i].split(",");
      contactDao.insertTel(new ContactTel(Integer.parseInt(value[0]), value[1]));
    }
    return 1;
  }

ビルダーの変更
  public ContactTel(int contactNo, int telTypeNo, String tel) {
    this.contactNo = contactNo;
    this.telTypeNo = telTypeNo;
    this.tel = tel;
  }
PK値を知るにはinsertが必要です
PK値で挿入します.
以前JDBCを習った時の方法
com.eomcs.jdbc.ex4.Exam0110.java
挿入後に自動的に増加するPK列の値を決定する方法
サブテーブルにデータを同時に入力するときに発生する問題
親投稿番号を知る必要があります
うん.前に入力した投稿番号は何ですか?
問題は、上に入力した投稿PK値が自動的に生成されることです.
解決策
com.eomcs.jdbc.ex4.Exam0111.java
  <!-- 자동 증가된 PK 값을 받고 싶을 때! -->
  <insert id="insert" parameterType="contact" keyProperty="no" keyColumn="contact_no" useGeneratedKeys="true">
    insert into ml_contact(name,email,company) 
    values(#{name},#{email},#{company})
  </insert>

  @RequestMapping("/contact/add")
  public Object add(Contact contact, String[] tel) throws Exception {
    contactDao.insert(contact);
    for (int i = 0; i < tel.length; i++) {
      String[] value = tel[i].split(",");
      contactDao.insertTel(new ContactTel(contact.getNo(), Integer.parseInt(value[0]), value[1]));
    }
    return 1;
  }
http://localhost:8080/contact/add?name=x3&[email protected]&company=bitcamp&tel=1,02-0000-0001&tel=2,02-0000-0002&tel=3,010-0000-0003


http://localhost:8080/contact/add?name=x4&[email protected]&company=bitcamp&tel=1,02-0000-0001&tel=2,02-0000-0002&tel=3,010-0000-0003


データをテーブルに分散保存
http://localhost:8080/contact/index.html

「連絡先の入力」画面



電話タイプ選択ボックスの追加
  var xName = document.querySelector("#x-name");
  var xEmail = document.querySelector("#x-email");
  var xCompany = document.querySelector("#x-company");

  document.querySelector("#x-add-btn").onclick = function() {
    if (xName.value == "" || xEmail.value == "" /* || xTel.value == "" */) {
      window.alert("필수 입력 항목이 비어 있습니다.");
      return;
    }
    console.log(xName.value);
    console.log(xEmail.value);
    console.log(xCompany.value);
  var xName = document.querySelector("#x-name");
  var xEmail = document.querySelector("#x-email");
  var xCompany = document.querySelector("#x-company");
  var xTelDivList = document.querySelectorAll(".x-tel-div")
  
  for (var xTelDiv of xTelDivList) {
	  console.log(xTelDiv);
  }
  for (var xTelDiv of xTelDivList) {
	  var xTelType = xTelDiv.querySelector("select");
	  var xTel = xTelDiv.querySelector("input");
  }


http://localhost:8080/contact/list

get()メソッドの変更
連絡先詳細表示画面を処理します.
  @RequestMapping("/contact/get")
  public Object get(int no) {
    Contact contact = contactDao.findByNo(no);
    if (contact == null) {
      return "";
    }
    contact.setTels(contactDao.findTelByContactNo(no));
    return contact;
  }

      // 4) 연락처 상세 정보를 화면에 출력한다.
      xName.value = contact.name;
      xEmail.value = contact.email;
      xCompany.value = contact.company;
      for (var tel of contact.tels) {
    	  console.log(tel);
      }
      // 4) 연락처 상세 정보를 화면에 출력한다.
      xName.value = contact.name;
      xEmail.value = contact.email;
      xCompany.value = contact.company;
      for (var i = 0; i < contact.tels.length; i++) {
    	  var xTelType = xTelDivList[i].querySelector("select");
    	  var xTel = xTelDivList[i].querySelector("input");
    	  
    	  console.log()
    	  xTelType.value = contact.tels[i].telTypeNo;
    	  xTel.value = contact.tels[i].tel;
      }
詳細ページに入ると、選択ボックスに相当するタイプが表示されます.
update
  document.querySelector("#x-update-btn").onclick = function() {
	  var firstTel = xTelDivList[0].querySelector("input"); // 첫번째 전화번호
	  if (xName.value == "" || xEmail.value == "" || firstTel.value == "") {
      window.alert("필수 입력 항목이 비어 있습니다.");
      return;
    }
電話番号の更新
既存の電話番号を押す
新しい挿入をする
int deleteTelByContactNo(int contactNo);
連絡先のすべての連絡先を削除
  @RequestMapping("/contact/update")
  public Object update(Contact contact, String[] tel) throws Exception {
    int count = contactDao.update(contact);
    if (count > 0) {
      contactDao.deleteTelByContactNo(contact.getNo());
      for (int i = 0; i < tel.length; i++) {
        String[] value = tel[i].split(",");
        if (value[1].length() == 0) {
          continue;
        }
        contactDao.insertTel(new ContactTel(contact.getNo(), Integer.parseInt(value[0]), value[1]));
      }
    }
    return count;
  }
delete
サブテーブルデータを削除する必要があります
  @RequestMapping("/contact/delete")
  public Object delete(int no) throws Exception {
    contactDao.deleteTelByContactNo(no);
    return contactDao.delete(no);
  }

電話入力画面の動的追加



<button type="button" onclick="deleteDiv(event)">삭제</button>
行内合成としてeではなくイベントを使用する
EventTarget.dispatchEvent()
https://developer.mozilla.org/ko/docs/Web/API/EventTarget/dispatchEvent
表のチェックイン後、↓コードを必要とせずに一度にインポートできます.

resultMapがcollectionラベルを使用するのは来週の月曜日です...
関連タグ