16、商品案例

商品案例

实现商品图片的上传,显示商品名称、价格 、数量、图片、描述等。可以对商品进行增改查。

导包、配置文件和工具类准备

  1. 导入commons-beanutils.jarcommons-fileupload.jarcommons-io.jarcommons-logging.jarmysql-connector-java-bin.jar放到WEB-INF/lib下。

  2. 数据库配置文件

    ClassName=com.mysql.jdbc.Driver
    url=jdbc\:mysql\://localhost\:3306/example
    user=root
    password=admin
    
  3. 数据库连接工具类

package utils;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JDBCUtil {
    private static String driver;
    private static String url;
    private static String user;
    private static String password;

    // 静态代码块,随着类的加载而加载,只加载一次
    static {
        try {
            Properties prop = new Properties();
            
            // 下面这个是本机使用的就填写项目所在位置,但是我们是要部署到服务器的,所以获取WEB-INF/classes目录下的,注意要加"/"
            // InputStream is = new FileInputStream("/product/src/jdbc_setting.properties");
            InputStream is = JDBCUtil.class.getResourceAsStream("/jdbc_setting.properties");
            // load()接收InputStream,所以向上转型
            prop.load(is);

            driver = prop.getProperty("ClassName");
            url = prop.getProperty("url");
            user = prop.getProperty("user");
            password = prop.getProperty("password");
            Class.forName(driver);
            

            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() {
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(url, user, password);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("创建连接失败!");
        }
        return connection;
    }
    // 释放资源
    // 参数可能为空
    // 调用close要抛出异常,即使出现异常也能关闭
   public void close(Connection conn, Statement state, ResultSet result) {
        try {
            if (result != null) {          
                result.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (state != null) {
                state.close();
                }
            } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                     try {
                        if (conn != null) {
                            conn.close();
                        }
                    } catch (SQLException e) {
                        e.printStackTrace();
                }
            }
        }
    }
}

写一个Bean封装商品数据

package bean;

public class Product {
    
    private int id;
    private String name;
    private double price;
    private int pnum;
    private String descreption;
    private String type;
    private String imgurl;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public int getPnum() {
        return pnum;
    }
    public void setPnum(int pnum) {
        this.pnum = pnum;
    }
    public String getDescreption() {
        return descreption;
    }
    public void setDescreption(String descreption) {
        this.descreption = descreption;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getImgurl() {
        return imgurl;
    }
    public void setImgurl(String imgurl) {
        this.imgurl = imgurl;
    }
    @Override
    public String toString() {
        return "Product [id=" + id + ", name=" + name + ", price=" + price + ", pnum=" + pnum + ", descreption="
                + descreption + ", type=" + type + ", imgurl=" + imgurl + "]";
    }
    
    
}

定义用户保存商品信息的接口并实现

package dao;

import java.util.List;

import bean.Product;

public interface ProductDao {
   // 保存商品
   void save(Product p);
   // 获得所有商品
   List getAllProducts();
   //根据商品id获得商品对象
   Product getById(int id);
   //更新商品数据
   void update(Product p);
}

实现上面的接口,之所以定义为接口是因为实现里面可能尽不相同。在这里主要是sql语句的不同,写成接口更加灵活。

package dao.imple;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import bean.Product;
import dao.ProductDao;
import utils.JDBCUtil;

public class ProductDaoImple implements ProductDao {

