2022年3月28日


AJAX上かWebブラウザ上か
16.1ファイルアップロード:JavaScriptで構築されたオブジェクト
http://localhost:8080/book/index.html
カタログに本の写真があります.
本を選ぶと、もっと大きな絵が見えます.
画像をクリックするとより大きな画像が表示されます
図書記録テーブルに図書画像ファイル名を格納するバーを追加します.
alter table ml_book
  add column photo varchar(255);

フィールドクラス(値オブジェクト;Value Object;VO)に、図書写真ファイル名を格納するフィールドを追加します.

手順3-SQL Mapperファイルを変更します.
写真列マッピング情報をresultMapラベルに追加

joinデータは省略できません...
紛らわしいので、フィールド名と欄名が同じでも書きます.
findAll、findByNo、insert、update SQL文に写真バーを追加
http://localhost:8080/book/index.html
手順4-写真ファイルのアップロード機能をページコントローラに追加します.
BookControlクラスの変更
サービスとデータの交換は不要
  @RequestMapping("/book/add")
  public Object add(Book book, MultipartFile file) throws Exception {

    // 파일이 업로드 되었다면 저장한다.
    if (file != null && file.getSize() > 0) {      
      try {
        String filename = UUID.randomUUID().toString(); // 임의의 파일명을 준비한다.

        // 파일명의 확장자를 알아낸다.
        int dotIndex = file.getOriginalFilename().lastIndexOf(".");
        if (dotIndex != -1) {
          filename += file.getOriginalFilename().substring(dotIndex);
        }

        // 파일을 지정된 폴더에 저장한다.
        File photoFile = new File("/Users/nana/upload/book/" + filename);
        file.transferTo(photoFile);

        // 저장된 파일명을 도메인 객체에 설정한다.
        book.setPhoto(filename);

      } catch (Exception e) {
        e.printStackTrace();
        return "error!";
      }
    }

    return bookService.add(book);
  }
updateも同じですしかし、コードは繰り返されます.
  private String saveFile(MultipartFile file) throws Exception {

    String filename = UUID.randomUUID().toString(); // 임의의 파일명을 준비한다.

    // 파일명의 확장자를 알아낸다.
    int dotIndex = file.getOriginalFilename().lastIndexOf(".");
    if (dotIndex != -1) {
      filename += file.getOriginalFilename().substring(dotIndex);
    }

    // 파일을 지정된 폴더에 저장한다.
    File photoFile = new File("/Users/nana/upload/book/" + filename);
    file.transferTo(photoFile);

    return filename;
  }
}
ここではファイルが有効かどうかチェックしません
呼び出し元に異常が発生した場合はどうすればいいですか.
  private String saveFile(MultipartFile file) throws Exception {

    if (file != null && file.getSize() > 0) {

      // 파일을 저장할 때 사용할 파일명을 준비한다.
      String filename = UUID.randomUUID().toString(); // 임의의 파일명을 준비한다.

      // 파일명의 확장자를 알아낸다.
      int dotIndex = file.getOriginalFilename().lastIndexOf(".");
      if (dotIndex != -1) {
        filename += file.getOriginalFilename().substring(dotIndex);
      }

      // 파일을 지정된 폴더에 저장한다.
      File photoFile = new File("/Users/nana/upload/book/" + filename);
      file.transferTo(photoFile);

      return filename;

    } else {
      return null;
    }
  }
}
  @RequestMapping("/book/add")
  public Object add(Book book, MultipartFile file) throws Exception {

    // 파일이 업로드 되었다면 저장한다.
    try {
      book.setPhoto(saveFile(file));
      return bookService.add(book);

    } catch (Exception e) {
      e.printStackTrace();
      return "error!";
    }
    
  }
同様にupdateを変更
フロントエンド
ステップ1-入力画面に画像アイテムを追加します.
写真ファイルをアップロードする入力ラベルを追加

id -> name
サーバに送信するパラメータ名



必須フィールド
値を入力するかどうかを確認します.

photo -> file

Multipartに転送されたデータと同じ名前にすることはできません
http://localhost:8080/book/form.html
空の文字列を日付オブジェクトに変更できません
文字列を日付オブジェクトとして保存します.
空の文字列は日付に変更できません

JavaScriptフォームデータの検索
    // 독서일을 지정하지 않았으면 서버에 보내지 않는다.
    if (xReadDate.value == "") {
    	fd.delete("readDate");
    }

読み取り日を指定しない場合は、readDateをサーバに送信するときに削除します.

↑readDateは存在しない
サムネイル画像と詳細ページに入ると見える画像が違います
異なる出力速度
画像が大きいほど速度が遅くなります
小さな画像の方が高速
に道を教える
/static/book/index.html


photo/null

スプリングガイドの配置パス


Spring Bootの実行

Tomcatサーバの実行

OSで提供される一時フォルダの使用
アプリケーションの配備

Windowsオペレーティングシステムの場合、一時フォルダ
C:UsersユーザーホームAppDataLocalTemp
実行するたびにフォルダが変わります
スプリングガイドは運転するたびに位置を決めます
docbase

スプリングガイドからファイルを保存するパス


JVMを実行するフォルダ
C:UsersユーザーホームMyListjava
↑JVM実行フォルダ
eclipse IDEでappクラスを実行する場合、実行フォルダはプロジェクトフォルダです.
はい、そうです.mylist-boot/app
これは、クリップで実行するか、JVMで実行するかによって異なります.

