Spring/Maven Project

Spring에 Server-Side Validation 처리

carrotweb 2023. 2. 12. 06:19
728x90
반응형

웹 서버에서 전송(Submit)된 게시물 내용(폼(form) 데이터)을 처리하거나 데이터베이스에 등록하기 전에 폼(form) 데이터의 값이 유효한지(데이터 타입이나 길이, 범위, 패턴이 맞는지) 검사하는 것을 Server-Side Validation이라고 합니다.

 

개발된 것을 보면 대부분 클라이언트(웹 브러우저)에서만 유효성 검사를 하는 경우가 많습니다. 그 이유는 사용자가 입력한 데이터에 대한 피드백을 바로 전달할 수 있기 때문입니다. 그렇지만 사용자가 클라이언트(웹 브러우저)의 스크립트를 조작하여 유효성 검사를 하지 않고 서버에 전송하게 되면 유효하지 않는 데이터가 데이터베이스에 저장될 수 있습니다. 그렇기 때문에 서버에서 다시 유효성 검사를 하는 것이 좋습니다. (대부분의 사용자는 웹 브라우저의 스크립트를 조작하지 못할 겁니다.)

 

클라이언트(웹 브러우저)에서 유효성 검사하지 않고 서버에서만 유효성 검사해도 됩니다. 그 이유는 전송된 폼(form) 데이터의 값이 유효하지 않으면 클라이언트(웹 브러우저)로 바로 돌려보내면 되기 때문입니다. 그렇지만 데이터의 유효성 검사가 서버에만 있기 때문에 데이터가 유효할 때까지 반복적으로 서버로 전송해야 하는 문제가 있습니다. (실제로 유효성 검사로 반복되는 빈도는 많지 않습니다.)

 

유효성 검사를 서버에서 하게 되면 클라이언트(웹 브러우저)에서 유효성 검사를 하지 않아도 되기 때문에 클라이언트(웹 브러우저)의 스크립트 코딩을 줄 일 수 있습니다. 그렇지만 유효성 검사를 서버와 클라이언트 모두 해주는 것이 좋습니다.

 

그럼 서버에서는 어디에서 유효성 검사를 해야 할까요?

클라이언트(웹 브러우저)로 부터 전송된 폼(form) 데이터가 들어오는 Controller 클래스에서 유효성 검사를 하면 됩니다.

 

 

Maven Spring Project에 Server-Side Validation 추가하기

 

1. Java Resource > src/main/java에서 com.home.study.test1.board.controller 패키지에 있는 BoardController 클래스를 오픈합니다. (BoardController.java)

 

2. addBoard 메서드에서 @ModelAttribute Annotation(어노테이션)이 적용된 board 객체를 사용하여 유효성 검사를 추가합니다.

  1. board의 getRegistrationId() 메서드를 사용하여 작성자 아이디를 가져오고 작성자 아이디가 빈 값이거나 길이가 2보다 작거나 20보다 크면 작성자 아이디가 유효하지 않기 때문에 게시물 입력 페이지로 에러 입력 아이디(errorInputId)와 에러 메시지(errorMessage)를 리턴합니다.
  2. board의 getSubject() 메서드를 사용하여 제목을 가져오고 제목이 빈 값이면 제목이 유효하지 않기 때문에 게시물 입력 페이지로 에러 입력 아이디(errorInputId)와 에러 메시지(errorMessage)를 리턴합니다.
package com.home.study.test1.board.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.home.study.test1.board.model.Board;
import com.home.study.test1.board.service.IBoardService;


@Controller
@RequestMapping("/board")
public class BoardController {

	@Autowired
	IBoardService boardService;

	@RequestMapping(value="/addform", method=RequestMethod.GET)
	public String addBoardForm(HttpServletRequest request, HttpServletResponse response,
			@ModelAttribute("board") Board board, ModelMap model) {
		return "board/boardform";
	}

	@RequestMapping(value="/addboard", method=RequestMethod.POST)
	public String addBoard(HttpServletRequest request, HttpServletResponse response,
			@ModelAttribute("board") Board board, ModelMap model) {
		String registrationId = board.getRegistrationId();
		if (registrationId.isEmpty()) {
			model.addAttribute("errorInputId","registrationId");
			model.addAttribute("errorMessage", "작성자 입력란에 아이디가 입력되지 않았습니다.\\n아이디를 입력하세요.");
			return "board/boardform";
		} else if (registrationId.length() < 2 || registrationId.length() > 20) {
			model.addAttribute("errorInputId","registrationId");
			model.addAttribute("errorMessage", "작성자 입력란에 아이디는 최소 2자이상 최대 20자 이내로 입력하세요.");
			return "board/boardform";
		}
		
		String subject = board.getSubject();
		if (subject.isEmpty()) {
			model.addAttribute("errorInputId","subject");
			model.addAttribute("errorMessage", "제목 입력란에 제목이 입력되지 않았습니다.\\n제목을 입력하세요.");
			return "board/boardform";
		}
		
		if (!boardService.insertBoardItem(board)) {
			return "board/boardform";
		}
		
		return "redirect:/index.do";
	}
}

 

