공부/Spring

[Spring] 회원관리 연습 웹 프로젝트 - 1 / 스프링 폼, 스프링 유효성 @Valid

thegreatjy 2023. 12. 30. 02:15
728x90

spring framework를 사용하여 회원 관리 웹 프로젝트를 만들겠다.
공부한 내용을 정리하며 프로젝트를 진행하겠다.

기능 목표

  • 스프링 폼 사용
  • 스프링 시큐리티 적용
  • 스프링 유효성 검사
  • 에러 화면 처리

회원가입 폼 화면 (스프링 폼)

  • 폼에서 전달되는 파라미터 이름으로 setter()메서드를 작성한 클래스의 프로퍼티(멤버변수)에 접근할 수 있다.
  • jsp 위에 스프링 폼 태그 라이브러리를 선언해야 한다.
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
  • modelAttribute 속성은 input, hidden 태그들이 커맨드 객체의 프로퍼티(멤버변수)에 접근할 수 있게 한다.
  • action 속성의 기본값은 현재 요청 url, method 속성 기본값은 post.
  1. 자바 클래스 생성
@Getter
@Setter
@ToString
public class MemberDTO {
    private String email;
    private String password;
    private String name;
    private Integer age;
    private String mobile;
}
  • setter()가 있어야 한다.
  1. jsp - 스프링 폼 태그
<%--@elvariable id="memberDTO" type="kr.co.chunjae.domain.MemberDTO"--%>
    <form:form modelAttribute="memberDTO" method="post" action="/save">
        <p>아이디 : <form:input path="email" name="email" /></p>
        <p>비밀번호 : <form:password path="password" name="password"/></p>
        <p>이름 : <form:input path="name" name="name" /></p>
        <p>나이 : <form:input path="age" name="age" /></p>
        <p>전화번호 : <form:input path="mobile" name="mobile" /></p>
        <input type="submit" value="가입하기"/>
        <input type="reset" value="다시작성"/>
    </form:form>
  • 위에 애너테이션 주석을 작성하면 path를 입력할 때, modelAttribute의 커맨드 객체에 빨간색이 지워지며, 자동완성이 된다! (intellij)
  • modelAttribute 속성값은 controller의 model.addAttribute(”키”, “밸류”);에서 키 값이랑 일치시켜야 한다.
  • submit 버튼은 일반 input 태그를 사용한다.
  1. controller
@GetMapping("/save")
    public String saveForm(Model model){
        MemberDTO memberDTO = new MemberDTO();
        model.addAttribute("memberDTO", memberDTO);
        return "save";
    }
  • 객체를 생성해준 후, model에 추가하여 jsp 화면을 출력해야 한다.
  • model.addAttribute(”키”, “값”);에서 키 값과 jsp 스프링 폼 태그에서의 modelAttribute 값이 동일해야 커맨드 객체에 맵핑이 된다.

회원가입 처리

@ModelAttribute

  • 폼 페이지에서 전달된 파라미터 값이 @ModelAttribute가 설정한 커맨드 객체에 자동으로 할당된다. (= 데이터 바인딩) 그리고 해당 커맨드 객체의 프로퍼리 값을 뷰 페이지에 출력한다.
  1. 파라미터 @ModelAttribute
  • 커맨드 객체에 맵핑되어 프로퍼티에 데이터를 채운다.
@PostMapping("/save")
    public String save(@ModelAttribute("member") MemberDTO memberDTO, Model model){
        log.info(memberDTO);
        int result = memberService.save(memberDTO);
        log.info(result);

        if(result == 1){ // 회원가입 성공
            return "redirect:/";
        }else{
            model.addAttribute("msg", "다시 시도해 주세요.");
            return "save";
        }
    }
  • @ModelAttribute(”키”)의 키 값은 jsp form 태그의 modelAttribute 값과 동일해야 한다.
  1. 메서드 @ModelAttribute
  • 뷰 페이지에서 공통으로 사용할 수 있는 커맨드 객체의 프로퍼티(멤버변수, 필드)를 설정하여 뷰 페이지에 출력한다.
  • 웹 요청 url을 처리할 수 없지만, 먼저 호출되며 컨트롤러 안에 여러 개 만들 수 있다.
  • controller
@ModelAttribute("msg")
public String setMsg(){
    return "회원가입 페이지";
}
  • jsp
${msg}

선택적 바인딩

