在xx培训机构的一次公开课上看到了spring自定义标签,手开始不自觉的痒痒起了。
废话少说, now , show code
一、自定义标签所返回的目标类, MyLabel, 此类没有什么好说的,就是一个平台的pojo
package cn.xmc168.label;
public class MyLabel {
private int userId;
private String userName;
private int age;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
二、自定义解析器 BeanDefinitionParser, 此类的作用是将配置文件的自定义标签元素解析成BeanDefinition. 名称为 MyLabelBeanDefinitionParser , 实现 AbstractSingleBeanDefinitionParser ,并覆盖 getBeanClass(Element element) 和 doParse(Element element, BeanDefinitionBuilder builder) 两个方法。
package cn.xmc168.label.parsers;
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 cn.xmc168.label.MyLabel;
public class MyLabelBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class> getBeanClass(Element element) {
return MyLabel.class;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
int age=0;
String userName=null;
try {
userName = element.getAttribute("userName");
age = Integer.parseInt( element.getAttribute("age"));
}catch(Exception e) {
e.printStackTrace();
}
if(age>0) {
builder.addPropertyValue("age", age);
}
if(StringUtils.hasText(userName)) {
builder.addPropertyValue("userName", userName);
}
}
}
三、定义NamespaceHandler ,作用是将解析器添加到map中。
package cn.xmc168.label.handler;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import cn.xmc168.label.parsers.MyLabelBeanDefinitionParser;
public class MyLabelNameSpaceHandler extends NamespaceHandlerSupport{
@Override
public void init() {
registerBeanDefinitionParser("mylabel", new MyLabelBeanDefinitionParser());
}
}
四、定义自定义标签的约束文件, 存放位置是classpath:META-INF
xmlns 和 targetNamespace 可以自己指定
五、创建spring.schemas文件, 存放位置是classpath:META-INF, 注意冒号需要转义。
http\://www.xmc168.cn/schema/mylabel.xsd=META-INF/spring-mylabel.xsd
六、创建spring.handlers ,存放位置是classpath:META-INF , 这个文件的作用是根据自定义标签的URI指定NameSpaceHandler
http\://www.xmc168.cn/schema/mylabel=cn.xmc168.label.handler.MyLabelNameSpaceHandler
已上是自定义标签的6个文件,现在看看在spring项目中怎么使用, 这里我们定义标签为myTag
七、applicationContext.xml 文件内容如下:
xmlns:myTag="http://www.xmc168.cn/schema/mylabel"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.xmc168.cn/schema/mylabel http://www.xmc168.cn/schema/mylabel.xsd">
package cn.xmc168.label;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AppTest {
@Autowired
private MyLabel myLabel;
@Test
public void test1() {
System.out.println(myLabel);
}
}
以上代码是测试通过的, 在测试的过程中也发现了一些坑
1、NameSpaceHandler.init方法注册的名字写错, 导致获取BeanDefinitionParser为空。后来是跟代码发现的这个问题。
2、AbstractBeanDefinitionParser.parse(Element element, ParserContext parserContext) 方法在获取id(估计是bean的id)时报错, 因为之前xsd中没有指定id, applicationContext.xml元素属性也没有指定id, 后来加上了id, 暂时解决这个问题, 但是我这里有一点疑惑的地方是:如果我的MyLabel类中也恰好有一个字段是int类型的名字也叫做id, 这里怎么配 ? 跟代码时,发现有这样一段代码
if (shouldGenerateId()) {
return parserContext.getReaderContext().generateBeanName(definition);
}
shouldGenerateId() 默认是false, 估计那里可以修改这个值, 修改成TRUE后可以不配bean的ID, 那么这个ID就可以用着类的ID了