3. /src/main/webapp/WEB-INF/views/board/boardform.jsp 파일을 오픈하고 서버에서 유효성 검사를 하기 위해서는 <script>를 수정합니다.

  1. 클라이언트에서 유효성 검사를 하지 않기 위해서 기존 등록 버튼에 있는 checkValidity() 메서드를 주석처리합니다.
  2. 에러 입력 아이디(errorInputId)와 에러 메시지(errorMessage)가 있으면 window.onload에서 alert으로 에러 메시지를 알려주고 에러 입력 아이디로 포커스를 이동시킵니다.
$(function() {
	$('#saveBtn').click(function() {
		var boardForm = $('#board');
		//if (!boardForm[0].checkValidity()) {
		//	boardForm.addClass('was-validated');
		//} else {
			boardForm.attr("action", "/board/addboard.do");
			boardForm.submit();
		//}
	});
	$('#cancelBtn').click(function() {
		window.history.go(-1);
	});
	<c:if test="${not empty errorInputId && not empty errorMessage}">
	setTimeout(function() {
		alert("${errorMessage}");
		$("#${errorInputId}").focus();
	}, 100);
	</c:if>
});

 

 

Maven Spring Project를 실행하여 웹 브라우저로 확인하기

 

1. "Servers"탭에서 "Tomcat9"를 선택하고 "start"버튼(start the server)을 클릭하면 Tomcat이 실행됩니다.

 

2. 웹 브라우저에서 "http://localhost:9000/index.do"를 입력하고 등록 버튼을 클릭하면 게시물 입력 폼(/board/addform.do)으로 이동됩니다.

 

3. 입력 폼에서 작성자, 제목, 내용에 입력하지 않고 등록 버튼을 클릭합니다. 그러면 작성자가 빈 값이기 때문에 alert으로 에러 메시지가 노출됩니다. 확인 버튼을 누르면 작성자 입력란으로 포커스가 이동됩니다.

 

4. 입력 폼에서 작성자에 "t" 입력하고 등록 버튼을 클릭합니다. 그러면 작성자의 길이가 유효하지 않아서 alert으로 에러 메시지가 노출됩니다. 확인 버튼을 누르면 작성자 입력란으로 포커스가 이동됩니다.

 

5. 입력 폼에서 작성자에 "testid3" 입력하고 등록 버튼을 클릭합니다. 그러면 제목이 빈 값이기 때문에 alert으로 에러 메시지가 노출됩니다. 확인 버튼을 누르면 제목 입력란으로 포커스가 이동됩니다.

 

이처럼 서버에서 유효성 검사를 하여 유효하지 않을 경우 에러 정보를 입력 페이지로 다시 보내어 웹 브라우저에서 에러를 처리하도록 할 수 있습니다.

 

 

참고로, setTimeout()를 사용하여 처리한 이유는 웹 브라우저에 페이지가 노출된 후 메시지가 노출될게 하기 위해서입니다. setTimeout()를 사용하지 않고 해 보시면 빈 화면에 alert으로 에러 메시지를 노출되는 것을 확인할 수 있습니다.

$(function() {
	$('#saveBtn').click(function() {
		var boardForm = $('#board');
		//if (!boardForm[0].checkValidity()) {
		//	boardForm.addClass('was-validated');
		//} else {
			boardForm.attr("action", "/board/addboard.do");
			boardForm.submit();
		//}
	});
	$('#cancelBtn').click(function() {
		window.history.go(-1);
	});
	<c:if test="${not empty errorInputId && not empty errorMessage}">
	alert("${errorMessage}");
	$("#${errorInputId}").focus();
	</c:if>
});

 

기존처럼 CSS로 유효성 검사 결과를 처리할 경우 form(폼)의 CSS에 "was-validated"를 추가하고 에러가 발생한 입력란에 setCustomValidity() 메서드를 사용하여 에러 메시지를 추가하면 됩니다. setCustomValidity() 메서드를 사용해야 에러가 발생한 입력란에 :invalid selector가 발생됩니다.

$(function() {
	$('#saveBtn').click(function() {
		var boardForm = $('#board');
		//if (!boardForm[0].checkValidity()) {
		//	boardForm.addClass('was-validated');
		//} else {
			boardForm.attr("action", "/board/addboard.do");
			boardForm.submit();
		//}
	});
	$('#cancelBtn').click(function() {
		window.history.go(-1);
	});
	<c:if test="${not empty errorInputId && not empty errorMessage}">
	$('#board').addClass('was-validated');
	$('#${errorInputId}')[0].setCustomValidity("${errorMessage}");
	//alert("${errorMessage}");
	//$("#${errorInputId}").focus();
	</c:if>
});

 

이렇게 서버에서 유효성 검사를 하기 위해서는 @ModelAttribute Annotation(어노테이션)이 적용된 객체에서 값을 가져와 유효성 검사를 해야 하는 번거로움이 있습니다. 그래서 좀 더 편하게 객체에서 유효성 검사를 할 수 있는 빈 유효성 검사 구현체에 대해 알아보고 적용해 보도록 하겠습니다.

728x90
반응형