@InitBinder

  • setAllowedFields() 메서드 : 폼 파라미터 이름들을 선택하여 데이터 바인딩을 허용한다.
  • setDisallowedFields() 메서드 : 데이터 바인딩을 허용하지 않는다.
  • setAllowedFields
@InitBinder
public void initBinder(WebDataBinder binder){
    binder.setAllowedFields("id", "password", "city"); 
    // 폼 태그의 파라미터를 선택적 바인딩 허용
}
  • setDisallowedFields
@InitBinder
public void initBinder(WebDataBinder binder){
    binder.setDisallowedFields("hobby"); 
    // 폼 태그의 파라미터를 선택적 바인딩 방지
}

스프링 유효성 검사

  • 자바 유효성 검사 : JSR-380
    • 필드에 대한 유효성 검사 제약사항 애너테이션을 선언
  • Validator 인터페이스 구현
    • Validator 인스턴스를 사용하여 해당 속성값의 유효성 검사를 수행
    • Validator 인터페이스는 애플리케이션의 모든 계층에서 유효성 검증을 위해 사용할 수 있다.
  1. pom.xml 의존성 라이브러리 등록
<!-- Validation -->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.4.3.Final</version>
        </dependency>
  1. servlet-context.xml에 컨트롤러 맵핑 등록
<annotation-driven />

제약 사항을 위반하여 오류가 발생하면 오류 메세지를 출력하도록 만든다.

JSR-380 사용한 유효성 검사

  • 도메인 클래스의 프로퍼티(멤버 변수), 즉 필드에 대해 유효성 검사의 제약 사항 애너테이션을 선언하여 해당 필드 값이 올바른지 검사한다.
  • JSR-380 애너테이션은 Hibernate Validator가 제공하는 애너테이션을 그대로 따른다. 즉, 개발자는 이미 정해진 규격에 맞춰서 유효성 검사를 수행해야 한다.
  • 방법
    1. 도메인 객체에 @JSR-380 제약 사항 애너테이션 선언, 오류 메세지 설정.
    2. 요청 처리 메서드(컨트롤러 내 메서드)의 매개변수에 @Valid 선언
    3. 뷰 페이지에 폼 태그 라이브러리 중 form:errors 태그를 사용하여 오류 메세지 출력

회원 객체의 필드에 제약 사항 애너테이션 적용

@Getter
@Setter
@ToString
public class MemberDTO {
    @NotNull
    @Size(min=1, max=50)
    @Pattern(regexp = "^[a-zA-Z0-9+-_.]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$")
    private String email;
    @Size(min=1, max=50, message = "1자 이상 50자 이하를 입력해 주세요.")
    private String password;
    @Size(min=1, max=30)
    private String name;
    @Min(value=1)
    private Integer age;
    @Size(max=30)
    private String mobile;
}

참고 : https://www.baeldung.com/java-validation

  • DecimalMin 과 Min 의 차이
    • @DecimalMin(value=”99999”) : 문자열로 값을 제한 → 더 큰 값을 지정할 수 있다.
    • @Min(value=9999) : int 숫자로 값을 제한
  • @Size(min=0, max=10) : 문자열의 길이를 제한
  • @NotNull, @NotEmpty
    • @NotNull : null이 아니어야 한다.
    • @NotEmpty : null 혹은 빈 문자열이 아니어야 한다.String, Collection, Map or Array 에 적용할 수 있다.
  • Pattern(regexp=”정규식”) : 정규 표현식 패턴과 일치해야 한다.

사용자 정의 오류 메세지 설정

  1. message 속성을 사용
@Size(min=1, max=50, message = "1자 이상 50자 이하를 입력해 주세요.")
private String password;
  1. 메세지 리소스 파일(messages.properties)를 만듦
  • 애너테이션.커맨드객체이름.필드이름 = 오류 메세지
    • 커맨드 객체 이름은 modelAttribute(”커맨드객체이름”)과 동일해야 한다.
    • 즉, jsp에서 <form:form modelAttribute=”여기”>
    • 컨트롤러 내 메서드의 파라미터 @Valid @ModelAttribute(”여기”)
    • 메세지 리소스 파일의 애너테이션이름.여기.필드명
    • 이 동일해야 한다.
  • 애너테이션 = 오류메세지
// src/main/resources/messages.properties 파일 생성

