JavaWeb-阶段性项目1:最简单的后台库存管理系统

1 写项目前

前置准备

知识准备

已掌握JavaSE/MySQL/JDBC+HTML/CSS/JavaScript基础

并已完成了Javaweb前置知识的学习

01-JavaWeb-HTML初识

02-JavaWeb-CSS初识

03-JavaWeb-JavaScript初识

04-JavaScript基础应用-鼠标悬浮/离开表格格式变化

05-JavaWeb-Tomcat8安装、Servlet初识

06-JavaWeb-Servlet方法/生命周期、HTTP/会话session

07-JavaWeb-视图模板技术Thymeleaf的使用

08-JavaWeb-Servlet保存作用域

资源准备

尚硅谷丨2022版JavaWeb教程视频

教学资源

https://pan.baidu.com/s/1TS7QJ_a2vHHmXkggAs8RMQ

提取码:yyds


文件目录

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>
        sample
    </title>
    <meta charset="UTF-8">
<link rel="stylesheet" href="imgs/css/index.css">
    <base href="http://localhost:8080/pro10/"/><!--当前页面上所有的路径都已href为基础-->
</head>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link href="../css/login.css" rel="stylesheet">
    <link th:href ="@{}/css/login.css">
</head>
<body>
    <p class="color">hello!</p>
</body>
</html>

以后都使用绝对路径    <link th:href ="@{}/css/login.css">的形式

后台管理系统页面

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>
        sample
    </title>
    <meta charset="UTF-8">
<link rel="stylesheet" href="imgs/css/index.css">
    <base href="http://localhost:8080/pro10/"/><!--当前页面上所有的路径都已href为基础-->
</head>
<body>
    <div id="div_containner">
        <div id="div_fruit_list">
            <p class="center f30">欢迎使用水果库存后台管理系统</p>
            <table id="tb1_fruit">
                <tr>
                    <th class="w20"><i>名称</i></th>
                    <th class="w20">单价</th>
                    <th class="w20">库存</th>
                    <th>操作</th>
                </tr>
                <tr th:if="${#lists.isEmpty(session.fruitList)}">
                    <td colspan="4">sorry, is empty</td>
                </tr>
                <tr th:unless="${#lists.isEmpty(session.fruitList)}" th:each="fruit : ${session.fruitList}">
                    <td th:text="${fruit.fname}">苹果</td>
                    <td th:text="${fruit.price}">5</td>
                    <td th:text="${fruit.fcount}">20</td>
                    <td><img src="imgs/delete.png" class="delImg"/></td>
                </tr>
            </table>
        </div>
    </div>
</body>
</html>

2 开始项目

实现功能1的过程

功能1:在水果名称上点击,超链接跳转显示详情页面,可以在详情页面编辑。

①给名称加上超链接

使用HTML内容元素<a>苹果</a>

 <a th:text="${fruit.fname}">苹果</a>

这里运用到了thymeleaf技术,

之前在会话域session中通过“fruitList”这个key取到的value是fruitList列表

@WebServlet("/index")
public class IndexServlet extends ViewBaseServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        FruitDAO fruitDAO = new FruitDAOImpl();
        List<Fruit> fruitList = fruitDAO.getFruitList();
        //保存到session作用域
        HttpSession session = req.getSession();
        session.setAttribute("fruitList",fruitList);

        //此处的视图名称是index
        //thymeleaf会将这个逻辑视图名称对应到物理视图名称上
        //逻辑视图名称 index
        //物理视图名称 view-prefix + 逻辑视图名称 + view-suffix
        //真实的视图名称是 / index .html
        super.processTemplate("index",req,resp);


    }
}

th:each="fruit : ${session.fruitList},每迭代一次取一个fruit对象,作为临时变量赋给“fruit”

可以看到,fruit.可以直接获取我们想要的fruit属性,

  • 经过服务器解析,Thymeleaf引擎根据th:text属性指定的『标签体新值』去替换『标签体原始值』

