第一步:
1、为项目配置 Tomcat 为 server:
2、导入 mysql的jar包 到项目目录中:
第二步:编码
1、数据库连接类ConnectMysql.java代码:
1 package com.testing.mysql; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 6 public class ConnectMysql { 7 //设置连接的成员变量 8 public Connection conn; 9 //数据库的远程连接地址、用户名和密码,此处是我自己的虚拟机里面的MySQL数据库(库名为test_project)和虚拟机的登录用户名、密码10 public static final String DBURL="jdbc:mysql://192.168.112.128:3306/test_project?useUnicode=true&autoReconnect=true&characterEncoding=utf-8";11 public static final String DBUSER="root";12 public static final String DBPWD="123456";13 //构造方法14 public ConnectMysql() {15 try {16 Class.forName("com.mysql.jdbc.Driver");17 conn = DriverManager.getConnection(DBURL, DBUSER, DBPWD);18 //设置连接的超时时间19 DriverManager.setLoginTimeout(10);20 } catch (Exception e) {21 // TODO Auto-generated catch block22 e.printStackTrace();23 }24 }25 }
2、创建UseMysql的类:
1 package com.testing.mysql; 2 3 import java.sql.CallableStatement; 4 import java.sql.Connection; 5 import java.sql.ResultSet; 6 import java.sql.ResultSetMetaData; 7 import java.sql.SQLException; 8 import java.sql.Statement; 9 import java.util.HashMap; 10 import java.util.Map; 11 12 public class UseMysql { 13 14 // 数据库连接对象 15 private Connection ct; 16 17 // 构造函数中初始化这个数据库连接对象 18 public UseMysql(Connection conn) { 19 ct = conn; 20 } 21 22 23 24 25 /** 26 * @param name登录用户名 27 * @return 返回查询信息的结果集合 28 */ 29 public Map<String, String> getUserInfo(String name) { 30 String sql = "SELECT * FROM userinfo where username=‘" + name + "‘;"; 31 System.out.println(sql); 32 // 保存查询结果的集合 33 ResultSet rs = null; 34 // 声明statement对象,通过这个对象查询数据库 35 Statement sm; 36 try { 37 // 通过数据库连接实例化statement对象 38 sm = ct.createStatement(); 39 // 执行查询 40 rs = sm.executeQuery(sql); 41 42 // 创建map存储表中信息 43 Map<String, String> map = new HashMap<String, String>(); 44 45 // 设置读取结果的循环控制变量,代表获取的数据的行数 46 int j = 1; 47 48 /* 49 * rs!=null说明sql语句执行查找成功,有内容返回。 rs.next()代表着集合当中还有下一个元素(一行的数据),并且读取该行的值。 50 * 如果sql查询不止一条语句,则可以用while循环取这些值 51 */ 52 while (rs != null && rs.next()) { 53 // 元组数据代表数据库查询结果中的一行,通过rsmd来获取数据的列数 54 ResultSetMetaData rsmd = rs.getMetaData(); 55 // 注意sql中的列从1开始,遍历一行数据中的每列内容,并以键值对形式存储到map中去 56 for (int i = 1; i <= rsmd.getColumnCount(); i++) { 57 // 展示的信息去除密码列和用户名列 58 if (!(rsmd.getColumnName(i).equals("pwd") || rsmd.getColumnName(i).equals("username"))) 59 // 将每一列的名称和数据作为键值对存放到map当中,将行数拼接到键里 60 map.put(rsmd.getColumnName(i) + j, rs.getString(i)); 61 } 62 System.out.println(map.toString()); 63 64 // 行数自增 65 j++; 66 } 67 // 关闭statement对象和查询结果集合对象,释放资源 68 sm.close(); 69 rs.close(); 70 return map; 71 } catch (Exception e) { 72 // TODO: handle exception 73 } 74 return null; 75 } 76 77 78 79 80 81 /** 82 * 通过查询语句验证登录结果的登录方法,如果能够查询到结果,则说明登录成功 83 * 84 * @param 登录用户名name 85 * @param 登录密码password 86 * @return 返回登录是否成功的布尔值,成功为true,失败为false 87 */ 88 public boolean Login(String name, String pwd) { 89 90 String sql = "SELECT * FROM userinfo WHERE username=‘" + name + "‘ AND pwd=‘" + pwd + "‘;"; 91 92 // 声明数据库连接状态statement对象,通过这个对象查询数据库 93 Statement sm; 94 // 设置一个变量来保存查询结果集 95 ResultSet rs = null; 96 97 try { 98 // 通过数据库连接实例化一个statement对象sm 99 sm = ct.createStatement();100 101 // 执行查询语句102 rs = sm.executeQuery(sql);103 104 // rs!=null说明sql语句执行查找成功,有内容返回,105 // 封装的方法rs.next()代表着集合当中还有下一个元素(一行的数据),并且读取该行的值。106 if (rs != null && rs.next()) {107 108 // 元组数据代表数据库查询结果中的一行。109 ResultSetMetaData rsmd = rs.getMetaData();110 111 // 声明一个map来存储一条记录中的内容112 HashMap<String, String> map = new HashMap<String, String>();113 114 // 注意sql中的列从1开始,遍历一条记录中的每列内容,并以键值对形式存储到map中去115 for (int i = 1; i <= rsmd.getColumnCount(); i++) {116 // 从第一列开始遍历一条记录中的每一列,将对应的键值对存储到map当中117 map.put(rsmd.getColumnName(i), rs.getString(i));118 }119 System.out.println(map.toString());120 // 关闭statement对象和查询结果集合对象,释放资源121 sm.close();122 rs.close();123 // 如果查询结果不为空,就返回登录成功124 return true;125 }126 // 如果查询结果为空,也要关闭对象释放资源127 sm.close();128 rs.close();129 } catch (SQLException e) {130 }131 // try建立查询失败或者查询结果为空都会执行到这里,返回false132 return false;133 }134 135 136 137 138 /**139 * 通过 存储过程 验证登录结果的登录方法,如果能够查询到结果,则说明登录成功 使用存储过程进行验证时,sql语句不再重新编译,可以防止sql注入140 * 141 * @param 登录用户名name142 * @param 登录密码password143 * @return 返回登录是否成功的布尔值,成功为true,失败为false144 */145 public boolean PLogin(String name, String pwd) {146 try {147 // 创建调用存储过程的对象,参数用?号代替,不要直接传递参数148 CallableStatement cm = ct.prepareCall("{call login(?,?)}");149 // 通过set方法传递存储过程用到的参数,1和2代表第几个参数,name和pwd代表参数值150 cm.setString(1, name);151 // cm.setInt(1, 1);152 cm.setString(2, pwd);153 // 获取查询结果154 ResultSet rs = cm.executeQuery();155 // 处理查询结果,与之前的方法一致,不再重复添加注释了156 if (rs != null && rs.next()) {157 ResultSetMetaData rsmd = rs.getMetaData();158 HashMap<String, String> map = new HashMap<String, String>();159 for (int i = 1; i <= rsmd.getColumnCount(); i++) {160 map.put(rsmd.getColumnName(i), rs.getString(i));161 }162 System.out.println(map.toString());163 cm.close();164 rs.close();165 return true;166 }167 cm.close();168 rs.close();169 } catch (SQLException e) {170 // TODO Auto-generated catch block171 // e.printStackTrace();172 }173 return false;174 }175 176 }
3、登录的后台 LoginTry.java 代码:
package com.testing.login;import java.io.IOException;import java.util.Map;import java.util.regex.Matcher;import java.util.regex.Pattern;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 com.testing.mysql.ConnectMysql;import com.testing.mysql.UseMysql;/** * Servlet implementation class LoginTry */@WebServlet("/LoginTry")public class LoginTry extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public LoginTry() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub // 返回值编码的修改 response.setContentType("text/html;charset=UTF-8"); // 收到的参数的编码修改 request.setCharacterEncoding("UTF-8"); String user = request.getParameter("loginname"); String pwd = request.getParameter("password"); LoginSample ls = new LoginSample(); Boolean result = ls.login(user, pwd); // 创建一个info信息来说明登录结果 String info = "{\"method\":\"get\","; if (result) { info += "\"status\":200,\"msg\":\"恭喜您登录成功!\""; } else { info += "\"status\":500,\"msg\":\"抱歉,您登录失败!\""; } info += "}"; // 控制台输出登录的info信息 System.out.println(info); // 接口返回信息 response.getWriter().append("get方法被调用!" + user + pwd).append(request.getContextPath()); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub // 返回值编码的修改 response.setContentType("text/html;charset=UTF-8"); // 收到的参数的编码修改 request.setCharacterEncoding("UTF-8"); String user = request.getParameter("userid"); String pwd = request.getParameter("pwds"); //声明一个数据库查询结果实例 Map<String, String> userinfo; //设置正则匹配模式,进行用户名和密码的正则过滤 String regEx = "[^a-zA-Z0-9_-]"; Pattern p = Pattern.compile(regEx); // 调用pattern对象p的mathcer方法,生成一个匹配matcher对象 Matcher m = p.matcher(user); Matcher m1 = p.matcher(pwd); //设置返回信息的变量res String res = "{"; // 判断用户名密码不为空 if (user != null && pwd != null) { // 判断长度3~16位 if (user.length() > 2 && user.length() < 17 && pwd.length() > 2 && pwd.length() < 17) { // 判断不包含特殊字符 if (!m.find() && !m1.find()) {// if (request.getSession().getAttribute("loginName") == null) { // 创建sql连接,以及实例化UseMysql类型 ConnectMysql connSql = new ConnectMysql(); UseMysql mySql = new UseMysql(connSql.conn); //使用创建的对象来调用UseMysql类中的Login(user,pwd)方法并将返回的布尔结果作为判断值 if (mySql.Login(user, pwd)) { res += "\"status\":200,\"msg\":\"恭喜您,登录成功!\"}"; userinfo = mySql.getUserInfo(user); // 在session当中记录本次登录的用户名 // request.getSession().setAttribute("loginName", user); } else { res += "\"status\":3000,\"msg\":\"用户名密码不匹配!\"}"; } // session当中有相应的loginName记录// }else {// if (request.getSession().getAttribute("loginName").equals(user)) {// res += "\"status\":3001,\"msg\":\"用户已经登录不能重复登录!\"}";// } else {// res += "\"status\":3002,\"msg\":\"已经有其他用户登录,不能重复登录!\"}";// }// } } else { res += "\"status\":3003,\"msg\":\"用户名密码不能包含特殊字符!\"}"; } } else { res += "\"status\":3004,\"msg\":\"用户名密码长度必须是3至16位!\"}"; } } else { res += "\"status\":3005,\"msg\":\"用户名密码长度不能为空!\"}"; } // 接口返回信息,返回信息中显示本次请求时的sessionID response.getWriter().append(res); }}
4、前端界面 index.html 代码:
1 <!doctype html> 2 <html> 3 <head> 4 <meta http-equiv="content-type" content="text/html" charset="utf-8"> 5 <title>zzp的网页</title> 6 7 <!--接下来引入JQuery最小版本的库文件 --> 8 <script src="jquery.min.js" type="text/javascript"></script> 9 <!-- 接下来引入自己写的js库文件 -->10 <script src="test.js" type="text/javascript"></script> 11 12 </head>13 14 15 <body >16 <h1 align="center">Hello HTML</h1>17 18 <form id="loginForm" method="post" action="./LoginTry">19 <div id="info" style="text-align:center">20 <p>请输入您的账号:</p>21 <input type="text" name="userid" placeholder="登录名" />22 <br/>23 <p>请输入您的密码:</p>24 <input type="password" name="pwds" placeholder="密码" />25 <br/><br/>26 27 <!-- 下面这一句原本是为了使用form表单的方式来调用post方法的 -->28 <!-- <input type="submit" value="开始登录"> -->29 30 <!-- 使用“登录”按钮的onclick事件来调用js文件,执行post方法的异步请求 -->31 <input type="button" onclick="javascript:loginJS()" value="登录" />32 </div>33 </form>34 35 </body>36 </html>
5、用到的js代码:
1 /** 2 * 点击登录界面中“登录”按钮会调用的js方法 3 */ 4 5 function loginJS() { 6 7 // 定义一个存放URL的变量,指定请求的接口地址 8 var AjaxURL = "http://localhost:8080/LoginInterServlet/LoginTry"; 9 10 $.ajax({11 url : AjaxURL,12 type : "post", // 采用post方法13 dataType : "json", // 请求和返回的参数格式;如果是非json格式需要使用text格式14 // 获取id=loginForm的form表单中的参数15 data : $(‘#loginForm‘).serialize(),16 17 // 当接口调用成功时,执行success中的方法,result参数指的是接口返回的信息18 success : function(result) {19 // result[***]表示的是对应的键经过 解析后的值20 // alert("status:"+result["status"]+", "+result["msg"]);21 22 //如果登录成功,将id=“info”的元素改为接口返回值中“msg”信息23 $(‘#info‘)[0].innerText=result["msg"];24 },25 26 // 当接口调用失败时,执行error中的方法27 error : function() {28 alert("服务器忙……请稍后重试!");29 }30 });31 32 }
运行验证:
结果截图:
eclipse的控制台运行后的结果截图:
数据库中数据截图: