JAVA如何生成XML文件,然后接口访问下载保存

2,518 阅读5分钟

业务场景:业务需求,使用定时任务在线生成XML,存放到项目根目录,然后接口访问,下载到本地

所涉及到的技术点:

1、定时任务(我这里使用的是quartz)

2、生成XML文件

3、下载相对路径的项目内文件

1、定时任务(我这里使用的是quartz)

这里只贴出下我的代码部分,以作记录,后面会细分析定时任务,这个是传统SSM框架,所以在配置文件中配置相关内容

<bean id="createSiteMapXML" class="com.testdaily.web.util.createSiteMapXMLJob"/>
<!--上面的bean,是实际需要运行的生成XML文件的代码-->
    <bean id="sendGroupMsgJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="group" value="send_group_msg_job_detail"/>
        <property name="name" value="send_group_msg_job_detail_name"/>
        <!--false表示等上一个任务执行完后再开启新的任务-->
        <property name="concurrent" value="false"/>
        <property name="targetObject">
            <ref bean="createSiteMapXML"/><!--这里是指向 类名-->
        </property>
        <property name="targetMethod">
            <value>SiteMapXML</value><!--这里是指向 createSiteMapXML 这个bean 中的,实际运行的方法名-->
        </property>
    </bean>


    <!--  调度触发器 -->
    <bean id="sendMsgTrigger"
          class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="name" value="send_msg_trigger_name"/>
        <property name="group" value="send_msg_trigger"/>
        <property name="jobDetail">
            <ref bean="sendGroupMsgJobDetail" />
        </property>
        <property name="cronExpression">
            <value>0 0 2 * * ?</value><!--这里是定时任务,表示凌晨2点执行该定时器-->
            <!--<value>*/30 * * * * ?</value>-->
        </property>
    </bean>


    <!-- 调度工厂 -->
    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="sendMsgTrigger"/><!--这里指向 上面定义的 调度器-->
            </list>
        </property>
    </bean>

2、生成XML文件

java中解析xml文件有四种方式,分别是DOM、SAX、JDOM、DOM4J,这四种前两种是系统自带的,后两种需要导入jar包,其中先要对xml文件有一个基本的了解。

xml文件是为了不同程序,不同平台之间数据传输,不同数据平台的数据共享的作用。是以树形结构的存储的。

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
	<book id="1" size="medium">
		<name >安徒生童话</name>
		<price>89</price>
		<language>英文</language>
		<year>2004</year>
	</book>
	<book id="2" size="lower">
		<name>一千零一夜</name>
		<price>65</price>
		<language>日语</language>
		<year>2014</year>
	</book>
	<book id="3" size="large">
		<name>美好</name>
		<price>99</price>
		<language>中文</language>
		<year>2015</year>
	</book>
</bookstore>

这就是一个简单的xml文件,第一行注意的是这是书写规范,并且代码格式为utf-8,还有GBK等,可以在这里修改 后面的每一个节点都有相对应的结束节点,在<>中的id和size就是这个节点的属性,注意需用“ ”,它内部的节点可以理解为子节点。

DOM解析
节点类型   named constant          nodeName()的返回值     nodeValue()的返回值
element    ELEMENT_NODE          element name                   null
Attr          ATTRIBUTE_NODE          属性名称                      属性值
text           TEXT_NODE                       #text                         节点内容

上面这个表还是挺重要的,不知道为什么要这样设置,反正挺烦人的还是得记住,尤其是在DOM解析时

先贴出从网上找到的以DOM方式的代码:

package project_xml;
 
import java.io.File;
import java.io.IOException;
 
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
 
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
 
public class xml_dom {
 	public static void main(String[] args) {
	    xml_dom xml_dom1=new xml_dom();
	   xml_dom1.xml_dom_parse();
	    //xml_dom1.creat_xml();
	}
	
