项目实战系列三: 家居购项目 第二部分

家居购项目

🐇servlet合并

需求

1.如果处理一个请求, 就对应一个Servlet, 会造成Servlet文件太多, 不利于管理.

2.在项目开发中, 同一个业务(模块), 一般对应一个Servlet即可, 比如LoginServlet, RegisterServlet, 都是在处理和会员相关的业务, 应当合并.

🍎方案一: 隐藏域

1.给login和register表单增加hidden元素, 区分登录和注册.

2但信息提交到MemberServlet后, 获取action参数值

3.分发请求.

代码实现

1.修改web/views/member/login.jsp, 增加隐藏域, 修改请求url为memberServlet

2.新建src/com/zzw/furns/web/MemberServlet.java, 合并到MemberServlet

java 复制代码
public class MemberServlet extends HttpServlet {

    private MemberService memberService = new MemberServiceImpl();

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String action = request.getParameter("action");
        if ("login".equals(action)) {
            login(request, response);
        } else if ("register".equals(action)) {
            register(request, response);
        } else {
            response.setContentType("text/html;charset=UTF-8");
            response.getWriter().write("<h1>404</h1>");
        }
    }

    protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        Member member = new Member(null, username, password, null);
        if (member != null) {
            System.out.println("登录成功");
            request.getRequestDispatcher("/views/member/login_ok.jsp").forward(request, response);
        } else {
            System.out.println("登录失败");
            request.setAttribute("msg", "用户名或密码错误,请重新登录");
            request.setAttribute("username", username);
            request.getRequestDispatcher(request.getHeader("Referer")).forward(request, response);
        }
    }

    protected void register(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String email = request.getParameter("email");

        Member member = new Member(null, username, password, email);
        if (!memberService.isExistsByUsername(username)) {
            //用户名可用
            if (memberService.registerMember(member)) {
                //注册成功
                System.out.println("注册成功,请登录");
                request.getRequestDispatcher("/views/member/register_ok.jsp").forward(request, response);
            } else {
                //注册失败
                System.out.println("注册失败,请重新注册");
                request.getRequestDispatcher("/views/member/register_fail.jsp").forward(request, response);
            }
        } else {
            request.setCharacterEncoding("UTF-8");
            request.setAttribute("msg", "用户名已存在,请重新注册");
            request.setAttribute("username", username);
            request.setAttribute("active", "register_tab");
            request.getRequestDispatcher("/views/member/login.jsp").forward(request, response);
        }
    }
}

3.测试...

🍎方案二: 反射+模板设计模式+动态代理

1.新建BasicServlet类, 继承HttpServlet

