阅读器访问地址:http://easyrss.tk/,欢迎体验!
阅读导览
一、 概述
二、 设计的基本概念和原理
三、 设计方案
四、 主要源代码
五、 阅读器使用说明
概述
获得信息是在人类的生活中是必不可少的环节。如果现在的社会对获得信息不快捷,那么这个社会将不会像如今这般的发达和进步。在当今网络技术相当发达的今天,大量的信息充斥在网上。现在网络越来越发达,用户在网上既能工作也能娱乐。当用户在网上需浏览很多个网站才能获取自己多需的信息时,那就感觉很累。因为现在每个网站都有很多信息,找到自己所喜欢的并不是一件轻松的事。这时RSS阅读器的功用就体现出来了。
RSS 是一种简单的订阅方式,它能能够起到聚合网络信息的作用。就像订报纸、杂志一样,您可以订阅任何喜欢的内容。网络用户可以在客户端借助于支持RSS的新闻聚合软件在不打开网站内容页面的情况下,将网站提供的支持RSS输出的网站内容(新闻、Blog等)聚集到RSS阅读器中,用户可以不必登录各个提供信息的网站,而通过"RSS阅读器"来阅读这些内容。
本设计要设计一个RSS阅读器,本阅读器将要实现的功能如下:
- 随时随地阅读:
通过注册与登录将用户信息保存到服务器,用户在任何时间、任何地方打开网页就可以阅读自己的RSS订阅。
- RSS源的分组管理与结构化显示:
简洁直观的分类显示用户的RSS订阅列表,简化操作、提高用户的阅读体验。
- RSS源的添加、修改与删除:
用户能够方便的添加、修改、删除RSS源及分组。
- RSS源的的解析与显示:
阅读器可以通过用户提供的RSS源URL解析出该RSS源的标题、包含的文章列表、文章地址和文章更新时间等信息,并且能正确地以一定格式显示出来供用户阅读。
设计的基本概念和原理
RSS与RSS阅读器概念
- RSS:
RSS(Really Simple Syndication)是一种描述和同步网站内容的格式,是使用最广泛的XML应用【1】。RSS搭建了信息迅速传播的一个技术平台,使得每个人都成为潜在的信息提供者。发布一个RSS文件后,这个RSS Feed中包含的信息就能直接被其他站点调用,而且由于这些数据都是标准的XML格式,所以也能在其他的终端和服务中使用,是一种描述和同步网站内容的格式。 RSS可以是以下三个解释的其中一个: Really Simple Syndication;RDF (Resource Description Framework) Site Summary; Rich Site Summary【2】。但其实这三个解释都是指同一种Syndication的技术。
RSS目前广泛用于网上新闻频道,blog和wiki,主要的版本有0.91, 1.0, 2.0。使用RSS订阅能更快地获取信息,网站提供RSS输出,有利于让用户获取网站内容的最新更新。网络用户可以在客户端借助于支持RSS的聚合工具软件,在不打开网站内容页面的情况下阅读支持RSS输出的网站内容。
- RSS阅读器:
RSS阅读器基本可以分为三类【3】:
第一类大多数阅读器是运行在计算机桌面上的应用程序,通过所订阅网站的新闻供应,可自动、定时地更新新闻标题。在该类阅读器中,有Awasu、FeedDemon和RSSReader这三款流行的阅读器,都提供免费试用版和付费高级版。
第二类新闻阅读器通常是内嵌于已在计算机中运行的应用程序中。例如,NewsGator内嵌在微软的Outlook中,所订阅的新闻标题位于Outlook的收件箱文件夹中。另外,Pluck内嵌在Internet Explorer浏览器中!
第三类则是在线的WEB RSS阅读器,其优势在于不需要安装任何软件就可以获得RSS阅读的便利,并且可以保存阅读状态,推荐和收藏自己感兴趣的文章。提供此服务的有两类网站,一种是专门提供RSS阅读器的网站,例如国外的feedly,国内的有道、鲜果、抓虾;另一种是提供个性化首页的网站,例如国外的netvibes、pageflakes,国内的雅蛙、阔地。
本阅读器即是基于JSP的WEB RSS阅读器。
阅读器实现原理
本RSS阅读器使用主要使用JSP技术,根据用户请求的Url借助Rome和Jdom开源工具来解析XML文件获取相应内容,然后将获取到的内容以方便阅读的格式显示在网页上【4】。同时用数据库与JSP相应技术实现阅读器功能的扩展,如:用户阅读列表的管理,显示效果的优化等。
设计方案
架构设计
网站前台使用JSP技术实现页面与功能,后台数据库使用SQLServer作数据管理,阅读内容从RSS源获取,如下图:
数据库设计
数据库使用SQL Server 2008 R2,数据表设计如下:
为保护系统安全,数据表结构不直接给出
界面设计
登录与注册:
登录界面 login.jsp
注册界面signup.jsp:
主页
主页index.jsp(中间的分割线可以拖动)
主页采用框架设计,上部为网站信息和当前用户信息;左边为RSS源列表;右边是主框架,用于显示阅读内容。左右框架大小可以拖动随意调整。
RSS树形列表:
dtree
RSS源显示采用dtree树形列表【5】展示,能够直观展示分组与分组中的RRS源。
文章列表:
以表格形式列出选定RSS订阅中的文章列表
文章内容:
文章内容
文章内容是直接展示文章原网页,保持原文排版,并防止被屏蔽。
添加与管理:
添加与管理都采用弹窗的方式,具体如下:
添加源
添加分组
管理分组
管理源
修改界面与添加界面相似,不再贴图。
提示信息(tips.jsp):
大部分提示信息由tips页面显示,举例如下:
注册提示
未登录提示
退出提示
……
提示页面会根据获取到的参数显示提示信息
功能设计
注册:
注册时,用户名、密码以及确认密码为必填项。由于密码不可见,设置确认密码可以防止输入错误。昵称为选填项,用以更加友好的显示用户名称,若为空显示时将以用户名代替。注册后将注册信息添加到数据库。同时应注意用户名不能和数据库中已有的用户名重复。
登录:
登录时首先获取用户名,连接数据库,查询该用户是否存在,若用户名不存在,跳转提示页面显示相应提示然后返回至登录页面。如果查找到,则再确认密码是否输入正确,密码正确则将用户uid存入session以备后面使用然后跳转至该用户主页。
主页:
主页采用框架布局,主要包括三个部分:
- 上部:显示网站logo,当前用户信息等。用户信息根据session中的uid从数据库中查询该用户的详细信息。若该用户昵称列表不为空则显示昵称,若为空则显示用户名。
- 左部:主要是RSS树形列表,详细见后文介绍;
- 右部:主要显示区域,显示文章列表及文章具体内容,详细见后文介绍。
RSS树形列表:
RSS源显示采用开源的dtree项目进行二次开发。首先根据之前放入session中的uid获取当前用户的RSS分组数据,每获取到一个分组就根据该分组的gid获取属于该组内的的RSS源数据,然后将数据放入dtree中,依次循环直至获取到所有数据。最后由dtree根据获取到的数据按照树形样式显示出来。用户点击列表中的项目将会在右侧主框架中打开相应的文章列表。
主框架的文章列表:
主框架从左框架中发来的链接中提取feed参数中的url值,解析该url获取到相应文章列表。对url和xml文件的解析采用rss解析器(rome.jar和jdom.jar)进行解析获取相应数据。
同时,为了解决部分文章不支持在框架中打开,文章列表设计了在新窗口打开的选项。主要实现方法是:用户改变"在新窗口中打开"的选项的状态后,js立即将该选项状态写入Cookie并发送刷新请求。服务器根据Cookies值动态修改文章链接的target属性并向客户端发送新的页面。
文章内容显示:
文章内容未做任何处理直接显示原文,简单方便。但是有些文章不支持在框架中显示,这时需要勾选"在新窗口中打开"的选项,使文章在新开的浏览器窗口中显示。
RSS源的添加与管理:
添加分为添加源与添加分组,两个界面属于同一个弹窗,通过顶部tab切换,直观快捷。
添加源时需要提交:Feed地址、标题、分组。feed地址填写需要订阅的rss地址;标题可以从Feed地址中提取(具体实现方式为服务器获取到feed地址,根据feed地址解析出订阅标题,然后向客户端发送带有订阅标题的新页面);分组通过列表框选择用户已有的分组。客户端提交表单后,服务器获取到相应的信息并添加至数据库,然后返回成功信息;用户可再次添加新的源。
添加分组时只需要提交需要添加的分组名称即可。
管理界面属于新的弹窗,初始显示用户的所有分组,每个分组包含"展开"、"修改"和"删除"三个菜单。点击分组名或"展开"菜单将会跳转到该分组下的RSS源列表。RSS源列表与分组列表相识,每个分组包含"修改"与"删除"两个菜单。
修改时提交需要修改的项目,服务器根据获取到的gid、lid以及修改后的信息更新对应项目数据并返回相应提示。
删除时提交对应分组的gid或RSS源的lid,服务器根据获取到的id信息输出相应项目并返回提示。删除非空分组时将会删除该分组下所有RSS源(有提示)。
提示信息:
提示信息显示页面或根据获取到的参数显示相应的提示信息并在延迟特定时间后跳转到相应界面,参数为空时显示"未知错误"并跳转至主页。
网络安全补充
为了保护网站与用户数据安全,采取了一下辅助安全措施:
- 注册输入限制:
用户名只能为字母与数字的组合
密码长度太短
用户名限制为字母与数字组合,防止用户使用SQL语言中的符号进行SQL注入。密码长度限制为8~20位。太短,密码不安全;太长,用户可以通过密码框使用SQL注入攻击
- 使用过滤器防止SQL注入:
只通过表单的输入限制来防止SQL注入是远远不够的,用户依然可一使用URL参数的形式进行注入攻击。所以我在原项目中加入了一个过滤器来防护一些简单的SQL注入攻击。
该过滤器的原理是,截取用户的所有输入,检测是否是否包含特定关键词,有则重定向到一个错误信息页面error.jsp。没有则通过过滤器。
当然只是用过滤器是不能完全防护SQL注入攻击的,更有效的方式是项目中所有SQL语句都采用预编译语句(PreparedStatement)接口来实现【6】。
面对日益复杂的网络安全环境,以上的安全措施只是简单的做了一些防护,对于一个实际项目是远远不够的。在实际的项目还用采取更加严谨,更加有效的措施。
具体方法参考本文:JSP使用过滤器防止SQL注入
主要源代码
视图部分
/RSSreader/WebContent/rsscontent.jsp:
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8" import="java.text.SimpleDateFormat"%>
<%
String pageTitle="";
String urlStr = request.getParameter("feed");
String target="";
Cookie cookies[]=request.getCookies(); //读出用户硬盘上的Cookie,并将所有的Cookie放到一个cookie对象数组里面
Cookie sCookie=null;
for(int i=0;i
<%=pageTitle%>
>
>
在新窗口中打开(部分网页不支持在框架中显示,请尝试勾选此项)
序号
标题
发布时间
<%
String date="无";
java.util.List list = feed.getEntries();
for (int i=0; i< list.size(); i++) {
com.sun.syndication.feed.synd.SyndEntry entry = (com.sun.syndication.feed.synd.SyndEntry)list.get(i);
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern("yyyy年MM月dd日 HH:mm");
if(entry.getPublishedDate()!=null)
{
date=sdf.format(entry.getPublishedDate());
}
%>
<%=i+1%>
><%=entry.getTitle()%>
<%=date %>
<%
}
} catch (Exception e) {
// TODO Auto-generated catch block
response.sendRedirect("tips.jsp?type=rssContentfail");
e.printStackTrace();
}
%>
<%=pageTitle%>
/RSSreader/WebContent/addGroup.jsp:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8" import="com.JDBConnection,java.sql.ResultSet,com.dataHelper,java.util.ArrayList"%>
添加分组
<%
String lastAdd = request.getParameter("lastAdd");
String from = request.getParameter("from");
String tip="";
String backurl="";
String backname="";
if(lastAdd!=null){
String name =new String(request.getParameter("name").getBytes("ISO8859_1"), "utf-8");
if(lastAdd.equals("ture")){
tip="成功添加分组:"+name;
}
if(lastAdd.equals("false")){
tip="添加分组失败";
}
}
%>
添加源 | 添加分组
/RSSreader/WebContent/addRss.jsp:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8" import="com.JDBConnection,java.sql.ResultSet,com.dataHelper,java.util.ArrayList"%>
添加RSS源
<%
String lastAdd = request.getParameter("lastAdd");
String title ="";
String url ="";
String tip="";
String Sgid="";
if(request.getParameter("title")!=null)
{
title=new String(request.getParameter("title").getBytes("ISO8859_1"), "utf-8");
}
if(request.getParameter("url")!=null)
{
url=request.getParameter("url");
}
if(request.getParameter("group")!=null)
{
Sgid=request.getParameter("group");
}
if(lastAdd!=null){
String name =new String(request.getParameter("name").getBytes("ISO8859_1"), "utf-8");
if(lastAdd.equals("ture")){
tip="成功添加RSS源:"+name;
}
if(lastAdd.equals("false")){
tip="添加RSS源失败";
}
}
%>
" οnunlοad="javascript:;window.opener.location.reload()">
添加源 | 添加分组
/RSSreader/WebContent/delete.jsp:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8" import="com.JDBConnection,java.sql.ResultSet"%>
editGroup
<%
String name=(String)session.getAttribute("name");
String nickname="";
if(name==null)
{
response.sendRedirect("index.jsp");
}
%>
<%
String gid =request.getParameter("gid");
String lid =request.getParameter("lid");
String type =request.getParameter("type");
String url="";
//DELETE FROM 表名称 WHERE 列名称 = 值
String sSql="";
if(type!=null){
if(type.equals("g")){
sSql="delete from rssGroup where gid="+gid;
url="manage.jsp";
}
if(type.equals("r")){
sSql="delete from rssList where lid="+lid;
url="rssListOfGroup.jsp?gid="+gid;
}
}
System.out.println("rssListOfGroup.Sql:"+sSql);
JDBConnection JDBC=new JDBConnection();
if(JDBC.executeUpdate(sSql)){
out.print("删除成功");
}
else{
out.print("删除失败");
}
%>
JAVA部分
/RSSreader/src/com/JDBConnection.java
package com;
import java.sql.*;
public class JDBConnection {
private final String url = "jdbc:sqlserver://localhost:1433;DatabaseName=RSSreader";
private final String userName = "sa";
private final String password = "123456";
private Connection con = null;
//通过构造方法加载数据库驱动
static {
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
} catch (Exception ex) {
System.out.println("数据库加载失败");
}
}
//创建数据库连接
public boolean creatConnection() {
try {
con = DriverManager.getConnection(url, userName, password);
con.setAutoCommit(true);
} catch (SQLException e) {
System.out.println(e.getMessage());
System.out.println("creatConnectionError!");
}
return true;
}
public void close(Connection con,Statement stmt,PreparedStatement pst,ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(pst!=null){
try {
pst.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void closeConnection(){
if(con!=null){
try {
con.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//对数据库的增加、修改和删除的操作
public boolean executeUpdate(String sql) {
if (con == null) {
creatConnection();
}
try {
Statement stmt = con.createStatement();
int iCount = stmt.executeUpdate(sql);
System.out.println("操作成功,所影响的记录数为" + String.valueOf(iCount));
this.close(con, stmt,null, null);
return true;
} catch (SQLException e) {
System.out.println(e.getMessage());
return false;
}
}
//对数据库的查询操作
public ResultSet executeQuery(String sql) {
ResultSet rs;
try {
if (con == null) {
creatConnection();
}
Statement stmt = con.createStatement();
try {
rs = stmt.executeQuery(sql);
} catch (SQLException e) {
System.out.println(e.getMessage());
return null;
}
} catch (SQLException e) {
System.out.println(e.getMessage());
System.out.println("executeQueryError!");
return null;
}
return rs;
}
}
/RSSreader/src/com/SqlFilter.java
package com;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//过滤sql关键字的Filter
public class SqlFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
//获得所有请求参数名
Enumeration params = req.getParameterNames();
String sql = "";
while (params.hasMoreElements()) {
//得到参数名
String name = params.nextElement().toString();
//System.out.println("name===========================" + name + "--");
//得到参数对应值
String[] value = req.getParameterValues(name);
for (int i = 0; i < value.length; i++) {
sql = sql + value[i];
}
}
System.out.println("被匹配字符串:"+sql);
if (sqlValidate(sql)) {
res.sendRedirect("error.jsp");
} else {
chain.doFilter(req, res);
}
}
//效验
protected static boolean sqlValidate(String str) {
str = str.toLowerCase();//统一转为小写
//String badStr = "and|exec";
String badStr = "'|and|exec|execute|insert|select|delete|update|count|drop|chr|mid|master|truncate|char|declare|sitename|net user|xp_cmdshell|or|like";
/*String badStr = "'|and|exec|execute|insert|create|drop|table|from|grant|use|group_concat|column_name|" +
"information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|*|" +
"chr|mid|master|truncate|char|declare|or|;|-|--|+|,|like|//|/|%|#"; */ //过滤掉的sql关键字,可以手动添加
String[] badStrs = badStr.split("\\|");
for (int i = 0; i < badStrs.length; i++) {
if (str.indexOf(badStrs[i]) !=-1) {
System.out.println("匹配到:"+badStrs[i]);
return true;
}
}
return false;
}
public void init(FilterConfig filterConfig) throws ServletException {
//throw new UnsupportedOperationException("Not supported yet.");
}
public void destroy() {
//throw new UnsupportedOperationException("Not supported yet.");
}
}
/RSSreader/src/dataCtrl/addGroup.java
package dataCtrl;
import com.JDBConnection;
public class addGroup {
private String gname;
private String uid;
public String getGname() {
return gname;
}
public void setGname(String gname) {
this.gname = gname;
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public boolean doAddGroup(){
String sSql = "insert into rssGroup(gname,uid) values('"+gname+"',"+uid+")";
System.out.println(sSql);
JDBConnection JDBC=new JDBConnection();
return JDBC.executeUpdate(sSql);
}
}
/RSSreader/src/dataCtrl/addRss.java
package dataCtrl;
import java.sql.*;
import com.JDBConnection;
import javafx.beans.property.adapter.JavaBeanProperty;
public class addRss {
private String title;
private String url;
private String gid;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getGid() {
return gid;
}
public void setGid(String gid) {
this.gid = gid;
}
public boolean doAddRss() throws SQLException{
//INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....);
String sSql = "insert into rssList(title,url,gid) values('"+title+"','"+url+"',"+gid+")";
System.out.println(sSql);
JDBConnection JDBC=new JDBConnection();
return JDBC.executeUpdate(sSql);
}
}
/RSSreader/src/dataCtrl/dealaddGroup.java
package dataCtrl;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class dealaddGroup
*/
@WebServlet("/dealaddGroup")
public class dealaddGroup extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public dealaddGroup() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String gname=request.getParameter("gname");
String sgname =new String(gname.getBytes("ISO8859_1"), "utf-8");
String uid=request.getParameter("uid");
addGroup adgp=new addGroup();
adgp.setGname(sgname);
adgp.setUid(uid);
if(adgp.doAddGroup()){
request.getRequestDispatcher("/addGroup.jsp?name="+gname+"&lastAdd=ture").forward(request,response);
//response.sendRedirect("index.jsp");
}
else{
request.getRequestDispatcher("/addGroup.jsp?name="+gname+"&lastAdd=false").forward(request,response);
}
doGet(request, response);
}
}
/RSSreader/src/dataCtrl/dealAddRss.java
package dataCtrl;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class dealAddRss1
*/
@WebServlet("/dealAddRss1")
public class dealAddRss extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public dealAddRss() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.setContentType("text/html;charset=utf-8");
String title=request.getParameter("title");
String stitle =new String(title.getBytes("ISO8859_1"), "utf-8");
String url =request.getParameter("url");
String gid=request.getParameter("group");
addRss adrs=new addRss();
adrs.setTitle(stitle);
adrs.setUrl(url);
adrs.setGid(gid);
try {
if(adrs.doAddRss()){
request.getRequestDispatcher("/addRss.jsp?name="+title+"&lastAdd=ture").forward(request,response);
//response.sendRedirect("index.jsp");
}
else{
request.getRequestDispatcher("/addRss.jsp?name="+title+"&lastAdd=false").forward(request,response);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
doGet(request, response);
}
}
/RSSreader/src/dataCtrl/getFeedTitle.java
package dataCtrl;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sun.syndication.io.FeedException;
/**
* Servlet implementation class getFeedTitle
*/
@WebServlet("/getFeedTitle")
public class getFeedTitle extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public getFeedTitle() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String urlStr =request.getParameter("url");
String title="";
String gid=request.getParameter("group");
String lid=request.getParameter("lid");
String Lastgid=request.getParameter("Lastgid");
String from=request.getParameter("from");
if (!urlStr.startsWith("http://"))
urlStr = "http://"+request.getParameter("feed");
//String urlStr = "http://feed.cnblogs.com/blog/u/249598/rss";
System.out.print(urlStr);
java.net.URLConnection feedUrl = new java.net.URL(urlStr).openConnection();
feedUrl.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
com.sun.syndication.io.SyndFeedInput input = new com.sun.syndication.io.SyndFeedInput();
com.sun.syndication.feed.synd.SyndFeed feed;
try {
feed = input.build(new com.sun.syndication.io.XmlReader(feedUrl));
title=feed.getTitle();
} catch (IllegalArgumentException | FeedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(from.equals("addRss")){
response.sendRedirect("addRss.jsp?title="+title+"&url="+urlStr+"&group="+gid+"&Lastgid="+Lastgid+"&lid="+lid);
}
if(from.equals("editRss")){
response.sendRedirect("editRss.jsp?title="+title+"&url="+urlStr+"&group="+gid+"&Lastgid="+Lastgid+"&lid="+lid);
}
doGet(request, response);
}
}
/RSSreader/src/loginCtrl/checkUser.java
package loginCtrl;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.JDBConnection;
public class checkUser {
private int uid=0;
private String name=" ";
private String pwd=" ";
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public boolean check() {
String sPwd="";
String sSql = "select * from users where uname='"+name+"'";
System.out.println(sSql);
try {
JDBConnection JDBC=new JDBConnection();
ResultSet rs =JDBC.executeQuery(sSql);
System.out.println(rs.isBeforeFirst());
if(rs.next())
{
System.out.println("?");
sPwd=rs.getString("upwd");
uid=rs.getInt("uid");
//System.out.println(sPwd);
JDBC.closeConnection();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
System.out.println("ConnectError!");
}
System.out.println(name+"-"+pwd+"-"+sPwd);
if(pwd.equals(sPwd))
{
return true;
}
else
{
return false;
}
}
}
/RSSreader/src/loginCtrl/dealsignup.java
package loginCtrl;
import java.io.IOException;
import java.sql.Connection;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class dealsignup
*/
@WebServlet("/dealsignup")
public class dealsignup extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public dealsignup() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=utf-8");
String name =request.getParameter("account");
String url =request.getParameter("url");
String nickname =request.getParameter("nickname");
if (nickname==null||nickname=="")
nickname=null;
else
nickname=new String(request.getParameter("nickname").getBytes("ISO8859_1"), "utf-8");
String pwd= request.getParameter("password");
String enpwd= request.getParameter("ensurepassword");
signup snp=new loginCtrl.signup();
System.out.println("dealsingnup:"+name+"-"+nickname+"-"+pwd+"-"+enpwd);
if(!pwd.equals(enpwd))
{
response.sendRedirect("tips.jsp?type=signupwithwrongpwd");
System.out.println("两次密码不一致");
}
else
{
snp.setName(name);
snp.setNickname(nickname);
snp.setPwd(pwd);
Connection conn=snp.connect();
if(snp.signupcheck(conn))
{
if(snp.dosignup(conn))
{
response.sendRedirect("tips.jsp?type=signupsuccess&str="+name);
System.out.println("注册成功");
}
else
{
response.sendRedirect("tips.jsp?type=sinupfail");
System.out.println("未知错误");
}
}
else
{
response.sendRedirect("tips.jsp?type=usernamevalid");
System.out.println("用户名已被注册");
}
snp.closeConnection(conn);
}
doGet(request, response);
}
}
/RSSreader/src/loginCtrl/loginCheck.java
package loginCtrl;
import java.io.IOException;
import java.sql.ResultSet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.JDBConnection;
/**
* Servlet implementation class loginCheck
*/
@WebServlet("/loginCheck")
public class loginCheck extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public loginCheck() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String name =request.getParameter("account");
String pwd= request.getParameter("password");
checkUser uc=new loginCtrl.checkUser();
System.out.println(name+"-"+pwd);
uc.setName(name);
uc.setPwd(pwd);
if(uc.check())
{
HttpSession session=request.getSession();
session.setAttribute("name", name);
session.setAttribute("uid", uc.getUid());
response.sendRedirect("index.jsp");
}
else
{
response.sendRedirect("tips.jsp?type=logfail");
}
doGet(request, response);
}
}
/RSSreader/src/loginCtrl/signup.java
package loginCtrl;
import java.sql.*;
public class signup {
private String name=" ";
private String nickname="";
private String pwd=" ";
private Connection conn;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public Connection connect() {
try
{
String JDriver="com.microsoft.sqlserver.jdbc.SQLServerDriver";//SQL数据库引擎
String connectDB= "jdbc:sqlserver://localhost:1433;DatabaseName=RSSreader";//数据源
try
{
Class.forName(JDriver);//加载数据库引擎,返回给定字符串名的类
}catch(ClassNotFoundException e)
{
//e.printStackTrace();
System.out.println("加载数据库引擎失败:"+e);
System.exit(0);
}
System.out.println("数据库驱动成功");
String user="sa";
String password="123456";
conn=DriverManager.getConnection(connectDB,user,password);//连接数据库对象
System.out.println("连接数据库成功");
}
catch(Exception e)
{
System.out.println("链接数据库失败:"+e);
}
return conn;
}
public boolean signupcheck(Connection conn)
{
try{
Statement stmt=conn.createStatement();
ResultSet rs=stmt.executeQuery("select * from users where uname='"+name+"'");
if(!rs.next())
return true;
}
catch(Exception e)
{
System.out.println("查询失败"+e);
return false;
}
return false;
}
public boolean dosignup(Connection conn) {
try
{
PreparedStatement ps = conn.prepareStatement("insert into users (uname,nickname,upwd) values(?,?,?)");
ps.setString(1, name);
ps.setString(2, nickname);
ps.setString(3, pwd);
int num =ps.executeUpdate();
System.out.println(num);
if (num==0)
return false;
ps.close();
}
catch(Exception e)
{
System.out.println("添加失败"+e);
return false;
}
return true;
}
public boolean closeConnection(Connection conn)
{
try
{
System.out.println("关闭链接成功");
conn.close();
}
catch(Exception e)
{
System.out.println("关闭链接失败"+e);
return false;
}
return true;
}
}
阅读器使用说明
注册与登录
使用阅读器之前需要注册用户并登录,服务器会保存用户的RSS列表数据。未登录之前阅读器会推荐阅读阅读列表,并指导用户寻找RSS源,如下图:
注册时输入为空或输入错误会有相应提示
注册成功后会提示用户记住用户名,然后跳转登录页面:
登录后来到主页,同样阅读器会引导新用户寻找RSS源,点击"寻找RSS源"会跳转到下面这样一个神奇的页面:
然后就是添加自己需要订阅的RSS源了。
添加与管理RSS源
注册登录后,就可以添加自己喜爱的RSS源了。点击添加,弹出添加对话框,这是我们需要先添加分组再添加RSS源。我们先添加两个测试分组,如下图:
添加成功会有提示:
添加好分组后再来添加RSS源,我们测试添加一个"知乎每日精选"的订阅:www.zhihu.com/rss 直接在浏览器中打开是这样的:
这个当然看不懂,我们将url粘贴到阅读器中,标题可以不用自己填,点击"从Feed中获取",阅读器会根据url从RSS源中解析出RSS源的标题。选择"测试分组1",保存。
第一个源已经添加成功了,接下来再添加几个源用作测试。
添加完成后,关闭对话框,左边列表会自动刷新,点击展开显示已添加的RSS源:
这样我们就完成了RSS源的添加。如果有些源名字、分组有错或者源失效了、自己不想再订阅了,我们可以对其进行编辑或者直接删除。点击"管理",弹出管理对话框:
此时我们可以修改分组名或者将其删除:
注意:删除分组会删除该组内的所有RSS源。修改之后:
点击展开,可以显示该分组下的所有RSS源:
同样我们可以修改RSS源或者将其删除,方法与对组的操作类似,修改后:
修改完成后,关闭对话框,同样左边列表会自动刷新:
阅读文章
点击其中一个RSS源,会在右边显示出该订阅的文章列表:
然后点击文章的标题就会显示文章的具体内容:
如果勾选了"在新窗口中打开",文章将会在新的浏览器窗口中打开。
好了基于JSP的RSS阅读器的介绍就到这里,阅读器访问地址:http://easyrss.tk/