spring自定义标签以及遇到的坑

在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

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.xmc168.cn/schema/mylabel" targetNamespace="http://www.xmc168.cn/schema/mylabel"
    elementFormDefault="qualified">
    <xsd:element name="mylabel" id="myLabel">
        <xsd:complexType>
        	<xsd:attribute name="id" type="xsd:string" />
            <xsd:attribute name="userId" type="xsd:string" />
            <xsd:attribute name="userName" type="xsd:string" />
            <xsd:attribute name="age" type="xsd:string" />
        </xsd:complexType>    
    </xsd:element>
</xsd:schema>

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 文件内容如下:

<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
	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">

	<myTag:mylabel id="myLabel" userId="11" userName="name" age="20" />
</beans>  


八、测试类
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了






猜你喜欢

转载自blog.csdn.net/xmc125/article/details/79849785