java/jsp/spring/note2013. 8. 7. 11:31

okjsp siva6님의 자료

[ "==" 과 "equals()" 의 차이점]


     Q&A를 읽다보면, String을 "=="연산자로 비교해서 에러를 발생시키는 경우가 많이

    있었습니다. 그래서, 여기에 대해서 정리를 해보고자 이 글을 작성했습니다. 여기

    쓰여있는 내용은 제 추측과 상상력이 동원되기도 했기 때문에 사실과 차이가 있을

    수도 있습니다. 그런 내용은 바로 알려주세요.


    두개는 어떤 차이가 있을까요?

    간단히 말하면, "=="은 연산자고 "equals()"는 메소드입니다.

    "=="에 대한 정의는 jvm에 있을 것이고,

    "equals()"에 대한 정의는 class에서 되어 있겠죠.


    "=="은 양쪽 항의 값을 비교하는 것입니다.

    "equals()"는 class에서 구현된 것에따라 어떤 처리를 해서 결과를 나타내겠죠..

    (구현에 따라서 다른 결과를 나타낼 수 있습니다.)


    우선, "=="부터 살펴보죠.

    위에서 말했듯이 양항의 값을 비교합니다.

    여기에 대한 설명은 java가 Call by reference 인지 Call by value인지에 대한

    설명이 되어야 하는데 이것은 다음 기회에 설명하겠습니다.(없을지도 모름)


    int i = 10, j = 20;

    의 코드가 실행되었다면,

    i라는 변수는 10이라는 값을 가지게 됩니다.

    물론, j는 20이라는 값을 가지게 됩니다.


    그런데,

    String str0 = "TEST", str1 = "테스트";

    라고 하면,

    str0는 "TEST"라는 객체를 가리키는 참조값을 가지게 됩니다.

    위에서 용어를 다르게 사용했습니다.

    "값을 가진다"와 "참조값을 가진다"

    객체는 직접 접근할 수 없습니다.

    단지, 그 위치를 참조하는 참조값을 가지고 접근하는 것 뿐입니다.


    다시 본론으로가면, "=="은 그 변수가 같은 값을 가지고 있는지만 체크하는 것입니다.

    int i = 10, int j = 20;

    int k = 10;

    String str0 = "TEST", str1 = "테스트";

    String str2 = new String("TEST");

    String str3 = "TEST"

    위의 코드를 수행하면, 메모리에는 다음과 같은 표의 상태가 됩니다.

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

    |변수명| 변수값      | 실제값        |

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

    | i    | 10          | (10)          |

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

    | j    | 20          | (20)          |

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

    | k    | 10          | (10)          |

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

    | str0 | 0x3a3...(?) | [String]TEST  |

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

    | str1 | 0xe1e...(?) | [String]테스트|

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

    | str2 | 0xe2b...(?) | [String]TEST  |

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

    | str3 | 0x3a3...(?) | [String]TEST  |

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

    (변수값의 0x....는 그냥 상상의 숫자입니다. 너무 신경쓰지마세요.)


    그럼, 비교를 해볼까요..

    1.( i == j )  :  false

    2.( i == k )  :  true

    여기까지는 쉽게 이해가 갈 것입니다.

    3.( str0 == str1 ) : false  -> 당연?

    4.( str0 == str2 ) : false

    -> 이게 false인 이유는 "=="은 단지 가지고 있는 값을 비교하기 때문입니다..

    위의 표에서 본다면, 실제값이 아닌 변수값을 비교하게 됩니다.

    5.( str0 == str3 ) : true   -> 이건?

    -> 이건 억지라고요? 4번과 뭐가 다르냐고요?

    새로운 객체는까 변수값이 다를 것이고 결코 같은 값이 들어 오지 않을 것이라고

    생각할 수도 있습니다.

    하지만, java가 좀 똑똑한 놈이라 이런 경우가 발생합니다.

    new를 사용하여 만든 String은 항상 새로운 객체이지만 ""로 만든 문자열은

    공유를 할 수 있습니다...

    str0을 가리키는 "TEST"라는 문자열을 만들때 메모리의 어떤 부분에 String 객체가

    저장되겠죠. 그곳의 위치가 0xe1e...입니다.

    그런데, 새로 "TEST"라는 객체를 만들면, java는 이게 이전에 만든 0xe1e...에 있

    는 [String]TEST와 동일하다고 판단하고, 새로운 변수에는 0xe1e를 할당하게 됩니다.

    (모든 객체가 그런것은 아닙니다...여기에서 또 clone문제가 생기네요?

    이것도 다음기회...)


    이상의 설명에서 "=="이 무엇을 하는 놈인지 아셨는지.........

    알송달송하면, 아래까지 읽고 다시 읽어 보세요.


    위와 같은 현상때문에 사용자들이 아무 생각없이 "=="을 String에 사용하고,

    결과가 일관성이 없다고 말씀들을 하시더군요...

    보통, 사용자가 생각하는 비교는 실재 저장하는 값이지 결코, 그것을 가리키는

    변수가 아니라는 점에서 그렇습니다....

    그래서, java가 이상한 놈이라고 생각들 합니다.

    그럼, 객체의 "==" 비교는 어떤 의미가 있을까요?

    그건 동일한 객체라는 것입니다.

    위의 str0과 str3은 동일한 객체라는 것을 알 수 있습니다.

    반면, 같은 실재값을 가지고 있다고 하더라고 str0과 str2는 서로 다른 객체죠.

    (참고로, 서로 같은 class의 instance인가는 instanceof를 사용하여 check할 수 있습니다.)


    그럼 실제로 같은 값을 포함하고 있느냐는 무엇으로 비교할까요?

    네.."equals()"죠..

    물론, String등에서죠...

    하지만, equals()는 새로 만들 수도 있기 때문에 어떤 기능을 할지는 알 수가 없습니다.

    (만드는 사람 마음.....)


    여기서는 Object와 String 객체의 equals()만을 살펴보겠습니다.

    Object는 아시는 것처럼 모든 class의 부모입니다. 결국, 모든 class는 object를

    상속받고, 결국 생성되는 모든 객체는 equals()메소드를 갖게 됩니다.

    물론, 자식 class에서 equals()를 재정의하면 그 메소드를 따르지만요.


    자, 그럼 대망의 Object의 equals()를 직접보겠습니다.


    public boolean equals(Object obj) {

return (this == obj);

    }


    이것입니다....(sun java 1.3.1 이지만, 다른 버젼도 별차이 없을것 같네요.)

    실망하셨나요?

    위의 글을 잘 읽으셨으면, (this == obj)가 어떤 의미를 가지는지는 판단하실 수

    있을 것입니다.


    그럼, String의 equals()는 어떻게 되어 있을까요?

    소스에서 바로 설명하죠.


    public boolean equals(Object anObject) {

if (this == anObject) { //----> 동일한 객체라면 더 비교할 필요가 없겠죠.

   return true;

}

if (anObject instanceof String) { //---> 입력된 객체가 String인지 체크합니다.

                                 //---> type이 다른데 같은 값을가져도 무의미.

   String anotherString = (String)anObject;

   int n = count;

   if (n == anotherString.count) { //---> 먼저 길이가 같은지 체크하네요.

                                   //---> 길이가 다르면 다른 놈이죠.

char v1[] = value;              //---> String은 내부적으로 char[]로 관리됩니다.

char v2[] = anotherString.value;//---> 부럽습니다. 같은 class라고 private로

                                     선언되어 있어도 직접접근이 되는군요.

int i = offset;

int j = anotherString.offset;

while (n-- != 0) {      //---> 하나하나 비교하는 군요.

   if (v1[i++] != v2[j++]) {

return false;

   }

}

return true;

   }

}

return false;

    }


    String의 equals()는 이렇게 그 객체가 가지고 있는 char[]의 값을 비교하여

    같으면 true, 틀리면 false로 return하게 되어 있습니다.

    만약, 다른 설정은 다르더라도(그럴께 없지만)

    저장된 값이 같으면 true가 됩니다.

    위의 표를 보면, "equals()"로 비교하게 되면 str0, str2, str3이 모두 같은

    value를 가져 true를 return 하게 됩니다.


    사용자가 주로 원하는 비교의 결과는 이것이겠죠.


    결론을 말하면, 기본형은 "=="로 비교하고, 객체는 equals()로 비교해라 입니다.

    결론은 단순한데 너무 길게 설명했네요.


    ---Tip------------------------------------------------------

    String을 비교할 때의 Tip입니다.


    public void showHI(String str0)

    {

        if( str0.equals("TEST") ) System.out.println("Hi!!!");

    }


    이런 코드가 있을 수 있겠죠.

    showHI("TEST")의 결과는 Hi!!!입니다..

    showHI("테스트")의 결과는      입니다..(blank)

    그럼,

    showHI(null)의 결과는 무엇일까요?

    바로 NullPointException입니다...

    왜냐하면, equals()를 가진 str0자체가 null이기 때문에 equals()를 사용할 수

    없기 때문입니다.

    위의 메소드는 아래처럼 변경되어야 합니다.


    public void showHI(String str0)

    {

        if( "TEST".equals(str0) ) System.out.println("Hi!!!");

    }


    이 코드는 null이 들어와도 blank입니다.

    100%확실한 객체인 "TEST"를 사용하는 것이

    99.9999%의 확실성을 가진 str0 객체를 사용하는 것보다 좋습니다.


    일반적으로 String 비교를 사용할 때는

    비교할 문자열의 equals()를 사용하는 습관을 가져 주십시요.

    (물론 선택의 문제입니다.)

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


