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

家居购项目

🐇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.测试,修改数据,点击提交


相关推荐
古月居GYH7 分钟前
在C++上实现反射用法
java·开发语言·c++
儿时可乖了1 小时前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
ruleslol1 小时前
java基础概念37:正则表达式2-爬虫
java
xmh-sxh-13141 小时前
jdk各个版本介绍
java
天天扭码2 小时前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶2 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺2 小时前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序2 小时前
vue3 封装request请求
java·前端·typescript·vue