html에서 이미지를 보는 방법은 두 가지가 있다.

1.이미 렌더링된 이미지

2.클릭 시 다운로드

CODE가 있는데, 사이트 내에서 "공통"으로 뽑기 위해 테이블 자체를 둔 것이다.

CODE를 보고 상품관리에 등록된 거구나 등 유추해야 한다.

RID는 게시판의 몇번글에 대한 첨부파일이다.

파일 첨부는 coomon->entity->uploadfile

에서 DTO부터 먼저 만들어보자

UploadFileId

code

rid

store_filename

upload_filename

fsize

ftype

cdate

udate

이렇게 DTO를 만들고

UploadFileDAO

package com.kh.app.domain.common.dao;

import com.kh.app.domain.entity.UploadFile;

import java.util.List;
import java.util.Optional;

public interface UploadFileDAO {

  /**
   * 업로드 파일 등록 - 단건
   * @param uploadFile
   * @return 파일Id
   */
  Long addFile(UploadFile uploadFile);

  /**
   * 업로드 파일 등록 - 여러건
   * @param uploadFiles
   */
  void addFiles(List uploadFiles);

  /**
   * 업로드파일조회
   * @param code
   * @param rid
   * @return
   */
  List findFilesByCodeWithRid(String code,Long rid);

  /**
   * 첨부파일조회
   * @param uploadfileId
   * @return
   */
  Optional findFileByUploadFileId(Long uploadfileId);


  /**
   * 첨부파일 삭제 by uplaodfileId
   * @param uploadfileId 첨부파일아이디
   * @return 삭제한 레코드수
   */
  int deleteFileByUploadFildId(Long uploadfileId);

  /**
   * 첨부파일 삭제 By code, rid
   * @param code 첨부파일 분류코드
   * @param rid 첨부파일아이디
   * @return 삭제한 레코드수
   */
  int deleteFileByCodeWithRid(String code, Long rid);
}
package com.kh.app.domain.common.dao;

import com.kh.app.domain.entity.UploadFile;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.*;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;
import java.util.Optional;

@Slf4j
@Repository
@RequiredArgsConstructor
public class UploadFileDAOImpl implements UploadFileDAO{

  private final NamedParameterJdbcTemplate template;

  //업로드파일 등록-단건
  @Override
  public Long addFile(UploadFile uploadFile) {

    StringBuffer sql = makeAddFileSql();
    SqlParameterSource param = new BeanPropertySqlParameterSource(UploadFile.class);
    KeyHolder keyHolder = new GeneratedKeyHolder();
    template.update(sql.toString(),param,keyHolder,new String[]{"uploadfile_id"});

    return keyHolder.getKey().longValue();
  }

  //업로드파일 등록-여러건
  @Override
  public void addFiles(List uploadFiles) {

    StringBuffer sql = makeAddFileSql();
    if(uploadFiles.size() == 1){
      SqlParameterSource param = new BeanPropertySqlParameterSource(uploadFiles.get(0));
      template.update(sql.toString(),param);
    }else {
      SqlParameterSource[] params = SqlParameterSourceUtils.createBatch(uploadFiles);
      //배치 처리 : 여러건의 갱신작업을 한꺼번에 처리하므로 단건처리할때보다 성능이 좋다.
      template.batchUpdate(sql.toString(), params);
    }
  }

  private StringBuffer makeAddFileSql() {
    StringBuffer sql = new StringBuffer();
    sql.append("INSERT INTO uploadfile ( ");
    sql.append("  uploadfile_id, ");
    sql.append("  code, ");
    sql.append("  rid, ");
    sql.append("  store_filename, ");
    sql.append("  upload_filename, ");
    sql.append("  fsize, ");
    sql.append("  ftype ");
    sql.append(") VALUES ( ");
    sql.append("  uploadfile_uploadfile_id_seq.nextval, ");
    sql.append("  :code, ");
    sql.append("  :rid, ");
    sql.append("  :store_filename, ");
    sql.append("  :upload_filename, ");
    sql.append("  :fsize, ");
    sql.append("  :ftype ");
    sql.append(") ");
    return sql;
  }

  //조회
  @Override
  public List findFilesByCodeWithRid(String code, Long rid) {
    StringBuffer sql = new StringBuffer();

    sql.append("SELECT  ");
    sql.append("   uploadfile_id, ");
    sql.append("   code, ");
    sql.append("   rid,  ");
    sql.append("   store_filename, ");
    sql.append("   upload_filename,  ");
    sql.append("   fsize,  ");
    sql.append("   ftype,  ");
    sql.append("   cdate,  ");
    sql.append("   udate ");
    sql.append("  FROM  uploadfile  ");
    sql.append(" WHERE CODE = :code  ");
    sql.append("   AND RID = :rid  ");

    return template.query(
        sql.toString(),
        Map.of("code",code,"rid",rid),
        BeanPropertyRowMapper.newInstance(UploadFile.class));
  }