java 复制代码
public class BasicServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
    
	@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String action = req.getParameter("action");
        try {
            //1.得到子类对应的class对象
            Class<? extends BasicServlet> aClass = this.getClass();
            //2.创建对象
            Object o = aClass.newInstance();
            //3.得到action方法对象
            Method declaredMethod = this.getClass()
                    .getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
            declaredMethod.invoke(o, req, resp);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

2.子类中没有doGet, doPost方法, 会调用父类的doGet, doPost.

🌳显示家居

需求分析

1.给后台管理提供独立登陆页面 [manage_login.jsp (已提供)

2.管理员(admin表 )登陆成功后, 显示管理菜单页面

3.管理员点击家居管理, 显示所有家居信息

程序框架图

1.页面准备

2.新建admin表 👉 参考member表

sql 复制代码
-- 创建会员表
CREATE TABLE admin (
	id INT PRIMARY KEY AUTO_INCREMENT,
	username VARCHAR(32) NOT NULL DEFAULT '' UNIQUE,
	`password` VARCHAR(32) NOT NULL,
	email VARCHAR(64)
)CHARSET utf8 ENGINE INNODB;

-- 插入数据
INSERT INTO admin VALUES(NULL, 'admin', MD5('admin'), '978964140@qq.com');
INSERT INTO admin VALUES(NULL, 'zhaozhiwei', MD5('zhaozhiwei'), '978964140@qq.com');
INSERT INTO admin(id, username, `password`, email) VALUES(NULL, 'tom', MD5('tom'), 'tom@sohu.com');

-- 查询
SELECT * FROM admin;
SELECT id, username, `password`, email FROM admin WHERE username = 'admine'
SELECT id, username, `password`, email FROM admin WHERE username = 'admin123' AND `password` = MD5('123456');

UPDATE admin SET `password`=MD5('admin') WHERE username='admin';

3.新建furn表

sql 复制代码
-- 创建家居网购需要的数据库和表
-- 删除数据库
DROP DATABASE IF EXISTS home_furnishing;

-- 删除表
DROP TABLE furn;

-- 创建数据库
CREATE DATABASE home_furnishing;

-- 切换
USE home_furnishing;

-- id int(11) 11表示的是宽度
-- id int(2)  2表示的也是宽度
-- 66360 -> int(11)  00000066360
-- 66360 -> int(2)   66360
-- unsigned 无符号类型,表示的范围大一些

-- 创建家居表
CREATE TABLE furn (
	id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT, -- id编号
	`name` VARCHAR(32) NOT NULL,-- 家居名
	business VARCHAR(32) NOT NULL,-- 商家
	price DECIMAL(10, 2) NOT NULL,-- 价格
	saleNum INT UNSIGNED NOT NULL,-- 销量
	inventory INT UNSIGNED NOT NULL,-- 库存
	image_path VARCHAR(256) NOT NULL -- 图片
)CHARSET utf8 ENGINE INNODB;

-- 插入数据
insert into `furn` (`id`, `name`, `business`, `price`, `saleNum`, `inventory`, `image_path`) values('1','小台灯','南极人','35.50','3002','6998','assets/images/product-image/default.jpg');
insert into `furn` (`id`, `name`, `business`, `price`, `saleNum`, `inventory`, `image_path`) values('2','黑丝袜','南极人','25.50','4002','5998','assets/images/product-image/default.jpg');
insert into `furn` (`id`, `name`, `business`, `price`, `saleNum`, `inventory`, `image_path`) values('3','胸罩','南极人','45.50','5002','4998','assets/images/product-image/default.jpg');

-- 查询数据
SELECT id, `name`, business, price, saleNum, inventory, image_path FROM furn WHERE `name` = '小台灯' LIMIT 1, 3;
SELECT id, `name`, business, price, saleNum, inventory, image_path FROM furn
SELECT COUNT(*) FROM furn WHERE `name` LIKE '%台%';

-- 删除数据
DELETE FROM furn WHERE id = 32;

-- 修改数据
UPDATE furn SET image_path = 'assets/images/product-image/default.jpg';
UPDATE furn SET `name`='手机', business='小米', price=3000, saleNum=9000, inventory=9000, image_path='zzw' WHERE id=37
UPDATE furn SET `name`='笔记本', business='戴尔', price=6000.00, saleNum=6500, inventory=5500 WHERE id=75;

4.新建Admin实体类 src/com/zzw/furns/entity/Admin.java

java 复制代码
public class Admin {
    private Integer id;
    private String username;
    private String password;
    private String email;

    public Admin() {
    }
}

5.新建Furn实体类(无参构造器与set方法底层反射用, get方法前端EL表达式用) src/com/zzw/furns/entity/Furn.java

java 复制代码
public class Furn {
    private String name;
    
    private String business;
    
    private BigDecimal price;//Decimal对应BigDecimal
    
    private Integer saleNum;
    
    private Integer inventory;
    
    private String imagePath;

    public Furn() {
    }
}

6.新建src/com/zzw/furns/dao/AdminDao.java

java 复制代码
public interface AdminDAO {
    //根据用户名和密码查询数据库中有无对应的Admin对象
    public Admin queryAdminByUsernameAndPassword(String username, String password);
}

7.新建src/com/zzw/furns/dao/impl/AdminDaoImpl.java

java 复制代码
public class AdminDAOImpl extends BasicDAO<Admin> implements AdminDAO {
    /**
     * 根据用户名和密码查询对应的Admin对象
     * @param username 用户名
     * @param password 密码
     * @return 对应的Admin对象, 如果没有 则返回null
     */
    @Override
    public Admin queryAdminByUsernameAndPassword(String username, String password) {
        String sql = "SELECT id, username, `password`, email FROM admin WHERE username = ? AND `password` = MD5(?)";
        Admin admin = querySingle(sql, Admin.class, username, password);
        return admin;
    }
}

8.测试, 新建src/com/zzw/furns/test/AdminDAOTest.java

java 复制代码
public class AdminDAOTest {

    private AdminDAO adminDAO = new AdminDAOImpl();
    @Test
    public void queryAdminByUsernameAndPassword() {
        String username = "zhaozhiwei";
        String password = "123123";
        Admin admin = adminDAO.queryAdminByUsernameAndPassword(username, password);
        System.out.println(admin);
    }
}

9.新建src/com/zzw/furns/service/AdminService.java

java 复制代码
public interface AdminService {
    /**
     * 根据传入的admin信息, 返回对应在DB中的admin对象
     * @param admin 是根据用户登录构建一个admin
     * @return 返回的是对应的DB中的admin对象, 如果不存在返回null
     */
    public Admin login(Admin admin);
}

10.新建src/com/zzw/furns/service/AdminServiceImpl.java

java 复制代码
public class AdminServiceImpl implements AdminService {
    private AdminDAO adminDAO = new AdminDAOImpl();

    /**
     * 判断用户名和密码是否存在
     * @param username 用户名
     * @param password 密码
     * @return
     */
    @Override
    public Admin login(Admin admin) {
        //返回一个对象
        return adminDAO.
                queryAdminByUsernameAndPassword(admin.getUsername(), admin.getPassword());
    }
}

11.测试, 新建src/com/zzw/furns/test/AdminServiceTest.java

java 复制代码
public class AdminServiceTest {
    private AdminService adminService = new AdminServiceImpl();

    @Test
    public void login() {
        Admin admin = new Admin(null, "zhaozhiwei", "123123", null);
        Admin login = adminService.login(admin);
        System.out.println("login = " + login);
    }
}

12.新建src/com/zzw/furns/dao/FurnDao.java

java 复制代码
public interface FurnDAO {
    //返回所有Furn对象
    public List<Furn> list();
}

13.新建src/com/zzw/furns/dao/impl/FurnDaoImpl.java

给字段起别名, 对应实体类的某一个属性

java 复制代码
public class FurnDAOImpl extends BasicDAO<Furn> implements FurnDAO {
    @Override
    public List<Furn> listAll() {
        String sql = "SELECT id, `name`, business, price, saleNum, inventory, image_path as imagePath FROM furn";
        List<Furn> furns = queryMany(sql, Furn.class);
        return furns;
    }
}

14.测试, 新建src/com/zzw/furns/test/FurnDaoTest.java

java 复制代码
public class FurnDAOTest {
    private FurnDAO furnDAO = new FurnDAOImpl();
    @Test
    public void listAll() {
        List<Furn> furns = furnDAO.listAll();
        for (Furn furn : furns) {
            System.out.println(furn);
        }
    }
}

15.新建src/com/zzw/furns/service/FurnService.java

java 复制代码
public interface FurnService {
    //显示家居
    public List<Furn> queryFurn();
}

16.新建src/com/zzw/furns/service/AdminServiceImpl.java

java 复制代码
public class FurnServiceImpl implements FurnService {

    private FurnDAO furnDAO = new FurnDAOImpl();

    @Override
    public List<Furn> queryFurn() {
        List<Furn> furns = furnDAO.listAll();
        return furns;
    }
}

17.测试, 新建src/com/zzw/furns/test/AdminServiceTest.java

java 复制代码
public class FurnServiceTest {
 
    private FurnService furnService = new FurnServiceImpl();

    @Test
    public void queryFurn() {
        List<Furn> furns =  furnService.queryFurn();
        for (int i = 0; i < furns.size(); i++) {
            System.out.println(furns.get(i));
        }
    }
}

18.接通web层, 创建src/com/zzw/furns/web/AdminServlet.java, 管理员登录Servlet

java 复制代码
public class AdminServlet extends BasicServlet {
    private AdminService adminService = new AdminServiceImpl();

    protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //如果在登陆界面用户没有输入内容, 后台接收到的是""
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        Admin admin = new Admin(null, username, password, null);

        admin = adminService.login(admin);
        if (admin != null) {//用户存在DB
            System.out.println("管理员登陆成功...");

            request.getRequestDispatcher("/views/manage/manage_menu.jsp")
                    .forward(request, response);
        } else {//用户不存在
            System.out.println("该管理员用户不存在, 登陆失败");
            request.setAttribute("username", username);
            request.setAttribute("errorMsg", "用户名或密码不正确");
            request.getRequestDispatcher("/views/manage/manage_login.jsp")
                    .forward(request, response);
        }
    }
}

配置web.xml

java 复制代码
<servlet>
    <servlet-name>AdminServlet</servlet-name>
    <servlet-class>com.zzw.furns.web.AdminServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>AdminServlet</servlet-name>
    <url-pattern>/adminServlet</url-pattern>
</servlet-mapping>

19.创建src/com/zzw/furns/web/FurnServlet.java, 家居显示Servlet

java 复制代码
public class FurnServlet extends BasicServlet {
    private FurnService furnService = new FurnServiceImpl();

    protected void list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<Furn> furns = furnService.queryFurn();
        //将结果保存到request域
        request.setAttribute("furns", furns);
        //请求转发到管理家具页面
        request.getRequestDispatcher("/views/manage/furn_manage.jsp")
                .forward(request, response);
    }
}

