留言板功能需求:
1.页面效果如下图所示,应包含留言和管理员回复功能;
2.访客发布和显示只要一个JSP页面,页面最上方是发布内容区域;
3.管理员回复功能由另一个页面实现。
4.页面下方列出已有留言,还需显示提交时间;
5.留言数据存在服务器的数据库中;
留言发布页面board,jsp的核心代码:
<body class="body">
<center>
<div class="cen">
<div class="edit">
<br><br>
<font face="Tw Cen MT" color="#665ea9" size="6" align="left">Leave your traces!</font><br><br>
<!-- 用户输入表单 -->
<form name="form_submit" action="board.jsp" align="center" method="post">
<!-- 用户图标 -->
<img src="user.png" width="40px" height="40px" align="center">
<!-- 用户名输入框 -->
<input type="text" class="cinput" name="user" placeholder="Username" maxlength="20" οnfοcus="ufocus()"><br>
<div id="name_id" class="divfont"> </div>
<!-- 邮箱图标 -->
<img src="email.png" width="40px" height="40px" align="center">
<!-- 邮箱输入框 -->
<input type="text" class="cinput" name="email" placeholder="Email" maxlength="20" οnfοcus="efocus()"><br>
<div id="email_id" class="divfont"> </div>
<!-- 留言输入框 -->
<textarea type="text" class="ctext" name="saying" placeholder="To say someting..." οnfοcus="sfocus()"></textarea><br>
<div id="saying_id" class="divfont"> </div>
<input type="hidden" name="stime" id="time_id" value="">
<input type="hidden" name="sip" id="ip_id" value="">
<!-- 提交按钮 -->
<input type="submit" class="btn_out" value="" name="OK" οnclick="return checksubmit()" οnmοusemοve="this.className='btn_move'" οnmοuseοut="this.className='btn_out'" >
</form>
</div>
<%
//如果用户提交信息 则插入数据库 其中头像为随机
if(request.getParameter("user")!=null)
{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://url??useUnicode=true&characterEncoding=utf-8",用户名,密码);
Statement stat = conn.createStatement();
//参数化
String sql = "INSERT INTO MessageBoard(MDisplay, MIp, MName, MEmail, MTime, MSaying, MImage) VALUES(1,?,?,?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
//随机头像
int i=new Random().nextInt(10);
String muser=new String(request.getParameter("user").getBytes("iso-8859-1"),"utf-8");
String msaying=new String(request.getParameter("saying").getBytes("iso-8859-1"),"utf-8");
//设置参数
ps.setString(1,request.getParameter("sip"));
ps.setString(2,muser);
ps.setString(3,request.getParameter("email"));
ps.setString(4,request.getParameter("stime"));
ps.setString(5,msaying);
ps.setString(6,"img/head"+i+".png");
ps.executeUpdate();
stat.close();
conn.close();
}
%>
<% //获取页数
int pagei=0;
int maxp=0;
if(request.getParameter("page")!=null)
if(request.getParameter("page")!=""){
String str1=request.getParameter("page");
Pattern pattern = Pattern.compile("[0-9]*");
if(pattern.matcher(str1).matches())
pagei=Integer.parseInt(str1);
}
Connection conn = DriverManager.getConnection("jdbc:mysql://url?useUnicode=true&characterEncoding=utf-8",用户名,密码);
Statement stat = conn.createStatement();
//查询总记录数
String sql1 = "SELECT count(MyId) totalCount FROM MessageBoard WHERE MDisplay=1";
ResultSet rset = stat.executeQuery(sql1);
int rowCount = 0;
//获取总记录数
while(rset.next()) {
rowCount=rset.getInt("totalCount");
}
maxp=(rowCount-1)/10;
//计算页数
if((pagei*10+1)>rowCount)
pagei=maxp;
%>
<input type="hidden" name="getpage" id="getpage_id" value="<%=pagei%>">
<input type="hidden" name="maxpage" id="maxpage_id" value="<%=maxp%>">
<%
pagei*=10;
%>
<div class="board">
<%
// 分页查询 pagei由程序计算生成 不是用户输入 因此不需要参数化
String sql = "SELECT Myid, MName, MTime, MSaying, MImage FROM MessageBoard WHERE MDisplay=1 ORDER BY MTime DESC limit "+pagei+" ,10 ";
ResultSet rs = stat.executeQuery(sql);
//把查询结果先保存下来
List<String> mesIdlist = new ArrayList<String>();
List<String> mesNamelist = new ArrayList<String>();
List<String> mesTimelist = new ArrayList<String>();
List<String> mesSayinglist = new ArrayList<String>();
List<String> mesImglist = new ArrayList<String>();
//打印留言信息
while(rs.next()){
mesIdlist.add(rs.getString("Myid"));
mesNamelist.add(rs.getString("MName"));
mesTimelist.add(rs.getString("MTime"));
mesSayinglist.add(rs.getString("MSaying"));
mesImglist.add(rs.getString("MImage"));
}
for(int ite=0;ite<mesIdlist.size();ite++){
String mesId = mesIdlist.get(ite);
String mesName = mesNamelist.get(ite);
String mesTime = mesTimelist.get(ite);
String mesSaying = mesSayinglist.get(ite);
String mesImg = mesImglist.get(ite);
mesName=mesName.replaceAll("<","<");
mesName=mesName.replaceAll(">",">");
mesName=mesName.replaceAll("\"",""");
mesName=mesName.replaceAll(" "," ");
String mesHead = mesSaying.substring(0, 1);
String mesLast = mesSaying.substring(1);
mesLast=mesLast.replaceAll("<","<");
mesLast=mesLast.replaceAll(">",">");
mesLast=mesLast.replaceAll("\"",""");
mesLast=mesLast.replaceAll(" "," ");
%>
<div class="mandiv">
<img src="<%=mesImg%>" width="74px" height="74px">
<%=mesName%>
</div>
<div class="sayingdiv"><font size="6"><%=mesHead%></font><%=mesLast%></div>
<div class="timediv"><%=mesTime%></div>
<%
// 查询对应留言回复 mesId由程序计算生成 因此不需要参数化
String resql = "SELECT Retext, Rtime FROM ReplyBoard WHERE MyId="+mesId+" ORDER BY Rtime";
ResultSet res = stat.executeQuery(resql);
//打印留言回复
while(res.next()){
String mesReply = res.getString("Retext");
String mesRtime = res.getString("Rtime");
mesReply=mesReply.replaceAll("<","<");
mesReply=mesReply.replaceAll(">",">");
mesReply=mesReply.replaceAll("\"",""");
mesReply=mesReply.replaceAll(" "," ");
%>
<div class="commentdiv"><strong>Administrator reply: </strong><%=mesReply%></div>
<div class="retimediv"><%=mesRtime%></div>
<%
}
%>
<HR>
<%
}
%>
<%
stat.close();
conn.close();
%>
</div>
</div>
<input type="text" style="width:950px;visibility:hidden;" >
<%
//分页按钮
if(pagei!=0){
%>
<button id="btn_previous" class="page_out" οnclick="prepage()" οnmοusemοve="this.className='page_move'" οnmοuseοut="this.className='page_out'"><</button>
<%
}else{
%>
<button class="page_out" style="visibility:hidden;" >h</button>
<%
}
%>
<font size="2"><%=pagei/10+1%></font>
<font size="2">/</font>
<font size="2"><%=maxp+1%></font>
<%
if(pagei/10<maxp){
%>
<button id="btn_next" class="page_out" οnclick="nextpage()" οnmοusemοve="this.className='page_move'" οnmοuseοut="this.className='page_out'">></button>
<%
}else{
%>
<button class="page_out" style="visibility:hidden;" >h</button>
<%
}
%>
</center>
</body>
管理员回复页面adm,jsp的核心代码:
<body class="body">
<center>
<div class="cen">
<div class="edit">
<br><br>
<font face="Tw Cen MT" color="#665ea9" size="6" align="left">Leave your traces!</font><br><br>
<!-- 用户输入表单 -->
<form name="form_submit" action="board.jsp" align="center" method="post">
<!-- 用户图标 -->
<img src="user.png" width="40px" height="40px" align="center">
<!-- 用户名输入框 -->
<input type="text" class="cinput" name="user" placeholder="Username" maxlength="20" οnfοcus="ufocus()"><br>
<div id="name_id" class="divfont"> </div>
<!-- 邮箱图标 -->
<img src="email.png" width="40px" height="40px" align="center">
<!-- 邮箱输入框 -->
<input type="text" class="cinput" name="email" placeholder="Email" maxlength="20" οnfοcus="efocus()"><br>
<div id="email_id" class="divfont"> </div>
<!-- 留言输入框 -->
<textarea type="text" class="ctext" name="saying" placeholder="To say someting..." οnfοcus="sfocus()"></textarea><br>
<div id="saying_id" class="divfont"> </div>
<input type="hidden" name="stime" id="time_id" value="">
<input type="hidden" name="sip" id="ip_id" value="">
<!-- 提交按钮 -->
<input type="submit" class="btn_out" value="" name="OK" οnclick="return checksubmit()" οnmοusemοve="this.className='btn_move'" οnmοuseοut="this.className='btn_out'" >
</form>
</div>
<%
//如果用户提交信息 则插入数据库 其中头像为随机
if(request.getParameter("user")!=null)
{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://url?useUnicode=true&characterEncoding=utf-8",用户名,密码);
Statement stat = conn.createStatement();
//参数化
String sql = "INSERT INTO MessageBoard(MDisplay, MIp, MName, MEmail, MTime, MSaying, MImage) VALUES(1,?,?,?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
//随机头像
int i=new Random().nextInt(10);
String muser=new String(request.getParameter("user").getBytes("iso-8859-1"),"utf-8");
String msaying=new String(request.getParameter("saying").getBytes("iso-8859-1"),"utf-8");
//设置参数
ps.setString(1,request.getParameter("sip"));
ps.setString(2,muser);
ps.setString(3,request.getParameter("email"));
ps.setString(4,request.getParameter("stime"));
ps.setString(5,msaying);
ps.setString(6,"img/head"+i+".png");
ps.executeUpdate();
stat.close();
conn.close();
}
%>
<% //获取页数
int pagei=0;
int maxp=0;
if(request.getParameter("page")!=null)
if(request.getParameter("page")!=""){
String str1=request.getParameter("page");
Pattern pattern = Pattern.compile("[0-9]*");
if(pattern.matcher(str1).matches())
pagei=Integer.parseInt(str1);
}
Connection conn = DriverManager.getConnection("jdbc:mysql://url?useUnicode=true&characterEncoding=utf-8",用户名,密码);
Statement stat = conn.createStatement();
//查询总记录数
String sql1 = "SELECT count(MyId) totalCount FROM MessageBoard WHERE MDisplay=1";
ResultSet rset = stat.executeQuery(sql1);
int rowCount = 0;
//获取总记录数
while(rset.next()) {
rowCount=rset.getInt("totalCount");
}
maxp=(rowCount-1)/10;
//计算页数
if((pagei*10+1)>rowCount)
pagei=maxp;
%>
<input type="hidden" name="getpage" id="getpage_id" value="<%=pagei%>">
<input type="hidden" name="maxpage" id="maxpage_id" value="<%=maxp%>">
<%
pagei*=10;
%>
<div class="board">
<%
// 分页查询 pagei由程序计算生成 不是用户输入 因此不需要参数化
String sql = "SELECT Myid, MName, MTime, MSaying, MImage FROM MessageBoard WHERE MDisplay=1 ORDER BY MTime DESC limit "+pagei+" ,10 ";
ResultSet rs = stat.executeQuery(sql);
//把查询结果先保存下来
List<String> mesIdlist = new ArrayList<String>();
List<String> mesNamelist = new ArrayList<String>();
List<String> mesTimelist = new ArrayList<String>();
List<String> mesSayinglist = new ArrayList<String>();
List<String> mesImglist = new ArrayList<String>();
//打印留言信息
while(rs.next()){
mesIdlist.add(rs.getString("Myid"));
mesNamelist.add(rs.getString("MName"));
mesTimelist.add(rs.getString("MTime"));
mesSayinglist.add(rs.getString("MSaying"));
mesImglist.add(rs.getString("MImage"));
}
for(int ite=0;ite<mesIdlist.size();ite++){
String mesId = mesIdlist.get(ite);
String mesName = mesNamelist.get(ite);
String mesTime = mesTimelist.get(ite);
String mesSaying = mesSayinglist.get(ite);
String mesImg = mesImglist.get(ite);
mesName=mesName.replaceAll("<","<");
mesName=mesName.replaceAll(">",">");
mesName=mesName.replaceAll("\"",""");
mesName=mesName.replaceAll(" "," ");
String mesHead = mesSaying.substring(0, 1);
String mesLast = mesSaying.substring(1);
mesLast=mesLast.replaceAll("<","<");
mesLast=mesLast.replaceAll(">",">");
mesLast=mesLast.replaceAll("\"",""");
mesLast=mesLast.replaceAll(" "," ");
%>
<div class="mandiv">
<img src="<%=mesImg%>" width="74px" height="74px">
<%=mesName%>
</div>
<div class="sayingdiv"><font size="6"><%=mesHead%></font><%=mesLast%></div>
<div class="timediv"><%=mesTime%></div>
<%
// 查询对应留言回复 mesId由程序计算生成 因此不需要参数化
String resql = "SELECT Retext, Rtime FROM ReplyBoard WHERE MyId="+mesId+" ORDER BY Rtime";
ResultSet res = stat.executeQuery(resql);
//打印留言回复
while(res.next()){
String mesReply = res.getString("Retext");
String mesRtime = res.getString("Rtime");
mesReply=mesReply.replaceAll("<","<");
mesReply=mesReply.replaceAll(">",">");
mesReply=mesReply.replaceAll("\"",""");
mesReply=mesReply.replaceAll(" "," ");
%>
<div class="commentdiv"><strong>Administrator reply: </strong><%=mesReply%></div>
<div class="retimediv"><%=mesRtime%></div>
<%
}
%>
<HR>
<%
}
%>
<%
stat.close();
conn.close();
%>
</div>
</div>
<input type="text" style="width:950px;visibility:hidden;" >
<%
//分页按钮
if(pagei!=0){
%>
<button id="btn_previous" class="page_out" οnclick="prepage()" οnmοusemοve="this.className='page_move'" οnmοuseοut="this.className='page_out'"><</button>
<%
}else{
%>
<button class="page_out" style="visibility:hidden;" >h</button>
<%
}
%>
<font size="2"><%=pagei/10+1%></font>
<font size="2">/</font>
<font size="2"><%=maxp+1%></font>
<%
if(pagei/10<maxp){
%>
<button id="btn_next" class="page_out" οnclick="nextpage()" οnmοusemοve="this.className='page_move'" οnmοuseοut="this.className='page_out'">></button>
<%
}else{
%>
<button class="page_out" style="visibility:hidden;" >h</button>
<%
}
%>
</center>
</body>
结果展示:
访客发布和显示页面:
管理员回复页面:
技术要点总结:
1、PreparedStatement参数化传值进行SQL操作,防止恶意用户的SQL注入。
2、分页查询(limit)可减轻数据库的负载以及web页面在传输时所占的带宽。
3、对于提交内容的特殊字符进行转换,以防止HTML或JS攻击。
4、对于中文字符,需要对其进行转码操作。
5、项目大了,纯JSP的页面显然显得过于臃肿,还是建议使用MVC模式或者其他框架模块化编写。