技术支持:JAVA、JSP
服务器:TOMCAT 7.0.86
编程软件:IntelliJ IDEA 2021.1.3 x64
前文几个功能的实现的博客
基于JSP、java、Tomcat、mysql三层交互的项目实战--校园交易网(1)-项目搭建(前期准备工作)-CSDN博客
基于JSP、java、Tomcat、mysql三层交互的项目实战--校园交易网(2)登录功能实现_tomcat jsp mysql-CSDN博客
基于JSP、java、Tomcat三者的项目实战--校园交易网(2)注册功能实现-CSDN博客
基于JSP、java、Tomcat三者的项目实战--校园交易网(3)主页-显示清单(list)-CSDN博客
基于JSP、java、Tomcat三者的项目实战--校园交易网(3)主页--数据库也显示清单遗漏问题-CSDN博客
基于JSP、java、Tomcat三者的项目实战--校园交易网(3)主页--添加商品功能-CSDN博客
基于JSP、java、Tomcat三者的项目实战--校园交易网(3)主页--显示当前用户的信息和系统时间和实现一个简单的购物车功能,包括添加商品、增加数量、减少数量、删除商品以及计算总金额-CSDN博客
在上一篇博客中,我们讲完了添加商品功能和显示时间是怎么写的和一个简单的购物车功能
我们可将添加进来的商品,点击加入购物车按钮,他就会在下面显示我们的购物车一栏,自动计算单价乘以数量,并且我们做了部分优化,左边数量可以减到0,这一栏商品就会自动消失,右边的删除按钮也能删除掉这个商品。
但是,当我要上传的商品数量万一价格要是有所浮动,我们要改变价格这种时候我们要怎么办呢?
基于这个考虑,我们在上方这一栏,我们加入了修改功能。
具体代码在主页中体现
<a href="load?id=<%=e.getId()%>">修改</a>
作用是创建一个超链接,其中 e.getId()
用于动态地生成商品的ID作为参数。具体来说:
<a>
标签定义了一个超链接,用户点击该链接时会跳转到指定的页面。href="load?id=<%=e.getId()%>"
设置了链接的目标地址为load
的服务,并通过参数id
将商品的ID传递给目标页面。<%=e.getId()%>
是一个 Java 代码块,用于输出当前商品的ID。这里假设e.getId()
是一个方法或者属性,返回该商品的唯一标识符。
因此,这个超链接的作用是允许用户点击以跳转到一个特定商品的修改页面,该页面根据传递的商品ID加载对应的商品信息以供修改操作。
当然,我们得充分意识到,当我们要进行一项修改工作时,我们首先要做的是先查找到数据,再去做修改数据的工作。
于是我们要再回到我们的这个load--->
load
是一个相对路径,指向你的项目中的某个 Servlet 或者 JSP 页面,在这段代码中我们指向的是一个服务来完成要做的事情,这个链接通常会被浏览器请求并发送到服务器端,服务器端根据路径和参数来处理请求。
因此使用 Servlet 来处理 load
请求,那么通常会在 web.xml
中配置 Servlet 的映射,指定请求的路径和对应的 Servlet 类。
web.xml
<servlet><servlet-name>load</servlet-name><servlet-class>Servlet.SelectShoppingServlet</servlet-class></servlet><servlet-mapping><servlet-name>load</servlet-name><url-pattern>/load</url-pattern></servlet-mapping>
load-->SelectShoppingServlet,我们就去服务层中找我们的这个查找商品功能。
服务端(查找功能)
SelectShoppingServlet(查找服务)
package Servlet;import dao.StudentDAO;
import entiy.Product;import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;public class SelectShoppingServlet extends HttpServlet {public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {request.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");StudentDAO studentDAO = new StudentDAO();String id = request.getParameter("id");System.out.println(id);PrintWriter writer = response.getWriter();try {Product product = studentDAO.findById(Integer.parseInt(id));request.setAttribute("goods",product );RequestDispatcher rd = request.getRequestDispatcher("Update.jsp");rd.forward(request,response);} catch (Exception e) {throw new RuntimeException(e);}}
}
我们可以看到,这段代码中主要来起作用的还是dao层的findById方法来锁定id进行查找,主要用于处理客户端的 HTTP 请求,并根据请求中的商品ID查询对应的商品信息,然后将该信息传递给一个名为 Update.jsp
的 JSP 页面进行展示或处理。
-
字符编码和响应类型设置:
request.setCharacterEncoding("utf-8")
和response.setContentType("text/html;charset=utf-8")
确保请求和响应都使用 UTF-8 编码,以支持处理中文和其他特殊字符。
-
DAO 对象的创建和使用:
StudentDAO studentDAO = new StudentDAO();
创建了一个用于访问数据库的StudentDAO
实例,用于执行对商品数据的操作。
-
获取和解析请求参数:
String id = request.getParameter("id");
获取名为 "id" 的请求参数,通常是客户端传递的商品ID。
-
查询数据库并获取商品信息:
Product product = studentDAO.findById(Integer.parseInt(id));
调用studentDAO
的findById
方法,根据解析后的商品ID查询数据库中对应的商品信息,并将结果存储在product
对象中。
-
设置请求属性和请求转发:
request.setAttribute("goods", product);
将查询得到的product
对象作为名为 "goods" 的请求属性存储起来,以便后续在目标页面Update.jsp
中使用。RequestDispatcher rd = request.getRequestDispatcher("Update.jsp");
创建一个请求分派器对象,用于将请求转发到名为Update.jsp
的 JSP 页面。rd.forward(request, response);
执行请求转发操作,将当前请求和响应对象传递给Update.jsp
页面,使其能够处理商品信息的展示或进一步的操作。
处理客户端请求、查询数据库、设置请求属性并将请求转发到另一个页面
dao层
public Product findById(int id) throws Exception{Connection conn = null;PreparedStatement prep = null;ResultSet rst = null;Product e =new Product();try {conn =DBUtil.getConnection();System.out.println(conn);prep = conn.prepareStatement("select * from goods where id="+id+"");System.out.println(id);rst = prep.executeQuery();if(rst.next()){int id1 = rst.getInt("id");String name = rst.getString("name");Double price = rst.getDouble("price");e.setId(id1);e.setName(name);e.setPrice(price);}}catch (Exception e1){e1.printStackTrace();throw e1;}finally {DBUtil.close(conn);}return e;}
findById方法用于根据给定的商品ID从数据库中查询对应的商品信息,并返回一个 Product
对象
-
数据库连接和准备语句:
Connection conn = DBUtil.getConnection();
获取数据库连接,DBUtil.getConnection()
是一个自定义的方法,用于获取数据库连接对象。prep = conn.prepareStatement("select * from goods where id="+id+"");
创建 PreparedStatement 对象,预编译 SQL 查询语句,通过商品ID从数据库中查询商品信息。
-
执行查询并处理结果集:
rst = prep.executeQuery();
执行查询操作,将查询结果存储在ResultSet
对象rst
中。if(rst.next()) { ... }
判断查询结果集中是否有数据,如果有,进入条件语句块处理查询到的商品信息。
-
将查询结果映射到实体对象:
int id1 = rst.getInt("id");
从结果集中获取商品ID。String name = rst.getString("name");
获取商品名称。Double price = rst.getDouble("price");
获取商品价格。e.setId(id1);
,e.setName(name);
,e.setPrice(price);
将查询到的商品ID、名称和价格设置到Product
对象e
的对应属性中。
-
异常处理和资源关闭:
catch (Exception e1) { ... }
捕获可能抛出的异常,打印异常堆栈信息,并重新抛出异常。finally { DBUtil.close(conn); }
在 finally 块中关闭数据库连接,确保资源得到正确释放,避免资源泄漏。
-
返回查询结果:
return e;
返回封装了查询到的商品信息的Product
对象e
。
实体层
Product
package entiy;public class Product {private int id;private String name;private double price;// 其他商品属性,如颜色、库存等// 构造方法、getter和setter方法public int getId() {return id;}public void setId(int id) {this.id = id;}public Product(/*, 其他属性 */) {this.name = name;this.price = price;// 初始化其他属性}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;}@Overridepublic String toString() {return "Product{" +"id=" + id +", name='" + name + '\'' +", price=" + price +'}';}
}
Student
package entiy;public class Student {private String name;private int idname;private String pd;public String getName(){return name;}public void setName(String name){this.name=name;}public int getIdname(){return idname;}public void setIdname(int idname){this.idname = idname;}public String getPd(){return pd;}public void setPd(String pd){this.pd = pd;}@Overridepublic String toString(){return "Student{"+"name="+name+"idname="+idname+",pd="+pd+'}';}}
网页端
Update.jsp
<%@ page import="entiy.Product" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head><title>修改商品信息</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="stylesheet" type="text/css"href="css/style.css" />
</head><body>
<div id="wrap"><div id="top_content"><div id="header"><div id="rightheader"></div><div id="topheader"><h1 id="title">商品修改</h1></div><div id="navigation"></div></div><div id="content"><p id="whereami"></p><h1>修改商品信息:</h1><form action="update" method="post"><%Product product = (Product) request.getAttribute("goods");System.out.println(product.getId());%><table cellpadding="0" cellspacing="0" border="0"class="form_table"><tr><td valign="middle" align="right">商品:</td><td valign="middle" align="left"><input type="text" class="inputgri" name="name" value="<%=product.getName()%>" /></td></tr><tr><td valign="middle" align="right">价格:</td><td valign="middle" align="left"><input type="text" class="inputgri" name="price" value="<%=product.getPrice()%>" /><input type="hidden" name="id" value="<%=product.getId()%>"></td></tr></table><p><input type="submit" class="button" value="提交" /></p></form></div></div><div id="footer"><div id="footer_bg">ABC@126.com</div></div>
</div>
</body>
</html>
主要就是用于展示和修改商品信息的表单页面。
<%@ page import="entity.Product" %>
:导入Product
实体类,用于在页面中访问商品对象的属性和方法。<form action="update" method="post">
:表单的提交地址为update
,使用 POST 方法提交表单数据。<% Product product = (Product) request.getAttribute("goods"); %>
:从请求中获取名为goods
的属性,并将其转换为Product
对象product
。这通常是通过在 Servlet 中设置请求属性来实现的,用于向页面传递数据。-
表单元素:
<input type="text" class="inputgri" name="name" value="<%=product.getName()%>" />
:文本输入框用于显示和修改商品名称,其值从product
对象的getName()
方法获取。<input type="text" class="inputgri" name="price" value="<%=product.getPrice()%>" />
:文本输入框用于显示和修改商品价格,值从product
对象的getPrice()
方法获取。<input type="hidden" name="id" value="<%=product.getId()%>">
:隐藏输入框用于传递商品ID,值从product
对象的getId()
方法获取。
<% System.out.println(product.getId()); %>
:在页面中打印商品的ID,通常用于调试目的。
因为其
<form action="update" method="post">
:
表单的提交地址为
update
,使用 POST 方法提交表单数据。所有我们在web.xml中又要再写一个
<servlet><servlet-name>update</servlet-name><servlet-class>Servlet.UpdateShoppingServlet</servlet-class></servlet><servlet-mapping><servlet-name>update</servlet-name><url-pattern>/update</url-pattern></servlet-mapping>
所以在服务端,我们还要继续写一个update功能,能够实现从id查找到我我们选中的商品然后去进行修改
服务端(更新或者说是修改功能)
UpdateShoppinngServlet
package Servlet;import dao.StudentDAO;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class UpdateShoppingServlet extends HttpServlet {public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {StudentDAO productDAO = new StudentDAO();request.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");// Get parameters from requestString idStr = request.getParameter("id");String name = request.getParameter("name");String priceStr = request.getParameter("price");// Validate parametersif (idStr == null || name == null || priceStr == null || idStr.isEmpty() || name.isEmpty() || priceStr.isEmpty()) {response.getWriter().println("Invalid parameters. Please provide all fields.");return;}try {// Parse parametersint id = Integer.parseInt(idStr);double price = Double.parseDouble(priceStr);// Update product in DAOproductDAO.Update(id, name, price);// Redirect to list page after successful updateresponse.sendRedirect("list");} catch (NumberFormatException e) {// Handle if id or price is not a valid numberresponse.getWriter().println("Invalid id or price format. Please enter valid numbers.");} catch (Exception e) {// Handle other exceptionsthrow new ServletException("Error updating product", e);}}
}
-
导入依赖和设置编码:
- 导入了
StudentDAO
类,该类用于处理与数据库的交互。 - 设置请求和响应的字符编码为UTF-8,以确保能够正确处理中文字符。
- 导入了
-
重写
service
方法:- Servlet类重写了
service
方法,该方法接收HttpServletRequest
和HttpServletResponse
作为参数,用于处理客户端的请求和生成响应。
- Servlet类重写了
-
创建DAO对象:
- 实例化了
StudentDAO
对象productDAO
,用于后续的数据库操作。
- 实例化了
-
获取和验证参数:
- 从请求中获取商品的ID(idStr)、名称(name)和价格(priceStr)。
- 对获取的参数进行非空和有效性验证:
- 如果有任何一个参数为空或空字符串,向响应输出错误信息并提前结束处理。
-
参数解析和更新操作:
- 尝试将获取到的ID和价格转换为整型和双精度浮点数,如果转换失败则捕获
NumberFormatException
。 - 调用
productDAO
的Update
方法,将解析后的ID、名称和价格传递给DAO层进行商品信息的更新操作。
- 尝试将获取到的ID和价格转换为整型和双精度浮点数,如果转换失败则捕获
-
处理更新结果:
- 如果更新成功,使用
response.sendRedirect("list")
将用户重定向到商品列表页面。 - 如果更新过程中出现非数字格式的ID或价格,捕获并处理
NumberFormatException
,向响应输出相应的错误信息。 - 如果更新过程中出现其他异常,捕获并抛出
ServletException
,并将异常信息传递给上层处理。
- 如果更新成功,使用
dao层(update方法)
public void Update(int id,String name,double price) throws Exception {Connection connection = DBUtil.getConnection();PreparedStatement preparedStatement = connection.prepareStatement("update goods set name=?,price=? where id =?;");preparedStatement.setString(1,name);preparedStatement.setDouble(2,price);preparedStatement.setInt(3,id);int i = preparedStatement.executeUpdate();connection.close();}
突然发现,可能前面都没说明这个DBUtil包的好像
DBUtil
package util;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class DBUtil {public static Connection getConnection() throws Exception {Connection conn = null;try {Class.forName("com.mysql.jdbc.Driver");conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sdjyy?" +"useUnicode=true&characterEncoding=utf8","root","asd123");} catch (Exception e) {e.printStackTrace();throw e;}return conn;}public static void close(Connection conn){if(conn!=null){try {conn.close();}catch (SQLException e){e.printStackTrace();}}}public static void main(String[] args)throws Exception{Connection conn = getConnection();System.out.println(conn);}
}
getConnection
方法用于获取数据库连接对象Connection
。- 首先,通过
Class.forName
加载 MySQL 数据库驱动程序com.mysql.jdbc.Driver
。 - 然后,使用
DriverManager.getConnection
方法建立与 MySQL 数据库的连接,连接的 URL 指定了本地主机和端口(localhost:3306
),以及数据库名(sdjyy
)和连接参数(使用Unicode编码和UTF-8字符集)。 - 如果连接过程中出现异常,会将异常打印出来并重新抛出,向上层调用方法传递异常信息。
close
方法用于关闭Connection
对象。- 首先检查传入的
conn
是否为null
,如果不为null
,则调用conn.close()
方法关闭数据库连接。 - 如果在关闭连接时发生
SQLException
异常,会将异常打印出来,但不会重新抛出异常,而是简单地记录异常信息。
实现功能截图
从网页上方我们可以明确得知我们拿到了id,也是,我们在写改操作时,常常会因为没有拿到id而数值传为空报错。
笔者在写改操作时,也是在dao层中没有写下我的setid方法,一直传为空,没有拿到id
修改完之后,我们可以看到成功修改了,同时也重定向回到了我们的list页面。