配置web.xml

xml 复制代码
<servlet>
    <servlet-name>FurnServlet</servlet-name>
    <servlet-class>com.zzw.furns.web.FurnServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>FurnServlet</servlet-name>
    <url-pattern>/manage/furnServlet</url-pattern>
</servlet-mapping>

20.前端页面, web/views/manage/manage_login.jsp, 管理员登录页面

html 复制代码
<span class="errorMsg"
      style="float: right; font-weight: bold; color: lightgray; font-size: 20pt; margin-left: 10px;">${msg}</span>
<%--管理员登陆--%>
<form action="adminServlet" method="post">
    <input type="hidden" name="action" value="login"/>
    <input type="text" name="username" value="${username}" placeholder="Username"/>
    <input type="password" name="password" placeholder="Password"/>
    <div class="button-box">
        <div class="login-toggle-btn">
            <input type="checkbox"/>
            <a class="flote-none" href="javascript:void(0)">Remember me</a>
            <a href="#">Forgot Password?</a>
        </div>
        <button type="submit"><span>Login</span></button>
    </div>
</form>

21.修改manage_menu.jsp, 家居菜单页面

22.修改furn_manage.jsp, 家居显示页面

html 复制代码
<thead>
<tr>
    <th>家居名</th>
    <th>商家</th>
    <th>价格</th>
    <th>销量</th>
    <th>库存</th>
    <th>图片</th>
    <th>操作</th>
