因為對接系統的XML所需映射的實體類有幾十個,自己來處理不太現實,於是一直找尋找這樣的工具,終於讓我發現了jaxb2-maven-plugin:
http://www.mojohaus.org/jaxb2-maven-plugin/Documentation/v2.2/
一鍵生成,使用也比較方便,但是需要在maven環境下,下面將介紹如果使用
在maven工程下的pom.xml導入:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxb2-maven-plugin</artifactId> <version>2.5.0</version> <executions> <execution> <id>id1</id> <phase>generate-sources</phase> <goals> <goal>xjc</goal> </goals> <configuration> <!-- XSD源文件 --> <sources> <source>src/main/xsd</source> </sources> <!-- 源碼輸出目錄 --> <outputDirectory>target/generated-sources/jaxb</outputDirectory> <!-- 指定文件生產 --> <!--<schemaFiles>client_centric_data.xsd</schemaFiles>--> <packageName>com.zgz.adsr</packageName> </configuration> </execution> </executions> <!--<configuration>--> <!--<!– The package of your generated sources –>--> <!--<packageName>com.zgz</packageName>--> <!--</configuration>--> </plugin>
然后,在工程中是用mvn clean install就會生成源碼了。
如果有多個XSD文件,可以不指定packageName,會自動分類,如果指定了,就所有實體類都在一起了,挺不方便的。可能是不清楚怎么設置,有清楚怎么設置的,麻煩評論讓我學習一下。
下面說說,映射父節點的東東,因為請求的XML父節點要設置前綴以及各種東東的,例如下圖:
可在生成的package-info.java文件中添加注解:
@javax.xml.bind.annotation.XmlSchema(
// 注意這里,下面的XmlNs匹配了,就顯示ie前綴 namespace = "http://www.shkf.com/rootelement", //子節點的設置 //elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED, xmlns={ @XmlNs(prefix="ie", namespaceURI="http://www.xxx.com/rootelement"), @XmlNs(prefix="ie1", namespaceURI="http://www.xxx.com/subaccount"), @XmlNs(prefix="ie2", namespaceURI="http://www.xxx.com/ccd"), @XmlNs(prefix="simple", namespaceURI="http://www.xxx.com/simple"), @XmlNs(prefix="tcl", namespaceURI="http://www.xxx.com/tcl"), @XmlNs(prefix="xsi", namespaceURI="http://www.w3.org/2001/XMLSchema-instance")} )
但是schemaLocation的設置就在請求實體轉換為XML的時候做設置:
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.xxx.com/rootelement root_elements.xsd ");
或者在父節點實體類加個屬性值:
@XmlAttribute(name ="xsi:schemaLocation")
public String schemaLocation="http://www.xxx.com/rootelement root_elements.xsd ";
還有一種方式設置前綴,繼承NamespacePrefixMapper,但跟着上面的屬性設置,好像會有點問題,具體還沒怎么研究。
使用這方式需要引用依賴,不然會報錯。
<dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.2.4-1</version> </dependency>
如要去掉standalone,可參考:
https://stackoverflow.com/questions/14152523/remove-standalone-yes-from-jaxb-generated-xml
https://blog.csdn.net/weixin_39964562/article/details/79072277
import java.io.*; import javax.xml.bind.*; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.stream.*; @XmlRootElement public class Login { private JAXBContext jaxbContext; private XMLOutputFactory xmlOutputFactory; public Login() { try { jaxbContext = JAXBContext.newInstance(Login.class); xmlOutputFactory = XMLOutputFactory.newFactory(); } catch(Exception e) { e.printStackTrace(); } } public static void main(String[] args) { Login demo = new Login(); System.out.println(demo.getMessage()); } public final String getMessage() { try { Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); jaxbMarshaller.setProperty("jaxb.encoding", "ISO-8859-1"); jaxbMarshaller.setProperty(Marshaller.JAXB_FRAGMENT, true); ByteArrayOutputStream baos = new ByteArrayOutputStream(); XMLStreamWriter xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(baos, (String) jaxbMarshaller.getProperty(Marshaller.JAXB_ENCODING)); xmlStreamWriter.writeStartDocument((String) jaxbMarshaller.getProperty(Marshaller.JAXB_ENCODING), "1.0"); jaxbMarshaller.marshal(this, xmlStreamWriter); xmlStreamWriter.writeEndDocument(); xmlStreamWriter.close(); return new String(baos.toByteArray()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
JaxbUtil類:
package xxxx.util; import com.sun.xml.bind.marshaller.NamespacePrefixMapper; //import com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper; import org.apache.commons.lang.StringUtils; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; /** * @author GuangZe * @version v1.0 * @project: vedio * @description: 這里描述類的用處 * @copyright: © 2020 * @company: * @date 2020/12/16 15:00 */ public class JaxbUtil { public static String validate(String xml, String xsdPath) { String errMsg = null; String[] xmlArr; int lineNum; try { Source root = new StreamSource(JaxbUtil.class.getClassLoader() .getResourceAsStream("xsd/root_elements.xsd")); Source code = new StreamSource(JaxbUtil.class.getClassLoader() .getResourceAsStream("xsd/code_lists.xsd")); Source simple = new StreamSource(JaxbUtil.class.getClassLoader() .getResourceAsStream("xsd/simple_types.xsd")); Source ccd = new StreamSource(JaxbUtil.class.getClassLoader() .getResourceAsStream("xsd/client_centric_data.xsd")); Source customer = new StreamSource(JaxbUtil.class.getClassLoader() .getResourceAsStream("xsd/customer_account.xsd")); Source sub = new StreamSource(JaxbUtil.class.getClassLoader() .getResourceAsStream("xsd/sub_account.xsd")); Source trade = new StreamSource(JaxbUtil.class.getClassLoader() .getResourceAsStream("xsd/trading_account.xsd")); Source[] sourceArr = {code, simple, ccd, customer, sub, trade, root}; Schema schema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(sourceArr); Validator validator = schema.newValidator(); Source s = new StreamSource(new StringReader(xml)); validator.validate(s); }catch (SAXParseException e){ e.printStackTrace(); xmlArr = xml.split("\n"); lineNum = e.getLineNumber(); errMsg = e.getMessage(); if(lineNum<=xmlArr.length && StringUtils.isNotBlank(xmlArr[lineNum-1])){ errMsg +="["+xmlArr[lineNum-1].trim()+"]"; } System.out.println(errMsg); } catch (SAXException e1) { e1.printStackTrace(); errMsg = e1.getMessage(); System.out.println(errMsg); } catch (IOException e2) { e2.printStackTrace(); errMsg = e2.getMessage(); System.out.println(errMsg); } return errMsg; } /** * 序列化 * @param object * @throws JAXBException */ public static String marshall(Object object) throws JAXBException { // 通過映射的類創建XMLContext上下文對象,其中參數為映射的類。 JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass()); // 通過JAXBComtext上下文對象的createMarshaller()方法,創建一個對象java格式轉化成XML的格式 Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); //自定義前綴 // NamespacePrefixMapper mapper = new PreferredMapper(); // marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", mapper); marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.xxx.com/rootelement root_elements.xsd "); // 最后,將JAVA對象轉換到制定的輸出位置,其中的object為java對象。 StringWriter writer = new StringWriter(); marshaller.marshal(object, writer); return writer.toString(); } /** * 解析 * @param clazz * @param xml * @return * @throws Exception */ public static Object unmarshaller(Class<?> clazz, String xml) throws Exception { if (StringUtils.isEmpty(xml)) { return null; } // 通過映射的類創建XMLComtext上下文對象,其中參數為映射的類。 JAXBContext jaxbContext = JAXBContext.newInstance(clazz); // 通過JAXBContext上下文對象創建createUnmarshaller()方法,創建XML轉換成JAVA對象的格式。 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); // 最后,將XML轉換成對映的類,轉換后需要強制性轉換成映射的類 StringReader stringReader = new StringReader(xml); Object object = unmarshaller.unmarshal(stringReader); return object; } public static class PreferredMapper extends NamespacePrefixMapper { @Override public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) { if ("http://www.xxx.com/rootelement".equals(namespaceUri)) { return "ie"; } return suggestion; } } }