业务场景:业务需求,使用定时任务在线生成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();
}
}
}