(尚硅谷)JavaWeb新版教程05-水果管理系统的初步实现

系列文章目录

  1. (尚硅谷)JavaWeb新版教程03-Tomcat-Servlet,介绍了 Tomcat 和 Servlet 的基本内容,实现了 Tomcat 的部署运行和访问。
  2. 实现浏览器 - Servlet - 数据库交互操作,这里实现了在浏览器上添加数据,能够直接添加到数据库中的操作。
  3. (尚硅谷)JavaWeb新版教程04-Thymeleaf-保存作用域 ,介绍了 Thymeleaf 技术,实现了将数据库真实的数据显示到浏览器界面上。


需求

我们要实现的功能:

  1. 将每一个水果变成一个超链接,并且点击这个链接可以跳转到对应的编辑页面对这一栏进行编辑,edit 页面有这个水果的所有信息 – edit
  2. 对水果的信息 edit 之后,点击修改按钮之后,数据库中的数据修改了,返回到 index 界面上的数据也更改了 – update
  3. 点击删除小图标,删除对应的那一行水果,页面上跳出来是否确认删除的动态确认框,确认之后,删除对应行数据 – del
  4. 表格右上角显示可以添加新库存记录的超链接,点击之后跳转到一个新的添加界面(一个表单),点击添加按钮添加数据之后重新回到 index 界面 – add
  5. index 页面上分页显示,每页显示5个水果,并且在表格下方设置首页、上一页、下一页、尾页的按钮,点击对应按钮可以跳转到对应页面 – index
  6. 在表格上方添加一个按照任意关键字检索的一个功能,将水果名称和备注中带有这个关键字的水果查出来并分页显示 – index

备注:

  • 下面主要讲解后台实现,对于具体的 CSS 美观设置不做介绍;
  • 同时对文中 Thymeleaf 基本语法可以查看参考文献:第八章 Thymeleaf
  • 配置 servlet 映射均用注解的方式。

1、水果编辑功能

1.1 edit 功能实现

  1. 首先呢,想要点击水果的名字能进行界面跳转,那么我们需要先将这一行字变成一个超链接,即在这一行通过设置 <a> 标签的 href 的属性设置对应的链接跳转地址为 edit.do。
<td><a th:text="${fruit.fname}" th:href="@{/edit.do(fid=${fruit.fid})}">苹果</a></td>
  1. 那么我们就需要一个 edit.html 静态界面和一个 EditServlet 组件来处理 edit.do 请求。
  • edit.html 界面上要显示 名称、单价、库存、备注,同时还有修改按钮,所以是展示的页面需要用一个表格来显示。

edit.html 的表格实现如下:

<p class="center f30">编辑库存信息</p>
<table id="tbl_fruit" th:object="${fruit}">
<!-- 隐藏域 : 功能类似于文本框 , 它的值会随着表单的发送也会发送给服务器,但是界面上用户看不到 -->
<input type="hidden" name="fid" th:value="*{fid}"/>
	<tr>
		<th class="w20">名称:</th>
		<td><input type="text" name="fname" th:value="*{fname}"/></td>
	</tr>
	<tr>
		<th class="w20">单价:</th>
		<td><input type="text" name="price" th:value="*{price}"/></td>
	</tr>
	<tr>
		<th class="w20">库存:</th>
		<td><input type="text" name="fcount" th:value="*{fcount}"/></td>
	</tr>
	<tr>
		<th class="w20">备注:</th>
		<td><input type="text" name="remark" th:value="*{remark}"/></td>
	</tr>
	<tr>
		<th colspan="2">
			<input type="submit" value="修改" />
		</th>
	</tr>
</table>

