Web项目系列文章推荐: |
---|
👉 JavaWeb企业实战项目(一):环境搭建-用户注册-邮件发送 |
👉 JavaWeb企业实战项目(二):用户登录-首页详情-商品分类 |
👉 JavaWeb企业实战项目(三):商品模块 |
👉 JavaWeb企业实战项目(四):订单模块 |
👉 JavaWeb企业实战项目(六):后台模块2 |
👉 待更新 |
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();
}
}