${fruit.fname}值覆盖到超链接标签中,根据之前的循环代码,就给全部的名称都打上了超链接!如下图:

②点击超链接跳转edit.html页面

 增加一个edit.html页面,作为我们编辑信息的页面

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>
        sample
    </title>
    <meta charset="UTF-8">
<link type="text/css" rel="stylesheet" href="css/edit.css">
    <base href="http://localhost:8080/pro10/"/><!--当前页面上所有的路径都已href为基础-->
</head>
<body>
    <div id="div_containner">
        <div id="div_fruit_list">
            <p class="center f30">编辑库存信息</p>
            <table id="tb1_fruit">
                <tr>
                    <th class="w20"><i>名称:</i></th>
                    <td><input type="text" name="fname" th:value="${fruit.fname}"/></td>
                </tr>
                <tr>
                    <th class="w20">单价:</th>
                    <td><input type="text" name="price" th:value="${fruit.price}"/></td>
                </tr>
                <tr>
                    <th class="w20">库存:</th>
                    <td><input type="text" name="fcount" th:value="${fruit.fcount}"/></td>
                </tr>
                <tr>
                    <th class="w20">备注:</th>
                    <td><input type="text" name="remark" th:value="${fruit.remark}"/></td>
                </tr>
                <tr>
                    <th th colspan="2">
                        <input type="submit" value="修改" />
                    </th>
                </tr>
            </table>
        </div>
    </div>
</body>
</html>

视频中的五次改写

超链接跳转到edit页面,edit.do给servlet发请求(.do的要意思就是调用servlet里面的doxxxx方法)

<td> <a th:text="${fruit.fname}" th:href=edit.do>苹果</a></td>

加上之前介绍的绝对路径表示方法${}

<td> <a th:text="${fruit.fname}" th:href="@{/edit.do}">苹果</a></td>

不光需要增加超链接,还需给后台发送参数fid,以获得对应的信息,这样才能在edit页面中编辑

<td> <a th:text="${fruit.fname}" th:href="@{/edit.do?fruit.fid}">苹果</a></td>

有一部分是字符串不需要thymeleaf解析,另一部分需要,所以这样改写。

<td> <a th:text="${fruit.fname}" th:href="@{/'edit.do?fid='+fruit.fid}">苹果</a></td>

最终写法(普通表达式与字符串拼接,还可以使用双竖线):

<td> <a th:text="${fruit.fname}" th:href="@{/edit.do(fid=${fruit.fid})}">苹果</a></td>

③在edit.html页面显示相应信息

增加一个servlet组件

package com.fancy.fruit.servlets;

import com.fancy.fruit.dao.FruitDAO;
import com.fancy.fruit.dao.impl.FruitDAOImpl;
import com.fancy.fruit.pojo.Fruit;
import com.fancy.myssm.basedao.myspringmvc.ViewBaseServlet;
import com.fancy.myssm.basedao.util.StringUtil;

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

@WebServlet("/edit.do")
public class EditServlet extends ViewBaseServlet {

    private FruitDAO fruitDAO = new FruitDAOImpl();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String fidStr = req.getParameter("fid");
        //HTML是模板,thymeleaf是引擎,我们在servlet中调用了引擎并且给了引擎需要的模板和参数
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            Fruit fruit = fruitDAO.getFruitByFid(fid);
            //获取到fruit对象后将之放置在session作用域
            req.setAttribute("fruit",fruit);
            //thymeleaf的viewBaseServlet中的方法,处理模板数据
            super.processTemplate("edit",req,resp);
        }
    }
}
HTML是模板,thymeleaf是引擎,我们在servlet中调用了引擎并且给了引擎需要的模板和参数

工具类

package com.fancy.myssm.basedao.util;

public class StringUtil {
    //判断字符串是否为null或者“”
    public static boolean isEmpty(String str){
        return str == null || "".equals(str);
    }

    public static boolean isNotEmpty(String str){
        return !isEmpty(str);
    }
}

