擼完了登錄模塊,接着擼商品添加,和商品列表模塊:
先亮出數據庫:

1 DROP TABLE IF EXISTS products; 2 CREATE TABLE products ( 3 id varchar(100) NOT NULL, 4 name varchar(100) DEFAULT NULL, 5 price double DEFAULT NULL, 6 category varchar(100) DEFAULT NULL, 7 pnum int(11) DEFAULT NULL, 8 description varchar(255) DEFAULT NULL, 9 imageurl varchar(255) DEFAULT NULL, 10 PRIMARY KEY (id) 11 )
一,商品展示頁涉及到商品的名稱,圖片,價格,庫存等信息,這里上傳功能主要涉及到的就是商品圖片上傳功能.這里需要導入commons-fileupload-1.2.1.jar,commons-io-1.4.jar兩個包.
下面是上傳頁面的jsp代碼:

1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <script type="text/javascript"> 6 7 function validateRequired(fieldName){ 8 9 var obj = document.getElementById(fieldName).value; 10 if(obj==""){ 11 document.getElementById(fieldName +"_msg").innerHTML = "<span style='color: red'>"+fieldName+"不能為空</span>"; 12 return false; 13 }else{ 14 document.getElementById(fieldName +"_msg").innerHTML = ""; 15 return true; 16 } 17 } 18 19 </script> 20 </head> 21 22 23 <body> 24 <h3>添加商品的頁面</h3> 25 <form method="post" enctype="multipart/form-data" action="${pageContext.request.contextPath}/add"><!-- enctype:設置表達的mime編碼為文件上傳 --> 26 <table> 27 <tr> 28 <td>商品名稱</td> 29 <td> 30 <input type="text" name="name" id="name"> 31 </td> 32 <td id="name_msg"></td> 33 </tr> 34 <tr> 35 <td>商品價格</td> 36 <td> 37 <input type="text" name="price" id="price"> 38 </td> 39 <td id="price_msg"></td> 40 </tr> 41 <tr> 42 <td>商品數量</td> 43 <td> 44 <input type="text" name="pnum" id="pnum"> 45 </td> 46 <td id="pnum_msg"></td> 47 </tr> 48 <tr> 49 <td>商品種類</td> 50 <td> 51 <select name="category"> 52 <option value="圖書、音像、數字商品">圖書、音像、數字商品</option> 53 <option value="手機、數碼、京東通信">手機、數碼、京東通信</option> 54 <option value="電腦、辦公">電腦、辦公</option> 55 <option value="服飾內衣、珠寶首飾">服飾內衣、珠寶首飾</option> 56 </select> 57 </td> 58 <td id="category_msg"></td> 59 </tr> 60 61 <tr> 62 <td>商品圖片</td> 63 <td> 64 <input type="file" name="imageurl" id="imageurl"> 65 </td> 66 <td id="imageurl_msg"></td> 67 </tr> 68 <tr> 69 <td>商品描述</td> 70 <td> 71 <textarea rows="5" cols="80" name="description"></textarea> 72 </td> 73 <td id="description_msg"></td> 74 </tr> 75 <tr> 76 <td colspan="3"> 77 <input type="submit" value="添加"> 78 </td> 79 </tr> 80 81 </table> 82 </form> 83 84 </body> 85 </html>
表單遞交到servlet后,做個三個操作:
1,判斷用戶提交的表單是不是文件上傳操作.
2,如果是文件上傳操作:我在utis包中創建了WebUtils工具類,對文件上傳行為進行操作最終返回Map,用於BeanUtils把表單數據綁定到數據實體中;
WebUtils對表單提交是數據進行判斷普通數據文本直接添加到map中,對文件上傳項(商品圖片)把文件保存到本地,然后把保存的路徑保存到map中.創建保存圖片的路徑是要注意:因為一般情況下造作系統中保存的文件個數超過一千時就會影響文件讀取的性能,所以這里在utils工具包中創建了UploadUtils工具類.其中包含了用hashcode來獲得不同的二級目錄,保證足夠的文件夾數來保存大量的圖片的方法,還有生成uuid給圖片命名的方法函數.
3,第二步獲得map綁定到數據實體中,然后執行增加操作.
首先是servlet類:

1 public void doPost(HttpServletRequest request, HttpServletResponse response) 2 throws ServletException, IOException { 3 //1,判斷是不是文件上傳 4 if(!ServletFileUpload.isMultipartContent(request)) 5 { 6 throw new MyRuntimeException("不是文件上傳操作......"); 7 } 8 //2,執行文件上傳 9 Map<String,String>map=WebUtils.doFileUpload(this.getServletContext().getRealPath("/upload"),request); 10 //3將數據封裝到商品bean中 11 Product p=new Product(); 12 try { 13 BeanUtils.populate(p, map); 14 } catch (IllegalAccessException e) { 15 16 e.printStackTrace(); 17 } catch (InvocationTargetException e) { 18 19 e.printStackTrace(); 20 } 21 //4調用業務層插入數據 22 ProductService ps=new ProductServiceImpl(); 23 ps.addProduct(p); 24 response.setContentType("text/html;charset=utf-8"); 25 response.getWriter().print("添加成功...<a href='"+request.getContextPath()+"/index.jsp'>返回</a>"); 26 } 27 }
WebUtils工具類:

1 public class WebUtils { 2 3 public static Map<String, String> doFileUpload(String realPath, 4 HttpServletRequest request) { 5 Map<String,String>map=new HashMap<String, String>(); 6 //拿到工廠類 7 DiskFileItemFactory factory=new DiskFileItemFactory(); 8 ServletFileUpload upload=new ServletFileUpload(factory); 9 upload.setHeaderEncoding("UTF-8");//解決中文名亂碼問題 10 try{ 11 List<FileItem>list=upload.parseRequest(request); 12 for(FileItem fileItem:list) 13 { 14 if(fileItem.isFormField()) 15 { 16 //普通輸入項 17 String name=fileItem.getFieldName(); 18 String value=fileItem.getString("utF-8"); 19 map.put(name, value); 20 } 21 else{ 22 //文件上傳項 23 String filename=fileItem.getName();//文件名可能是aa.txt 也可能是c: \ users \ aa.txt 24 //這兩種類型的名字,而我們需要的是aaa.txt這種格式的所以要進行過濾 25 int index=filename.lastIndexOf("\\"); 26 if(index!=-1) 27 { 28 filename=filename.substring(index+1); 29 } 30 //走到這里,文件名肯定是aa.txt形式的了 31 //生成唯一文件名 32 String uuidname=UploadUtils.generateRandonFileName(filename); 33 String randomDir=UploadUtils.generateRandomFileDir(uuidname);// / 1/ 5 34 String imageurl="/upload"+randomDir;// 相對工程根目錄的 文件夾 地址了 /upload/1/5/ 35 File file=new File(request.getSession().getServletContext().getRealPath(imageurl));//ServletContext.getRealPath(String virtual path),參數是虛擬路徑,返回值是real path 36 file.mkdirs();//創建路徑 37 InputStream in=fileItem.getInputStream(); 38 OutputStream out=new FileOutputStream(new File(file,uuidname)); 39 int len=0; 40 byte[] buf=new byte[1024]; 41 while((len=in.read(buf))>0) 42 { 43 out.write(buf, 0, len); 44 } 45 in.close(); 46 out.close(); 47 //刪除臨時文件 48 fileItem.delete(); 49 map.put("imageurl", imageurl+"/"+uuidname); 50 //圖片縮小工具 51 PicUtils pic=new PicUtils(new File(file,uuidname).getCanonicalPath()); 52 pic.resize(180,220); 53 } 54 } 55 return map; 56 } 57 catch(Exception e) 58 { 59 e.printStackTrace(); 60 throw new MyRuntimeException(e); 61 } 62 } 63 64 }
在WebUtils中吧圖片保存到文件夾中的時候,我順便使用了一工具類PicUtils把原圖片按照指定的尺寸縮小了一下圖片另存了一下,小圖片可以在首頁顯示,大圖片可以在商品詳細頁面中顯示.
PicUtils代碼:

1 /** 2 * 制作圖片縮略圖 3 * 4 * @author zhanglei 5 * 6 */ 7 public class PicUtils { 8 private String srcFile; 9 private String destFile; 10 private int width; 11 private int height; 12 private Image img; 13 14 /** 15 * 構造函數 16 * 17 * @param fileName 18 * String 19 * @throws IOException 20 */ 21 public PicUtils(String fileName) throws IOException { 22 File _file = new File(fileName); // 讀入文件 23 this.srcFile = fileName; 24 // 查找最后一個. 25 int index = this.srcFile.lastIndexOf("."); 26 String ext = this.srcFile.substring(index); 27 this.destFile = this.srcFile.substring(0, index) + "_s" + ext; 28 img = javax.imageio.ImageIO.read(_file); // 構造Image對象 29 width = img.getWidth(null); // 得到源圖寬 30 height = img.getHeight(null); // 得到源圖長 31 } 32 33 /** 34 * 強制壓縮/放大圖片到固定的大小 35 * 36 * @param w 37 * int 新寬度 38 * @param h 39 * int 新高度 40 * @throws IOException 41 */ 42 public void resize(int w, int h) throws IOException { 43 BufferedImage _image = new BufferedImage(w, h, 44 BufferedImage.TYPE_INT_RGB); 45 _image.getGraphics().drawImage(img, 0, 0, w, h, null); // 繪制縮小后的圖 46 FileOutputStream out = new FileOutputStream(destFile); // 輸出到文件流 47 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); 48 encoder.encode(_image); // 近JPEG編碼 49 out.close(); 50 } 51 52 /** 53 * 按照固定的比例縮放圖片 54 * 55 * @param t 56 * double 比例 57 * @throws IOException 58 */ 59 public void resize(double t) throws IOException { 60 int w = (int) (width * t); 61 int h = (int) (height * t); 62 resize(w, h); 63 } 64 65 /** 66 * 以寬度為基准,等比例放縮圖片 67 * 68 * @param w 69 * int 新寬度 70 * @throws IOException 71 */ 72 public void resizeByWidth(int w) throws IOException { 73 int h = (int) (height * w / width); 74 resize(w, h); 75 } 76 77 /** 78 * 以高度為基准,等比例縮放圖片 79 * 80 * @param h 81 * int 新高度 82 * @throws IOException 83 */ 84 public void resizeByHeight(int h) throws IOException { 85 int w = (int) (width * h / height); 86 resize(w, h); 87 } 88 89 /** 90 * 按照最大高度限制,生成最大的等比例縮略圖 91 * 92 * @param w 93 * int 最大寬度 94 * @param h 95 * int 最大高度 96 * @throws IOException 97 */ 98 public void resizeFix(int w, int h) throws IOException { 99 if (width / height > w / h) { 100 resizeByWidth(w); 101 } else { 102 resizeByHeight(h); 103 } 104 } 105 106 /** 107 * 設置目標文件名 setDestFile 108 * 109 * @param fileName 110 * String 文件名字符串 111 */ 112 public void setDestFile(String fileName) throws Exception { 113 if (!fileName.endsWith(".jpg")) { 114 throw new Exception("Dest File Must end with \".jpg\"."); 115 } 116 destFile = fileName; 117 } 118 119 /** 120 * 獲取目標文件名 getDestFile 121 */ 122 public String getDestFile() { 123 return destFile; 124 } 125 126 /** 127 * 獲取圖片原始寬度 getSrcWidth 128 */ 129 public int getSrcWidth() { 130 return width; 131 } 132 133 /** 134 * 獲取圖片原始高度 getSrcHeight 135 */ 136 public int getSrcHeight() { 137 return height; 138 } 139 }
UploadUtils工具類:

1 public class UploadUtils { 2 3 /* 4 * 獲得hashcode生成二級目錄 5 */ 6 public static String generateRandomFileDir(String uuidFileName) { 7 int hashCode=uuidFileName.hashCode(); 8 //一級目錄 9 int d1=hashCode&0xf; 10 //二級目錄 11 int d2=(hashCode>>4)&0xf; 12 return "/"+d1+"/"+d2; 13 } 14 //隨機生成uuid文件名 15 public static String generateRandonFileName(String filename) { 16 return UUID.randomUUID().toString()+filename.substring(filename.lastIndexOf(".")); 17 } 18 /* 19 * 將包含就對路徑是文件(c: \d\aa.txt) 返回 aa.txt 文件形式 20 */ 21 public static String subFileName(String fileName) 22 { 23 int index=fileName.lastIndexOf("\\"); 24 if(index!=-1) 25 { 26 fileName=fileName.substring(index+1); 27 } 28 return fileName; 29 } 30 }
添加商品的service層------
ProductService接口:

1 public interface ProductService { 2 3 void addProduct(Product p); 4 5 List<Product> getList(); 6 7 Product getProduct(Product p); 8 9 10 }
ProductServiceImpl類:

1 public class ProductServiceImpl implements ProductService { 2 3 ProductDao pDao=factory.DaoFactory.getInstance().createDao(ProductDao.class); 4 @Override 5 public void addProduct(Product p) { 6 pDao.insert(p); 7 } 8 @Override 9 public List<Product> getList() { 10 11 return pDao.getAll(); 12 } 13 @Override 14 public Product getProduct(Product p) { 15 return pDao.getProduct("id",p.getId()); 16 } 17 18 }
有沒有發現上面ProductServiceImpl類中是通過工廠的方式來獲取dao的,因為這也可以解耦.今天就不寫這個工廠了,放到明天寫.不用工廠,咱可以直接new一個出來就行了.明天寫了工廠在用工廠的方法獲dao;
ProductDaoImpl類的接口ProductDao:

1 public interface ProductDao { 2 3 void insert(Product p); 4 5 List<Product> getAll(); 6 7 Product getProduct(String string, String id); 8 9 void update(Connection connection, OrderItem odi)throws SQLException; 10 11 }
操作商品的ProductDaoImpl類:

1 public class ProductDaoImpl implements ProductDao { 2 3 //生成商品id 4 public String generateProducId(){ 5 6 String value = UUID.randomUUID().toString(); 7 8 int pid = Math.abs(value.hashCode()); 9 return "product-"+pid; 10 } 11 @Override//添加一個商品 12 public void insert(Product p) { 13 QueryRunner runner=new QueryRunner(JdbcUtils.getDataSource()); 14 String sql="insert into products values(?,?,?,?,?,?,?)"; 15 Object[] params={generateProducId(),p.getName(),p.getPrice(),p.getCategory(),p.getPnum(),p.getDescription(),p.getImageurl()}; 16 try { 17 runner.update(sql,params); 18 } catch (SQLException e) { 19 e.printStackTrace(); 20 throw new MyRuntimeException(e); 21 } 22 } 23 24 @Override//獲得商品列表 25 public List<Product> getAll() { 26 QueryRunner runner=new QueryRunner(JdbcUtils.getDataSource()); 27 try { 28 return runner.query("select * from products",new BeanListHandler<Product>(Product.class)); 29 } catch (SQLException e) { 30 e.printStackTrace(); 31 throw new MyRuntimeException(e); 32 } 33 } 34 @Override//通過條件key,獲取單個商品 35 public Product getProduct(String key, String value) { 36 QueryRunner runner=new QueryRunner(JdbcUtils.getDataSource()); 37 try { 38 return runner.query("select * from products where "+key+"=?",new BeanHandler<Product>(Product.class),value); 39 } catch (SQLException e) { 40 e.printStackTrace(); 41 throw new MyRuntimeException(e); 42 } 43 } 44 @Override//這里用於購買商品時,庫存減去購買的數量,最后一篇下單和在線購買中用到 45 public void update(Connection conn, OrderItem odi) throws SQLException { 46 //先獲得pnum 47 QueryRunner runner = new QueryRunner(); 48 String sql ="select pnum from products where id=?"; 49 int pnum = (Integer) runner.query(conn, sql , new ScalarHandler(),odi.getProduct_id()); 50 if(pnum<odi.getBuynum()) 51 { 52 //庫存不足 53 throw new MyRuntimeException("not enough"); 54 55 } 56 sql= "update products set pnum= pnum-? where id=?"; 57 58 runner.update(conn, sql, odi.getBuynum(),odi.getProduct_id()); 59 } 60 61 }
二,顯示商品列表:
這個比較簡單,先訪問servlet程序獲取商品列表,然后傳給jsp頁面,jsp頁面用el表達式獲取一下.
servlet涉及到的代碼:

1 ProductService ps=new ProductServiceImpl(); 2 List<Product> prod=new ArrayList<Product>(); 3 prod=ps.getList(); 4 request.setAttribute("list", prod); 5 request.getRequestDispatcher("/list_products.jsp").forward(request, response);
service層和dao層的代碼都在上面.
jsp頁面代碼:

1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 3 4 5 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 6 <html> 7 <head> 8 9 <title>My JSP 'list_products.jsp' starting page</title> 10 11 <meta http-equiv="pragma" content="no-cache"> 12 <meta http-equiv="cache-control" content="no-cache"> 13 <meta http-equiv="expires" content="0"> 14 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 15 <meta http-equiv="description" content="This is my page"> 16 <script type="text/javascript"> 17 function addCart(id){ 18 19 20 // 購物車是 一個 map 對象 , Map<Product,Integer> map, 購物車是 保存 在 session 中的 21 // <a href=""></a> 22 window.location.href='${pageContext.request.contextPath}/addCart?id='+id; 23 } 24 25 </script> 26 </head> 27 28 <body> 29 <c:if test="${empty list }" > 30 沒有商品 31 </c:if> 32 <c:if test="${not empty list }" > 33 <h3 align="center">商品列表</h3> 34 <c:forEach items="${list }" var="product"> 35 36 <img src="/myestore${product.imageurl_s }" style="cursor: pointer;" onclick="jumptodetail('${product.id}');" align="left"> 37 <div> 38 商品名稱:${product.name } 39 </div> 40 <br> 41 <div> 42 商品價格:${product.price } 43 </div> 44 <br> 45 <div> 46 商品種類:${product.category } 47 </div> 48 <br> 49 <div> 50 <c:if test="${product.pnum>0 }"> 51 <font color="green">現貨充足</font> 52 </c:if> 53 <c:if test="${product.pnum<=0 }"> 54 <font color="red">庫存不足</font> 55 </c:if> 56 </div> 57 <img src="/myestore/img/buy.bmp" style="cursor: pointer;" onclick="addCart('${product.id}');"> 58 <br clear="left"> 59 </c:forEach> 60 </c:if> 61 62 </body> 63 </html>
看一下效果:
"登錄&添加商品&商品列表"擼完收工........