</tr>
</thead>
<tbody>
<c:forEach items="${furns}" var="furn">
    <tr>
        <td class="product-thumbnail">
            <a href="#"><img class="img-responsive ml-3"
                             src="assets/images/product-image/1.jpg"
                             alt=""/></a>
        </td>
        <td class="product-name"><a href="#">${furn.name}</a></td>
        <td class="product-name"><a href="#">${furn.business}</a></td>
        <td class="product-price-cart"><span class="amount">${furn.price}</span></td>
        <td class="product-quantity">
                ${furn.saleNum}
        </td>
        <td class="product-quantity">
                ${furn.inventory}
        </td>
        <td class="product-remove">
            <a href="#"><i class="icon-pencil"></i></a>
            <a href="#"><i class="icon-close"></i></a>
        </td>
    </tr>
</c:forEach>
</tbody>

23.测试

1)管理员登录

🌳添加家居

思路分析

1.请求添加家居, 请求FurnServlet的add方法, 将前端提交的数据封装到Furn对象

2.调用FurnService.add(Furn furn)方法

3.跳转到显示家居的页面

程序框架图

1.修改com.zzw.furns.FurnDAO

java 复制代码
//添加Furn对象
public boolean add(Furn furn);

2.修改com.zzw.furns.impl.FurnDaoImpl

java 复制代码
@Override
public boolean add(Furn furn) {
    String sql = "INSERT INTO furn(id, `name`, business, price, saleNum, inventory, image_path) " +
            "VALUES(NULL, ?, ?, ?, ?, ?, ?)";
    int updateRows = update(sql, furn.getName(), furn.getBusiness(), furn.getPrice(),
            furn.getSaleNum(), furn.getInventory(), furn.getImagePath());
    return updateRows > 0;
}

3.测试, 修改FurnDaoTest

java 复制代码
@Test
public void add() {
    BigDecimal price = new BigDecimal(32.2);
    String imagePath = "assets/images/product-image/4.jpg";
    Furn furn =
            new Furn(null, "桌子", "南极人", price, 4500, 8000, imagePath);
    System.out.println(furnDAO.add(furn) ? "添加成功" : "添加失败");
}

