D+60 - 파일 업로드 기능 구현.소프트삭제,하드삭제

Bku·2024년 3월 22일

학원 일기

목록 보기
58/67
post-thumbnail

검색 페이지 넘겨도 검색 유지

검색 결과가 여러 페이지일때 페이지를 넘기면 검색 된 내용의 다음 페이지가 아니라, 전체 정보의 다음 페이지로 넘어간다. 이걸 해결하기 위해선 url에 검색할 요소의 정보를 추가해주면 된다.

  <%--        TODO: 페이지번호 --%>
    <div class="d-flex justify-content-center"> <%--중앙정령 해주는 클래스 속성--%>
        <ul class="pagination">
            <li class="page-item ${(startPage+1==1)? 'disabled' : ''}">
                <a href="/basic/dept?page=${startPage-1}&size=${3}&dname=${dname}"<%--dname도 RequestParam으로 받았지만 두개만 사용 가능--%> class="page-link">Previous</a>
            </li>
            <%--todo 반복문 실행--%>
            <c:forEach var="data" begin="${startPage}" end="${endPage}">
                <li class="page-item ${(currentPage == data)? 'active':''}"><a class="page-link" href="/basic/dept?page=${data}&size=${3}&dname=${dname}">${data+1}</a><%-- 단순 반복일 경우 (요소를 반복해서 보여주는 것이 아닐경우) begin과 end가 필요하다.--%>
                </li><%-- 클릭하면 해당 페이지의 데이터가 뜨게 링크 걸어줘야함--%>
            </c:forEach>
            <li class="page-item ${(endPage+1==totalPages)? 'disabled' : ''}">
                <a href="/basic/dept?page=${endPage+1}&size=${3}&dname=${dname}" class="page-link" >Next</a>
            </li>
        </ul>
    </div>

파일 업로드 기능 구현

이미지를 업로드하는 방법은 2가지가 있다.

1) DB 에 파일을 업로드하는 방법과
2) 서버컴퓨터의 일정 폴더에 업로드하는 방법이 있음

DB 업로드를 진행하면 오라클 SQL 을 이용해서 간편하게 업로드가 가능하고, 수정/삭제 등 관리가 용이함
요즘은 DB 보다 가격이 싼 아마존 클라우드(AWS) 의 S3 공간을 임대해서 파일을 업로드하고 사용하기도 함 , 이때는 아마존에서 제공하는 함수를 이용해서 업로드 / 삭제를 진행함
이 예제에서는 과거부터 현재까지 이용되고 있는 DB 에 파일을 저장하는 방법으로 진행할 것이다.

설계

REST API

이미지를 업로드하거나 수정, 삭제 등을 할 때 사용할 URL이다.

이미지 자료형

이미지의 자료형은 BLOB이다.

소프트삭제를 위한 delete yn과 하드삭제를 위한 delete_time을 만들었다.

소프트삭제

실제 DB에서는 삭제하지 않고 화면에서만 삭제를 시켜 사용자로는 삭제를 시켰다고 생각하게 만들 수 있다. 개인정보는 삭제를 해도 법적으로 보관을 해야할 수 있기 때문에 이런 기능을 사용한다.

deleteYn 공통 속성 만들기

이 컬럼으로 삭제여부를 판단 한다. 소프트 삭제를 하면 y, 안했을때는 n값을 주어

select * from 테이블 where deleteYn = n

위 sql문을 이용해 n을 가지는 값만 보여줌으로 DB에서는 삭제를 하지 않아도 사용자는 볼 수 없게 만들 수 있다.

공통클래스 BaseTimeEntity2 코드

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity2 {

    private String insertTime;

    private String updateTime;

    private String deleteYn; // 소프트삭제용 속성 - 삭제가 됐으면 y 안됐으면 n을 뜨게 함
    // select * from 테이블 where deleteYn = n을 해주면 삭제는 안됐지만 화면에는 n만뜨게 하여 삭제된거처럼 볼수 있게 해준다.

    private String deleteTime;
    @PrePersist // jpa에서 insert가 실행되기 전에 실행하는 함수, 이 함수가 먼저 실행되고 insert문이 실행이된다.
    void OnPrePersist(){
        LocalDateTime localDateTime = LocalDateTime.now();
        DateTimeFormatter dateTimeFormatter
                = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        this.insertTime = localDateTime.format(dateTimeFormatter);

        this.deleteYn = "N";
    }

    @PreUpdate // jpa에서 update문이 실행되기 전에 실행되는 함수
    void OnPreUpdate(){
        LocalDateTime localDateTime = LocalDateTime.now();
        DateTimeFormatter dateTimeFormatter
                = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        this.updateTime = localDateTime.format(dateTimeFormatter);
        this.insertTime = this.updateTime;

        this.deleteYn= "N";
    }
}

