与你相遇,好幸运
2016-06-26 17:30
411 查看
与你相遇,好幸运
——RSS 阅读器 项目总结
学习Java已经快一个学期了。她是那么的善解人意,心思澄明,让我心生欢喜。终于我们有了第一次邂逅——RSS阅读器。有幸与你相遇,请多多指教。
RSS阅读器简介:
近几年来网络信息大爆炸,人们需要了解的信息铺天盖地,众多信息中我们不能花太多时间去逐条读取,人们期待能够像浏览报纸标题一样,首先快速获取新闻摘要然后再对感兴趣的新闻仔细阅读,于是一个很早就出现的技术开始普遍和流行,它就是RSS,目前很多网站出现了XML或RSS的标志,该标志通过超级链接直接接到一个被称为“RSS feed”的XML文件,这是网站在利用RSS来发布最新消息。这种做法得到大量网站的支持。 RSS也叫聚合RSS,是在线共享内容的一种简易方式(也叫聚合内容,Really Simple Syndication)。通常在时效性比较强的内容上使用RSS订阅能更快获取信息,网站提供RSS输出,有利于让用户获取网站内容的最新更新。用户可以通过RSS订阅软件,自动接收感兴趣的网站的更新内容,而不需要自己一个一个去浏览这些网站。 RSS阅读器是一个桌面程序,其核心功能是根据用户选择的RSS2.0新闻源,分析新闻源中重要的信息,并按照项目要求格式输出显示内容及存储文件。
项目目标:
(1)本系统为Java桌面应用程序,负责解析本机制定路径下的RSS2.0格式的新闻源及相应的输出。(2)RSS阅读器项目的主要功能包括:RSS文件读取,RSS文件分析,RSS内容输出,定时更新。
(3)系统界面简介明了,操作方便,用户体验较好。
RSS阅读器项目相关知识:
GUI,集合类,线程,类与对象,异常处理,IO,XML,Java API,类型 与工具与环境
类型 | 工具与环境 |
---|---|
开发工具 | Eclipse 3.3 + JDK1.6 |
Web服务器 | Tomcat6.0 |
数据库访问工具 | MySQL Tools for 4.0 |
程序框架 | Spring2.0+Hibernate3.0+Struts2.0 |
页面技术 | JavaScript、HTML、CSS |
运行环境 | 操作系统:Windows XP SP3 |
Framework:.NET Framework 2.0 | |
Internet Explorer 8.0 | |
数 据 库 | Orcale8.0 |
MySQL5.0 | |
XML解析器 | MSXML4.0 |
图形组件 | JFreeChart4.0 |
GUI
功能截图:
开始界面:整体界面:
GUI(图形用户界面)相关代码
public class JMainFrame extends JFrame { RSSService rssService = null; FileDaoImpl fileDaoImpl = null; //窗口属性 private final static int WIDTH = 800; private final static int HEIGHT = 600; private final static String TITLE = "RSS阅读器"; //窗口组件 private JTextArea jtaContent; //新闻文本区 private JButton jbExport; //导出按钮 private DefaultTableModel dtmTableModel; //表格数据模型 private JTable jtTable; //表格 private List<News> newsList; //新闻内容列表 private List<Channel> channelList; //频道列表 //构造函数 public JMainFrame() { rssService = new RSSService(); //初始化 channelList = rssService.getChannelList(); this.setTitle(TITLE); //标题 this.setSize(WIDTH, HEIGHT); //大小 setCenter(); //窗口居中 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //窗口关闭 this.setContentPane(getJPMain()); // 添加到面板 } //定义setCenter()方法,使窗口位于屏幕中央 private void setCenter() { Toolkit kit = Toolkit.getDefaultToolkit(); //定义工具包 Dimension screension = kit.getScreenSize(); //获取屏幕的尺寸 this.setLocation((screension.width - WIDTH) / 2, (screension.height - HEIGHT) / 2); } //创建主面板 private JPanel getJPMain() { JPanel JpMain = new JPanel(); JpMain.setLayout(new BorderLayout()); //带滚动条的表格,带滚动条的文本区,分割面板 JpMain.add(getJSPClientArea(), BorderLayout.CENTER); //菜单 setJMenuBar(getJMBMy()); //状态栏 JpMain.add(getJSB(), BorderLayout.SOUTH); //工具栏 JpMain.add(getJTB(), BorderLayout.NORTH); return JpMain; } //分割面板 private JSplitPane getJSPClientArea() { JSplitPane jspVertical = new JSplitPane(JSplitPane.VERTICAL_SPLIT); jspVertical.setDividerLocation(280); jspVertical.setLeftComponent(getJSPTable()); jspVertical.setRightComponent(getJSPContent()); return jspVertical; } //菜单 private JMenuBar getJMBMy() { //创建菜单栏 JMenuBar jmbMy = new JMenuBar(); //创建“文件”菜单,并且设置相应的快捷键 JMenu fileJMenu = new JMenu("文件(F)"); fileJMenu.setMnemonic('f'); //“文件”菜单监听器 fileJMenu.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { for (int i = 0; i < channelList.size(); i++) { final Channel channel = channelList.get(i); } } }); //创建“文件”菜单下面的菜单项 for (int i = 0; i < channelList.size(); i++) { final Channel channel = channelList.get(i); JMenuItem menuItem = new JMenuItem(channel.toString()); fileJMenu.add(menuItem); //“文件”菜单下面的菜单项监听器 menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String filePath = channel.getFilePath(); newsList = rssService.getNewsList(filePath); showTable(newsList); } }); } //创建“导出”菜单项 JMenuItem export = new JMenuItem("导出(E)"); export.setMnemonic('e'); //“导出”菜单项监听器 export.addActionListener(new ExportActionListener()); //创建“退出”菜单项 JMenuItem exit = new JMenuItem("退出(X)"); exit.setMnemonic('x'); //“退出”菜单项监听器 exit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); //将“导出”菜单项“退出”菜单项添加到菜单中 fileJMenu.addSeparator(); fileJMenu.add(export); fileJMenu.addSeparator(); fileJMenu.add(exit); //创建“帮助”菜单并且设置相应的快捷键 JMenu helpJMenu = new JMenu("帮助(H)"); helpJMenu.setMnemonic('h'); //创建“关于RSS阅读器”菜单项 JMenuItem about = new JMenuItem("关于RSS阅读器"); about.setMnemonic('a'); //“关于RSS阅读器”菜单项监听器 about.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(null, "欢迎联系加QQ:2544247346交流讨论", "关于RSS阅读器", JOptionPane.INFORMATION_MESSAGE); } }); //将“关于RSS阅读器”菜单项“添加到”帮助“菜单中 helpJMenu.add(about); //将“文件”菜单,“帮助”菜单添加到菜单栏中 jmbMy.add(fileJMenu); jmbMy.add(helpJMenu); return jmbMy; } //“导出”监听器 class ExportActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { if (newsList == null) { JOptionPane.showMessageDialog(null, "请先选择频道", "提示", JOptionPane.WARNING_MESSAGE); } else if (rssService.save(newsList)) { JOptionPane.showMessageDialog(null, "新闻信息保存成功", "成功", JOptionPane.INFORMATION_MESSAGE); } else { JOptionPane.showMessageDialog(null, "新闻信息保存失败", "失败", JOptionPane.ERROR_MESSAGE); } } } //带滚动条的文本区 private JScrollPane getJSPContent() { JScrollPane jspContent = null; if (jtaContent == null) { jtaContent = new JTextArea(); //创建新闻内容文本区 jtaContent.setLineWrap(true); //设置文本区的换行策略 jtaContent.setEditable(false); //设置文本区为不可编辑 jspContent = new JScrollPane(jtaContent); //设置带文本区的滚动面板 jspContent.setPreferredSize(new Dimension(780, 260)); } return jspContent; } //带滚动条的表格 private JScrollPane getJSPTable() { JScrollPane jspTable = null; if (jtTable == null) { dtmTableModel = new DefaultTableModel(); dtmTableModel.addColumn("主题"); dtmTableModel.addColumn("接收时间"); dtmTableModel.addColumn("发布时间"); dtmTableModel.addColumn("作者"); jtTable = new JTable(dtmTableModel); jtTable.editCellAt(10,10); //采用匿名内部类的形式为表格添加鼠标单击事件监听器 jtTable.addMouseListener(new MouseAdapter() { //重写mouseClicked()方法处理鼠标点击事件 public void mouseClicked(MouseEvent e) { //判断鼠标是否单击 if (e.getClickCount() == 1) { int selectedRow = jtTable.getSelectedRow(); //获得鼠标单击行的位置 News selectedNews = newsList.get(selectedRow); //获得选中的新闻信息 jtaContent.setText(rssService.newsToString(selectedNews)); //将选中的新闻信息内容显示在面板 } } }); jspTable = new JScrollPane(jtTable); } return jspTable; } // Class MyTable extends JTable{ // public boolean isCellEditable(int row,int col){ // } // } //显示表格 private void showTable(List<News> newsList) { //清空表格的内容 int rowCount = dtmTableModel.getRowCount(); while (rowCount > 0) { dtmTableModel.removeRow(0); rowCount--; } //遍历新闻内容列表,将相应的新闻内容显示到表格中 for (int i = 0; i < newsList.size(); i++) { News news = newsList.get(i); //按指定的时间格式,获得当前日期 SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); Date date = new Date(); String currentDate = dateFormat.format(date); //将标题的新闻、当前日期、发布日期和作者显示在表格中 String[] data = { news.getTitle(), currentDate, news.getPubDate(), news.getAuthor() }; dtmTableModel.addRow(data); } } //状态栏 private JPanel getJSB() { JPanel jsb = new JPanel(); jsb.setLayout(new FlowLayout(FlowLayout.LEFT)); JLabel jlStatus = new JLabel("www.ruanko.com"); jsb.add(jlStatus); return jsb; } //工具栏 private JToolBar getJTB() { JToolBar jpNorth = new JToolBar(); jpNorth.add(getJBExport()); return jpNorth; } //导出按钮 private JButton getJBExport() { if (jbExport == null) { ImageIcon exportIcon = new ImageIcon("images/export.png"); jbExport = new JButton(exportIcon); jbExport.setBorder(null); jbExport.setToolTipText("导出新闻信息"); jbExport.addActionListener(new ExportActionListener()); } return jbExport; } }
1、RSS文件读取
(1)功能描述
RSS文件读取,RSS文件解析,RSS文件导出(2)功能截图
(3)开发思路和核心代码
public class RSSService { private List<Channel> channelList; private List<News> newsList; private NewsDao rssDao; public RSSService (){ rssDao=new FileDaoImpl(); channelList = new ArrayList<Channel>(); Channel channel1 = new Channel(); channel1.setName("腾讯 - 国际要闻"); channel1.setFilePath("NewsFiles/rss_newswj.xml"); channel1.setUrl("http://news.qq.com/newsgj/rss_newswj.xml"); Channel channel2 = new Channel(); channel2.setName("腾讯 - 国内新闻"); channel2.setFilePath("NewsFiles/rss_newsgn.xml"); channel2.setUrl("http://news.qq.com/newsgn/rss_newsgn.xml"); Channel channel3 = new Channel(); channel3.setName("新浪 - 体育新闻"); channel3.setFilePath("NewsFiles/sports.xml"); channel3.setUrl("http://rss.sina.com.cn/news/allnews/sports.xml"); Channel channel4 = new Channel(); channel4.setName("新浪 - 社会新闻"); channel4.setFilePath("NewsFiles/focus15.xml"); channel4.setUrl("http://rss.sina.com.cn/news/society/focus15.xml"); channelList.add(channel1); channelList.add(channel2); channelList.add(channel3); channelList.add(channel4); } public List <Channel> getChannelList(){ return channelList; } public List<News> getNewsList(String filePath){ Document doc = load(filePath); newsList = parse(doc); return newsList; } public Document load(String filePath){ Document doc = null; //1 指定解析器 SAXBuilder sb = new SAXBuilder(false); //2 创建文件对象 File fXml = new File(filePath); if(fXml.exists() && fXml.isFile()){ // 加载一个XML文件,得到Document对象 try{ // 3 调用build() doc = sb.build(fXml); }catch(JDOMException e){ e.printStackTrace(); }catch (IOException e){ e.printStackTrace(); } } return doc; } private News itemToNews(Element item){ News news = new News(); String title = item.getChildText("title").trim(); String link = item.getChildText("link"); String author = item.getChildText("author"); String guid = item.getChildText("guid"); String pubDate = item.getChildText("pubDate"); String category = item.getChildText("category"); String description = item.getChildText("description").trim(); news.setTitle(title); news.setLink(link); news.setAuthor(author); news.setGuid(guid); news.setPubDate(pubDate); news.setCategory(category); news.setDescription(description); return news; } private List<News> parse(Document doc){ List<News> newsList = new ArrayList<News>(); News news = null; Element root = doc.getRootElement(); Element eChannel = root.getChild("channel"); List<Element> itemList = eChannel.getChildren("item"); for(int i = 0; i < itemList.size(); i++){ Element item = itemList.get(i); news = itemToNews(item); newsList.add(news); } return newsList; } public String newsToString(News news){ String content = null; content = "标题:" + news.getTitle() + "\r\n" + "链接:" + news.getLink() + "\r\n" + "作者:" + news.getAuthor() + "\r\n" + "发布时间:" + news.getPubDate() + "\r\n" + "--------------------------------------------------------\r\n" + news.getDescription() + "\r\n" + "\r\n"; return content; } public boolean save(List<News> newsList) { NewsDao dao = new FileDaoImpl(); return dao.save(newsList); } }
导出代码:
public class FileDaoImpl implements NewsDao { private static String FILE_PATH = "NewsFiles/rss.txt"; public boolean save(List<News> newsList) { boolean flag = true; File file = new File(FILE_PATH); FileWriter fw = null; BufferedWriter bw = null; try { for (int i = 1; file.exists(); i++) { //打开文件 file = new File("NewsFiles/rss_" + i + ".txt"); } fw = new FileWriter(file, true); bw = new BufferedWriter(fw); RSSService rssService = new RSSService(); for (News news : newsList) { String content = rssService.newsToString(news); //写文件 bw.append(content); } bw.flush(); fw.flush(); flag = true; } catch (IOException e) { e.printStackTrace(); flag = false; } finally { try { // 关闭文件 bw.close(); fw.close(); } catch (IOException e) { e.printStackTrace(); } } return flag; } }
2、定时更新
(1)功能描述
自动下载相关的XML文件,并在RSS阅读器中更新(2)开发思路和核心代码
public class UpdateThread extends Thread{ private final static int TIMEOUT = 5 * 1000; //超时5分钟 private final static int BUFFER_SIZE = 65536; //缓冲区大小64k private final static int DELAY_TIME = 300 * 1000; //5分钟 private List<Channel> channelList; public UpdateThread(){ RSSService rssService = new RSSService(); channelList = rssService.getChannelList(); } public void run(){ //死循环,每5分钟更新一次RSS文件 while(true) { System.out.println("正在更新........" + new Date()); for(int i = 0; i < channelList.size(); i++) { Channel channel = channelList.get(i); System.out.println("更新" + channel.getName()); update(channel.getUrl(), channel.getFilePath()); } System.out.println("更新完毕........" + new Date()); //让线程休眠5分钟 try{ sleep(DELAY_TIME); }catch(InterruptedException e){ e.printStackTrace(); } } } public void update(String urlPath, String filePath) { // 创建HTTP连接 HttpURLConnection httpConn; try { URL url = new URL(urlPath); httpConn = (HttpURLConnection)url.openConnection(); // 判断HTTP连接是否成功 int responseCode = httpConn.getResponseCode(); if (responseCode != HttpURLConnection.HTTP_OK) { return; } } catch (MalformedURLException e) { e.printStackTrace(); return; } catch (IOException e) { return; } // 1 在HTTP服务器上检查是否有新的RSS文件 File file = new File(filePath); if (hasNewRSS(httpConn, file)) { System.out.println("现在更新"); try { httpConn.setConnectTimeout(TIMEOUT); // 设置一个指定的超时值 httpConn.connect(); // 打开到此URL引用的资源的通信链接 // 2 下载RSS文件, 并且保存到缓冲区中 InputStream in = httpConn.getInputStream(); byte[] byteBuffer = new byte[BUFFER_SIZE]; for (int i = 0; i < byteBuffer.length; i++) { byteBuffer[i] = 0; } // 3 将RSS文件保存到文件中 int length = 0; FileOutputStream fileOutputStream = new FileOutputStream(filePath); FileChannel channel = fileOutputStream.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); while (length >= 0) { length = in.read(byteBuffer); for (int i = 0; i < length; i++) { buffer.put(byteBuffer[i]); } } buffer.flip(); channel.write(buffer); // 关闭文件 channel.close(); in.close(); fileOutputStream.close(); // 断开HTTP连接 httpConn.disconnect(); } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("RSS文件已更新完毕!"); } } private boolean hasNewRSS(HttpURLConnection httpConn, File file) { long current = System.currentTimeMillis(); long httpLastModified = httpConn.getHeaderFieldDate("Last-Modified", current); long fileLastModified = file.lastModified(); if (httpLastModified > fileLastModified) { return true; } else { return false; } } }
关于界面和功能仍有很多不足,正在不断学习,不断改善。
相关文章推荐
- 为什么构造函数不能是虚函数
- 跟着SY速学Ubuntu系列七:Composer学习(3):超简单的实现ORM框架的依赖加载
- 对于ArrayList中的泛型进行分析
- 08、css框架与表格
- Unison(rpm方式)安装及应用--nginx高可用
- 【DAY1】hadoop的安装配置基础学习笔记
- 来自 Fedora 24 工作站版的四大改进
- 通过反射获取类的类名,方法和内部成员变量
- 230. Kth Smallest Element in a BST
- 141.Valid Perfect Square
- html标签简单总结
- adb工具如何连接手机安装apk
- 模板类中可以使用虚函数吗?模板成员函数可以是虚函数吗?
- shell下的sed命令
- adb工具如何连接手机安装apk
- 《深入理解JVM》读书笔记
- The Direct3D 11 Graphics Pipeline
- heap and heap sort
- Python int()函数 基础知识篇
- HTTP服务器的简单实现