okjsp siva6님의 자료

'java/jsp/spring > note' 카테고리의 다른 글

Spring Framework + Jakarta Commons Validator ?!  (0) 2013.02.28
Posted by 유기농농부
java/jsp/spring/error2013. 3. 4. 08:45

출근하고 갑자기 톰캣을 실행시키는데 에러가 났다.

뭐 에러를 읽어보면 내가 사용하는 아이바티스랑 스프링이랑 버전이 안맞아서 그렇다, DTD를 참조하지 못해서 그렇다는 등..

여러가지 원인이 있겠지만 갑자기 잘 실행되다가 안된다면 서버를 클린시켜주면 끝.

개발을 시작하기전에 서버를 크린시켜주고 시작하는 습관을 가지자 ~

Posted by 유기농농부
java/jsp/spring/note2013. 2. 28. 10:23

http://www.egovframe.org 표준프레임워크 온라인 지원포탈을 보면 Spring Framework + Jakarta Commons Validator 에 대해서 자세하게 설명되어있다.

개요를 살펴보자면

입력값 검증을 위한 Validation 기능은 Valang, Jakarta Commons, Spring 등에서 제공한다.
여기서는 Jakarta Commons Validator를 Spring Framework과 연동하여 사용하는 방법에 대해서 설명하고자 한다.
Jakarta Commons Validator는 필수값, 각종 primitive type(int,long,float…), 최대-최소길이, 이메일, 신용카드번호등의 값 체크등을 할 수 있도록 Template이 제공된다.
이 Template은 Java 뿐 아니라 Javascript로도 제공되어 client-side, server-side의 검증을 함께 할 수 있으며,
Configuration과 에러메시지를 client-side, server-side 별로 따로 하지 않고 한곳에 같이 쓰는 관리상의 장점이 있다.
Struts에서는 Commons Validator를 사용하기 위한 org.apache.struts.validator.ValidatorPlugIn 같은 플러그인 클래스를 제공하는데,
Spring에서는 Spring Modules 프로젝트에서 연계 모듈을 제공한다.
여기서는 server-side, client-side validation을 위해,
설치방법, Spring Module에서 제공하는 핵심 클래스인 DefaultValidatorFactory, DefaultValidator와 설정파일인 validator-rules.xml, validator.xml 에 대한 간략한 설명과
예제 프로젝트인 easycompany에 적용하는 과정을 설명한다.

DefaultValidatorFactory DefaultBeanValidator
프로퍼티 'validationConfigLocationsApache'에 정의된 Validation rule을 기반으로
Commons Validator들의 인스턴스를 얻는다.
DefaultBeanValidator는 org.springframework.validation.Validator를 implements하고 있지만,
DefaultValidatorFactory가 가져온 Commons Validator의 인스턴스를 이용해 validation을 수행한다.
Controller에 validation 수행할때 이 DefaultBeanValidator를 참조하면 된다.

아래 코드를 참조해 빈 정의 파일(예제에는 easycompany-servlet.xml)에 다음과 같이 ValidatorFactory,Validator,validator-rules.xml,validation.xml 파일을 등록한다.

...
<!-- Integration Apache Commons Validator by Spring Modules -->				
    <bean id="beanValidator" class="org.springmodules.validation.commons.DefaultBeanValidator">
	<property name="validatorFactory" ref="validatorFactory"/>
    </bean>
 
    <bean id="validatorFactory" class="org.springmodules.validation.commons.DefaultValidatorFactory">
	<property name="validationConfigLocations">
		<list>
                      <!-- validator-rules.xml, validator.xml의 위치-->
			<value>/WEB-INF/conf/validator-rules.xml</value>
			<value>/WEB-INF/conf/validator.xml</value>
		</list>
	</property>
    </bean>
...

validator-rules.xml 설정

validator-rules.xml은 application에서 사용하는 모든 validation rule에 대해 정의하는 파일이다.
예제에 있는 validator-rules.xml의 필수값 체크 부분을 보면 아래와 같이 작성되어 있다.

      <validator name="required"
            classname="org.springmodules.validation.commons.FieldChecks"
               method="validateRequired"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.springframework.validation.Errors"
                  msg="errors.required">
         <javascript><![CDATA[
         .....
            ]]>
         </javascript>
      </validator>
name validation rule(required,mask,integer,email…)
classname validation check를 수행하는 클래스명(org.springmodules.validation.commons.FieldChecks)
method validation check를 수행하는 클래스의 메소드명(validateRequired,validateMask…)
methodParams validation check를 수행하는 클래스의 메소드의 파라미터
msg 에러 메시지 key
javascript client-side validation을 위한 자바스크립트 코드

 

여기까진 지원포탈의 설명이었고, 자 이제부터 시작을 하자.

 

1. Validator

입력값 검증을 위한 Validation 기능은 Valang, Jakarta Commons, Spring 등에서 제공한다.

Spring Modules (0.9 기준)에서 제공하는 validation rule들은 아래와 같다.

1.2  validator_common.xml

 

경로: XXXXXXXX/validation/validator_common.xml

 

validator.xml validation Form을 맵핑 합니다.

form name field property validation할 폼 클래스의 이름, 필드와 각각 매핑 됩니다. 

Server-Side Validation

 

1.3 Controller

 

variable

 

Package: org.springmodules.validation.commons.Default.BeanValidator;

validator_common.xml 등록한 DefaultBeanValidator Controller에서 validation을 수행한다.

 

Function

 

beanValidator.valiadate(object  arg0, errors arg1)  valiadate 수행합니다.

 

validation 에러가 있으면 해당 에러 메시지 리턴 합니다.

 

 


 

1.4 JSP

 

경로:XXXXXXXXXXXX/WEB-INF/jsp/XXXXXXXXXXXXX/Sample/sampleRegister.jsp

 

 Javascript code

    

 

JSP Code

 

Validation을 적용할 JSP를 작성합니다.

form submit을 하면 이름, 나이, 이메일등의 입력값이 Employee 클래스에 바인딩이 되서 Controller에 전달이 되고, Controller validation 수행 로직이 있으면 validator.xml 내용에 따라 validation이 이루어 진다.

만일 에러가 발생하면 <form:error…/>에 에러에 해당하는 메시지를 출력한다.

 

 


 

1.5 에러메시지 등록

 

경로: XXXXXXXXXXXXXXXXXXXX/properties/XXXXX/message/XXXXXXXXXXXX.properties

 

→ 메시지 파일에 에러 메시지를 등록한다.
validation 에러가 발생하면 validator-rules.xml에서 정의했던 msg값으로 에러메시지의 key값을 찾아 해당하는 메시지를 출력해준다.

 

 


 

Client-Side Validation

 

TestPage.jsp 추가

 

1. commons-validator taglib를 선언한다.

 

<%@ taglib prefix="validator" uri="http://www.springmodules.org/tags/commons-validator" %>

 

2. 필요한 자바 스크립트 함수를 generate 하기 위한 코드를 추가 한다. validation-rules.xml에서 선언한 함수를 불러 오기 위해, 위에서 작성한 TestPage.jsp를 아래와 같이 호출한다

 

<script type="text/javascript" src="<c:url value='/common/co/validator/validator.do'/>"></script>

 

3. formName validator_common.xml 정의한 from을 써줍니다.

 

<validator:javascript formName="sampleVO" staticJavascript="false" xhtml="true" cdata="false"/>

 

 

Script code

 

javaScript 함수 호출 시 validate + formname 명을 작성 하면 동적으로 validate가 가능합니다.

 

 

 

 

 

 

 

client-validation을 위해 바로 submit하지 않고 먼저 validateRequired함수를 호출합니다.

 

 

 

 

 

'java/jsp/spring > note' 카테고리의 다른 글

비교연산자 'equals' 와 '=='  (0) 2013.08.07
Posted by 유기농농부
java/jsp/spring/error2013. 2. 26. 13:19

java.lang.IllegalStateException: Errors/BindingResult argument declared without preceding model attribute. Check your handler method signature!  

 

위의 에러는 Validate를 하는 메소드 내에서 BindingResult의 순서와 관련된 에러인듯 하다.

 

BindingResult가 HttpServletRequest, HttpServletResponse, ModelMap 등~ 보다 먼저 선언되어야

에러가 나지 안았다!!!

 public String updateSwList(            

            @ModelAttribute("swInfoVO") ST_Sw_VO swInfoVO,
            BindingResult bindingResult,
            Model model,
            SessionStatus status)
            throws Exception{


이와같이 BindingResult를 꼭 앞에 쓰는 습관을 길러야겠다...



물론 원인은 알지 못한다...........


'java/jsp/spring > error' 카테고리의 다른 글

Context initialization failed  (2) 2013.03.04
Posted by 유기농농부