스프링은 EJB의 무겁고 복잡한 플랫폼에서 벗어나 POJO기반의 경량화된 개발 환경을 제공하는 오픈소스 프레임워크

 

좋은 객체 지향 설계의 5가지 원칙(SOLID)

 

SOLID

-SRP : 단일 책임원칙(Single Responsibility Principle)

한클래스는 하나의 책임만 가져야 한다.

중요한 기준은 변경! 변경이 있을때 파급효과 적으면 단일 책침 원칙을 잘 따른것!

 

-OCP: 개방-폐쇄의 원칙(Open/Closed Principle)

소프트웨어 요소는 확장에는 열려있고 변경에는 닫혀있어야 한다.

다형성 활용!

 

-LSP: 리스코프 치환 원칙(Liskov Substitution Principle)

프로그램의 객체는 프로그램의 정확성을 깨지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다

 

-ISP: 인터페이스 분리 원칙(Interface Segregation Principle)

특정 클라이언트를 위한 여러개의 인터페이스가 범용 인터페이스 하나보다 낫다

인터페이스가 명확해지고, 대체 가능성이 높아진다

 

-DIP: 의존관계 역전 원칙(Dependency Inversion Principle)

구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻

역할에 의존하게 해야한다

 

-----------------------------------------------------------------------------------

 

Bean Validation은 특정한 구현체가 아니라 Bean Validation 2.0이라는 기술 표준이며 검증 애노테이션과 여러 인터페이스의 모음이다. 

 

Bean Validation 의존관계 추가

 

build.gradle

implementation 'org.springframework.boot:spring-boot-starter-validation'

spring-boot-starter-validation을 의존관계를 추가하면 라이브러리가 추가된다.

 

@NotBlank 빈값 + 공백만 있는 경우를 허용하지 않는다.
@NotNull null을 허용하지 않는다.
@Range(min=?, max=?) ?에 숫자를 넣으며 범위 안의 값이어야 한다.
@Max(?) 최대 ? 까지만 허용된다.

 

스프링 부트는 spring-boot-starter-validation 라이브러리를 넣으면 자동으로 Bean Validator를 인지하고 스프링에 통합

 

스프링 부트는 자동으로 글로벌 Validator로 등록한다.

LocalValidatorFactoryBean 을 글로벌 Validator로 등록한다. 이 Validator는 @NotNull 같은 애노테이션을 보고 검증을 수행한다. 이렇게 글로벌 Validator가 적용되어 있기 때문에, @Valid , @Validated 만 적용하면 된다.

검증 오류가 발생하면, FieldError , ObjectError 를 생성해서 BindingResult 에 담아준다.

하지만 직접 글로벌 Validator를 직접 등록하면 스프링 부트는 Bean Validator를 글로벌 Validator 로 등록하지 않는다.

 

@Bean Validation은 등록할때와 수정할때 요구사항이 다를수있어 이를 해결하기 위해 groups, Form 전송 객체 분리 를 사용한다.

 

BeanValidation groups 기능 

 

인터페이스를 생성하고 어노테이션에 groups를 추가한다.

groups는 실무에서 잘 사용하지 않는다고 한다.

등록시 폼에서 전달하는 데이터가 Item 도메인 객체와 딱 맞지 않기 때문이다.

 

 SaveCheck 인터페이스

package hello.itemservice.domain.item;
    public interface SaveCheck {
    }

 

groups 사용

 @NotBlank(groups = {SaveCheck.class})
     private String itemName;

 

Controller에 SaveCheck Groups적용

@PostMapping("/add")
public String addItemV2(@Validated(SaveCheck.class) @ModelAttribute Item item,
BindingResult bindingResult, RedirectAttributes redirectAttributes) {
   //...
}

 

 

Form 전송 객체 분리

 

폼데이터 잔달에 Item 도메인 객체 사용

HTML Form -> Item -> Controller -> Item -> Repository

장점: Item 도메인 객체를 컨트롤러, 리포지토리 까지 직접 전달해서 중간에 Item을 만드는 과정이 없어서 간단하다.

단점: 간단한 경우에만 적용할 수 있다. 수정시 검증이 중복될 수 있고, groups를 사용해야 한다.

 

 

폼 데이터 전달을 위한 별도의 객체 사용

HTML Form -> ItemSaveForm -> Controller -> Item 생성 -> Repository

 

장점: 전송하는 폼 데이터가 복잡해도 거기에 맞춘 별도의 폼 객체를 사용해서 데이터를 전달 받을 수 있다. 보통 등록과, 수정용으로 별도의 폼 객체를 만들기 때문에 검증이 중복되지 않는다.

단점: 폼 데이터를 기반으로 컨트롤러에서 Item 객체를 생성하는 변환 과정이 추가된다.

 

 

저장과 수정의 폼을 분리해서 사용한다.

 

Controller 예시

public String addItem(@Validated @ModelAttribute("item") ItemSaveForm form,
BindingResult bindingResult, RedirectAttributes redirectAttributes) {
    //...
}

ItemSaveForm 를 받아오고 @ModelAttribute("item") 를 통해 item이란 명으로 바꿔준다. 

 

 

 

@ModelAttribute vs @RequestBody

HTTP 요청 파리미터를 처리하는 @ModelAttribute 는 각각의 필드 단위로 세밀하게 적용도어서 특정 필드에 타입이 맞지 않는 오류가 발생해도 나머지 필드는 정상 처리할 수 있다.

HttpMessageConverter는 @ModelAttribute와 다르게 각각의 필드 단위로 적용되는 것이 아니라 전체 객체 단위로 적용된다.

 

@ModelAttribute 는 필드 단위로 정교하게 바인딩이 적용된다. 특정 필드가 바인딩 되지 않아도 나머지 필드는 정상 바인딩 되고, Validator를 사용한 검증도 적용할 수 있다.

@RequestBody 는 HttpMessageConverter 단계에서 JSON 데이터를 객체로 변경하지 못하면 이후 단계 자체가 진행되지 않고 예외가 발생한다. 컨트롤러도 호출되지 않고, Validator도 적용할 수 없다.

 

 

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard

 

스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 인프런 | 강의

웹 애플리케이션 개발에 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. MVC 2편에서는 MVC 1편의 핵심 원리와 구조 위에 실무 웹 개발에 필요한 모든 활용 기술들을 학습할 수 있

www.inflearn.com

 

'Spring' 카테고리의 다른 글

[Spring JPA] 엔티티 설계  (0) 2023.04.08
[Spring JPA] 어노테이션 정리  (0) 2023.04.05
[SpringBoot] 검증1-Validation  (0) 2023.03.30
[SpringBoot] 메시지 국제화  (0) 2023.03.28
스프링 JUnit5 어노테이션 정리  (0) 2022.12.06

+ Recent posts