Spring Custom XML Namespace 만들기 2. 레퍼런스
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/extensible-xml.html
레퍼런스를 보자. 초반에 먼저 개략적인 개발 단계가 나온다.
- 커스텀 엘리먼트를 기술할 XML 스키마 작성
- NamespaceHandler 구현체 코딩(매우 간단하고 쉬움)
- BeanDefinitionParser 구현체 코딩(실제 작업할 부분)
- 위에서 만든것들 스프링에 등록하기(매우 간단하고 쉬움)
근데.. 왠지 이거 순서가 잘못된것 같다. 아니.. 파서도 안만들었는데 뭘 등록하라고 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]
아직 레퍼런스를 다 보진 못했는데 일단은 대략 어떤식으로 만드는지 파악이 됐다. 중요한건 어제 토비님 글에서 본것처럼 만들려고 구상한 커스텀 설정에 따라 파서 구현 방법이 달라진다는 것이다. 아마 레퍼런스 남은 부분에선 그것을 설명하려는 것 같다. 요건 낼 아침에 일찍 인나면 봐야지..