18,927
社区成员
在本篇中,我们将制作一个投票系统,让学生给自己喜爱的老师投票。该系统由1个界面组成,系统运行,出现投票界面,如图所示:
▍显示效果
在这个界面中,标题为:“欢迎给教师投票”;在界面上有一个表格,显示了各位教师的编号、姓名、得票数;其中,得票数显示为一个红色的进度条,并显示得票的数值;表格的第4列是投票链接,点击链接,该教师的票数加1,并显示在界面上。
比如,点击编号为2的教师对应的投票链接,界面效果为:
▍显示效果
由此可见,其票数增加了1票。
在这个项目中,我们只需要用到1个界面:投票界面。需要编写的JSP文件有几个呢?
一种想法认为,只需要编写1个JSP,在里面显示投票界面,同样是这个JSP,负责接受用户的投票,将对应的教师的得票数加1。这种方法比较直观,但是可维护性较差,2个功能的所有代码放在一个JSP内,如果作细微的修改,则比较麻烦,也不利于开发上的分工。
因此我们建议采用如下方法:使用2个JSP,1个JSP负责显示投票界面,另1个JSP负责接受用户的投票,将对应的教师的得票数加1,工作完毕再跳转回第1个JSP。结构如图所示:
▍结构
各页面的命名和作用如下表所示:
▍各模块定义
此处使用Access数据库。很明显,本项目中只需要1个数据表,包含教师编号、教师姓名和得票数。
创建表的脚本如下:
插入一些数据,每个教师初始状态的得票数为0。
本项目中,票数以进度条形式出现,如图所示:
如何出现进度条呢?
实际上,进度条就是一个普通的红色图片,只不过显示时固定其高度,让宽度和得票数成正比就可以了。
用图像处理工具(如画图板)准备一个进度条文件:bar.jpg,含有一个很小的红色正方形即可。
打开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。
接下来编写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,就可以得到相应效果。
前面的例子中,有一个较大的问题,就是:display.jsp和vote.jsp中,存在大量访问数据库的重复代码。比如,display.jsp和vote.jsp中都存在:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn = DriverManager.getConnection("jdbc:odbc:DSSchool");
如何解决这个问题?
对于代码重复,常见的解决方法是将重复的代码写入函数。如何定义函数呢?
我们知道,函数可以在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声明中。
定义了函数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,也能得到同样的效果。
刷票是一种恶意投票行为。在本系统中,也存在刷票的隐患。
访问display.jsp,显示效果如图所示:
▍显示效果
给编号为1的教师投票,界面变为:
▍显示效果
注意,此时浏览器地址栏上的地址变为:
▍地址效果
在保持该URL的情况下,点击浏览器上的刷新按钮:
▍刷新按钮
就可以达到刷票的效果。比如,刷新10次,界面效果为:
▍显示效果
如果使用JavaScript进行定时自动刷新,后果可想而知!
如何解决这个问题呢?请大家评论区补充。