servlet+jsp+mysql+資料庫連線池實現註冊登陸驗證碼功能
首先專案的結構及所用到的jar包如圖:
主要用到jdbc和jstl的jar包,大家可自行去相應網站下載
一、資料庫和資料表的建立
1.建庫語句:
create database test;
2.建表語句:
CREATE TABLE `t_users` ( `user_name` varchar(20) COLLATE utf8_unicode_ci NOT NULL, `password_md5` varchar(50) COLLATE utf8_unicode_ci NOT NULL, `email` varchar(30) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`user_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
二、eclipse配置資料庫連線池
首先建立一個動態web專案
1.把jdbc所用到的jar包複製到/web-inf/lib目錄下,如圖:
2.在meta-inf下建立一個context.xml檔案,並輸入以下程式碼:
<?xml version="1.0" encoding="UTF-8"?> <Context path="/test" reloadable="true"> <!-- 配置資料來源 --> <Resource auth="Container" driverClassName="com.mysql.jdbc.Driver" maxActive="100" maxldle="30" maxWait="10000" name="jdbc/test" password="root" type="javax.sql.DataSource" url="jdbc:mysql://localhost:3306/test?autoReconnect=true" username="root"> </Resource> </Context>
<Resource屬性說明>
1)name:指定Resource的JNDI名字。
2)auth:指定管理Resource的Manager,它有兩個可選值:Container和Application。Container表示由容器來建立和管理Resource,Application表示由web應用來建立和管理Resource。
3)type: 指定Resource的Java類名。
4)username:指定連線資料庫的使用者名稱。
5)password:指定連線資料庫的口令。
6)driverClassName:指定連線資料庫的JDBC驅動器中的Driver實現類的名字。
7)url:指定連線資料庫的URL,127.0.0.1是要連線的資料庫伺服器的ip,3306是資料庫伺服器埠,BookDB是資料庫名稱。
8)maxActive:指定資料庫連線池中處於活動狀態的資料庫連線的最大數目,取值為0,表示不受限制。
9)maxIdle:指定資料庫連線池中處於空閒狀態的資料庫連線的最大數目,取值為0,表示不受限制。
10)maxWait:指定資料庫連線池中的資料庫連線處於空閒狀態的最長時間(以毫秒為單位),超過這一時間,將會丟擲異常。取值為-1,表示可以無限期等待。
3.配置web.xml
在<web-app></web-app>之間加入如下程式碼:
<resource-ref> <description>MySQL DBCP</description> <res-ref-name>jdbc/test</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>
<resource-ref>屬性說明:
1)description:對所引用的資源的說明。
2)res-ref-name:指定所引用資源的JNDI名字,與<Resource>元素中的name屬性對應。
3)res-type:指定所引用資源的類名,與<Resource>元素中的type屬性對應。
4)res-auth:指定管理所引用資源的Manager,與<Resource>元素中的auth屬性對應。
4.配置server.xml檔案
在tomcat\conf下找到server.xml檔案,在<GlobalNamingResources></GlobalNamingResources>之間加入如下內容:
<Resource name="jdbc/test" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/test?characterEncodering=utf-8" username="root" password="root" maxActive="200" maxIdle="50" maxWait="3000"/>
在<Host></Host>之間加入如下內容:
<Context docBase="D:\eclipse-workspace\loginRegister\WebContent" path="/LoginRegister" reloadable="true" source="org.eclipse.jst.j2ee.server:test"> <ResourceLink global="jdbc/test" name="jdbc/test" type="javax.sql.DataSource"/> </Context>
<Context>屬性說明:
1)docBase:指定Web應用的檔案路徑,可以給定絕對路徑,也可以給定相對於<Host>的appBase屬性的相對路徑。如果Web應用採用開放目錄結構,則指定Web應用的根目錄;如果Web應用是個WAR檔案,則指定WAR檔案的路徑。
2)path:指定訪問該Web應用的URL入口。
3)reloadable:如果這個屬性為true,Tomcat伺服器會在執行狀態下監視classes下檔案的改動和WEB-INF/web.xml檔案的改動,監測到檔案被改動,伺服器會自動重新載入Web應用。
4)source:
<ResourceLink>屬性說明:
1)global:被連線的連線全域性資源的名稱。
2)name:建立的資源連線的名稱,相對於java:comp/env context。
3)type:當web應用在該資源連線上進行查詢時,返回的Java類名的全稱。
至此資料庫連線池配置完
三、實現訪問資料庫的DBServlet類
實現程式碼如下:
import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet;
import javax.naming.Context; import javax.naming.InitialContext; 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.sql.DataSource;
/** * Servlet implementation class DBServlet */ @WebServlet("/DBServlet") public class DBServlet extends HttpServlet { private static final long serialVersionUID = 1L; //用於連線資料庫的Connection物件 protected Connection conn=null; protected ResultSet execSQL(String sql,Object... args) throws Exception{ //建立Preparedment物件 PreparedStatement pStmt=conn.prepareStatement(sql); //為pStmt物件設定SQL引數值 for(int i=0;i<args.length;i++) { pStmt.setObject(i+1,args[i]); //設定SQL引數值 } pStmt.execute(); //執行SQL語句 //返回結果集,如果執行的SQL語句不返回結果集,則返回null return pStmt.getResultSet(); } //核對使用者輸入的驗證碼是否合法 protected boolean checkValidationCode(HttpServletRequest request, String validationCode) { //從httpSession中獲得系統隨機生成的驗證碼 String validationCodeSession=(String)request.getSession() .getAttribute("validation_code"); //如果獲得的驗證碼為null,說明驗證碼過期,使用者必須重新整理客戶端頁面,以獲得新的驗證碼 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; } /** * @see HttpServlet#HttpServlet() */ public DBServlet() { super(); // TODO Auto-generated constructor stub }
/** * @see Servlet#destroy() */ public void destroy() { // TODO Auto-generated method stub try { //如果資料庫連線正常開啟則關閉 if(conn!=null) conn.close(); }catch(Exception e) { } }
/** * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response) */ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub try { //如果conn為null,開啟資料庫連線 if(conn==null) { //建立上下文物件ctx Context ctx=new InitialContext(); //TODO //獲取資料來源 DataSource ds=(DataSource)ctx.lookup("java:/comp/env/jdbc/test"); conn=ds.getConnection(); //為Connection物件賦值 } }catch(Exception e) { } } }
四、實現圖形驗證碼
程式碼如下:
import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.util.Random;
import javax.imageio.ImageIO; import javax.servlet.ServletException; import javax.servlet.http.*;
public class ValidationCode extends HttpServlet { //圖形驗證碼的字元集合,系統將隨機從這個字串中選擇一些字元作為驗證碼 private static String codeChars= "@#$%^&*123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; //返回一個隨機顏色(Color物件) private static Color getRandomColor(int minColor,int maxColor) { Random random=new Random(); //儲存minColor最大不會超過255 if(minColor>255) minColor=255; //儲存maxColor最大不會超過255 if(maxColor>255) maxColor=255; //獲得hong、綠、藍三種顏色的隨機顏色值 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); } @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub //獲取驗證碼集合的長度 int charsLength=codeChars.length(); //關閉客戶端瀏覽器的緩衝區 response.setHeader("ragma","No-cache"); response.setHeader("Cache-Control","no-cache"); response.setDateHeader("Expires",0); //設定圖形驗證碼的長和寬 int width=90,height=20; BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); //獲得用於輸出文字的Graphics物件 Graphics g=image.getGraphics(); Random random=new Random(); g.setColor(getRandomColor(180,250)); //隨機設定要填充的顏色 g.fillRect(0,0, width, height); //填充圖形背景 //設定初始字型 g.setFont(new Font("Times New Roman",Font.ITALIC,height)); g.setColor(getRandomColor(120,180)); //隨機設定字型顏色 //用於儲存最後隨機生成的驗證碼 StringBuilder validationCode=new StringBuilder(); //驗證碼的隨機字型 String[] fontNames= {"Times New Roman","Book antiqua","Arial"}; for(int i=0;i<3+random.nextInt(3);i++) { //隨機生成3-5個驗證碼 //隨機設定當前驗證碼的字元的字型 g.setFont(new Font(fontNames[random.nextInt(3)],Font.ITALIC,height)); //隨機獲得當前驗證碼的字元 char codeChar=codeChars.charAt(random.nextInt(charsLength)); validationCode.append(codeChar); //隨機設定當前驗證碼字元的顏色 g.setColor(getRandomColor(10,100)); //在圖形上輸出驗證碼字元,x和y都是隨機生成的 g.drawString(String.valueOf(codeChar), 16*i+random.nextInt(7),height-random.nextInt(6)); } //獲得HttpSession物件 HttpSession session=request.getSession(); //設定5分鐘失效 session.setMaxInactiveInterval(5*60); //將驗證碼儲存在session物件中 session.setAttribute("validation_code",validationCode.toString()); g.dispose(); //關閉Graphics物件 OutputStream os=response.getOutputStream(); //以jpeg格式向客戶端傳送圖形驗證碼 ImageIO.write(image,"JPEG",os); } }
五、實現註冊系統
1.實現註冊Servlet類
Register.java程式碼如下:
import java.io.IOException;
import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public class Register extends DBServlet{
@Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub String userName=null; if(request.getParameter("login")!=null) { response.sendRedirect("login.jsp"); return; }try { super.service(request, response); userName=request.getParameter("username"); String password=request.getParameter("password"); String email=request.getParameter("email"); String validationCode=request.getParameter("validation_code"); if(userName==null||password==null||validationCode==null) return; if(userName.equals("")||password.equals("")||validationCode.equals("")) return; userName=new String(userName.getBytes("ISO-8859-1"),"UTF-8"); request.setAttribute("page","register.jsp"); if(!checkValidationCode(request,validationCode)) return; email=(email==null)?"":email; String _password=password; String sql="insert into t_users(user_name,password_md5,email) values(?,?,?)"; execSQL(sql,userName,_password,email); request.setAttribute("info","使用者註冊成功!"); }catch(Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); request.setAttribute("info",userName+"已經被使用!"); }finally { RequestDispatcher rd=request.getRequestDispatcher("result.jsp"); rd.forward(request,response); }
} }
2.實現這測系統主介面
register.jsp程式碼如下:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html> <html> <head> <script type="text/javascript"> function checkRegister(){ var username=document.getElementById("username"); if(username.value==""){ alert("使用者名稱不能為空!"); username.focus(); return; } var password=document.getElementById("password"); if(password.value==""){ alert("必須輸入密碼!"); password.focus(); return; } var repassword=document.getElementById("repassword"); if(repassword.value!=password.value){ alert("兩次輸入的密碼不一致!"); repassword.focus(); return; } var email=document.getElementById("email"); if(email.value!==""){ if(!checkEmail(email)) return; } var validation_code=document.getElementById("validation_code"); if(validation_code.value==""){ alert("驗證碼b不能為空"); validation_code.focus(); return; } register_form.submit(); } function checkEmail(email){ var email=email.value; var pattern =/^([a-zA-Z0-9._-])[email protected]([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/; flag=pattern.test(email); if(!flag){ alert("email格式不正確"); email.focus(); return false; } return true; } function refresh(){ var img=document.getElementById("img_validation_code") img.src="validation_code?"+Math.random(); } </script> <meta charset="utf-8"> <title>註冊頁面</title> </head> <body> <form name="register_form" action="register" method="post"> <span class="require">*</span>使用者名稱: <input type="text" id="username" name="username" size="30" maxLength="30"/><br/> <span class="require">*</span>密碼: <input type="password" id="password" name="password" size="30" maxLength="30"/><br/> <span class="require">*</span>請再次輸入密碼: <input type="password" id="repassword" name="repassword" size="30" maxLength="30"/><br/> 郵箱地址: <input type="text" id="email" name="email" size="30" maxLength="30"/><br/> <span class="require">*</span>驗證碼: <input type="text" id="validation_code" name="validation_code" style="width:60px;margin-top:2px" size="30" maxLength="30"/> <img id="img_validation_code" src="validation_code"/> <input type="button" value="重新整理" onclick="refresh()"/><br/> <input type="button" value="註冊" onclick="checkRegister()"/> <input type="submit" value="登陸" name="login"/> </form> </body> </html>
3.實現結果jsp頁面
result.jsp程式碼如下:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>結果頁</title> </head> <body> <form name="form" action="${requestScope.page}" method="post"/> <script type="text/javascript"> <c:if test="${requestScope.info!=null}"> alert('${requestScope.info}'); form.submit(); </c:if> </script> </body> </html>
六、實現登陸系統
1.實現登陸servlet
Login.java程式碼如下:
import java.io.IOException; import java.sql.ResultSet;
import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public class Login extends DBServlet{
@Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub if(request.getParameter("register")!=null) { response.sendRedirect("register.jsp"); return; } String page="login.jsp"; String userName=""; try { super.service(request, response); userName=request.getParameter("username"); String password=request.getParameter("password"); String validationCode=request.getParameter("validation_code"); if(userName==null||password==null||validationCode==null) return; if(userName.equals("")||password.equals("")||validationCode.equals("")) return; userName=new String(userName.getBytes("ISO-8859-1"),"UTF-8"); if(!checkValidationCode(request,validationCode)) return; String sql="select user_name,password_md5 from t_users where user_name=?"; ResultSet rs=execSQL(sql,new Object[]{userName}); if(rs.next()==false) { request.setAttribute("userError",userName+"不存在"); }else { if(!rs.getString("password_md5").equals(password)) request.setAttribute("passwordError","密碼不正確"); else page="WEB-INF/main.jsp"; //TODO } }catch(Exception e) { }finally { request.setAttribute("username",userName); RequestDispatcher rd=request.getRequestDispatcher(page); rd.forward(request,response); } } }
在web-inf下建立main.jsp
之所以把main.jsp放到web-inf目錄中,是因為這個目錄中的檔案在客戶端瀏覽器是無法直接訪問的,一般需要驗證才能訪問的頁面都應該放在該目錄或其子目錄中
main.jsp的程式碼如下:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>登陸成功</title> </head> <body> 登陸成功 </body> </html>
2.實現登陸系統主介面
login.jsp程式碼如下:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>登陸頁面</title> <script type="text/javascript"> function checkLogin(){ var username=document.getElementById("username"); if(username.value==""){ alert("使用者名稱不能為空!"); username.focus(); return; } var password=document.getElementById("password"); if(password.value==""){ alert("必須輸入密碼!"); password.focus(); return; } var validation_code=document.getElementById("validation_code"); if(validation_code.value==""){ alert("驗證碼不能為空"); validation_code.focus(); return; } login_form.submit(); } function refresh(){ var img=document.getElementById("img_validation_code") img.src="validation_code?"+Math.random(); } </script> </head> <body> <form name="login_form" action="login" method="post"> 賬號: <input type="text" id="username" value="${requestScope.username}" name="username" size="30" maxLength="30"/> <font color="#FF0000">${requestScope.userError}</font><br/> 密碼: <input type="password" id="password" name="password" size="30"/> <font color="#FF0000">${requestScope.passwordError}</font><br/> 驗證碼: <input type="text" id="validation_code" name="validation_code" style="width:60ox;margin-top:2px;" size="30" maxLength="30"/> <font color="#FF0000">${requestScope.codeError}</font> <img id="img_validation_code" src="validation_code"/> <input type="button" value="重新整理" onclick="refresh()"/><br/> <input type="button" value="登陸" name="login" onclick="checkLogin()"/> <input type="submit" value="註冊" name="register"/> </form> </body> </html>
最後elipse啟動tomcat即可執行