01、投票系统的案例需求
在本篇中,我们将制作一个投票系统,让学生给自己喜爱的老师投票。该系统由 1 个界面组成,系统运行,出现投票界面,如图所示:
▍显示效果
在这个界面中,标题为:“欢迎给教师投票”;在界面上有一个表格,显示了各位教师的编号、姓名、得票数;其中,得票数显示为一个红色的进度条,并显示得票的数值;表格的第 4 列是投票链接,点击链接,该教师的票数加 1,并显示在界面上。
比如,点击编号为 2 的教师对应的投票链接,界面效果为:
▍显示效果
由此可见,其票数增加了 1 票。
02、投票系统分析
在这个项目中,我们只需要用到 1 个界面:投票界面。需要编写的 JSP 文件有几个呢?
一种想法认为,只需要编写 1 个 JSP,在里面显示投票界面,同样是这个 JSP,负责接受用户的投票,将对应的教师的得票数加 1。这种方法比较直观,但是可维护性较差,2 个功能的所有代码放在一个 JSP 内,如果作细微的修改,则比较麻烦,也不利于开发上的分工。
因此我们建议采用如下方法:使用 2 个 JSP,1 个 JSP 负责显示投票界面,另 1 个 JSP 负责接受用户的投票,将对应的教师的得票数加 1,工作完毕再跳转回第 1 个 JSP。结构如图所示:
▍结构
各页面的命名和作用如下表所示:
▍各模块定义
03、开发过程
1)准备数据
此处使用Access数据库。很明显,本项目中只需要 1 个数据表,包含教师编号、教师姓名和得票数。
创建表的脚本如下:
插入一些数据,每个教师初始状态的得票数为 0。
2)如何出现进度条
本项目中,票数以进度条形式出现,如图所示:
如何出现进度条呢?
实际上,进度条就是一个普通的红色图片,只不过显示时固定其高度,让宽度和得票数成正比就可以了。
用图像处理工具(如画图板)准备一个进度条文件:bar.jpg,含有一个很小的红色正方形即可。
3)编写 display.jsp
打开 MyEclipse,新建一个 Web 项目:Vote,将 bar.jpg 拷贝到 WebRoot 下的 img 目录(该目录可以事先新建),首先我们编写 display.jsp,代码如下。
<%@ page language="java" import="java.sql.*" pageEncoding="gb2312"%>
<html>
<body>
<table align="center">
<caption>欢迎给教师投票</caption>
<tr bgcolor="yellow">
<td>编号</td>
<td>姓名</td>
<td>得票数</td>
<td>投票</td>
</tr>
<%
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn = DriverManager.getConnection("jdbc:odbc:DSSchool");
Statement stat = conn.createStatement();
String sql =
"SELECT TEACHERNO,TEACHERNAME,VOTE FROM T_VOTE";
ResultSet rs = stat.executeQuery(sql);
while(rs.next()){
String teacherno
<tr bgcolor="pink"= rs.getString("TEACHERNO");
String teachername = rs.getString("TEACHERNAME");
int vote = rs.get>
<td><%=teacherno %></td>
<td><%=teachername %></td>
<td><img src="img/bar.jpg" width="<%=vote%>" height="10"> <%=vote%></td>
<td><a href="vote.jsp?teacherno=<%=teacherno%>">投票</a></td>
</tr>
<%
}
stat.close();
conn.close();
%>
</table>
</body>
</html>
复制代码
在上述代码中,
<img src="img/bar.jpg" width="<%=vote%>" height="10"
复制代码
显示进度条,高度固定为 10,宽度和得票数相等。
<a href="vote.jsp?teacherno=<%=teacherno%>">投票</a>
复制代码
使用 url 传值将 teacherno 的值以参数形式传给 vote.jsp。
4)编写 vote.jsp
接下来编写 vote.jsp,代码如下:
<%@ page language="java" import="java.sql.*" pageEncoding="gb2312"%>
<html>
<body>
<%
String teacherno = request.getParameter("teacherno");
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn = DriverManager.getConnection("jdbc:odbc:DSSchool");
String sql =
"UPDATE T_VOTE SET VOTE=VOTE+1 WHERE TEACHERNO=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1,teacherno);
ps.executeUpdate();
ps.close();
conn.close();
%>
<jsp:forward page="display.jsp"></jsp:forward>
</body>
</html>
复制代码
在上述代码中,
String teacherno = request.getParameter("teacherno");
复制代码
获得前一个页面传过来的 teacherno 参数,赋值给 teacherno 变量。
<jsp:forward page="display.jsp"></jsp:forward>
复制代码
表示工作完成之后,跳回 display.jsp,此处用到了 JSP 的 forward 动作。
编写完毕,这个项目的结构如图所示:
▍项目结构
访问 display.jsp,就可以得到相应效果。
04、进一步改进
1)存在的问题
前面的例子中,有一个较大的问题,就是:display.jsp 和 vote.jsp 中,存在大量访问数据库的重复代码。比如,display.jsp 和 vote.jsp 中都存在:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn = DriverManager.getConnection("jdbc:odbc:DSSchool");
复制代码
如何解决这个问题?
2)如何封装数据库连接
对于代码重复,常见的解决方法是将重复的代码写入函数。如何定义函数呢?
我们知道,函数可以在 JSP 声明中定义,因此,可以将数据库连接代码专门放在一个声明中,代码如下:
<%@ page language="java" import="java.sql.*" pageEncoding="gb2312"%>
<%!
public Connection getConnection() throws Exception{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn = DriverManager.getConnection("jdbc:odbc:DSSchool");
return conn;
}
%>
复制代码
特别提醒:如果不是直接访问页面,而仅仅是定义一些功能,文件扩展名理论上可以任意。另外,该函数一定要定义在 JSP 声明中。
3)如何重用代码
定义了函数 getConnection,我们就可以在 display.jsp 和 vote.jsp 中使用该函数了。当然,在此之前,要导入 db.inc。
经过处理的 display.jsp 代码如下:
<%@ page language="java" import="java.sql.*" pageEncoding="gb2312"%>
<%@ include file="db.inc" %>
<html>
<body>
<table align="center">
<caption>欢迎给教师投票</caption>
<tr bgcolor="yellow">
<td>编号</td>
<td>姓名</td>
<td>得票数</td>
<td>投票</td>
</tr>
<%
Connection conn = getConnection();
Statement stat = conn.createStatement();
String sql =
"SELECT TEACHERNO,TEACHERNAME,VOTE FROM T_VOTE";
ResultSet rs = stat.executeQuery(sql);
while(rs.next()){
String teacherno = rs.getString("TEACHERNO");
String teachername = rs.getString("TEACHERNAME");
int vote = rs.getInt("VOTE");
%>
<tr bgcolor="pink">
<td><%=teacherno %></td>
<td><%=teachername %></td>
<td><img src="img/bar.jpg" width="<%=vote%>" height="10"> <%=vote%></td>
<td><a href="vote.jsp?teacherno=<%=teacherno%>">投票</a></td>
</tr>
<%
}
stat.close();
conn.close();
%>
</table>
</body>
</html>
复制代码
在上述代码中,
<%@ include file="db.inc" %>
复制代码
表示导入 db.inc。
Connection conn = getConnection();
复制代码
表示调用导入的 getConnection 方法。
访问 display.jsp,也能得到同样的效果。
05、思考:如何防止刷票
刷票是一种恶意投票行为。在本系统中,也存在刷票的隐患。
访问 display.jsp,显示效果如图所示:
▍显示效果
给编号为 1 的教师投票,界面变为:
▍显示效果
注意,此时浏览器地址栏上的地址变为:
▍地址效果
在保持该 URL 的情况下,点击浏览器上的刷新按钮:
▍刷新按钮
就可以达到刷票的效果。比如,刷新 10 次,界面效果为:
▍显示效果
如果使用 JavaScript 进行定时自动刷新,后果可想而知!
如何解决这个问题呢?请大家评论区补充。
评论