一、流程分析
二、代码
1.view层
1)main.jsp
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 4 5 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 6 <html> 7 <head> 8 9 <title>main</title> 10 11 <meta http-equiv="pragma" content="no-cache"> 12 <meta http-equiv="cache-control" content="no-cache"> 13 <meta http-equiv="expires" content="0"> 14 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 15 <meta http-equiv="description" content="This is my page"> 16 <meta http-equiv="content-type" content="text/html;charset=utf-8"> 17 <!-- 18 <link rel="stylesheet" type="text/css" href="styles.css"> 19 --> 20 <link rel="stylesheet" type="text/css" href="<c:url value='/jsps/css/main.css'/>"> 21 </head> 22 23 <body> 24 <table class="table" align="center"> 25 <tr class="trTop"> 26 <td colspan="2" class="tdTop"> 27 <iframe frameborder="0" src="<c:url value='/jsps/top.jsp'/>" name="top"></iframe> 28 </td> 29 </tr> 30 <tr> 31 <td class="tdLeft" rowspan="2"> 32 <iframe frameborder="0" src="<c:url value='/CategoryServlet?method=findAll'/>" name="left"></iframe> 33 </td> 34 <td class="tdSearch" style="border-bottom-width: 0px;"> 35 <iframe frameborder="0" src="<c:url value='/jsps/search.jsp'/>" name="search"></iframe> 36 </td> 37 </tr> 38 <tr> 39 <td style="border-top-width: 0px;"> 40 <iframe frameborder="0" src="<c:url value='/jsps/body.jsp'/>" name="body"></iframe> 41 </td> 42 </tr> 43 </table> 44 </body> 45 </html>
2)left.jsp
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 4 5 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 6 <html> 7 <head> 8 <title>left</title> 9 <base target="body"/> 10 <meta http-equiv="pragma" content="no-cache"> 11 <meta http-equiv="cache-control" content="no-cache"> 12 <meta http-equiv="expires" content="0"> 13 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 14 <meta http-equiv="description" content="This is my page"> 15 <meta http-equiv="content-type" content="text/html;charset=utf-8"> 16 <!-- 17 <link rel="stylesheet" type="text/css" href="styles.css"> 18 --> 19 <script type="text/javascript" src="<c:url value='/jquery/jquery-1.5.1.js'/>"></script> 20 <script type="text/javascript" src="<c:url value='/menu/mymenu.js'/>"></script> 21 <link rel="stylesheet" href="<c:url value='/menu/mymenu.css'/>" type="text/css" media="all"> 22 <link rel="stylesheet" type="text/css" href="<c:url value='/jsps/css/left.css'/>"> 23 <script language="javascript"> 24 /* 25 * 1. 对象名必须与第一个参数相同! 26 2. 第二个参数是显示在菜单上的大标题 27 */ 28 var bar = new Q6MenuBar("bar", "传智播客网上书城"); 29 $(function() { 30 bar.colorStyle = 4;//指定配色样式,一共0,1,2,3,4 31 bar.config.imgDir = "<c:url value='/menu/img/'/>";//小工具所需图片的路径 32 bar.config.radioButton=true;//是否排斥,多个一级分类是否排斥 33 34 /*bar.add("程序设计", "Java Javascript", "/goods/jsps/book/list.jsp", "body"); 35 bar.add("程序设计", "JSP", "/goods/jsps/book/list.jsp", "body"); 36 bar.add("程序设计", "C C++ VC VC++", "/goods/jsps/book/list.jsp", "body"); 37 38 bar.add("办公室用书", "微软Office", "/goods/jsps/book/list.jsp", "body"); 39 bar.add("办公室用书", "计算机初级入门", "/goods/jsps/book/list.jsp", "body"); 40 41 bar.add("图形 图像 多媒体", "Photoshop", "/goods/jsps/book/list.jsp", "body"); 42 bar.add("图形 图像 多媒体", "3DS MAX", "/goods/jsps/book/list.jsp", "body"); 43 bar.add("图形 图像 多媒体", "网页设计", "/goods/jsps/book/list.jsp", "body"); 44 bar.add("图形 图像 多媒体", "Flush", "/goods/jsps/book/list.jsp", "body"); 45 46 bar.add("操作系统/系统开发", "Windows", "/goods/jsps/book/list.jsp", "body"); 47 bar.add("操作系统/系统开发", "Linux", "/goods/jsps/book/list.jsp", "body"); 48 bar.add("操作系统/系统开发", "系统开发", "/goods/jsps/book/list.jsp", "body");*/ 49 50 /* 51 1. 程序设计:一级分类名称 52 2. Java Javascript:二级分类名称 53 3. /goods/jsps/book/list.jsp:点击二级分类后链接到的URL 54 4. body:链接的内容在哪个框架页中显示 55 */ 56 <c:forEach items="${parents}" var="parent"> 57 <c:forEach items="${parent.children}" var="child"> 58 bar.add("${parent.cname}", "${child.cname}", "/goods/BookServlet?method=findByCategory&cid=${child.cid}", "body"); 59 </c:forEach> 60 </c:forEach> 61 $("#menu").html(bar.toString()); 62 }); 63 </script> 64 </head> 65 66 <body> 67 <div id="menu"></div> 68 </body> 69 </html>
3)mymenu.js
1 /* 2 * MenuBar只负责生成<div>,不会实现功能。 3 * MenuBar的add()方法:bar.add("menu1", "item1", "http://www.qdmmy6.com/"); 4 * MenuBar的menus属性是一个数组(其时它是一个Map),每个元素对应一个menu。 5 * 数组中的元素还是一个数组,这个数组中的元素是MenuItem对象。 6 * add()方法首先查找menus["menu1"]元素(即名为"menu1"的菜单)是否存在, 7 * 如果存在,使用"item1"与"http://www.qdmmy6.com/"创建MenuItem对象。然后把MenuItem对象添加到menus["menu1"]中去。 8 * 如果不存在,先创建menus["menu1"],在把MenuItem添加进去。 9 */ 10 function Q6MenuBar(objName, barName) { 11 this.obj = objName; 12 this.barName = barName; 13 this.config = { 14 topHeight:null, 15 bottomHeight:null, 16 width:null, 17 radioButton:true, 18 imgDir:"img/" 19 }; 20 this.icon = {jiaIcon:"jia.png",jianIcon:"jian.png"}; 21 this.colorStyle = 2; 22 this.colors = []; 23 this.colors[0] = { 24 menuBgColor:"rgb(246,133,1)", 25 menuBorderColor:"rgb(236,171,87)", 26 itemBgColor:"rgb(38,38,38)", 27 itemBorderColor:"rgb(100,100,100)", 28 itemBgMoveColor:"rgb(32,145,177)", 29 itemBorderMoveColor:"rgb(119,171,113)", 30 itemMoveColor:"rgb(255,255,255)", 31 itemColor:"rgb(255,255,255)", 32 menuBarColor:"rgb(255,255,255)", 33 menuContentColor:"rgb(255,255,255)" 34 }; 35 this.colors[2] = { 36 itemBgMoveColor:"rgb(246,133,1)", 37 itemBorderMoveColor:"rgb(236,171,87)", 38 menuBgColor:"rgb(78,78,78)",//38 39 menuBorderColor:"rgb(102,102,102)",//100 40 itemBgColor:"rgb(32,145,177)", 41 itemBorderColor:"rgb(119,171,113)", 42 itemMoveColor:"rgb(255,255,255)", 43 itemColor:"rgb(255,255,255)", 44 menuBarColor:"rgb(255,255,255)", 45 menuContentColor:"rgb(255,255,255)" 46 }; 47 this.colors[1] = { 48 menuBgColor:"rgb(25,119,176)", 49 menuBorderColor:"rgb(211,211,211)", 50 itemBgColor:"rgb(121,201,236)", 51 itemBorderColor:"rgb(68,141,174)", 52 itemBgMoveColor:"rgb(110,172,44)", 53 itemBorderMoveColor:"rgb(172,221,74)", 54 itemMoveColor:"rgb(255,255,255)", 55 itemColor:"rgb(255,255,255)", 56 menuBarColor:"rgb(255,255,255)", 57 menuContentColor:"#333333" 58 }; 59 this.colors[3] = { 60 menuBgColor:"rgb(159,153,138)", 61 menuBorderColor:"rgb(142,132,107)", 62 itemBgColor:"rgb(254,238,189)", 63 itemBorderColor:"rgb(164,91,19)", 64 itemBgMoveColor:"rgb(252,211,61)", 65 itemBorderMoveColor:"rgb(164,91,19)", 66 itemMoveColor:"rgb(76,48,0)", 67 itemColor:"rgb(0,116,199)", 68 menuBarColor:"rgb(76,48,0)", 69 menuContentColor:"rgb(76,48,0)" 70 }; 71 this.colors[4] = { 72 menuBgColor:"#15B69A", 73 menuBorderColor:"gray", 74 itemBgColor:"#EAFFFA", 75 itemBorderColor:"#15B69A", 76 itemBgMoveColor:"rgb(13,133,96)", 77 itemBorderMoveColor:"gray", 78 itemMoveColor:"#FFFFFF", 79 itemColor:"gray", 80 menuBarColor:"#FFFFFF", 81 menuContentColor:"gray" 82 }; 83 this.font = { 84 }; 85 this.menus = []; 86 //<div class="title" name="title"><span class="titleText">' + barName + '</span></div><div> 87 } 88 89 /* 90 * 添加方法 91 * 首先查看this.menus[menuName]这个菜单(就是一个数组)是否存在。 92 * 如果不存在,先创建这个菜单(数组)。 93 * 使用menuItemName和url创建MenuItem对象,把MenuItem对象添加到菜单(数组)尾部。 94 * frameName -- 指定在哪个帧中打开页面 95 */ 96 Q6MenuBar.prototype.add = function(menuName, menuItemName, url, frameName) { 97 if (!this.menus[menuName]) { 98 this.menus[menuName] = []; 99 } 100 var len = this.menus[menuName].length; 101 this.menus[menuName][len] = new MenuItem(menuItemName, url, frameName); 102 103 // MenuItem类 104 function MenuItem(menuItemName, url, frameName) { 105 this.menuItemName = menuItemName; 106 this.url = url; 107 this.frameName = frameName; 108 } 109 } 110 /* 111 MenuBar的toString()方法 112 该方法会生成与MenuBar相关的HTML代码,然后遍历menus属性,生成每个菜单对应HTML代码。 113 */ 114 Q6MenuBar.prototype.toString = function() { 115 // menuBar对应的<div> 116 var str = '<div style="border:1px solid' + this.colors[this.colorStyle].menuBorderColor + ';color:' + this.colors[this.colorStyle].menuBarColor + ';" class = "menuBar" name="menuBar" onClick="' + this.obj + '.showMenu(event, this)">\n'; 117 // menuBar的标题<div> 118 str += '<div style="background-color:' + this.colors[this.colorStyle].menuBgColor + ';" class="barTitle" name="barTitle"><span class="barTitleText">' + this.barName + '</span></div>\n'; 119 // 使用循环添加每个菜单对应的HTML代码。 120 for(var menuName in this.menus) { 121 str += this.menu2Str(menuName); 122 } 123 // menuBar尾部对应的<div> 124 str += '<div style="background-color:' + this.colors[this.colorStyle].menuBgColor + ';" name="barBottom" class="barBottom">'; 125 str += '</div>'; 126 return str; 127 } 128 129 /* 130 * 该方法首先生成与菜单对应的HTML代码。 131 * menuName是菜单名字,可以使用menus[menuName]来获取一维数组。 132 * 遍历一维数组,获取其中每个MenuItem,生成MenuItem对应的HTML代码。 133 */ 134 Q6MenuBar.prototype.menu2Str = function(menuName){ 135 var icon = this.config.imgDir + this.icon.jiaIcon; 136 // 菜单对应的<div> 137 var str = '<div name="menu">\n'; 138 // 菜单标题对应的<div>,其中包含icon与text两部分。 139 str += '<div style="background-color:' + this.colors[this.colorStyle].menuBgColor + ';border-right-color:' + this.colors[this.colorStyle].menuBorderColor + ';border-bottom-color:' + this.colors[this.colorStyle].menuBorderColor + ';" name="menuTitle" class="menuTitle"><span name="menuTitleIcon" class="menuTitleIcon"><img src="' + icon + '"/></span><span class="menuTitleText">' + menuName + '</span></div>\n'; 140 // 菜单内容对象的<div>,所有菜单荐都存放在这个<div>中。 141 str += '<div style="color:' + this.colors[this.colorStyle].menuContentColor + ';" class="menuContent" name="menuContent">\n'; 142 // 使用循环添加每个MenuItem对应的HTML 143 for(var i = 0; i < this.menus[menuName].length; i++) { 144 str += this.item2Str(this.menus[menuName][i]); 145 } 146 str += '</div>\n</div>\n'; 147 return str; 148 } 149 150 /* 151 * menuItem是MenuItem类型的对象。 152 * 该方法生成menuItem对应的HTML代码。 153 */ 154 Q6MenuBar.prototype.item2Str = function(menuItem){ 155 return '<div style="border:1px solid ' + this.colors[this.colorStyle].itemBorderColor + ';background-color:' + this.colors[this.colorStyle].itemBgColor + '; color:' + this.colors[this.colorStyle].itemColor + ';" class="menuItem" onMouseMove="' + this.obj + '.itemMouseMove(this)" onMouseOut="' + this.obj + '.itemMouseOut(this)" onClick="skip(\'' + menuItem.url + '\', \'' + menuItem.frameName + '\')">' + menuItem.menuItemName + '</div>\n'; 156 } 157 158 function skip(url, frameName) { 159 if(parent[frameName]) { 160 parent[frameName].location.href=url; 161 } else { 162 location.href=url; 163 } 164 } 165 166 167 /////////////////////////// 168 169 170 171 /* 172 获取当前被点击的menu元素。 173 只有点击:div menuTitle、img、menuTitleText,才获取父元素。 174 如果父元素是menuContent,返回null。 175 */ 176 Q6MenuBar.prototype.getCurrMenu = function(res) { 177 tagName = res.tagName; 178 name = res.getAttribute("name"); 179 while(tagName != "DIV" || name != "menu") { 180 // alert(tagName + ", " + name); 181 res = res.parentNode; 182 if(!res) { 183 return null; 184 } 185 tagName = res.tagName; 186 name = res.getAttribute("name"); 187 if(tagName == "DIV" && name == "menuContent") { 188 return null; 189 } 190 } 191 return res; 192 } 193 194 Q6MenuBar.prototype.attr = function(ele, attrName) { 195 if(ele.getAttribute) { 196 return ele.getAttribute(attrName); 197 } 198 return null; 199 } 200 201 Q6MenuBar.prototype.showMenu = function(evt, menuBar) { 202 var e = evt ? evt : window.event; 203 var res = e.srcElement || e.target; 204 var menu = this.getCurrMenu(res);//获取当前被点击的menu 205 if(!menu) return; 206 this.openMenu(menuBar, menu); 207 } 208 209 // 打开或关闭menu 210 Q6MenuBar.prototype.openMenu = function(menuBar, menu) { 211 var childs = menu.childNodes;//获取menuBar的所有子元素 212 for(var i = 0; i < childs.length; i++) { 213 //因为Firefor中,换行会出现空白节点,所以需要小心。 214 //获取所有content元素 215 if(this.attr(childs[i], "name") == 'menuContent') { 216 var display = childs[i].style.display; 217 if(!display || display=='none') { 218 if (this.config.radioButton) { 219 this.closeMenu(menuBar);//关闭所有menu 220 } 221 childs[i].style.display='block';//打开当前menu 222 this.changeImg(menu, false);//更换当前menu图标 223 } else { 224 if (this.config.radioButton) { 225 this.closeMenu(menuBar);//关闭所有menu 226 } 227 childs[i].style.display='none'; 228 this.changeImg(menu, true); 229 } 230 } 231 } 232 } 233 234 // 更换图片 235 Q6MenuBar.prototype.changeImg = function (menu, flag) { 236 var img = menu.getElementsByTagName("img")[0]; 237 var jiaIcon = this.config.imgDir + this.icon.jiaIcon; 238 var jianIcon = this.config.imgDir + this.icon.jianIcon; 239 img.src = flag ? jiaIcon : jianIcon; 240 } 241 242 // 关闭所有menu 243 Q6MenuBar.prototype.closeMenu = function(menuBar) { 244 var menus = menuBar.childNodes; 245 //获取menuBar中所有menu 246 for(var i=0; i < menus.length; i++) { 247 if(this.attr(menus[i], 'name') != 'menu') continue; 248 var childs = menus[i].childNodes; 249 //获取当前menu中所有content 250 for(var j = 0; j < childs.length; j++) { 251 if(this.attr(childs[j], 'name') != 'menuContent') continue; 252 childs[j].style.display='none'; 253 } 254 this.changeImg(menus[i], true); 255 } 256 } 257 258 Q6MenuBar.prototype.itemMouseMove = function(e) { 259 e.style.border = "1px solid " + this.colors[this.colorStyle].itemBorderMoveColor; 260 e.style.backgroundColor = this.colors[this.colorStyle].itemBgMoveColor; 261 e.style.color = this.colors[this.colorStyle].itemMoveColor; 262 e.style.fontWeight = "bold"; 263 } 264 265 Q6MenuBar.prototype.itemMouseOut = function(e) { 266 e.style.border = "1px solid " + this.colors[this.colorStyle].itemBorderColor; 267 e.style.backgroundColor = this.colors[this.colorStyle].itemBgColor; 268 e.style.color = this.colors[this.colorStyle].itemColor; 269 e.style.fontWeight = ""; 270 }
2.servlet层
1)CategoryServlet.java
1 public class CategoryServlet extends BaseServlet { 2 3 private CategoryService categoryService = new CategoryService(); 4 5 /** 6 * 查询所有分类 7 * @param request 8 * @param response 9 * @return 10 */ 11 public String findAll(HttpServletRequest request, HttpServletResponse response) { 12 List<Category> parents = categoryService.findAll(); 13 request.setAttribute("parents", parents); 14 return "f:/jsps/left.jsp"; 15 } 16 }
3.service层
1)CategoryService.java
1 public class CategoryService { 2 3 private CategoryDao categoryDao = new CategoryDao(); 4 5 /** 6 * 查询所有分类 7 * @return 8 */ 9 public List<Category> findAll() { 10 try { 11 return categoryDao.findAll(); 12 } catch (SQLException e) { 13 throw new RuntimeException(e); 14 } 15 } 16 }
4.dao层
1)CategoryDao.java
1 public class CategoryDao { 2 3 private QueryRunner qr = new TxQueryRunner(); 4 5 /** 6 * 返回所有分类 7 * @return 8 * @throws SQLException 9 */ 10 public List<Category> findAll() throws SQLException { 11 // 1. 查询出所有一级分类 12 String sql = "SELECT * FROM t_category WHERE pid IS NULL ORDER BY orderBy"; 13 List<Map<String,Object>> mapList = qr.query(sql, new MapListHandler()); 14 15 List<Category> parents = toCategoryList(mapList); 16 17 // 2. 循环遍历所有的一级分类,为每个一级分类加载它的二级分类 18 for(Category parent : parents) { 19 // 查询出当前父分类的所有子分类 20 List<Category> children = findByparent(parent.getCid()); 21 // 设置给父分类 22 parent.setChildren(children); 23 } 24 return parents; 25 } 26 27 /** 28 * 通过父分类查询子分类 29 * @param cid 30 * @return 31 * @throws SQLException 32 */ 33 private List<Category> findByparent(String cid) throws SQLException { 34 String sql = "select * from t_category where pid=?"; 35 List<Map<String,Object>> mapList = qr.query(sql, new MapListHandler(), cid); 36 return toCategoryList(mapList); 37 } 38 39 40 /** 41 * 可以把多个Map(List<Map>)映射成多个Category(List<Category>) 42 * @param mapList 43 * @return 44 */ 45 private List<Category> toCategoryList(List<Map<String, Object>> mapList) { 46 List<Category> categoryList = new ArrayList<Category>(); 47 for(Map<String,Object> map : mapList) { 48 Category c = toCategory(map); 49 categoryList.add(c); 50 } 51 return categoryList; 52 } 53 54 /** 55 * 把一个Map中的数据映射到Category中 56 * @param map 57 * @return 58 */ 59 private Category toCategory(Map<String, Object> map) { 60 /* 61 * map {cid:xx, cname:xx, pid:xx, desc:xx, orderBy:xx} 62 * Category{cid:xx, cname:xx, parent:(cid=pid), desc:xx} 63 */ 64 Category category = CommonUtils.toBean(map, Category.class); 65 return category; 66 } 67 }