	 public void xml_dom_parse() {
		   DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
			try {
				DocumentBuilder db=dbf.newDocumentBuilder();
				Document docu=db.parse("book.xml");
				//获取所有的书籍节点
	           NodeList booklist=docu.getElementsByTagName("book");
	           for(int i =0;i<booklist.getLength();i++){
	           	Node book_item=booklist.item(i);
	           	System.out.println("第"+(i+1)+"本书");
	           	NamedNodeMap node_att=book_item.getAttributes();//读取属性,并存在一个<span style="font-family: Arial, Helvetica, sans-serif;">NamedNodeMap中</span>
	           	for(int j=0;j<node_att.getLength();j++){
	           		Node node=node_att.item(j);
	           		System.out.print(node.getNodeName()+":"+node.getNodeValue()+" ");
	           		System.out.println();
	           	}
	           	NodeList book_child=book_item.getChildNodes();
	           	for(int k=0;k<book_child.getLength();k++){
	           		Node book_child_ele=book_child.item(k);
	           		if(book_child_ele.getNodeType()==Node.ELEMENT_NODE){//如果没有会打印出很多空格,因为text也是一种节点类型,
	           			//System.out.println(book_child_ele.getNodeName()+":"+book_child_ele.getFirstChild().getNodeValue());
	           			////这个就是采集到这个<name></name>中所有的所有的text
	           			System.out.println(book_child_ele.getNodeName()+":"+book_child_ele.getTextContent());
	           		}
	           	}
	           	System.out.println("以上就是第"+(i+1)+"本书");
	           	
	           }
			} catch (ParserConfigurationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SAXException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	 
	 public void creat_xml() {
		try {
			DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
			DocumentBuilder db=dbf.newDocumentBuilder();
			Document document=db.newDocument();
			//可以将standalone设置为true,这样就不会显示了,表示的意思是不需要说明文档
			document.setXmlStandalone(true);
			Element bookstore=document.createElement("bookstore");
			Element book=document.createElement("book");
			Element name=document.createElement("name");
			name.setTextContent("安徒生童话");
			book.setAttribute("id", "1");
			book.setAttribute("size", "lower");
			book.appendChild(name);
			bookstore.appendChild(book);
			document.appendChild(bookstore);
			TransformerFactory tf=TransformerFactory.newInstance();
			Transformer transformer=tf.newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.transform(new DOMSource(document), new StreamResult(new File("book1.xml")));
		} catch (ParserConfigurationException  e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

我的项目里面使用的是DOM4J的方式,下面是部分代码:

    try {
            // 1、创建document对象
            Document document = DocumentHelper.createDocument();
            // 2、创建根节点rss
            Element rss = document.addElement("urlset");
            // 3、向rss节点添加version属性
            // rss.addAttribute("version", "1.0");
            // 4、生成子节点及子节点内容
            Element postingchannel = rss.addElement("url");
            Element postingtitle = postingchannel.addElement("loc");
            postingtitle.setText("http://www.shenxuanxiao.cn/article-"+postingId+".html");
            Element postingtitle1 = postingchannel.addElement("lastmod");
            postingtitle1.setText(time);
            Element postingtitle2 = postingchannel.addElement("changefreq");
            postingtitle2.setText("daily");
            Element postingtitle3 = postingchannel.addElement("priority");
            postingtitle3.setText("0.8");
            // 5、设置生成xml的格式
            OutputFormat format = OutputFormat.createPrettyPrint();
            // 设置编码格式
            format.setEncoding("UTF-8");
            String filePath= ClassUtils.getDefaultClassLoader().getResource("").getPath();
            // 6、生成xml文件
            File file = new File(filePath+"SiteMap.xml");
            XMLWriter writer = new XMLWriter(new FileOutputStream(file), format);
            // 设置是否转义,默认使用转义字符
            writer.setEscapeText(false);
            writer.write(document);
            writer.close();
            System.out.println("生成 SiteMap.xml成功");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("生成 SiteMap.xml失败");
        }    

如果想了解其他三种方式,可以阅读:juejin.cn/post/684490…

3、下载相对路径的项目内文件

根据业务需求,我这里是直接访问接口,下载项目内部文件,所有只需要确定文件的路径即可,下面是实现代码

@RequestMapping(value = "/downloadSiteMapXML", method = {RequestMethod.GET})
    @ResponseBody
    public void downloadSiteMapXML(HttpServletRequest request, HttpServletResponse response  ){
        try{
            String filePath= ClassUtils.getDefaultClassLoader().getResource("").getPath();//项目的根目录
            String resultFileName = "SiteMap.xml";//输出时的文件名
            resultFileName = URLEncoder.encode(resultFileName,"UTF-8");//设置字符集
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-disposition", "attachment; filename=" + resultFileName);// 设定输出文件头
            response.setContentType("application/msexcel");// 定义输出类型
            //输入流:本地文件路径
            DataInputStream in = new DataInputStream(
                    new FileInputStream(new File(filePath+ "SiteMap.xml")));//读取本地文件
            //输出流
            OutputStream out = response.getOutputStream();
            //输出文件
            int bytes = 0;
            byte[] bufferOut = new byte[1024];
            while ((bytes = in.read(bufferOut)) != -1) {
                out.write(bufferOut, 0, bytes);
            }
            out.close();
            in.close();
        } catch(Exception e){
            e.printStackTrace();
            response.reset();
            try {
                OutputStreamWriter writer = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
                String data = "<script language='javascript'>alert(\"\\u64cd\\u4f5c\\u5f02\\u5e38\\uff01\");</script>";
                writer.write(data);
                writer.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }