Ajax技术已经不算什么新鲜事了,Ajax局部刷新的文章在网上已经应有尽有,但是,这些文章有一个很严重的缺点,就是把查询出来的内容在JS不停地构造HTML内容,再把这些内容放在页面,好像自己的JS构造节点技术很牛B很熟练似的,或者认为查询出来的内容只能通过这种方法去局部刷新。导致后期大部分HTML在JavaScript脚本里面,IDE工具无法识别。现在不说Javascript熟练不熟练的问题。主要是脚本就应该是脚本,HTML就应该是HTML,混在一起根本就画面太丑没法看。一方面用框架不停地声称耦合度什么的,一方面自己就写出一堆耦合度极其恐怖的程序,根本不知道是什么心态。那么,如果把Ajax查询出来的内容放在HTML显示,尽量避免利用Javascript构造节点呢?你或许需要JQuery的load方法。下面用一个Servlet3.0的例子来说明这个东西,免得SSH杂糅太多包让人看不懂。
一、基本目标
修改数据库的表单在1.jsp,
2.jsp只是用来显示数据库的查询信息。也就是说2.jsp这是那张表格。
修改数据之后,我们只需要局部刷新2.jsp是不是?这样没这么卡是不是?
二、基本思想
Web工程的目录结构如下,ajax技术必须要jQuery,然后,Servlet3.0中必须的javax.servlet-api-3.1.0.jar,查询MySql必须的mysql-connector-java-5.1.32.jar就不说了。网上自己一搜就有了。web.xml除了jsp的基本框架以外,不用写任何东西,让Eclipse自动创建就行了《【Javaweb】Eclipse for JavaEE新建的Web工程自动生成web.xml》(点击打开链接),随后,所有Servlet直接用Servlet3.0标准配置。
然后,整个网络工程的大体流程是这样的。可能有点乱,但是配合下面的代码,应该大致能够理解的。
三、制作过程
1、首先dbDAO.java如下,这个文件在《【Servlet】根据MVC思想设计用户登陆、用户注册、修改密码系统》(点击打开链接)已经讲解过了,这里就不讲了。完全一模一样,一个字都没有改
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();
}
}
}
2、2.jsp里面就一个等待ajax查询结果填充的表格,这个ajax是该页面一载入就被执行,其查询结果等待url为jsonRequest的Servlet返回。注意引入jquery包。利用到文件碎片的插入方式,这样就不会太卡。文件碎片在《【JavaScript】利用文件碎片DocumentFragment改进兼容IE6可调可控的图片滑块》( 点击打开链接),就已经介绍过了。2.jsp这个页面被刷新,被载入,就马上显示当前testtable表的内容。
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ page import="java.util.*"%>
<!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">
<script src="jquery-1.11.1.js"></script>
<title>2</title>
</head>
<body>
<table border="1" id="data"></table>
</body>
</html>
<script>
$.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>
3、ServletJson.java也就是url为jsonRequest的Servlet。Servlet如何把查询结果构造成Json字符串返回页面的。在《【Servlet】在Servlet3.0中利用json+ajax把数据库查询出来的数据推向前台显示,无额外的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();
}
}
4、1.jsp,这个页面是整个WEB工程的核心,
首先是HTML布局如下,当然,里面有很多无关紧要的文本,主要是用来说明这些文本到头来是不会刷新的。
loadHTML是用来载入2.jsp的。相当于以前很流行,但现在被人唾弃的iframe。还有一个等待脚本载入的下来列表。
<%@ 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>1</title>
<script src="jquery-1.11.1.js"></script>
</head>
<body>
我是1.jsp的内容!
<p style="color: blue">我是不被刷新的</p>
<span style="color: red">我是不被刷新的</span>
<br /> id=
<select id="id"></select> username=
<input type="text" id="username" name="username" /> number=
<input type="text" id="number" name="number" />
<button onclick="ajaxSubmit()">修改</button>
<h1>==============以下为2.jsp的内容!====================</h1>
<div id="loadHTML"></div>
<h1>==============以上为2.jsp的内容!====================</h1>
我是1.jsp的内容!
<br />
<p style="color: blue">我是不被刷新的</p>
<span style="color: red">我是不被刷新的</span>
</body>
</html>
这个页面的脚本如下,一上来就通过load方法载入2.jsp的内容,也就是读取数据库里面的东西。然后,通过countDataBase.java这个Servlet,载入当前testtable的id列。之后,为修改按钮提供脚本,传递表达的数据什么id,username,number等给update.java这个Servlet根据此来修改数据。
<script>
$("#loadHTML").load("2.jsp");
$.ajax({
type : "post",
url : "countDataBase",
dataType : "text",
success : function(data) {
data = eval(data);
for (var i = 0; i < data.length; i++) {
option = document.createElement("option");
option.innerHTML = data[i].id;
option.value = data[i].id;
document.getElementById("id").appendChild(option);
}
},
error : function() {
alert("出错了");
}
});
function ajaxSubmit() {
var id = $("#id").val();
var username = $("#username").val();
var number = $("#number").val();
$.ajax({
type : "post",
url : "update",
data : {
id : id,
username : username,
number : number,
},
success : function(data) {
$("#loadHTML").load("2.jsp");
},
error : function() {
alert("出错了");
}
});
}
</script>
5、先说countDataBase.java这个Servlet,其实也没有什么好说的,就是把数据库的id列查询出来,用ajax退回给1.jsp
import java.io.*;
import java.sql.ResultSet;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
@SuppressWarnings("serial")
@WebServlet(name = "countDataBase", urlPatterns = { "/countDataBase" })
public class countDataBase extends HttpServlet {
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("},");
}
} 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();
}
}
6、最后是update.java这个Servlet,这个更没有东西说,设置好编码,防止中文乱码,根据1.jsp传递过来的数据,修改数据库相应的列,就是如此地简单。不懂也没关系,可以看回我之前的《【Servlet】根据MVC思想设计用户登陆、用户注册、修改密码系统》( 点击打开链接)
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
@SuppressWarnings("serial")
@WebServlet(name = "update", urlPatterns = { "/update" })
public class update extends HttpServlet {
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 {
request.setCharacterEncoding("utf-8");
String id=(String)request.getParameter("id");
String username=(String)request.getParameter("username");
String number=(String)request.getParameter("number");
try {
dbDAO db = new dbDAO();
db.modify("update testtable set username=? where id=?",username,id);
db.modify("update testtable set number=? where id=?",number,id);
} catch (Exception e) {
e.printStackTrace();
}
PrintStream out = new PrintStream(response.getOutputStream());
response.setContentType("text/html;charSet=utf-8");
//搞完把json打印在本Servlet上,之后前台页面读这页的内容就可以了
out.println("修改成功");
out.close();
}
}
四、总结与展望
大家可以看到1.jsp中的脚本中根本没有过多的html代码,数据库查询出来的东西,只需要在2.jsp进行简单的构造就可以,利用一个简单的load方法,把2.jsp读进来。不要直接在1.jsp的脚本中构建一个表格。这达到了html代码与javascript的代码分离的目的,同时每一次修改只是刷新一个div的内容,到达了局部刷新的效果。以后要修改数据库查询的内容。比如2.jsp中的那个表格的样式,你就不用再脚本中修改。直接该2.jsp集合。2.jsp的作用不是正如以前iframe时代那些banner.html,footer.html……吗?而1.jsp不是正是如同以前充满iframe标签的主页面吗?