4.修改com.zzw.furns.FurnService

java 复制代码
//添加家居
public boolean addFurn(Furn furn);
java 复制代码
/**
 * 添加家居
 *
 * @param furn 前端传来的Furn对象
 * @return 返回布尔值
 */
@Override
public boolean addFurn(Furn furn) {
    return furnDAO.add(furn);
}

5.修改com.zzw.furns.impl.FurnServiceImpl

java 复制代码
/**
 * 添加家居
 *
 * @param furn 前端传来的Furn对象
 * @return 返回布尔值
 */
@Override
public boolean addFurn(Furn furn) {
    return furnDAO.add(furn);
}

6.测试,修改com.zzw.furns.impl.FurnServiceTest

java 复制代码
/**
 * 添加家居
 *
 * @param furn 前端传来的Furn对象
 * @return 返回布尔值
 */
@Override
public boolean addFurn(Furn furn) {
    return furnDAO.add(furn);
}

7.工具类src/com/zzw/furns/utils/DataUtils.java

java 复制代码
public class DataUtils {
    public static int parseInt(String str, Integer defaultValue) {
        try {
            int num = Integer.parseInt(str);
            return num;
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }
}

8.web层, 修改FurnServlet, 添加方法add

java 复制代码
protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String name = req.getParameter("name");
    String business = req.getParameter("business");
    BigDecimal price = new BigDecimal(req.getParameter("price"));
    int saleNum = DataUtils.parseInt(req.getParameter("saleNum"), 0);
    int inventory = DataUtils.parseInt(req.getParameter("inventory"), 0);

    Furn furn = new Furn(null, name,
            business, price, saleNum, inventory, "assets/images/product-image/default.jpg");

    if (furnService.add(furn) > 0) {
        System.out.println("添加成功, 请求转发到list");
        //req.getRequestDispatcher("/manage/furnServlet?action=list")
        //        .forward(req, resp);
        resp.sendRedirect(req.getContextPath() + "/manage/furnServlet?action=list");
    } else {
        System.out.println("添加失败, 返回到添加页面");
        req.getRequestDispatcher("views/manage/furn_add.jsp")
                .forward(req, resp);
    }
}

9.解决中文乱码问题

在BasicServlet中设置utf-8.

10.前端: furn_manage跳转到添加家居页面

html 复制代码
<!-- Single Wedge Start -->
<div class="header-bottom-set dropdown">
    <a href="views/manage/furn_add.jsp">添加家居</a>
</div>

11.添加furn_add.jsp

html 复制代码
<!--添加到table标签的下一行-->
<span class="errorMsg"
      style="float: right; font-weight: bold; color: lightgray; font-size: 20pt; margin-left: 10px;"></span>


12.测试

🍉解决重复添加

1.请求转发设置成重定向

🍉后端数据校验说明

后端方案一: 修改FurnServlet.java

java 复制代码
String name = req.getParameter("name");
if (StringUtils.isEmpty(name)) {
    req.setAttribute("msg", "商品名不能为空");
    req.getRequestDispatcher("/views/manage/furn_add.jsp").forward(req, resp);
    return;
}

String business = req.getParameter("business");
if (StringUtils.isEmpty(business)) {
    req.setAttribute("msg", "商家不能为空");
    req.getRequestDispatcher("/views/manage/furn_add.jsp").forward(req, resp);
    return;
}

String saleNumTemp = req.getParameter("saleNum");
//不能为空
if (StringUtils.isEmpty(saleNumTemp)) {
    req.setAttribute("msg", "销量不能为空");
    req.getRequestDispatcher("/views/manage/furn_add.jsp").forward(req, resp);
    return;
}

String inventoryTemp = req.getParameter("inventory");
if (StringUtils.isEmpty(inventoryTemp)) {
    req.setAttribute("msg", "库存不能为空");
    req.getRequestDispatcher("/views/manage/furn_add.jsp").forward(req, resp);
    return;
}

String priceTemp = req.getParameter("price");
if (StringUtils.isEmpty(priceTemp)) {
    req.setAttribute("msg", "价格不能为空");
    req.getRequestDispatcher("/views/manage/furn_add.jsp").forward(req, resp);
    return;
}

Integer saleNum = null;
try {
    saleNum = Integer.parseInt(saleNumTemp);
} catch (NumberFormatException e) {
    req.setAttribute("msg", "销量格式错误");
    req.getRequestDispatcher("/views/manage/furn_add.jsp").forward(req, resp);
    return;
}

