웹사이트를 살펴보면 기본적으로 제공되는 언어 외의 다른 언어를 지원하는 것을 볼 수 있다. 그런 설정은 과연 어떻게 하는건지 의문을 가진 적이 있었는데, HTML을 처음 배웠던 시기에는 아예 HTML을 국가별로 따로 작성하여 만드는 것이라고 생각했다. 하지만 이는 기능적인 부분의 도움을 받아 클래스를 사용하면 쉽게 처리가 가능하다.

 

   Locale 클래스   

   java클래스로 request 객체를 사용하여 불러오거나, 아니면 new 방식으로 생성하는 등 클래스를 사용하는 것 처럼 호출하면 사용자의 지역 환경에 따라 결정되는 지역적 문화등에 관한 정보를 알려준다. 언어나 날짜 시간, 여기서 날짜 또한 각 나라마다 표기법이 다르기 때문에 맞춰서 반영된다. JSP페이지에서 사용할 경우 스크립트 태그를 이용해 import(java.util.Locale)를 하고 request객체로 불러와 Locale객체에 담을 수 있다.

Get
getDefault() Locale locale의 현재 값을 가져옴
getCountry() String 현재 locale의 국가/지역 코드(대문자, ex.KR)를 가져옴
getDisplayCountry() String 현재 locale의 국가 이름을 가져옴
getLanguage() String 현재 locale의 언어 코드(소문자, ex.ko)를 가져옴
getDisplayLanguage() String 현재 locale의 언어 이름을 가져옴

 

   Locale 객체에 담긴 정보를 확인하기 위해 getDisplayCountry 함수를 사용하여 현재 국가의 이름을 가져오는 것을 확인할 수 있다. 형식을 지정하여 오늘의 날짜와 요일까지 알아내기 위해 getDateInstance함수를 사용하여 형식을 모두(FULL) 보여주는 것으로 지정하고 변수로 locale을 지정하자 오늘의 날짜가 나온 것을 확인했다. 다음으로 숫자 표기에 관한 내용인데, 국가마다 화폐가 다른 점을 반영하기 위해서 알아두면 좋을 것 같다. 일단 숫자의 형식을 쉼표(,)로 구분하기 위해 getNumberInstance 함수를 사용하여 제 위치에 찍힌 쉼표를 확인했다.

 

   fmt 태그   

   기본적인 작업을 끝냈다면 JSP에서 다양한 포멧을 지원하는 fmt 태그에 대해 알아보자. fmt 태그는 다국어 문서 처리를 위한 국제화 및 지역화 태그이다. 즉, 앞서 말했듯이 각 국가별로 웹 페이지를 따로 제작하는 것이 아니라, 기존의 소스코드는 그대로 두되 지역에 따라 언어팩만 교체하여 다국어 문서 작성이 가능하다는 것이다.

 

   fmt태그를 사용하기 위해서는 먼저 lib파일에 해당 jar파일을 가지고 있어야 한다. (실습은 jstl-1.2.jar 파일을 사용함)

   그리고 taglib 디렉티브 태그를 사용하여 해당 페이지에 포함시켜주면 사용 준비는 끝난다.

