昨天的商品列表基础上进行:
1添加
仍然先从sql语句开始:
insert into tb_product(prod_id,prod_name,prod_price,prod_img,prod_desc) VALUE ('xxxx00001','test',35,'test','test')
再查询:SELECT * from tb_product tp
表中多了一条记录。
①.后端
在ProdDao里增加方法:
//添加商品 传入商品对象,返回执行成功的记录数 Integer addProduct(Product insertProd);
在ProdDaoImpl里实现该方法:
@Override public Integer addProduct(Product insertProd) { Connection conn = DBHelper.getConn(); String sql = "insert into tb_product(prod_id,prod_name,prod_price,prod_img,prod_desc) values (?,?,?,?,?) "; PreparedStatement preparedStatement = null; ResultSet resultSet = null; Integer resNum = 0; System.out.println(sql); try { //防止注入攻击 preparedStatement = conn.prepareStatement(sql); preparedStatement.setString(1,insertProd.getProdId()); preparedStatement.setString(2,insertProd.getProdName()); preparedStatement.setDouble(3,insertProd.getProdPrice()); preparedStatement.setString(4,insertProd.getProdImg()); preparedStatement.setString(5,insertProd.getProdDesc()); resNum = preparedStatement.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { DBHelper.CloseConn(conn,null,preparedStatement,resultSet); } return resNum; }
在Mytest:
public class MyTest { public static void main(String[] args) { ProdDao prodDao = new ProdDaoImpl(); Product insertProd = new Product("test123","test123",123d,"test123","test123"); Integer integer = prodDao.addProduct(insertProd); System.out.println(integer); } }
测试结果:insert into tb_product(prod_id,prod_name,prod_price,prod_img,prod_desc) values (?,?,?,?,?)
1
数据库刷新,记录也增加了。
在ProdService:
//添加商品 传入商品对象,返回执行成功的记录数 Integer addProduct(Product insertProd);
在ProdServiceImpl:
@Override public Integer addProduct(Product insertProd) { ProdDao pd = new ProdDaoImpl(); return pd.addProduct(insertProd); }
在controller包下新建AddProdServlet,准备做添加服务接口:
@WebServlet("/addProd") public class AddProdServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /* * * 查询商品信息服务接口 * 请求地址 /day6/addProd * 请求参数 prodid 商品编号 * prodname 商品名称 * prodprice 商品价格 * prodimg 商品图片 * proddesc 商品描述 * 请求方式 get/post * 响应数据格式 json * 响应数据实例 * {"retCode":10000,"retMsg":"操作成功"} * {"retCode":10005,"retMsg":"操作失败"} * * * */ /*接收参数 转换格式 封装对象*/ req.setCharacterEncoding("utf-8"); String prodId = req.getParameter("prodid"); String prodName = req.getParameter("prodname"); String prodPriceStr = req.getParameter("prodprice"); String prodImg = req.getParameter("prodimg"); String prodDesc = req.getParameter("proddesc"); //需要格式转换的固定写法 Double prodPrice = 0d; if(prodPriceStr != null && "".equals(prodPriceStr)){ prodPrice = Double.parseDouble(prodPriceStr); } Product insertProd = new Product(prodId,prodName,prodPrice,prodImg,prodDesc); /* * 调用业务逻辑代码 * */ ProdService ps = new ProdServiceImpl(); Integer resNum = ps.addProduct(insertProd); /* * 返回数据 * * */ ReturnEntity re = new ReturnEntity(); if(resNum>0){ re.setRetCode(ReturnCode.OPT_SUCCESS.getCode()); re.setRetMsg(ReturnCode.OPT_SUCCESS.getMsg()); }else{ re.setRetCode(ReturnCode.OPT_FAILED.getCode()); re.setRetMsg(ReturnCode.OPT_FAILED.getMsg()); } resp.setContentType("application/json;charset=utf-8"); PrintWriter writer = resp.getWriter(); writer.print(JSON.toJSONString(re)); writer.flush(); writer.close(); } }
测试:这里使用一个新的工具postman,可以模拟http请求,但可将用例保存起来,用起来方便。
双击就自动安装好,然后跳过。
进入页面,New,Collect。相当于一个目录,是测试用例的集合。可起名(myreqs),可写注释(测试案例1)。
再new,Request。 起名(testAddProd),注释(测试添加商品案例),然后选择将测试案例放在哪个目录。
在idea重新部署,运行,在该工具点击send,下面出现返回的数据,可改格式。
{ "retCode": 10000, "retMsg": "操作成功" }
最后数据库再检查数据是否进去。
②.回到前端
一般有两种处理方式:
1.再准备一个添加页面,查询页面跳到添加页面,一般是准备一个按钮或超链接跳转。用户在添加页面添加完,发一个ajax请求去后台。根据响应的结果,展示处理结果。处理结果是另一个页面,由添加页面跳转过去。最后展示页面自动跳转回查询页面。
2.查询页面做一些弹出框,添加结束,发ajax请求,将结果直接展示在当前页面,并且弹出框关闭,最后刷新数据。
1.第一种策略
先在showProd.html中增加添加按钮:
<body> <div class="mydiv"> <form class="form-inline"> <div class="form-group"> <label for="prodid">商品编号</label> <input type="text" class="form-control" id="prodid" placeholder="prodid"> </div> <div class="form-group"> <label for="prodname">商品名称</label> <input type="email" class="form-control" id="prodname" placeholder="prodname"> </div> //添加查询按钮 <button id="queryBtn" type="button" class="btn btn-primary">查询</button> <a href="/day6/addProd.html" class="btn btn-success">添加</a> </form>
其他不变。
新建addProd.html
点击查询页面的添加按钮,跳转到添加页面,在添加页面输入信息,想要的效果是点击保存,发送ajax请求,调用保存的服务接口。
同时,不管成功失败都给用户展示一下结果,一个成功页面,一个失败页面。
新建web.pages.common包,在包下新建failed.html和success.html
addProd.html代码如下:
<head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" type="text/css" href="/day6/css/bootstrap.css"/> <script src="/day6/js/jquery-3.6.0.js" type="text/javascript" charset="utf-8"></script> <script src="/day6/js/bootstrap.js" type="text/javascript" charset="utf-8"></script> <style> .mydiv{ border: 1px solid gray; padding: 50px; width: 70%; height: 800px; margin: 50px auto; border-radius: 5%; } .mydiv img{ width:80px ; height:80px ; } </style> </head> <body> <div class="mydiv"> <form id="myform"> <div class="form-group"> <label for="prodid">商品编号</label> <input type="text" class="form-control" id="prodid" name="prodid" placeholder="prodid"> </div> <div class="form-group"> <label for="prodname">商品名称</label> <input type="email" class="form-control" id="prodname" name="prodname" placeholder="prodname"> </div> <div class="form-group"> <label for="prodprice">商品单价</label> <input type="text" class="form-control" id="prodprice" name="prodprice" placeholder="prodprice"> </div> <div class="form-group"> <label for="prodimg">图片地址</label> <input type="text" class="form-control" id="prodimg" name="prodimg" placeholder="prodimg"> </div> <div class="form-group"> <label for="proddesc">商品描述信息</label> <input type="text" class="form-control" id="proddesc" name="proddesc" placeholder="proddesc"> </div> <button id="addBtn" type="button" class="btn btn-primary">保存</button> </form> </div> </body> <script> /* * * * * * 查询商品信息服务接口 * 请求地址 /day6/addProd * 请求参数 prodid * prodname * prodprice * prodimg * proddesc * * 请求方式 get/post * 响应数据格式 json * 响应数据实例 * 没有数据: * {"retCode":10000,"retMsg":"操作成功"} * {"retCode":10005,"retMsg":"操作失败"} * */ $("#addBtn").click(function(){ var insertParams = $("#myform").serialize(); //serialize()格式化键值对,前提form里的表单元素要有name属性 $.post("/day6/addProd",insertParams,function(data){ console.log(data) if(data.retCode==10000){ location.href = "day6/pages/common/success.html"; }else if (data.retCode==10005){ location.href = "day6/pages/common/failed.html"; } },"json") }) </script>
failed.html代码如下:
<html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 操作失败 请联系管理员!!!!! </body> <script> setTimeout(function(){ location.href="../showProd.html"; },2000); </script> </html>
success.html代码如下:
<html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 执行成功!!!! </body> <script> setTimeout(function(){ location.href="../showProd.html"; },2000); </script> </html>
效果如下:
访问:http://localhost:8080/day6/pages/showProd.html 在出现 的查询页面点击添加按钮
跳转到:http://localhost:8080/day6/pages/addProd.html 在出现的添加页面将商品相关信息填写完,点击保存按钮。成功则跳转到成功页面,并显示执行成功!!!! 失败则跳转到失败页面,并展示操作失败 请联系管理员!!!!!
2.第二种策略
所有的功能都放在一个页面。更常见。
此时所有的代码都在showProd.html里:
用到bootstrap里的模态框(弹出框)
先做添加商品的弹出页面(id为防止重名,加了后缀Add)
<body> <div class="mydiv"> <form class="form-inline"> <div class="form-group"> <label for="prodid">商品编号</label> <input type="text" class="form-control" id="prodid" placeholder="prodid"> </div> <div class="form-group"> <label for="prodname">商品名称</label> <input type="email" class="form-control" id="prodname" placeholder="prodname"> </div> <button id="queryBtn" type="button" class="btn btn-primary">查询</button> <!--<a href="/day6/pages/addProd.html" class="btn btn-success">添加</a>--> <!-- Button trigger modal 这是添加的按钮,点击触发弹出框--> <button type="button" class="btn btn-success " data-toggle="modal" data-target="#addModal"> 添加 </button> </form> <br/> <table class="table"> <tr> <th>商品编号</th> <th>商品信息</th> <th>单价</th> <th>描述信息</th> </tr> <tbody id="mainData"> </tbody> </table> <button class="btn btn-default prevBtn">上一页</button> <button class="btn btn-default nextBtn">下一页</button> 当前第 <span id="pageSpan"></span> 页;总共 <span id="totalPageSpan"></span> 页 每页显示 <span id="pageSizeSpan"></span> 条记录 </div> <!-- Modal 弹出的界面--> <div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">添加商品</h4> </div> <div class="modal-body"> <form id="myform"> <div class="form-group"> <label for="prodid">商品编号</label> <input type="text" class="form-control" id="prodidAdd" name="prodid" placeholder="prodid"> </div> <div class="form-group"> <label for="prodname">商品名称</label> <input type="email" class="form-control" id="prodnameAdd" name="prodname" placeholder="prodname"> </div> <div class="form-group"> <label for="prodpriceAdd">商品单价</label> <input type="text" class="form-control" id="prodpriceAdd" name="prodprice" placeholder="prodprice"> </div> <div class="form-group"> <label for="prodimgAdd">图片地址</label> <input type="text" class="form-control" id="prodimgAdd" name="prodimg" placeholder="prodimg"> </div> <div class="form-group"> <label for="proddescAdd">商品描述信息</label> <input type="text" class="form-control" id="proddescAdd" name="proddesc" placeholder="proddesc"> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button> <button type="button" class="btn btn-primary" data-dismiss="modal">保存</button> </div> </div> </div> </div> </body>
接下来,弹出的添加界面输入商品信息,点击保存按钮后,保存数据。
在保存按钮增加id属性:
<button id="addSubmitBtn" type="button" class="btn btn-primary" data-dismiss="modal">保存</button>
在script标签增加事件,要做的事:将form里的键值对抓出来,调用添加服务接口。
但响应的处理不同(给用户展示操作成功失败的信息),不往其他页面跳转,这里用警告框(有x可关闭)。
此时就需要在页面加一个div,去定位,漂浮在其它元素上,里面没有东西,需要展示结果时将警告框填入。
给div加样式:
定位属性想要控制在指定位置出现,并脱离文档流,用绝对或者固定定位,之后加上偏移。
样式上做一些弹出框,希望弹出框在正中间,加上left:50%;之后是左边在正中间,不是中线在正中间,想让整体在中间,需要弹出框左移自己框的一半。
警告框关闭后,应该能自己刷新数据,将刚才新增的数据加在查询页面,实际就是再掉调一次查询功能。
代码如下:
<style> <--以前的代码--> .showResPanel{ position: absolute; top: 30%; left: 50%; } .myalert{ width:300px; height: 150px; margin-left:-150px; } </style> <body> <--之前的代码--> <div class="showResPanel"> </div> </body> <script> //之前的代码不动 $("#addSubmitBtn").click(function () { var insertParams = $("#myform").serialize(); //serialize()格式化键值对,前提form里的表单元素要有name属性 $.post("/day6/addProd",insertParams,function(data){ console.log(data) //展示结果 var alertcls = ""; if(data.retCode==10000){ alertcls = "alert-success"; }else if (data.retCode==10005){ alertcls = "alert-danger"; } var mycontent = '<div class="myalert alert '+alertcls+' alert-dismissible fade in" role="alert">' + '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' + '<h4>操作结果</h4>' + '<p>'+data.retMsg+'</p>' + '</div>' $(".showResPanel").html(mycontent); //刷新数据 重新查询table数据 var params = {"prodid":$("#prodid").val(),"prodname":$("#prodname").val(),"page":page}; queryData(params); },"json") }) </script>
不管哪种策略,都要准备一组添加数据的框,然后通过ajax请求,把框里的数据发给后台,调用添加的服务接口,根据后台反馈的成功或者失败,展示操作的结果。最后把数据刷新出来。
2.合并servlet
做完查询和添加,还剩修改和删除。
首先准备两个服务接口。最终一个商品写了四个服务接口,很麻烦。 故这里将和商品相关的服务接口都写在一个类里。
官方给出的解决方案:在servlet重写的service方法里,通过if-else根据请求方式的不同去分段。
故,我们也可以直接重写get,post等请求方式,get用来取数据,put做添加,post做修改,delete做删除,这些在http协议有。但,服务接口太多会不够用。
我们也可以在请求里多传入一个参数,该参数指明具体做哪个操作,即/day6/ajaxProd?doWhat=addProd。if-else根据操作的不同去分段。弊端是很多地方需要拼参数,代码的结构不好看。
还有一种处理方案:
请求地址是/day6/ajaxProd/addProd 或者 /day6/ajaxProd/editProd 的形式。
多个不同的请求都想进入同一个servlet,在servlet地址的配置上也可使用通配符*,即
/ajaxProd/*
如何读取请求地址:
req.getServletPath(); //获取的是"/ajaxProd",会忽略*部分 req.getRequestURI(); //获取当次请求地址 /day6/ajaxProd/add req.getRequestURL(); //获取当次请求的完整的地址 http://localhost:8080/day6/ajaxProd/add
截取最后一部分,用req.getRequestURI()即可。
代码如下:
@WebServlet("/ajaxProd/*") public class AjaxProdServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //读取请求地址最后一部分,拿到方法名 String requestURI = req.getRequestURI(); String myMethodName = requestURI.substring(requestURI.lastIndexOf("/") + 1); try { //拿到方法名,想让方法名去执行,需要反射.反射获取的是public修饰的方法 //通过当前的类型获取定义出的方法。 Method myMethodName1 = this.getClass().getDeclaredMethod(myMethodName, HttpServletRequest.class, HttpServletResponse.class); //invoke()去执行该方法对象,参数是用哪个实例对象调该方法,是当前servlet实例对象调用,用this。还要传入指定的参数,是定义方法对象时的 //两个类型参数 Object invoke = myMethodName1.invoke(this, req, resp); /*//如果不用反射,没有this.myMethodName()!!!只能if-else if("addProd".equals(myMethodName)){ this.addProd(req,resp); }*/ } catch (NoSuchMethodException e) { //没有指定的方法,比如/day6/ajaxProd/test,类里没有test方法,就会报该异常 //没有指定的方法,对于请求而言,实质就是没有对应的服务器处理,告诉它404会更好,Tomcat里有该功能 resp.sendError(404); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } public void addProd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /* * * 查询商品信息服务接口 * 请求地址 /day6/addProd * 请求参数 prodid 商品编号 * prodname 商品名称 * prodprice 商品价格 * prodimg 商品图片 * proddesc 商品描述 * 请求方式 get/post * 响应数据格式 json * 响应数据实例 * {"retCode":10000,"retMsg":"操作成功"} * {"retCode":10005,"retMsg":"操作失败"} * * * */ /*接收参数 转换格式 封装对象*/ req.setCharacterEncoding("utf-8"); String prodId = req.getParameter("prodid"); String prodName = req.getParameter("prodname"); String prodPriceStr = req.getParameter("prodprice"); String prodImg = req.getParameter("prodimg"); String prodDesc = req.getParameter("proddesc"); //需要格式转换的固定写法 Double prodPrice = 0d; if(prodPriceStr != null && "".equals(prodPriceStr)){ prodPrice = Double.parseDouble(prodPriceStr); } Product insertProd = new Product(prodId,prodName,prodPrice,prodImg,prodDesc); /* * 调用业务逻辑代码 * */ ProdService ps = new ProdServiceImpl(); Integer resNum = ps.addProduct(insertProd); /* * 返回数据 * * */ ReturnEntity re = new ReturnEntity(); if(resNum>0){ re.setRetCode(ReturnCode.OPT_SUCCESS.getCode()); re.setRetMsg(ReturnCode.OPT_SUCCESS.getMsg()); }else{ re.setRetCode(ReturnCode.OPT_FAILED.getCode()); re.setRetMsg(ReturnCode.OPT_FAILED.getMsg()); } resp.setContentType("application/json;charset=utf-8"); PrintWriter writer = resp.getWriter(); writer.print(JSON.toJSONString(re)); writer.flush(); writer.close(); } public void queryProd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /* * 接收参数 * 转换格式 * 封装对象 * * 查询商品信息服务接口 * 请求地址 /day6/ajaxProd * 请求参数 page 页码 * pageSize 每页显示的记录数 * 请求方式 get/post * 响应数据格式 json * 响应数据实例 * 没有数据: * {"retCode":20001,"retMsg":"没有数据"} * 有数据: * {"retCode":20000, * "retData":[{"prodDesc":"测试手机","prodId":"SJ00150033","prodImg":"img/phone1.jpg","prodName":"测试手机33","prodPrice":1033}], * "retMsg":"查询成功", * "pageInfo":{"page":1,"pageSize":3,"totalPage":3}} * * */ req.setCharacterEncoding("utf-8"); String pageStr = req.getParameter("page"); String pageSizeStr = req.getParameter("pageSize"); String prodId = req.getParameter("prodid"); String prodName = req.getParameter("prodname"); Integer page = 1; Integer pageSize = 3; if(!"".equals(pageStr)&&pageStr!=null){ page = Integer.parseInt(pageStr); } if(!"".equals(pageSizeStr)&&pageSizeStr!=null){ pageSize = Integer.parseInt(pageSizeStr); } /* * 调用业务逻辑代码 * */ //查询使用的Product对象 Product queryProd = new Product(); queryProd.setProdId(prodId); queryProd.setProdName(prodName); ProdService ps =new ProdServiceImpl(); List<Product> allProd = ps.getAllProd(page,pageSize,queryProd); //返回的总页数(增加一处) Integer totalPage = ps.getTotalPage(pageSize,queryProd); System.out.println(allProd); /* * 返回数据 * * */ ReturnEntity re = new ReturnEntity(); if(allProd.size()>0){ re.setRetCode(ReturnCode.QUERY_SUCCESS.getCode()); re.setRetMsg(ReturnCode.QUERY_SUCCESS.getMsg()); re.setRetData(allProd); //增加第二处 PageInfo pif = new PageInfo(page,pageSize,totalPage); re.setPif(pif); }else{ re.setRetCode(ReturnCode.QUERY_NODATA.getCode()); re.setRetMsg(ReturnCode.QUERY_NODATA.getMsg()); //增加第三处 PageInfo pif = new PageInfo(1,1,1); //没参数,则三个都给1 re.setPif(pif); } resp.setContentType("application/json;charset=utf-8"); PrintWriter writer = resp.getWriter(); writer.print(JSON.toJSONString(re)); writer.flush(); writer.close(); } public void deleteProd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } }
服务接口的接收地址改为@WebServlet("/ajaxProd/*")后,前端请求对应的地址也修改一下:
在showProd类里:
在script部分,查询的地址改变:
function queryData(params){ $.getJSON("/day6/ajaxProd/queryProd",params,function(data){ //... })
添加方法的地址修改:
$("#addSubmitBtn").click(function () { var insertParams = $("#myform").serialize(); //serialize()格式化键值对,前提form里的表单元素要有name属性 $.post("/day6/ajaxProd/addProd",insertParams,function(data){ //... },"json") })
测试:
重新部署,运行,访问:http://localhost:8080/day6/pages/showProd.html
查询页面出现,点击添加,输入商品信息,点击保存,弹出操作结果 操作正确,关闭该框,会在查询页面找到刚才新增的这条商品信息,同时在数据库也能找到该条数据。
这也说明,合并的查询和添加服务接口没问题。
如果再增加一个用户服务接口,里面也是查询,增加,....等方法。
对应的方法,代码差不多,故可使用一个公共父类,把公共方法定义在父类里,让子类继承。
新建BaseServlet,作为公共父类,主要目的重写service方法。(公共父类不加请求地址)
public class BaseServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String requestURI = req.getRequestURI(); String myMethodName = requestURI.substring(requestURI.lastIndexOf("/") + 1); try { Method myMethodName1 = this.getClass().getDeclaredMethod(myMethodName, HttpServletRequest.class, HttpServletResponse.class); myMethodName1.invoke(this, req, resp); } catch (NoSuchMethodException e) { resp.sendError(404); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
在AjaxProdServlet里,直接删掉继承的公共父类的代码即可,其他不变:
@WebServlet("/ajaxProd/*") public class AjaxProdServlet extends BaseServlet { public void addProd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //... } public void queryProd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //... }
3.修改
①.前端
页面的变化形式:还是在查询页面多加一个修改按钮,选择要修改的记录,点击该按钮,弹出一个框,修改信息,点击保存,出现修改成功或者失败的提示信息。若修改成功,关闭提示信息,页面会自动刷新。(用一个页面的策略)
如何定位到操作的是哪条记录,在showProd.htm里,找到table标签,加一条操作
<table class="table"> <tr> <th>商品编号</th> <th>商品信息</th> <th>单价</th> <th>描述信息</th> <th>操作</th> </tr> <tbody id="mainData"> </tbody> </table>
对应的将生成的数据添加进去:
function queryData(params){ $.getJSON("/day6/ajaxProd/queryProd",params,function(data){ console.log(data); $("#mainData").html(""); if(data.retCode == 20000){//查询成功 遍历数据 //把数据遍历到页面中 $.each(data.retData,function(i,d){ var content = '<tr>' +'<td>'+d.prodId+'</td>' +'<td>'+d.prodName+'<br/><img src="/day6/'+d.prodImg+'"/></td>' +'<td>'+d.prodPrice+'</td>' +'<td>'+d.prodDesc+'</td>' +'<td><input prodid="'+d.prodId+'" type="button" value="修改" class="btn btn-warning"></td>' +'</tr>'; $("#mainData").append(content); }) //...
另一种定位要操作记录的方法:
不在每一行后面放按钮,在添加后面加一个按钮。
<button type="button" class="btn btn-success " data-toggle="modal" data-target="#addModal"> 添加 </button> <button type="button" class="btn btn-warning " data-toggle="modal" data-target="#editModal"> 修改 </button>
在body标签里添加对应的Modal后加:
<!-- Modal --> <div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" >修改商品</h4> </div> <div class="modal-body"> <form id="editform"> <div class="form-group"> <label for="prodid">商品编号</label> <input type="text" class="form-control" id="prodidEdit" name="prodid" placeholder="prodid"> </div> <div class="form-group"> <label for="prodname">商品名称</label> <input type="email" class="form-control" id="prodnameEdit" name="prodname" placeholder="prodname"> </div> <div class="form-group"> <label for="prodpriceAdd">商品单价</label> <input type="text" class="form-control" id="prodpriceEdit" name="prodprice" placeholder="prodprice"> </div> <div class="form-group"> <label for="prodimgAdd">图片地址</label> <input type="text" class="form-control" id="prodimgEdit" name="prodimg" placeholder="prodimg"> </div> <div class="form-group"> <label for="proddescAdd">商品描述信息</label> <input type="text" class="form-control" id="proddescEdit" name="proddesc" placeholder="proddesc"> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button> <button id="editSubmitBtn" type="button" class="btn btn-primary" data-dismiss="modal">保存</button> </div> </div> </div> </div>
按钮添加好后,选择一条记录,点击修改按钮,弹出一个框,修改商品信息。
点击到对应行,增加点击效果。首先元素生成在页面,才能加点击效果。
function queryData(params){ $.getJSON("/day6/ajaxProd/queryProd",params,function(data){ console.log(data); $("#mainData").html(""); if(data.retCode == 20000){//查询成功 遍历数据 //把数据遍历到页面中 $.each(data.retData,function(i,d){ var content = '<tr>' +'<td>'+d.prodId+'</td>' +'<td>'+d.prodName+'<br/><img src="/day6/'+d.prodImg+'"/></td>' +'<td>'+d.prodPrice+'</td>' +'<td>'+d.prodDesc+'</td>' +'</tr>'; $("#mainData").append(content); }) //添加点击事件 $("mainData tr").click(function () { var prodid = $(this).find("td").eq(0).html(); console.log(prodid); }) //...
现在点击一条记录,开发者工具的控制台输出对应的商品编号,即定位到对应的记录。
少一些样式,需要让用户看到。最简单的方式,点击该行,变色。
//添加点击事件 $("mainData tr").click(function () { var prodid = $(this).find("td").eq(0).html(); console.log(prodid); $(this).addClass("info"); })
点击后,背景色变成浅蓝色。
点击后还需要清掉
//添加点击事件 $("mainData tr").click(function () { var prodid = $(this).find("td").eq(0).html(); console.log(prodid); $("mainData tr").removeClass("info"); $(this).addClass("info"); })
拿到编号后,通过一个变量保存该值,点击修改按钮,就可将对应记录发到后台查完整数据,响应回来之后,弹出商品信息,修改信息即可。
声明一个变量:
var page ; var pageSize ; var totalPage ; var selectedId;
//添加点击事件 $("mainData tr").click(function () { selectedId = $(this).find("td").eq(0).html(); console.log(selectedId); $("mainData tr").removeClass("info"); $(this).addClass("info"); })
找到修改按钮,加一个id属性:
<button id="editBtn" type="button" class="btn btn-warning " data-toggle="modal" data-target="#editModal"> 修改 </button>
在script标签增加:
//打开修改对话框按钮 $("#editBtn").click(function () { //通过当前选中行的id 查询完整的数据 })
②.后端
从要使用的sql开始:通过id查商品
在ProdDao,增加方法:
//通过id查商品 Product getProdById(String prodId);
在ProdDaoImpl:
@Override public Product getProdById(String queryProdId) { Connection conn = DBHelper.getConn(); String sql = " select tp.prod_id,tp.prod_desc,tp.prod_name,tp.prod_price,tp.prod_img from tb_product tp where tp.prod_id=? "; PreparedStatement preparedStatement = null; ResultSet resultSet = null; Product myProd = null; System.out.println(sql); try { preparedStatement = conn.prepareStatement(sql); preparedStatement.setObject(1,queryProdId); resultSet = preparedStatement.executeQuery(); while(resultSet.next()){ String prodId = resultSet.getString("prod_id"); String prodName = resultSet.getString("prod_name"); Double prodPrice = resultSet.getDouble("prod_price"); String prodImg = resultSet.getString("prod_img"); String prodDesc = resultSet.getString("prod_desc"); myProd = new Product(prodId,prodName,prodPrice,prodImg,prodDesc); } } catch (SQLException e) { e.printStackTrace(); }finally { DBHelper.CloseConn(conn,null,preparedStatement,resultSet); } return myProd; }
在MyTest:
public class MyTest { public static void main(String[] args) { ProdDao prodDao = new ProdDaoImpl(); Product prodById = prodDao.getProdById("SJ00110013"); System.out.println(prodById); } }
测试结果:
select tp.prod_id,tp.prod_desc,tp.prod_name,tp.prod_price,tp.prod_img from tb_product tp where tp.prod_id=? Product(prodId=SJ00110013, prodName=便宜手机, prodPrice=95.3, prodImg=img/phone2.jpg, prodDesc=便宜手机, prodNum=null)
ProdService类:
Product getProdById(String prodId);
ProdServiceImpl:
@Override public Product getProdById(String prodId) { ProdDao pd = new ProdDaoImpl(); return pd.getProdById(prodId); }
在AjaxProdServlet增加对应方法:
public void readyForEdit(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); String prodid = req.getParameter("prodid"); ProdService ps = new ProdServiceImpl(); Product prodById = ps.getProdById(prodid); ReturnEntity re = new ReturnEntity(); if (prodById!=null){ re.setRetCode(ReturnCode.QUERY_SUCCESS.getCode()); re.setRetMsg(ReturnCode.QUERY_SUCCESS.getMsg()); re.setRetData(prodById); }else{ re.setRetCode(ReturnCode.QUERY_NODATA.getCode()); re.setRetMsg(ReturnCode.QUERY_NODATA.getMsg()); } resp.setContentType("application/json;charset=utf-8"); PrintWriter writer = resp.getWriter(); writer.print(JSON.toJSONString(re)); writer.flush(); writer.close(); }
测试:使用Postman工具
输入的url:http://localhost:8080/day6/ajaxProd/readyForEdit?prodid=11
输入的参数:Prodid 给的value为1,点击send
结果:
{"retCode":20000,"retData":{"prodDesc":"11","prodId":"11","prodImg":"11","prodName":"11","prodPrice":0},"retMsg":"查询成功"}
③.回到前端
补全刚才的代码:
//打开修改对话框按钮 $("#editBtn").click(function(){ //通过当前选中行的id 查询完整的数据 $.getJSON("/day6/ajaxProd/readyForEdit","prodid="+selectedId,function(data){ //把修改的完整输入 填入页面中 $("#prodidEdit").val(data.retData.prodId); $("#prodnameEdit").val(data.retData.prodName); $("#prodpriceEdit").val(data.retData.prodPrice); $("#prodimgEdit").val(data.retData.prodImg); $("#proddescEdit").val(data.retData.prodDesc); }) })
选中某条记录,点击修改按钮,会返回对应的商品信息。
到目前为止,修改商品写完一半了。
接下来写修改的服务接口
④.回到后端
ProdDao:
//修改商品 传入商品对象,返回执行成功的记录数 Integer editProduct(Product insertProd);
ProdDaoImpl:
@Override public Integer editProduct(Product insertProd) { Connection conn = DBHelper.getConn(); String sql = "update tb_product set prod_name = ? ,prod_price = ? ,prod_img = ? ,prod_desc = ? where prod_id = ? "; PreparedStatement preparedStatement = null; ResultSet resultSet = null; Integer resNum = 0; System.out.println(sql); try { preparedStatement = conn.prepareStatement(sql); preparedStatement.setString(1,insertProd.getProdName()); preparedStatement.setDouble(2,insertProd.getProdPrice()); preparedStatement.setString(3,insertProd.getProdImg()); preparedStatement.setString(4,insertProd.getProdDesc()); preparedStatement.setString(5,insertProd.getProdId()); resNum = preparedStatement.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { DBHelper.CloseConn(conn,null,preparedStatement,resultSet); } return resNum; }
MyTest:
public class MyTest { public static void main(String[] args) { ProdDao prodDao = new ProdDaoImpl(); Product insertProd = new Product("test12345","test123",123d,"test123","test123"); Integer integer = prodDao.editProduct(insertProd); System.out.println(integer); } }
ProdService:
Integer editProduct(Product insertProd);
ProdServiceImpl:
@Override public Integer editProduct(Product insertProd) { ProdDao pd = new ProdDaoImpl(); return pd.editProduct(insertProd); }
AjaxProdServlet:
public void editProd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); String prodId = req.getParameter("prodid"); String prodName = req.getParameter("prodname"); String prodPriceStr = req.getParameter("prodprice"); String prodImg = req.getParameter("prodimg"); String prodDesc = req.getParameter("proddesc"); Double prodPrice = 0d; if(prodPriceStr!=null&&!"".equals(prodPriceStr)){ prodPrice = Double.parseDouble(prodPriceStr); } Product insertProd = new Product(prodId,prodName,prodPrice,prodImg,prodDesc); /* * 调用业务逻辑代码 * * */ ProdService ps =new ProdServiceImpl(); Integer resNum = ps.editProduct(insertProd); /* * 返回数据 * * */ ReturnEntity re = new ReturnEntity(); if(resNum>0){ re.setRetCode(ReturnCode.OPT_SUCCESS.getCode()); re.setRetMsg(ReturnCode.OPT_SUCCESS.getMsg()); }else{ re.setRetCode(ReturnCode.OPT_FAILED.getCode()); re.setRetMsg(ReturnCode.OPT_FAILED.getMsg()); } resp.setContentType("application/json;charset=utf-8"); PrintWriter writer = resp.getWriter(); writer.print(JSON.toJSONString(re)); writer.flush(); writer.close(); }
测试:
⑤.回到前端
和添加功能非常像。
//修改提交按钮 $("#editSubmitBtn").click(function(){ var url ="/day6/ajaxProd/editProd"; var params =$("#editform").serialize(); CUDData(url,params); }) function CUDData(url,params){//c u r d $.post(url,params,function(data){ console.log(data); var alertcls = ""; //展示结果 if(data.retCode==10000){ alertcls = "alert-success"; }else if(data.retCode==10005){ alertcls = "alert-danger"; } var mycontent = '<div class="myalert alert '+alertcls+' alert-dismissible fade in" role="alert">' + '<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' + '<h4>操作结果</h4>' + '<p>'+data.retMsg+'</p>' + '</div>'; $(".showResPanel").html(mycontent); //刷新数据 重新查询table数据 var params = {"prodid":$("#prodid").val(),"prodname":$("#prodname").val(),"page":page}; queryData(params); },"json") }
这里应该把商品编号做成只读:
<div class="form-group"> <label for="prodidAdd">商品编号</label> <input type="text" class="form-control" id="prodidEdit" readonly name="prodid" placeholder="prodid"> </div>
4.删除
删除也是两种方式:1.每行后加一个删除按钮
2.选择到一行后再删除
选中一行的功能已经做好,下面来展示要删除的数据;
先做一个和修改类似的按钮,点击该按钮,弹出信息:
①.前端
先加一个按钮:
<button id="editBtn" type="button" class="btn btn-warning" data-toggle="modal" data-target="#editModal"> 修改 </button> <button id="delBtn" type="button" class="btn btn-danger" data-toggle="modal" data-target="#delModal"> 删除 </button>
再来一组弹出框:
也可以展示form,每个都加上只读。但没太大必要,只需提醒。
<!-- Modal --> <div class="modal fade" id="delModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" >删除商品</h4> </div> <div class="modal-body"> 此操作将删除编号为 <span id="delprodid" style="color: deeppink"></span> 的记录 确实删除么!!! </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button id="delSubmitBtn" type="button" class="btn btn-primary" data-dismiss="modal">删除</button> </div> </div> </div> </div>
此时弹出框只需把记录的编号填进去。
处理弹出框内容:
//打开删除对话框按钮 $("#delBtn").click(function(){ //展示要删除数据对话框 提示当前数据的id $("#delprodid").html(selectedId); })
对于弹出的信息,如果确定删除,则发到后台,调用删除服务接口。
②.后台
编写删除服务接口:
还是先看sql:DELETE FROM tb_product WHERE prod_id = '111'
执行后,数据库该条记录消失。
ProDao:
//删除商品 传入商品编号,返回执行成功的记录数 Integer delProduct(String prodId);
ProDaoImpl:
@Override public Integer delProduct(String prodId) { Connection conn = DBHelper.getConn(); String sql = "delete from tb_product where prod_id = ? "; PreparedStatement preparedStatement = null; ResultSet resultSet = null; Integer resNum = 0; System.out.println(sql); try { preparedStatement = conn.prepareStatement(sql); preparedStatement.setString(1,prodId); resNum = preparedStatement.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { DBHelper.CloseConn(conn,null,preparedStatement,resultSet); } return resNum; }
MyTest:
public class MyTest { public static void main(String[] args) { ProdDao prodDao = new ProdDaoImpl(); Integer integer = prodDao.delProduct("11"); System.out.println(integer); } }
控制台:
delete from tb_product where prod_id = ? 1
数据库中该条记录消失
ProdService:
Integer delProduct(String prodId);
ProdServiceIml:
@Override public Integer delProduct(String prodId) { ProdDao pd = new ProdDaoImpl(); return pd.delProduct(prodId); }
AjaxProdServlet:
public void delProd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("执行删除"); req.setCharacterEncoding("utf-8"); String prodId = req.getParameter("prodid"); /* * 调用业务逻辑代码 * * */ ProdService ps =new ProdServiceImpl(); Integer resNum = ps.delProduct(prodId); /* * 返回数据 * * */ ReturnEntity re = new ReturnEntity(); if(resNum>0){ re.setRetCode(ReturnCode.OPT_SUCCESS.getCode()); re.setRetMsg(ReturnCode.OPT_SUCCESS.getMsg()); }else{ re.setRetCode(ReturnCode.OPT_FAILED.getCode()); re.setRetMsg(ReturnCode.OPT_FAILED.getMsg()); } resp.setContentType("application/json;charset=utf-8"); PrintWriter writer = resp.getWriter(); writer.print(JSON.toJSONString(re)); writer.flush(); writer.close(); }
测试:
http://localhost:8080/day6/ajaxProd/delProd?prodid=13141
数据库对应记录消失
服务接口完成,用页面发出请求,调用服务接口。
③.前端
//删除提交 $("#delSubmitBtn").click(function(){ var url ="/day6/ajaxProd/delProd"; var params ="prodid="+selectedId; CUDData(url,params); })