1, index页面(带直接显示数据)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.*" %> //刚开始的时候不要忘记引入各种包 <%@ page import="com.hanqi.Dao.*" %> <%@ page import="com.hanqi.*" %> <!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> <% String pid = request.getParameter("parentid"); //接收自己传给自己的参数 if(pid==null||pid.trim().length()<=0) { pid = "0"; } int pid1 = Integer.parseInt(pid); //获取数据 MemberDal md = new MemberDal(); Memberclass m = md.getMemberclass(pid1); int backid = 0; if(m!=null) { backid = m.getParentId(); } %> <script src="js/jquery-1.11.3.min.js"></script> <script> //这里使用jQuery隐藏和显示添加文本框 $(document).ready(function () { $("#i1").click(function (){ $("#d1").toggle(100); }) }); $(document).ready($("#d1").hide()); //隐藏 </script> <script> function check() { var obj = /\d{6}/; //正则表达式判断是否是6位数字以上的 if(fm.name.value=="") { alert("地区不能为空"); return false; } else if(!(obj.test(fm.postcode.value)||fm.postcode.value=="")) { alert("邮编请符合规则"); return false; } else { return true; } } function con(){ var cfm = confirm("确定要删除该地区吗? 删除该地区的同时, 会将该地区下的所有地区都删除! "); return cfm; } /*function show() { document.getElementById("fm").style.display="block"; }*/ //样式表中的隐藏属性, display = none或者block function backSuper() { window.location="index.jsp?parentid=<%=backid %>"; //window.history.back(); //使页面后退的两种简单方法 //window.history.go(-1); } </script> </head> <body> <a href="Finder">显示全部省级地区</a> <br> <br> <input id="i1" type="button" value="在此级别添加地区" /> <input type="button" value="返回上级地区" onclick="backSuper()" /> <br> <table border="1" cellspacing="1" cellpadding="1"> <tr> <th width="80">地名</th> <th width="80">邮编</th> <th width="80">管理</th> <th width="80">删除</th> </tr> <% ArrayList<Memberclass> al = md.getList(pid1); //Memberclass u; if(al!=null) { for(Memberclass rset : al) { out.print("<tr><td>"); //通过输出表格标签的形式组建表格 out.print(rset.getName()); out.print("</td><td>"); out.print(rset.getPostCode()==null?"":rset.getPostCode()); //用三元表达式让其不显示"null" out.print("</td><td>"); out.print("<a href='index.jsp?parentid="+rset.getId()+"'>下级地区</a>"); out.print("</td><td>"); out.print("<a onclick='return con()' href='DeleteMember?parentid="+rset.getParentId()+"&id="+rset.getId()+"'>删除</a></td></tr>"); } } %> </table> <br> <div id="d1"> <form id="fm" method="post" action="InsertMember" onSubmit="return check()"> <input name="parentid" type="hidden" value="<%=pid%>"> <ul> <li>请输入地区: <input name="name" type="text" value="" /></li> <li>请输入邮编: <input name="postcode" type="text" value="" maxlength="6"/></li> <li><input type="submit" value="添加" /><input type="reset" value="取消" /></li> </ul> </form> </div> 带刷新的三级联动<br> <iframe src="list.jsp" width="500" height="50"></iframe><br><br> 无刷新三级联动<br> <iframe src="ajaxlist1.jsp" width="500" height="50"></iframe> </body> <script> //设置开始的隐藏状态, 隐藏添加的文本框 $("#d1").hide(); </script> </html>
2, Servlet控制层
录入数据
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); //先设置转码的指令 String name = request.getParameter("name"); String postcode = request.getParameter("postcode"); //接收参数 String parentid = request.getParameter("parentid"); if(name!=null&&name.trim().length()>0) { //get方法需要在这里在进行一次转码 //name = new String(name.getBytes("iso-8859-1"),"utf-8"); if(parentid!=null&&parentid.trim().length()>0) { Memberclass m = new Memberclass(); m.setName(name); m.setParentId(Integer.parseInt(parentid)); m.setPostCode(postcode); MemberDal ma = new MemberDal(); try { if(ma.insert(m)>0) { response.sendRedirect("Finder?parentid="+parentid); //顺便将参数传回去, 控制显示页面 } else { response.getWriter().append("添加失败"); } } catch (Exception e) { response.getWriter().append(e.getMessage()); } } else { response.getWriter().append("地区parentid不能为空"); } } else { response.getWriter().append("地区name不能为空"); } }
删除数据
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("utf-8"); response.setContentType("text/htm; charset=utf-8"); String id = request.getParameter("id"); String parentid = request.getParameter("parentid"); if(id==null||id.trim().length()<=0) { response.getWriter().append("id不能为空"); } else { MemberDal1 de = new MemberDal1(); try { if(de.deleteDG(Integer.parseInt(id))>0) { //判断递归级联删除的返回值为多少 response.sendRedirect("Finder?parentid="+(parentid==null?"0":parentid)); //使用三元表达式赋值控制显示数据 } else { response.getWriter().append("删除数据失败"); } } catch(Exception e) { response.getWriter().append(e.getMessage()); } } }
查询显示数据(使用一个sevrlet), 在index中可以直接获取数据, 两种方法均可
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("text/html; charset=utf-8"); try { //异常包裹处理是非常重要的 Connection con = Dbhelper.getConnection(); if(con!=null) { String parentid = null; String sql = "select * from member where parentid ="+parentid; Statement stm = con.createStatement(); ResultSet rs = stm.executeQuery(sql); //在这里混了好几次了, 根据返回值的不同, 执行的语句也是不一样的, 高度注意这里 ArrayList<Memberclass> result = new ArrayList<Memberclass>(); //实例化一个集合要标明对象类型Memberclass if(rs!=null) { while(rs.next()) { Memberclass place = new Memberclass(); place.setId(rs.getInt("id")); place.setParentId(rs.getInt("parentid")); place.setName(rs.getString("name")); place.setPostCode(rs.getString("postcode")); result.add(place); } request.setAttribute("placelist", result); } else { response.getWriter().append("无结果返回"); } //p.close(); con.close(); stm.close(); } else{ response.getWriter().append("连接数据库失败"); } } catch(Exception e) { response.getWriter().append(e.getMessage()); } request.getRequestDispatcher("index.jsp").forward(request, response); //注意跳转的方式 }
3, Dal工具类
链接数据库, 加载驱动(没什么好说的, 背下来)
public class Dbhelper { public static Connection getConnection() throws Exception { Class.forName("oracle.jdbc.driver.OracleDriver"); String url = "jdbc:oracle:thin:@localhost:1521:orcl"; Connection conn = DriverManager.getConnection(url, "test1204", "1234"); return conn; } }
对象类(当时学的时候觉得很深奥, 现在已经用的比较熟练了, 为什么?)
package com.hanqi.Dao; public class Memberclass { private int id; private int ParentId; private String Name; private String PostCode; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getParentId() { return ParentId; } public void setParentId(int parentId) { ParentId = parentId; } public String getName() { return Name; } public void setName(String name) { Name = name; } public String getPostCode() { return PostCode; } public void setPostCode(String postCode) { PostCode = postCode; } }
增删查方法体类(重点是递归级联删除, 以后关于地区的问题, 大部分都要使用到这个技术, 还有建立树形文件夹)
package com.hanqi.Dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; public class MemberDal { //插入数据 public int insert(Memberclass m) throws Exception { int row = 0; Connection conn = Dbhelper.getConnection(); PreparedStatement pst = null; if(conn!=null) { try { //注意在写占位符的时候尽量不要加空格 String sql = "insert into member (id, parentid, name, postcode) values (sq_member.nextval,?,?,?)"; pst = conn.prepareStatement(sql); pst.setInt(1, m.getParentId()); pst.setString(2, m.getName()); pst.setString(3, m.getPostCode()); row = pst.executeUpdate(); } catch(Exception ex) { throw ex; } finally { try{ pst.close(); //如果出现异常也要确保资源能够正常释放 } catch(Exception ex1) { throw ex1; } conn.close(); } } return row; } //删除数据, 只能删除两级 public int delete(int id) throws Exception { int row = 0; Connection con = Dbhelper.getConnection(); PreparedStatement ps = null; if(con!=null) { try { //运用上下级id的关系 String sql = "delete member where id = ? or parentid = ?"; ps = con.prepareStatement(sql); ps.setInt(1, id); ps.setInt(2, id); row = ps.executeUpdate(); } catch(Exception e) { throw e; } finally { try { ps.close(); } catch(Exception e1) { throw e1; } con.close(); } } return row; } //构造查询的方法 public ArrayList<Memberclass> getList(int parentid) throws Exception { ArrayList<Memberclass> rst = null; Connection con = Dbhelper.getConnection(); PreparedStatement p = null; ResultSet rs = null; if(con!=null) { try { String sql = "select * from member where parentid = ?"; p = con.prepareStatement(sql); p.setInt(1, parentid); rs = p.executeQuery(); rst = new ArrayList<Memberclass>(); if(rs!=null) { while(rs.next()) { Memberclass place = new Memberclass(); place.setId(rs.getInt("id")); place.setParentId(rs.getInt("parentid")); place.setName(rs.getString("name")); place.setPostCode(rs.getString("postcode")); rst.add(place); } } } catch(Exception e) { System.out.println(e); } finally { try { p.close(); } catch(Exception e1) { System.out.println(e1); } finally { try { con.close(); } catch(Exception e2) { } finally { rs.close(); } } } } return rst; } //返回上一级单条查询 public Memberclass getMemberclass(int id) throws Exception{ Memberclass rtn = null; Connection conn = Dbhelper.getConnection(); PreparedStatement pst = null; ResultSet rs = null; if(conn!=null) { try { String sql = "select * from member where id=?"; pst = conn.prepareStatement(sql); pst.setInt(1, id); rs = pst.executeQuery(); if(rs!=null&&rs.next()) { rtn = new Memberclass(); rtn.setId(rs.getInt("id")); rtn.setParentId(rs.getInt("parentid")); } } catch(Exception ex) { throw ex; } finally { try { pst.close(); //如果出现异常也要确保资源能够正常释放 } catch(Exception ex1) { throw ex1; } conn.close(); } } return rtn; } //递归级联删除 //递归级联删除 private void dgDel(Connection con, int id) throws SQLException { PreparedStatement pst = null; ResultSet rs = null; Statement st = null; try { //找到第一条复合条件的先将其删除 String sql = "delete member where id = ? "; pst = con.prepareStatement(sql); pst.setInt(1, id); pst.executeUpdate(); //找到其下一级 sql = "select * from member where parentid = " + id; st = con.createStatement(); rs = st.executeQuery(sql); //因为在这个题目当中有一个id==parentid的隐含条件, 所以这里可以使用递归级联删除 //遍历子节点 if (rs != null) { while(rs.next()) { dgDel(con, rs.getInt("id"));//递归调用 } } } catch(Exception ex) { System.out.println(ex); } finally { try { rs.close(); } catch(Exception ex) { } try { pst.close(); } catch(Exception ex) { } try { st.close(); } catch(Exception ex) { } } } //删 public int deleteDG(int id) throws Exception { int rtn = -1; Connection conn = Dbhelper.getConnection(); PreparedStatement pst = null; if (conn != null) { try { //因为牵扯到级联删除, 这个地方一定要用到事务, 设置为手动提交 //手动提交 conn.setAutoCommit(false); //递归级联删除 dgDel(conn, id); conn.commit(); //之前一直返回的是一个负数是因为rtn这个一直没被赋值, 这样做一下判断, 如果删除成功了就赋值为1 rtn = 1; } catch(Exception ex) { conn.rollback(); throw ex; } finally { try { pst.close(); } catch(Exception ex) { } conn.close(); } } return rtn; } }
地区的三级联动
1, 显示页面, jsp页面
带刷新的三级联动
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.*" %> <%@ page import="com.hanqi.Dao.*" %> <%@ page import="com.hanqi.*" %> <!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> <% String first = request.getParameter("first"); //接收自己传给自己的数据 String second = request.getParameter("second"); int ifirst = 0; int isecond = 0; if(first!=null&&first.trim().length()>0) { ifirst = Integer.parseInt(first); } if(second!=null&&second.trim().length()>0) { isecond = Integer.parseInt(second); } %> <script> function firstOnChange() { //将第一级的id传进去, 再刷新页面 var first = document.getElementById("first"); window.location = "list.jsp?first="+first.value; } function secondOnChange() { //在这里, 当选择第二级和第三级选项是, 会影响第一级的选择, //这时候要把两个参数都传一下, 使页面重新刷新 var first = document.getElementById("first"); var second = document.getElementById("second"); window.location = "list.jsp?first="+first.value+"&second="+second.value; } </script> </head> <body> 一级地区 <select id="first" onchange="firstOnChange()"> <option value="0">未选择</option> <% MemberDal md = new MemberDal(); ArrayList<Memberclass> al = md.getList(0); if(al!=null) { for(Memberclass m:al) { //运用三元表达式在页面刷新之后还能选中之前选中的选项 out.print("<option value='"+m.getId()+"' "+(m.getId()==ifirst?"selected":"")+">"+m.getName()+"</option>"); } } %> </select> 二级地区 <select id="second" onchange="secondOnChange()"> <option value="0">未选择</option> <% ArrayList<Memberclass> al2 = null; if(ifirst!=0) { al2 = md.getList(ifirst); if(al2!=null) { for(Memberclass m1:al2) { out.print("<option value='"+m1.getId()+"' "+(m1.getId()==isecond?"selected":"")+">"+m1.getName()+"</option>"); } } } %> </select> 三级地区 <select id="third"> <option value="0">未选择</option> <% ArrayList<Memberclass> al3 = null; if(isecond!=0) { al3 = md.getList(isecond); //必须判断是否为空, 否则会出现空指令异常 if(al3!=null) { for(Memberclass m2:al3) { out.print("<option value='"+m2.getId()+"'>"+m2.getName()+"</option>"); } } } %> </select> </body> </html>
不带刷新的三级联动(关于onchange事件的调用函数有N种, 包括自己定义一种格式, 手工接收返回的数据, 包括使用jQuery+Ajax写onchange的函数, 包括使用json来接收和编译取到的数据)
使用jQuery的话就不需要Servlet来控制了, 可以直接返回数据
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import="java.util.*" %> <%@ page import="com.hanqi.Dao.*" %> <%@ page import="com.hanqi.*" %> <!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 src="js/jquery-1.11.3.min.js"></script> <script> var hx = false; //最原始的方法, 直接用ajax, 自己手工接收参数, 在sevrlet控制层自己构造一个格式 function firstOnChange() { if(window.XMLHttpRequest) { hx = new XMLHttpRequest; } else if(window.ActiveXObject) { hx = new ActiveXObject(Msxml2.XMLHTTP); } else { hx = new ActiveXObject(Microsoft.XMLHTTP); } var first = document.getElementById("first"); hx.open("GET","AjaxGetList1?parentid="+first.value,true); //这里使用的GET方法, 注意与POST方法的区别 //设置回调函数 hx.onreadystatechange = firstCh; hx.send(null); function firstCh() { if(hx.readyState==4) { if(hx.status==200) { //接收返回的内容 var ts = hx.responseText; 分割字符串 var ar = ts.split(";"); var doc = document.getElementById("second"); //清除掉之前的下拉选项 doc.options.length=1; for(var i = 0; i<ar.length-1; i++) { var rr = ar[i].split(":"); doc.options.add(new Option(rr[1],rr[0])); } } } } //清除掉第三级下拉菜单 var doc = document.getElementById("third"); doc.options.length=1; //secondOnChangeJq(); } //同上 function secondOnChange() { if(window.XMLHttpRequest) { hx = new XMLHttpRequest; } else if(window.ActiveXObject) { hx = new ActiveXObject(Msxml2.XMLHTTP); } else { hx = new ActiveXObject(Microsoft.XMLHTTP); } var second = document.getElementById("second"); hx.open("GET","AjaxGetList1?parentid="+second.value,true); hx.onreadystatechange = secCh; hx.send(null); function secCh() { if(hx.readyState==4) { if(hx.status==200) { var ts = hx.responseText; var ar = ts.split(";"); var doc = document.getElementById("third"); doc.options.length=1; for(var i = 0; i<ar.length-1; i++) { var rr = ar[i].split(":"); doc.options.add(new Option(rr[1],rr[0])); } } } } } //使用jQuery运行ajax function secondOnChangeJq() { var url="AjaxGetList1?parentid="+$("#second").val(); var cb = function(data,status) { //直接返回数据和状态 //alert("data:"+data+"\nStatus:"+status); var ar = data.split(";"); var doc = document.getElementById("third"); doc.options.length=1; //必须要等于1, 要保留第一个选项 for(var i = 0; i<ar.length-1; i++) { var rr = ar[i].split(":"); //设置下拉选项的value doc.options.add(new Option(rr[1],rr[0])); } } //直接调用 $.get(url,cb); } //使用JSON来接收字符串 function jsonChange() { var cb = function(data,status) { alert(data); //使用eval()方法解析json var array = eval("("+data+")"); var doc = document.getElementById("second"); doc.options.length=1; //json返回的是一个数组, 数组的每个单位是一个对象, 每个对象都是一个键值对, 可以在这里直接调用属性值 for(var i = 0; i<array.length; i++) { doc.options.add(new Option(array[i].name,array[i].id)); } } var url = "JsonGetList?parentid="+$("#first").val()+"&nocache="+new Date().getTime(); //添加一个时间消除缓存 $.get(url,cb); } </script> </head> <body> 一级地区 <select id="first" onchange="firstOnChange()"> <option value="0">未选择</option> <% MemberDal md = new MemberDal(); ArrayList<Memberclass> al = md.getList(0); if(al!=null) { for(Memberclass m:al) { out.print("<option value='"+m.getId()+"'>"+m.getName()+"</option>"); } } %> </select> 二级地区 <select id="second" onchange="secondOnChangeJq()"> <option value="-1">未选择</option> </select> 三级地区 <select id="third"> <option value="-1">未选择</option> </select> </body> </html>
2, Servlet控制层
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //啥事也别干, 先设置字符集 request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("text/html; charset=utf-8"); //第二步, 接收参数 String parentid = request.getParameter("parentid"); int pid = 0; if(parentid!=null&&parentid.trim().length()>0) { pid = Integer.parseInt(parentid); } else { pid = -1; } String str = ""; try { MemberDal m = new MemberDal(); ArrayList<Memberclass> array = m.getList(pid); if(array!=null) { for(Memberclass q:array) { str = str+q.getId()+":"+q.getName()+";"; //这里就是自己构造的一个格式 } } } catch (Exception e) { //response.getWriter().append(e.getMessage()); } //返回只能返回一个文本或者字符串, response.getWriter().append(str); }