Spring Custom XML Namespace 만들기 3. view-resolver

[xml]
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
[/xml]

뷰 리졸버 설정으로 자주 사용하던 설정인데 prefix와 suffix 설정 빼고는 매번 거의 동일하게 사용한다. 하지만 클래스 이름에 집착하지 않는 분들이라면 저처럼 외울수도 없을 뿐더라 매번 찾아 보기도 귀찮습니다.

그래서 생각한게 커스텀 XML 네임스페이스.

[xml]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ssns="http://www.springsprout.org/schema/ssns"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springsprout.org/schema/ssns http://www.springsprout.org/schema/ssns.xsd">

<ssns:jstl-view-resolver />

</beans>
[/xml]

이렇게 설정하면 자동완성도 되고 관심있는 설정말 하면 되기 때문에 주요설정이 눈에 더 잘 띕니다.

완성! 과정은 생략..


Spring Custom XML Namespace 만들기 2. 레퍼런스

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/extensible-xml.html

레퍼런스를 보자. 초반에 먼저 개략적인 개발 단계가 나온다.

  1. 커스텀 엘리먼트를 기술할 XML 스키마 작성
  2. NamespaceHandler 구현체 코딩(매우 간단하고 쉬움)
  3. BeanDefinitionParser 구현체 코딩(실제 작업할 부분)
  4. 위에서 만든것들 스프링에 등록하기(매우 간단하고 쉬움)

근데.. 왠지 이거 순서가 잘못된것 같다. 아니.. 파서도 안만들었는데 뭘 등록하라고 NamespaceHandler를 구현하라는건지.. @_@;; 옛날에는 이런것도 스프링 이슈트래커에 올려주면 금방금방 피드백도 주고 잘 고쳐줬었는데.. 요즘은 어떨런지 모르겠다. 귀찮네;;

1 -> 3 -> 2-> 4 순서가 맞는것 같다.

1. XML 스키마 작성

[xml]
<myns:dateformat id="dateFormat"
pattern="yyyy-MM-dd HH:mm"
lenient="true"/>
[/xml]

이런 형태의 커스텀 엘리먼트를 제공할 계획이라면 다음과 같은 스키마를 작성해야 한다.

[xml]
<!– myns.xsd (inside package org/springframework/samples/xml) –>

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.mycompany.com/schema/myns"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
targetNamespace="http://www.mycompany.com/schema/myns"
elementFormDefault="qualified"
attributeFormDefault="unqualified">

<xsd:import namespace="http://www.springframework.org/schema/beans"/>

<xsd:element name="dateformat">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="lenient" type="xsd:boolean"/>
<xsd:attribute name="pattern" type="xsd:string" use="required"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>

</xsd:schema>
[/xml]

2. BeanDefinitionParser 구현

[java]
package org.springframework.samples.xml;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

import java.text.SimpleDateFormat;

public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

protected Class getBeanClass(Element element) {
return SimpleDateFormat.class;
}

protected void doParse(Element element, BeanDefinitionBuilder bean) {
// this will never be null since the schema explicitly requires that a value be supplied
String pattern = element.getAttribute("pattern");
bean.addConstructorArg(pattern);

// this however is an optional property
String lenient = element.getAttribute("lenient");
if (StringUtils.hasText(lenient)) {
bean.addPropertyValue("lenient", Boolean.valueOf(lenient));
}
}
}
[/java]

구상한 XML에서 사용할 값을 읽어와서 bean에다 설정해준다.

3. NamespaceHandler 구현

[java]
package org.springframework.samples.xml;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class MyNamespaceHandler extends NamespaceHandlerSupport {

public void init() {
registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
}
}
[/java]

커스텀 엘리먼트와 그것을 처리할 파서를 매핑해준다. 커스턴 엘리먼트는 1번 과정에서 스키마 만들면서 만든거나 다름없고 파서는 2번 과정에서 만들었으니 그것을 사용해서 등록하면 된다.

4. 등록하기

코딩은 끝났고 이제 META-INF 디렉토리에 프로퍼티 파일을 만들어서 핸들러와 스키마를 설정해줘야 한다. 이걸 JAR로 묶어서 클래스패스에 두면 스프링이 자동으로 읽어서 스프링 XML 설정 파일로 사용할 수 있게 해준다. (해봐야지.)

