JSP/Servlet 实现简单的留言板
系 统 概 述
一个简单的留言板所实现的功能有:用户注册、用户登录、查看留言信息和留言四个功能。在学习了JSP/Servlet后编写的
一个简单的实例,虽然简单,却拥有一个完整系统的必要功能,所以可以让自己初步了解使用JSP/Servlet技术开发系统的一般步骤。
系统功能简介:
用户注册:当用户注册一个新用户时,就是向数据库user_table表中添加一条记录。
当用户输入注册信息后,将用户的的注册信息提交到服务端负责处理注册信息的Servlet。当Servlet成功处理完用户的信息后,
客户端自动跳转到【登录界面】进行登录。
用户登录:当用户输入用户名、密码和验证码时。系统将信息提交的处理登录信息的Servlet。Servlet则调用服务器控制器里
的方法来处理用户登录。当用户登录成功时,客户端自动跳转到【留言板】。
留言板:调用数据库中的留言信息,显示在页面上。同时用户可以通过【留言】按钮,跳转到【留言】界面,留言功能和注册功能
类似,向数据库ly_table表中添加一条记录。
数据库的设计:
对于该系统来说有两个表【user_table】和【ly_table】。
【user_table】如下:
字段名 | 类型 | 含义 |
id | int | 用户id |
username | varchar(20) | 用户名 |
password | varchar(20) | 密码 |
【ly_table】如下:
字段名 | 类型 | 含义 |
id | int | 留言信息的id |
userId | int | 用户的id |
title | varchar(25) | 标题名字 |
date | date | 留言时间 |
connect | text | 留言类容 |
实现系统的基础类:
实现在注册、登录系统中使用的一些重要的类:连接和操作数据库的DB类、存储用户的User类、
存储留言信息的LeaveMessageTable类和实现图形验证码的ValidationCode类。
连接和操作数据库的DB类中具体包括如下方法:
public User checkUser(String username , String password) :检查用户时候存在,存在就返回一个User对象,否则返回null 。
public boolean checkValidationCode(HttpServletRequest request ,String validationCode) :检测验证码是否正确。
public boolean addInfo(LeaveMessageTable ly) : 向数据库插入留言。
public boolean insertUser(String username,String password) :向数据库存入用户。
public ArrayList findLyInfo() : 从数据库中导出留言,返回一个ArrayList对象。
private ResultSet execSQL(String sql , Object ...args) : 执行SQL语句。
在DB类的构造函数中连接数据库。这样有Servlet类创建DB对象时,便在创建过程中进行数据库的连接。
package com.cnblogs.jbelial.DBServlet; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; import javax.servlet.http.HttpServletRequest; import Common.Encrypter; import Common.LeaveMessageTable; import Common.User; public class DB{ // 定义数据库连接变量 private Connection connection ; // 定义参数 private String sql_driver = "com.mysql.jdbc.Driver" ; private String sql_url = "jdbc:mysql://localhost:3306/web_ly_table" ; private String sql_username = "root" ; private String sql_password = "hezuoan" ; public DB() { try { //建立数据库的连接 Class.forName(sql_driver) ; connection = DriverManager.getConnection(sql_url,sql_username,sql_password) ; } catch(Exception e) { e.printStackTrace() ; } } // 用于执行各种SQL语句的方法 private ResultSet execSQL(String sql , Object ...args) throws SQLException { PreparedStatement pstmt = connection.prepareStatement(sql) ; // 为PreparedStatement对象设置SQL参数 for (int i = 0 ; i < args.length ; ++ i) { pstmt.setObject(1 + i, args[i]) ; } // 运行 pstmt.execute() ; return pstmt.getResultSet(); } // 核对用户输入的验证码是否正确 public boolean checkValidationCode(HttpServletRequest request , String validationCode) { String validationCodeSession = (String) request.getSession().getAttribute("validationCode") ; if(validationCodeSession == null) { // 给result.jsp设置信息 request.setAttribute("info" , "验证码过期") ; // 给login.jsp设置信息 request.setAttribute("codeError", "验证码过期") ; return false ; } if(!validationCode.equalsIgnoreCase(validationCodeSession)) { request.setAttribute("info","验证码错误") ; request.setAttribute("codeError", "验证码错误") ; return false ; } return true; } // 检查用户登录信息 public User checkUser(String username , String password) { try { String sql = "select * from user_table where username = ? and password = ?" ; ResultSet rs = execSQL(sql,username,password) ; User user = new User() ; while (rs.next()) { user.setId(rs.getInt("id")) ; user.setUsername(rs.getString("username")) ; user.setPassword(rs.getString("password")) ; return user ; } return null ; } catch(Exception e) { e.printStackTrace(); return null ; } } // 插入留言 public boolean addInfo(LeaveMessageTable ly){ try{ String sql = "insert into ly_table(userId,data,title,content) values(?,?,?,?)" ; execSQL(sql , ly.getUserId(), ly.getDate(),ly.getTitle(),ly.getContent()); return true; }catch(Exception e){ e.printStackTrace(); return false; } } // 插入用户 public boolean insertUser(String username,String password){ try{ String sql = "insert into user_table(username,password) values(?,?)" ; execSQL(sql ,username , password) ; return true; }catch(Exception e){ e.printStackTrace(); return false; } } // 获取留言信息。 public ArrayList findLyInfo() { ArrayList arrayList = new ArrayList() ; try { String sql = "select * from ly_table" ; ResultSet rs = execSQL(sql) ; while(rs.next()) { LeaveMessageTable ly = new LeaveMessageTable() ; ly.setId(rs.getInt("id")) ; ly.setUserId(rs.getInt("userId")) ; ly.setDate(rs.getDate("data")) ; ly.setTitle(rs.getString("title")) ; ly.setContent(rs.getString("content")) ; arrayList.add(ly) ; } return arrayList ; } catch(Exception e) { e.printStackTrace() ; return null ; } } // 获取用户名 public String getUserName(int id) { String username = null; try{ String sql = "select username from user_table where id = ?" ; ResultSet rs= execSQL(sql , new Object[]{id}); while(rs.next()){ username=rs.getString(1); } return username; }catch(Exception e){ e.printStackTrace(); return null; } } }
User类和LeaveMessageTable类:
User类中则包含Id、用户名和密码三个属性。同时包含各个属性的set和get方法。
package Common; public class User { // 用户的id private int id ; // 用户名 private String username ; // 用户密码 private String password ; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
LeaveMessageTable类:包含了如下属性Id、留言用户Id、留言标题、留言时间、留言类容属性。同时也包含了各个属性的
set和get方法。
package Common; import java.sql.Date; public class LeaveMessageTable { private int id ; private int userId ; private Date date ; private String title ; private String content ; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
实现图形验证码:
实现图形验证码大致分为5步上来完成:
1、建立图形缓冲区;
2、在图形缓冲区用随机颜色填充背景。
3、在图形缓冲区上输出验证码。
4、将验证码保存在HttpSession对象中。
5、向客户端输出图形验证码。
通过ValidationCode类来实现验证码功能,该类也是Servlet类,在客户端只要像访问普通Servlet一样访问ValidationCode类即可。
package com.cnblogs.jbelial.Validation; import java.awt.*; import java.awt.image.BufferedImage; import java.io.* ; import java.util.Random; import javax.imageio.ImageIO; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @SuppressWarnings("serial") public class ValidationCode extends HttpServlet { // 图形验证码的字符集合,系统通过随机从这些字符串中选择一些字符作为验证码 private static String codeChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTYVWXYZ" ; // 返回一个随机颜色 private static Color getRandomColor(int minColor , int maxColor) { Random random = new Random() ; if (minColor > 255) minColor = 255 ; if (maxColor > 255) maxColor = 255 ; // 获取颜色的随机值 int red = minColor + random.nextInt(maxColor - minColor) ; int green = minColor + random.nextInt(maxColor - minColor) ; int blue = minColor + random.nextInt(maxColor - minColor) ; return new Color(red,green,blue) ; } public void doGet (HttpServletRequest request , HttpServletResponse response) throws IOException { // 获取验证码集合的长度。 int charsLength = codeChars.length() ; // 关闭浏览器缓冲区 response.setHeader("ragma", "No-cache") ; response.setHeader("Cache-Control", "no-cache") ; response.setDateHeader("Expires", 0) ; // 设置图片传送的格式。 response.setContentType("image/jpeg"); // 设置图形验证码的长和宽度 int width = 90 ; int height = 20 ; // 建立图形缓冲区 BufferedImage image = new BufferedImage(width , height, BufferedImage.TYPE_INT_RGB) ; // 获取用于输出文字的Graphics对象 Graphics graphics = image.getGraphics() ; Random random = new Random() ; // 设置要填充的颜色 graphics.setColor(getRandomColor(180 , 250)) ; // 填充图形背景 graphics.fillRect(0, 0, width, height) ; // 设置初始字体和颜色 graphics.setFont(new Font("Time New Roman" , Font.ITALIC, height)) ; graphics.setColor(getRandomColor(120,180)) ; // 保存验证码 StringBuilder validationCode = new StringBuilder() ; // 验证码的随机字体 String[] fontNames = {"Times New Roman" , "Book antiqua" , "Arial" } ; // 随机生成验证码 for (int i = 0 ; i < 4 ; ++ i) { // 设置当前验证码字符的字体 graphics.setFont(new Font(fontNames[random.nextInt(3)] , Font.ITALIC , height)) ; // 随机获得验证码的字符 char codeChar = codeChars.charAt(random.nextInt(charsLength)) ; validationCode.append(codeChar) ; graphics.setColor(getRandomColor(20,120)) ; // 在图形上输出验证码字符 graphics.drawString(String.valueOf(codeChar), 16*i+random.nextInt(7), height - random.nextInt(6) ) ; } // 获得Session对象,并设置Session对象为3分钟 HttpSession session = request.getSession(); session.setMaxInactiveInterval(5*60) ; // 将验证码放入session对象中. session.setAttribute("validationCode",validationCode.toString() ) ; // 关闭graphics对象。 graphics.dispose() ; // 向客户端发送图形验证码 ImageIO.write(image,"JPEG" ,response.getOutputStream()) ; } public void doPost (HttpServletRequest request , HttpServletResponse response) throws IOException { doGet(request , response) ; } }
实现注册系统:
包括一个register.jsp、result.jsp和RegisterServlet类。
RegisterServlet类负责处理处理用户的提交的注册信息。
RegisterServlet类在处理用户注册信息之前,创建DB类对象来连接数据库。然后通过调用DB类的方法来判断验证码是否正确和用户名是否被注册。
当一系列的判断都通过时,则向数据库中插入用户记录。
RegisterServlet类的最后不管是否向数据库中插入用户记录,都会跳转到result.jsp页面。
package com.cnblogs.jbelial.Register; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import Common.User; import com.cnblogs.jbelial.DBServlet.DB; public class RegisterServlet extends HttpServlet { /** * The doGet method of the servlet. <br> * * This method is called when a form has its tag value method equals to get. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置字符集编码 request.setCharacterEncoding("UTF-8") ; response.setContentType("UTF-8"); // 判断是否跳到【登录】 if (request.getParameter("login") != null) { response.sendRedirect("login.jsp") ; return ; } DB db = new DB() ; String username = null ; // 设置result页面要跳转的页面 String page = "login.jsp" ; try { // 获取界面的用户名和密码参数 username = request.getParameter("username") ; String password = request.getParameter("password") ; String validationCode = request.getParameter("validationCode") ; // 核对验证码 if (!db.checkValidationCode(request, validationCode)) return ; User user = db.checkUser(username,password) ; if (user != null) { request.setAttribute("info", username + "已被使用!") ; page = "register.jsp" ; } else if (db.insertUser(username , password)) { // 定义result.jsp中使用的消息 request.setAttribute("info" , "用户注册成功") ; } request.setAttribute("page", page) ; } catch(Exception e) { } finally { // 跳转到result.jsp RequestDispatcher rd = request.getRequestDispatcher("/result.jsp") ; rd.forward(request, response) ; } } /** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to post. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response) ; } }
register.jsp则负责显示注册页面:
<%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>用户注册</title> <script type="text/javaScript"> function refresh() { var img = document.getElementById("imgValidationCode") ; img.src = "ValidationCode"+Math.random() ; } function checkRegister() { var username = document.getElementById("username") ; if(username.value == "" ) { alert("请输入用户名!") ; //把焦点放到username输入文本上 username.focus() ; return ; } var password = document.getElementById("password") ; if(password.value == "" ) { alert("请输入密码!"); password.focus() ; return ; } var re_password = document.getElementById("re_password") ; if(re_password.value != password.value) { alert("输入的密码不一致!") ; re_password.focus() ; return ; } var validationCode = document.getElementById("validationCode") ; if(validatoinCode.value == "") { alert("请输入验证码!"); validatoinCode.focus() ; return ; } register_form.submit() ; } </script> </head> <body> <center> <h2>用户注册</h2> <form name = "register_form" action = "RegisterServlet" method = "post"> <table> <tr> <td> 用户名: </td> <td> <input type = "text" id = "username" name = "username" size = "25"> </td> </tr> <tr> <td> 密码: </td> <td> <input type = "password" id = "password" name = "password" size = "25"> </td> </tr> <tr> <td> 再次输入密码: </td> <td> <input type = "password" id = "re_password" name = "re_password" size = "25"> </td> </tr> <tr> <td> 验证码: </td> <td> <input type = "text" id = "validationCode" name = "validationCode" style = "width:60px;margin-top:10px"/> <img id = "imgValidationCode" src = "ValidationCode"/> <input type = "button" value = "刷新" onclick = "refresh()"/> </td> </tr> </table> <input type = "button" value = "注册" onclick = "checkRegister()"/> <input type = "submit" value = "登录" name = "login"> </form> </center> </body> </html>
result.jsp页面则负责显示结果:
<%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <body> <form name = "result_form" action = "${requestScope.page}" , method = "post"> ${requestScope.info} <input type = "submit" value = "确定" > </form> </body> </html>
实现登录系统:
登录系统和注册系统类似,包含login.jsp和LoginServlet类。
LoginServlet类负责处理用户提交的登录信息。通过创建DB对象来连接数据库,再调用DB中的方法来判断用户提交的验证码和用户名、密码
的真确性,如果都正确则跳转到main.jsp,否则返回到login.jsp并显示提示消息;
package com.cnblogs.jbelial.Login; import java.io.IOException; import java.util.ArrayList; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import Common.User; import com.cnblogs.jbelial.DBServlet.DB; public class LoginServlet extends HttpServlet { /** * The doGet method of the servlet. <br> * * This method is called when a form has its tag value method equals to get. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置字符集编码 request.setCharacterEncoding("UTF-8") ; response.setContentType("UTF-8"); // 判断是否跳到【注册】 if (request.getParameter("register") != null) { response.sendRedirect("register.jsp") ; return ; } DB db = new DB() ; // 设置跳转界面 String page = "login.jsp" ; String username = null ; try { // 获取请求页面的参数 username = request.getParameter("username") ; String password = request.getParameter("password") ; String validationCode = request.getParameter("validationCode") ; // 验证码检测 if (!db.checkValidationCode(request, validationCode)) return ; User user = db.checkUser(username,password) ; if (user == null) request.setAttribute("userError", "用户名或密码错误") ; if (user != null) { // 如果根据检查,user不为空,表示用户名正确和密码正确,进行下一步操作。 ArrayList arrayList = new ArrayList() ; arrayList = db.findLyInfo() ; request.setAttribute("arrayList", arrayList) ; // 设置跳转到主界面 page = "main.jsp" ; request.getSession().setAttribute("user", user) ; } } catch(Exception e){} finally { request.setAttribute("username", username) ; RequestDispatcher rd = request.getRequestDispatcher("/"+page) ; rd.forward(request, response) ; } } /** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to post. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response) ; } }
login.jsp则负责显示登录界面
<%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>用户登录</title> </head> <script type="text/javaScript"> function refresh() { var img = document.getElementById("imgValidationCode") ; img.src = "ValidationCode" ; } function checkLogin() { var username = document.getElementById("username_id"); if (username.value == "" ) { alert("请输入用户名!") ; username.focus() ; return ; } var password = document.getElementById("password_id") ; if (password.value == "") { alert("密码不能为空"); password.focus() ; return ; } var validationCode = document.getElementById("validationCode_id") ; if ( validationCode.value == "") { alert("验证吗不能为空") ; validationCode.focus() ; return ; } login_form.submit() ; } </script> <body> <center> <h2>用户登录</h2> <form name = "login_form" action = "LoginServlet" method = "post" > <table> <tr> <td> 用户名: </td> <td> <input type = "text" id = "username_id" value = "${requestScope.username}" name = "username" size = "25" />${requestScope.userError} </td> </tr> <tr> <td> 密 码: </td> <td> <input type="password" id="password_id" name="password" size="25"> </td> </tr> <tr> <td> 验证码: </td> <td> <input type = "text" id = "validationCode_id" name = "validationCode" style = "width:60px;margin-top:10px"/> <img id = "imgValidationCode" src = "ValidationCode"/> <input type = "button" value = "刷新" onclick = "refresh()"/> ${requestScope.codeError} </td> </tr> </table> <input type = "button" value = "登录" onclick = "checkLogin()"> <input type = "submit" value = "注册" name = "register"> </form> </center> </body> </html>
实现留言系统:
留言系统包括负责显示用户留言的main.jsp页面、用户写留言的LeaveMessage.jsp页面和处理用户提交留言的addMessageServlet类 。
addMessageServlet类就是把用户提交的留言信息提取出来,然后存入数据库。
main.jsp则在用户登录后,自动跳转到显示留言的界面。