您的位置:首页 > 其它

与你相遇,好幸运

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

}


关于界面和功能仍有很多不足,正在不断学习,不断改善。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: