JavaWeb企业实战项目(五):后台模块1

1、任务总述

1、权限过滤器
2、查询所有分类
3、修改分类信息
4、查询商品信息
5、上传商品信息(重点)
6、利用工厂模式解耦

2、权限过滤器

应用场景:
  项目运行过程,希望某些资源不能被用户直接访问到,只有登录后才可以访问。例如:购物车页面,购物详情,购物列表等资源
解决方案:
  创建一个自定义过滤器,在过滤器中为这些资源分别配置好路径,在过滤器中判断用户是否登录。登录成功,放行;没有登录,返回提示信息并转发到提示页面
步骤实现:
  1、创建过滤器,为过滤器配置不同的路径
  2、实现过滤器代码
  PS:一个过滤器可以配置不同的路径

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
	//将request转成HttpServletRequest
	HttpServletRequest myReq = (HttpServletRequest)request;
	//获取当前session中的user数据
	User user = (User)myReq.getSession().getAttribute("userinfo");
	//如果用户存在直接放行.不存在跳转并提示
	if(user!=null){
		chain.doFilter(request, response);
	}else{
		String msg = "请先登录之后再访问!";
		request.setAttribute("msg", msg);
		myReq.getRequestDispatcher("/jsp/info.jsp").forward(request, response);
	}
}

3、查看所有分类

复习frameset框架:
其中frameset中的rows是Y轴分布切割,cols是X轴分布切割

<frameset rows="30%,60%,*">
	<frame src="work3/input.jsp">
	<frameset cols="50%,50%">
		<frame src="work2/carDemo1.jsp">
		<frame src="work2/carDemo2.jsp">
	</frameset>
	<frame src="6_2.jsp">
</frameset>

dtree组件:
由JS实现树形菜单组件,开源免费,使用简单
如何使用
1、导入dtree.js
2、导入dtree.css
3、导入dtree下所有的图片
4、在页面中实现以下语句