    @Override
    public void save(Product p) {
        // 1. 获得连接
        Connection connection = JDBCUtil.getConnection();
        // 2. 准备sql语句
        String sql = "insert into `example`.`t_product` ("
                + "`id`,`name`,`price`,`pnum`,`descreption`,`type`,`imgurl`) " + "values "
                + "(NULL, ?, ?, ?, ?, ?, ?);";
        // 3.获得PreparedStatement
        PreparedStatement ps = null;
        try {
            ps = connection.prepareStatement(sql);
            // 4. 设置参数, 1表示第一个?
            ps.setString(1, p.getName());
            ps.setDouble(2, p.getPrice());
            ps.setInt(3, p.getPnum());
            ps.setString(4, p.getDescreption());
            ps.setString(5, p.getType());
            ps.setString(6, p.getImgurl());

            // 5. 执行sql
            int rows = ps.executeUpdate();
            // 这里只是新增了一行,不等于1说明添加失败
            if (rows != 1) {
                throw new RuntimeException("添加商品失败!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException("添加商品失败!");
        } finally {
            // 关闭资源
            JDBCUtil.close(connection, ps, null);
        }

    }

    @Override
    public List getAllProducts() {
        List list = new ArrayList<>();
        // 1. 建立连接
        Connection connection = JDBCUtil.getConnection();
        // 2. 准备sql语句
        String sql = "select * from t_product;";
        // 3. 创建PreparedStatement
        PreparedStatement pStatement = null;
        ResultSet rs = null;
        try {
            pStatement = connection.prepareStatement(sql);
            // 4. 执行查询
            rs = pStatement.executeQuery();

            // 5. 遍历结果集
            while (rs.next()) {
                // 将结果集中的数据封装到Product对象中
                Product p = new Product();
                p.setId(rs.getInt("id"));
                p.setName(rs.getString("name"));
                p.setPrice(rs.getDouble("price"));
                p.setPnum(rs.getInt("pnum"));
                p.setDescreption(rs.getString("descreption"));
                p.setType(rs.getString("type"));
                p.setImgurl(rs.getString("imgurl"));

                list.add(p);

            }

        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException("查询商品数据失败!");
        } finally {
            // 6 关闭资源
            JDBCUtil.close(connection, pStatement, rs);
        }

        // 返回产品列表
        return list;

    }

    public Product getById(int id) {
        // 1 获得连接
        Connection conn = JDBCUtil.getConnection();
        // 2 sql语句
        String sql = "select * from t_product where id = ?;";
        // 3 创建PrepareStatement
        PreparedStatement ps = null;
        ResultSet rs = null;
        Product p = null;
        try {
            ps = conn.prepareStatement(sql);
            // 设置参数
            ps.setInt(1, id);
            // 4 执行sql
            rs = ps.executeQuery();
            // 5 遍历结果集
            if (rs.next()) {
                // 将结果集中的数据封装到Product对象中
                p = new Product();
                p.setName(rs.getString("name"));
                p.setId(rs.getInt("id"));
                p.setPrice(rs.getDouble("price"));
                p.setPnum(rs.getInt("pnum"));
                p.setType(rs.getString("type"));
                p.setImgurl(rs.getString("imgurl"));
                p.setDescreption(rs.getString("descreption"));

            }

        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException("根据id查询商品数据失败!");
        } finally {
            // 6 关闭资源
            JDBCUtil.close(conn, ps, rs);
        }
        // 7 返回产品集合
        return p;
    }
    
    // 更新产品 
    public void update(Product p) {
        // 进行判断,edit.jsp里面只是将图片进行显示。如果不上传新的图片,imgurl为空。所以EditServlet里面应该对FileItem的大小就行判断。
        // 即fileItem .getSize() > 0 才执行保存imgurl,更新数据库的图片地址。否则不会更改数据库的图片地址
        boolean hasNewImg = p.getImgurl() != null;

        // 1 获得连接
        Connection conn = JDBCUtil.getConnection();
        // 2 准备sql
        String sql = "UPDATE " + "`t_product`" + " SET                    "
                + " `name` = ?, " + "`price` = ?," + "`pnum` = ?,          "
                + "`descreption` = ?," + "`type` = ? ";
        if (hasNewImg) {
            sql += ",`imgurl` = ?" + " WHERE `id` = ?;";
        } else {
            sql += " WHERE `id` = ?;";
        }

        PreparedStatement ps = null;
        try {
            // 3 获得PrepareStatement
            ps = conn.prepareStatement(sql);
            // 4 设置参数
            ps.setString(1, p.getName());
            ps.setDouble(2, p.getPrice());
            ps.setInt(3, p.getPnum());
            ps.setString(4, p.getDescreption());
            ps.setString(5, p.getType());
            if (hasNewImg) {
                ps.setString(6, p.getImgurl());
                ps.setInt(7, p.getId());
            } else {
                ps.setInt(6, p.getId());
            }

            // 5 执行sql
            int rowcount = ps.executeUpdate();
            if (rowcount != 1) {
                throw new RuntimeException("修改商品数据失败!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException("修改商品数据失败!");
        } finally {
            // 6 关闭资源
            JDBCUtil.close(conn, ps, null);
        }

    }

}

接下来是一个商品服务类,就更简单了。只是简单调用了上面实现类的save方法而已。

package service;


import java.util.List;

import bean.Product;
import dao.imple.ProductDaoImple;

public class ProductService {
    
    ProductDaoImple productDaoImple = new ProductDaoImple();
    
    public void save(Product p) {
        productDaoImple.save(p);
    }
    
    public List getAllProducts() {
        return productDaoImple.getAllProducts();
    }
    
  //根据id查询商品对象
    public Product getById(int id){
        return productDaoImple.getById(id);
                
    }
    public void update(Product p){
        productDaoImple.update(p);
    }
}

添加商品的界面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>



  
    
    
    My JSP 'login.jsp' starting page
    
    
    
        
    
    
    

  
  
  
    
添加商品
商品名称
商品价格
商品库存
类别
商品图片
商品描述

保存到数据库

package web;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;

import bean.Product;
import service.ProductService;
import utils.PathUtils;

@WebServlet("/AddProductServlet")
public class AddProductServlet extends HttpServlet {
    private ProductService productService = new ProductService();
    Product product = new Product();

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 1. 创建配置工厂
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 2. 创建解析器
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 用来存放表单中的键值对
        Map map = new HashMap<>();

        // 3. 解析request
        List fileItems = null;

        try {
            fileItems = upload.parseRequest(request);
            // 4. 遍历FileItem
            if (fileItems != null) {
                for (FileItem fileItem : fileItems) {
                    // 是普通段
                    if (fileItem.isFormField()) {
                        // 由于是文件上传制定了enctype="multipart/form-data",
                        // 用下面这个方法获取不到参数。
                        // BeanUtils.populate(product,
                        // request.getParameterMap());

                        // 需要用FileItem的getString()才能获得键对应的值
                        String key = fileItem.getFieldName();
                        String value = fileItem.getString("UTF-8");
                        // 同一个name属性的值可能相同,Map不允许重复键,所以放入数组
                        map.put(key, new String[] { value });
                        // 是文件,将文件保存到项目根目录下的upload文件夹
                    } else {

                        // 获得upload文件夹路径
                        String uploadPath = getServletContext().getRealPath("/upload");
                        // 生成日期文件夹
                        String datePath = PathUtils.getPath(uploadPath);
                        // 生成文件名
                        String fileName = UUID.randomUUID().toString();
                        // 保存图片
                        InputStream is = fileItem.getInputStream();
                        FileOutputStream fos = new FileOutputStream(uploadPath + datePath + fileName);
                        IOUtils.copy(is, fos);

                        // 保存访问路径
                        product.setImgurl("/upload" + datePath + fileName);

                        // 关流
                        fos.close();

                    }
                }
            }

        } catch (FileUploadException e) {
            e.printStackTrace();
            throw new RuntimeException("你的操作有误!");
        }

        try {
            BeanUtils.populate(product, map);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        // 保存商品到数据库
        productService.save(product);

        // 重定向到列表显示,先到servlet在到jsp,因为需要从servlet中从数据库取得数据
        response.sendRedirect(request.getContextPath() + "/ListServlet");
    }
}

上面写了一个PathUtils来获取日期文件夹的路径

package utils;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;


public class PathUtils {
    
    public static String getPath(String prefix) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("/yyyy/MM/dd/");
        // 解析好后是  /2017/04/17/
        String datePath = dateFormat.format(new Date());
        // 日期文件夹的完整路径
        String wholePath = prefix + datePath;
        File file = new File(wholePath);
        // 不存在就创建,保证AddProduct里面访问时候就已经存在
        if (!file.exists()) {
            file.mkdirs();
        }
        return datePath;
        
    }
    
}

商品显示

这里只是为了学习才引入JSON,一般不这样用。

package web;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import bean.Product;
import net.sf.json.JSONArray;
import service.ProductService;

@WebServlet("/ListServlet")
public class ListServlet extends HttpServlet {
    
    private ProductService ps = new ProductService();
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       List products =  ps.getAllProducts();
        //2 将商品列表放入request域, 将bean直接放入,解析成json
       String json = JSONArray.fromObject(products).toString();
       request.setAttribute("json", json);
           //3 转发到list.jsp
       request.getRequestDispatcher("/WEB-INF/page/list.jsp").forward(request, response);
    
    }


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

使用js动态生成表格

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>



  
    
    
    My JSP 'index.jsp' starting page
    
    
        
    
    
    
    
    
  
  
  
        

商品列表

看一下,文字和图片都会瞎写的

16、商品案例_第1张图片

点击添加,跳转到商品列表

16、商品案例_第2张图片

商品修改

点击商品标题的超链接,跳转道ToEditServlet,并且携带了参数id

package web;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import bean.Product;
import service.ProductService;

/**
 * Servlet implementation class ToEditServlet
 */
@WebServlet("/ToEditServlet")
public class ToEditServlet extends HttpServlet {
    
    private ProductService pService = new ProductService();
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // list.jsp里面
    
    
    
        
    
    
    

  
  
  
  
    
修改商品
商品名称:
商品价格:
库存:
类别: <%--原来数据库里类别是什么,就让哪个默认选中 --%>
商品图片: ![](/product${requestScope.product.imgurl})
商品描述:
<%-- 不修改id故隐藏,但是要提交 --%>

由EditServlet更新数据库,并重定向到ListServlet重新从数据库取得数据并显示。注意:edit.jsp只是显示了未修改的图片而已,如果不修改,即没有选择文件上传。文件段的fileitem内容就是空的,保存imgurl时就为空,一更新数据导致数据库中原来的图片也丢失。所以需要判断fileItem.getSize() > 0保证确实上传了文件才更新图片imgurl,否则不更新imgurl

package web;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;

import bean.Product;
import service.ProductService;
import utils.PathUtils;

@WebServlet("/EditServlet")
public class EditServlet extends HttpServlet {
    // 由于修改商品使用的表格和添加商品的表格差不多,这里基本可以用AddProductServlet的代码。只是最后是update
    private ProductService productService = new ProductService();
    Product product = new Product();

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 1. 创建配置工厂
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 2. 创建解析器
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 用来存放表单中的键值对
        Map map = new HashMap<>();

        // 3. 解析request
        List fileItems = null;

        try {
            fileItems = upload.parseRequest(request);
            // 4. 遍历FileItem
            if (fileItems != null) {
                for (FileItem fileItem : fileItems) {
                    // 是普通段
                    if (fileItem.isFormField()) {
                        // 由于是文件上传制定了enctype="multipart/form-data",
                        // 用下面这个方法获取不到参数。
                        // BeanUtils.populate(product,
                        // request.getParameterMap());

                        // 需要用FileItem的getString()才能获得键对应的值
                        String key = fileItem.getFieldName();
                        String value = fileItem.getString("UTF-8");
                        // 同一个name属性的值可能相同,Map不允许重复键,所以放入数组
                        map.put(key, new String[] { value });
                        // 是文件,将文件保存到项目根目录下的upload文件夹
                    } else {
                        // 上传的文件不为空才保存imgurl,否则为空保存为null,更新数据库图片丢失
                        if (fileItem.getSize() > 0) {
                            // 获得upload文件夹路径
                            String uploadPath = getServletContext().getRealPath("/upload");
                            // 生成日期文件夹
                            String datePath = PathUtils.getPath(uploadPath);
                            // 生成文件名
                            String fileName = UUID.randomUUID().toString();
                            // 保存图片
                            InputStream is = fileItem.getInputStream();
                            FileOutputStream fos = new FileOutputStream(uploadPath + datePath + fileName);
                            IOUtils.copy(is, fos);

                            // 保存访问路径
                            product.setImgurl("/upload" + datePath + fileName);

                            // 关流
                            fos.close();
                        }
                    }
                }
            }

        } catch (FileUploadException e) {
            e.printStackTrace();
            throw new RuntimeException("你的操作有误!");
        }
        try {
            BeanUtils.populate(product, map);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        // 保存商品到数据库
        productService.update(product);

        // 重定向到列表显示,先到servlet在到jsp,因为需要从servlet中从数据库取得数据
        response.sendRedirect(request.getContextPath() + "/ListServlet");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }
}

看下修改页面,修改后将回到商品展示页面,此时数据已经修改。


by @sunhaiyu

2017.4.18

你可能感兴趣的:(16、商品案例)