Javaweb(七) - 三层架构(BaseDao)
1、BaseDao
持久层业务接口实现类的公共父类,定义了jdbc操作数据库的所有公共方法,方便子类继承;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
/**
* 持久层业务接口实现类的公共父类,定义了jdbc操作数据库的所有公共方法,方便子类继承
* @author zhukang
*
*/
public class BaseDao {
// 数据库操作对象
protected Connection conn = null;
protected PreparedStatement pstmt = null;
protected ResultSet rs = null;
/**
* 获取数据库连接,返回获取连接成功还是失败
*/
public boolean getConnection(){
try {
// 创建Properties属性对象
Properties properties = new Properties();
// 使用反射机制,读取外部配置文件
InputStream inputStream = BaseDao.class.getClassLoader().getResourceAsStream("jdbc.properties");
// 加载输入流对象,获取配置文件内容
properties.load(inputStream);
// 读取数据库连接信息
String driverClass = properties.getProperty("driverClass");
String jdbcUrl = properties.getProperty("jdbcUrl");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
// 加载驱动
Class.forName(driverClass);
// 获取数据库连接对象
conn = DriverManager.getConnection(jdbcUrl, user, password);
} catch (Exception e) {
e.printStackTrace();
// 获取连接失败
return false;
}
// 获取连接成功
return true;
}
/**
* 增删改的通用方法:只需要提供执行的SQL语句和SQL语句需要的参数,使用预处理对象
*/
public int executeUpdate(String executeSql, Object ... params){
// 定义SQL语句执行的影响行数
int row = 0;
// 获取数据库连接,如果获取失败,不执行操作
if(getConnection()){
// 公共执行增删改的处理代码
try {
// 创建预处理操作对象
pstmt = conn.prepareStatement(executeSql);
// 实现动态传参,注意: 传入的预编译SQL的?和传入的参数个数和顺序要一致,即:要保证一一对应
for (int i = 0; i < params.length; i++) {
pstmt.setObject(i + 1, params[i]);
}
// 执行增删改操作,并获取影响行数
row = pstmt.executeUpdate();
System.out.println("BaseDao增删改的SQL=>"+pstmt);
} catch (Exception e) {
e.printStackTrace();
} finally {
releaseResource(conn, pstmt, null);
}
}
// 返回影响行数
return row;
}
/**
* 查询的通用方法:只需要提供执行的SQL语句和SQL语句需要的参数,使用预处理对象
*/
public void executeSelect(String executeSql, Object ... params){
// 获取数据库连接,如果获取成功,执行查询,否则不执行
if(getConnection()){
// 公共执行查询的处理代码
try {
// 创建预处理操作对象
pstmt = conn.prepareStatement(executeSql);
// 实现动态传参,注意: 传入的预编译SQL的?和传入的参数个数和顺序要一致,即:要保证一一对应
for (int i = 0; i < params.length; i++) {
pstmt.setObject(i + 1, params[i]);
}
// 执行查询操作,并获取结果集
rs = pstmt.executeQuery();
System.out.println("BaseDao查询的SQL=>"+pstmt);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 不释放资源,因为rs要返回,关闭后,直接外层不可以使用
}
}
}
/**
* 释放数据库操作对象资源
*/
public void releaseResource(Connection conn, Statement stmt, ResultSet rs){
try {
// 手动释放
if (null != rs) {
rs.close();
}
if (null != stmt) {
stmt.close();
}
if (null != conn) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、一个 Servlet 多请求 参数 mothed
使用反射实现;
(全部查询当作条件查询的没有条件来查询会比较方便后面的操作);
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//根据请求携带的方法参数名参数,调用不同业务的处理方法
String mothedName = req.getParameter("mothed") == null ? "animes" : req.getParameter("mothed");
//利用反射,根据方法名调用指定方法
try {
Method method = getClass().getDeclaredMethod(mothedName,HttpServletRequest.class,HttpServletResponse.class);
method.setAccessible(true);
method.invoke(this, req,resp);
} catch (Exception e) {
e.printStackTrace();
}
}
//查询所有的动漫列表
protected void animes(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("======= AnimesServlet查询所有的动漫列表==========");
String aname = req.getParameter("aname");
String author = req.getParameter("author");
String cid = req.getParameter("cid");
List<Anime> animes = animeService.animeList(aname, author, cid);
String animesJson = JSON.toJSONStringWithDateFormat(animes,"yyyy-MM-dd");
System.out.println(animesJson);
System.out.println("=============================================");
resp.getWriter().print(animesJson);
}
//删除动漫
protected void delAnime(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("==============删除动漫=====================");
}
//添加动漫
protected void addAnime(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("==============添加动漫=====================");
}
//修改动漫
protected void modAnime(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("==============修改动漫=====================");
}
3、搜索 点击搜索按钮,$("form").serialize()获取参数,并条件查询
$(function(){
//页面初始化加载,主动查询列表
//查询所有的数据,就是条件查询的没有条件
showAnimeList();
//动态获取动漫数据,动态显示
function showAnimeList(){
$.getJSON("animes",$("form").serialize() ,function(data){
// 确定数据要动态显示的位置
var $tbody = $("tbody");
//如果没有数据,不能显示分页和提示暂无数据
if(data == null || data == ""){
//先清空再,显示提示信息
$tbody.empty().append("<tr align='center'><td colspan='8'>暂无数据</td></tr>");
//隐藏 tfoot
$("tfoot").hide();
//直接返回,因为没有数据,不需要拼接页面
return;
}
// 隔行变色
var count = 1;
//定义动态展示内容,如果不定义为空字符的话,一直拼接新数据
var animeCountent = "";
// 数据解析
$(data).each(function(){
// 定义颜色
var bgColor = count % 2 == 0 ? "style='background-color:#ddd;'" : "";
animeCountent +=
"<tr align='center' " + bgColor + ">"
+ "<td>" + this.id + "</td>"
+ "<td>" + this.cname + "</td>"
+ "<td>" + this.name + "</td>"
+ "<td>" + this.author + "</td>"
+ "<td>" + this.actor + "</td>"
+ "<td>" + this.produce + "</td>"
+ "<td>" + this.create_date + "</td>"
+ "<td><a href='#'>修改</a> <a href='#'>删除</a></td>"
+ "</tr>";
count++;
});
$tbody.empty().append(animeCountent);
//有数据就要展示tfoot
$("tfoot").show();
});
}
//点击搜索按钮,根据条件筛选数据
$("#searchAnimes").click(function(){
showAnimeList();
});
});
4、分页查询sql 动态拼接(apramsList)
public class AnimeDaoImpl extends BaseDao implements AnimeDao{
@Override
public List<Anime> selectAnimeList(String aname, String author, String cid) {
//查询动漫详情的SQL语句
String executeSql = "select a.id, a.cid, a.name, a.author, a.actor, a.produce, a.create_date, c.name from animes a, category c where a.cid = c.id ";
//执行查询的参数集合
//此写法弊端,如果两个或者多个参数同时有,必须不停的增加判断,添加参数
//Object[] params = new Object[]{};
//动态参数,推荐使用
List<Object> paramList = new ArrayList<Object>();
//根据不同的查询条件,拼接SQL语句和参数
//条件中有动漫名
if(null != aname && !"".equals(aname)) {
//模糊匹配
executeSql += " and a.name like concat('%',?,'%')";
paramList.add(aname);
}
//条件中有作者
if(null != author && !"".equals(author)) {
//模糊匹配
executeSql += " and a.author like concat('%',?,'%')";
paramList.add(author);
}
//条件中有类型
if(null != cid && !"0".equals(cid)) {
executeSql += " and a.cid = ?";
paramList.add(cid);
}
//定义返回动漫列表的数据集合
List<Anime> animes = new ArrayList<Anime>();
try {
// 执行查询
this.executeSelect(executeSql, paramList.toArray());
// 解析查询结果
while(rs.next()){
// 每条数据,创建一个动漫对象,存储数据
Anime anime = new Anime();
anime.setId(rs.getInt(1));
anime.setCid(rs.getInt(2));
//对动漫name结构处理
if(null != aname && !"".equals(aname)) {
//标记name
String markname = rs.getString(3).replace(aname, "<span style='color:red'>"+aname+"</span>");
anime.setName(markname);
}else {
anime.setName(rs.getString(3));
}
anime.setAuthor(rs.getString(4));
anime.setActor(rs.getString(5));
anime.setProduce(rs.getString(6));
anime.setCreate_date(rs.getDate(7));
anime.setCname(rs.getString(8));
// 将每条动漫数据对象放入集合
animes.add(anime);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭资源
this.releaseResource(conn, pstmt, rs);
}
//返回动漫集合
return animes;
}
}
5、作业总结技巧(BaseDao 页面不跳转 Ajax)
5.1 Ajax动态拼接元素及数据
5.1.1 Ajax动态添加分类数据
//$(function() jQuery标志
$(function(){
//定位z展示分类的下拉元素
var $cidSelect = $("#cid");
//获取动漫分类,动态展示
$.getJSON("categories",function(data){
//遍历返回的分类集合json集合数,动态加载分类选项
$(data).each(function(){
//alert(this.id+this.name);
$cidSelect.append("<option value='"+this.id+"'>"+this.name+"</option>");
});
});
});
5.1.2Ajax动态添加动漫数据
加载动漫数据的时候,直接考虑到模糊匹配查询,全部查询就是不带条件查询;
(这里的代码又展示了一遍,主要是提示后面的操作是基于这些代码操作的);
//$(function() jQuery标志
$(function(){
//页面初始化加载,主动查询列表
showAnimeList();
//动态获取动漫数据,动态显示
function showAnimeList(){
$.getJSON("animes",$("form").serialize() ,function(data){
// 确定数据要动态显示的位置
var $tbody = $("tbody");
//如果没有数据,不能显示分页和提示暂无数据
if(data == null || data == ""){
//先清空再,显示提示信息
$tbody.empty().append("<tr align='center'><td colspan='8'>暂无数据</td></tr>");
//隐藏 tfoot
$("tfoot").hide();
//直接返回,因为没有数据,不需要拼接页面
return;
}
// 隔行变色
var count = 1;
//定义动态展示内容,如果不定义为空字符的话,一直拼接新数据
var animeCountent = "";
// 数据解析
$(data).each(function(){
// 定义颜色
var bgColor = count % 2 == 0 ? "style='background-color:#ddd;'" : "";
animeCountent +=
"<tr align='center' " + bgColor + ">"
+ "<td>" + this.id + "</td>"
+ "<td>" + this.cname + "</td>"
+ "<td>" + this.name + "</td>"
+ "<td>" + this.author + "</td>"
+ "<td>" + this.actor + "</td>"
+ "<td>" + this.produce + "</td>"
+ "<td>" + this.create_date + "</td>"
+ "<td><a href='modAnime.jsp?id="+this.id
+"&cid="+this.cid
+"&cname="+this.cname
+"&name="+this.name
+"&author="+this.author
+"&actor="+this.actor
+"&produce="+this.produce
+"&create_date="+this.create_date+"'>修改</a> "
+ "<a class='delAnime' href='animes?mothed=delAnime&id="+this.id+"'>删除</a>"
+"</td>"
+ "</tr>";
count++;
});
$tbody.empty().append(animeCountent);
//有数据就要展示tfoot
$("tfoot").show();
});
}
//点击搜索按钮,根据条件筛选数据
$("#searchAnimes").click(function(){
showAnimeList();
});
});
5.1 标记搜索词
5.1 .2 通过SQl 的 replace 标记
没有同名字段时可以使用;
//条件中有作者
if(null != author && !"".equals(author)) {
//标记关键字 author
String markAuthor = "replace(`author`,'"+author +"',\"<span style='color:red'>"+author+"</span>\") as 'a.author'";
//标记
executeSql = executeSql.replace("a.author", markAuthor);
//模糊匹配
executeSql += " and a.author like concat('%',?,'%')";
paramList.add(author); //添加参数
}
5.1.4 通过 replace 对结果进行 标记
//对动漫name结构处理
if(null != aname && !"".equals(aname)) {
//如果有这个条件 标记name
String markname = rs.getString(3).replace(aname, "<span style='color:red'>"+aname+"</span>");
anime.setName(markname);
}else {
//没有这个条件则不需要标记
anime.setName(rs.getString(3));
}
5.2 修改 类型 选择 select
先将修改传过来的类型参数隐藏到一个input标签中,在动态获取类型的时候,JQuery获取原来的类型参数,并选择性的给option标签添加selected参数;
<%
//获取前端参数,封装到实体类,并添加到request域中,方便获取
//注意日期不要放进实体类
//直接value="<%=request.getParameter("create_date") %>" 要不然会类型不匹配
request.setAttribute("upAnimes", anime);
%>
<!-- 隐藏动漫类型 cid -->
<input type="hidden" id="mycid" class="form-control" value="${upAnimes.cid }" required>
<script type="text/javascript">
//异步获取并遍历动漫类型
$(function(){
//获取动漫分类,动态展示
$.getJSON("categories",function(data){
//定位z展示分类的下拉元素
var $cidSelect = $("#cid");
//遍历返回的分类集合json集合数,动态加载分类选项
var cid = $("#mycid").val();
$(data).each(function(){
//alert(this.id+this.name);
if(cid == this.id){
$cidSelect.append("<option value='"+this.id+"' selected>"+this.name+"</option>");
}else{
$cidSelect.append("<option value='"+this.id+"'>"+this.name+"</option>");
}
});
});
});
5.3 Ajax 拼接确认删除(动态绑定事件)
5.3.1 给动态添加的元素,添加cilck事件(无法绑定事件)
cilck无法直接给动态的元素添加事件;
//确认删除提示 错误,click事件不能动态绑定事件
$(".delAnime").click(function(){
if(!confirm("是否确认删除 ${anime.name } ")){
return false;
}
});
5.3.2 添加动态元素时直接动态添加 onClick=”return confirm(\"确认删除\")“
"<a class='delAnime' href='animes?mothed=delAnime&id="+this.id+"' onClick='return confirm(\"确认删除《"+this.name+"》?\")'>删除</a></td>"
5.3.3 $(document).on 绑定动态加载元素的事件
//动态绑定事件(当前和以后添加的元素都可以绑定)
//$(document).on 绑定动态加载子元素的事件 document是父级元素即可
$(document).on('click', '.delAnime', function(){
if(!confirm("是否确认删除 ${anime.name }")){
return false;
}
});
5.6 分页条件查询 (不需要pageSupper类)
分页条件查询,包括了一般查询,所以一个分页条件查询就够了;
前端处理分页参数;
5.6.1 参数
参数 | 说明 | 提交 |
---|---|---|
aname | 条件查询参数 | 表单提交 |
author | 条件查询参数 | 表单提交 |
cid | 条件查询参数 | 表单提交 |
pageNo | 当前页面页码 | 获取tfoot的pageNum,Ajax提交的时候拼接参数 |
pageSize | 页面大小 | 获取tfoot的pageSize,Ajax提交的时候拼接参数 |
totalCount | 数据总条数 | Ajax获取,然后填入 totalCount 中,分页请求时直接获取 |
<!-- 条件查询参数 aname author cid -->
<form action="#">
<p style="text-align: center">
名称:<input type="text" name="aname" size="15"/>
作者:<input type="text" name="author" size="15"/>
分类:<select name="cid" id="cid">
<option value="0">全部</option>
</select>
<input type="button" value = "搜索" id = "searchAnimes" />
</p>
</form>
<!-- totalCount -->
共 <span id="totalCount">5</span> 条
<!-- pageSize 和 pageNum -->
每页
<!-- <span id = "pageSize">5</span> -->
<select name="pageSize" id="pageSize">
<option value="3" selected>3</option>
<option value="5">5</option>
<option value="10">10</option>
</select>
条
当前第 <span id = "pageNum">1</span> 页 /
5.6.2 分页标签
<tfoot>
<tr>
<td colspan="8" style="height: 40px; text-align: center">
<input type="button" value="添加" id="addAnime"/>
<a href="#">首页</a> |
<a href="#"><<上一页</a> |
<a href="#">下一页>></a> |
<a href="#">尾页</a> |
共 <span id="totalCount">5</span> 条
每页
<!-- <span id = "pageSize">5</span> -->
<select name="pageSize" id="pageSize">
<option value="3" selected>3</option>
<option value="5">5</option>
<option value="10">10</option>
</select>
条
当前第 <span id = "pageNum">1</span> 页 /
共 <span id="totalPage">1</span> 页
</td>
</tr>
</tfoot>
5.6.3 数据总量函数
Ajax请求 分页查询的数据总量,并填写到页面上,方便后面分页处理
//设置数据总量 函数
function totalCount(){
//通过 不分页 的条件查询,查询出总数据量
$.getJSON("animes?mothed=animesCount",$("form").serialize() ,function(data){
//定义数据总量
var totalCount = data;
//alert(" totalCount 数据总量:"+totalCount);
//获取数据总量元素
var $totalCount = $("#totalCount");
//重置数据总量
$totalCount.text(totalCount);
});
}
5.6.4 分页处理函数 (作用类似PageSupport)
包括 上一页,下一页的隐藏处理
//分页处理函数
function pageSearch(pageSize,pageNum,totalPage){
//后去分页数据
//页面容量 (页面容量可以不操作,我是为了可以手动改变页面容量)
var $pageSize = $("#pageSize");
//当前页码
var $pageNum = $("#pageNum");
//页面总数
var $totalPage = $("#totalPage");
//重置分页数据
//页面容量 (页面容量可以不处理,因为Ajax异步的,页面不会刷新)
//$pageSize.text(pageSize);
$pageSize.val(pageSize);
//当前页码
$pageNum.text(pageNum);
//页面总数
$totalPage.text(totalPage);
//处理上一页和下一页
//上一页
if(pageNum <= 1){
$("tfoot a:eq(1)").hide();
}else{
$("tfoot a:eq(1)").show();
}
//下一页
if(pageNum >= totalPage){
$("tfoot a:eq(2)").hide();
}else{
$("tfoot a:eq(2)").show();
}
}
5.6.5 分页条件查询 动态显示数据
- 获取处理总页数
- 分页参数获取 pageNum,pageSize
- 动态拼接数据
- 处理pageSize,pageNum,totalPage
//===页面初始化加载,主动分页条件查询处理===
//分页条件查询处理
pageAnimeList();
//动态 分页 条件 获取动漫数据,动态显示
function pageAnimeList(){
//处理总页数
totalCount();
//获取分页查询的数据
//页面容量
var $pageSize = $("#pageSize");
//pageSize 用 <span> 标签
//var pageSize = $pageSize.text();
//pageSize 用 <select> 标签
var pageSize = $pageSize.val();
//当前页码
var $pageNum = $("#pageNum");
var pageNum = $pageNum.text();
//数据总数
//$.getJSON("animes",$("form").serialize() ,function(data){
//分页查询
$.getJSON("animes?mothed=pageAnimes&pageNum="+pageNum+"&pageSize="+pageSize,$("form").serialize() ,function(data){
// 确定数据要动态显示的位置
var $tbody = $("tbody");
//如果没有数据,不能显示分页和提示暂无数据
if(data == null || data == ""){
//先清空再,显示提示信息
$tbody.empty().append("<tr align='center'><td colspan='8'>暂无数据</td></tr>");
//隐藏 tfoot
$("tfoot").hide();
//直接返回,因为没有数据,不需要拼接页面
return;
}
// 隔行变色
var count = 0;
//定义动态展示内容,如果不定义为空字符的话,一直拼接新数据
var animeCountent = "";
// 数据解析
$(data).each(function(){
// 定义颜色
var bgColor = count % 2 == 1 ? "style='background-color:#ddd;'" : "";
animeCountent +=
"<tr align='center' " + bgColor + ">"
+ "<td>" + this.id + "</td>"
+ "<td>" + this.cname + "</td>"
+ "<td>" + this.name + "</td>"
+ "<td>" + this.author + "</td>"
+ "<td>" + this.actor + "</td>"
+ "<td>" + this.produce + "</td>"
+ "<td>" + this.create_date + "</td>"
+ "<td><a href='modAnime.jsp?id="+this.id
+"&cid="+this.cid
+"&cname="+this.cname
+"&name="+this.name
+"&author="+this.author
+"&actor="+this.actor
+"&produce="+this.produce
+"&create_date="+this.create_date+"'>修改</a> "
+ "<a class='delAnime' href='animes?mothed=delAnime&id="+this.id+"'>删除</a>"
+"</td>"
+ "</tr>";
count++;
});
//清空原来的tbody,添加新的数据
$tbody.empty().append(animeCountent);
//有数据就要展示tfoot
$("tfoot").show();
//分页处理
//获取总数据量 处理 页面数量
//数据总量
var $totalCount = $("#totalCount");
var totalCount = $totalCount.text();
//处理总页数
var totalPage = 1;
if((totalCount%pageSize) == 0){
//alert("totalCount="+totalCount+"pageSize"+pageSize);
totalPage = totalCount/pageSize;
}else{
//alert("totalCount="+totalCount+"pageSize"+pageSize);
totalPage = ((parseInt(totalCount/pageSize))+1);
}
//alert("处理总页数==>>totalPage==>"+totalPage);
pageSearch(pageSize,pageNum,totalPage);
});
}
//点击搜索按钮,根据条件筛选数据
$("#searchAnimes").click(function(){
//分页条件查询
pageAnimeList();
});
5.6.6 分页跳转处理
//分页跳转
//首页
$("tfoot a:eq(0)").click(function(){
$("#pageNum").text(1);
//分页条件查询
pageAnimeList();
return false;
});
// 上一页
$("tfoot a:eq(1)").click(function(){
var pageNum = parseInt($("#pageNum").text()) - 1;
$("#pageNum").text(pageNum);
//分页条件查询
pageAnimeList();
return false;
});
// 下一页
$("tfoot a:eq(2)").click(function(){
//alert("下一页");
//alert(parseInt($("#pageNum").text()) + 1);
$("#pageNum").text(parseInt($("#pageNum").text()) + 1);
//分页条件查询
pageAnimeList();
return false;
});
// 尾页
$("tfoot a:eq(3)").click(function(){
$("#pageNum").text(parseInt($("#totalPage").text()));
//分页条件查询
pageAnimeList();
return false;
});
5.6.7 修改pageSize
//修改pageSize
//select标签的change()事件, 切换选项时触发
$("#pageSize").change(function(){
//获取修改后的 currentPageSize
var pageSize = $(this).children('option:selected').val();
//修改页面大小后,再主动查询一次动漫数据
pageAnimeList();
});
5.6.8 数据总数 和 条件分页查询的 servlet
5.6.8.1 数据总数
//条件查询所有的动漫列表条数
protected void animesCount(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("======= AnimesServlet查询所有的动漫的总数量==========");
String aname = req.getParameter("aname");
String author = req.getParameter("author");
String cid = req.getParameter("cid");
int totalCount = animeService.animeListCount(aname, author, cid);
String totalCountJson = JSON.toJSONString(totalCount);
System.out.println("AnimesServlet == >animesCount=动漫总条数==>>"+totalCountJson);
System.out.println("=============================================");
resp.getWriter().print(totalCountJson);
}
5.6.8.2 分页条件查询
//分页条件查询所有的动漫
protected void pageAnimes(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("======= 分页条件查询 AnimesServlet查询所有的动漫列表==========");
//条件查询参数
String aname = req.getParameter("aname");
String author = req.getParameter("author");
String cid = req.getParameter("cid");
//分页参数
Integer pageNum = new Integer(req.getParameter("pageNum"));
Integer pageSize = new Integer(req.getParameter("pageSize"));
System.out.println("pageAnimes==> pageNum==>"+pageNum);
System.out.println("pageAnimes==> pageSize==>"+pageSize);
List<Anime> animes = animeService.PageSelectAnimeList(aname, author, cid, pageNum, pageSize);
String animesJson = JSON.toJSONStringWithDateFormat(animes,"yyyy-MM-dd");
System.out.println(animesJson);
System.out.println("=============================================");
resp.getWriter().print(animesJson);
}
5.6.8.3 多个Ajax请求注意点
多个Ajax请求,javaScript无法控制其执行顺序,有时候会出错;
一个请求拿到另外一个请求的rs中数据;(这里数据总条数取到了某条数据的id)
或第二个请求还没有从rs中取出数据,rs就被关闭(No operations allowed after statement closed.);
(另外这里还有一个特殊点,我的setvlet请求是同一个类的多个方法通过反射执行的);
这里需要将用来反射调用方法的公共 **dopost方法上锁 synchronized **;
//doPost 方法上锁,保证一次只有一个请求,就保证 一次只有一个SQL执行,一次只有一个rs,就不会数据错乱;
@Override
protected synchronized void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//根据请求携带的方法参数名参数,调用不同业务的处理方法
String mothedName = req.getParameter("mothed") == null ? "animes" : req.getParameter("mothed");
//利用反射,根据方法名调用指定方法
try {
Method method = getClass().getDeclaredMethod(mothedName,HttpServletRequest.class,HttpServletResponse.class);
method.setAccessible(true);
method.invoke(this, req,resp);
} catch (Exception e) {
e.printStackTrace();
}
}
5.7 删除
5.7.1 动态添加的a标签 绑定事件
直接带着id到后台删除;
+ "<a class='delAnime' href='animes?mothed=delAnime&id="+this.id+"'>删除</a>"
//动态绑定事件(当前和以后添加的元素都可以绑定)
//$(document).on 绑定动态加载子元素的事件
$(document).on('click', '.delAnime', function(){
if(!confirm("是否确认删除 ${anime.name }")){
return false;
}
});
5.7.2 删除成功后 提示
resp.getWriter().print("<script type='text/javascript'>alert('删除成功!!!'); location.href = 'animeList.jsp'</script>");
5.8 修改
这种方式比较的麻烦,携带的参数太多,不过也是一个方法,可以扩张一下思维;
+ "<td><a href='modAnime.jsp?id="+this.id
+"&cid="+this.cid
+"&cname="+this.cname
+"&name="+this.name
+"&author="+this.author
+"&actor="+this.actor
+"&produce="+this.produce +"&create_date="+this.create_date+"'>修改</a> "
5.9 添加
<input type="button" value="添加" id="addAnime"/>
//添加按钮处理 跳转到添加页面
$("#addAnime").click(function(){
location.href = "addAnime.jsp";
});