var d=new dTree(“d”);
d.openAll();  d.closeAll();
//param1: 当前节点id
//param2: 父节点id
//param3: 节点上的文字描述
//param4: 跳转路径
//param5: 提示信息
//param6: 发生变化的frame的name属性值
d.add('010201','0102','分类管理’,'${pageContext.request.contextPath}/admin/category/list.jsp','','mainFrame');

查看所有分类原理分析:
查看所有分类
步骤实现:
1、准备工作
  *_创建AdminCategoryServlet
  *_修改链接 left.jsp
  d.add('010201','0102','分类管理','${pageContext.request.contextPath}/AdminCategoryServlet?method=findAllCats','','mainFrame');
2、AdminCategoryServlet -> findAllCats

public String findAllCats(HttpServletRequest request, HttpServletResponse response) throws Exception {
	//调用业务成对象并获取所有分类
	CategoryService service = new CategoryServiceImpl();
	List<Category> allCats = service.getAllCats();
	//将全部分类信息放入request
	request.setAttribute("allCats", allCats);
	//转发到/admin/category/list.jsp
	return "/admin/category/list.jsp";
}

3、service&dao(之前就实现过category的业务层和dao层了)
4、在/admin/category/list.jsp获取分类信息,完成响应
  选中标签元素Ctrl+K跳到对应尾标签

<c:forEach items="${allCats}" var="c" varStatus="status">
	<tr onmouseover="this.style.backgroundColor = 'white'"
		onmouseout="this.style.backgroundColor = '#F5FAFE';">
		<td style="CURSOR: hand; HEIGHT: 22px" align="center"
			width="18%">
			${status.count}
		</td>
		<td style="CURSOR: hand; HEIGHT: 22px" align="center"
			width="17%">
			${c.cname}
		</td>
		<td align="center" style="HEIGHT: 22px">
			<a href="edit.jsp">
				<img src="${pageContext.request.contextPath}/img/admin/i_edit.gif" border="0" style="CURSOR: hand">
			</a>
		</td>

		<td align="center" style="HEIGHT: 22px">
			<a href="#">
				<img src="${pageContext.request.contextPath}/img/admin/i_del.gif" width="16" height="16" border="0" style="CURSOR: hand">
			</a>
		</td>
	</tr>
</c:forEach>

4、添加分类信息

页面跳转:
1、/admin/category/list.jsp js函数addCategory:
  window.location.href = "${pageContext.request.contextPath}/AdminCategoryServlet?method=addCategoryUI";
2、
/AdminCategoryServlet -> addCategoryUI
  return “/admin/category/add.jsp”;
原理分析:
添加分类信息
步骤实现:
1、/admin/category/add.jsp
  设置form -> method,action
  设置form表单下各种input标签的name属性
2、AdminCategoryServlet -> addCategory

public String addCategory(HttpServletRequest request, HttpServletResponse response) throws Exception {
	//获取到分类名称cname
	String cname = request.getParameter("cname");
	//创建分类ID,并设置分类对象的属性
	Category category = new Category();
	category.setCname(cname);
	category.setCid(UUIDUtils.getId());
	//调用业务层添加分类功能
	CategoryService service = new CategoryServiceImpl();
	service.addCategory(category);
	//重定向到查询全部分类信息
	response.sendRedirect("/store_v5/AdminCategoryServlet?method=findAllCats");
	return null;
}

3、CategoryService -> CategoryDaoImp

@Override
public void addCategory(Category category) throws SQLException {
	dao.addCategory(category);
	Jedis jedis = JedisUtils.getJedis();
	jedis.del("allCats");
	JedisUtils.closeJedis(jedis);
}

PS:在CategoryService及时更新redis中缓存的信息
总结:虽然使用redis可以提升项目性能,但是带来开发量. 开发中,如果对redis缓存中的数据发生了更新操作,及时更新redis缓存信息,否则会造成数据不统一问题.
删除分类思路:
问题:删除分类的时候,由于分类被很多商品所参照,无法删除
解决方案1
  先删除所有向关联的商品信息,删除分类
解决方案2
  设置所有的商品上cid列的值为null/其他分类ID
解决方案3
  设计分类表多增加一个列(有效/无效)

5、查看商品信息

原理分析:
查看商品信息
步骤实现:
1、修改连接 left.jsp 中商品管理分类的跳转链接
d.add('010401','0104','商品管理', '/store_v5/AdminProductServlet?method=findAllProductsWithPage&num=1', '提示信息','mainFrame');
2、AdminProductServlet -> findAllProductsWithPage

public String findAllProductsWithPage(HttpServletRequest request, HttpServletResponse response) throws Exception {
	//request获取当前页
	String curPage = request.getParameter("num");
	//调用业务层查看全部商品信息返回PageModel
	ProductService service = new ProductServiceImpl();
	PageModel pageModel = service.findAllProductsWithPage(Integer.parseInt(curPage));
	//将pageModel放入request中并转发到admin/product/list.jsp
	request.setAttribute("page", pageModel);
	return "/admin/product/list.jsp";
}

3、ProductService

@Override
public PageModel findAllProductsWithPage(int curPage) throws SQLException {
	int totalRecords = dao.getAllProductsNum();
	//创建PageModel对象
	PageModel pm = new PageModel(curPage, totalRecords, 6);
	//关联url和集合
	pm.setUrl("AdminProductServlet?method=findAllProductsWithPage");
	pm.setList(dao.findAllProductsWithPage(pm.getStartIndex(),pm.getPageSize()));
	return pm;
}

4、/admin/product/list.jsp获取商品信息和分页数据

6、上传商品信息原理分析

上传的准备工作:
1、表单method 必须为post
2、提供file组件
3、设置form标签的enctype属性为multipart/form-data
  如果没有设置enctype浏览器是无法将文件自身传递到服务端
分析上传时HTTP协议的格式:
POST 目标路径 HTTP/1.1 + 请求头 + 请求体
测试(JSP文件):

<form action="TestUpload" enctype="multipart/form-data" method="post">
	name:<input type="text" name="name">
	file:<input type="file" name="file">
	<input type="submit">
</form>

测试(TestUpload文件):

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	request.setCharacterEncoding("utf-8");
	ServletInputStream inputStream = request.getInputStream();
	int read = -1;
	while((read = inputStream.read())!=-1){
		char c = (char)read;
		System.out.print(c);
	}
}

测试结果大致如下:
-----------------------------7e4b316306d8 为分割线,分割线之间为每个具体数据
-----------------------------7e4b316306d8-- 为结尾分割线
测试结果
测试结论:
1、如果设置了表单form标签的enctype属性之后,请求体部分的内容的格式发生更改
2、如果设置了mutipart/form-data,在服务端是无法通过request.getParameter(name);获取数据,因为getParameter是典型的获取键值对数据类型(以普通字符流传输),而mutipart/form-data则是用字节流传输(传输文件)
3、可以通过request.getInputStream();获取请求体部分的数据,手动实现上传功能是可行的

7、实现上传商品信息

实现思路:
1、导入commons-fileupload-1.2.1.rar之后
2、执行很简单的3行语句(包括第三步)
3、获取到一个集合(对象)
  将每对分割线中间的内容封装在FileItem对象上.
4、遍历集合
5、如果当前的FileItem对象是普通项
  将普通项上name属性的值作为键,将获取到的内容作为值,放入MAP{username<==>tom,password<==>1234}
6、如果当前的FileItem对象是上传项
  通过FileItem获取到输入流对象,通过输入流可以获取到图片二进制数据
  在服务端创建一个空文件(后缀必须和上传到服务端的文件名后缀一致)
  建立和空文件对应的输出流
  将输入流中的数据刷到输出流中
  释放资源
  向map中存入一个键值对的数据userhead<===>/image/11.bmp {username<==>tom,password<==>1234,userhead<===>image/11.bmp}
7、利用BeanUtils将MAP中的数据填充到user对象上
8、调用servcie_dao将user上携带的数据存入数据仓库,重定向到查询全部商品信息路径
出现问题:
1、如果文件重名发生覆盖问题
  UUID
2、同目录下文件/目录过多,性能问题
  在images下最多创建16个目录,任意一个目录进入之后最多创建16个目录,最多创建8层目录。可以创建16^8个目录
实现代码:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	request.setCharacterEncoding("utf-8");
	/*ServletInputStream inputStream = request.getInputStream();
	int read = -1;
	while((read = inputStream.read())!=-1){
		char c = (char)read;
		System.out.print(c);
	}*/
	try {
		//1、执行File3行语句
		DiskFileItemFactory factory = new DiskFileItemFactory();
		ServletFileUpload fileUpload = new ServletFileUpload(factory);
		//2、获取到每一个集合(对象)、创建map、Test
		List<FileItem> items = fileUpload.parseRequest(request);
		Map<String, String> map = new HashMap<String,String>();
		Test user = new Test();
		//3、遍历集合
		for (FileItem fileItem : items) {
			if(fileItem.isFormField()){//4、当前的Fileitem对象是普通项
				//将普通项上name属性作为建,将获取到的内容作为值,放入
				map.put(fileItem.getFieldName(), fileItem.getString("utf-8"));
			}else{//5、当前的Fileitem为上传项
				//通过Fileitem获取到输入流对象,通过输入流对象获得二进制数据
				InputStream is = fileItem.getInputStream();
				//获得一个项目工程的图片目录=路径
				String dirPath = getServletContext().getRealPath("/img/");
				//获取文件名(个别浏览器返回文件绝对路径,需处理)
				String fileName = fileItem.getName();
				int index = fileName.lastIndexOf("\\");//获取到最后的'\'下标
				if(index != -1){fileName = fileName.substring(index+1);}//如果存在'\',则截取最后文件名
				//System.out.println(dirPath+"\\"+fileName);	//测试输出
				//在服务端创建一个空文件
				File file = new File(dirPath, fileName);
				if(!file.exists()){file.createNewFile();}
				//创建和空文件对应的输出流
				OutputStream os = new FileOutputStream(file);
				//将输入流中的数据刷到输出流中
				IOUtils.copy(is, os);
				//释放资源
				IOUtils.closeQuietly(is);
				IOUtils.closeQuietly(os);
				//向map中存入一个键值对的数据
				map.put(fileItem.getFieldName(), file.getPath());
			}
		}
		//6、利用BeanUtils将Map中的数据填充到user对象上
		BeanUtils.populate(user, map);
	} catch (Exception e) {
		e.printStackTrace();
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章