Integer inventory = null;
try {
    inventory = Integer.parseInt(inventoryTemp);
} catch (NumberFormatException e) {
    req.setAttribute("msg", "库存格式错误");
    req.getRequestDispatcher("/views/manage/furn_add.jsp").forward(req, resp);
    return;
}

BigDecimal price = null;
try {
    price = new BigDecimal(priceTemp);
} catch (NumberFormatException e) {
    req.setAttribute("msg", "价格格式错误");
    req.getRequestDispatcher("/views/manage/furn_add.jsp").forward(req, resp);
    return;
}

前端数据校验, 修改web/views/manage/furn_add.jsp

js 复制代码
<script src="script/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
    window.onload = function () {
        $("input[type='submit']")[0].onclick = function () {
            if ($("input[name='name']").val() == "" || $("input[name='name']").val() == null) {
                alert("请输入家居名");
                return false;
            } else if ($("input[name='business']").val() == "" || $("input[name='business']").val() == null) {
                alert("请输入商家名");
                return false;
            } else if ($("input[name='price']").val() == "" || $("input[name='price']").val() == null) {
                alert("请输入价格");
                return false;
            } else if ($("input[name='saleNum']").val() == "" || $("input[name='saleNum']").val() == null) {
                alert("请输入销量");
                return false;
            } else if ($("input[name='inventory']").val() == "" || $("input[name='inventory']").val() == null) {
                alert("请输入库存");
                return false;
            }else if (!/^\d+(\.\d+)?$/.test($("input[name='price']").val())) {
                alert("价格格式不对");
                return false;
            } else if (!/^\d+$/.test($("input[name='saleNum']").val())) {
                alert("销量格式不对");
                return false;
            } else if (!/^\d+$/.test($("input[name='inventory']").val())) {
                alert("库存格式不对");
                return false;
            }
        }
    }
</script>

🍉BeanUtils自动封装Bean

1.引入jar包

2.修改src/com/zzw/furns/utils/DataUtils.java, 增加方法

java 复制代码
//将方法, 封装到静态方法, 方便使用
public static <T> T copyParamToBean(Map value, T bean) {
    try {
        //req.getParameterMap() 将数据封装到furn对象
        // 底层使用反射封装数据
        // 前端的name属性值需要和javabean的属性名一致
        BeanUtils.populate(bean, value);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    return bean;
}

3.修改src/com/zzw/furns/web/FurnServlet.javaadd方法, 使用BeanUtils自动封装javabean

java 复制代码
protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //这里我们使用第二种方式, 将前端提交的数据, 自动封装成Furn的Javabean对象
        //使用beanUtils完成javabean对象的自动封装
        Furn furn =
                DataUtils.copyParamToBean(req.getParameterMap(), new Furn());

        if (furnService.addFurn(furn)) {
            String pageNo = req.getParameter("pageNo");
            System.out.println("添加成功..");
            //req.getRequestDispatcher("/manage/furnServlet?action=list").forward(req, resp);
            resp.sendRedirect(req.getContextPath() + "/manage/furnServlet?action=list");
        } else {
            System.out.println("添加失败");
            req.setAttribute("errorMsg", "添加失败");
            req.getRequestDispatcher("/views/manage/furn_add.jsp").forward(req, resp);
        }
    }

debug小技巧👉

2.报错
原因: 由于前端没有传imagePath的字段, 所以后端在构建furn对象的时候, imagePath属性位null
解决方案 👇

🌳删除家居

需求分析

1.管理员进入到家居管理页面

2.点击删除家居链接, 弹出确认窗口, 确认-删除, 取消-放弃

程序框架图

1.修改com.zzw.furns.FurnDAO

java 复制代码
//根据id删除对应的furn对象
public boolean deleteFurnById(int id);

2.修改com.zzw.furns.impl.FurnDaoImpl

java 复制代码
@Override
public boolean deleteFurnById(int id) {
    String sql = "DELETE FROM furn WHERE id = ?";
    int updateRows = update(sql, id);
    return updateRows > 0;
}

3.测试, 修改FurnDaoTest

java 复制代码
@Test
public void deleteFurnById() {
    int id = 30;
    System.out.println("执行结果= " + furnDAO.deleteFurnById(id));
}

