一、基本思想
首先明确一点,在web中的request、session、application的三大容器中是不能存放arraylist<Class>类动态数组的,这些容器实质上只是一个存放Object的HashMap,你把HashMap的东西根据key取出来之后,其值根本无法如同String,int通过强制数组转换成arraylist<Class>类动态数组的,即使可以也是非常麻烦的。这些东西都是Java的基本数据结果,具体可以参见《【Java】Java中的Collections类——Java中升级版的数据结构》(点击打开链接)。当然还有一个,但page容器已经可以用脚本代替了,这里就不说了。因此问题就来了,用数据库查出来的表怎么传到前台?这里不像php能够直接输出,也不想aspx有一个数据适配器,还有一个数据源这么爽。所以三大框架就这样应运而生呢?当然,在普普通通的Servlet中,你还是利用json+ajax把整张从数据库查出的表推向前台。
JSON其实也不是什么玄虚的东西,它只是一个通用于前台后台的Map,通过key能够轻松value的东西,而且本质只是一个字符串。
例如var jsonExample={"id":"1","s":"23333"}就是一个Json,你通过jsonExample.id就等到一个1了,jsonExample.s就是23333了。
二、基本目标
下面举个例子说明在普普通通的Servlet中,如何利用json+ajax把数据库查询出来的表推向前台显示。
在网页中点击查询,马上输入一张test数据库的testtable表,
可以看到,每次点击查询,实际上从后台推来一个由JSON构成的数组。
三、制作思想
1、首先在Eclipse for javaee中搭好Servlet与JDBC的开发环境,也就是在WEB-INF\lib目录中放入网上一搜就有的javax.servlet-api-3.1.0.jar与mysql-connector-java-5.1.32.jar。web.xml里面什么都不用写,一会儿按照Servlet3.0标准去构建,按照Eclipse for javaee自动生成的就可以了,具体见《【Javaweb】Eclipse for JavaEE新建的Web工程自动生成web.xml》(点击打开链接)。在WebContent放入Jquery支持Ajax。在src写好Servlet的Model,具体见《【Servlet】根据MVC思想设计用户登陆、用户注册、修改密码系统》(点击打开链接),跟里面的dbDAO.java一模一样,具体如下:
import java.sql.*; public class dbDAO { private Connection con; // 构造函数,连接数据库 public dbDAO() throws Exception { String dburl = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useOldAliasMetadataBehavior=true"; String dbusername = "root"; String dbpassword = "root"; Class.forName("com.mysql.jdbc.Driver"); this.con = DriverManager.getConnection(dburl, dbusername, dbpassword); } // 执行查询 public ResultSet query(String sql, Object... args) throws Exception { PreparedStatement ps = con.prepareStatement(sql); for (int i = 0; i < args.length; i++) { ps.setObject(i + 1, args[i]); } return ps.executeQuery(); } // 执行插入 public boolean insert(String sql, Object... args) throws Exception { PreparedStatement ps = con.prepareStatement(sql); for (int i = 0; i < args.length; i++) { ps.setObject(i + 1, args[i]); } if (ps.executeUpdate() != 1) { return false; } return true; } // 执行修改 public boolean modify(String sql, Object... args) throws Exception { PreparedStatement ps = con.prepareStatement(sql); for (int i = 0; i < args.length; i++) { ps.setObject(i + 1, args[i]); } if (ps.executeUpdate() != 1) { return false; } return true; } // 析构函数,中断数据库的连接 protected void finalize() throws Exception { if (!con.isClosed() || con != null) { con.close(); } } }
一切搞好,整个Web工程的目录结构如下。关键是index.jsp请求ServletJson.java去查询数据库,然后ServletJson.java营造一个Json字符串推回给index.jsp。index.jsp再于自己的脚本中构建相应的节点显示到网页中。
2、先说ServletJson.java,由于dbDAO.java的存在,直接通过调用里面的query方法送条sql语句给它就可以查询了。然后通过循环构造一个JSON数组给index.jsp的javascript。Javascript中,无论是什么数组,都应该用[]表示。然后JSON就是诸如{"id":"1","s":"23333"}的东西,注意的是,key与value都要被双引号引着。无论value是数还是字符串,都要有双引号。没有双引号会出错的!在Servlet中利用输出流打印出一个Json字符串就行了,无需用到网上那些包,自己构造出Json就可以了。注意格式。
import java.io.*; import java.sql.*; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; //说明这个Servlet是没有序列号的 @SuppressWarnings("serial") //说明这个Servlet的名称是jsonRequest,其地址是/jsonRequest这与在web.xml中设置是一样的 @WebServlet(name = "jsonRequest", urlPatterns = { "/jsonRequest" }) public class ServletJson extends HttpServlet { //放置用户之间通过直接在浏览器输入地址访问这个servlet protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintStream out = new PrintStream(response.getOutputStream()); response.setContentType("text/html;charSet=utf-8"); out.print("请正常打开此页"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //把从数据库的查询结果构造一个json字符串推向前台 StringBuffer json = new StringBuffer(); json.append("["); try { dbDAO db = new dbDAO(); ResultSet rs = db.query("select * from testtable"); while (rs.next()) { json.append('{'); //注意每一个key-value对都要在引号之中,单引号或者双引号都可以 json.append("'id':").append("'").append(rs.getInt("id")).append("'").append(","); json.append("'username':").append("'") .append(rs.getString("username").trim()).append("'").append(","); json.append("'number':").append("'") .append(rs.getString("number").trim()).append("'"); json.append("},"); } } catch (Exception e) { e.printStackTrace(); } //这是为了删除最后一次循环中出现的那个逗号 json.deleteCharAt(json.length() - 1); json.append("]"); PrintStream out = new PrintStream(response.getOutputStream()); response.setContentType("text/html;charSet=utf-8"); //搞完把json打印在本Servlet上,之后前台页面读这页的内容就可以了 out.println(json.toString()); out.close(); } }
这一页主要对返回Json的字符串进行解析,注意,请求的类型是text,再用eval去把它换成json就可以了,请求类型是json是不行的,因为传过来的东西是json数组,数组,而不是json。构造的时候利用文件碎片,不懂请看《【JavaScript】利用文件碎片DocumentFragment改进兼容IE6可调可控的图片滑块》(点击打开链接)与《【JavaScript】网页节点的增删改查》(点击打开链接)技术把查询页面呈现在页面上,这样你就不用多次把节点搬到页面上,频繁地局部更新页面是不好的,拼接的时候注意先把源table节点的东西清空。
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>ServletJson</title> <!-- 注意引入jquery --> <script src="jquery-1.11.1.js"></script> </head> <body> <button onclick="ajaxSubmit()">查询</button> <table border="1" id="data"> </table> </body> </html> <script> function ajaxSubmit() { $.ajax({ type : "post", url : "jsonRequest", dataType : "text", success : function(data) { data = eval(data); //构造前先清空源节点 document.getElementById("data").innerHTML = ""; //设置一个文件碎片 var frag = document.createDocumentFragment(); //这是表头 var tr = document.createElement("tr"); tr.innerHTML = "<td>id</td><td>username</td><td>number</td>"; frag.appendChild(tr); //利用循环构造表格的每一行,把其放在文件碎片上面 for (var i = 0; i < data.length; i++) { tr = document.createElement("tr"); tr.innerHTML = "<td>" + data[i].id + "</td>" + "<td>" + data[i].username + "</td>" + "<td>" + data[i].number + "</td>"; frag.appendChild(tr); } //此时文件碎片已经是一张表了,直接放网页就可以了 document.getElementById("data").appendChild(frag); }, error : function() { alert("出错了"); } }); } </script>