쌓고 쌓다

[스프링 부트] Form 전송 객체 분리(검증 달리하기) - 30 본문

프로그래밍/spring

[스프링 부트] Form 전송 객체 분리(검증 달리하기) - 30

승민아 2023. 9. 14. 20:34

현재 게시글 등록과 수정시 전달하는 폼 데이터가 동일하다.

하지만. 폼에서 전달하는 데이터가 실무에서는 차이가 있다.

등록시에는 약관과 같은 추가적인 정보를 받을 수 있으며,

등록시와 다르게 수정시 다른 BeanValidation을 적용할 수도 있다. (EX. 게시글 수정시 내용은 없어도 괜찮음)

 

그래서 폼 데이터와 동일한 데이터를 전달 받을 별도의 객체를 만들어서 받는것이 좋다.

 

전달 받은 별도의 객체의 데이터를 통해 컨트롤러에서 게시글 객체를 생성하자.

원래의 폼 데이터 처리 방식과 비교해서 생각해보면 게시글 객체를 또 다시 만드는 이유를 알 수 있다.

 

기존 방식 - 도메인 객체 그대로 사용

HTML Form -> Poster -> Controller -> Poster -> Repository

Poster를 도메인 객체를 컨트롤러에서 리포지토리까지 그대로 전달하여 과정이 편함.
하지만 검증 방식을 달리 적용하길 원하는 상황이 온다면 groups를 사용해야함.

 

변경 방식 - 맞춤 도메인 객체를 사용

HTML Form -> PosterSaveObject -> Controller -> Poster(생성) -> Repository

맞춤 폼 객체를 만들어 사용하여 데이터를 받으며 데이터 검증에 용이함.
하지만 별도의 Poster 객체로 만드는 과정이 필요하다.

 

생각해보면 게시글의 PK인 id는 게시글 등록 전까지는 없는 데이터이며

수정시에 게시글의 PK가 존재한다.

즉, 등록과 수정에 데이터 차이가 있다는 것이다. 그래서 별도의 객체로 전달 받자.

 

등록시에는 PosterSaveForm

수정시에는 PosterUpdateForm을 사용하자.

 

PosterSaveForm

@Data
public class PosterSaveForm {

    @NotBlank
    private String title;

    @NotBlank
    private String writer;

    @NotBlank
    private String content;

    @NotNull
    @Range(min = 100, max = 250)
    private Long height;

    @NotNull
    @Range(min=50, max = 200)
    private Long weight;

    @NotNull
    private Boolean fix;
}

게시글 저장 Form에 바인딩될 클래스이다.

 

PosterUpdateForm

@Data
public class PosterUpdateForm {

    @NotBlank
    private String title;

    @NotBlank
    private String writer;

    @NotBlank
    private String content;

    private Long height;

    private Long weight;

    @NotNull
    private Boolean fix;
}

게시글 수정 Form에 바인딩될 클래스이다.

게시글 작성과 달리 키(height)와 몸무게(Weight)는 검증하지 않기에

값이 없어도 된다.

 

이렇게 Form 객체를 달리 만들어서 작성과 수정때 Validation을 달리할 수 있다.

 

PosterController

    @PostMapping("/posters/{category}")
    public String write(@PathVariable("category") Category category,
                        @Validated @ModelAttribute(name = "poster") PosterSaveForm form, BindingResult bindingResult) throws IOException {

        if(bindingResult.hasErrors()) {
            return "posters/createPosterForm";
        }

        Poster poster = new Poster();
        poster.setCategory(category);
        poster.setTitle(form.getTitle());
        poster.setWriter(form.getWriter());
        poster.setContent(form.getContent());
        poster.setHeight(form.getHeight());
        poster.setWeight(form.getWeight());
        poster.setFix(form.getFix());
        
        posterService.write(poster);
        ...
    }

 

파라미터에 바인딩 되는 클래스를 PosterSaveForm으로 변경했으며,

@ModelAttribute("poster")로 model에 담길 데이터의 KeyAttribute를 "poster"로 지정했다.

그리고 폼 객체 PosterSaveForm을 기준으로 Poster 객체를 생성해준다.

 

Poster 객체의 검증은 사용하지 않으므로 어노테이션들을 지워도 괜찮다.

@Entity
@Getter
@Setter
@ToString
public class Poster {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String writer;
    private String content;
    private LocalDateTime regdate;
    private Long height;
    private Long weight;

    @JsonBackReference
    @OneToMany(mappedBy = "poster", cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
    private List<UploadFile> imgFiles = new ArrayList<>();

    @Enumerated(EnumType.STRING)
    private Category category;

    private Boolean fix;

    @Column(name="comment_cnt")
    private int commentCnt;
}

 

 

Form 객체 분리 검증 결과

게시글 등록시 키 필드의 유효성 검사를 진행했지만

게시글 수정시 키 필드의 유효성 검사는 진행하지 않는다.

 

+ 앞서 등록과 수정시 사용하는 뷰 템플릿 페이지를 똑같은데 굳이 분리를 왜 하나 싶었는데

유지보수 관점에서 좋다..!

Comments