后台
后台的内容,必须要设置权限
用户可以访问一个网站的哪些内容?
dao:不行 / service:不行
servlet:能 / jsp:能
用户可以访问的只有WEB层
分类管理
功能:增删改查
相关类
其他不变,为管理员提供单独的Servlet,然后给这个Servlet添加过滤器!
web.servlet.admin:AdminCategoryServlet
查看所有分类
(略)同前台 只是转发到不同的页面
添加分类
add.jsp→AdminCatetgoryServlet#add()
1.封装表单数据;
2.补全:cid
3.调用service方法完成添加工作
4.调用findAll()方法
service#add(Category c):Serivice层可能需要判断分类名是否可以重名
dao#add(Catetgory c):
删除分类
list.jsp(删除链接)→
AdminCategoryServlet#delete():
1.获取参数:cid
2.调用service方法完成删除
*如果出现异常,保存异常信息,转发到msg.jsp显示
3.调用findAll()
service#delete(String cid)
*通过cid查看该分类下的图书本数,如果大于0,抛出异常
*如果等于0,删除该分类
修改分类
第一步:加载分类从list页面把分类信息加载传递到mod页面
第二步:提交表单进行修改(如果不可以重名需要增加判断)
代码
多级目录手风琴菜单JS
/* * MenuBar只负责生成<div>,不会实现功能。 * MenuBar的add()方法:bar.add("menu1", "item1", "http://www.qdmmy6.com/"); * MenuBar的menus属性是一个数组(其时它是一个Map),每个元素对应一个menu。 * 数组中的元素还是一个数组,这个数组中的元素是MenuItem对象。 * add()方法首先查找menus["menu1"]元素(即名为"menu1"的菜单)是否存在, * 如果存在,使用"item1"与"http://www.qdmmy6.com/"创建MenuItem对象。然后把MenuItem对象添加到menus["menu1"]中去。 * 如果不存在,先创建menus["menu1"],在把MenuItem添加进去。 */ function Q6MenuBar(objName, barName) { this.obj = objName; this.barName = barName; this.config = { topHeight:null, bottomHeight:null, width:null, radioButton:true, imgDir:"img/" }; this.icon = {jiaIcon:"jia.png",jianIcon:"jian.png"}; this.colorStyle = 2; this.colors = []; this.colors[0] = { menuBgColor:"rgb(246,133,1)", menuBorderColor:"rgb(236,171,87)", itemBgColor:"rgb(38,38,38)", itemBorderColor:"rgb(100,100,100)", itemBgMoveColor:"rgb(32,145,177)", itemBorderMoveColor:"rgb(119,171,113)", itemMoveColor:"rgb(255,255,255)", itemColor:"rgb(255,255,255)", menuBarColor:"rgb(255,255,255)", menuContentColor:"rgb(255,255,255)" }; this.colors[2] = { itemBgMoveColor:"rgb(246,133,1)", itemBorderMoveColor:"rgb(236,171,87)", menuBgColor:"rgb(78,78,78)",//38 menuBorderColor:"rgb(102,102,102)",//100 itemBgColor:"rgb(32,145,177)", itemBorderColor:"rgb(119,171,113)", itemMoveColor:"rgb(255,255,255)", itemColor:"rgb(255,255,255)", menuBarColor:"rgb(255,255,255)", menuContentColor:"rgb(255,255,255)" }; this.colors[1] = { menuBgColor:"rgb(25,119,176)", menuBorderColor:"rgb(211,211,211)", itemBgColor:"rgb(121,201,236)", itemBorderColor:"rgb(68,141,174)", itemBgMoveColor:"rgb(110,172,44)", itemBorderMoveColor:"rgb(172,221,74)", itemMoveColor:"rgb(255,255,255)", itemColor:"rgb(255,255,255)", menuBarColor:"rgb(255,255,255)", menuContentColor:"#333333" }; this.colors[3] = { menuBgColor:"rgb(159,153,138)", menuBorderColor:"rgb(142,132,107)", itemBgColor:"rgb(254,238,189)", itemBorderColor:"rgb(164,91,19)", itemBgMoveColor:"rgb(252,211,61)", itemBorderMoveColor:"rgb(164,91,19)", itemMoveColor:"rgb(76,48,0)", itemColor:"rgb(0,116,199)", menuBarColor:"rgb(76,48,0)", menuContentColor:"rgb(76,48,0)" }; this.font = { }; this.menus = []; //<div class="title" name="title"><span class="titleText">' + barName + '</span></div><div> } /* * 添加方法 * 首先查看this.menus[menuName]这个菜单(就是一个数组)是否存在。 * 如果不存在,先创建这个菜单(数组)。 * 使用menuItemName和url创建MenuItem对象,把MenuItem对象添加到菜单(数组)尾部。 * frameName -- 指定在哪个帧中打开页面 */ Q6MenuBar.prototype.add = function(menuName, menuItemName, url, frameName) { if (!this.menus[menuName]) { this.menus[menuName] = []; } var len = this.menus[menuName].length; this.menus[menuName][len] = new MenuItem(menuItemName, url, frameName); // MenuItem类 function MenuItem(menuItemName, url, frameName) { this.menuItemName = menuItemName; this.url = url; this.frameName = frameName; } } /* MenuBar的toString()方法 该方法会生成与MenuBar相关的HTML代码,然后遍历menus属性,生成每个菜单对应HTML代码。 */ Q6MenuBar.prototype.toString = function() { // menuBar对应的<div> 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'; // menuBar的标题<div> str += '<div style="background-color:' + this.colors[this.colorStyle].menuBgColor + ';" class="barTitle" name="barTitle"><span class="barTitleText">' + this.barName + '</span></div>\n'; // 使用循环添加每个菜单对应的HTML代码。 for(var menuName in this.menus) { str += this.menu2Str(menuName); } // menuBar尾部对应的<div> str += '<div style="background-color:' + this.colors[this.colorStyle].menuBgColor + ';" name="barBottom" class="barBottom">'; str += '</div>'; return str; } /* * 该方法首先生成与菜单对应的HTML代码。 * menuName是菜单名字,可以使用menus[menuName]来获取一维数组。 * 遍历一维数组,获取其中每个MenuItem,生成MenuItem对应的HTML代码。 */ Q6MenuBar.prototype.menu2Str = function(menuName){ var icon = this.config.imgDir + this.icon.jiaIcon; // 菜单对应的<div> var str = '<div name="menu">\n'; // 菜单标题对应的<div>,其中包含icon与text两部分。 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'; // 菜单内容对象的<div>,所有菜单荐都存放在这个<div>中。 str += '<div style="color:' + this.colors[this.colorStyle].menuContentColor + ';" class="menuContent" name="menuContent">\n'; // 使用循环添加每个MenuItem对应的HTML for(var i = 0; i < this.menus[menuName].length; i++) { str += this.item2Str(this.menus[menuName][i]); } str += '</div>\n</div>\n'; return str; } /* * menuItem是MenuItem类型的对象。 * 该方法生成menuItem对应的HTML代码。 */ Q6MenuBar.prototype.item2Str = function(menuItem){ 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'; } function skip(url, frameName) { if(parent[frameName]) { parent[frameName].location.href=url; } else { location.href=url; } } /////////////////////////// /* 获取当前被点击的menu元素。 只有点击:div menuTitle、img、menuTitleText,才获取父元素。 如果父元素是menuContent,返回null。 */ Q6MenuBar.prototype.getCurrMenu = function(res) { tagName = res.tagName; name = res.getAttribute("name"); while(tagName != "DIV" || name != "menu") { // alert(tagName + ", " + name); res = res.parentNode; if(!res) { return null; } tagName = res.tagName; name = res.getAttribute("name"); if(tagName == "DIV" && name == "menuContent") { return null; } } return res; } Q6MenuBar.prototype.attr = function(ele, attrName) { if(ele.getAttribute) { return ele.getAttribute(attrName); } return null; } Q6MenuBar.prototype.showMenu = function(evt, menuBar) { var e = evt ? evt : window.event; var res = e.srcElement || e.target; var menu = this.getCurrMenu(res);//获取当前被点击的menu if(!menu) return; this.openMenu(menuBar, menu); } // 打开或关闭menu Q6MenuBar.prototype.openMenu = function(menuBar, menu) { var childs = menu.childNodes;//获取menuBar的所有子元素 for(var i = 0; i < childs.length; i++) { //因为Firefor中,换行会出现空白节点,所以需要小心。 //获取所有content元素 if(this.attr(childs[i], "name") == 'menuContent') { var display = childs[i].style.display; if(!display || display=='none') { if (this.config.radioButton) { this.closeMenu(menuBar);//关闭所有menu } childs[i].style.display='block';//打开当前menu this.changeImg(menu, false);//更换当前menu图标 } else { if (this.config.radioButton) { this.closeMenu(menuBar);//关闭所有menu } childs[i].style.display='none'; this.changeImg(menu, true); } } } } // 更换图片 Q6MenuBar.prototype.changeImg = function (menu, flag) { var img = menu.getElementsByTagName("img")[0]; var jiaIcon = this.config.imgDir + this.icon.jiaIcon; var jianIcon = this.config.imgDir + this.icon.jianIcon; img.src = flag ? jiaIcon : jianIcon; } // 关闭所有menu Q6MenuBar.prototype.closeMenu = function(menuBar) { var menus = menuBar.childNodes; //获取menuBar中所有menu for(var i=0; i < menus.length; i++) { if(this.attr(menus[i], 'name') != 'menu') continue; var childs = menus[i].childNodes; //获取当前menu中所有content for(var j = 0; j < childs.length; j++) { if(this.attr(childs[j], 'name') != 'menuContent') continue; childs[j].style.display='none'; } this.changeImg(menus[i], true); } } Q6MenuBar.prototype.itemMouseMove = function(e) { e.style.border = "1px solid " + this.colors[this.colorStyle].itemBorderMoveColor; e.style.backgroundColor = this.colors[this.colorStyle].itemBgMoveColor; e.style.color = this.colors[this.colorStyle].itemMoveColor; e.style.fontWeight = "bold"; } Q6MenuBar.prototype.itemMouseOut = function(e) { e.style.border = "1px solid " + this.colors[this.colorStyle].itemBorderColor; e.style.backgroundColor = this.colors[this.colorStyle].itemBgColor; e.style.color = this.colors[this.colorStyle].itemColor; e.style.fontWeight = ""; }
left.jsp bodyJS代码手风琴目录使用
<script language="javascript"> var bar1 = new Q6MenuBar("bar1", "ITCAST网络图书商城"); function load() { bar1.colorStyle = 3; bar1.config.imgDir = "<c:url value='/menu/img/'/>"; bar1.config.radioButton=false; bar1.add("分类管理", "查看分类", "<c:url value='/admin/AdminCategoryServlet?method=findAll'/>", "body"); bar1.add("分类管理", "添加分类", "<c:url value='/adminjsps/admin/category/add.jsp'/>", "body"); bar1.add("图书管理", "查看图书", "<c:url value='/admin/AdminBookServlet?method=findAll'/>", "body"); bar1.add("图书管理", "添加图书", "<c:url value='/admin/AdminBookServlet?method=addPre'/>", "body"); bar1.add("订单管理", "所有订单", "<c:url value='/adminjsps/admin/order/list.jsp'/>", "body"); bar1.add("订单管理", "未付款订单", "<c:url value='/adminjsps/admin/order/list.jsp'/>", "body"); bar1.add("订单管理", "已付款订单", "<c:url value='/adminjsps/admin/order/list.jsp'/>", "body"); bar1.add("订单管理", "未收货订单", "<c:url value='/adminjsps/admin/order/list.jsp'/>", "body"); bar1.add("订单管理", "已完成订单", "<c:url value='/adminjsps/admin/order/list.jsp'/>", "body"); var d = document.getElementById("menu"); d.innerHTML = bar1.toString(); } </script> </head> <body onload="load()" style="margin: 0px; background: rgb(254,238,189);"> <div id="menu"></div> </body>
servlet
public class AdminCategoryServlet extends BaseServlet { private CategoryService categoryService = new CategoryService(); /** * 修改分类 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * 1. 封装表单数据 * 2. 调用service方法完成修改工作 * 3. 调用findAll */ Category category = CommonUtils.toBean(request.getParameterMap(), Category.class); categoryService.edit(category); return findAll(request, response); } /** * 修改之前的加载工作 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String editPre(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String cid = request.getParameter("cid"); request.setAttribute("category", categoryService.load(cid)); return "f:/adminjsps/admin/category/mod.jsp"; } /** * 删除分类 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * 1. 获取参数:cid * 2. 调用service方法,传递cid参数 * > 如果抛出异常,保存异常信息,转发到msg.jsp显示 * 3. 调用findAll() */ String cid = request.getParameter("cid"); try { categoryService.delete(cid); return findAll(request, response); } catch(CategoryException e) { request.setAttribute("msg", e.getMessage()); return "f:/adminjsps/msg.jsp"; } } /** * 添加分类 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * 1. 封装表单数据 * 2. 补全:cid * 3. 调用service方法完成添加工作 * 4. 调用findAll() */ Category category = CommonUtils.toBean(request.getParameterMap(), Category.class); category.setCid(CommonUtils.uuid()); categoryService.add(category); return findAll(request, response); } public String findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * 1. 调用service方法,得到所有分类 * 2. 保存到request域,转发到/adminjsps/admin/category/list.jsp */ request.setAttribute("categoryList", categoryService.findAll()); return "f:/adminjsps/admin/category/list.jsp"; } }
图书管理
增删改查
相关类
AdminBookServlet
AdminAddBookServlet(添加图书,包含上传):上传不能使用BaseServlet,因为BaseServlet中需要使用getParameter()方法,而上传getParameter()
方法就不能再使用了。
查询所有图书
(略) 同前台
加载图书
(略) 同前台
添加图书
添加图书分两步:
1.加载所有分类,到add.jsp中显示
left.jsp(菜单项:添加图书)→
AdminBookServlet#addPre():
*查询所有分类,保存到request域,转发到add.jsp
*在add.jsp中循环遍历所有分类,显示在<select>中
2.添加图书
*上传三步:?创建工厂/ 创建解析器/ 解析request得到表单字段
*把表单字段封装到Book对象中
*保存上传文件,把保存的路径设置给Book的image属性
*调用service方法保存Book对象到数据库中
*调用findAll()
servlet代码
public class AdminAddBookServlet extends HttpServlet { private BookService bookService = new BookService(); private CategoryService categoryService = new CategoryService(); public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); /* * 1. 把表单数据封装到Book对象中 * * 上传三步 */ // 创建工厂 DiskFileItemFactory factory = new DiskFileItemFactory(15 * 1024, new File("F:/f/temp")); // 得到解析器 ServletFileUpload sfu = new ServletFileUpload(factory); // 设置单个文件大小为15KB sfu.setFileSizeMax(20 * 1024); // 使用解析器去解析request对象,得到List<FileItem> try { List<FileItem> fileItemList = sfu.parseRequest(request); /* * * 把fileItemList中的数据封装到Book对象中 * > 把所有的普通表单字段数据先封装到Map中 * > 再把map中的数据封装到Book对象中 */ Map<String,String> map = new HashMap<String,String>(); for(FileItem fileItem : fileItemList) { if(fileItem.isFormField()) { map.put(fileItem.getFieldName(), fileItem.getString("UTF-8")); } } Book book = CommonUtils.toBean(map, Book.class); // 为book指定bid book.setBid(CommonUtils.uuid()); /* * 需要把Map中的cid封装到Category对象中,再把Category赋给Book */ Category category = CommonUtils.toBean(map, Category.class); book.setCategory(category); /* * 2. 保存上传的文件 * * 保存的目录 * * 保存的文件名称 */ // 得到保存的目录 String savepath = this.getServletContext().getRealPath("/book_img"); // 得到文件名称:给原来文件名称添加uuid前缀!避免文件名冲突 String filename = CommonUtils.uuid() + "_" + fileItemList.get(1).getName(); /* * 校验文件的扩展名 */ if(!filename.toLowerCase().endsWith("jpg")) { request.setAttribute("msg", "您上传的图片不是JPG扩展名!"); request.setAttribute("categoryList", categoryService.findAll()); request.getRequestDispatcher("/adminjsps/admin/book/add.jsp") .forward(request, response); return; } // 使用目录和文件名称创建目标文件 File destFile = new File(savepath, filename); // 保存上传文件到目标文件位置 fileItemList.get(1).write(destFile); /* * 3. 设置Book对象的image,即把图片的路径设置给Book的image */ book.setImage("book_img/" + filename); /* * 4. 使用BookService完成保存 */ bookService.add(book); /* * 校验图片的尺寸 */ Image image = new ImageIcon(destFile.getAbsolutePath()).getImage(); if(image.getWidth(null) > 200 || image.getHeight(null) > 200) { destFile.delete();//删除这个文件! request.setAttribute("msg", "您上传的图片尺寸超出了200 * 200!"); request.setAttribute("categoryList", categoryService.findAll()); request.getRequestDispatcher("/adminjsps/admin/book/add.jsp") .forward(request, response); return; } /* * 5. 返回到图书列表 */ request.getRequestDispatcher("/admin/AdminBookServlet?method=findAll") .forward(request, response); } catch (Exception e) { if(e instanceof FileUploadBase.FileSizeLimitExceededException) { request.setAttribute("msg", "您上传的文件超出了15KB"); request.setAttribute("categoryList", categoryService.findAll()); request.getRequestDispatcher("/adminjsps/admin/book/add.jsp") .forward(request, response); } } } }
删除图书
book表与orderitem有关联关系
删除图书不是真的数据库表中删除记录,而是给book表添加一个del字段,它是booleanod类型,表示是否已删除
没有被删除的图书,该列的值为false,否则为true
需要处理前台已写过的代码:
*修改BookDao:所有与查询相关的方法,都需要添加where条件,即del=false
*修改Book类,添加del属性
*数据库表增加del字段 boolean类型
删除图书:其实就是把表的del列修改为true
desc.jsp(del按钮)→
AdminBookServlet#del()
*获取bid
*调用service方法完成删除
*返回列表,即调用findAll()
编辑图书
dsec.jsp(编辑按钮)→
AdminBookServlet#edit()
*封装表单数据
*调用service方法
*return findAll()
代码jsp
同一表单 多个按钮(编辑,删除) 利用JS
使不同的按钮提交到不同的servlet方法
<script type="text/javascript"> function setMethod(method) { var ele = document.getElementById("method"); ele.value = method; } </script> </head> <body> <div> <img src="<c:url value='/${book.image }'/>" border="0"/> </div> <form style="margin:20px;" id="form" action="<c:url value='/admin/AdminBookServlet'/>" method="post"> <input type="hidden" name="method" value="" id="method"/> <input type="hidden" name="bid" value="${book.bid }"/> <input type="hidden" name="image" value="${book.image }"/> 图书名称:<input type="text" name="bname" value="${book.bname }"/><br/> 图书单价:<input type="text" name="price" value="${book.price }"/>元<br/> 图书作者:<input type="text" name="author" value="${book.author }"/><br/> 图书分类:<select style="width: 150px; height: 20px;" name="cid"> <c:forEach items="${categoryList }" var="c"> <option value="${c.cid }" <c:if test="${c.cid eq book.category.cid }">selected="selected"</c:if> >${c.cname }</option> </c:forEach> </select><br/> <input type="submit" value="删除" onclick="setMethod('delete')"/> <input type="submit" value="编辑" onclick="setMethod('edit')"/> </form> </body>
代码servlet
public class AdminBookServlet extends BaseServlet { private BookService bookService = new BookService(); private CategoryService categoryService = new CategoryService(); /** * 添加图书 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String addPre(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * 查询所有分类,保存到request,转发到add.jsp * add.jsp中把所有的分类使用下拉列表显示在表单中 */ request.setAttribute("categoryList", categoryService.findAll()); return "f:/adminjsps/admin/book/add.jsp"; } public String load(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * 1. 获取参数bid,通过bid调用service方法得到Book对象 * 2. 获取所有分类,保存到request域中 * 3. 保存book到request域中,转发到desc.jsp */ request.setAttribute("book", bookService.load(request.getParameter("bid"))); request.setAttribute("categoryList", categoryService.findAll()); return "f:/adminjsps/admin/book/desc.jsp"; } /** * 查看所有图书 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setAttribute("bookList", bookService.findAll()); return "f:/adminjsps/admin/book/list.jsp"; } /** * 删除图书 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String bid = request.getParameter("bid"); bookService.delete(bid); return findAll(request, response); } /** * 修改图书 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Book book = CommonUtils.toBean(request.getParameterMap(), Book.class); Category category = CommonUtils.toBean(request.getParameterMap(), Category.class); book.setCategory(category); bookService.edit(book); return findAll(request, response); } }
前台登陆过滤
访问前需要过滤资源
jsps/cart/*
jsps/order/*
CartServlet
OrderServlet
判断session ,是否存在user, 放行chain.doFilter(request, response)
public class LoginFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { /* * 1. 从session中获取用户信息 * 2. 判断如题session中存在用户信息,放行! * 3. 否则,保存错误信息,转发到login.jsp显示 */ HttpServletRequest httpRequest = (HttpServletRequest) request; User user = (User)httpRequest.getSession().getAttribute("session_user"); if(user != null) { chain.doFilter(request, response); } else { httpRequest.setAttribute("msg", "您还没有登录!"); httpRequest.getRequestDispatcher("/jsps/user/login.jsp") .forward(httpRequest, response); } } public void init(FilterConfig fConfig) throws ServletException { } }