商品案例
实现商品图片的上传,显示商品名称、价格 、数量、图片、描述等。可以对商品进行增改查。
导包、配置文件和工具类准备
导入
commons-beanutils.jar
、commons-fileupload.jar
、commons-io.jar
、commons-logging.jar
、mysql-connector-java-bin.jar
放到WEB-INF/lib下。-
数据库配置文件
ClassName=com.mysql.jdbc.Driver url=jdbc\:mysql\://localhost\:3306/example user=root password=admin
数据库连接工具类
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
商品列表
看一下,文字和图片都会瞎写的
点击添加,跳转到商品列表
商品修改
点击商品标题的超链接,跳转道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里面