水果库存管理系统 进阶1 单sevlet版

6 篇文章 0 订阅
6 篇文章 0 订阅

水果库存管理系统 进阶1 单sevlet版

image-20220329104941719

上一个基础版,我们是写了好多个Servlet,然后每个不同的操作我们就去找到不同的Servlet去响应请求完成应答。这么写的逻辑好理解,但是如果代码量大了,就会显得比较乱,所以我们想,能否将所有的servlet整合到一个Servlet中呢?还真的可以。

Servlet改动

我们可以将所有servlet整合成一个大的FruitServlet,然后将原本那么多不同的servlet实现的功能写成FruitSerlet中的函数。

image-20220329110159581

首先第一步,创建一个FruitServlet,然后重写servlet方法:

request.setCharacterEncoding("UTF-8");

String operate = request.getParameter("operate");
if(StringUtil.isEmpty(operate)){
    operate = "index" ;
}

然后下面对这个operate进行判断:

switch(operate){
    case "index":
        index(request,response);
        break
    case "add":
        add(request,response);
        break;
    case "del":
        del(request,response);
        break;
    case "edit":
        edit(request,response);
        break;
    case "update":
        update(request,response);
        break;
    default:
        throw new RuntimeException("operate值非法!");

其实看这个FruitServlet就能大概理解一些,也就是FruitServlet会接受一个参数(方法名),然后根据这个参数判断要执行什么方法。

比如接收的参数为index,就执行index方法,接收的参数为add,就执行add方法。

所以我们要做的事也很简单,就是把原本不同servlet实现的功能写成FruitServlet中的不同函数。

比如说原本的UpdateServlet是这样的:

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");
    }
}

那么现在就得将里面的实现代码,都迁移到FruitServlet的update函数中。

private void update(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 ));

    response.sendRedirect("fruit.do");
}

之前不是有个 private FruitDAO fruitDAO = new FruitDAOImpl();现在就将这个写到FruitServlet的变量中就行了。

而唯一一处还需要注意的就是:

之前的最后是 response.sendRedirect(“index”);之前是直接让原本的请求去请求index.servlet(通过研究,发现让原本的update.html发送新的请求给index,且这个请求是没参数的),让其获取新的数据库中的数据然后重返页面。

而现在是 response.sendRedirect(“fruit.do”);现在得让原本的请求重新去请求fruit.do(FruitServlet),让其重新获取页面。

(原本以为不太行呀,因为FruitSevlet接收请求时需要传一个参数(方法名呀)但是这里没有。后面想了一想,可以的,这里是重定向,也就是让原本的请求去申请FruitSevlet,原本的请求是update.html,让其重新发一个请求给FruitServlet,且这个请求是没有参数的,所以Fruit.do前面设置如果获取不到方法的参数,就默认执行index方法。所以重定位请求页面时,就是执行index方法,重新渲染后显示页面。

String operate = request.getParameter("operate");
if(StringUtil.isEmpty(operate)){
    operate = "index" ;
}

还是有用的。

而其它三个方法都是同样道理:

    private void edit(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        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);
        }
    }

    private void del(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        String fidStr = request.getParameter("fid");
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            fruitDAO.delFruit(fid);

            //super.processTemplate("index",request,response);
            response.sendRedirect("fruit.do");
        }
    }

    private void add(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("fruit.do");

    }

    private void index(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
        HttpSession session = request.getSession() ;

        // 设置当前页,默认值1
        Integer pageNo = 1 ;

        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,则类型转换。否则,pageNo默认就是1
            }
            //如果不是点击的查询按钮,那么查询是基于session中保存的现有keyword进行查询
            Object keywordObj = session.getAttribute("keyword");
            if(keywordObj!=null){
                keyword = (String)keywordObj ;
            }else{
                keyword = "" ;
            }
        }

        // 重新更新当前页的值
        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 ;

        session.setAttribute("pageCount",pageCount);

   
        super.processTemplate("index",request,response);
    }
}

HTML代码改动

现在重点就在于修改html页面中的逻辑,让原本的请求某个特定servlet改为请求FruitServlet,然后同时传一个要执行的方法的名字参数过来。

比如输入关键词查询的逻辑这里:

<form th:action="@{/fruit.do}" 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>

action="@{/fruit.do},action要改成去找fruit.do,而重要的是下面要加一个,也就是加一个隐藏域将要执行的方法名传过去(search方法)

所以这两句的逻辑就是找到FruitSerlet,然后让其执行search方法,就跟之前找到searchServlet是同样的作用。

修改的地方改成这样:

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

有一些则是在JavaScript代码中改:

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

总结一下:

1.创建一个FruitServlet,然后将之前不同功能的类delServlet,editServlet,updateServlet改为FruitServlet中的不同函数。(记得重定位等代码需要改一些)

2.将html代码中的相应请求不同类的代码改写,改写为请求FruitServlet,同时传一个方法参数(可以是隐藏域发,或者是直接在地址名后面加)

进阶反射代码

如果说一个Sevrlet类中有很多个方法,那么我们做switch-case的时候会写很多很多代码,有没有什么改进呢?

switch(operate){
    case "index":
        index(request,response);
        break;
    case "add":
        add(request,response);
        break;
    case "del":
        del(request,response);
        break;
    case "edit":
        edit(request,response);
        break;
    case "update":
        update(request,response);
        break;
    default:
        throw new RuntimeException("operate值非法!");
}

太冗长了,有无改进的方法?

有,就是运用反射进制。

反射机制是啥咧?让我们复习一下

很简单,其实就是说,我们可以获取一个类的属性(比如获取一个类的成员变量,或者获取一个类的方法)。

比如 Class cls = Class.forName(className);Method method = cls.getMethod(methodName);

就是先获取一个类的原始类(给出路径),然后获取其中名字为methodName的方法。

同时,你还可以执行该方法,就是用invoke方法,但是要传一个实例进去。所以现在看一下要我们的switch-case案例可以怎么改:

  1. 获取FruitServlet的所有方法,然后看请求传过来的名字有没有名字相同的,有的话,执行该方法
  2. 如何执行该方法呢?就用invoke方法,然后实例传一个this指针进去。

代码如下:

    String operate = request.getParameter("operate");
    if(StringUtil.isEmpty(operate)){
        operate = "index" ;
    }
    //可以获取到该类的方法的数组
    Method[] methods=this.getClass().getDeclaredMethods();
    for(Method m:methods){
        String methodName=m.getName();
        if(operate.equals(methodName)){
            try {
                m.invoke(this,request,response);
                return;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    throw new RuntimeException("operate值非法")
}

源代码如下:
@WebServlet("/fruit.do")
public class FruitServlet extends ViewBaseServlet {
private FruitDAO fruitDAO = new FruitDAOImpl();

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

    String operate = request.getParameter("operate");
    if(StringUtil.isEmpty(operate)){
        operate = "index" ;
    }
    //可以获取到该类的方法的数组
    Method[] methods=this.getClass().getDeclaredMethods();
    for(Method m:methods){
        String methodName=m.getName();
        if(operate.equals(methodName)){
            try {
                m.invoke(this,request,response);
                return;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    throw new RuntimeException("operate值非法")
}


private void update(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 ));

    response.sendRedirect("fruit.do");
}

private void edit(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
    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);
    }
}

private void del(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
    String fidStr = request.getParameter("fid");
    if(StringUtil.isNotEmpty(fidStr)){
        int fid = Integer.parseInt(fidStr);
        fruitDAO.delFruit(fid);

        //super.processTemplate("index",request,response);
        response.sendRedirect("fruit.do");
    }
}

private void add(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("fruit.do");

}

private void index(HttpServletRequest request , HttpServletResponse response)throws IOException, ServletException {
    HttpSession session = request.getSession() ;

    // 设置当前页,默认值1
    Integer pageNo = 1 ;

    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,则类型转换。否则,pageNo默认就是1
        }
        //如果不是点击的查询按钮,那么查询是基于session中保存的现有keyword进行查询
        Object keywordObj = session.getAttribute("keyword");
        if(keywordObj!=null){
            keyword = (String)keywordObj ;
        }else{
            keyword = "" ;
        }
    }

    // 重新更新当前页的值
    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 ;

    session.setAttribute("pageCount",pageCount);


    super.processTemplate("index",request,response);
}

}

总结一下:

1.创建一个FruitServlet,然后将之前不同功能的类delServlet,editServlet,updateServlet改为FruitServlet中的不同函数。(记得重定位等代码需要改一些)

2.将html代码中的相应请求不同类的代码改写,改写为请求FruitServlet,同时传一个方法参数(可以是隐藏域发,或者是直接在地址名后面加)

3.利用反射机制,可以获取到类的方法名的一个数组,然后将传进来的方法名跟数组逐个比较,比较成功的就执行该方法。(反射机制,可以使代码更整洁)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值