데이터 유효성 검사
애플리케이션에서 사용자가 입력한 데이터 또는 외부로부터 받은 데이터의 유효성을 검사하는 기능
유효성 검사 방법
유효성 검사를 하는 방법은 프론트(웹 브라우저, 사용자, 클라이언트)에서 하는 방법과 서버(백) 에서 하는 방법 2가지가 존재한다
- 프론트(웹 브라우저, 사용자, 클라이언트)
- HTML, JSP 페이지에서 Javascript를 통해 사용자의 입력 값을 검사함
- 네트워크(트래픽) 낭비를 방지함
- 서버의 부하가 적어짐
- 서버(백, 개발자)
- 아무리 프론트에서 철저히 유효성 검사를 하더라도 잘못된 URL 호출을 막기엔 한계가 있기 때문에 잘못된 URL 호출에 대해 유효성 검사가 반드시 필요함
- 즉, Javascript로 유효성 검사를 하는 것에는 한계가 있기 때문에 JAVA로 유효성 검사를 해야함
실습
test.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>유효성 검사 예제</title>
</head>
<body>
<form action="test" method="POST">
ID <input type="text" name="id" value="${ apple }"> <br>
PW <input type="password" name="password"> <br>
<input type="submit">
</form>
</body>
</html>
위의 View(JSP)를 보고 Controller에서 지켜줘야 할 것
- 커맨드 객체 : 멤버변수 이름이 각각 id, password로 지정
- model, addAttribute() 수행 시 id 값 이름을 apple 지정
- @RequestMapping에 method를 POST로 지정
기존의 유효성 검사 방식은 아래와 같이 Controller 에서 직접 진행하였음
@RequestMapping("test")
public String test(VO vo, Model model) {
if(vo.getId() == null || vo.getId().equals("") || vo.getId().isEmpty() || vo.getId().isBlank()) {
// 생략
}
if(vo.getPassword().length() <= 5) {
// 생략
}
model.addAttribute("apple", vo.getId());
return "test";
}
하지만 부트에서는 기본적인 유효성 검사(null, 길이, ...)는 흔해서 부트에서 지원해줌
따라서, Validator라는 유효성을 검사하는 클래스를 생성해야 한다
VOValidator.java
public class VOValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return VO.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
VO vo = (VO)target;
String id = vo.getId();
if(id == null || id.isEmpty() || id.isBlank() || id.trim().isBlank()) {
System.out.println("로그 : id값이 올바르지 않습니다.");
errors.rejectValue("id", "id값 없음");
}
String password = vo.getPassword();
if(password == null || password.isEmpty() || password.isBlank() || password.trim().isBlank()) {
System.out.println("로그 : password값이 올바르지 않습니다.");
errors.rejectValue("password", "password값 없음");
}
}
}
메소드 강제성을 부여 받기 위해 implements Validator를 추가한다
support 메소드
- 유효성 검사할 객체의 클래스 정보를 반환
validate 메소드
- target : 유효성 검사를 진행할 객체(현재는 VO 객체가 들어옴)
- error : 검증이 통과되지 못한 경우, 왜 통과가 안되었는지를 반환하는 객체
- 유효성 검사 로직을 작성 (현재 검사해야할 것은 id, password 공백 검사)
CTRL.java
@RequestMapping("test")
public String test(VO vo, BindingResult br, Model model) {
VOValidator voV = new VOValidator();
voV.validate(vo, br);
if(br.hasErrors()) {
System.out.println("로그 : 에러 발생함! ");
}
model.addAttribute("apple", vo.getId());
return "test";
}
결과값을 받을 BlindingResult 객체를 커맨드 객체로 선언하고 br이 존재한다면 에러가 발생했다는 로그 출력
발생하지 않았다면 model 객체에 VO의 id 값을 저장하여 test.jsp로 이동시킴
하지만, 지금 위의 CTRL.java 코드는 개발자가 직접 new를 하고 있기 때문에 유지보수에 불리하게 사용되고 있다
따라서 자동으로 new를 해주기 위해서 의존성을 주입해줘야 한다
build.gradle
dependencies {
//...
implementation 'org.springframework.boot:spring-boot-starter-validation'
}
다음으로 위의 코드를 수정하는 방법이 2가지가 존재한다
첫번째 방법은 컨트롤러가 동작했을 때 Validator 가 이미 new 되었을 수 있도록 메소드를 생성하는 방법이다
CTRL.java
@RequestMapping("test")
public String test(@Valid VO vo, BindingResult br, Model model) {
if(br.hasErrors()) {
System.out.println("발생한 에러 목록");
System.out.println(br.getAllErrors());
if(br.getFieldError("id") != null) { // id에서 Error가 발생했다는 의미
System.out.println(br.getFieldError("id").getCode());
}
if(br.getFieldError("password") != null) { // pw에서 Error가 발생했다는 의미
System.out.println(br.getFieldError("password").getCode());
}
}
model.addAttribute("apple", vo.getId());
return "test";
}
@InitBinder
protected void initBinder(WebDataBinder wdb) {
wdb.setValidator(new VOValidator());
}
먼저 initBinder 메소드를 작성한 후 @InitBinder 를 작성하므로써 컨트롤러가 동작했을 때 Validator가 이미 new 되있도록 하고 유효성 검사를 실행할 객체인 VO에 @Valid 를 작성하여 사용하는 방법이다
위와 같이 기존에는 이런 방식을 자주 사용했지만 요즘에는 @ 을 활용하여 아래와 같이 많이 사용한다
두번째 방법은 VOValidate 코드를 VO로 옮기는 방법이다
(Validate 가 수행하는 일을 @을 통해 끌고 오는 것임)
VO.java
@Data
public class VO {
@NotNull(message="id값 Null")
@NotEmpty(message="id값 Empty")
@Size(min=5, max=100, message="id값 6이상 100이하 가능")
private String id;
@NotNull(message="password값 Null")
@NotEmpty(message="password값 Empty")
private String password;
}
CTRL.java
@RequestMapping("test")
public String test(@Valid VO vo, BindingResult br, Model model) {
if(br.hasErrors()) {
System.out.println("발생한 에러 목록");
System.out.println(br.getAllErrors());
if(br.getFieldError("id") != null) { // id에서 Error가 발생했다는 의미
System.out.println(br.getFieldError("id").getDefaultMessage());
}
if(br.getFieldError("password") != null) { // pw에서 Error가 발생했다는 의미
System.out.println(br.getFieldError("password").getDefaultMessage());
}
}
model.addAttribute("apple", vo.getId());
return "test";
}
getDefaultMessage() 를 통해 어노테이션으로 설정한 값을 볼 수 있도록 작성한다
'Spring Boot' 카테고리의 다른 글
[Spring Boot] 예외 처리 미루기 (MVC 패턴) (2) | 2023.09.20 |
---|---|
[Spring Boot] DB 연결 방법 (0) | 2023.09.18 |
[Spring Boot] 참조 변수 (1) | 2023.09.14 |
[Spring Boot] 스프링 부트 매번 해야하는 설정 및 정적 리소스 실습 (2) | 2023.09.14 |
[Spring Boot] Lombok (0) | 2023.09.14 |