NotNull.member.email = \uC774\uBA54\uC77C\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694.
Size.member.email = 1\uC790 \uC774\uC0C1 50\uC790 \uC774\uD558\uB85C \uC785\uB825\uD574 \uC8FC\uC138\uC694.
Pattern.member.email = \uC774\uBA54\uC77C \uD615\uC2DD\uC744 \uB9DE\uCD94\uC5B4 \uC8FC\uC138\uC694.
Size.member.password = 1\uC790 \uC774\uC0C1 50\uC790 \uC774\uD558\uB85C \uC785\uB825\uD574 \uC8FC\uC138\uC694.
Size.member.name = 1\uC790 \uC774\uC0C1 30\uC790 \uC774\uD558\uB85C \uC785\uB825\uD574 \uC8FC\uC138\uC694.
Min.member.age = 1 \uC774\uC0C1\uC758 \uC22B\uC790\uB97C \uC785\uB825\uD574 \uC8FC\uC138\uC694.
Size.member.mobile = 1\uC790 \uC774\uC0C1 50\uC790 \uC774\uD558\uB85C \uC785\uB825\uD574 \uC8FC\uC138\uC694.
  • 인텔리제이 setting>plugin>unicode escaper 설치하면 편리하게 한글을 유니코드로 변경할 수 있다.
  • servlet-context.xml에 빈 등록을 해야 한다.
// servlet-context.xml
<!-- 유효성 검사 메세지 -->
    <beans:bean id= "messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <beans:property name="basename" value="messages"/>
        <beans:property name="defaultEncoding" value="UTF-8" />
    </beans:bean>

컨트롤러의 요청 처리 메서드 내 매개변수 @Valid

  • 폼 페이지에서 입력된 값이 커맨드 객체로 맵핑될 때, 유효성 검사가 실행된다.
  • 오류가 발생하면 Errors 객체에 오류 결과 값이 저장된다.
  • Errors 혹은 BindingResult 는 바인딩 받는 객체 바로 다음에 선언!!!!!!
import org.springframework.validation.Errors;
import javax.validation.Valid;

@PostMapping("/save")
  public String save(@Valid @ModelAttribute("member") MemberDTO memberDTO, Errors errors, Model model){
      // 유효성 검사 오류 결과 확인
      if(errors.hasErrors()){
          return "save";
      }
}

form:errors 태그로 오류 메세지 출력

  • message 속성에 개발자가 정의한 오류 메세지를 출력하거나, 기본 메세지를 출력한다.
  • <form:errors path = “필드이름” /> : 해당 필드 이름에 연관된 모든 오류를 출력한다.
  • <form:errors path = “*” /> : 모든 오류를 출력한다.
// save.jsp

<%--@elvariable id="member" type="kr.co.chunjae.domain.MemberDTO"--%>
<form:form modelAttribute="member" method="post" action="/member/save">
    <p>아이디 : <form:input path="email" name="email" /> <form:errors path="email"/></p>
</form:form>

= trouble shooting =

  • 에러 1

Resolved [org.springframework.validation.BindException 에러 발생

  • 해결방법
    • 버전 변경 (이건 영향이 없어보인다.)
    • <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>7.0.4.Final</version>
    • 컨트롤러의 요청 처리 메서드의 파라미터에서 Errors 혹은 BindingResult 순서를 모델 바로 뒤로 바꾼다. (어이없네 예민하네)
    • @PostMapping("/save") public String save(@Valid @ModelAttribute("member") MemberDTO memberDTO, Errors errors, Model model){} // 원래 MemberDTO memberDTO, Model model, Errors errors 순서이었다.
[https://dmaolon00.tistory.com/entry/Error-해결-orgspringframeworkvalidationBindException-orgspringframeworkval](https://dmaolon00.tistory.com/entry/Error-%ED%95%B4%EA%B2%B0-orgspringframeworkvalidationBindException-orgspringframeworkval)
  • 에러 2
    • 메세지 리소스 파일의 오류 메세지가 나오지 않고 기본 메세지가 출력됨.
  • 해결방법
    • jsp, 컨트롤러, 메세지 리소스 파일의 커맨드 객체 이름을 동일하게 맞춘다.
    • 즉, jsp에서 <form:form modelAttribute=”여기”>
    • 컨트롤러 내 메서드의 파라미터 @Valid @ModelAttribute(”여기”)
    • 메세지 리소스 파일의 애너테이션이름.여기.필드명
    • 이 동일해야 한다.

= 깃허브에서 전체 코드 확인하기 =
https://github.com/thegreatjy/ChunjaeFullStack/tree/main/Spring_Study/memberFrameWorkPractice

728x90