一、注解
在Java模型中的创建与 xml 文件对应的节点和属性需要用注解来表示
@XmlRootElement
作用:将一个Java类映射为一段XML的根节点参数:
name 定义这个根节点的名称
namespace 定义这个根节点命名空间
@XmlAccessorType
作用:定义映射这个类中的何种类型需要映射到XML。
可接收四个参数,分别是:
XmlAccessType.FIELD:表示将这个类中的 非静态(static)、非序列化(transient)属性映射到xml,有无get/set方法均可
XmlAccessType.PROPERTY:使用 set/get 方法来序列化属性或者元素(get方法可不需注解自动映射)——说明:通过get方法映射到xml,get方法上是否添加注解都可,但是不能在属性上添加注解
XmlAccessType.PUBLIC_MEMBER:将这个类中的所有public的field(字段)或property(get/set对)同时映射到XML(默认注解),该注解包含了XmlAccessType.FIELD和XmlAccessType.PROPERTY两个注解,所以注意不要对同一个字段添加两次注解
XmlAccessType.NONE:不映射
补充说明:
@XmlAccessorType的默认访问级别是 XmlAccessType.PUBLIC_MEMBER,因此,如果java对象中的private成员变量设置了public权限的 getter/setter方法,就不要在private变量上使用@XmlElement和@XmlAttribute注解,否则在由java对象生成 xml时会报同一个属性在java类里存在两次的错误。
同理,如果@XmlAccessorType的访问权限为XmlAccessType.NONE, 如果在java的成员变量上使用了@XmlElement或@XmlAttribute注解,这些成员变量依然可以映射到xml文件。
@XmlElements
// 表示或的关系,list集合中内容可以为以下两种类型
@XmlElements({
@XmlElement(name = "Person", type = Person.class),
@XmlElement(name = "String", type = String.class)
})
private List list;
补充说明:如果List使用泛型,则List集合中只能含有一种数据类型,此时使用该注解无用。
@XmlElement
作用:指定一个字段或get/set方法映射到XML的节点。如,当一个类的XmlAccessorType 被标注为PROPERTY时,在某一个没有get/set方法的字段上标注此注解,即可将该字段映射到XML。
参数:
defaultValue 指定节点默认值
name 指定节点名称
namespace 指定节点命名空间
type 定义该字段或属性的关联类型
required 是否必须(默认为false)
nillable 该字段是否包含 nillable="true" 属性(默认为false)
@XmlAttribute
作用:指定一个字段或get/set方法映射到XML的属性(区别@XmlElement——节点)。
参数:
Name 指定属性名称
namespace 指定属性命名空间
required 是否必须(默认为false)
@XmlTransient
作用:定义某一字段或属性不需要被映射为XML。
如,当一个类的XmlAccessorType 被标注为PROPERTY时,在某一get/set方法的字段上标注此注解,那么该属性则不会被映射。
@XmlType
作用:定义映射的一些相关规则
参数:
propOrder 指定映射XML时的节点顺序
factoryClass 指定UnMarshal时生成映射类实例所需的工厂类,默认为这个类本身
factoryMethod 指定工厂类的工厂方法
name 定义XML Schema中type的名称
namespace 指定Schema中的命名空间
@XmlElementWrapper
作用:为数组元素或集合元素定义一个父节点。
如,类中有一元素为List items,若不加此注解,该元素将被映射为
<items>...</items>
<items>...</items>
这种形式,此注解可将这个元素进行包装,如:
@XmlElementWrapper(name="items")
@XmlElement(name="item")
public List items;
将会生成这样的XML样式:
<items>
<item>...</item>
<item>...</item>
</items>
@XmlJavaTypeAdapter
作用:自定义某一字段或属性映射到XML的适配器。
如,类中包含一个接口,我们可以定义一个适配器(继承自 javax.xml.bind.annotation.adapters.XmlAdapter类),指定这个接口如何映射到XML。
@XmlSchema
作用:配置整个包的namespace,这个注解需放在package-info.java文件中
二、代码实例
/** * @Title: Menus.java * @Package cn.com.kamfu.base * @Description: TODO(用一句话描述该文件做什么) * @author: liandy * @date: 2019年7月17日 上午1:41:42 * @version V1.0 */ package cn.com.kamfu.lang; import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSeeAlso; /** * @ClassName: Menus * @Description:TODO(这里用一句话描述这个类的作用) * @author: liandy * @date: 2019年7月17日 上午1:41:42 * */ @XmlRootElement(name = "items") @XmlAccessorType(XmlAccessType.FIELD) public class ListObj<T> { @XmlElement(name = "item") private List<T> item; public List<T> getItem() { return item; } public void setItem(List<T> item) { this.item = item; } }
/** * @Title: XmlList.java * @Package cn.com.kamfu.base * @Description: TODO(用一句话描述该文件做什么) * @author: liandy * @date: 2019年7月17日 上午12:16:58 * @version V1.0 */ package cn.com.kamfu.lang; import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlRootElement; /** * @ClassName: XmlList * @Description:TODO(这里用一句话描述这个类的作用) * @author: liandy * @date: 2019年7月17日 上午12:16:58 * */ @XmlAccessorType(XmlAccessType.FIELD) public class Menu { @XmlElement(name = "id") private String id; @XmlElement(name = "name") private String name; @XmlElement(name = "url") private String url; @XmlElementWrapper(name = "items") private List<Menu> item; public Menu() { super(); } public Menu(String id, String name, String url) { super(); this.id = id; this.name = name; this.url = url; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public List<Menu> getMenu() { return item; } public void setMenu(List<Menu> menu) { this.item = menu; } }
package cn.com.kamfu.util; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.enterprise.inject.New; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import org.dom4j.jaxb.JAXBReader; import cn.com.kamfu.lang.ListObj; import cn.com.kamfu.lang.Menu; public class JaxbXmlUtil { /** * @Title: marshallerByJaxb * @Description: TODO(这里用一句话描述这个方法的作用) * @param: @param path * @param: @param object * @param: @param classesToBeBound * @return: void * @throws */ public static void marshallerByJaxb(String path,Object object,Class... classesToBeBound) { try { JAXBContext jc = JAXBContext.newInstance(classesToBeBound); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");// 编码格式 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);// 是否格式化生成的xml串 marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);// 是否省略xml头声明信息 File file = new File(path); if (!file.exists()) { file.createNewFile(); } marshaller.marshal(object, file); } catch (JAXBException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static Object unmarshallerByJaxb(String path,Object object,Class... classesToBeBound) { try { JAXBContext jc = JAXBContext.newInstance(classesToBeBound); Unmarshaller unmarshaller = jc.createUnmarshaller(); File file = new File(path); if (!file.exists()) { throw new FileNotFoundException("Can not load xml file!"); } return unmarshaller.unmarshal(file); } catch (JAXBException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } public static void main(String[] args) throws JAXBException { ListObj<Menu> listObj=new ListObj<Menu>(); List<Menu> menuallList=new ArrayList<Menu>(); Menu menu = new Menu("1","用户管理",""); Menu item1=new Menu("2","新增用户",""); Menu item2=new Menu("2","删除用户",""); Menu item3=new Menu("2","修改用户",""); Menu item4=new Menu("2","查询用户",""); List<Menu> list=new ArrayList<Menu>(); list.add(item1);list.add(item2);list.add(item3);list.add(item4); menu.setMenu(list); menuallList.add(menu);menuallList.add(menu);menuallList.add(menu); listObj.setItem(menuallList); URL url=JAXBReader.class.getClassLoader().getResource(""); String path=url.getFile().toString()+"config/menu.xml"; JaxbXmlUtil.marshallerByJaxb(path,listObj, listObj.getClass(),menu.getClass()); ListObj<Menu> ssListObj=(ListObj<Menu>) JaxbXmlUtil.unmarshallerByJaxb(path,new ListObj<Menu>(),listObj.getClass(),menu.getClass()); System.out.println(1); } }
三、List、Map集合类型说明
集合必须封装在对象内部才能使用jaxb转为xml,不能直接将集合直接转为xml
3.1 List
List集合或数组只要封装到对象内部,使用@XMLElementWrapper注解
说明:当对象内部只有一个List集合的属性时,可以不加@XMLElementWrapper注解增加一层节点,直接将List结合内的对象作为根节点下的二级节点即可。
3.2 Map
如:Map<String, Person>集合,Person为自定义的一个对象
1.创建一个新对象(如:AllPerson)作为中转对象,该对象内含有两个属性,分别是String和Person类型的(前者为Map的key,后者为Map的value);
2.使用@XMLJavaTypeAdapter注解将Map<String, Person>转为AllPerson[],数组的大小与Map的大小相同;
总结:XmlAdapter中的两个方法各有用处,注意不要漏掉
Object->xml时
Map<String, Person>—转为—> AllPerson[](AllPerson对象中包含String, Person)
Xml->Object时
AllPerson[](AllPerson对象中包含String, Person)—转为—> Map<String, Person>