スプリングガイドからファイルを読み込む


ファイルを保存するフォルダ
URLパスで指定した
ファイル名をパラメータとして使用

springboot returnバイナリファイルの検索
https://www.baeldung.com/spring-controller-return-image-file
https://stackoverflow.com/questions/35680932/download-a-file-from-spring-boot-rest-service

実際のファイル名と元のファイル名を保存
ダウンロードする場合は、元のファイル名を記入するだけです.
// header.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=오리지널파일명");
  @RequestMapping("/book/photo")
  public ResponseEntity<Resource> photo(String filename) {
    try {
      // 다운로드할 파일의 입력 스트림 자원을 준비한다.
      File downloadFile = new File("./upload/book/" + filename); // 다운로드 상대 경로 준비
      FileInputStream fileIn = new FileInputStream(downloadFile.getCanonicalPath()); // 다운로드 파일의 실제 경로를 지정하여 입력 스트림 준비
      InputStreamResource resource = new InputStreamResource(fileIn); // 입력 스트림을 입력 자원으로 포장

      // HTTP 응답 헤더를 준비한다.
      HttpHeaders header = new HttpHeaders();

      // 만약 다운로드 받는 쪽에서 사용할 파일명을 지정하고 싶다면 다음의 응답 헤더를 추가하라!
      // header.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=오리지널파일명");

      header.add("Cache-Control", "no-cache, no-store, must-revalidate");
      header.add("Pragma", "no-cache");
      header.add("Expires", "0");

      //      // HTTP 응답 생성기를 사용하여 다운로드 파일의 응답 데이터를 준비한다.
      //      BodyBuilder http응답생성기 = ResponseEntity.ok(); // 요청 처리에 성공했다는 응답 생성기를 준비한다.
      //      http응답생성기.headers(header); // HTTP 응답 헤더를 설정한다.
      //      http응답생성기.contentLength(0); // 응답 콘텐트의 파일 크기를 설정한다.
      //      http응답생성기.contentType(MediaType.APPLICATION_OCTET_STREAM); // 응답 데이터의 MIME 타입을 설정한다.
      //
      //      // 응답 데이터를 포장한다.
      //      ResponseEntity<Resource> 응답데이터 = http응답생성기.body(resource);
      //
      //      return 응답데이터; // 포장한 응답 데이터를 클라이언트로 리턴한다.

      return ResponseEntity.ok()
          .headers(header)
          .contentLength(downloadFile.length())
          .contentType(MediaType.APPLICATION_OCTET_STREAM)
          .body(resource);

    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }

  }
bodyのパラメータタイプはresourceのみなのでresourceにパッケージします
http://localhost:8080/book/photo?filename=9bd261b8-1f71-477b-8d85-d77af3bdb5f5.png
https://developer.mozilla.org/ko/docs/Web/CSS/vertical-align

一部の本はイメージがない

このように基本的なイメージを浮かび上がらせるには
        if (book.photo == null) {
        	book.photo = "default.png";
        }

Javaサムネイル検索の作成
ライブラリをダウンロードする必要があります
https://github.com/coobird/thumbnailator
https://search.maven.org/artifact/net.coobird/thumbnailator/0.4.17/jar
// 썸네일 이미지 생성 라이브러리
implementation 'net.coobird:thumbnailator:0.4.17'
gradle eclipse
Refresh
      // 썸네일 이미지 파일 생성
      Thumbnails.of(photoFile)
      	.size(50, 50)
      	.outputFormat("jpg")
      	.toFile(new File("./upload/book/" + "50x50_" + filename));
サムネイル画像なので、ファイルサイズは確かに小さいです

写真を変えた
画像データを変更しない場合は、更新項目から除外します.
BookDao.xml
update sql文で動的
https://mybatis.org/mybatis-3/dynamic-sql.html
  <update id="update" parameterType="book">
    update ml_book set 
      title=#{title}, 
      author=#{author},
      press=#{press},
      feed=#{feed},
      read_date=#{readDate},
      page=#{page},
      price=#{price}
      <if test="photo != null">
        ,photo=#{photo}
      </if>
    where 
      book_no=#{no}
  </update>
sql文の作成時に条件文、繰返し文を追加できます
• if
• choose (when, otherwise)
• trim (where, set)
• foreach

Lombok


プロジェクトへのLombokライブラリの追加
https://projectlombok.org/
https://projectlombok.org/setup/gradle
https://plugins.gradle.org/plugin/io.freefair.lombok


git/bitcamp-study/mylist-boot/app> gradle compileJava
ソースファイルのコンパイル
bin:このクリップでコンパイルされたファイルを配置するフォルダ
build:gradle構築ツールでコンパイルされたファイルがあるフォルダ
javap -cp bin/main com.eomcs.mylist.domain.Member


gradle compileJava
javap -cp build/classes/java/main com.eomcs.mylist.domain.Member



gradle compileJava
javap -cp build/classes/java/main com.eomcs.mylist.domain.Member

このクリップにコンパイルすると、
https://projectlombok.org/download

乗客名簿積み荷目録
JArファイルにどのような内容がありますか

java -jar lombok.jar


IDEを確認し、「Install/Update」をクリックします.

ドメインクラスへのLombokの適用
Lombokジェネレータ
https://projectlombok.org/features/constructor