  //첨부파일 조회
  @Override
  public Optional findFileByUploadFileId(Long uploadfileId) {
    StringBuffer sql = new StringBuffer();
    sql.append(" select * ");
    sql.append("  from uploadfile ");
    sql.append(" where uploadfile_id = :uploadfile_id ");

    UploadFile uploadFile = null;
    try {
      Map param = Map.of("uploadfile_id", uploadfileId);
      uploadFile = template.queryForObject(sql.toString(),param,BeanPropertyRowMapper.newInstance(UploadFile.class));
      return Optional.of(uploadFile);
    }catch (EmptyResultDataAccessException e){
      return Optional.empty();
    }
  }

  // 첨부파일 삭제 by uplaodfileId
  @Override
  public int deleteFileByUploadFildId(Long uploadfileId) {
    StringBuffer sql = new StringBuffer();
    sql.append("delete from uploadfile ");
    sql.append(" where uploadfile_id = :uploadfile_id ");

    return template.update(sql.toString(), Map.of("uploadFile_id",uploadfileId));
  }

  // 첨부파일 삭제 by code, rid
  @Override
  public int deleteFileByCodeWithRid(String code, Long rid) {
    StringBuffer sql = new StringBuffer();
    sql.append("delete from uploadfile ");
    sql.append(" where code = :code ");
    sql.append("   and rid = :rid ");

    return template.update(sql.toString(),Map.of("code",code,"rid",rid));
  }
}

SqlParameterSource[] params = SqlParameterSourceUtils.createBatch(uploadFiles);는 uploadfile의 정보를 배열로 담은 것이다.

template.batchUpdate(sql.toString(), params);이건 배열에 담긴 걸 한 꺼번에 처리한다는 뜻이다.

배치처리란 insert문 여러 개를 한 꺼번에 쏘는 것이다.

이번엔 Test를 할 차례다.

ctrl+shift+T로 구조를 똑같게 테스트 환경을 만들 수 있다

@SpringBootTest

UploadDAOImplTest {
  @Autowired
  private UploadFileDAO uploadFileDAO
    
 @Test
 @Displayname("단건 첨부")   
  
}

IOC는 개발자가 직접 객체를 생성하지 않고, 프레임워크가 직접 생성하는 객체다.

DI는 private UploadFileDAO uploadFileDAO즉 DAO에 담긴 객체를 내게 달라는 뜻이다.

@RequiredArgsConstrutor는

final 생성자를 재료로 삼아서, 매개변수를 만들어 준다.

그렇게 되면 객체 연관관계 , 즉 sql의 pk,fk와 같이 app같에도 객체와 객체사이 참조가 되버린다.

여기선 uploadFileDAOImpl과 NamedParameterJDBCTemplate이 그 관계다.

insert into code (code_id,decode,pcode_id,useyn) values('F01','첨부파일',null,'Y');
insert into code (code_id,decode,pcode_id,useyn) values('F010301','상품관리_일반','F01','Y');
insert into code (code_id,decode,pcode_id,useyn) values('F010302','상품관리_이미지','F01','Y');

F01은 파일 첨부다.

스프링프레임이 관리하는 객체를 Bean이라고 한다.

이제 SaveForm에서

private List<MultipartFile> attachFiles; // 일반파일

private List<MultipartFile> imageFiles; // 이미지파일 이렇게 해서 이미지,파일을 받을 수 있다.

단건으로 할려면

MulipartFile attachFile로 하면 됨.

그럼 saveform요청메세지 body에 담겨져 온다.

multipartFileTouploadFile

여기서 AttachfileType aa = AttachFileType.F010301

로 해서 이넘 타입의 상수 값을 가질 수 있다 .

여기서 aa앞에 있는 AttachfileType의 값만 소환 가능.

Enum은 한정된 값을 정한 타입이다. ex)요일,성별 등 정해진 값.

@Transaction은 논리적 최소 단위다 2 or not 즉 2개의 로직이 실행되지않으면 아예 실행안되는 것이다.

<div><label for="">일반첨부</label><input type="file"></div>

여기서 파일 여러 개 추가 할려면

<div><label for="">일반첨부</label><input type="file" multiple></div>

이렇게 하면 된다.

 

'HTTP 웹 기본 지식' 카테고리의 다른 글

네트워크 상에서 데이터의 이동 이해하기  (0) 2023.05.29
HTTP 1.1/2.0/3.0  (0) 2023.04.21
TCP/UDP  (0) 2023.04.20
IP(인터넷 프로토콜)  (0) 2023.04.13
인터넷에서 컴퓨터 둘은 어떻게 통신할까?  (0) 2023.04.08

+ Recent posts