Web版RSS阅读器(五)——初步完成阅读功能

最后更新于:2022-04-01 20:40:22

     上一篇博文《[Web版RSS阅读器(四)——定制自己的Rss解析库myrsslib4j](http://blog.csdn.net/xiaoxian8023/article/details/10048325)》中,已经分享给大家制作自己的rss解析库。稍微有点遗憾的是,它仅仅支持rss格式的博客。现在给大家分享一下我基于rome修改而成的另一款rss解析库——myrome,完美支持atom和rss 2种格式。     myrome.jar是在rome的基础上修改而来的,主要改动的地方是:([查看](http://note.youdao.com/share/?id=e9cdd75e55131fe6383e63d49fcc2440&type=note)[详细修改说明](http://note.youdao.com/share/?id=e9cdd75e55131fe6383e63d49fcc2440&type=note)) 1. 修改GetAuthor()返回null 1. 修改getPublishedDate()返回null 1. 添加获取文章摘要的接口和方法     附下载地址:[http://pan.baidu.com/share/link?shareid=3563208157&uk=1259218556](http://pan.baidu.com/share/link?shareid=3563208157&uk=1259218556)     本篇主题是把myrome加入到RssReader中,修改界面,完成初步的访问和阅读的功能。具体实现的效果为: 1. 根据不同的订阅信息,加载对应的图标,从而一眼得知订阅的出处 1. 点击左侧的某个订阅,在中间的页面中显示出标题、时间和摘要列表,用水平线隔开 1. 点击某个摘要信息,在右侧内容区域,显示该文章的所有内容。 1. 双击摘要信息,则会用新窗口打开原文章地址。     等不及了吗?点[这里](http://mfxuan.free.800m.net/)或者**[](http://mfxuan.free.800m.net/)**[这里](http://test.free.800m.net/)抢先查看效果吧。     言归正传,接下来请大家跟随我初步成功的脚步:     下载myrome-1.0.jar,拷贝到WebRoot/WEB-INF/lib下。如果已经引用过rome-0.2.jar,要提前删除掉。在com.tgb.rssreader.manager包中新建RomeReadRss类,用来解析在线rss内容。 【RomeReadRss.java】 ~~~ package com.tgb.rssreader.manager; import java.net.URL; import java.net.URLConnection; import com.sun.syndication.feed.synd.SyndFeed; import com.sun.syndication.io.SyndFeedInput; import com.sun.syndication.io.XmlReader; /** * 解析Rss订阅信息 * * @author Longxuan * */ public class RomeReadRss { /** * 解析Rss订阅信息 */ public SyndFeed parseRss(String rss) { SyndFeed feed = null; feed = null; try { URLConnection feedUrl = new URL(rss).openConnection(); // 由于服务器屏蔽java作为客户端访问rss,所以设置User-Agent feedUrl.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); // 读取Rss源 XmlReader reader = new XmlReader(feedUrl); SyndFeedInput input = new SyndFeedInput(); // 得到SyndFeed对象,即得到Rss源里的所有信息 feed = input.build(reader); } catch (Exception e) { e.printStackTrace(); } return feed; } } ~~~     修改left.jsp页的树形节点加载信息,根据不同的博客提供商,加载不同的图标。点击某节点后,将rss地址传递给servlet,去解析在线的rss。 【left.jsp】 ~~~ <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <%@ page import="com.tgb.rssreader.bean.*" %> <%@ page import="java.util.*" %> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()+path+"/"; %>
~~~     在com.tgb.rssreader.web包中新建一个RssServlet类,继承HttpServlet,实现doGet和doPost方法。它接收到有left.jsp传递过来的rss地址,调用RomeReadRss来解析rss内容。解析完毕后,转向middle.jsp,在中间这个网页中,显示解析的内容。 【RssServlet.java】 ~~~ package com.tgb.rssreader.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.sun.syndication.feed.synd.SyndFeed; import com.tgb.rssreader.manager.RomeReadRss; /** * 解析Rss信息资源Servlet * @author Longxuan * */ @SuppressWarnings("serial") public class RssServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取rss地址 String rss = request.getParameter("rss"); //获取基于myrome的解析对象 RomeReadRss romeReadRss = RomeReadRss.getInstance(); //解析rss内容,存放到SyndFeed对象中 SyndFeed feed = romeReadRss.parseRss(rss); //设置属性,用于传递SyndFeed对象 request.getSession().removeAttribute("feed"); request.getSession().setAttribute("feed", feed); //转向middle.jsp request.getRequestDispatcher("/middle.jsp").forward(request, response); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException { doGet(req, resp); } } ~~~     解析完毕后,开始修改middle.jsp。它接受到request中传递过来的SyndFeed对象,读取文章标题、发布时间及摘要信息,每篇文章都用横线隔开。未阅读过的显示黑色字体,阅读过后,显示灰色字体,鼠标指上去会变蓝色。点击文章摘要后,将该摘要的索引值传递过去;双击文章摘要信息,则会在新窗口中打开对应文章的实际连接。 【middle.jsp】 ~~~ <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <%@ page import="com.sun.syndication.feed.synd.*"%> <%@page import="java.util.List"%> <%@page session="true" %> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %>
~~~          当点击某篇文章标题时,将该文章的索引值传递到ArticleServlet中,在Session中找到对应的文章,把文章正文内容传递到content.jsp页面。所以在com.tgb.rssreader.web包中新建ArticleServlet类,继承HttpServlet,实现doGet和doPost方法。 【ArticleServlet.java】 ~~~ package com.tgb.rssreader.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.sun.syndication.feed.synd.SyndContent; import com.sun.syndication.feed.synd.SyndEntry; import com.sun.syndication.feed.synd.SyndFeed; /** * 获取文章正文 * @author Longxuan * */ @SuppressWarnings("serial") public class ArticleServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取要查看的文章的索引值 int articleIndex = request.getParameter("articleIndex") == null? 0: Integer.parseInt( request.getParameter("articleIndex")); //获取session中的变量 SyndFeed feed = (SyndFeed) request.getSession().getAttribute("feed"); SyndContent content = (SyndContent)((SyndEntry)feed.getEntries().get(articleIndex)).getContents().get(0); request.setAttribute("content", content.getValue()); request.getRequestDispatcher("/content.jsp").forward(request, response); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } } ~~~     在content.jsp中获取文章内容进行显示即可: 【content.jsp】 ~~~ <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <%@page import="com.sun.syndication.feed.synd.*"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %>

<%= request.getAttribute("content")==null?"" + "欢迎使用提高班在线Rss阅读器!" + "——@龙轩" :request.getAttribute("content").toString()%>


~~~     至此,Web版Rss阅读器阅读博客功能基本已经完工了,终于可以看到这款rss阅读器的样子了。当然需要优化的地方还很多。暂时打算告一段落,等过段时间再进行优化。基本的代码都已经写过了,~~不打算单独提供源码了。~~本来不打算提供源码了,因为按照步骤,差不多能整出来的。不过为了方便大家,刚刚还是把源码上传了,资源地址: [http://download.csdn.net/detail/xiaoxian8023/8116737](http://download.csdn.net/detail/xiaoxian8023/8116737)      最后晒一下效果图吧: [![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c293e265.jpg)](http://mfxuan.free.800m.net/) [![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c294f0f5.jpg)](http://mfxuan.free.800m.net/) **(点击图片在查看网站实例)** ** ** 如果您觉得做得不错,值得鼓励,就轻轻地【**顶一下**】吧 ';

Web版RSS阅读器(四)——定制自己的Rss解析库myrsslib4j

最后更新于:2022-04-01 20:40:20

      在上篇博文《[Web版RSS阅读器(三)——解析在线Rss订阅](http://blog.csdn.net/xiaoxian8023/article/details/9811833)》中,已经提到了遇到的问题,这里再详细说一下。       在解析rss格式的订阅时,遇到的最主要的问题是,出现了“Server returned HTTP response code: 403 for URL: http://xxxxxx”的错误,[百度一下](http://www.baidu.com/s?wd=Server+returned+HTTP+response+code%3A+403+for+URL)就知道,这是在网站访问中很常见的一个错误,服务器理解客户的请求,但拒绝处理它。即拒绝访问!接着查资料,得知某些服务器(比如CSDN博客)拒绝java作为客户端进行对其的访问,所以在解析时,会抛异常。      不让访问怎么办,别怕,我们上有政策,下有对策。通过设置User-Agent来欺骗服务器,从而访问服务器。     ~~~ connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //用UA伪装访问连接对象 ~~~      但是折腾了半天,发现只有修改rsslib4j.jar才能给连接对象设置UA。只好找源码修改一下了,N久之后,在Google Code上猎取到一个开源的项目newrsslib4j,它是在rsslib4j的基础上修改而来的,项目开源主页:[http://code.google.com/p/newrsslib4j/](http://code.google.com/p/newrsslib4j/)。满怀欣喜的下载下来,结果发现,依旧有403的问题。一狠心,自己来做一个rsslib,然后就checkout了newrsslib4j的源码,自己动手改动。      1. 修改403 forbidden问题。      修改org.gnu.stealthp.rsslib包中的RssParser类的setXmlResource()方法,给URLConnection对象,添加UA。 ~~~ /** * Set rss resource by URL * @param ur the remote url * @throws RSSException */ public void setXmlResource(URL ur) throws RSSException{ try{ URLConnection con = u.openConnection(); //----------------------------- //添加时间:2013-08-14 21:00:17 //人员:@龙轩 //博客:http://blog.csdn.net/xiaoxian8023 //添加内容:由于服务器屏蔽java作为客户端访问rss,所以设置User-Agent con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //----------------------------- con.setReadTimeout(10000); String charset = Charset.guess(ur); is = new InputSource (new UnicodeReader(con.getInputStream(),charset)); if (con.getContentLength() == -1 && is == null){ this.fixZeroLength(); } }catch(IOException e){ throw new RSSException("RSSParser::setXmlResource fails: "+e.getMessage()); } } ~~~      修改org.mozilla.intl.chardet包中的Charset类的guess()方法,注释掉原来的InputStream对象,创建URLConnection,设置User-Agent,通过URLConnection对象创建InputStream : ~~~ //judge from url public static String guess(URL url) throws IOException { //----------------------------- //修改时间:2013-08-14 21:00:17 //人员:@龙轩 //博客:http://blog.csdn.net/xiaoxian8023 //修改内容:注释InputStream,创建URLConnection,设置User-Agent,通过URLConnection对象创建InputStream //InputStream in = url.openStream(); URLConnection con = url.openConnection(); con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); InputStream in = con.getInputStream(); //----------------------------- return guess(in); } ~~~      2. 添加获取文章摘要的方法      测试以后,发现Rss格式的订阅,居然没有提供一个获取内容摘要的方法。所以,继续修改。修改org.gnu.stealthp.rsslib包中的RssObject类,添加一个getSummary()方法,用来获取内容摘要: ~~~ //----------------------------------- //添加时间:2013-08-14 19:32:15 //人员:@龙轩 //添加内容:添加getSummary()方法,返回文章摘要信息 /** * Get the element's summary * @return the summary */ public String getSummary(){ String summary = getDescription(); if (summary.length() >= 300) { summary = summary.substring(0, 300); } String regEx_html = "\\s|<[^>]+>|&\\w{1,5};"; // 定义HTML标签和特殊字符的正则表达式 Pattern pattern = Pattern.compile(regEx_html,Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(summary); summary = matcher.replaceAll(""); // 过滤script标签 if (summary.length() >= 100) { summary = summary.substring(0, 100); } summary = summary + "..."; return summary; } //添加结束----------------------------------------------- ~~~      3. 解决解析不完全问题      网易博客可以很好的解析出博客的link,language等节点,但是csdn、某些新闻资讯网站则不行。花了很长的时间去找问题,终于在不经意间,发现网易的博客节点的排列顺序与别的不一样,link,language等节点排在image节点上面的,而csdn则是在image的下面(如图),程序在解析时,先解析channel下的节点,写入到channel中,读取到image,则标记解析channel的变量为false,然后开始解析image节点下的内容。解析完毕以后,又要去解析channel节点下的link时,channel标记已经为false了,不能再继续解析,所以总是返回null。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c290a429.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c291a6d4.jpg)      修改方案也很简单,就是所有标记解析channel为false的节点,在解析完毕该节点后,重新标记解析channel为true,这样就可以继续解析channel节点下的其他值 。具体修改操作:查看org.gnu.stealthp.rsslib包的RSSHandler类的startElement()方法,看看谁执行了 reading_chan = false; 这句代码。然后在endElement()方法中,重新设置 reading_chan = true; 即可: ~~~ /** * Receive notification of the end of an element * @param uri The Namespace URI, or the empty string if the element has no Namespace URI or if Namespace processing is not being performed. * @param localName The local name (without prefix), or the empty string if Namespace processing is not being performed * @param qName The qualified name (with prefix), or the empty string if qualified names are not available */ public void endElement(String uri, String localName, String qName){ String data = buff.toString().trim(); if (qName.equals(current_tag)){ data = buff.toString().trim(); buff = new StringBuffer(); } if (reading_chan) processChannel(qName,data); if (reading_item) processItem(qName,data); if (reading_image) processImage(qName,data); if (reading_input) processTextInput(qName,data); if (tagIsEqual(qName,CHANNEL_TAG)){ reading_chan = false; chan.setSyndicationModule(sy); } if (tagIsEqual(qName,ITEM_TAG)){ reading_item = false; //----------------------------------------- //添加时间:2013-08-14 21:00:17 //人员:@龙轩 //博客:http://blog.csdn.net/xiaoxian8023 //添加内容:重新允许解析channel reading_chan = true; //添加结束--------------------------------- chan.addItem(itm); } if (tagIsEqual(qName,IMAGE_TAG)){ reading_image = false; //----------------------------------------- //添加时间:2013-08-14 21:00:17 //人员:@龙轩 //博客:http://blog.csdn.net/xiaoxian8023 //添加内容:重新允许解析channel reading_chan = true; //添加结束--------------------------------- chan.setRSSImage(img); } if (tagIsEqual(qName,SEQ_TAG)){ reading_seq = false; chan.addRSSSequence(seq); } if (tagIsEqual(qName,TEXTINPUT_TAG)){ reading_input = false; //----------------------------------------- //添加时间:2013-08-14 21:00:17 //人员:@龙轩 //博客:http://blog.csdn.net/xiaoxian8023 //添加内容:重新允许解析channel reading_chan = true; //添加结束--------------------------------- chan.setRSSTextInput(input); } } ~~~      至此,修改的就差不多了,打开一下org.javali.util.test包的RssNewsFetcher类,修改一下测试列表和方法: ~~~ package org.javali.util.test; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import org.gnu.stealthp.rsslib.RSSChannel; import org.gnu.stealthp.rsslib.RSSException; import org.gnu.stealthp.rsslib.RSSHandler; import org.gnu.stealthp.rsslib.RSSItem; import org.gnu.stealthp.rsslib.RSSParser; public class RssNewsFetcher { /** * rss订阅列表 */ private final static String[] rssArr = new String[] { //"http://news.baidu.com/n?cmd=1&class=civilnews&tn=rss", "http://xiaoxian100.blog.163.com/rss", "http://blog.csdn.net/xiaoxian8023/rss/list" }; /** * 测试解析rss订阅 * @throws IOException */ public void testFetchRssNews() throws IOException { for (int i = 0; i < rssArr.length; i++) { try { //获取rss订阅地址 URL url = new URL(rssArr[i]); RSSHandler handler = new RSSHandler(); //解析rss RSSParser.parseXmlFile(url, handler, false); //获取Rss频道信息 RSSChannel ch = handler.getRSSChannel(); System.out.println("---------------------------------------------"); System.out.println("博客标题:" + ch.getTitle()); System.out.println("博客链接:" + ch.getLink()); System.out.println("博客描述:" + ch.getDescription()); System.out.println("博客语言:" + ch.getLanguage()); System.out.println("发布时间:" + ch.getPubDate()); System.out.println("图片地址:" +ch.getRSSImage().getUrl()); System.out.println("图片指向:" +ch.getRSSImage().getLink()); System.out.println("共有文章数目为:" + ch.getItems().size()); // for(i=0;i ';

Web版RSS阅读器(三)——解析在线Rss订阅

最后更新于:2022-04-01 20:40:18

    上篇博客《[ Web版RSS阅读器(二)——使用dTree树形加载rss订阅分组列表](http://blog.csdn.net/xiaoxian8023/article/details/9745727)》已经写到读取rss订阅列表了,今天就说一下,当获取一条在线rss订阅的信息,怎么去解析它,从而获取文章或资讯。     首先说一下rss的版本。很多人都说rss,但是有相当一部分人,都不知道rss居然不只一种格式。我们常用的订阅格式有Rss和Atom 2种格式。Rss有版本从v0.9一直到现在的v2.0,Atom最新的版本则是1.0。     DeveloperWorks有一篇文章《[使用 RSS 和 Atom 实现新闻联合](http://www.ibm.com/developerworks/cn/web/wa-syndrssatom/index.html)》提及两者的相似点与不同点: ``> #### RSS 和 Atom 摘要的相似点 >   > 每个摘要文件实际上代表一个通道。它包含通道标题、链接、描述、作者等等。通道信息提供关于摘要的基本信息。通道信息之后是一些项。每项代表一篇可以从摘要阅读器阅读的真实的新闻或者文章。通常情况下,每项包含有标题、链接、更新时间和摘要信息。 > #### RSS 和 Atom 摘要的不同点 > 参考 [RSS 2.0 and Atom 1.0, Compared](http://www.intertwingly.net/wiki/pie/Rss20AndAtom10Compared),回顾 RSS 和 Atom 的不同点。

不同点RSS 2.0Atom 1.0

部署RSS 2.0 得到广泛部署。Atom 1.0 还未得到广泛部署。

规范哈佛大学拥有版权并冻结了 RSS 2.0 规范。Atompub 工作组(属于 IETF)就 Atom 1.0 规范达成一致意见,并在将来有可能重新修订。

所需内容RSS 2.0 包含所需的摘要级别的标题、链接和描述。它不需要在摘要中出现的任何单独项的字段。Atom 1.0 包含摘要和条目所需的标题(可以为空)、惟一标识和最后更新的时间戳。

有效负载(payload)RSS 2.0 可以包含普通文本或者转义 HTML,但是不能分辨所提供的是两个中的哪一个。Atom 1.0 包含有效负载容器。

全部或者部分内容RSS 2.0 有一个 <description> 元素,可以包含条目的全部文本或者大纲。它没有用于标识内容是否完全的内置方法。Atom 1.0 提供单独的 <summary> 和 <content> 元素。如果它是非文本的或者非本地的内容,出于可访问性的原因摘要将很好用。

自动发现RSS 2.0 用不同的方法实现自动发现。Atom 1.0 标准化自动发现。

提取和聚合RSS 2.0 只有一个可识别的形式:一个<rss> 文档。Atom 1.0 允许独立的 Atom Entry 文档,可以使用任何网络协议传输;例如,XMPP。Atom 也支持聚合摘要,其中,条目指向它们来自的摘要,前提是如果它们将被包含到其他摘要中。

> > RSS 和 Atom 具有相似的基于 XML 的格式。它们的基本结构是相同的,只在节点的表达式上有一点区别。 在Rss标准格式: ~~~                   Lift Off News      http://liftoff.msfc.nasa.gov/      Liftoff to Space Exploration.      en-us      Tue, 10 Jun 2003 04:00:00 GMT      Tue, 10 Jun 2003 09:41:01 GMT   http://blogs.law.harvard.edu/tech/rss      Weblog Editor 2.0   5               Star City      http://liftoff.msfc.nasa.gov/news/2013/news-starcity.asp      How do Americans get ready to work with Russians aboard the   International Space Station? They take a crash course in culture, language   and protocol at Russia's Star City.      Tue, 03 Jun 2003 09:39:21 GMT      IT      bill   http://liftoff.msfc.nasa.gov/2003/06/03.html#item573            Space Exploration   http://liftoff.msfc.nasa.gov/   Sky watchers in Europe, Asia, and parts of Alaska and Canada   will experience a partial eclipse of the Sun on Saturday, May 31st.   Fri, 30 May 2003 11:06:42 GMT   http://liftoff.msfc.nasa.gov/2003/05/30.html#item572           ~~~ Atom 1.0的格式: ~~~  Schema Web    2004-06-01T10:11:12Z     Uche Ogbuji       Welcome to Stanza Web       龙轩 http://www.cnblogs.com/longxuan/         2004-06-01T10:11:12Z       
    

Welcome to      Stanza Web.      Come back often to keep track of the best in modern poetry.     

    

This site is powered by       Atom     

   
  
 
~~~     大部分新闻或博客网站都使用的是rss,当然Atom也占有部分市场。比如博客园就是用的Atom,而CSDN则用的是RSS。    了解了这些以后,就可以开始解析Rss了。    在网上找了一下开源的包,选了2款常用的都实验了一下,一个是Rome.jar,一个是rsslib4j.jar。二者的区别我就不多介绍了,有兴趣了可以去百度一下。rsslib4j 小巧,兼容性好,但是现在只支持解析rss 0.9x ,1.0 和 2.0,暂时对于atom无能为力。rsslib4j的开源主页:[http://sourceforge.net/projects/rsslib4j/](http://sourceforge.net/projects/rsslib4j/)。有什么需要的,可以在主页进行下载。     在WebRoot/lib中引用rsslib4j-0.2.jar,在src的com.tgb.rssreader.manager包中新建一个类Rsslib4jReadRss,贴出代码: ~~~ package com.tgb.rssreader.manager; import java.net.URL; import java.net.URLConnection; import java.util.List; import org.gnu.stealthp.rsslib.RSSChannel; import org.gnu.stealthp.rsslib.RSSHandler; import org.gnu.stealthp.rsslib.RSSImage; import org.gnu.stealthp.rsslib.RSSItem; import org.gnu.stealthp.rsslib.RSSParser; public class Rsslib4jReadRss { //这里定义一个在线的rss摘要的地址(对应我的网易博客) public static final String remoteRSS="http://xiaoxian100.blog.163.com/rss"; public static void main(String[] args) throws Exception { // 让RSSParser去解析在线的rss的url RSSHandler remoteRSSHandler = new RSSHandler(); URL url = new URL(remoteRSS); URLConnection feedUrl = url.openConnection(); RSSParser.parseXmlFile(feedUrl.getURL(), remoteRSSHandler, false); // 取得rss元素的信息并且打印在控制台上 String remoteRSSInfo=Rsslib4jReadRss.getRSSInfo(remoteRSSHandler); System.out.println("********我的网易博客的 rss信息如下**********"); System.out.println(remoteRSSInfo); System.out.println("**************************"); } public static String getRSSInfo(RSSHandler handler) { StringBuffer rssInfo = new StringBuffer(); // 取得rss提要的频道信息(Channel) RSSChannel channel = handler.getRSSChannel(); // Part1: 分离出rss频道的元信息 // (1)频道的标题 String titleInfo = channel.getTitle(); // (2)频道的链接信息 String linkInfo = channel.getLink(); // (3)频道的描述信息 String descriptionInfo = channel.getDescription(); // (4)频道使用的语言 String languageInfo = channel.getLanguage(); // (5)频道版权信息 String copyrightInfo = channel.getCopyright(); // (6)频道的generator的信息 String generatorInfo = channel.getGenerator(); // (7)频道的image信息 RSSImage channelImage = channel.getRSSImage(); String channelImageUrl = channelImage.getUrl(); rssInfo.append("频道标题: " + titleInfo + "\n"); rssInfo.append("频道相关Link信息: " + linkInfo + "\n"); rssInfo.append("频道描述信息: " + descriptionInfo + "\n"); rssInfo.append("频道使用的语言: " + languageInfo + "\n"); rssInfo.append("频道版权信息: " + copyrightInfo + "\n"); rssInfo.append("频道产生器信息: " + generatorInfo + "\n"); rssInfo.append("频道图片URL: " + channelImageUrl + "\n"); //Part2: 分离出rss频道的所有摘要(feed),这里用item表示 List channelItems = channel.getItems(); int itemSize = channelItems.size(); if (itemSize >= 1) { rssInfo.append("\n"); rssInfo.append("一共有 " + itemSize + "个摘要在这个频道中"); rssInfo.append("\n"); for (int i = 0; i < itemSize; i++) { int itemNo = i + 1; RSSItem item = (RSSItem) channelItems.get(i); rssInfo.append("\n"); rssInfo.append("摘要" + itemNo + ":"); // (1)摘要的作者 String itemAuthor = item.getAuthor(); // (2)摘要的标题 String itemTitle = item.getTitle(); // (3)摘要的描述 String itemDescription = item.getDescription(); // (4)摘要的链接 String itemLink = item.getLink(); // (5)摘要的发布日期 String itemPubDate = item.getPubDate(); rssInfo.append("作者: " + itemAuthor + "\n"); rssInfo.append("标题: " + itemTitle + "\n"); rssInfo.append("描述: " + itemDescription + "\n"); rssInfo.append("链接: " + itemLink + "\n"); rssInfo.append("发布日期: " + itemPubDate + "\n"); rssInfo.append("\n"); } } return rssInfo.toString(); } } ~~~     由于文章太多,在Console中测试时,可能会看不到后面的效果,所以我只让程序读取了一个文章摘要(for循环次数修改为1),效果图如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c28e561f.jpg)     在解析网易博客时,还算勉强可以胜任,但是在解析CSDN博客时,就会报错"Server returned HTTP response code: 403 for URL: http://xxxxxx",这是因为CSDN博客,拒绝java作为客户端进行访问其服务器。而且在解析个别信息时,会出现null值。     那怎么办呀?别着急,下篇博文,大家跟我一起修改rsslib4j,做自己的rsslib4j。敬请期待!
';

Web版RSS阅读器(二)——使用dTree树形加载rss订阅分组列表

最后更新于:2022-04-01 20:40:15

    在上一边博客《[Web版RSS阅读器(一)——dom4j读取xml(opml)文件](http://blog.csdn.net/xiaoxian8023/article/details/9628751)》中已经讲过如何读取rss订阅文件了。这次就把订阅的文件读取到页面上,使用树形结构进行加载显示。

      不打算使用特殊的控件进行树型显示,也不想自己写了,想省劲些,就在

网上找了一个js树形脚本——dTree。dTree是一个易于使用的JavaScript树形

菜单控件。支持无限分级,可以在同一个页面中放置多个dTree,可以为每个

节点指定不同的图标。

      主页:http://destroydrop.com/javascripts/tree/default.html

      下载:http://destroydrop.com/javascripts/tree/dtree.zip

      示例:http://destroydrop.com/javascripts/tree/v1/


    我使用的是mvc2来实现加载rss分组列表的。mvc2的流程如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c28b4f26.jpg)     由于这次是使用jsp来显示,所以把rss文件夹转移到WebRoot文件夹下了。对原来的【ReadXML.java】做了部分修改,重新贴出来。 ~~~ package com.tgb.rssreader.manager; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import com.tgb.rssreader.bean.RssBean; import com.tgb.rssreader.bean.RssConfigBean; import com.tgb.rssreader.bean.RssTeamBean; /** * 读取xml文件 * @author Longxuan * */ public class ReadXML { // rss分组订阅列表 private List rssTeamBeanList = new ArrayList(); /** * 读取rss文件列表 * @param directory */ public void ReadRssTeam(String directory) { // rss文件列表配置信息实体 RssConfigMgr rssConfigMgr = new RssConfigMgr(); List list = rssConfigMgr.getRssConfig(); String errText = "";// 记录错误信息 // 循环读取rss文件列表 for (RssConfigBean rssConfig : list) { // System.out.println(rssConfig.getName() + "----" + // rssConfig.getPath()); try { // 读取rss文件内容 //ReadRss(System.getProperty("user.dir")+ rssConfig.getPath()); ReadRss(directory + rssConfig.getPath()); } catch (Exception e) { errText += e.getMessage(); } } //如果有异常信息,则汇总后抛出 if(!"".equals(errText)){ throw new RuntimeException(errText); } } /** * 读取ompl文件 * * @param filePath */ private void ReadRss(String filePath) { File file = new File(filePath); if (!file.exists()) { // System.out.println("找不到【" + filePath + "】文件"); // return; throw new RuntimeException("找不到【" + filePath + "】文件"); } try { // 读取并解析XML文档 // SAXReader就是一个管道,用一个流的方式,把xml文件读出来 SAXReader reader = new SAXReader(); FileInputStream fis = new FileInputStream(file); // 下面的是通过解析xml字符串的 Document doc = reader.read(fis); // 获取根节点 Element rootElt = doc.getRootElement(); // 获取根节点 // System.out.println("根节点:" + rootElt.getName()); // 拿到根节点的名称 // 获取head/title节点 Element titleElt = (Element) rootElt.selectSingleNode("head/title");// 获取head节点下的子节点title // 获取分组名称 String title = titleElt.getTextTrim(); // 获取body节点 Element bodyElt = (Element) rootElt.selectSingleNode("body"); // 获取body下的第一个outline节点 Element outlineElt = (Element) bodyElt.selectSingleNode("outline"); // 判断该outlineElt节点的属性数量,>2说明是详细博客订阅信息,否则则是分组信息。 if (outlineElt.attributes().size() > 2) { // 详细博客订阅信息 // 实例化 RSS分组实体 RssTeamBean rssTeamBean = new RssTeamBean(); // 获取body节点下的outline节点 Iterator iter = bodyElt.elementIterator("outline"); // 输出分组名称 // System.out.println("分组名称:" + title); // 记录分组名称 rssTeamBean.setTitle(title); rssTeamBean.setText(title); // 实例化订阅列表 List rssBeanList = new ArrayList(); // 获取详细博客订阅信息 ReadBlogsInfo(iter, rssBeanList); // 设置订阅列表到分组中 rssTeamBean.setRssBeanList(rssBeanList); // 添加分组到rss分组订阅列表 rssTeamBeanList.add(rssTeamBean); } else { // 分组信息 // 获取body节点下的outline节点 Iterator iter = bodyElt.elementIterator("outline"); while (iter.hasNext()) { // 读取outline节点下的所有outline信息,每条信息都是一条订阅记录 Element TeamElt = (Element) iter.next(); // 实例化 RSS分组实体 RssTeamBean rssTeamBean = new RssTeamBean(); // 重新获取分组名称 title = TeamElt.attributeValue("title"); String text = TeamElt.attributeValue("text"); // System.out.println("分组title:" + title + " text:" + // text); // 记录分组名称和显示名称 rssTeamBean.setTitle(title); rssTeamBean.setText(text); // 实例化订阅列表 List rssBeanList = new ArrayList(); // 获取body节点下的outline节点 Iterator iterRss = TeamElt.elementIterator("outline"); // 获取详细博客订阅信息 ReadBlogsInfo(iterRss, rssBeanList); // 设置订阅列表到分组中 rssTeamBean.setRssBeanList(rssBeanList); // 添加分组到rss分组订阅列表 rssTeamBeanList.add(rssTeamBean); } } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (DocumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 读取当前组博客订阅信息 * * @param iter * 当前节点的子节点迭代器 * @param rssBeanList * 订阅列表 */ private void ReadBlogsInfo(Iterator iter, List rssBeanList) { // 遍历所有outline节点,每个节点都是一条订阅信息 while (iter.hasNext()) { RssBean rssBean = new RssBean(); Element outlineElt = (Element) iter.next(); String htmlUrl = outlineElt.attributeValue("htmlUrl"); // 拿到当前节点的htmlUrl属性值 String xmlUrl = outlineElt.attributeValue("xmlUrl"); // 拿到当前节点的xmlUrl属性值 String version = outlineElt.attributeValue("version"); // 拿到当前节点的version属性值 String type = outlineElt.attributeValue("type"); // 拿到当前节点的type属性值 String outlineTitle = outlineElt.attributeValue("title"); // 拿到当前节点的title属性值 String outlineText = outlineElt.attributeValue("text"); // 拿到当前节点的text属性值 rssBean.setHtmlUrl(htmlUrl); rssBean.setXmlUrl(xmlUrl); rssBean.setVersion(version); rssBean.setType(type); rssBean.setTitle(outlineTitle); rssBean.setText(outlineText); rssBean.setText(outlineText); // 将每条订阅信息,存放到订阅列表中 rssBeanList.add(rssBean); } } /** * 获取Rss分组订阅列表 * * @return */ public List getRssTemBeanList() { return rssTeamBeanList; } } ~~~     正题终于开始了:在src中新建包com.tgb.rssreader.web,添加RssTeamServlet,继承HttpServlet,实现doGet和doPost方法。它主要是用来调用com.tgb.rssreader.manager包下的ReadXML 类,以获取到分组信息,然后将其转发给left.jsp。源代码如下: ~~~ package com.tgb.rssreader.web; import java.io.IOException; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.tgb.rssreader.bean.RssTeamBean; import com.tgb.rssreader.manager.ReadXML; /** * 加载Rss分组 * @author Longxuan * */ @SuppressWarnings("serial") public class RssTeamServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取web项目的根目录的实际目录 String path = this.getServletConfig().getServletContext().getRealPath("/"); ReadXML readXML = new ReadXML(); //读取目录下的rss文件夹中的所有opml文件 //将所有分组信息保存在一个List中, //将每个分组下的所有订阅信息,保存在该RssTeamBean中的一个List中 readXML.ReadRssTeam(path); //获取装有所有分组信息的列表 List rssTemBeanList = readXML.getRssTemBeanList(); //将所有分组信息保存在request的属性rssTemBeanList中 request.setAttribute("rssTemBeanList", rssTemBeanList); //转发request request.getRequestDispatcher("/left.jsp").forward(request, response); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } } ~~~     最后一步就是在界面上动工了。界面是自己先简单的做了个html的模版,已上传至[百度网盘](http://pan.baidu.com/share/link?shareid=2484310135&uk=1259218556)。布局使用frameset分割成3列,树形结构的Rss分组信息左侧,即left.jsp。中间的为某个rss订阅地址的文章列表,名为middle.jsp,右侧则是显示文章的地方,名为content.jsp。     现在先做成这样一个效果:左侧的left.jsp页,使用dTree的树形结构加载rss分组信息。点击一个订阅信息节点,在右侧显示出来对应的订阅内容。修改的是left.jsp,贴出源码: ~~~ <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <%@ page import="com.tgb.rssreader.bean.*" %> <%@ page import="java.util.*" %> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()+path+"/"; %>
~~~ 暂时的效果图如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c28cb0a5.jpg)     至此,读取rss分组已经完成了。接下来的博文中,会给大家解说一下rss版本以及解析在线的rss订阅。敬请期待。
';

Web版RSS阅读器(一)——dom4j读取xml(opml)文件

最后更新于:2022-04-01 20:40:13

    接触java不久,偶有收获,最近想做一个web版RSS阅读器来锻炼一下。手头有几个从不同版本的foxmail中导出的opml文件,大家应该都知道,opml文件就是xml格式的。那么就先从这里入手,练习一下使用dom4j读取xml文件。     在java程序设计中,尤其是java web开发程序,xml应用频率超高。Spring、Hibernate、Struts等各种web 框架,MyEclipse、Oracle等IDE,也都主要依托xml。可以说xml对于系统的配置,有着至关重要的作用。而这些也同时增强了系统的灵活性。     先说一下思路:     新建一个java web项目,不过暂时没有使用jsp,servlet。本文只是使用自带的调试器,先进行测试读取xml。接下来的博文中,会带大家一起显示在已经优化的界面中,并提供大部分的rss阅读器的功能。     由于从不同版本的foxmail中导出,文件格式稍有不同,主要分歧是在订阅分组功能上。有的版本导出来的分组信息是在head/title内容中,body/outline则放的是全部的订阅信息;有的导出来的分组信息则是在body/outline中title和text属性中,而详细的订阅信息则放在body/outline/outline中。     我想做的系统可以支持读取多个opml文件,所以需要一个rss文件列表配置文件【rss_config.xml】,对应一个实体:RssConfigBean.java,主要包含有opml文件路径信息;分组信息也需要单独出来,命名为【RssTeamBean.java】,包括title和text两个属性和一个订阅信息的列表。订阅信息肯定也是独立的,命名为【RssBean.java】,包括text、title、xmlUrl、htmlUrl、version、type六个属性。     首先通过读取rss_config.xml,拿到所有opml文件路径,然后循环读取opml,拿到分组信息及每个分组下的所有详细订阅信息,保存到实体中,以供调用显示。     光说不管用,直接上代码:     ①. opml文件 【单分组foxmail6.5.opml】 ~~~ 六期新博客地址 ~~~ 【多分组foxmail7.opml】 ~~~ Subscription in Foxmail ~~~ ②. 在src中新建rss文件列表配置文件 【rss_config.xml】 ~~~ 单分组foxmail6.5 \rss\单分组foxmail6.5.opml 多分组foxmail7 \rss\多分组foxmail7.opml ~~~ ③. 新建包com.tgb.rssreader.bean,添加3个java文件: 【RssBean.java】详细订阅信息 ~~~ package com.tgb.rssreader.bean; /** * 详细订阅信息 * @author Longxuan * */ public class RssBean { /** * 显示名称 */ private String text; /** * 标题 */ private String title; /** * rss订阅地址 */ private String htmlUrl; /** * rss订阅地址 */ private String xmlUrl; /** * 版本 */ private String version; /** * 类型 */ private String type; public String getText() { return text; } public void setText(String text) { this.text = text; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getHtmlUrl() { return htmlUrl; } public void setHtmlUrl(String htmlUrl) { this.htmlUrl = htmlUrl; } public String getXmlUrl() { return xmlUrl; } public void setXmlUrl(String xmlUrl) { this.xmlUrl = xmlUrl; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getType() { return type; } public void setType(String type) { this.type = type; } } ~~~ 【RssConfigBean.java】 rss配置信息 ~~~ package com.tgb.rssreader.bean; /** * rss配置信息 * @author Longxuan * */ public class RssConfigBean { /** * 分组名称 */ private String name; /** * 路径 */ private String path; public String getPath() { return path; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void setPath(String path) { this.path = path; } } ~~~ 【RssTeamBean.java】rss分组信息 ~~~ package com.tgb.rssreader.bean; import java.util.List; /** * rss分组信息 * @author Longxuan * */ public class RssTeamBean { /** * 分组标题 */ private String title; /** * 分组名称 */ private String text; private List rssBeanList ; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getText() { return text; } public void setText(String text) { this.text = text; } public List getRssBeanList() { return rssBeanList; } public void setRssBeanList(List rssBeanList) { this.rssBeanList = rssBeanList; } } ~~~ ④. 新建包com.tgb.rssreader.manager,添加2个文件: 【RssConfigMgr.java】rss文件列表配置管理器 ~~~ package com.tgb.rssreader.manager; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import com.tgb.rssreader.bean.RssConfigBean; /** * rss文件列表配置管理器 * @author Longxuan * */ public class RssConfigMgr { /** * 读取rss文件列表配置信息 * @return */ public List getRssConfig() { List list = new ArrayList(); RssConfigBean rssConfigBean = null; InputStream is = Thread.currentThread().getContextClassLoader() .getResourceAsStream("rss_config.xml"); if (is == null) { //System.out.println("找不到该文件"); //return null; throw new RuntimeException("找不到rss_config.xml文件"); } try { // 读取并解析XML文档 // SAXReader就是一个管道,用一个流的方式,把xml文件读出来 SAXReader reader = new SAXReader(); // 下面的是通过解析xml字符串的 Document doc = reader.read(is); Element rootElt = doc.getRootElement(); // 获取根节点 //System.out.println("根节点:" + rootElt.getName()); // 拿到根节点的名称 Iterator iter = rootElt.elementIterator("rss-list"); // 获取根节点下的子节点rss-list // 遍历rss-list节点 while (iter.hasNext()) { Element recordEle = (Element) iter.next(); String name = recordEle.elementTextTrim("rss-name"); // 拿到rss-list节点下的子节点name值 //System.out.println("name:" + name); String path = recordEle.elementTextTrim("rss-path"); // 拿到rss-list节点下的子节点path值 //System.out.println("path:" + path); rssConfigBean = new RssConfigBean(); //保存到rssConfigBean中 rssConfigBean.setName(name); rssConfigBean.setPath(path); //保存到list中 list.add(rssConfigBean); } } catch (DocumentException e) { e.printStackTrace(); } return list; } } ~~~ 【ReadXML.java】读取xml文件 ~~~ package com.tgb.rssreader.manager; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import com.tgb.rssreader.bean.RssBean; import com.tgb.rssreader.bean.RssConfigBean; import com.tgb.rssreader.bean.RssTeamBean; /** * 读取xml文件 * @author Longxuan * */ public class ReadXML { // rss分组订阅列表 private List rssTeamBeanList = new ArrayList(); /** * 读取rss文件列表 */ public void ReadRss() { // rss文件列表配置信息实体 RssConfigMgr rssConfigMgr = new RssConfigMgr(); List list = rssConfigMgr.getRssConfig(); String errText = "";// 记录错误信息 // 循环读取rss文件列表 for (RssConfigBean rssConfig : list) { // System.out.println(rssConfig.getName() + "----" + // rssConfig.getPath()); try { // 读取rss文件内容 ReadRss(System.getProperty("user.dir")+ rssConfig.getPath()); } catch (Exception e) { errText += e.getMessage(); } } } /** * 读取ompl文件 * * @param filePath */ private void ReadRss(String filePath) { File file = new File(filePath); if (!file.exists()) { // System.out.println("找不到【" + filePath + "】文件"); // return; throw new RuntimeException("找不到【" + filePath + "】文件"); } try { // 读取并解析XML文档 // SAXReader就是一个管道,用一个流的方式,把xml文件读出来 SAXReader reader = new SAXReader(); FileInputStream fis = new FileInputStream(file); // 下面的是通过解析xml字符串的 Document doc = reader.read(fis); // 获取根节点 Element rootElt = doc.getRootElement(); // 获取根节点 // System.out.println("根节点:" + rootElt.getName()); // 拿到根节点的名称 // 获取head/title节点 Element titleElt = (Element) rootElt.selectSingleNode("head/title");// 获取head节点下的子节点title // 获取分组名称 String title = titleElt.getTextTrim(); // 获取body节点 Element bodyElt = (Element) rootElt.selectSingleNode("body"); // 获取body下的第一个outline节点 Element outlineElt = (Element) bodyElt.selectSingleNode("outline"); // 判断该outlineElt节点的属性数量,>2说明是详细博客订阅信息,否则则是分组信息。 if (outlineElt.attributes().size() > 2) { // 详细博客订阅信息 // 实例化 RSS分组实体 RssTeamBean rssTeamBean = new RssTeamBean(); // 获取body节点下的outline节点 Iterator iter = bodyElt.elementIterator("outline"); // 输出分组名称 // System.out.println("分组名称:" + title); // 记录分组名称 rssTeamBean.setTitle(title); rssTeamBean.setText(title); // 实例化订阅列表 List rssBeanList = new ArrayList(); // 获取详细博客订阅信息 ReadBlogsInfo(iter, rssBeanList); // 设置订阅列表到分组中 rssTeamBean.setRssBeanList(rssBeanList); // 添加分组到rss分组订阅列表 rssTeamBeanList.add(rssTeamBean); } else { // 分组信息 // 获取body节点下的outline节点 Iterator iter = bodyElt.elementIterator("outline"); while (iter.hasNext()) { // 读取outline节点下的所有outline信息,每条信息都是一条订阅记录 Element TeamElt = (Element) iter.next(); // 实例化 RSS分组实体 RssTeamBean rssTeamBean = new RssTeamBean(); // 重新获取分组名称 title = TeamElt.attributeValue("title"); String text = TeamElt.attributeValue("text"); // System.out.println("分组title:" + title + " text:" + // text); // 记录分组名称和显示名称 rssTeamBean.setTitle(title); rssTeamBean.setText(text); // 实例化订阅列表 List rssBeanList = new ArrayList(); // 获取body节点下的outline节点 Iterator iterRss = TeamElt.elementIterator("outline"); // 获取详细博客订阅信息 ReadBlogsInfo(iterRss, rssBeanList); // 设置订阅列表到分组中 rssTeamBean.setRssBeanList(rssBeanList); // 添加分组到rss分组订阅列表 rssTeamBeanList.add(rssTeamBean); } } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (DocumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 读取当前组博客订阅信息 * * @param iter * 当前节点的子节点迭代器 * @param rssBeanList * 订阅列表 */ private void ReadBlogsInfo(Iterator iter, List rssBeanList) { // 遍历所有outline节点,每个节点都是一条订阅信息 while (iter.hasNext()) { RssBean rssBean = new RssBean(); Element outlineElt = (Element) iter.next(); String htmlUrl = outlineElt.attributeValue("htmlUrl"); // 拿到当前节点的htmlUrl属性值 String xmlUrl = outlineElt.attributeValue("xmlUrl"); // 拿到当前节点的xmlUrl属性值 String version = outlineElt.attributeValue("version"); // 拿到当前节点的version属性值 String type = outlineElt.attributeValue("type"); // 拿到当前节点的type属性值 String outlineTitle = outlineElt.attributeValue("title"); // 拿到当前节点的title属性值 String outlineText = outlineElt.attributeValue("text"); // 拿到当前节点的text属性值 // System.out.print(""); rssBean.setHtmlUrl(htmlUrl); rssBean.setXmlUrl(xmlUrl); rssBean.setVersion(version); rssBean.setType(type); rssBean.setTitle(outlineTitle); rssBean.setText(outlineText); rssBean.setText(outlineText); // 将每条订阅信息,存放到订阅列表中 rssBeanList.add(rssBean); } } /** * 获取Rss分组订阅列表 * * @return */ public List getRssTemBeanList() { return rssTeamBeanList; } public static void main(String[] args) { ReadXML readXML = new ReadXML(); readXML.ReadRss(); List rssTemBeanList = readXML.getRssTemBeanList(); for (RssTeamBean rssTeamBean : rssTemBeanList) { System.out.println("【分组title:" + rssTeamBean.getTitle() + " text:"+ rssTeamBean.getText()+"】"); for (RssBean rssBean : rssTeamBean.getRssBeanList()) { System.out.print(""); } System.out.println("-------------------------------------------------"); } } } ~~~     由于没有使用jsp进行显示,所以要想看效果,直接右键main函数,选择“Run As”-》“1 Java Application” ,进行测试。这里给出效果图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c28933c4.jpg)     已经可以完全读取了。不论是单组旧版的,还是多分组新版导出来的opml文件,都可以正常读取。接下来的博文中,会写怎么把结果读取到jsp,会使用树结构来显示。后续版本会加上添加,删除,修改,移动订阅信息及复制订阅信息到组。同时也提供导入,导出功能。这些都会出现在后续博客中。尽请期待。
';

前言

最后更新于:2022-04-01 20:40:11

> 原文出处:[Web版Rss阅读器](http://blog.csdn.net/column/details/rssreader.html) 作者:[崔成龙](http://blog.csdn.net/xiaoxian8023) **本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!** # Web版Rss阅读器 > 从设计开始到基本功能实现,练习java web的简单入门的范例。
';