estore商城案例(二)------登录&添加商品&商品列表(下)

撸完了登录模块,接着撸商品添加,和商品列表模块:

先亮出数据库:

 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>

看一下效果:

"登录&添加商品&商品列表"撸完收工........

estore商城案例(二)------登录&添加商品&商品列表(下),布布扣,bubuko.com

时间: 2024-10-02 20:54:17

estore商城案例(二)------登录&添加商品&商品列表(下)的相关文章

estore商城案例(二)------登录&amp;添加商品&amp;商品列表(上)

今天继续写一下第二个功能:登录&添加商品&商品列表 1.登录页面,很简单做个表单提交一下就可以了,记住登录的功能也先简单写一下,明天写filter过滤器会完善自动登录的功能,以及权限管理. 登录页面代码: 1 <html> 2 <head> 3 4 <title>My JSP 'login.jsp' starting page</title> 5 6 <script type="text/javascript">

estore商城案例(三)------Filter过滤器:自动登录&amp;权限管理

前面写好了用户登录\注册\添加商品的功能模块.下面写一下对于这些功能模块的相关过滤器---自动登录与权限管理: 一.自动登录: 业务逻辑是这样的:jsp登录页面有个“自动登录选项”,如果登录这勾选了,那么在serlvet程序中则会额外的生成一个保存用户名和密码的cookie,然后每次用户向服务器发送请求时,Filter过滤器都会先判断用户的登录状态(session),如果已经登录那么无需做出受任何操作直接放行,如果没有登录(无session),那么这时体现自动登录功能作用的时候到了,先获取自动登

estore商城案例(四、五)------添加购物车&amp;购物车显示/生成订单&amp;在线支付

一.添加购物车 1.获得商品id提交到servlet程序 2.根据id获取product对象 3.判断seesion中是否有存在购物车session.没有的话表示  添加的第一件商品  需要先创建session:有的话直接在session里添加获得的produce(添加product 要先判断session中是否存在对应的商品,存在话直接修改商品数量,没有的话新添加这个商品). servlet程序代码: 1 public void doGet(HttpServletRequest request

estore商城案例(一)------用户注册&amp;邮件激活(下)

先补上昨天注册页面的验证码代码: 1 public void doGet(HttpServletRequest request, HttpServletResponse response) 2 throws ServletException, IOException { 3 BufferedImage bf=new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); 4 Graphics2D graphice=(Graphics2D

用PHP添加购物商品

1 <?php 2 session_start(); 3 header ( "Content-type: text/html; charset=UTF-8" ); //设置文件编码格式 4 require("system/system.inc.php"); //包含配置文件 5 /** 6 * 1表示添加成功 7 * 2表示用户没有登录 8 * 3表示商品已添加过 9 * 4表示添加时出现错误 10 * 5表示没有商品添加 11 */ 12 $reback =

零基础学习java------35---------删除一个商品案例,删除多个商品

一. 删除一个商品案例 将要操作的表格 思路图  前端代码 <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>> <!DOC

在基础管理下添加一个商品类型维护的模块(7-31)

一    验证不能为空的操作: 在form中添加代码@NotEmpty(field="商品类型", message="{errors.required}") 在controller中对应不能为空的位置添加 if(results.hasErrors()) return "manager/commodityType/addCommodityType"; 3.不能为空的格式:<td style="background-color: #f

Cookie小案例-----记住浏览过的商品记录

Cookie小案例------记住浏览过的商品记录 我们知道,这个功能在电商项目中很常见.这里处理请求和页面显示都是由servlet实现,主要是为了体现cookie的作用, 实现功能如下: 1,点击购买的商品后,显示到另一页面 2,记住用户浏览过的商品,并在页面时中显示 3,当浏览过的数量超过最大值限度时,最下面一个商品被挤下去 4,当浏览过的商品本身就在浏览记录中,显示列表将其从中间移到最上面 显示一打开网站的样子和显示用户的浏览记录: package cn.itcast.cookie; im

MySQL主从复制故障案例二

案例二: 一主多从的架构下,主库master宕机 解决思路: 1,登录从库 show processlist: 查看两个线程的更新状态 结果说明: 之前主从同步正常 分别登录其余2个从库32,33查看: cat   /data/3306/data/master.info cat   /data/3307/data/master.info 比较,那个POS最大,说明更接近主库,那么我们就选举此slave作为新的master. 或者利用半同步技术,直接选举实时同步了的这个库为新的master 如果,