判断从请求包中根据fid获取到的fid参数是否为空(是否取到了)

如果取到了,servlet就转发给thymeleaf渲染,最终展现在edit.html页面上。

最终效果

edit.html改写

<table id="tb1_fruit">
                <tr>
                    <th class="w20"><i>名称:</i></th>
                    <td><input type="text" name="fname" th:value="${fruit.fname}"/></td>
                </tr>
                <tr>
<table id="tb1_fruit" th:object="${fruit}">
    <tr>
        <th class="w20"><i>名称:</i></th>
        <td><input type="text" name="fname" th:value="*{fname}"/></td>
    </tr>
    <tr>

表示在table标签内部所使用的属性都是来自于fruit对象中

④在edit.html页面修改后提交

修改BaseDAO的executeUpdate方法

BaseDAO修改前

//执行更新,返回影响行数
protected int executeUpdate(String sql , Object... params){
    boolean insertFlag = false ;
    insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
    try {
        conn = getConn();
        if(insertFlag){
            psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
        }else {
            psmt = conn.prepareStatement(sql);
        }
        setParams(psmt,params);
        int count = psmt.executeUpdate() ;
​
        rs = psmt.getGeneratedKeys();
        if(rs.next()){
            return ((Long)rs.getLong(1)).intValue();
        }
        return count ;
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        close(rs,psmt,conn);
    }
    return 0;
}

BaseDAO修改后

//执行更新,返回影响行数
protected int executeUpdate(String sql , Object... params){
    boolean insertFlag = false ;
    insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
    try {
        conn = getConn();
        if(insertFlag){
            psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
        }else {
            psmt = conn.prepareStatement(sql);
        }
        setParams(psmt,params);
        int count = psmt.executeUpdate() ;
​
        if(insertFlag){
            rs = psmt.getGeneratedKeys();
            if(rs.next()){
                return ((Long)rs.getLong(1)).intValue();
            }
        }
        return count ;
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        close(rs,psmt,conn);
    }
    return 0;
}

修改原因:只有insert操作时需要获取自增列,所以要在rs = psmt.getGeneratedKeys();前加判断

 

跟着视频敲完代码后报500错误,查看原因,看报错信息定位updateservlet第25行,参数写错了

原因

实现功能2的过程 (删除与添加)

①在index.html页面点击删除图标删除数据

在index.html\页面添加

<td><img src="imgs/delete.png" class="delImg" th:onclick="'delFruit('+${fruit.fid}+')'"/></td>

使用竖线自动识别thymeleaf表达式添加‘

<td><img src="imgs/delete.png" class="delImg" th:onclick="|delFruit(${fruit.fid})|"/></td>

添加js文件

function delFruit(fid){
    if(confirm("是否确认删除")){
        window.location.href='del.do?fid='+fid;
    }
}
  • window-当前网页窗口

  • location-地址栏对象

  • 地址栏对象的href属性附上del.do?fid

新建DelServlet

package com.fancy.fruit.servlets;
​
import com.fancy.fruit.dao.FruitDAO;
import com.fancy.fruit.dao.impl.FruitDAOImpl;
​
import com.fancy.myssm.basedao.myspringmvc.ViewBaseServlet;
import com.fancy.myssm.basedao.util.StringUtil;
​
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
​
@WebServlet("/del.do")
public class DelServlet extends ViewBaseServlet {
    private FruitDAO fruitDAO = new FruitDAOImpl();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取fid
        String fidStr = req.getParameter("fid");
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
        }
    }
}

 

没有删掉,排错

delFruit方法写错了,应该调用父类的executeUpdate方法来进行数据库数据的删除操作

    @Override
    public void delFruit(Integer fid){
        super.executeUpdate("delete from t_fruit where fid = ? ",fid) ;
    }
}

成功删除了

②在index.html页面新增添加水果信息功能

在index页面上添加添加库存记录的页面链接

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>
        sample
    </title>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="imgs/css/index.css">
    <script language="JavaScript" src="js/index.js"></script>
    <base href="http://localhost:8080/pro10/"/><!--当前页面上所有的路径都已href为基础-->
</head>
<body>
    <div id="div_containner">
        <div id="div_fruit_list">
            <p class="center f30">欢迎使用水果库存后台管理系统</p>
            <div style="border:0px solid red;width:60%;margin-left:32%;text-align:right;">
                <a th:href="@{/add.html}" style="border:0px solid blue;margin-bottom:4px">添加新库存记录</a>
            </div>
            <table id="tb1_fruit">
                <tr>
                    <th class="w20"><i>名称</i></th>
                    <th class="w20">单价</th>
                    <th class="w20">库存</th>
                    <th>操作</th>
                </tr>
                <tr th:if="${#lists.isEmpty(session.fruitList)}">
                    <td colspan="4">sorry, is empty</td>
                </tr>
                <tr th:unless="${#lists.isEmpty(session.fruitList)}" th:each="fruit : ${session.fruitList}">
                    <td> <a th:text="${fruit.fname}" th:href="@{/edit.do(fid=${fruit.fid})}">苹果</a></td>
                    <td th:text="${fruit.price}">5</td>
                    <td th:text="${fruit.fcount}">20</td>
                    <td><img src="imgs/delete.png" class="delImg" th:onclick="|delFruit(${fruit.fid})|"/></td>
                </tr>
            </table>
        </div>
    </div>
</body>
</html>

添加add.html页面

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>
        sample
    </title>
    <meta charset="UTF-8">
<link type="text/css" rel="stylesheet" href="css/edit.css">
    <base href="http://localhost:8080/pro10/"/><!--当前页面上所有的路径都已href为基础-->
</head>
<body>
    <div id="div_containner">
        <div id="div_fruit_list">
            <p class="center f30">编辑库存信息</p>
            <form th:action="@{/add.do}" method="post" th:object="${fruit}">
                <!--隐藏域,它的值会随着表单一起发送给服务器,用户看不见 -->
                <input type="hidden" name="fid" th:value="*{fid}"/>
            <table id="tb1_fruit">
                <tr>
                <tr>
                    <th class="w20"><i>名称:</i></th>
                    <td><input type="text" name="fname"/></td>
                </tr>
                <tr>
                    <th class="w20">单价:</th>
                    <td><input type="text" name="price"/></td>
                </tr>
                <tr>
                    <th class="w20">库存:</th>
                    <td><input type="text" name="fcount"/></td>
                </tr>
                <tr>
                    <th class="w20">备注:</th>
                    <td><input type="text" name="remark"/></td>
                </tr>
                <tr>
                    <th th colspan="2">
                        <input type="submit" value="添加" />
                    </th>
                </tr>
            </table>
                <form/>
        </div>
    </div>
</body>
</html>

新建添加功能的servlet组件

package com.fancy.fruit.servlets;
​
import com.fancy.fruit.dao.FruitDAO;
import com.fancy.fruit.dao.impl.FruitDAOImpl;
import com.fancy.fruit.pojo.Fruit;
import com.fancy.myssm.basedao.myspringmvc.ViewBaseServlet;
​
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
​
@WebServlet("/add.do")
public class AddServlet extends ViewBaseServlet {
    private FruitDAO fruitDAO = new FruitDAOImpl();
​
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.设置编码
        req.setCharacterEncoding("UTF-8");
        //2.获取参数
        String fidStr = req.getParameter("fid");
        int fid = Integer.parseInt(fidStr);
        String fname = req.getParameter("fname");
        String priceStr = req.getParameter("price");
        int price = Integer.parseInt(priceStr);
        String fcountStr = req.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);
        String remark = req.getParameter("remark");
​
        Fruit fruit = new Fruit(fid, fname, price, fcount, remark);
​
        fruitDAO.addFruit(fruit);
        
        resp.sendRedirect("index");
    }
}

为什么是doPost?因为input的是表单form

 

