与你相遇,好幸运

与你相遇,好幸运

                                ——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;
        }
    }

}

关于界面和功能仍有很多不足,正在不断学习,不断改善。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值