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();
}
}