在FruitDAO接口添加新的方法addFruit

package com.fancy.fruit.dao;
​
import com.fancy.fruit.pojo.Fruit;
​
import java.util.List;
​
public interface FruitDAO {
    //获取所有的库存列表信息
    List<Fruit> getFruitList();
​
    //根据fid获取特定的水果库存信息
    Fruit getFruitByFid(Integer fid);
​
    //修改指定的库存记录
    void updateFruit(Fruit fruit);
​
    //根据fid删除指定的库存记录
    void delFruit(Integer fid);
    
    //添加新库存记录
    void addFruit(Fruit fruit);
}

在FruitDAOImpl实现该方法addFruit()

package com.fancy.fruit.dao.impl;
​
import com.fancy.fruit.dao.FruitDAO;
import com.fancy.fruit.pojo.Fruit;
import com.fancy.myssm.basedao.BaseDAO;
​
import java.util.List;
​
public class FruitDAOImpl extends BaseDAO<Fruit> implements FruitDAO {
    @Override
    public List<Fruit> getFruitList() {
        return super.executeQuery("select * from t_fruit");
    }
​
    //根据fid获取特定的水果库存信息
    @Override
    public Fruit getFruitByFid(Integer fid){
        return super.load("select * from t_fruit where fid= ? ",fid);
    }
​
    @Override
    public void updateFruit(Fruit fruit) {
        String sql = "update t_fruit set fname = ? , price = ? , fcount = ? , remark = ? where fid = ? " ;
        super.executeUpdate(sql,fruit.getFname(),fruit.getPrice(),fruit.getFcount(),fruit.getRemark(),fruit.getFid());
    }
​
    @Override
    public void delFruit(Integer fid){
        super.executeUpdate("delete from t_fruit where fid = ? ",fid) ;
    }
​
    public void addFruit(Fruit fruit){
        String sql = "insert into t_fruit values(0,?,?,?,?,?)";
        super.executeUpdate(sql,fruit.getFname(),fruit.getPrice(),fruit.getFcount(),fruit.getRemark(),fruit.getFid());
    }
}

问题,一直报错Uncaught ReferenceError: page is not defined at HTMLInputElement.onclick,以下根据我跟着视频敲遗漏造成代码的问题的排错过程,仅供参考,最终解决方案请直接移步“视频36P问题最终解决方案”

没有添加进去?

排错一

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    super.processTemplate("add.html",req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    super.processTemplate("add",req,resp);
}

排错二

412-A specified precondition has failed for this request.为此请求指定的先决条件失败。

服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.设置编码
        req.setCharacterEncoding("UTF-8");
        //2.获取参数
        String fidStr = req.getParameter("fid");
        int fid = Integer.parseInt(fidStr);
        String fname = req.getParameter("fname");
        String priceStr = req.getParameter("price");
        int price = Integer.parseInt(priceStr);
        String fcountStr = req.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);
        String remark = req.getParameter("remark");
​
        Fruit fruit = new Fruit(fid, fname, price, fcount, remark);
​
        fruitDAO.addFruit(fruit);
​
        resp.sendRedirect("index");
    }
}

修改后

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.设置编码
        req.setCharacterEncoding("UTF-8");
        //2.获取参数
        String fname = req.getParameter("fname");
        String priceStr = req.getParameter("price");
        int price = Integer.parseInt(priceStr);
        String fcountStr = req.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);
        String remark = req.getParameter("remark");
​
        Fruit fruit = new Fruit(0, fname, price, fcount, remark);
​
        fruitDAO.addFruit(fruit);
​
        resp.sendRedirect("index");
    }
}

再次添加

还是412...

再次检查,FruitDAOImpl里的addFruit方法错了

修改前

public void addFruit(Fruit fruit){
    String sql = "insert into t_fruit values(0,?,?,?,?,?)";
    super.executeUpdate(sql,fruit.getFname(),fruit.getPrice(),fruit.getFcount(),fruit.getRemark(),fruit.getFid());
}