4.修改com.zzw.furns.FurnService

java 复制代码
//根据id删除家居
public boolean deleteFurnById(int id);

5.修改com.zzw.furns.impl.FurnServiceImpl

java 复制代码
@Override
public boolean deleteFurnById(int id) {
    return furnDAO.deleteFurnById(id);
}

6.测试,修改com.zzw.furns.impl.FurnServiceTest

java 复制代码
@Test
public void deleteFurnById() {
    int id = 31;
    System.out.println("执行结果= " + furnService.deleteFurnById(id));
}

6.web层 - 修改src/com/zzw/furns/web/FurnServlet.java, 增加del方法

java 复制代码
protected void del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int id = DataUtils.parseInt(req.getParameter("id"), 0);

        if (furnService.deleteFurnById(id) > 0) {
            System.out.println("删除成功");
        } else {
            System.out.println("删除失败");
            req.setAttribute("msg", "删除失败");
        }
        
        resp.sendRedirect(req.getContextPath() + "/manage/furnServlet?action=list");
    }

7.修改web/views/manage/furn_manage.jsp页面

html 复制代码
<a furnName="${furn.name}" href="manage/furnServlet?action=del&id=${furn.id}">
    <i class="icon-close"></i>
</a>

jQuery操作父元素, 兄弟元素, 子元素, 请移步👉
js弹框请移步👉

js 复制代码
<script src="scripts/jquery-3.6.0.js"></script>
<script type="text/javascript">
    window.onload = function () {
        $("a[furnName]").click(function () {
            var furnName = $(this).attr("furnName");

            //js弹框
            //1.window.confirm 方法会弹出一个确认窗口
            //2.点击确定, 返回true
            //3.点击取消, 返回false
            var b = window.confirm("你确认要删除 " + furnName+ " 家居信息吗?");
            if (!b) {
                return false;
            }
            //简便写法
            return window.confirm("你确认要删除 " + furnName+ " 家居信息吗?");

            //最终写法
            return confirm("你确定要删除 " + furnName + " 家居信息嘛?");
        });
    }
</script>

🌳修改家具

思路分析

1.管理员进入家居管理页面furn_manage.jsp

2.点击修改家居链接, 回显该家居信息 furn_update.jsp

3.填写新的信息, 点击修改家居按钮

4.修改成功后, 显示刷新后的家居列表

程序框架图

1.修改com.zzw.furns.FurnDAO

java 复制代码
//根据id查询furn对象
public Furn queryFurnById(int id);

//将传入的furn对象, 更新到数据库
public boolean updateFurn(Furn furn);

2.修改com.zzw.furns.impl.FurnDaoImpl

java 复制代码
/**
 * 根据传来的id查询对应的Furn对象
 *
 * @param id 参数
 * @return 返回查询到的Furn对象
 */
@Override
public Furn queryFurnById(int id) {
    String sql = "SELECT id, `name`, business, price, saleNum, inventory, " +
            "image_path as imagePath FROM furn WHERE id = ?";
    Furn furn = querySingle(sql, Furn.class, id);
    return furn;
}


/**
 * 根据id修改furn表对应的记录
 * @param furn 要修改的内容
 * @return 返回true或false
 */
@Override
public boolean updateFurn(Furn furn) {
    String sql = "UPDATE furn SET `name`=?, business=?, price=?, saleNum=?, inventory=?, image_path=? WHERE id=?";
    int updateRows =
            update(sql, furn.getName(), furn.getBusiness(), furn.getPrice(), furn.getSaleNum(),
                    furn.getInventory(), furn.getImagePath(), furn.getId());
    return updateRows > 0;
}

3.测试, 修改FurnDaoTest

java 复制代码
@Test
public void queryFurnById() {
    int id = 75;
    Furn furn = furnDAO.queryFurnById(id);
    System.out.println(furn);
}


@Test
public void updateFurn() {
    Furn furn = new Furn(5, "手机", "小米", new BigDecimal(3000), 6000, 9000, "zzw");
    furnDAO.updateFurn(furn);
    System.out.println();
}

4.修改com.zzw.furns.FurnService

java 复制代码
//根据id查询家居
public Furn queryFurnById(int id);

//根据id修改家居信息
public boolean updateFurn(Furn furn);

5.修改com.zzw.furns.impl.FurnServiceImpl

java 复制代码
/**
 * 根据前端传来的id查询家居
 *
 * @param id 参数
 * @return 返回查询到的家居
 */
@Override
public Furn queryFurnById(int id) {
    Furn furn = furnDAO.queryFurnById(id);
    return furn;
}

/**
 * 根据id修改家居信息
 *
 * @param furn 要修改的内容
 * @return 返回true或false
 */
@Override
public boolean updateFurn(Furn furn) {
    return furnDAO.updateFurn(furn);
}

6.测试,修改com.zzw.furns.impl.FurnServiceTest

java 复制代码
@Test
public void queryFurnById() {
    int id = 75;
    Furn furn = furnService.queryFurnById(id);
    System.out.println(furn);
}

@Test
public void updateFurn() {
    Furn furn = new Furn(75, "耳麦", "苹果", new BigDecimal(500),
            5000, 7000, "");
    System.out.println(furnService.updateFurn(furn));
}

7.web层 - 修改src/com/zzw/furns/web/FurnServlet.java, 增加display方法和update方法

java 复制代码
protected void display(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   int id = DataUtils.parseInt(req.getParameter("id"), 0);

    Furn furn = furnService.queryFurnById(id);
    if (furn != null) {
        //将furn对象放入request域
        req.setAttribute("furn", furn);
        req.getRequestDispatcher("/views/manage/furn_update.jsp")
                .forward(req, resp);
    } else {
        System.out.println("查询不到该信息");
        req.getRequestDispatcher("/manage/furnServlet?action=list")
                .forward(req, resp);
    }
}

protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   Furn furn =
            DataUtils.copyParamToBean(req.getParameterMap(), new Furn());

    if (furnService.updateFurn(furn) > 0) {
        System.out.println("更新成功");
        resp.sendRedirect(req.getContextPath() + "/manage/furnServlet?action=list");
    } else {
        req.setAttribute("msg", "更新失败");
        req.getRequestDispatcher("/manage/furnServlet?action=display&id=" + furn.getId())
                .forward(req, resp);
    }
}

8.前端, 修改web/views/manage/furn_manage.jsp页面, 点击修改,发出请求

html 复制代码
<a href="manage/furnServlet?action=display&id=${furn.id}">
    <i class="icon-pencil"></i>
</a>

9.添加web/views/manage/furn_update.jsp页面, 在tr标签下面添加span标签

html 复制代码
<span class="errorMsg"
      style="float: right; font-weight: bold; color: lightgray; font-size: 20pt; margin-left: 10px;">${msg}</span>


10.修改web/views/manage/furn_update.jsp页面, 数据校验

js 复制代码
<script src="script/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
    window.onload = function () {
        $("input[type='submit']")[0].onclick = function () {
            if ($("input[name='name']").val() == "" || $("input[name='name']").val() == null) {
                alert("请输入家居名");
                return false;
            } else if ($("input[name='business']").val() == "" || $("input[name='business']").val() == null) {
                alert("请输入商家名");
                return false;
            } else if ($("input[name='price']").val() == "" || $("input[name='price']").val() == null) {
                alert("请输入价格");
                return false;
            } else if ($("input[name='saleNum']").val() == "" || $("input[name='saleNum']").val() == null) {
                alert("请输入销量");
                return false;
            } else if ($("input[name='inventory']").val() == "" || $("input[name='inventory']").val() == null) {
                alert("请输入库存");
                return false;
            }else if (!/^\d+(\.\d+)?$/.test($("input[name='price']").val())) {
                alert("价格格式不对");
                return false;
            } else if (!/^\d+$/.test($("input[name='saleNum']").val())) {
                alert("销量格式不对");
                return false;
            } else if (!/^\d+$/.test($("input[name='inventory']").val())) {
                alert("库存格式不对");
                return false;
            }
        }
    }
</script>

11.测试,修改数据,点击提交


相关推荐
向宇it12 分钟前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
小蜗牛慢慢爬行14 分钟前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
星河梦瑾1 小时前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富1 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
love静思冥想1 小时前
JMeter 使用详解
java·jmeter
言、雲1 小时前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
TT哇1 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
Yvemil72 小时前
《开启微服务之旅:Spring Boot 从入门到实践》(三)
java
Anna。。2 小时前
Java入门2-idea 第五章:IO流(java.io包中)
java·开发语言·intellij-idea
.生产的驴2 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven