[struts2] <s:select> 사용법 2

프로그래밍/Framework 2011. 3. 22. 17:36 Posted by galad
<s:select name="startYear" list="yearList" listValue="label" listKey="value"></s:select> 년
<s:select name="startMonth" list="monthList" listValue="label" listKey="value"></s:select> 월
~ <s:select name="endYear" list="yearList" listValue="label" listKey="value"></s:select> 년
<s:select name="endMonth" list="monthList" listValue="label" listKey="value"></s:select> 월

Action에서 name으로 받아지는 값이 있으면 select box에서 기본값으로 설정된다.

    private List<LabelInfo> yearList;
    private List<LabelInfo> monthList;
    private String startYear;
    private String startMonth;
    private String endYear;
    private String endMonth;


###java
private List<LabelInfo> yearList;
private List<LabelInfo> monthList;
private String startYear;
private String startMonth;
private String endYear;
private String endMonth;
http://maven.apache.org/guides/mini/guide-configuring-maven.html

계정\.m2\setting.xml 내에 <localRepository> 엘리먼트를 추가/수정하면 된다.

[struts2] <s:if> 사용법3

프로그래밍/Framework 2011. 1. 3. 14:08 Posted by galad
<s:set var="isTvAppAdmin"><%=isTvAppAdmin%></s:set>

<s:if test="!{isTvAppAdmin}">
<s:if test="{isTvAppAdmin != 'true'}">
<s:if test="{isTvAppAdmin.equals('true')}">
<s:if test='{isTvAppAdmin != "true"}'>
<s:if test='%{#isTvAppAdmin.equals("false")}'>
...
...
</s:if>

isTvAppAdmin에 true를 넣고,
거짓이면 if문 내의 것이 실행되도록 했음.

test = !{...} 에서 {} 안의 것이 참 또는 거짓을 판별하는 조건이 되고, !는 NOT 임.

(수정)
위와 같은 경우, s:set 으로 isTvAppAdmin 에 넣은 값이 문자열 "true" 또는 "false" 라서 s:if 에서 boolean 으로 사용되지 않음.
즉, {문자열} 일 경우에는 무조건 참. 그래서 문자열 비교로 수정하였음.

(수정2)
문자열 비교이므로 equals 사용할 것. ㅡ.ㅡ;;;;

(수정3)
문자열 비교인데 equals 안됨.
수정1에서 안되었던 것은 문자열 비교이므로 ""로 묶어야 하는데 ''으로 묶어서 안되었던 것인 듯.

(수정4)
역시 equals로 해야만 함!.
단, s:set으로 밸류 스택에 넣었기 때문에 #변수명으로 불러와야만 함!
그리고 !{조건} 은 성립하지 않는 듯. 결과값이 생각과 다름.  <s:if test='%!{#isTvAppAdmin.equals("true")}'> 가 안되서 위와 같이 했음.
<s:debug> 태그로 표시된 value stack에 접근하기
<s:property value="#parameters.artist_id"/><br>
<s:property value="#parameters.artist_name"/><br>
<s:property value="#parameters.nationality"/><br>
<s:property value="#parameters.activity_type"/><br>
<s:property value="#parameters.genre"/><br>
<s:property value="#parameters.activity_period"/><br>
<s:property value="#parameters.imgFileName"/><br>
<s:property value="#com.opensymphony.xwork2.ActionContext.parameters.imgFileName"/>

<s:debug> 내용을 보면 Value Stack Contents 와 Stack Context로 나누어져있는데, Stack Context에는 #key 로 접근할 수 있다고 쓰여 있다.

parameters {activity_type=[Ljava.lang.String;@1f55cae, artist_id=[Ljava.lang.String;@197d09f, artist_name=[Ljava.lang.String;@18e1b, nationality=[Ljava.lang.String;@1f808e6, genre=[Ljava.lang.String;@18b492, activity_period=[Ljava.lang.String;@f1b25e}

파라메터 인터셉터 <interceptor-ref name="params"> 를 설정하면, request의 파라메터 값이 밸류 스택에 저장된다고 한다.
위처럼 들어가는 듯..

근데 input type="file"은 못가져오나?
jsp
<form name="frm "action="${pageContext.request.contextPath}/openapi/artist/add.omp" method="post" enctype="multipart/form-data">
    <input type="text" name="test"><br>
    <input type="file" name="img"><br>
    <input type="submit">
</form>

action
public class ArtistAction extends BaseAction {

    /**
     *
     */
    private static final long serialVersionUID = 384851516132095345L;
    private final static Logger log = Logger.getLogger(ArtistAction.class);

    private File img;            // 업로드할 실제 파일
    private String imgFileName;    // 업로드할 파일명, 규칙 : (파일input태그 name) + FileName

    public String add() {
        HttpServletRequest request = getRequest();

        log.debug(request.getParameter("test"));
        log.debug("FileName = " + imgFileName);
        log.debug("FileSize = " + img.length());

        return SUCCESS;
    }

    public File getImg() {
        return img;
    }

    public void setImg(File img) {
        this.img = img;
    }

    public String getImgFileName() {
        return imgFileName;
    }

    public void setImgFileName(String imgFileName) {
        this.imgFileName = imgFileName;
    }
}

interceptor에 <interceptor-ref name="fileUpload"/> 설정되어 있고, <input type="file" name='img"> 태그의 name만 aciton의 멤버변수명과 일치시켜 주면 간단하게 파일을 받을 수 있다.

꼭 <s:file> 태그를 쓰지 않아도 상관없다.

[strust2] Chain Result

프로그래밍/Framework 2010. 12. 14. 16:50 Posted by galad
다른 package의 Action으로 chain 걸기

    <package name="openapi" extends="bp-common" namespace="/openapi">
        <action name="*/*" class="com.omp.bp.cms.openapi.action.OpenApiAction">
            <result type="chain">
                <param name="namespace">${namespace}</param>
                <param name="actionName">${actionName}</param>
                <param name="method">${actionName}</param>
            </result>
        </action>
    </package>

    <package name="artist" extends="bp-common" namespace="/artist">
        <action name="add" class="com.omp.bp.cms.openapi.artist.action.ArtistAction" method="add">
            <result>/serverIp.jsp</result>
        </action>
    </package>

적절하게 namespace, actionName, method를 넘겨주면 된다.
request 시의 parameter를 모두 다음 Action에서 사용하고 싶을 때 사용.
http://www.okjsp.pe.kr/seq/136284

struts 2는 콘트롤러, 디스패쳐, 발리데이션용으로 사용하시고, 
spring은 DI콘테이너, AOP로 사용하시고, 
iBatis는 ORM프레임워크로 사용하시면 되겠네요. 

팁으로, 
Tiles 2.0 는 레이아웃템플레이트 
Acegi는 표준세큐리티프레임워크 
Google Web Toolkit는 리치클라이언트 
JUnit4는 테스트프레임워크 
JMockit는 단위테스트용 Mock프레임워크로 하시면, 

'오픈소스 full stack frame work', 즉 UI,DB, 세큐리티등의 기본적인 문제영역에 대한 
All in one환경을 구축하게 되어, 프레임워크간의 상성에 대해 걱정할 필요없이, 
비지니스로직에 집중가능합니다. 

사용하시면 기존 개발방식보다 훨 쉽게 프로그래밍이 되지 않을까 싶네요.


http://struts.apache.org/2.0.11/index.html 
http://www.springframework.org/ 
http://tiles.apache.org/ 
http://www.acegisecurity.org/ 
http://ibatis.apache.org/ 
http://code.google.com/intl/kr/webtoolkit/ 
http://www.junit.org/ 
https://jmockit.dev.java.net/


 (펌)

 

http://struts.apache.org/2.x/docs/comparing-struts-1-and-2.html (원본)

 

 

Expression Language

Struts 1은 JSTL을 통합한다. 따라서 JSTL EL을 사용한다. EL은 기본 객체 graph traversal을 가지고 있다.그러나, 상대적으로 약한 집합 그리고 index화된 property를 제공한다. 

Struts 2는 JSTL과 사용 할수있다.그러나, Framework은 또한 더 막강하고 유연한 표현 언어인 Object Graph Notation Language(OGNL)이라 불리는 언어를 제공한다.

Binding values into views

Struts 1 접근을 위해 page context안에 객체를 bing하기 위해 표준 JSP 메커니즘을 사용한다.

Struts 2는 ValueStack 기술이 사용된다. 그래서 , taglib은 객체 type을 rendering하기 위해 view에 coupling 없이 접근한다. ValueStack 정책은 같은 이름의 property 이름 이면서 다른 property type들에 대해서 type들의 범위에 교차하여 view의 재사용을 허용한다.

Type Conversion

Struts 1 ActionForm property는 일반적으로 모두 String이다. Struts 1 은 형변환을 위해서 Common-Beanutil들을 사용한다. 변환기는 클래스 마다 하지 instance마다 설정하는 것은 아니다.

 

Struts 2는 형변환을 위해서 OGNL 을 사용한다. Framework은  지초적이고 일반적인 객체 타입와 원시적인 객체타입을 위해 변환기를 포함한다.

Validation

Struts 1은 manual validation을  ActionForm의 validate 함수 또는 Commons Validator를 확장을 통하여  통해  제공한다. Class들은 동일한 class내에서  다른 validation context를 가지고 있다. 그러나, sub-object들 상에서 validation을  chain할 수는 없다.

 

Struts 2 는 validation method와 XWork Validation Framework을 통하여 manual validation을 제공한다. XWork Validation Framework은 sub-property에 property Class type과 validation context를 위한 validation정의된 chaining validation을 제공한다.

Control Of Action Execution

Struts 1 은 각각의 모듈을 위해  분할된 Request Processor( 생명주기 )을  제공하나, 모듈 안의 모든 Action 들은 반드시 같은 생명주기를 공유해야 한다.

Struts 2 는 기본적인interceptor Stack을 통해 Action마다 다른 생명주기를 생성할 수 있도록 제공한다. stack은 필요한 곳에 생성하거나 다른 action들과 사용되도록 Custom할 수 있다.

 

 

http://raberto.tistory.com/entry/Struts1-and-2 (번역)

 

출처 : http://jedison.tistory.com/69

 

본 튜토리얼은 제가 Struts 2를 공부할 목적으로 아래의 원문에 링크된 문서를 번역하여 정리한 것입니다.
원문: http://www.roseindia.net/struts/struts2/Struts2vsStruts1.shtml


이섹션에서 두개의 프레임워크 사이의 다양한 특징을 비교할 예정이다. 스트럿츠 2.x는 스트럿츠 1.x와 비교하여 매우 단순하다. 스트럿츠 2.x의 엑설런트한 특징 몇가지가 아래와 같다.

1. 서블릿 의존
스트럿츠 1의 액션은 하나의 액션이 invoked될 때 HttpServletRequest과 HttpServletResponse 객체가 execute 메서드를 통과하기 때문에 서블릿 API에 의존성을 가지고 있다. 그러나 스트럿츠 2의 경우에 액션은 컨테이너에 의존적이지 않다. 왜냐하면 액션이 단순한 POJO이기 때문이다. 스트럿츠 2에서 서블릿 컨텍스트는 고립되어 테스트된 액션을 허락하는 단순한 맵으로서 표현됩니다. 필요하다면 스트럿츠 2 액션은 진짜 request와 response에 접근할 수 있습니다. 그러나 다른 아키텍쳐 요소들이 HttpServletRequest나 HttpServletResponse에 직접적으로 접근할 필요를 줄어거나 제거했습니다.

2. Action 클래스들
인 터페이스 기반이 아닌 추상클래스 기반으로 개발된 스트럿츠1의 디자인 관련 이슈들은 스트럿츠2에서 해결이 되었습니다. 스트럿츠1의 Action 클래스들은 프레임웍에 의존적인 기반 추상클래스를 상속받도록 되어 있었지만 스트럿츠2의 Action클래스들은 옵셔널하고 커스텀한 서비스를 적용하기 위해 인터페이스를 구현할 수도 있고 아예 하지 않을 수도 있습니다. 스트럿츠2의 경우 Action 클래스들은 단순 POJO들로 개발되기 때문에 컨테이너에 대한 종속관계가 없습니다. 스트럿츠2는 ActionSupport 클래스를 제공하여 공통적으로 사용되는 인터이스들을 구현할 수 있도록 지원합니다.  그럼에도 불구하고 Action 클래스가 어떤 인터페이스를 구현하도록 요구되지는 않습니다. 어떤 POJO 오브젝트라도 execute 메소드만 존재한다면 스트럿츠2에서 Action 오브젝트로 사용이 가능합니다.

3. 검증
스트럿츠 1과 스트럿츠 2 모두 검증 메서드를 통한 수동 검증을 지원합니다.
스트럿츠 1은 검증 메서드를 액션 폼에서 사용하거나 확장시킨 Commons Validator를 통하여 검증합니다.
그러나, 스트럿츠2 는 검증메서드와 XWork 검증 프레임워크를 통하여 수동 검증을 지원한다. XWork Validation 프레임워크는 프라퍼티 클래스 타입과 validation 컨텍스트를 위해 정의된 valadations를 사용하여 서브 프라퍼티까지 연결된 검증을 지원한다.

4.쓰레딩 모델
스트럿츠1에서, 액션 리소스들은 thread-safe하거나 synchronized 되어야만 한다. 그래서 액션들은 singletons이고 thread-safe 이다. 그 액션을 위한 모든 리퀘스트를 처리하기 위한 단 하나의 인스턴스만 존재해야 한다.
싱글톤 전략은 스트럿츠 1 액션에서 할 수 있는 것에 대한 제한을 두게 되었고 개발을 하기 위해 주의가 요구된다. 그러나스트럿츠 2에서, 액션 객체는 각각의 리퀘스트에 대해 초기화된다, 그래서 thread-safety 이슈가 없다. (사실, 서블릿 컨테이너들은 각각의 리퀘스트에 대해 버리는 객체를 많이 생성한다, 그리고 하나 이상의 객체는 실행 패널티를 부과하지 않거나 garbage collection에 영향을 주지 않는다.)


5.테스트용이
스트럿츠 1 어플리케이션의 테스트는 조금 복잡하다. 스트럿츠1 액션들을 테스트하기 위한 주요 장애물은 실행 메소드이다. 왜나하면 그것은 서블릿 API를 나타내기 때문이다. 써드파티 확장인 Struts TestCase는 스트럿츠 1을 위한 mock object 집합을 제공한다. 그러나 스트럿츠 2 액션들은 액션을 초기화하고, 프라퍼티를 세팅하고 메소드들을 invoke 함으로써 테스트될 수 있다. Dependency Injection 지원은 또한 테스팅을 보다 쉽게 만든다. 스트럿츠 2의 액션은 간단한 POJO들이고 프레임웍에 독립적이다. 그러므로 스트럿츠2에서의 테스트는 매우 쉽다.

6.입력값 수집
스트럿츠 1은 입력값을 받기 위해서 ActionForm 객체를 사용합니다. 그리고 모든 ActionForm들은 프레임워크에 종속적인 기본 클래스를 확장하는 것이 필요하다. 자바빈즈는 ActionForm으로 사용될 수 없다. 그래서 개발자들은 입력값을 받기 위해 불필요한 클래스들을 생성해야만 한다.
그러나 스트럿츠 2는 Action 프라퍼티(근원적인 프레임워크에 독립적인 입력 프라퍼티)를 사용은 추가적인 입력 객체의 필요성을 제거했다. 그러므로 불필요성을 감소시켰다. 스트럿츠 2에서는 추가적으로, Action 프라퍼티들은 tag라이브러리들을 통해서 웹 페이지로부터 엑세스될 수있다. 스트럿츠 2는 또한 POJO 폼 뿐만아니라 POJO Action 을 지원하며 ActionForm 패턴도 지원한다. 심지어는 비즈니스나 도메인 객체를 포함한 풍부한 객체 타입을 입/출력 객체로서 사용할 수 있다.

7.표현언어
스트러츠1은 JSTL과 통합되어 있습니다. 그리고 JSTL-EL을 사용한다. 스트럿츠 1 EL은 기본 객체를 가집니다. 그러나 상대적으로 컬렉션과 인덱스된 프라퍼티의 지원은 약하다. 스트럿츠 2도 또한 JSTL을 사용한다. 그러나 Object Graphic Notation Language(OGNL)라고 불리우는 보다 강력하고 유연한 표현언어를 지원한다.

8.뷰와 값의 연결
뷰의 영역에서, 스트럿츠 1은 접근하기 위한 페이지 컨텍스트에서 객체(모델 영역에서 진행된) 를 바인드하기 위해 표준 JSP 메카니즘을 사용한다. 그러나 스트럿츠 2는 "ValueStack"이라는 기술을 사용한다. 태그라이브러리는 view와 그것을 렌더링할 객체 타입을 연결해 놓지 않고서 값에 접근할 수 있습니다. ValueStack 전략은 같은 프라퍼티 이름을 가졌지만 타입은 다른 타입의 범위를 넘나들며 view의 재사용을 허가합니다.

9.형변환
보통, 스트럿츠 1 Actionform 프라퍼티는 모두 String입니다. 스트럿츠1은 형변환시에 Commons-Beanutils를 사용한다.  이 타입 변환기들은 클래스당이며 인스턴스 당으로 설정되지 않는다. 그러나 스트럿츠 2는 형변환시에 OGNL을 사용한다. 프레임워크는 기본적이고 공통적인 객체타입과 프리머티브의 변환기를 포함한다.

10.Action 실행제어
스트럿츠1은 각각의 모듈에 대한 Request Processr를 분리합니다. 그러나 한개의 모듈안에서 모든 액션은 같은 라이프 사이클을 공유해야합니다. 그러나 스트럿츠 2는 Interceptor Stacks을 통해 생성된 각각의 액션에 대해 다른 라이프 사이클의 생성을 지원합니다. 사용자 스택이 생성될 수 있으며 필요하다면 다른 액션을 사용할 있습니다.

'프로그래밍 > Framework' 카테고리의 다른 글

[strust2] Chain Result  (0) 2010.12.14
[spring] struts 2 와 spring 과의 비교  (0) 2010.10.27
[struts2] <s:if> 사용법2  (0) 2010.08.04
[struts2] Workflow interceptor  (0) 2010.03.02
[Strust2] 가이드 문서, 레퍼런스 문서  (0) 2009.07.30

[struts2] <s:if> 사용법2

프로그래밍/Framework 2010. 8. 4. 11:24 Posted by galad
<s:if test="%{contentType < 11}"><%--VOD면--%>
    <option value="2">2 일</option>
    <option value="7">7 일</option>
    <option value="30">30 일</option>
</s:if>
<s:else>
    <option value="7">7 일</option>
    <option value="30">30 일</option>
    <option value="60">60 일</option>
    <option value="90">90 일</option>
    <option value="120">120 일</option>
    <option value="365">365 일</option>
</s:else>

contentType은 String 인데도, %{} 안에서 숫자와의 비교가 가능
숫자로 변환해서 비교하는 건지, 문자열로 비교하는 건지...

[struts2] Workflow interceptor

프로그래밍/Framework 2010. 3. 2. 14:22 Posted by galad
Action이 ActionSupport 를 상속하고 있으면 Validateable 을 제대로 구현하지 않더라도 기본적인 것은 체크하는 듯...

form에 같은 이름의 input이 2개 있는데 - 배열로 받아야 할 듯 - Action에서는 하나만 처리하게 해놨더니

계속 예외가 발생하는데 원인을 알 수가 없어서 고생했음.

HttpWatcher 같은 걸로 확인할 때 참고할 것.
여태까지는 무조건 value="" 에 값을 넣어서 설정해왔는데
알고 보니 name="XXX" 변수명이 Action에서 사용되고 있으면 자동설정된다.

<s:select name="parentCategoryId" list="parentCategoryList" listKey="key" listValue="value" headerKey="" headerValue="선택" onchange="setCategoryListComboByParentCategory();"></s:select>

이 jsp를 결과로 하는 액션클래스에서 parentCategoryId를 멤버변수로 get/set 함수를 갖고 있으면, 액션클래스에서 parentCategoryId에 설정한 값이 위의 태그의 기본값으로 설정된다.

<s:select name="contentInfo.categoryId" list="categoryList" listKey="value" listValue="label" headerKey="" headerValue="선택" onchange="setExtMetaByCategoryId();"></s:select>

마찬가지. 단 contentInfo 클래스의 categoryId 멤버변수값


[Strust2] <s:radio> 사용법

프로그래밍/Framework 2009. 7. 29. 14:19 Posted by galad
radio에 디폴트로 선택되게 하고 싶을 때

<s:radio name="productInfo.updateTypeCd" list="#{'A':'오름차순', 'D':'내림차순(최근 등록한 콘텐츠가 위로 정렬)'}" value="%{'D'}"></s:radio>

위와 같이 리스트를 강제로 설정하고, 기본값도 문자열로 주고 싶으면 %{'D'} 를 지킬 것. %{}를 사용하지 않으면 Struts2에서 태그를 변환하지 않는 듯.



<s:radio name="productInfo.updateTypeCd" list="#{'A':'오름차순', 'D':'내림차순(최근 등록한 콘텐츠가 위로 정렬)'}" value="D"></s:radio>

이게 될 것 같지만 되지 않는다..
출처 : http://www.tutcity.com/view/struts-2-modeldriven-action-example.18734.html

뭔가 했더니 jsp에서 user.name 이런 식으로 접근하던 것을 name 만으로 직접 접근 가능하게 해주는 것이었다...

액션 클래스에 implements ModelDriven 를 하고,

public Object getModel() {
      return user;
}

만 추가하면 됨.
<s:checkbox name="codeId" fieldValue="%{serviceType}" theme="simple"></s:checkbox>

위의 태그는 실제로 다음의 HTML을 만듬.

<input type="checkbox" name="codeId" value="s1" id="getServiceType_codeId"/>
<input type="hidden" id="__checkbox_getServiceType_codeId" name="__checkbox_codeId" value="s1" />

아래의 히든 input은 스트러츠에서 쓰는 듯하고,
체크 박스에 값 설정하려면 스트러츠 태그에서 value속성이 아닌 fieldValue를 써야한다. 주의!

참조: http://struts.apache.org/2.1.6/docs/checkbox.html

추가.
value속성은 boolean값 입력해서 checked/unchecked 설정하는데 쓰임
JSP:
<s:checkbox label="checkbox test" name="checkboxField1" value="aBoolean" fieldValue="true"/>

Velocity:
#tag( Checkbox "label=checkbox test" "name=checkboxField1" "value=aBoolean" )

Resulting HTML (simple template, aBoolean == true):
<input type="checkbox" name="checkboxField1" value="true" checked="checked" />

추가2.

체크박스가 같은 이름으로 여럿이고 그 중에서 체크된 것의 값만을 받으려 할 때,
일일이 체크된 것을 스크립트로 계산할 필요없다.
Action에 멤버변수로 체크박스의 체크된 값만을 받을 수 있다.

<s:checkbox name="codeId" fieldValue="%{serviceType}" theme="simple"></s:checkbox>
이 경우엔 Action에서
private String codeId;로 해서 getter/setter만 있으면 체크된 것들의 fieldValue만 가져온다.
"XXXX, XXXX, XXXX" 와 같이 콤마로 구분한다. 다만 사이사이 공백도 있으므로 trim할 것.

추가3.
checkbox 인터셉터를 설정하면 체크안해도 값을 넘겨받을 수 있다.
<!-- 회원관리 -->
        <action name="manage*" class="com.omp.bp.cms.manage.action.ManageAction" method="manage{1}">
            <interceptor-ref name="checkbox">
              <param name="uncheckedValue">N</param> // uncheck시 값
          </interceptor-ref>
            <interceptor-ref name="bpCommonStack"></interceptor-ref>
            <result>/cms/manage/manage{1}.jsp</result>
            <result name="JoinApproved" type="redirect">/manage/manageJoin.omp</result>
            <result name="Updated" type="redirect">/manage/manageMember.omp</result>
        </action>


'프로그래밍 > Framework' 카테고리의 다른 글

[Strust2] <s:radio> 사용법  (1) 2009.07.29
[Struts2] Model-driven interceptor  (0) 2009.05.27
[iBatis] queryForMap() 사용법  (0) 2009.04.21
[iBatis] iterate 사용법  (1) 2009.04.13
[Struts2] <s:iterator> <s:if> 사용법  (0) 2009.04.13

[iBatis] queryForMap() 사용법

프로그래밍/Framework 2009. 4. 21. 18:57 Posted by galad
참조: http://openframework.or.kr/Wiki.jsp?page=QueryForMapExample

<resultMap id="AccountResult" class="Account">
  <result property="id" column="ACC_ID"/>
  <result property="firstName" column="ACC_FIRST_NAME"/>
  <result property="lastName" column="ACC_LAST_NAME"/>
  <result property="emailAddress" column="ACC_EMAIL"/>
</resultMap>


<select id=
"selectAllAccounts" resultMap="AccountResult">
  select * from ACCOUNT
</select>

위와 같은 iBatis sql문에 대해 다음과 같이 쿼리.

queryForMap("selectAllAccounts", null, "id");

파라미터는 null이고, 쿼리 결과를 Map으로 받는데 키는 id에 대응하는 ACC_ID 칼럼값이 된다.
테이블에서는 모든 값(칼럼)을 가져와서 Accout 클래스형으로 값을 저장.
즉, key=ACC_ID칼럼값, value=Account클래스의 형태의 Map이 된다.

queryForMap("selectAllAccounts", null, "id""emailAddress");

역시 파라미터는 null이고 결과를 Map으로 받는데, 키는 id에 대응하는 ACC_ID 칼럼값이며,
값은 emailAddress에 대응하는 ACC_EMAIL칼럼값만 가져온다.
즉, key=ACC_ID칼럼값, value=ACC_EMAIL칼럼값의 형태의 Map이 된다.

두번째 사용법.

<statement id="getContentType" resultClass="org.apache.commons.collections.SequencedHashMap">
    SELECT * FROM OMPDBA.CONTENT_TYPE WHERE STATUS = 'U'
</statement>

위와 같이 resultMap이 없는 경우.

queryForMap(sqlId, paramMap, keyColumn, valueColumn);

파라미터명으로 써있는데로, 실제 칼럼명 자체를 파라미터로 넘겨준다.

중요.
    <statement id="SELECT_SERVICE_TYPE" resultClass="java.util.HashMap">
        SELECT
            a.SERVICE_TYPE, b.SERVICE_TYPE_NAME
        FROM
            CONTENT_SERVICE_SYSTEM a, SERVICE_TYPE b
        WHERE
            a.SERVICE_TYPE = b.SERVICE_TYPE
            AND a.CONTENT_TYPE = #PARAM0#
            AND b.STATUS = 'U'
        ORDER BY
            b.DISPLAY_ORDER ASC
    </statement>


위의 두번째 사용법에서 resultClass에 주목.
queryForMap은 결과를 map으로 돌려주는 것이므로, 위의 쿼리 결과는 SequencedHashMap이 Map안에 들어간 형태로 나와버린다?
이건 아닌 듯. resultClass 속성을 삭제하면 결과가 String으로 나와버림.
원하는 key-value형태로 나오지 않음.
java.util.HashMap(Map아님. interface라 안되는듯)으로 하면, ORDER BY 해도 순서가 제멋대로.
org.apache.commons.collections.map.ListOrderedMap로 해도 순서가 제멋대로.
즉, 키-값으로 넣을 수 있는 것이 반드시 resultClass 또는 resultMap 속성에 와야 하지만, 그렇다고 순서를 보장하진 않음.(Map답네..)

[iBatis] iterate 사용법

프로그래밍/Framework 2009. 4. 13. 20:13 Posted by galad
    <statement id="CHECK_SUB_CONTENT_TYPE_FOR_DELETE" resultClass="java.lang.String">
        SELECT
            COUNT(*) TOTAL_COUNT
        FROM
            SUB_CONTENT_TYPE
        <iterate prepend="WHERE" property="deleteContentTypeList" open="("  conjunction="," close=")">
            CONTENT_TYPE IN #deleteContentTypeList[]#
        </iterate>
    </statement>

    <statement id="CHECK_SUB_CONTENT_TYPE_FOR_DELETE" resultClass="java.lang.String">
        SELECT
            COUNT(*) TOTAL_COUNT
        FROM
            SUB_CONTENT_TYPE
        <iterate prepend="WHERE CONTENT_TYPE IN " property="deleteContentTypeList" open="("  conjunction="," close=")">
            #deleteContentTypeList[]#
        </iterate>
    </statement>

    <statement id="CHECK_SUB_CONTENT_TYPE_FOR_DELETE" parameterClass="java.util.List" resultClass="java.lang.String">
        SELECT
            COUNT(*) TOTAL_COUNT
        FROM
            SUB_CONTENT_TYPE
        <dynamic prepend="WHERE">
            <iterate property="deleteContentTypeList" open="("  conjunction="," close=")">
                CONTENT_TYPE IN #deleteContentTypeList[]#
            </iterate>
        </dynamic>
    </statement>

버근지 뭔지 몰라도 위의 방식은 하나도 안된다. property속성을 쓰면 안되는건지...
근데 되는 사람들도 있는 것 같고..

    <statement id="CHECK_SUB_CONTENT_TYPE_FOR_DELETE" resultClass="java.lang.String">
        SELECT
            COUNT(*) TOTAL_COUNT
        FROM
            SUB_CONTENT_TYPE
        <dynamic prepend="WHERE">
            <iterate open="CONTENT_TYPE IN ("  close=")" conjunction="," >
                #[]#
            </iterate>
        </dynamic>
    </statement>

이것처럼 아예 property 속성을 없애고, list의 이름을 없이 하면 잘됨.

참고:http://lostsin.tistory.com/tag/iBATIS

sql의 xml설정은 다음과 같이 하고

     <delete id="deletes" >
          DELETE FROM users
          <dynamic prepend="WHERE id IN">
              <iterate open="(" conjunction="," close=")">
                  #[]#
              </iterate>
          </dynamic>
      </delete>


DAO는 다음과 같이 한다
    public int delete(Integer[] ids) {
        return getSqlMapClientTemplate().delete("users.deletes", ids);
    }

해당 쿼리는 <iterate> 구문에 의하여 WHERE id IN (1,2,3,4,5) 방식으로
값이 매핑되게 된다.


보너스1.
List<>를 사용하는 방법도 xml 쿼리 부분은 동일하다.

List<String> list = new ArrayList<String>(3);

list.add("1");

list.add("2");

list.add("3");

List objs = sqlMapClient.queryForList("select-test",list);




보너스2.
parameterClass="map" 을 사용할 땐

     WHERE

session_id IN

<iterate property="sessionIds" open="(" close=")" conjunction=",">

#key[]#

</iterate>

hash의 key 값으로 사용된 string을 지정해주면 된다 (?)

추가.
            HashMap map = new HashMap();
            map.put("deleteContentTypeList", deleteContentTypeList);
            map.put("updateId", updateId);
            map.put("updateTime", updateTime);
           
            this.update("contenttype.DELETE_CONTENT_TYPE", map);

    <statement id="DELETE_CONTENT_TYPE">
        UPDATE
            CONTENT_TYPE
        SET
              STATUS = 'D'
            , UPDATE_ID = #updateId#
            , UPDATE_TIME = #updateTime#
        <dynamic prepend="WHERE">
            <iterate property="deleteContentTypeList" open="CONTENT_TYPE IN (" close=")" conjunction=",">
                #deleteContentTypeList[]#
            </iterate>
        </dynamic>
    </statement>

이건 또 된다. map에 넣어서 넘겨주면 멀쩡히 잘 되는군...

# 추가
list 를 패러미터로 전달 시 iterate 태그에서 property 를 설정하면(map으로 넘겼을 떄 말고),
전달된 list 에서 해당 property 를 찾으려고 시도하는 것 같다.
<iterate> 태그에서 property 속성을 제거하면 정상적으로 작동한다.

<select id="selectSomething" parameterClass="list">
    // select something and use iterate
    <iterate> // iterate 태그 내 property 속성을 제거하라
        #someList[]#
    </iterate>
</select>

참고: http://www.struts2.org/struts2-control-tags-using-iterator-tag/

<table>
    <s:iterator value="serviceTypeList" id="serviceTypeInfo" status="cust_stat">
    <tr bgcolor="<s:if test="#cust_stat.odd==true">grey</s:if><s:else>white</s:else>">
        <td>serviceType</td>
        <td><s:property value="serviceType"/></td>
    </tr>
    </s:iterator>
</table>

value -> list
id -> 루프 돌 때의 현재 object
status -> 상태값.(짝수/홀수 등등)

위의 결과는 다음.

serviceType s1
serviceType s2
serviceType s3


추가.


id false
false String Deprecated. Use 'var' instead
란다.

<s:iterator value="serviceTypeList" status="stat" var="serviceTypeInfo">
<s:if test="{#temp.isSelected.equals('Y')}" >
위는 위에서 말한 id 대신 var 사용한 것이고, var 사용하면 Stack Context에 들어가서 #key로 참조 가능하다. <s:debug/>로 확인가능.

그리고 iterator 안에서 if 태그 사용하기 예제. 찾기 힘들었다...

ps. if 태그에서 test="{}" 괄호 빼먹지 말 것!!!

추가2.

if tag 사용법이 좀 헷갈리네.
<s:if test="%{true}"> -> 항상 참
<s:if test='%{#serviceTypeInfo.isSelected == "Y"}' > -> 문자열 비교 시 사용. 'Y' 랑은 다르니 조심할 것
<s:if test='%{isSelected == "Y"}' > -> 위랑 같다. iterator 안에서는 #serviceTypeInfo 처럼 강제로 밸류스택을 안 찾아도 되는건가?

추가3.
<s:if test='%{status.equalsIgnoreCase("R")}'>준비중</s:if>
위의 것도 잘 된다. equals도 잘 될 듯. 비교 대상이 문자열("")인가 문자('')인가를 헷갈리지 말 것

'프로그래밍 > Framework' 카테고리의 다른 글

[iBatis] queryForMap() 사용법  (0) 2009.04.21
[iBatis] iterate 사용법  (1) 2009.04.13
[iBatis] 동적쿼리에서 ORDER BY 하기  (0) 2009.04.13
[iBatis] 동적쿼리문 생성  (0) 2009.04.13
[Struts2] <s:select> 사용법  (0) 2009.04.10
<statement id="SELECT_CONTENT_TYPE" resultMap="contenttype-resultMap">
        SELECT
            *
        FROM (
            SELECT
                ROWNUM ROWCNT,
                CONTENT_TYPE, CONTENT_TYPE_NAME, SUBSET_LIST_KEY, STATUS,
                DESCRIPTION_PAGE_NAME, INPUT_PAGE_NAME, DETAIL_VIEW_PAGE_NAME,
                CREATE_ID, CREATE_TIME, UPDATE_ID, UPDATE_TIME
            FROM
                CONTENT_TYPE
        )
        <dynamic prepend="WHERE">
            <isNotEmpty property="pageNavi.startRow">
                ROWCNT BETWEEN #pageNavi.startRow# AND #pageNavi.endRow#
            </isNotEmpty>
        </dynamic>
        <dynamic prepend="ORDER BY">
            <isNotEmpty property="orderColumn">
                $orderColumn$ $orderType$
            </isNotEmpty>
        </dynamic>
    </statement>

$orderColumn$ 인 것에 주목.
문자열 치환일 경우엔 $가 붙는다.
#은 preparedStatment에서 바인딩 하는 경우에 사용한다.(?에 값 넣는 경우처럼)

'프로그래밍 > Framework' 카테고리의 다른 글

[iBatis] iterate 사용법  (1) 2009.04.13
[Struts2] <s:iterator> <s:if> 사용법  (0) 2009.04.13
[iBatis] 동적쿼리문 생성  (0) 2009.04.13
[Struts2] <s:select> 사용법  (0) 2009.04.10
[Struts2] 태그에서 변수 사용법  (0) 2009.04.08

[iBatis] 동적쿼리문 생성

프로그래밍/Framework 2009. 4. 13. 16:08 Posted by galad
출처: http://narrowway.tistory.com/entry/iBatis%EB%8F%99%EC%A0%81-%EC%BF%BC%EB%A6%AC%EB%AC%B8-%EC%83%9D%EC%84%B1

<statement id="dynamicGetAccountList" resultMap="account-result">

  select * from account

  <dynamic prepend="WHERE">

    <isNotNull prepend="AND" property="firstName">

      (acc_first_name = #firstName#

    <isNotNull prepend="OR" property="lastName">

       acc_last_name = #lastName#

    </isNotNull>

    )

    </isNotNull>

    <isNotNull prepend="AND" property="emailAddress">

      acc_email like #emailAddress#

    </isNotNull>

    <isGreaterThan prepend="AND" property="id" campareValue="0">

      acc_id = #id#

    </isGreaterThan>

  </dynamic>

  order by acc_last_name

</statement>

 

상황에 의존적인 위 동적 statement로 부터 각각 다른 16가지의 SQL문이 생성될 수 있다. if-else구조와 문자열 연결을 코딩하는 경우 수백라인이 필요할 수도 있다.

동적 statement를 사용하는 것은 몇몇 조건적인 태그를 추가하는 것처럼 간단하게 작성할 수 있다.

 

이러한 조건들에 대해 간단히 정리하면 아래와 같다.

 

바이너리 조건 요소-바이너리 조건 요소는 정적값 또는 다른 프로퍼티값을 위한 프로퍼티값과 비교한다. 만약 결과가 true라면 몸체부분의 SQL쿼리가 포함된다.

 

바이너리 조건 속성

prepend

Statement에 붙을 오버라이딩 가능한 SQL부분(옵션)

property

비교되는 property(필수)

compareProperty

비교되는 다른 property (필수 또는 compareValue)

compareValue

비교되는 값(필수 또는 compareProperty)

 

<isEqual>

프로퍼티가 값 또는 다른 프로퍼티가 같은지 체크

<isNotEqual>

프로퍼티가 값 또는 다른 프로퍼티가 같지 않은지 체크

<isGreaterThan>

프로퍼티가 값 또는 다른 프로퍼티 보다 큰지 체크

<isGreaterEqual>

프로퍼티가 값 또는 다른 프로퍼티 보다 크거나 같은지 체크

<isLessThan>

프로퍼티가 값 또는 다른 프로퍼티 보다 작은지 체크

<isLessEqual>

프로퍼티가 값 또는 다른 프로퍼티 보다 작거나 같은지 체크

 

사용법 예제)

<isLessEqual prepend="AND" property="age" compareValue="18">

  ADOLESCENT = 'TRUE'

</isLessEqual>

 

단일 조건 요소-단일 조건 요소는 특수한 조건을 위해 프로퍼티의 상태를 체크한다.

prepend

statement에 붙을 오버라이딩 가능한 SQL부분(옵션)

property

체크하기 위한 프로퍼티(필수)

 

<isPropertyAvailable>

프로퍼티가 유효한지 체크

(이를 테면 파라미터의 프로퍼티이다.)

<isNotPropertyAvailable>

프로퍼티가 유효하지 않은지 체크

(이를 테면 파라미터의 프로퍼티가 아니다.)

<isNull>

프로퍼티가 null인지 체크

<isNotNull>

프로퍼티가 null이 아닌지 체크

<isEmpty>

Collection, 문자열 또는 String.valueOf() 프로퍼티가 null이거나 empty(“” or size() < 1)인지 체크

<isNotEmpty>

Collection, 문자열 또는 String.valueOf() 프로퍼티가 null 이아니거나 empty(“” or size() < 1)가 아닌지 체크

 

사용법 예제)

<isNotEmpty prepend="AND" property="firstName">

  FIRST_NAME = #firstName#

</isNotEmpty>


다른 요소들

Parameter Present : 파라미터 객체가 존재하는지 체크

Parameter Present Attributes : prepend - the statement에 붙을 오버라이딩 가능한 SQL부분

<isParameterPresent>

파라미터 객체가 존재(not null)하는지 체크

<isNotParameterPresent>

파라미터 객체가 존재하지(null) 않는지 체크

 

사용법 예제)

<isNotParameterPresent prepend="AND">

EMPLOYEE_TYPE = 'DEFAULT'

</isNotParameterPresent>


Iterate : 이 태그는 Collection을 반복하거나 리스트내 각각을 위해 몸체 부분을 반복한다.

Iterate Attributes :

  prepend - the statement에 붙을 오버라이딩 가능한 SQL부분 (옵션)

  property - 반복되기 위한 java.util.List타입의 프로퍼티 (필수)

  open - 반복의 전체를 열기 위한 문자열, 괄호를 위해 유용하다. (옵션)

  close - 반복의 전체를 닫기 위한 문자열, 괄호를 위해 유용하다. (옵션)

  conjunction - 각각의 반복 사이에 적용되기 위한 문자열, AND 그리고 OR을 위해 유용하다. (옵션)

<iterate>

java.util.List 타입의 프로퍼티 반복


사용법 예제)

<iterate prepend="AND" property="userNameList" open="(" close=")" conjunction="OR">

username = #userNameList[]#

</iterate>


주의:iterator요소를 사용할 때 리스트 프로퍼티의 끝에 중괄호[]를 포함하는 것은 중요하다. 중괄호는 문자열처럼 리스트를 간단하게 출력함으로부터 파서를 유지하기 위해 리스트처럼 객체를 구별한다.