day5--后台管理模块开发
1.模块分析
案例1-后台所有分类展示
需求: 在左侧的树上上添加一个连接 "分类列表",点击分类列表 将所有的分类展示在右边的主页面上
步骤分析:
1.在left.jsp上添加一个连接 父节点"分类管理",在分类管理下面添加一个子节点"分类列表"
连接: /store/adminCategory?method=findAll
2.编写adminCategoryservlet,继承baseservlet,编写findAll方法
调用service 查询所有分类,返回值:List<Category>
请求转发 /admin/category/list.jsp
d-tree用法:
1.项目中和页面中导入dtree.js
2.项目中和页面中导入dtree.css
3.在页面中创建一个div,添加样式 class="dtree"
4.在div中编写js代码 创建一个树d = new dTree('d');
添加节点
方法及参数说明:
d.add(当前节点id,父节点id,显示名称,点击时候打开的连接,放上去显示的名称,在那个地方打开这个连接)
添加根节点
根节点的父节点的id为-1
添加其他节点
5.最后通过document.write(d) 写到页面上即可
6.例子: d = new dTree('d');
d.add('01',-1,'系统菜单树');
d.add('0102','01','分类管理','','','mainFrame');
d.add('010201','0102','分类列表','${pageContext.request.contextPath}/adminCategory?method=findAll','','mainFrame');
d.add('010202','0102','添加分类','${pageContext.request.contextPath}/adminCategory?method=addUI','','mainFrame');
d.add('0104','01','商品管理');
d.add('010401','0104','已上架商品列表','${pageContext.request.contextPath}/adminProduct?method=findAll','','mainFrame');
d.add('010402','0104','添加商品','${pageContext.request.contextPath}/adminProduct?method=addUI','','mainFrame');
d.add('0105','01','订单管理');
d.add('010501','0105','订单管理','${pageContext.request.contextPath}/adminOrder_findAll.action?page=1','','mainFrame');
document.write(d);
<!--id Number 唯一的ID号
pid Number 判定父节点的数字,根节点的值为
name String 节点的文本标签
url String 节点的Url
title String 节点的Title
target String 节点的target
icon String 用做节点的图标,节点没有指定图标时使用默认值
iconOpen String 用做节点打开的图标,节点没有指定图标时使用默认值
open Boolean 判断节点是否打开 -->
案例2-后台添加分类
需求:
在一个表单页面中,输入分类名称,点击保存,将分类保存到数据库
步骤分析:
1.在left.jsp上添加一个连接 "添加分类" /store/adminCategory?method=addUI
2.在admincategoryservlet下编写addUI方法 请求转发到 /admin/category/add.jsp
3.修改add.jsp, action:/store/adminCategory?method=save
给分类input标签添加name属性
4,点击保存,发送 adminCategory一个请求 请求方法:save
获取cname,设置cid
封装category对象
调用service完成添加操作
重定向到分类列表页面
5.service 调用dao保存
更新redis中数据(清空redis中该条记录)
案例3-后台展示所有商品
需求: 点击左边树上的一个连接 "已上架商品列表",在右边的主页面上展示所有的商品
步骤分析:
1.在left.jsp上添加一个连接 "已上架商品列表", /store/adminProduct?method=findAll
2.编写adminProductServlet,继承baseservlet,编写findAll方法
调用service,获取所有的已上架的商品信息 返回值:list
将list放入reque st中,请求转发 /admin/product/list.jsp
案例4-后台添加商品
需求:
有一个商品的表单页面,填写商品信息,选择商品的图片,点击保存,将商品的信息保存到数据库中和web服务器上
技术分析:
文件上传: 就是将客户端的数据发送到服务器上
文件上传要求:
浏览器端要求:
1.表单提交方式 post
2.提供文件上传框(组件) input type="file"
3.表单entype属性必须为 multipart/form-data
服务器端要求: request.getInputStream()
注意:
若表单使用了 multipart/form-data ,使用原生request去获取参数的时候都为null
使用工具类或者框架去解析用户上传的内容
commons -fileupload
struts(底层:commons-fileupload)
serlvet 3.0
apache出品的一款专门处理文件上传的工具类 commons-fileupload
使用步骤:
1.导入jar包
2.创建磁盘文件项工厂
DiskFileItemFactory factory=new DiskFileItemFactory();
3.创建核心上传对象
ServletFileUpload upload=new ServletFileUpload(factory);
4.解析请求,获取所有的上传组件 List<FileItem>
List<FileItem> list=upload.parseRequest(request);
5.遍历list 获取每一个上传项
getFiledName():获取标签name属性的值
isFormFiled():判断是否是普通上传 组件
true:普通上传组件
false:文件上传组件 <input type="file">
普通上传组件
getString("utf-8"):获取用户输入的内容
文件上传组件
getName():文件 名称
getInputStream():获取文件的流
delete():删除文件上传时候产生的临时文件
上传注意问题:
1.文件名称 浏览器不同,有可能获取的名称不同, 1.txt 或者 G:1.txt
2.文件重名 给文件来一个随机名称
uuid方式 毫米值+三个随机数
数据库中可以存放多个字段: 文件名称和文件路径
文件名称:身份证正面.jpg
文件路径:g:123123123423sfsf.jpg
文件下载:
response.setHeader("content-disposition","attachment;filename="+真实名称);
3.文件安全(fastDFS)
安全目录:web-inf meta-inf 项目之外的目录
不安全目录:项目目录(除去web-inf和meta-inf)
4.目录分离 常用的方式:
按用户划分 按时间划分 按数量划分 随机划分
步骤分析:
1.在left.jsp上添加一个连接,"添加商品",点击他,在主页面上打开一个表单页面
/store/adminProduct?method=addUI
2.在adminproductserlvet中编写addUI方法
调用categoryservice查询所有的分类 findList
请求转发到 /admin/product/add.jsp
分类信息没有查询出来:
方式1:同步 方式2:异步
3.编辑表单页面 action: /store/addProduct method:post entype:multipart/form-data
给所有的子标签添加name属性 点击保存,向addProductServlet发送请求
4.编写addProductServlet
封装prodcut对象
让product的所有字段都有值
将product的图片保存到服务器
以前使用beanUtils.populate(Product bean,Map map);
但是现在request.getParameterMap不好使,若还想使用上面的方法封装对象,
我们需要创建一个map 且map中存放product对象的信息
Map<String 字段名,Object 值> map
字段名: getFieldName()
值:getString("utf-8");
除了图片
将图片通过commons-fileupload保存到服务器上
将图片的路径 put到map中
调用service保存商品
重定向到商品列表页面
5.service dao
注意: 图片目录 保存 备份
2.代码区
<%@ page language="java" pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>菜单</title> <link href="${pageContext.request.contextPath}/css/left.css" rel="stylesheet" type="text/css"/> <link rel="StyleSheet" href="${pageContext.request.contextPath}/css/dtree.css" type="text/css" /> </head> <body> <table width="100" border="0" cellspacing="0" cellpadding="0"> <tr> <td height="12"></td> </tr> </table> <table width="100%" border="0"> <tr> <td> <div class="dtree"> <a href="javascript: d.openAll();">展开所有</a> | <a href="javascript: d.closeAll();">关闭所有</a> <script type="text/javascript" src="${pageContext.request.contextPath}/js/dtree.js"></script> <script type="text/javascript"> d = new dTree('d'); d.add('01',-1,'系统菜单树'); d.add('0102','01','分类管理','','','mainFrame'); d.add('010201','0102','分类列表','${pageContext.request.contextPath}/adminCategory?method=findAll','','mainFrame'); d.add('010202','0102','添加分类','${pageContext.request.contextPath}/adminCategory?method=addUI','','mainFrame'); d.add('0104','01','商品管理'); d.add('010401','0104','已上架商品列表','${pageContext.request.contextPath}/adminProduct?method=findAll','','mainFrame'); d.add('010402','0104','添加商品','${pageContext.request.contextPath}/adminProduct?method=addUI','','mainFrame'); d.add('0105','01','订单管理'); d.add('010501','0105','订单管理','${pageContext.request.contextPath}/adminOrder_findAll.action?page=1','','mainFrame'); document.write(d); </script> </div> </td> </tr> </table> </body> </html> <!--id Number 唯一的ID号 pid Number 判定父节点的数字,根节点的值为 name String 节点的文本标签 url String 节点的Url title String 节点的Title target String 节点的target icon String 用做节点的图标,节点没有指定图标时使用默认值 iconOpen String 用做节点打开的图标,节点没有指定图标时使用默认值 open Boolean 判断节点是否打开 -->
<%@ page language="java" pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Language" content="zh-cn"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style> body { SCROLLBAR-ARROW-COLOR: #ffffff; SCROLLBAR-BASE-COLOR: #dee3f7; } </style> </head> <frameset rows="103,*,43" frameborder=0 border="0" framespacing="0"> <frame src="${pageContext.request.contextPath}/admin/top.jsp" name="topFrame" scrolling="NO" noresize> <frameset cols="159,*" frameborder="0" border="0" framespacing="0"> <frame src="${pageContext.request.contextPath}/admin/left.jsp" name="leftFrame" noresize scrolling="YES"> <frame src="${pageContext.request.contextPath}/admin/welcome.jsp" name="mainFrame"> </frameset> <frame src="${pageContext.request.contextPath}/admin/bottom.jsp" name="bottomFrame" scrolling="NO" noresize> </frameset> </html>
package com.itheima.web.servlet; import java.io.IOException; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.itheima.domain.Category; import com.itheima.service.CategoryService; import com.itheima.utils.BeanFactory; import com.itheima.utils.UUIDUtils; import com.itheima.web.servlet.base.BaseServlet; /** * 后台分类管理模块 */ public class AdminCategoryServlet extends BaseServlet { private static final long serialVersionUID = 1L; /** * 添加分类 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String save(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { //1.封装category对象 Category c = new Category(); c.setCid(UUIDUtils.getId()); c.setCname(request.getParameter("cname")); //2.调用service完成添加操作 CategoryService cs = (CategoryService) BeanFactory.getBean("CategoryService"); cs.save(c); //3.重定向 response.sendRedirect(request.getContextPath()+"/adminCategory?method=findAll"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(); } return null; } /** * 跳转到添加页面 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String addUI(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { return "/admin/category/add.jsp"; } /** * 展示所有分类 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { //1.调用service 获取所有的分类 CategoryService cs = (CategoryService) BeanFactory.getBean("CategoryService"); List<Category> list=cs.findList(); //2.将返回值放入request域中 请求转发 request.setAttribute("list", list); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(); } return "/admin/category/list.jsp"; } }
package com.itheima.web.servlet; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.IOUtils; import com.itheima.constant.Constant; import com.itheima.domain.Category; import com.itheima.domain.Product; import com.itheima.service.ProductService; import com.itheima.utils.BeanFactory; import com.itheima.utils.UUIDUtils; import com.itheima.utils.UploadUtils; /** * 保存商品 */ public class AddProductServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { //0.使用fileuload保存图片和将商品的信息放入map中 //0.1 创建map 存放商品的信息 Map<String,Object> map=new HashMap<>(); //0.2 创建磁盘文件项工厂 (设置临时文件的大小和位置) DiskFileItemFactory factory = new DiskFileItemFactory(); //0.3 创建核心上传对象 ServletFileUpload upload = new ServletFileUpload(factory); //0.4 解析request List<FileItem> list = upload.parseRequest(request); //0.5遍历list 获取每一个文件项 for (FileItem fi : list) { //0.6获取name属性值 String key = fi.getFieldName(); //0.7判断是否是普通的上传组件 if(fi.isFormField()){ //普通 map.put(key, fi.getString("utf-8")); }else{ //文件 //a.获取文件的名称 1.jpg String name = fi.getName(); //b.获取文件真实名称 1.jpg String realName = UploadUtils.getRealName(name); //c.获取文件的随机名称 12312312434234.jpg String uuidName = UploadUtils.getUUIDName(realName); //d.获取随机目录 /a/3 String dir = UploadUtils.getDir(); //e.获取文件内容(输入流) InputStream is = fi.getInputStream(); //f.创建输出流 //获取products目录的真实路径 String productPath = getServletContext().getRealPath("/products"); //创建随机目录 File dirFile = new File(productPath,dir); if(!dirFile.exists()){ dirFile.mkdirs(); } // d:/tomcat/webapps/store/prouduct/a/3/12312312434234.jpg FileOutputStream os = new FileOutputStream(new File(dirFile,uuidName)); //g.对拷流 IOUtils.copy(is, os); //h.释放资源 os.close(); is.close(); //i.删除临时文件 fi.delete(); //j.将商品的路径放入map中 prouduct/a/3/12312312434234.jpg map.put(key, "products"+dir+"/"+uuidName); } } //1.封装product对象 Product p = new Product(); //1.1.手动设置 pid map.put("pid", UUIDUtils.getId()); //1.2.手动设置 pdate map.put("pdate", new Date()); //1.3.手动设置 pflag 上架 map.put("pflag", Constant.PRODUCT_IS_UP); //1.4.使用beanutils封装 BeanUtils.populate(p, map); //1.5.手动设置 category Category c = new Category(); c.setCid((String)map.get("cid")); p.setCategory(c); //2.调用service 完成保存 ProductService ps = (ProductService) BeanFactory.getBean("ProductService"); ps.save(p); //3.重定向 response.sendRedirect(request.getContextPath()+"/adminProduct?method=findAll"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("保存商品失败"); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
package com.itheima.utils; import java.util.Random; import java.util.UUID; public class UploadUtils { /** * 获取文件真实名称 * 由于浏览器的不同获取的名称可能为:c:/upload/1.jpg或者1.jpg * 最终获取的为 1.jpg * @param name 上传上来的文件名称 * @return 真实名称 */ public static String getRealName(String name){ //获取最后一个"/" int index = name.lastIndexOf("\"); return name.substring(index+1); } /** * 获取随机名称 * @param realName 真实名称 * @return uuid 随机名称 */ public static String getUUIDName(String realName){ //realname 可能是 1.jpg 也可能是 1 //获取后缀名 int index = realName.lastIndexOf("."); if(index==-1){ return UUID.randomUUID().toString().replace("-", "").toUpperCase(); }else{ return UUID.randomUUID().toString().replace("-", "").toUpperCase()+realName.substring(index); } } /** * 获取文件目录,可以获取256个随机目录 * @return 随机目录 */ public static String getDir(){ String s="0123456789ABCDEF"; Random r = new Random(); return "/"+s.charAt(r.nextInt(16))+"/"+s.charAt(r.nextInt(16)); } public static void main(String[] args) { //String s="G:\day17-基础加强\resource\1.jpg"; String s="1"; String realName = getRealName(s); System.out.println(realName); String uuidName = getUUIDName(realName); System.out.println(uuidName); String dir = getDir(); System.out.println(dir); } }