<%@ taglip prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %>
구분 태그 유형 설명
Locale 설정 setLocale 국제화 태그가 사용할 Locale 정보를 설정함
requestEndcoding 요청 파라미터의 문자 인코딩을 설정함 (UTF-8을 권장함)
메세지 처리 bundle 사용할 리소스 번들을 설정
message 리소스 번들에서 로케일에 맞는 메세지를 가져와 출력함
setBundle 리소스 번들을 읽어와 특정 변수에 저장
날짜 formatDate 날짜 형식을 표현함
parseDate 문자열에서 원하는 패턴의 날짜 형식으로 변환함
숫자 formatNumber 숫자 형식을 표현함
parseNumber  문자열에서 원하는 패턴의 숫자 형식으로 변환함 
시간 setTimeZone 특정 범위의 시간대를 설정함
timeZone 시간대를 설정함

 

   메세지 처리 태그에서 말하는 리소스 번들이란 쉽게 말해 해당 태그들이 사용하는 파일을 일컫는다. 리소스 번들로 사용되는 파일들은 대부분 WEB-INF/classes/ 폴더에 속해야 하는데, 해당 폴더는 사용자가 임의로 저장을 할 수 있는 공간이 아니다. 해당 폴더는 웹 페이지를 서버에 Run시킬 때, .java파일을 컴파일하여 .class(기계어)로 바뀐 파일이 보관되는 장소이므로 해당 폴더에 존재하려면 java폴더에 properties 파일을 사용하여 저장되어 있어야 한다.

 

   properties 파일은 일종의 텍스트 문서로 기본 파일은 디폴트값이 되며, 언더바(_)와 함께 뒤에 작성되는 지역 소문자 코드가 언어팩의 지역을 나타낸다(ko-한국어/en-영어/ja-일본어 등…).

 

 


   < Book-Market 사이트 만들어보기 ⑥ >   

 

   이제 리소스 번들을 이용하여 언어를 바꾸는 법을 배웠으니 응용하여 Book Market 페이지의 언어를 다양하게 만들어 보도록 하겠다. 먼저 리소스 번들이 들어갈 패키지를 java폴더 아래에 만들고 [New] → [File] 탭에 들어가 properties파일을 작성한다. 기본 값이 될 파일은 파일명 뒤에 지역 코드를 붙이지 않아도 되며, 여기서는 한국어/영어/일본어 총 세 개의 파일을 만들어 도서등록 페이지에 연결할 것이다.

 

   영어를 제외한 한국어나 한자는 모두 작성 즉시 유니코드로 변환되어 기록되는데, 오타를 확인하고 싶을 경우 해당 유니코드 위에 마우스 오버를 시키면 작성한 글이 무엇인지 나오니 참고하도록 하자.

 

   이제 setLocale태그를 사용하여 제일 먼저 현재 지역 언어를 설정해줄건데, 이는 a태그를 통해 받은 파라미터로 지정하게 했다. 아무런 값을 할당받지 못한 상태라면 아무 지역코드를 쓰지않은 원본이 기본값이 되기 때문에 따로 지정하지 않아도 자연스레 한국어 원판이 나오게 될 것이다. 다만 여기서 주의할 점은 value부분에 큰 따옴표(" ")를 사용하여 작성해야 했는데, 표현식의 충돌이 일어난건지 큰 따옴표로 작성하면 에러가 뜬다. 따라서 EL문을 사용하거나 아니면 그냥 따옴표(' ')를 사용하여 작성하니 큰 문제가 생기진 않았다.

 

   언어 설정이 끝나면 bundle태그를 통해 로컬라이징이 필요한 부분에 미리 작성해둔 key값을 넣어주기만 하면 끝난다. 이렇게 되면 사용자가 a태그에 요청을 할 때마다 파라미터의 값이 바뀌며 적용되는 setLocale값에 따라 해당하는 메세지를 반영하게 된다. 참고로 a태그의 경로에 물음표(?)로 시작하는 것은 해당 페이지에 파라미터를 보내는 것과 같다. leng(key값) = ko(value값) 식으로 전송되니까 알아두도록 하자.

 

   여기서 유심히 봐야 될 부분은 bundle메서드의 끝나는 지점이다.

   

   언어가 바뀌어야 하는 부분마다 fmt:message 처리를 진행하고 이후 더는 필요없는 부분에서 bundle 태그를 닫아야 하는 점을 유의하자.

 

   유효성 검사란 HTML에 작성된 데이터가 전송되기 전, 사용자가  과연 지정된 형식에 맞게  작성 하였는지 검사하는 것을 말한다. 실수로 다른 데이터를 입력하게 되면 처리 과정에서 에러가 날 뿐 아니라, 사용자의 입장에서는 이미 작성한 폼을 다시 새로 작성해야하는 번거로움을 줄여줄 수 있기 때문이라도 필요한데 이는 컨트롤러에서 실행할 지, HTML 자체에서 실행할 지 개발자가 어느 방향으로 제작했는지가 중요하다.

 

   HTML도 발전을 거듭하여 java코드로만 행해졌던 유효성 검사 대부분은 form에서도 지정할 수 있는데, 주로 서버를 거치지 않은 간단한 항목에 대해서는 HTML 자체에서 걸러낼 수 있다. 입력 데이터가 없을 경우, 날짜 혹은 이메일의 형식을 지키지 않은 경우, 나이를 입력할 때 숫자로 쓰지 않은 경우, 입력 폼의 제한 길이를 초과했을 경우 등 input이나 textarea 등 직접 사용자의 텍스트를 값으로 받는 태그는 대부분 해당 검사가 가능하니 오늘은 유효성 검사가 어떻게 흘러가는지 과정을 살펴보도록 하겠다.

 

   먼저, 유효성 검사를 거치기 위해서는 입력된 값이 무엇인지 확인하는 절차가 필요할 것이다.

 

 

   오랜만에 JS(자바스크립트)를 사용하게 되었다. HTML을 읽어내는 크롬이나 사파리 같은 번역기들은 기본적으로 HTML / CSS 파일을 해석할 수 있는데, 여기서 Java Script 또한 해석이 가능하기 때문에 유효성 검사에 많이 활용된다고 한다...

 

   JS는 기존에 배운 것과 동일하다, 다만 jsp에서 script태그를 이용하여 작성할 경우 자동완성 기능은 제공하지 않기 때문에 되도록 js파일을 만들어 작성하는 것을 권장하는 편이다. querySelector를 이용하여 가져온 값을 알림창으로 출력하는 기능을 통해 제대로 값을 가져온 것을 확인하자.

 

 


let but = document.querySelector("#sub");
but.addEventListener("click", checkLogin);
//submit으로 form의 내용을 바로 전송하지 않기 위해 타입을 button으로 지정하고 이벤트를 할당했다

let myForm = document.querySelector("#ex8_2_form");

//버튼에 할당된 이벤트 내용이다
function checkLogin() 
{
   let id = document.querySelector("#id");
   let pw = document.querySelector("#pw");
   console.log("실행");
   console.log(id);
   console.log(pw);
   //해당 태그를 잘 선택했는지 확인한다

   //id의 값이 null일 경우 경고창이 뜨고, return을 통해 해당 기능을 즉시 종료한다
   if(id.value=="")
   {
      alert("아이디를 입력해주세요.");
      id.focus();
      return false;

   //pw의 값이 null일 경우 경고창이 뜨고, return을 통해 해당 기능을 즉시 종료한다
   } else if(pw.value=="")
   {
      alert("비밀번호를 입력해주세요.");
      pw.focus();
      return false;

   }
   
   //if문이 실행되지 않고 넘어오면(유효성 검사 통과) submit() 함수를 통해 해당 form을 전송한다.
   myForm.submit();
   
}

 

   여기서 한번 고생을 한 부분이 있는데(놀랍게 js로 돌아오자마자 트러블을 일으켰다, 여러모로 대단한 언어다) 앞 예시에서 input태그의 id값을 submit으로 준 것 때문에 그대로 쓰다가 유효성 검사를 위한 함수를 작성하는데서 자꾸 오류가 터져 막막했었다. 정확한 이유는 모르겠지만 submit()이 함수가 아니라는 에러가 돌아왔는데, 그 이유가 바로 input태그의 아이디 값을 submit으로 주었고, querySelector를 통해 가져온 것이 화근이 되었던 것 같다.

 

   정말 이유는 모르겠지만 결국 input 태그의 id값을 수정하였고 그 결과 정상적으로 작동되는 것을 확인했다... ...

 

   어쨌든 이런 식으로 함수를 활용하여 사용자가 입력한 데이터가 전송되기 전 검출하는 함수를 작성할 수 있었다. 하지만 HTML5 부터는 해당 기능을 form에 추가할 수 있기 때문에 복잡한 것이 아니라면 그 기능을 활용하는게 더 편할 것이다.

 


   < Book-Market 사이트 만들어보기 ⑤ >   

 

 

   이제 유효성 검사의 원리와 방법을 배웠으니 책을 등록하는 페이지에서 작성 방법을 제한하는 함수를 작성하여 적용하자.

 


let but = document.querySelector("#but");
but.addEventListener("click", CheckAddBook);

function CheckAddBook(){

   let bookId = document.querySelector("#bookId")
   let name = document.querySelector("#name");
   let unitPrice = document.querySelector("#unitPrice");
   let unitsInStock = document.querySelector("#unitsInStock");
   let description = document.querySelector("#description");
   let newBook = document.querySelector("#newBook");
   //모두 HTML태그를 가져와 저장했다

   //도서 아이디 체크를 위한 기능을 작성했다
   //파라미터로 정규 표현식을 사용한 범위, input태그, 메세지를 받는다
   function check(regExp, e, msg){

      //정규표현식과 input태그에 들어온 패턴을 비교하여 참일경우 여기서 기능을 멈춘다 (아래의 경고문구는 실행X)
      if(regExp.test(e.value)){
         return true;
      }

       //정규표현식과 맞지 않다면 경고창에 메세지를 띄우고 해당 input에 포커스를 맞춘다
       alert(msg);
       e.focus();
       return false;
    }

   //도서 아이디 체크 : 위의 기능에서 true/false를 반환받아 작동한다
   //정규 표현식 : ISBN으로 시작해야하며 0~9사이의 숫자 5자리부터 12자리까지 입력 가능
   //기능 경고창에 띄울 메세지를 입력했다
   if(!check(/^ISBN[0-9]{4,11}$/, bookId, "[도서 코드]\nISBN과 숫자를 조합하여 5~12자까지 입력하세요.\n첫 글자는 반드시 ISBN으로 시작하세요.")){
      return false;
   }



   //도서명 체크
   if(name.value.length < 4 || name.value.length > 50){
      alert("[도서명]\n최소 4자에서 50자까지 입력하세요.");
      name.focus();
      return false;
   }

   //도서 가격 체크
   if(unitPrice.value.length == 0 || isNaN(unitPrice.value)){
      alert("[가격]\n숫자만 입력하세요.");
      unitPrice.focus();
      return false;
   }

   if(unitPrice.value < 0){
      alert("[가격]\n음수를 입력할 수 없습니다.");
      unitPrice.focus();
      return false;
   }

   //재고수 체크
   //isNaN : 숫자가 아닐 경우 true를 반환
   if(isNaN(unitsInStock.value)){
      alert("[재고]\n숫자만 입력하세요.");
      unitsInStock.focus();
      return false;
   }

   //설명 체크
   if(description.value.length < 100){
      alert("[상세설명]\n최소 100자 이상 입력하세요.");
      description.focus();
      return false;
   }

   newBook.submit();

}

 

   if문을 활용해서 모든 input태그를 검사하고 하나라도 참이 나올 경우 return false 를 통해 즉시 해당 문구에서 기능을 멈추고 form을 전송하지 않는다. 모두 옳게 작성됐을 경우엔 if문에서 빠져나와 맨 아래의 submit() 함수를 통해 해당 form의 내용을 지정된 경로로 이동시켜, 결과적으로는 도서 추가가 완료된다.

+ Recent posts