第八章AJAX(2)
第 15 节15-AJAX案例:无刷新登录
第 16-18 节16-AJAX案例:文章无刷新评论1-3
第 19-25 节19-AJAX案例:学生增删改查1 -7
第 26 节26-如何在AJAX中重定向
第 27 节27-AJAX显示loading避免用户等不急
第 28 节28-JQuery的AJAX全局事件
【第 15 节15-AJAX案例:无刷新登录】
案例练习
案例:ajax登录、带验证码。
案例:新闻的无刷新评论。刚进入界面的时候评论也是页面显示后才加载,“正在加载评论”。进入页面的时候AJAX加载已有评论。用户在评论文本框中输入文本,点击评论按钮,向服务器发出ajax请求,将用户的评论内容发给服务器,如果服务器返回“插入成功”的消息则将用户的评论动态添加到现有表格中,如果用户评论中含有“TMD”、“去死”等不良信息则提示用户“请文明用语”。
【Login.jsp】
<%@ 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>登录</title>
<script type="text/javascript" src="jquery-1.8.3.js"></script>
<script type="text/javascript">
//刷新验证码
var refreshYZM = function(){
$("#imgYZM").attr("src","login?action=yzm&a="+Math.random());
};
//写AJAX时候推荐顺序:请求、处理、响应
var loginSubmitSuccess=function(data)
{
if(data.errorCode=="yzmError")
{
$("#msg").text("验证码错误");
refreshYZM();
}
else if(data.errorCode=="userNotFound")
{
$("#msg").text("用户名不存在");
refreshYZM();
}
else if(data.errorCode=="passwordError")
{
$("#msg").text("密码错误");
refreshYZM();
}
else if(data.errorCode=="ok")
{
$("#msg").text("登录成功");
location.href="index.jsp";//todo
}
}
$(function(){
refreshYZM();//进入页面的时候也刷新一下验证码,防止有的浏览器可能会缓存
$("#imgYZM").click(refreshYZM);
$("#btnLogin").click(function(){
var username1 = $("#username").val();
var password = $("#password").val();
var yzm = $("#yzm").val();
//todo: 三个文本框必填
$.ajax({type:"POST",dataType:"json",url:"login",
data:{action:"loginSubmit",username:username1,password:password,yzm:yzm},
success:loginSubmitSuccess,
error:function(){alert("登录AJAX出错");}
});
});
});
</script>
</head>
<body>
用户名:<input type="text" id="username"/><br/>
密码:<input type="password" id="password"/><br/>
验证码:<input type="text" id="yzm"/><img src="login?action=yzm" id="imgYZM"/><br/>
<input type="button" id="btnLogin" value="登录"/>
<span id="msg"></span>
</body>
</html>
【LoginServlet.java】
package com.rupeng.web6;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
public class LoginServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String action = req.getParameter("action");
if(RupengUtils.isNullOrEmpty(action))
{
req.getRequestDispatcher("/Login.jsp").forward(req, resp);
}
else if(action.equals("yzm"))
{
resp.setContentType("image/jpeg");
BufferedImage img = new BufferedImage(100, 30,
BufferedImage.TYPE_3BYTE_BGR);
Graphics2D g = img.createGraphics();
g.setColor(Color.red);
g.setFont(new Font("宋体", Font.BOLD, 30));
String randNum = createRandNum();
req.getSession().setAttribute("YZM", randNum);//把生成的验证码放到Session中
//不能放到Cookie等浏览器端可以接触的地方。必须放到服务器中
g.drawString(randNum, 0, 25);
g.dispose();
ImageIO.write(img, "JPEG", resp.getOutputStream());
}
else if(action.equals("loginSubmit"))
{
String username = RupengUtils.getParameter(req, "username");
String password = req.getParameter("password");
String yzm = req.getParameter("yzm");
AjaxResult result = new AjaxResult();
String yzmInSession = (String)req.getSession().getAttribute("YZM");
if(!yzm.equals(yzmInSession))
{
result.setErrorCode("yzmError");//验证码错误
}
else
{
UserInfo user = UserDAO.getByUserName(username);
if(user==null)
{
result.setErrorCode("userNotFound");//用户名不存在
}
else if(!user.getPassword().equals(password))
{
result.setErrorCode("passwordError");//密码错误
}
else
{
result.setErrorCode("ok");
}
}
Gson gson = new Gson();
String json = gson.toJson(result);
resp.getWriter().print(json);
}
}
static String createRandNum()
{
char[] nums = { 'a', 'c', 'd', 'e', 'f', 'h', 'k', 'm', 'n', 's', 't',
'w', 'x', 'y', 'z', '2', '3', '4', '5', '7', '8' };
String randNum = "";
Random rand = new Random(System.currentTimeMillis());
for (int i = 0; i <= 4; i++)
{
randNum += nums[rand.nextInt(nums.length)];
}
return randNum;
}
}
【第 16-18 节16-AJAX案例:文章无刷新评论1-3】
【建立数据库表】
T_Articles字段(Id,Title,Content)
T_ArticleComments(Id,ArticleId(外键),Content,PostDateTime,)
【ArticleDAO.java】
package com.rupeng.web6;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ArticleDAO
{
public ArticleInfo getById(int id)
{
ResultSet rs = null;
try
{
rs = JdbcUtils.executeQuery("select * from T_Articles where Id=?",
id);
if (rs.next())
{
ArticleInfo info = new ArticleInfo();
info.setId(rs.getInt("Id"));
info.setContent(rs.getString("Content"));
info.setTitle(rs.getString("Title"));
return info;
} else
{
return null;
}
} catch (SQLException e)
{
throw new RuntimeException(e);
} finally
{
JdbcUtils.closeAll(rs);
}
}
}
【ArticleInfo.java】
package com.rupeng.web6;
public class ArticleInfo
{
private int id;
private String title;
private String content;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
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;
}
}
【ArticleCommentDAO.java】
package com.rupeng.web6;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class ArticleCommentDAO
{
/**
* 获得主键为aId的文章的所有评论
* @param aId
* @return
*/
public List<ArticleCommentInfo> getByArticleId(int aId)
{
ResultSet rs = null;
try
{
rs = JdbcUtils.executeQuery("select * from T_ArticleComments where ArticleId=?", aId);
List<ArticleCommentInfo> list = new ArrayList<ArticleCommentInfo> ();
while(rs.next())
{
ArticleCommentInfo comment = new ArticleCommentInfo();
comment.setArticleId(aId);
comment.setContent(rs.getString("Content"));
comment.setId(rs.getInt("Id"));
comment.setPostDateTime(rs.getDate("PostDateTime"));
list.add(comment);
}
return list;
} catch (SQLException e)
{
throw new RuntimeException(e);
}
finally
{
JdbcUtils.closeAll(rs);
}
}
/**
* 发表评论
* @param aId 文章id
* @param content 评论的内容
*/
public void postComment(int aId,String content)
{
try
{
JdbcUtils.executeUpdate("insert into T_ArticleComments(ArticleId,Content,PostDateTime) values(?,?,now())",
aId,content);
} catch (SQLException e)
{
throw new RuntimeException(e);
}
}
}
【ArticleCommentInfo.java】
package com.rupeng.web6;
import java.sql.Date;
public class ArticleCommentInfo
{
private int id;
private int articleId;
private String content;
private Date postDateTime;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public int getArticleId()
{
return articleId;
}
public void setArticleId(int articleId)
{
this.articleId = articleId;
}
public String getContent()
{
return content;
}
public void setContent(String content)
{
this.content = content;
}
public Date getPostDateTime()
{
return postDateTime;
}
public void setPostDateTime(Date postDate)
{
this.postDateTime = postDate;
}
}
【ViewArticle.jsp】
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!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><c:out value="${model.title}"/></title>
<script type="text/javascript" src="jquery-1.8.3.js"></script>
<script type="text/javascript">
var loadCommentsSuccess = function(obj)
{
$("#ulComments").html("");//移除旧的评论
for(var i=0;i<obj.data.length;i++)
{
var comment = obj.data[i];
$("#ulComments").append($("<li>"+comment.postDateTime+":"+comment.content+"</li>"));
}
}
//加载评论
var loadComments = function()
{
var aId=${model.id};
$.ajax({type:"POST",dataType:"json",url:"article",
data:{action:"loadComments",aId:aId},
success:loadCommentsSuccess,
error:function(){alert("评论加载失败!");}
});
}
var postCommentSuccess = function(data){
if(data.errorCode=="ok")
{
alert("评论发表成功");
$("#txtComment").val("");//清空文本框
loadComments();//刷新加载评论
}
else if(data.errorCode=="diryWord")
{
alert("请文明用语!");
}
}
$(function(){
loadComments();//页面打开的时候加载评论
$("#btnComment").click(function(){
var content = $("#txtComment").val();
if(content=="")
{
alert("请输入评论内容 ");
return;
}
var aId = "${model.id}";//当前文章id,通过JSTL动态输出到JS中
$.ajax({type:"POST",dataType:"json",url:"article",
data:{action:"postComment",content:content,aId:aId},
success:postCommentSuccess,
error:function(){alert("发表评论AJAX错误");}
});
});
});
</script>
</head>
<body>
<h1><c:out value="${model.title}"/></h1>
<c:out value="${model.content}"/>
<p>
<textarea rows="5" cols="50" id="txtComment">
</textarea>
<input type="button" id="btnComment" value="发布评论"/>
</p>
<ul id="ulComments">
</ul>
</body>
</html>
【ArticleServlet.java】
package com.rupeng.web6;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ArticleServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String action = req.getParameter("action");
if(action.equals("view"))
{
int id = Integer.parseInt(req.getParameter("id"));
ArticleInfo article = new ArticleDAO().getById(id);
if(article==null)
{
req.setAttribute("msg", "指定id的文章不存在");
req.getRequestDispatcher("/Error.jsp").forward(req, resp);
}
else
{
req.setAttribute("model", article);
req.getRequestDispatcher("/ViewArticle.jsp").forward(req, resp);
}
}
else if(action.equals("postComment"))
{
//AJAX不需要进行乱码处理了
String content = req.getParameter("content");//RupengUtils.getParameter(req, "content");
AjaxResult result = new AjaxResult();
if(content.contains("他妈的")||content.contains("去死"))
{
result.setErrorCode("diryWord");//脏话
}
else
{
Integer aId = Integer.parseInt(req.getParameter("aId"));
new ArticleCommentDAO().postComment(aId, content);
result.setErrorCode("ok");
}
resp.getWriter().print(result.toString());
}
else if(action.equals("loadComments"))
{
resp.setContentType("application/json;charset=UTF-8");
resp.setCharacterEncoding("UTF-8");//别忘了设置编码
int aId = Integer.parseInt(req.getParameter("aId"));
List<ArticleCommentInfo> list = new ArticleCommentDAO().getByArticleId(aId);
AjaxResult result = new AjaxResult();
result.setErrorCode("ok");
result.setData(list);
resp.getWriter().print(result.toString());
}
}
}
【CommentInfo.java】
package com.rupeng.web6;
import java.sql.Date;
public class CommentInfo
{
private int id;
private Date createDateTime;
private String message;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public Date getCreateDateTime()
{
return createDateTime;
}
public void setCreateDateTime(Date createDateTime)
{
this.createDateTime = createDateTime;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
}
【CommentDAO.java】
package com.rupeng.web6;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
public class CommentDAO
{
public List<CommentInfo> getAll()
{
List<CommentInfo> list = new LinkedList<CommentInfo>();
ResultSet rs = null;
try
{
rs = JdbcUtils.executeQuery("select * from T_Comments");
while (rs.next())
{
CommentInfo comment = new CommentInfo();
comment.setId(rs.getInt("Id"));
comment.setCreateDateTime(rs.getDate("CreateDateTime"));
comment.setMessage(rs.getString("Message"));
list.add(comment);
}
return list;
} catch (SQLException e)
{
throw new RuntimeException(e);
}
}
public void addnew(String message)
{
try
{
JdbcUtils.executeUpdate(
"Insert into T_Comments(CreateDateTime,Message) values(now(),?)",
message);
} catch (SQLException e)
{
throw new RuntimeException(e);
}
}
}
【第 26 节26-如何在AJAX中重定向】
AJAX通用原则:一般不要在AJAX服务器端重定向,如果需要重定向,那么需要服务器端把地址发给浏览器,在浏览器端通过JS重定向。
【Ajax1Servlet.java】
//resp.sendRedirect("index.jsp");//不能直接这样,传递给浏览器的是html页面
只能在服务器中{errorCode:"redirect",data:"index.jsp"}传递json对象
在js中location.href=obj.data;
【第 27 节27-AJAX显示loading避免用户等不急】
【student.jsp】
<%@ 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>学生管理</title>
<style type="text/css" >
#dialog{position: absolute;
top: 0;
left: 0;
right:0;
bottom:0;
width:100%;
height:100%;
background-color: #8FB0D1;
-moz-opacity: 0.8;
opacity:0.8;
z-index:1001;
filter: alpha(opacity=40);}
</style>
<script type="text/javascript" src="jquery-1.8.3.js"></script>
<script type="text/javascript">
var addnewSubmitSuccess = function(obj)
{
//$("#dialog").hide();//隐藏“loading”遮罩层
if(obj.errorCode=="error")
{
alert("保存出错:"+obj.data);
}
else if(obj.errorCode=="ok")
{
alert("保存成功");
reloadData();//重新数据列表
$("#divAddNew").hide();//隐藏"新增"的层
}
}
$("#btnSave").click(function(){
//todo:检查所有字段都填写了
var name = $("#name").val();
var gender = $("#gender").val();
var birthDay = $("#birthDay").val();
var classId = $("#classId").val();
var teChangSheng = $("#teChangSheng").attr("checked")=="checked";
var minZuId = $("#minZuId").val();
//$("#dialog").show();//显示“loading”遮罩层
$.ajax({type:"POST",dataType:"json",url:"student",
data:{action:"addnewSubmit",name:name,gender:gender,birthDay:birthDay,classId:classId,teChangSheng:teChangSheng,minZuId:minZuId},
success:addnewSubmitSuccess,
error:function(){$("#dialog").hide();alert("保存AJAX请求失败");}
});
});
});
</script>
</head>
<body>
<div id="dialog" style="display:none">
<img src="loading.gif"/>
</div>
<input type="button" value="保存" id="btnEditSave"/>
<input type="button" value="取消" id="btnCancelEdit"/>
</div>
</body>
</html>
【第 28 节28-JQuery的AJAX全局事件】
全局事件:
1)全局Loading的显示,避免用户焦急的重复点击(服务端加上延迟)
$("body").bind("ajaxSend",function () {
//显示Loading
}).bind("ajaxComplete",function () {
//隐藏loading
});
2)、 ajaxError 全局错误处理
//$("body").bind("ajaxSend",function(){alert("ajaxSend");});//页面中任何ajax请求发起之前ajaxSend都会触发
//$("body").bind("ajaxComplete",function(){alert("ajaxComplete");});//页面中任何ajax请求处理完成后,ajaxComplete都会触发
$("body").bind("ajaxSend",function(){$("#dialog").show();});//ajax请求之前显示遮罩层
$("body").bind("ajaxComplete",function(){$("#dialog").hide();});//ajax请求完成后隐藏遮罩层
$("body").bind("ajaxError",function(){alert("服务器处理失败AJAX");});