修改后

public void addFruit(Fruit fruit){
    String sql = "insert into t_fruit values(0,?,?,?,?)";
    super.executeUpdate(sql,fruit.getFname(),fruit.getPrice(),fruit.getFcount(),fruit.getRemark());
}
视频36P问题最终解决方案

最后还要改add.html,改成@{/adds.do}

<form th:action="@{/adds.do}" method="post">

在AddServlet里加一个doGet方法

public class AddServlet extends ViewBaseServlet {
    private FruitDAO fruitDAO = new FruitDAOImpl();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.processTemplate("adds",req,resp);
    }

实现功能3的过程(添加分页)

实现分页切换功能

①获取指定页码上的库存列表信息,每页显示5条

public interface FruitDAO {
    //获取指定页码上的库存列表信息,每页显示5条
    List<Fruit> getFruitList(Integer pageNo);
public class FruitDAOImpl extends BaseDAO<Fruit> implements FruitDAO {
    @Override
    public List<Fruit> getFruitList(Integer pageNo) {
        return super.executeQuery("select * from t_fruit limit ?,5",(pageNo-1)*5);
    }
public class IndexServlet extends ViewBaseServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        FruitDAO fruitDAO = new FruitDAOImpl();
        List<Fruit> fruitList = fruitDAO.getFruitList(1);
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>
        sample
    </title>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="imgs/css/index.css">
    <script type="text/javaScript" src="js/index.js"></script>
    <base href="http://localhost:8080/pro11/"/><!--当前页面上所有的路径都已href为基础-->
</head>
<body>
    <div id="div_containner">
        <div id="div_fruit_list">
            <p class="center f30">欢迎使用水果库存后台管理系统</p>
            <div style="border:0px solid red;width:60%;margin-left:32%;text-align:right;">
                <a th:href="@{/adds.do}" style="border:0px solid blue;margin-bottom:4px;">添加新库存记录</a>
            </div>
            <table id="tb1_fruit">
                <tr>
                    <th class="w20"><i>名称</i></th>
                    <th class="w20">单价</th>
                    <th class="w20">库存</th>
                    <th>操作</th>
                </tr>
                <tr th:if="${#lists.isEmpty(session.fruitList)}">
                    <td colspan="4">sorry, is empty</td>
                </tr>
                <tr th:unless="${#lists.isEmpty(session.fruitList)}" th:each="fruit : ${session.fruitList}">
                    <td> <a th:text="${fruit.fname}" th:href="@{/edit.do(fid=${fruit.fid})}">苹果</a></td>
                    <td th:text="${fruit.price}">5</td>
                    <td th:text="${fruit.fcount}">20</td>
                    <td><img src="imgs/delete.png" class="delImg" th:onclick="|delFruit(${fruit.fid})|"/></td>
                </tr>
            </table>
            <div style="width:60%;margin-left:10%;border:0px;" class="center">
                <input type="button" value="首 页" class="btn" th:onclick="|page(1)|"/>
                <input type="button" value="上一页" class="btn" th:onclick="|page(${session.pageNo - 1})|"/>
                <input type="button" value="下一页" class="btn" th:onclick="|page(${session.pageNo+1})|"/>
                <input type="button" value="尾 页" class="btn"/>
            </div>
        </div>
    </div>
</body>
</html>

index.js

function delFruit(fid){
    if(confirm("是否确认删除")){
        window.location.href='del.do?fid='+fid;
    }
}
​
function page(pageNo){
    window.location.href="index?pageNo="+pageNo;
}

②实现尾页跳转效果

package com.fancy.fruit.servlets;
​
​
import com.fancy.fruit.dao.FruitDAO;
import com.fancy.fruit.dao.impl.FruitDAOImpl;
import com.fancy.fruit.pojo.Fruit;
import com.fancy.myssm.basedao.myspringmvc.ViewBaseServlet;
import com.fancy.myssm.basedao.util.StringUtil;
​
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
​
//Servlet从3.0版本开始支持注解方式的注册
@WebServlet("/index")
public class IndexServlet extends ViewBaseServlet {
    @Override
    public void doGet(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        Integer pageNo = 1 ;
        String pageNoStr = request.getParameter("pageNo");
        if(StringUtil.isNotEmpty(pageNoStr)){
            pageNo = Integer.parseInt(pageNoStr);
        }
​
        HttpSession session = request.getSession() ;
        session.setAttribute("pageNo",pageNo);
​
        FruitDAO fruitDAO = new FruitDAOImpl();
        List<Fruit> fruitList = fruitDAO.getFruitList(pageNo);
​
        session.setAttribute("fruitList",fruitList);
​
        //总记录条数
        int fruitCount = fruitDAO.getFruitCount();
        //总页数
        int pageCount = (fruitCount+5-1)/5 ;
        /*
        总记录条数       总页数
        1               1
        5               1
        6               2
        10              2
        11              3
        fruitCount      (fruitCount+5-1)/5
         */
        session.setAttribute("pageCount",pageCount);
​
        //此处的视图名称是 index
        //那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
        //逻辑视图名称 :   index
        //物理视图名称 :   view-prefix + 逻辑视图名称 + view-suffix
        //所以真实的视图名称是:      /       index       .html
        super.processTemplate("index",request,response);
    }
}

③设置首页、上一页、尾页无法点击

<div style="width:60%;margin-left:10%;border:0px;padding-top:5px;" class="center">
    <input type="button" value="首 页" class="btn" th:onclick="|page(1)|" th:disabled="${session.pageNo==1}"/>
    <input type="button" value="上一页" class="btn" th:onclick="|page(${session.pageNo - 1})|" th:disabled="${session.pageNo==1}" th:disabled="${session.pageNo==1}"/>
    <input type="button" value="下一页" class="btn" th:onclick="|page(${session.pageNo+1})|" th:disabled="${session.pageNo==session.pageCount}"/>
    <input type="button" value="尾 页" class="btn" th:onclick="|page(${session.pageCount})|" th:disabled="${session.pageNo==session.pageCount}"/>
</div>

实现功能4的过程(根据关键字查询)

在index添加form表单

</head>
<body>
    <div id="div_containner">
        <div id="div_fruit_list">
            <p class="center f30">欢迎使用水果库存后台管理系统</p>
            <div style="border:0px solid red;width:60%;margin-left:32%;text-align:right;">
                <form th:action="@{search.do}" method="post">
                    请输入查询关键字:<input type="text" name="keyword"/>
                    <input type="submit" value="查询" class="btn">
                </form>
                <a th:href="@{/adds.do}" style="border:0px solid blue;margin-bottom:4px;">添加新库存记录</a>
            </div>

①模糊查询(带分页效果)

添加一个隐藏的oper变量

将action改为向index页面发送数据单(action属性用于规定当提交表单时,向何处发送表单数据)

<form th:action="@{/index}" method="post" style="border:1px solid red;">
    <input type="hidden" name="oper" value="search"/>
    请输入查询关键字:<input type="text" name="keyword"/>
    <input type="submit" value="查询" class="btn">
</form>

在IndexServlet添加相应判断条件

//Servlet从3.0版本开始支持注解方式的注册
@WebServlet("/index")
public class IndexServlet extends ViewBaseServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
​
    }
​
    @Override
    public void doGet(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        //添加关键词查询功能
        request.setCharacterEncoding("UTF-8");
        Integer pageNo = 1 ;
        HttpSession session = request.getSession() ;
​
        String oper = request.getParameter("oper");
        //如果oper!=null 说明是通过表单的查询按钮点击过来的
        //如果oper = null 说明不是通过表单的查询按钮点击过来的
        String keyword = null;
        if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
            //说明是通过表单的查询按钮点击过来的
            //此时pageNo应该还原为1,keyword应该从请求参数中获取
            pageNo = 1;
            keyword = request.getParameter("keyword");
            if(StringUtil.isEmpty(keyword)){
                keyword = "";
            }
            session.setAttribute("keyword",keyword);
        }else {
            //说明此处不是通过表单的查询按钮点击过来的,比如是点击上一页、下一页或直接在地址栏输入
            //此时keyword应该从session作用域中获取
            String pageNoStr = request.getParameter("pageNo");
            if(StringUtil.isNotEmpty(pageNoStr)){
                pageNo = Integer.parseInt(pageNoStr);
            }
            Object keywordObj =session.getAttribute("keyword");
            if(keywordObj != null){
                keyword = (String) keywordObj;
            }else {
                keyword = "" ;
            }
        }

因为index传递过来的是form表单(同之前的edit),这里在doPost方法里调用doGet,因为本次要实现的功能与之前doGet方法的功能差不多,只需要在查询列表时增加keyword关键词判断,所以只需在doGet里实现较为方便。

添加一个隐藏的oper变量,是为了判断keyword是否是通过表单的查询按钮点击过来的,

如果是,需要将pageNo还原为1,因为查询到的结果是从第一页开始显示的,然后我们就从请求参数中获取keyword;并且判断keyword是空的情况(有可能用户什么都没输入点了“查找”),将keyword赋值为空字符串,最后将keyword保存到session作用域中;

如果不是,首先从请求中获取pageNo,判断是否为空,不为空就转化为integer类型变量,再从session作用域中获取keyword对象,不为空则转化为String类型,为空则重新赋值为空字符串。

 

在FruitDAO接口增加相应方法

import com.fancy.fruit.pojo.Fruit;
​
import java.util.List;
​
public interface FruitDAO {
    //获取指定页码上的根据关键词检索到的库存列表信息,每页显示5条
    List<Fruit> getFruitList(String keyword,Integer pageNo);
​
    //根据fid获取特定的水果库存信息
    Fruit getFruitByFid(Integer fid);
​
    //修改指定的库存记录
    void updateFruit(Fruit fruit);
​
    //根据fid删除指定的库存记录
    void delFruit(Integer fid);
​
    //添加新库存记录
    void addFruit(Fruit fruit);
​
    //查询根据关键词检索到的库存总记录条数
    int getFruitCount(String keyword);
}

在FruitDAOImpl实现两个方法

public class FruitDAOImpl extends BaseDAO<Fruit> implements FruitDAO {
    @Override
    public List<Fruit> getFruitList(String keyword,Integer pageNo) {
        return super.executeQuery("select * from t_fruit where fname like ? or remark like ? limit ? , 5","%"+keyword+"%","%"+keyword+"%",(pageNo-1)*5);
    }
@Override
public int getFruitCount(String keyword) {
    return ((Long)super.executeComplexQuery("select count(*) from t_fruit where fname like ? or remark like ?","%"+keyword+"%","%"+keyword+"%")[0]).intValue();
}

在 给方法添加keyword

List<Fruit> fruitList = fruitDAO.getFruitList(keyword,pageNo);
​
session.setAttribute("fruitList",fruitList);
​
//总记录条数
int fruitCount = fruitDAO.getFruitCount(keyword);

运行

搜索“果”,查询名称和备注带有果的水果信息

可实现翻页

②查询后关键字一直显示

在index页面加入th:value

<form th:action="@{/index}" method="post" style="border:1px solid red;">
    <input type="hidden" name="oper" value="search"/>
    请输入查询关键字:<input type="text" name="keyword" th:value="${session.keyword}" />
    <input type="submit" value="查询" class="btn">
</form>

查询的关键字可一直显示在框内


以上内容是本人在学习尚硅谷2022新版Javaweb中34-38P的过程中的学习笔记,如有遗漏或错误的地方请私信我,一起交流、共同进步。后续还将跟视频进度同步更新更多内容。

转载本文内容请注明出处。

posted @ 2022-08-04 23:59  Fancy[love]  阅读(202)  评论(0编辑  收藏  举报