[TIL] Day44 - 첨부파일 테이블 범용화 / 서비스 / 에러 처리

JIONY·2022년 11월 13일
1

TIL - Web BE - Spring Boot

목록 보기
20/20
post-thumbnail

첨부파일 테이블 범용화

게시판 첨부파일 정보를 DB에 저장할 때, 두 가지 방법을 사용할 수 있음. 첨부파일 테이블에 게시글 번호를 추가하면 해당 테이블을 게시판용으로만 사용할 수 있음. 연결 테이블을 추가하면, 첨부파일 테이블을 범용화할 수 있음. 이 때 파일 정보를 온전히 조회하려면 Join을 사용해야 함.

[테이블 연결 관계]

  • 첨부파일-회원 프로필 이미지/게시판 첨부파일
  • 회원 프로필 이미지-회원
  • 게시판 첨부파일-게시판


첨부파일 정보 조회

조회 구문

  • 첨부파일 테이블과 연결된 데이터만 조회하도록 inner join 사용
  • 해당 조회 구문은 자주 사용하므로 view로 등록해두는 것도 좋음
-- view 생성 구문
create view board_attachment_view as
select B.board_no, A.* from 
	board_attachment B inner join attachment A
	on B.attachment_no = A. attachment_no;
-- 게시글 1번의 첨부파일 조회 구문
select * from board_attachment_view
where board_no = 1;

컨트롤러

  • 게시글 등록 후 파일이 있다면 해당 파일을 등록(attachment)하고 파일을 저장한 뒤에 연결 테이블에 연결 정보를 저장(게시글 번호, 첨부파일 번호)하도록 처리

첨부파일 뷰에 첨부

Dao, DaoImpl

  • 게시글 번호로 첨부파일 테이블(AttachmentDto) 조회

컨트롤러

  • 게시글 상세화면 매핑에서 게시글 번호로 게시글 정보, 댓글 정보, 파일정보까지 조회해서 모델에 첨부


첨부파일 다운로드

  • 특정 주소에 소속되어 있도록 하면 안됨(ex. 유저 프로필은 다양한 화면에서 조회되어야 함)

AttachmentController 생성

  • 화면이 없는 컨트롤러이므로 @Controller+@Responsebody 어노테이션을 같이 써야 함
    • 화면을 반환하지 않는 컨트롤러에는 @RestController를 사용
  • 파일은 한 번에 하나만 다운로드할 수 있음
  • 다운로드는 다음 페이지가 없으므로 경로변수를 사용함
  • 다운로드는 폴더를 생성할 필요 없음
  • 공용주소 필수

view

  • 다음과 같은 주소를 사용해 클릭하면 파일을 다운받을 수 있는 버튼을 생성
    • <a href="/attachment/download/${attachmentDto.attachmentNo}">↓다운로드</a>


연쇄 삭제 처리

  • 게시글 삭제 시, 첨부파일 정보와 실제 파일도 삭제되도록 해야 함

첨부파일을 조회하려면 게시글 번호를 알아야 하는데, 게시글이 삭제된 이후에는 게시글 번호를 알 수 없음. 따라서 글 삭제 전에 삭제될 게시글의 첨부파일 정보를 조회해둬야 함
- List<AttachmentDto> attachmentList = attachmentDao.selectBoardAttachmentList(boardNo);

  • 첨부파일이 0~n개 있을 수 있음
    • 반복문 필요(0개면 반복을 안함)


서비스

  • Repository보다는 상위, Controller보다는 하위 개념
  • 단위 작업(트랜잭션)을 처리하는 도구
    • Controller 코드 압축 목적
    • 정해진 유형이 없음
  • Service 패키지에 Repository처럼 추상화 구조로 구현 (Service 인터페이스와 구현체 Implements 클래스를 생성)
  • 구현체를 @Service 어노테이션을 통해 Bean으로 등록
  • 중간에 에러 발생 시, 서비스가 실행한 부분 rollback 가능
  • 규칙이 있는 건 아니지만 insert, update, delete를 2회 이상 같은 컨트롤러에서 하면 서비스로 분리 권장

Controller 문제점

  • 코드가 비대해짐
  • 해결책: 아래 세 가지와 같이 Controller에서만 할 수 있는 작업을 두고 나머지를 줄이는 방향으로 수정
    • 파라미터 받기
    • 모델에 데이터 첨부
    • 세션 데이터 조회, 리다이렉션 등 웹 환경에서 할 수 있는 것

모듈화 후보

  • 게시글 등록
    • 번호 생성-새글/답글 구분-등록 과정을 하나의 트랜잭션으로 모듈화
  • 첨부파일 업로드
    • 파일 등록-저장-연결을 하나의 트랜잭션으로 모듈화
  • 연결 테이블 정보 등록
    • 파일 연결을 하나의 트랜잭션으로 모듈화

서비스화

컨트롤러에서 서비스로 분리할 코드를 옮겨오고, 컨트롤러에서는 서비스를 호출하는 방식으로 사용


예외처리

현재 에러 발생 시, 내장 서버에 있는 오류 페이지(Whitelabel)가 화면에 출력되고 있음. 오류페이지 재정의가 필요함

  • 인터셉터로도 할 수 있지만, 예외처리가 주 목적인 도구는 아니므로 컨트롤러의 오류를 간섭하는 객체 @ControllerAdvice를 사용

  • AOP 개념 쓰임

    • 관점 지향 프로그래밍. 어떤 로직을 핵심 vs. 부가적인 관점으로 나누고, 그 관점을 기준으로 각각 모듈화하겠다는 것. 여러 곳에서 반복해서 쓰는 코드들을 흩어진 관심사라고 하고, 이 흩어진 관심사들을 모듈화해 핵심적인 비즈니스 로직에서 분리, 재사용하겠다는 것이 AOP의 취지임
    • ex. @ControllerAdvice 어노테이션을 주석 처리하면, 원래대로 내장 에러 페이지가 나오게 됨

500 에러

ExceptionProcessor

  • error 패키지에 클래스 생성

@ControllerAdvice

  • @ControllerAdvice or @Rest~ 중 간섭하고 싶은 컨트롤러 종류에 맞게 어노테이션을 선택해 빈 등록
  • 대상 특정 필요
    • Controller 패키지에 있는 도구를 간섭
      • @ControllerAdvice(basePackages = {"패키지명"})
    • or @Controller 어노테이션 달고 있는 클래스 간섭
      • @ControllerAdvice(annotations = {Controller.class})
    • s가 붙으면 무조건 배열임(annotations = {})
      • 하나만 지정해도 되고 배열로 지정해도 됨

ExceptionHandler

  • 원하는 상황이 발생하면 자동으로 간섭해 실행할 메소드
  • 메소드는 컨트롤러와 동일한 구성 가능
  • 예외 객체 선언 가능(메소드를 try-catch의 catch 같이 쓸 수 있는 느낌)
  • 반환 시 view resolver의 영향을 받음
  • 여러 번 재정의해서 에러를 구분할 수 있음
@ControllerAdvice(basePackages = {"com.jw.springhome.controller"})
public class ExceptionProcessor {
	
	@ExceptionHandler(Exception.class)
	public String handle(Exception e) {
		return "error/exception"; //jsp경로
	}

	//에러 구분 가능
	@ExceptionHandler(TargetNotFoundException.class)
	public String handle2(Exception e){
		return "error/notfound";
	}
}


400 에러

400번대 에러는 서버에 아예 닿지 못했을 때 발생하므로 컨트롤러에서 처리가 불가능함

  • src/main/resources > public > error 폴더 생성
    • public: 컴파일 영향 받지 않음(자바가 관리할 수 없음), 완제품이 들어가는 폴더
    • jsp가 아니므로 html 파일만 생성 가능


400 vs. 500

  • 500번은 수집을 해야 함(내부 오류이므로 개발자 해결이 필요하기 때문)
    • 오류 정보를 기록하는 등의 추가 작업이 필요
    • 500번대 에러도 public/error 폴더에 만들 수 있음
    • @Controlleradvice, /error 둘 다 있으면 커스터마이징 페이지의 우선순위가 더 높음
      (스프링부트가 자동으로 구성한 기본 오류 핸들러는 /error를 먼저 찾고 없다면 Whitelabel을 제공)
  • 404는 사용자 잘못으로 발생하는 에러
    • 수집 불필요
    • 에러 페이지로 이동시키는 간단한 방법만 살펴봄

0개의 댓글