insert와 update가 일어날때 deleteYn은 N값을 가지게 만들었다.

파일 업로드 Entity 클래스

업로드는 시퀀스를 사용하지 않고 다른 방법으로 구현할 것이라 시퀀스를 사용하지 않고 java의 uuid를 사용할 것이다.

uuid란 자바에서 문자열이 생성되는 것으로 세계에서 유일하게 생성이 되야한다. 그래서 절대 중복이 될 수 없다.

entity 코드

@Entity
@Table(name = "TB_FILE_DB")
@DynamicUpdate
@DynamicInsert
// todo : lombok 어노테이션
@NoArgsConstructor
@AllArgsConstructor
@ToString
// todo : soft delete jpa 어노테이션 - jpa 에서 soft delete를 편하게 할수 있도록 제공하는 어노테이션들이다.
@Where(clause = "DELETE_YN = 'N'") // 소프트 딜리트를 위한 조건절에 들어갈 내용을 넣어주는 어노테이션이다.
// N인 애들만 보여줄 것이므로 다음과 같이 했다.
@SQLDelete(sql = "UPDATE TB_FILE_DB " +
        "SET DELETE_YN = 'Y', DELETE_TIME=TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') " +
        "WHERE UUID = ?") // 소프트 삭제가 진행되면 진행할 대체 sql문을 적어주는 곳이다.
// 소프트 삭제시에는 delete가 아니고 update로 y값을 해주어야하기때문에 위와 같이 작성해준다.
public class FileDb extends BaseTimeEntity2 {

    @Id
    private String uuid; // 자바에서 생성할 기본키
    private String fileTitle;
    private String fileContent;
    private String fileName;

    @Lob // 컬럼에 이미지를 저장하는 DB자료형이 blob자료형이고, 자바에서는 byte를 DB에서 blob라고 해주는 역할을 한다.
    private byte[] fileData; // DB에서 blob 타입은 java에서는 byte로 해주면된다.
    private String fileUrl;

}

Where, SQLDelete,Lob 어노테이션이 새롭게 추가되었다.

  • Where : 소프트 딜리트를 한 후 결과를 조회할 조건절에 들어갈 내용을 넣어주는 어노테이션이다. N인 애들만 보여줄 것이므로 "DELETE_YN = 'N'" 값을 주었다.
  • SQLDelete : 소프트 삭제가 진행되면 진행할 대체 sql문을 적어주는 곳이다. 소프트 삭제시에는 delete가 아니고 update로 y값을 해주어야하기때문에
  • Lob : 컬럼에 이미지를 저장하는 DB자료형이 blob자료형이고, 스프링에서는 byte[]를 DB에서 blob라고 인식는 역할을 한다.
"UPDATE TB_FILE_DB 
SET DELETE_YN = 'Y', DELETE_TIME=TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') 
WHERE UUID = ?"

소프트 삭제가 되면 DELETE_YN는 Y가 되어야하고, 소프트 삭제가 된 시간이 입력되어야하므로 추가하는 것이다.

sql문을 entity클래스에 사용하는 이유

원래 DB는 Respository 파이들과 상호작용함으로 sql문도 repository문에 작성하는 것으로 알고있다. 하지만 SQLDelete은 entity클래스에 적어주는 것이었다.

왜 그런지를 생각해보니 이는 직접적인 sql문이 아니고 delete맵핑이 들어오면 이것을 delete문으로 인식하지 않고 update문으로 바꿔주는 역할을 하는 어노테이션이다. 그런데 우리는 삭제를 다 delete매핑으로 할거기 때문에 소프트매핑에 관련된 속성들만 걸러내서 update문으로 바꿔주고 나머지는 delete 문으로 제거를 해야한다.

그래서 repository에 이것을 사용하면 어느것에 update를 해야하는지 알 수 없기 때문에 소프트삭제관련된 속성들이 있는 클래스에만 어노테이션을 걸어 이것을 이 속성들에 대해 delete매핑이 들어오면 update로 바꿔준다.

파일 업로드 Service, Repository, Controller클래스

이 두 클래스는 페이지 구현했을때의 service, repository, Controller와 코드가 같다.

profile
기억보단 기록

0개의 댓글