4-1. “META-INF/spring.handlers”

[xml]
http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler
[/xml]

이때 “:” 문자를 백슬러쉬로 이스케이프 시켜줘야 한다.

4-2. “META-INF/spring.schema”

[xml]
http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd
[/xml]

5. 커스텀 XML 설정 사용하기

[xml]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:myns="http://www.mycompany.com/schema/myns"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd">

<!– as a top-level bean –>
<myns:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm" lenient="true"/>

<bean id="jobDetailTemplate" abstract="true">
<property name="dateFormat">
<!– as an inner bean –>
<myns:dateformat pattern="HH:mm MM-dd-yyyy"/>
</property>
</bean>

</beans>
[/xml]

아직 레퍼런스를 다 보진 못했는데 일단은 대략 어떤식으로 만드는지 파악이 됐다. 중요한건 어제 토비님 글에서 본것처럼 만들려고 구상한 커스텀 설정에 따라 파서 구현 방법이 달라진다는 것이다. 아마 레퍼런스 남은 부분에선 그것을 설명하려는 것 같다. 요건 낼 아침에 일찍 인나면 봐야지..

Spring Custom XML Namespace 만들기 1. 사전 조사

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/extensible-xml.html

스프링 2.0부터 커스텀 XML 빈 설정 파서를 작성해 스프링 IoC 컨테이너에 연동할 수 있었다.

이 기능은 사실 최초의 Epril 세미나이자 KSUG의 시발점이 되었던 세미나에서 토비님이 발표하셨던 내용이다.

Spring 2.0의 XML 확장기능(1) Spring 2.0의 XML 확장기능(2) Spring 2.0의 XML 확장기능(3)

벌써 3년도 훌쩍넘어 4년이 거의 다 되가는 글인데 XML 확장에 대해서는 이 글 만한 한글 자료가 없다.(두번째 글에 이미지가 링크가 꺠진게 약간 아쉽다.)

일단 레퍼런스를 보기전에 토비님 글을 쭉 읽어봤다. 대략 이런 순인것 같다.

  1. 커스텀 빈 구상
  2. BeanDefinition 파서 구현
  3. XML 스키마 작성
  4. 네임스페이스 핸들러 작성
  5. 네임스페이스 핸들러와 스키마 등록

우선 커스텀 네임스페이스를 이용해 등록할 빈이 top-level 빈 한개 인지, top-level 빈 한개와 거기에 속해있는 inner 빈까지 등록할 것인지, top-level 빈을 여러개 등록할 것인지 등에따라 달라지며 또 두번쨰 경우였던 top-level 한개와 그 안에 inner 빈이 등록되는 경우에는 inner 빈들도 BeanFactory에 등록할지 여부에 따라 구현 방법이 또 조금 다른것 같다.

그러니 커스텀 네임스페이스로 간추릴 빈 설정을 파악하는게 중요하고 그 뒤엔 거기에 맞는 클래스를 사용해 BeanDefinitionParser를 구현하면 되겠다. 친절하게 각 경우에 따른 예제까지도 올려주셨다.

그 다음은 XML 스키마를 작성하는 일인데 이게 쬐금 귀찮다. XML 스키마를 직접 작성해본건 5년전 쯤 대학교에서 과제로 한번 해본게 다다. 그런데 역시나 또 친절하시게도 XML 스키마 작성 방법에 관한 링크도 걸어두셨다.

다음은 BeanDefinitionParser와 그 parser가 처리할 태그를 NamespaceHandler라는 것으로 매핑해주는 것이다.

마지막으로는 이 네임스페이스 핸들러를 spring.handlers라는 파일에 작성해주고 네임스페이스는 spring.schemas 라는 파일에 작성해 두 파일을 META-INF에 넣어두는 것인데.. 이 부분이 쬐금.. 불편하게 느껴진다. 좀 더 편한 방법은 없을런지..

내일은 레퍼런스도 봐야겠다. 어흑 언능 씻고 나가야지.