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 判断节点是否打开 -->
left.jsp
<%@ 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>
home.jsp
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";
}
}
AdminCategoryServlet 后台分类管理模块
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);
}
}
AddProductServlet 保存商品
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);
}
}
UploadUtils