解释:

  • 这里在整个表格的最开始的 table 标签写上 th:object=“${fruit}” ,那么在下面每一行使用 th:value=“*{fcount}” 时,表示这一行的数据显示的是从数据库上请求的 fruit.fcount 的数据;
  • 我们点击某一个水果怎么知道是哪个水果呢,通过每个水果的唯一主键 fid 来确认,但是这个 fid 用户是不需要的,所以设置一个隐藏属性,即将文本框 <input> 标签的 type 属性设置为 hidden 的就可以了;
  • 隐藏域 : 功能类似于文本框 , 它的值会随着表单的发送也会发送给服务器,但是界面上用户看不到。

EditServlet 组件实现:

@WebServlet("/edit.do")
public class EditServlet extends ViewBaseServlet {
	//新建一个fruitDAO的实现类对象,用来调用DAO方法,多态的体现
    private FruitDAO fruitDAO = new FruitDAOImpl();

    @Override
    public void doGet(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
    	//获取fid属性
        String fidStr = request.getParameter("fid");
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            //从后台获取数据
            Fruit fruit = fruitDAO.getFruitByFid(fid);
            //放到请求的保存作用域中
            request.setAttribute("fruit",fruit);
            //将这个页面渲染之后显示出来
            super.processTemplate("edit",request,response);
        }
    }
}

解释:

  • 没有设置请求方式,默认是 get 方式,所以重写 doGet 方法;
  • 从后台获取数据需要用到 fruitDAO 中的方法,新建一个 fruitDAO 的实现类对象,用来根据 fid 获取特定的水果库存信息,多态的体现。
  1. 这里需要通过 fid 获取水果信息,所以需要在 FruitDAO 接口中定义 getFruitByFid 方法,并且在 FruitDAOImpl 中调用 BaseDAO 的方法来实现这个方法。

FruitDAO 接口实现:

//根据fid获取特定的水果库存信息
Fruit getFruitByFid(Integer fid);

FruitDAOImpl 实现类实现这个方法:

@Override
public Fruit getFruitByFid(Integer fid) {
    return super.load("select * from t_fruit where fid = ? ", fid);
}

解释:

  • 这里的 super 调用的是 BaseDAO 父类中的方法。

1.2 update 功能实现

  1. 上面一步 edit 界面编辑好之后,还有一个修改按钮,既然点击修改按钮要能把数据提交给数据库,我们就需要将 edit 设置成一个 form 表单,将 form 标签设置在 table 标签外面,这样表格中修改的文本框也可以一起提交。
  2. 那么我们就需要点击 “修改” 按钮之后触发 update.do 行为,我们需要创建一个 UpdateServlet 组件来处理这个请求。

edit .html 界面添加:

<form th:action="@{/update.do}" method="post" th:object="${fruit}">

解释:

  • 其中的 th:action=“@{/update.do}” 表示跳转到 update.do 界面
  • 请求方式要写成 post 方法

UpdateServlet 组件实现:

@WebServlet("/update.do")
public class UpdateServlet extends ViewBaseServlet {

    private FruitDAO fruitDAO = new FruitDAOImpl();

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.设置编码
        request.setCharacterEncoding("utf-8");

        //2.获取表单参数
        String fidStr = request.getParameter("fid");
        Integer fid = Integer.parseInt(fidStr);
        String fname = request.getParameter("fname");
        String priceStr = request.getParameter("price");
        int price = Integer.parseInt(priceStr);
        String fcountStr = request.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);
        String remark = request.getParameter("remark");

        //3.执行更新
        fruitDAO.updateFruit(new Fruit(fid,fname, price ,fcount ,remark ));

        //4.资源跳转
        //super.processTemplate("index",request,response);
        //request.getRequestDispatcher("index.html").forward(request,response);
        //此处需要重定向,目的是重新给IndexServlet发请求,重新获取furitList,然后覆盖到session中,这样index.html页面上显示的session中的数据才是最新的
        response.sendRedirect("index");
    }
}

解释:

  • 上面表单的请求的方法是 post 方法,所以我们要重写 doPost 方法 ;
  • 因为要向数据库添加数据,可能有中文数据,首先要设置编码集,否则添加的中文字符就是乱码;
  • 此处资源跳转需要用重定向,目的是重新给 IndexServlet 发请求,重新获取 furitList,然后覆盖到 session 中,这样 index.html 页面上显示的 session 中的数据才是最新的;
  • 重新请求一次,数据库才会把新数据发给客户端,才会获取新数据放到保存作用域中,否则直接内部转发这个界面存放的仍然是未修改前的数据。
  1. 需要更新数据库中的某 fid 水果的四项基本信息,我们需要在 FruitDAO 接口中定义 updateFruit 方法,并且在 FruitDAOImpl 中调用 BaseDAO 的方法来实现这个方法。

FruitDAO 接口实现:

//修改指定的库存记录
void updateFruit(Fruit fruit);

FruitDAOImpl 实现类实现:

@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());
}

2、删除功能

  1. 我们点击小图标,想要把这一行数据删掉,先要跳出一个是否确认删除的确认框(js 的内容),我们新建一个 index.js 文件中放置这个功能函数

index.js 功能实现:

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

解释:

  • 这个 del.do?fid= 链接地址就是在我们的绝对地址基础上后面加上这一串,比如我们点击第一个水果,那么我们浏览器上显示的地址就会变成 http://localhost:8080/del.do?fid=1 ,从而跳到对应的页面。
  1. 然后我们在 index.html 的删除图标那一列调用这个函数

index.html 界面添加:

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

解释:

  • 里面的 th:οnclick=“|delFruit(${fruit.fid})|” ,双竖线括起来的代表一个函数,而不是一个字符串,$ 符代表一个请求的参数,这里当作 delFruit 这个函数的一个形参传进去。
  1. 我们需要删除数据库中的某 fid 水果,我们需要在 FruitDAO 接口中定义 delFruit 方法,并且在 FruitDAOImpl 中调用 BaseDAO 的方法来实现这个方法。

FruitDAO 接口实现:

//根据fid删除指定的库存记录
void delFruit(Integer fid);

FruitDAOImpl 实现类实现:

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

3、添加新库存记录

  1. 我们首先想要在表格右上角显示可以添加新库存记录的超链接,那么我们就需要在 index.html 中表格上方添加一个 div 块,独占一行,然后在 div 块中添加一个超链接标签 <a>。
<a th:href="@{/add.html}" style="border:0px solid blue;margin-bottom:4px;">添加新库存记录</a>
  1. 点击超链接之后跳转到一个新的添加界面(这里需要设置成一个表单),那我们要创建一个 add.html 文件

add.html 文件实现:

<div id="div_container">
	<div id="div_fruit_list">
		<p class="center f30">新增库存信息</p>
		<form action="add.do" method="post">
			<table id="tbl_fruit">
				<tr>
					<th class="w20">名称:</th>
					<!-- <td><input type="text" name="fname" th:value="${fruit.fname}"/></td> -->
					<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 colspan="2">
						<input type="submit" value="添加" />
					</th>
				</tr>
			</table>
		</form>
	</div>
</div>

解释:

  • form 表单,在点击 “添加” 按钮之后,我们要发送一个 add.do 请求给 AddServlet 组件;
  • 并且由于表单携带数据,所以方法设置为 post 方法。

注意:

  • 这里会有一个 bug 就是,在 add.html 页面写完东西之后点击添加没办法添加,还在这个静态页面,那是因为将 action=“add.do” 这个行为设置成 th:action=“@{/add.do}” 导致的。
  • 由于index.html中的添加超链接的 action 是 th:href=“@{/add.html}”,加上 .html 后缀是不经过 Thymeleaf 渲染的,所以在 add.html 中的所有有关的 Thymeleaf 表达式全部失效,也就是 th:xxxxxx 表达式全部失效,那么后面设置的 action 是失效的。
  • 解决方法就是将 所有有关 Thymeleaf 表达式全部删掉,替换成普通表单。

AddServlet 组件实现:

@WebServlet("/add.do")
public class AddServlet extends ViewBaseServlet {

    private FruitDAO fruitDAO = new FruitDAOImpl();

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");

        String fname = request.getParameter("fname");
        Integer price = Integer.parseInt(request.getParameter("price")) ;
        Integer fcount = Integer.parseInt(request.getParameter("fcount"));
        String remark = request.getParameter("remark");

        Fruit fruit = new Fruit(0,fname , price , fcount , remark ) ;

        fruitDAO.addFruit(fruit);//添加到后台

        response.sendRedirect("index");//重新发送请求,从后台获取数据,跳转到index页面
    }
}

解释:

  • 上面 add.html 请求的方法是 post 方法,所以我们要重写 doPost 方法;
  • 要写数据到数据库,所以要设置编码集;
  • 因为有新数据更新,所以要用重定向方式,再给服务端重新发送请求,获取新数据。
  1. 需要将数据添加到数据库,所以我们需要在 FruitDAO 接口中定义该方法,并且在 FruitDAOImpl 实现这方法。

FruitDAO 接口实现:

//添加新库存记录
void addFruit(Fruit fruit);

FruitDAOImpl 实现类实现:

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

4、分页显示

  1. 想要分页显示,每页显示5个水果,我们只需要修改对应的 sql 语句就可以了。

FruitDAO 接口实现:

//获取指定页码上的库存列表信息 , 每页显示5条
List<Fruit> getFruitList(Integer pageNo);

FruitDAOImpl 实现类实现:

@Override
public List<Fruit> getFruitList(Integer pageNo) {
    return super.executeQuery("select * from t_fruit limit ? , 5", (pageNo - 1) * 5);
}
  1. 然后我们要在表格下方设置首页、上一页、下一页、尾页的按钮,点击对应按钮可以跳转到对应页面,首先在 index.html 表格下方设置四个按钮。

index.html 修改如下:

<div style="width:60%;margin-left:20%;border:0px solid red;padding-top:4px;" class="center">
	<input type="button" value="首  页" class="btn"/>
	<input type="button" value="上一页"/>
	<input type="button" value="下一页" class="btn"/>
	<input type="button" value="尾  页" class="btn"/>
</div>
  1. 然后设置对应的页面函数,让服务端知道你想去哪个页面需要设置 th:onclick 事件。

index.html 修改如下:

<div style="width:60%;margin-left:20%;border:0px solid red;padding-top:4px;" 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>

解释:

  • 对于传给 page 函数的参数,我们需要获取当前会话作用域中保存的当前在第几页是什么,需要请求 session.pageNo,这里会话作用域中的值的设置需要 IndexServlet 组件来实现。

其中的 page 函数需要 JavaScript 来实现:

function page(pageNo){
    window.location.href="index?pageNo="+pageNo;
}

IndexServlet 组件实现:

//Servlet从3.0版本开始支持注解方式的注册
@WebServlet("/index")
public class IndexServlet extends ViewBaseServlet {
    @Override
    public void doGet(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        //获取当前的会话session
        HttpSession session = request.getSession() ;
        //设置当前页默认值为1
        Integer pageNo = 1 ;
        String pageNoStr = request.getParameter("pageNo");
        //如果从请求中读到了pageNo,就强转,如果没读到就默认为1
        if(StringUtil.isNotEmpty(pageNoStr)){
             pageNo = Integer.parseInt(pageNoStr);
         }

        //更新session中的pageNo值
        session.setAttribute("pageNo",pageNo);

        FruitDAO fruitDAO = new FruitDAOImpl();
        List<Fruit> fruitList = fruitDAO.getFruitList(pageNo);

        session.setAttribute("fruitList",fruitList);

        //此处的视图名称是 index
        //那么thymeleaf会将这个 逻辑视图名称 对应到 物理视图 名称上去
        //逻辑视图名称 :   index
        //物理视图名称 :   view-prefix + 逻辑视图名称 + view-suffix
        //所以真实的视图名称是:      /       index       .html
        super.processTemplate("index",request,response);
    }
}
  1. 点击尾页按钮的时候,我们需要跳到最后一页,那我们就需要知道当前数据库数据每页显示 5 个数据的话,一共能分成几页,需要计算一个 pageCount 值,同时修改 index.html 中尾页的 th:onclick 事件。

index.html 修改如下:

<input type="button" value="尾  页" class="btn" th:onclick="|page(${session.pageCount})|"/>

解释:

  • 我们还需要知道总共数据库中的数据需要多少页来显示,我们需要请求 session.pageCount 数据。
//Servlet从3.0版本开始支持注解方式的注册
@WebServlet("/index")
public class IndexServlet extends ViewBaseServlet {

    @Override
    public void doGet(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        //获取当前的会话session
        HttpSession session = request.getSession() ;
        //设置当前页默认值为1
        Integer pageNo = 1 ;
        String pageNoStr = request.getParameter("pageNo");
        //如果从请求中读到了pageNo,就强转,如果没读到就默认为1
        if(StringUtil.isNotEmpty(pageNoStr)){
             pageNo = Integer.parseInt(pageNoStr);
         }

        //更新session中的pageNo值
        session.setAttribute("pageNo",pageNo);

        FruitDAO fruitDAO = new FruitDAOImpl();
        List<Fruit> fruitList = fruitDAO.getFruitList(pageNo);
		//更新session中的fruitList列表
        session.setAttribute("fruitList",fruitList);

        //总记录条数
        int fruitCount = fruitDAO.getFruitCount(keyword);
        //总页数
        int pageCount = (fruitCount-1)/5 + 1;

		//更新session中的pageCount值
        session.setAttribute("pageCount",pageCount);

        super.processTemplate("index",request,response);
    }
}
  1. 在第一页的时候,我们不能再让用户往前点击了,这个时候 “第一页” 和 “首页” 按钮应该失效不能用了,在最后一页的时候,“下一页” 和 “尾页” 按钮需要失效,所以我们需要设置 th:disabled 属性,表示这个按钮不能使用了。

index.html 修改如下:

<div style="width:60%;margin-left:20%;border:0px solid red;padding-top:4px;" 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}"/>
	<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>

解释:

  • 当前的 pageNo 和当前的总共页数 pageCount 我们需要从会话作用域中去获取,所以用 session.pageNo 表示请求数据。

5、关键字查询功能

  1. 在表格上方添加一个按照任意关键字检索的一个功能,首先我们要有一个 div 块,其中前面提示 “请输入查询关键字”,后面有一个输入框能够让用户输入字符,后面还要有一个 “查询” 按钮。

index.html 实现:

<form th:action="@{/index}" method="post" style="float:left;width:60%;margin-left:20%;">
	<input type="hidden" name="oper" value="search"/>
	请输入关键字:<input type="text" name="keyword" th:value="${session.keyword}"/>
	<input type="submit" value="查询" class="btn"/>
</form>

解释:

  • 这个文本框中的信息要发送给服务端,所以要设置成 form 表单,同时还由 indexServlet 组件来处理,所以设置 action为 /index, 请求方法设置为 post 方法;
  • 因为要区分当前查询的请求和其他正常显示的 index 界面不一样,所以我们可以设置一个隐藏属性 oper 属性,其他操作发出的请求是没有这个 oper属性的,也就是为空;
  • 当点击下一页的时候,你输入的这个关键字还要显示在文本框一栏,所以需要从会话保存作用域中请求 session.keyword 参数。
  1. 我们需要根据这个获取到的关键字来限定从数据库获取到的数据,所以我们需要修改我们的 getFruitList 方法,其中包含文本框的关键字,同时 IndexServlet 组件处理这个请求。

FruitDAO 接口实现:

//获取指定页码上的库存列表信息 , 每页显示5条
List<Fruit> getFruitList(String keyword , Integer pageNo);

FruitDAOImpl 实现类实现:

@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);
}
  1. 获取 oper 参数,有就是查询操作,没有就是其他操作;
  2. 如果是查询操作,将此时的 pageNo 设置为 1 ,因为要从第一页开始显示,同时获取它的 keyword 参数值,并将它放置到会话作用域中
  3. 如果不是查询操作,但也有可能这个时候是我在查询界面,但是点击了上下页操作,所以在 oper 为空的时候也要处理一下 keyword 参数

IndexServlet 组件实现:

//Servlet从3.0版本开始支持注解方式的注册
@WebServlet("/index")
public class IndexServlet extends ViewBaseServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置编码集
        request.setCharacterEncoding("UTF-8");
        doGet(req,resp);
    }

    @Override
    public void doGet(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        //获取当前的会话session
        HttpSession session = request.getSession() ;
        //设置当前页默认值为1
        Integer pageNo = 1 ;

        //获取oper的值,判断查询表单是否由提交
        String oper = request.getParameter("oper");
        //如果oper!=null 说明 通过表单的查询按钮点击过来的
        //如果oper是空的,说明 不是通过表单的查询按钮点击过来的
        String keyword = null ;
        if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
            //说明是点击表单查询发送过来的请求
            //此时,pageNo应该还原为1 , keyword应该从请求参数中获取
            pageNo = 1 ;
            keyword = request.getParameter("keyword");
            //如果keyword为null,需要设置为空字符串,否则查询的时候会拼接成 %null%,我们期望的是 %%
            if(StringUtil.isEmpty(keyword)){
                keyword = "" ;
            }
            //将keyword保存或者覆盖到session中
            session.setAttribute("keyword",keyword);
        }else{
            //说明此处不是点击表单查询发送过来的请求(比如点击下面的上一页下一页或者直接在地址栏输入网址)
            //此时keyword应该从session作用域获取
            String pageNoStr = request.getParameter("pageNo");
            if(StringUtil.isNotEmpty(pageNoStr)){
                pageNo = Integer.parseInt(pageNoStr);//如果从请求中读到了pageNo,就强转,如果没读到就默认为1
            }
            //如果不是点击的查询按钮,那么查询是基于session中保存的现有keyword进行查询
            Object keywordObj = session.getAttribute("keyword");
            if(keywordObj!=null){
                keyword = (String)keywordObj ;
            }else{
                keyword = "" ;
            }
        }

        //更新session中的pageNo值
        session.setAttribute("pageNo",pageNo);

        FruitDAO fruitDAO = new FruitDAOImpl();
        List<Fruit> fruitList = fruitDAO.getFruitList(keyword , pageNo);

        session.setAttribute("fruitList",fruitList);

        //总记录条数
        int fruitCount = fruitDAO.getFruitCount(keyword);
        //总页数
        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);
    }
}

解释:

  • 因为请求方法为 post 方法,所以要重写 doPost 方法,但是实现逻辑还需要用到之前的那些方法,所以直接在 doPost 方法中调用 doGet 方法,实际实现逻辑添加到 doGet 方法中;
  • 由于要与数据库交互,传给数据库一个中文字符,所以要设置编码集,防止中文乱码

6、代码示例

6.1 html 代码

index.html 代码

<html xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="utf-8">
	<link rel="stylesheet" href="css/index.css">
	<script language="JavaScript" src="js/index.js"></script>
</head>
<body>
<div id="div_container">
	<div id="div_fruit_list">
		<p class="center f30">欢迎使用水果库存后台管理系统</p>
		<div style="border:0px solid red;width:60%;margin-left:20%;text-align:right;">
			<form th:action="@{/index}" method="post" style="float:left;width:60%;margin-left:20%;">
				<input type="hidden" name="oper" value="search"/>
				请输入关键字:<input type="text" name="keyword" th:value="${session.keyword}"/>
				<input type="submit" value="查询" class="btn"/>
			</form>
			<a th:href="@{/add.html}" style="border:0px solid blue;margin-bottom:4px;">添加新库存记录</a>
		</div>
		<table id="tbl_fruit">
			<tr>
				<th class="w20">名称</th>
				<th class="w20">单价</th>
				<th class="w20">库存</th>
				<th>操作</th>
			</tr>
			<tr th:if="${#lists.isEmpty(session.fruitList)}">
				<td colspan="4">对不起,库存为空!</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><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/del.jpg" class="delImg" th:οnclick="'delFruit('+${fruit.fid}+')'"/></td> -->
				<td><img src="imgs/del.jpg" class="delImg" th:onclick="|delFruit(${fruit.fid})|"/></td>
			</tr>
		</table>
		<div style="width:60%;margin-left:20%;border:0px solid red;padding-top:4px;" 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}"/>
			<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>
	</div>
</div>
</body>
</html>

edit.html 代码

<html xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta charset="utf-8">
		<link rel="stylesheet" href="css/edit.css">
	</head>
	<body>
		<div id="div_container">
			<div id="div_fruit_list">
				<p class="center f30">编辑库存信息</p>
				<form th:action="@{/update.do}" method="post" th:object="${fruit}">
					<!-- 隐藏域 : 功能类似于文本框 , 它的值会随着表单的发送也会发送给服务器,但是界面上用户看不到 -->
					<input type="hidden" name="fid" th:value="*{fid}"/>
					<table id="tbl_fruit">
						<tr>
							<th class="w20">名称:</th>
							<!-- <td><input type="text" name="fname" th:value="${fruit.fname}"/></td> -->
							<td><input type="text" name="fname" th:value="*{fname}"/></td>
						</tr>
						<tr>
							<th class="w20">单价:</th>
							<td><input type="text" name="price" th:value="*{price}"/></td>
						</tr>
						<tr>
							<th class="w20">库存:</th>
							<td><input type="text" name="fcount" th:value="*{fcount}"/></td>
						</tr>
						<tr>
							<th class="w20">备注:</th>
							<td><input type="text" name="remark" th:value="*{remark}"/></td>
						</tr>
						<tr>
							<th colspan="2">
								<input type="submit" value="修改" />
							</th>
						</tr>
					</table>
				</form>
			</div>
		</div>
	</body>
</html>

add.html 代码

<html xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta charset="utf-8">
		<link rel="stylesheet" href="css/add.css">
	</head>
	<body>
	<div id="div_container">
		<div id="div_fruit_list">
			<p class="center f30">新增库存信息</p>
			<!--<form action="add.do" method="post">-->
			<form action="add.do" method="post">
				<table id="tbl_fruit">
					<tr>
						<th class="w20">名称:</th>
						<!-- <td><input type="text" name="fname" th:value="${fruit.fname}"/></td> -->
						<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 colspan="2">
							<input type="submit" value="添加" />
						</th>
					</tr>
				</table>
			</form>
		</div>
	</div>
	</body>
</html>

6.2 CSS 代码

index.css 代码

*{
	color: threeddarkshadow;
}
a{
	text-decoration: none;
}
body{
	margin:0;
	padding:0;
	background-color:#808080;
}
div{
	position:relative;
	float:left;
}

#div_container{
	width:80%;
	height:100%;
	border:0px solid blue;
	margin-left:10%;
	float:left;
	background-color: honeydew;
	border-radius:8px;
}
#div_fruit_list{
	width:100%;
	border:0px solid red;
}
#tbl_fruit{
	width:60%;
	line-height:28px;
	margin-top:16px;
	margin-left:20%;
}
#tbl_fruit , #tbl_fruit tr , #tbl_fruit th , #tbl_fruit td{
	border:1px solid gray;
	border-collapse:collapse;
	text-align:center;
	font-size:16px;
	font-family:"黑体";
	font-weight:lighter;
	
}
.w20{
	width:20%;
}
.delImg{
	width:24px;
	height:24px;
}
.btn{
	border:1px solid lightgray;
	width:80px;
	height:24px;
}

.center{
	text-align:center;
}
.f30{
	font-size: 30px;
}

edit.css 代码

*{
	color: threeddarkshadow;
}
body{
	margin:0;
	padding:0;
	background-color:#808080;
}
div{
	position:relative;
	float:left;
}

#div_container{
	width:80%;
	height:100%;
	border:0px solid blue;
	margin-left:10%;
	float:left;
	background-color: honeydew;
	border-radius:8px;
}
#div_fruit_list{
	width:100%;
	border:0px solid red;
}
#tbl_fruit{
	width:60%;
	line-height:28px;
	margin-top:16px;
	margin-left:20%;
}
#tbl_fruit , #tbl_fruit tr , #tbl_fruit th , #tbl_fruit td{
	border:1px solid gray;
	border-collapse:collapse;
	text-align:center;
	font-size:16px;
	font-family:"黑体";
	font-weight:lighter;
	
}
.w20{
	width:20%;
}
.delImg{
	width:24px;
	height:24px;
}
.btn{
	border:1px solid lightgray;
	width:80px;
	height:24px;
}

.center{
	text-align:center;
}
.f30{
	font-size: 30px;
}

add.css 代码

*{
	color: threeddarkshadow;
}
body{
	margin:0;
	padding:0;
	background-color:#808080;
}
div{
	position:relative;
	float:left;
}

#div_container{
	width:80%;
	height:100%;
	border:0px solid blue;
	margin-left:10%;
	float:left;
	background-color: honeydew;
	border-radius:8px;
}
#div_fruit_list{
	width:100%;
	border:0px solid red;
}
#tbl_fruit{
	width:60%;
	line-height:28px;
	margin-top:16px;
	margin-left:20%;
}
#tbl_fruit , #tbl_fruit tr , #tbl_fruit th , #tbl_fruit td{
	border:1px solid gray;
	border-collapse:collapse;
	text-align:center;
	font-size:16px;
	font-family:"黑体";
	font-weight:lighter;
	
}
.w20{
	width:20%;
}
.delImg{
	width:24px;
	height:24px;
}
.btn{
	border:1px solid lightgray;
	width:80px;
	height:24px;
}

.center{
	text-align:center;
}
.f30{
	font-size: 30px;
}

6.3 JS 代码

index.js 代码:

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

function page(pageNo){
    window.location.href="index?pageNo="+pageNo;
}

6.4 Servlet 组件实现

IndexServlet 组件

5、关键字查询中有完整代码

EditSevlet 组件

1.1 edit 功能实现中有完整代码

UpdateServlet 组件

1.2 update 功能实现中有完整代码

DelServet 组件

2、删除功能中有完整代码

AddServlet 组件

3、添加新库存记录中有完整代码

7、网页展示

初始页面:
在这里插入图片描述
点击下一页:
在这里插入图片描述
点击尾页:
在这里插入图片描述

点击添加新库存按钮:
在这里插入图片描述
点击添加按钮之后尾页显示:
在这里插入图片描述

点击某水果进入编辑界面:
在这里插入图片描述
修改阿克苏1单价和库存点击修改按钮后:
在这里插入图片描述
点击阿克苏2的删除按钮:
在这里插入图片描述
确认删除后的尾页:
在这里插入图片描述
在查询框内输入阿点击查询按钮后:
在这里插入图片描述


总结

以上就是水果库存后台管理系统的初步实现,后序还会使用 MVC 对水果系统中的功能进行封装和修改。

  • 6
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值