栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

7.Java Web之mvc-servlet优化

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力
1.mvc-servlet优化1

将所有Servlet合并为一个

1.新建FruitServlet合并Servlet
2.修改指向其他Servlet的代码,指向FruitServlet,同时传operate参数指明采用什么操作(如add,del,update等)

① FruitServlet

package com.example.myssm.servlets;

import com.example.fruit.dao.FruitDAO;
import com.example.fruit.dao.impl.FruitDAOImpl;
import com.example.fruit.pojo.Fruit;
import com.example.myssm.myspringmvc.ViewBaseServlet;
import com.example.myssm.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;

@WebServlet("/fruit.do")
public class FruitServlet extends ViewBaseServlet {
    private FruitDAO fruitDAO = new FruitDAOImpl();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置编码
        req.setCharacterEncoding("utf-8");
        String operate = req.getParameter("operate");
        if(StringUtil.isEmpty(operate)){
            operate = "index";
        }
        switch(operate){
            case "index":
                index(req,resp);
                break;
            case "add":
                add(req,resp);
                break;
            case "del":
                del(req,resp);
                break;
            case "edit":
                edit(req,resp);
                break;
            case "update":
                update(req,resp);
                break;
            default:
                throw new RuntimeException("operate值非法");
        }
    }

    //UpdateServlet的doPost
    protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //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");
        int fcount = Integer.parseInt(fcountStr);
        String remark = req.getParameter("remark");

        //3 执行更新
        fruitDAO.updateFruit(new Fruit(fid,fname,price,fcount,remark));
        //4 资源跳转
//        super.processTemplate("index",req,resp);
        //req.getRequestDispatcher("inex.html").forward(req,resp);
        //此处需要重定向,目的是重新给IndexServlet发请求,重新获取fruitList,然后覆盖到session
        resp.sendRedirect("fruit.do");
    }

    //EditServlet得到doGet
    protected void edit(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String fidStr = req.getParameter("fid");
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            Fruit fruit = fruitDAO.getFruitByFid(fid);
            req.setAttribute("fruit",fruit);
            super.processTemplate("edit",req,resp);
        }
    }

    //delServlet的doGet
    protected void del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String fidStr = req.getParameter("fid");
    
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            fruitDAO.delFruit(fid);
            resp.sendRedirect("fruit.do");
        }
    }

    //addServlet的doPost
    protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String fname = req.getParameter("fname");
        String priceStr = req.getParameter("price");
        Integer price = Integer.parseInt(priceStr);
        String fcountStr = req.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);
        String remark = req.getParameter("remark");

        fruitDAO.addFruit(new Fruit(0,fname,price,fcount,remark));

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

    //indexServlet的doGet
    protected void index(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        Integer pageNo = 1;

        String oper = req.getParameter("oper");
        //如果oper!=null 说明,通过表单的查询按钮的过来的
        //如果oper是空的,说明,不是通过表单的查询按钮点过来的

        HttpSession session = req.getSession();
        String keyword = null;
        if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
            //说明是点击表单查询发送过来的请求
            //此时,pageNo应该还原为1,keyword应该从请求参数中获取
            pageNo = 1;
            keyword = req.getParameter("keyword");
            if(StringUtil.isEmpty(keyword)){
                keyword = "";
            }
            session.setAttribute("keyword",keyword);
        }else{
            //说明此处不是点击表单查询发送的请求
            String pageNoStr = req.getParameter("pageNo");
            if(StringUtil.isNotEmpty(pageNoStr)){
                pageNo = Integer.parseInt(pageNoStr);
            }
            Object keywordObj = session.getAttribute("keyword");
            if(keywordObj!=null){
                keyword = (String) keywordObj;
            }else{
                keyword = "";
            }
        }

        session.setAttribute("pageNo",pageNo);
        FruitDAO fruitDAO = new FruitDAOImpl();
        List fruitList = fruitDAO.getFruitList(keyword,pageNo);
        //保存到session作用域
        session.setAttribute("fruitList",fruitList);

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

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

② 修改index.html(index、查询、edit)



	
	
	


欢迎使用水果库存后台管理系统

请输入查询关键字:
添加新库存
名称 单价 库存 操作
对不起,库存为空!

7.Java Web之mvc-servlet优化

③ 修改add1.html(add)



    
    


编辑库存信息

名称:
单价:
库存:
备注:

④修改edit.xml(update)



    
    


编辑库存信息

名称:
单价:
库存:
备注:

⑤修改index.js(del、分页)

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

function page(pageNo){
    window.location.href="fruit.do?pageNo="+pageNo;
}
2.mvc-servlet优化2——reflect

采用反射机制优化FruitServlet

当存在很多方法时,写switch-case显得冗余,使用反射能很好的解决这一问题,而不需要关心具体有多少方法

修改FruitServlet的service方法

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置编码
        req.setCharacterEncoding("utf-8");
        String operate = req.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 {
                    //找到和operate同名的方法,那么通过反射技术调用它
                    m.invoke(this,req,resp);
                    return ;
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        throw new RuntimeException("operate值非法");
    }
3.mvc-servlet优化3——dispatcherServlet引入

dispatcherServlet(中央控制器、核心控制器)
通过dispatcherServlet去调用不同的Servlet(如userServlert,FruitServlet等)

①在java包下新建applicationContext.xml



    
    



②重命名FruitServlet为FruitController并修改(FruitController变为普通的类)

package com.example.myssm.servlets;

import com.example.fruit.dao.FruitDAO;
import com.example.fruit.dao.impl.FruitDAOImpl;
import com.example.fruit.pojo.Fruit;
import com.example.myssm.myspringmvc.ViewBaseServlet;
import com.example.myssm.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.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

public class FruitController extends ViewBaseServlet {
    //之前FruitServlet是一个Servlet组件,那么其中的init方法一定会被调用
    //之前的init方法内部有:super.init();

    private FruitDAO fruitDAO = new FruitDAOImpl();

    //UpdateServlet的doPost
    protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //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");
        int fcount = Integer.parseInt(fcountStr);
        String remark = req.getParameter("remark");

        //3 执行更新
        fruitDAO.updateFruit(new Fruit(fid,fname,price,fcount,remark));
        //4 资源跳转
//        super.processTemplate("index",req,resp);
        //req.getRequestDispatcher("inex.html").forward(req,resp);
        //此处需要重定向,目的是重新给IndexServlet发请求,重新获取fruitList,然后覆盖到session
        resp.sendRedirect("fruit.do");
    }

    //EditServlet得到doGet
    protected void edit(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String fidStr = req.getParameter("fid");
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            Fruit fruit = fruitDAO.getFruitByFid(fid);
            req.setAttribute("fruit",fruit);
            super.processTemplate("edit",req,resp);
        }
    }

    //delServlet的doGet
    protected void del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String fidStr = req.getParameter("fid");

        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            fruitDAO.delFruit(fid);
            resp.sendRedirect("fruit.do");
        }
    }

    //addServlet的doPost
    protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String fname = req.getParameter("fname");
        String priceStr = req.getParameter("price");
        Integer price = Integer.parseInt(priceStr);
        String fcountStr = req.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);
        String remark = req.getParameter("remark");

        fruitDAO.addFruit(new Fruit(0,fname,price,fcount,remark));

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

    //indexServlet的doGet
    protected void index(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        Integer pageNo = 1;

        String oper = req.getParameter("oper");
        //如果oper!=null 说明,通过表单的查询按钮的过来的
        //如果oper是空的,说明,不是通过表单的查询按钮点过来的

        HttpSession session = req.getSession();
        String keyword = null;
        if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
            //说明是点击表单查询发送过来的请求
            //此时,pageNo应该还原为1,keyword应该从请求参数中获取
            pageNo = 1;
            keyword = req.getParameter("keyword");
            if(StringUtil.isEmpty(keyword)){
                keyword = "";
            }
            session.setAttribute("keyword",keyword);
        }else{
            //说明此处不是点击表单查询发送的请求
            String pageNoStr = req.getParameter("pageNo");
            if(StringUtil.isNotEmpty(pageNoStr)){
                pageNo = Integer.parseInt(pageNoStr);
            }
            Object keywordObj = session.getAttribute("keyword");
            if(keywordObj!=null){
                keyword = (String) keywordObj;
            }else{
                keyword = "";
            }
        }

        session.setAttribute("pageNo",pageNo);
        FruitDAO fruitDAO = new FruitDAOImpl();
        List fruitList = fruitDAO.getFruitList(keyword,pageNo);
        //保存到session作用域
        session.setAttribute("fruitList",fruitList);

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

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

③新建DispatcherServlet类
获取所有applicationContext.xml中存的类并保存在beanMap中,根据传入的ServletPath来调用不同Controller(原Servlet)的方法

package com.example.myssm.myspringmvc;

import com.example.myssm.util.StringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@WebServlet("*.do")
public class DispatcherServlet extends HttpServlet {
    private Map beanMap = new HashMap<>();

    public DispatcherServlet(){
        try {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
            //1.创建DocumentBuilderFactory
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            //2.创建documentBuilder对象
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            //3.创建Document对象
            Document document = documentBuilder.parse(inputStream);

            //4.获取所有的bean节点
            NodeList beanNodeList = document.getElementsByTagName("bean");

            for(int i = 0;i < beanNodeList.getLength();i++){
                Node beanNode = beanNodeList.item(i);
                if(beanNode.getNodeType() == Node.ELEMENT_NODE){
                    Element beanElement = (Element) beanNode;
                    String beanId = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    Object beanObj = Class.forName(className).newInstance();

                    beanMap.put(beanId,beanObj);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置编码
        req.setCharacterEncoding("utf-8");

        //假设url是 http://localhost:8080/hello.do
        //那么servletPath是:/hello.do
        //思路是:
        //1./hello.do -> hello
        //2.hello -> HelloController
        String servletPath = req.getServletPath();
//        System.out.println("servletPath = " + servletPath); //servletPath = /hello.do
        int lastDotIndex = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(1,lastDotIndex);

//        System.out.println(servletPath); //hello

        Object controllerBeanObj = beanMap.get(servletPath);

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

        try {
            Method method = controllerBeanObj.getClass().getDeclaredMethod(operate, HttpServletRequest.class, HttpServletResponse.class);
            if(method!=null){
                method.setAccessible(true);
                method.invoke(controllerBeanObj,req,resp);
            }else{
                throw new RuntimeException("operate值非法");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

④ 由于FruitController没有调用构造器,因此没有调用父类ViewBaseServlet的init()方法,因此暂时无法正常运行,在下一节解决

4.mvc-servlet优化4——提取视图资源处理通用代码

解决上节资源跳转问题,将资源跳转放在DispatcherServlet中,且让DispatcherServlet继承ViewBaseServlet即可

① 修改FruitController(将资源跳转操作改为返回字符串,用于说明进行什么操作)

package com.example.myssm.servlets;

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;

public class FruitController{
    private FruitDAO fruitDAO = new FruitDAOImpl();

    //UpdateServlet的doPost
    protected String update(HttpServletRequest req){

        //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");
        int fcount = Integer.parseInt(fcountStr);
        String remark = req.getParameter("remark");

        //3 执行更新
        fruitDAO.updateFruit(new Fruit(fid,fname,price,fcount,remark));
        //4 资源跳转
//        super.processTemplate("index",req,resp);
        //req.getRequestDispatcher("inex.html").forward(req,resp);
        //此处需要重定向,目的是重新给IndexServlet发请求,重新获取fruitList,然后覆盖到session
//        resp.sendRedirect("fruit.do");
        return "redirect:fruit.do";
    }

    //EditServlet得到doGet
    protected String edit(HttpServletRequest req){
        String fidStr = req.getParameter("fid");
        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            Fruit fruit = fruitDAO.getFruitByFid(fid);
            req.setAttribute("fruit",fruit);
//            super.processTemplate("edit",req,resp);
            return "edit";
        }
        return "error";
    }

    //delServlet的doGet
    protected String del(HttpServletRequest req) {
        String fidStr = req.getParameter("fid");

        if(StringUtil.isNotEmpty(fidStr)){
            int fid = Integer.parseInt(fidStr);
            fruitDAO.delFruit(fid);
//            resp.sendRedirect("fruit.do");
            return "redirect:fruit.do";
        }
        return "error";
    }

    //addServlet的doPost
    protected String add(HttpServletRequest req){
        String fname = req.getParameter("fname");
        String priceStr = req.getParameter("price");
        Integer price = Integer.parseInt(priceStr);
        String fcountStr = req.getParameter("fcount");
        Integer fcount = Integer.parseInt(fcountStr);
        String remark = req.getParameter("remark");

        fruitDAO.addFruit(new Fruit(0,fname,price,fcount,remark));

//        resp.sendRedirect("fruit.do");
        return "redirect:fruit.do";
    }

    //indexServlet的doGet
    protected String index(HttpServletRequest req) {

        Integer pageNo = 1;

        String oper = req.getParameter("oper");
        //如果oper!=null 说明,通过表单的查询按钮的过来的
        //如果oper是空的,说明,不是通过表单的查询按钮点过来的

        HttpSession session = req.getSession();
        String keyword = null;
        if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
            //说明是点击表单查询发送过来的请求
            //此时,pageNo应该还原为1,keyword应该从请求参数中获取
            pageNo = 1;
            keyword = req.getParameter("keyword");
            if(StringUtil.isEmpty(keyword)){
                keyword = "";
            }
            session.setAttribute("keyword",keyword);
        }else{
            //说明此处不是点击表单查询发送的请求
            String pageNoStr = req.getParameter("pageNo");
            if(StringUtil.isNotEmpty(pageNoStr)){
                pageNo = Integer.parseInt(pageNoStr);
            }
            Object keywordObj = session.getAttribute("keyword");
            if(keywordObj!=null){
                keyword = (String) keywordObj;
            }else{
                keyword = "";
            }
        }

        session.setAttribute("pageNo",pageNo);
        FruitDAO fruitDAO = new FruitDAOImpl();
        List fruitList = fruitDAO.getFruitList(keyword,pageNo);
        //保存到session作用域
        session.setAttribute("fruitList",fruitList);

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

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

② DispatcherServlet(继承ViewBaseServlet,完成ViewBaseServlet的inie(),完成资源跳转)

package com.example.myssm.myspringmvc;

import com.example.myssm.util.StringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
    private Map beanMap = new HashMap<>();

    public DispatcherServlet(){
    }

    public void init() throws ServletException {
        super.init();
        try {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
            //1.创建DocumentBuilderFactory
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            //2.创建documentBuilder对象
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;
            //3.创建Document对象
            Document document = documentBuilder.parse(inputStream);

            //4.获取所有的bean节点
            NodeList beanNodeList = document.getElementsByTagName("bean");

            for(int i = 0;i < beanNodeList.getLength();i++){
                Node beanNode = beanNodeList.item(i);
                if(beanNode.getNodeType() == Node.ELEMENT_NODE){
                    Element beanElement = (Element) beanNode;
                    String beanId = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    Object beanObj = Class.forName(className).newInstance();
 
                    beanMap.put(beanId,beanObj);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置编码
        req.setCharacterEncoding("utf-8");
        //假设url是 http://localhost:8080/hello.do
        //那么servletPath是:/hello.do
        //思路是:
        //1./hello.do -> hello
        //2.hello -> HelloController
        String servletPath = req.getServletPath();
//        System.out.println("servletPath = " + servletPath); //servletPath = /hello.do
        int lastDotIndex = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(1,lastDotIndex);

//        System.out.println(servletPath); //hello

        Object controllerBeanObj = beanMap.get(servletPath);

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

        try {
            Method method = controllerBeanObj.getClass().getDeclaredMethod(operate, HttpServletRequest.class);

            if(method!=null){
                //2.Controller组件中的方法调用
                method.setAccessible(true);
                Object returnObj = method.invoke(controllerBeanObj,req);

                //3.视图处理
                String methodReturnStr = (String) returnObj;
                if(methodReturnStr.startsWith("redirect:")){//如:redirect:fruit.do
                    String redirectStr = methodReturnStr.substring("redirect:".length());
                    resp.sendRedirect(redirectStr);
                }else{
                    super.processTemplate(methodReturnStr,req,resp); //如:"edit"
                }
            }else{
                throw new RuntimeException("operate值非法");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5.mvc-servlet优化5——在核心控制器中统一获取参数及视图处理

参数的获取在DispatcherServlet中完成

① 获取参数的实际名称,对idea进行设置(jdk8 新特性)

② 删除out文件夹下的文件然后重新build

③ 修改FruitController的方法为参数传入的方式

package com.example.myssm.servlets;

import com.example.fruit.dao.FruitDAO;
import com.example.fruit.dao.impl.FruitDAOImpl;
import com.example.fruit.pojo.Fruit;
import com.example.myssm.util.StringUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;

public class FruitController{
    private FruitDAO fruitDAO = new FruitDAOImpl();

    //UpdateServlet的doPost
    protected String update(Integer fid,String fname ,Integer price,Integer fcount,String remark){
        //3 执行更新
        fruitDAO.updateFruit(new Fruit(fid,fname,price,fcount,remark));
        //4 资源跳转
//        resp.sendRedirect("fruit.do");
        return "redirect:fruit.do";
    }

    //EditServlet得到doGet
    protected String edit(Integer fid,HttpServletRequest req){
        if(fid != null){
            Fruit fruit = fruitDAO.getFruitByFid(fid);
            req.setAttribute("fruit",fruit);
//            super.processTemplate("edit",req,resp);
            return "edit";
        }
        return "error";
    }

    //delServlet的doGet
    protected String del(Integer fid) {
        if(fid != null){
            fruitDAO.delFruit(fid);
//            resp.sendRedirect("fruit.do");
            return "redirect:fruit.do";
        }
        return "error";
    }

    //addServlet的doPost
    protected String add(Integer fid,String fname ,Integer price,Integer fcount,String remark){
        fruitDAO.addFruit(new Fruit(0,fname,price,fcount,remark));
//        resp.sendRedirect("fruit.do");
        return "redirect:fruit.do";
    }

    //indexServlet的doGet
    protected String index(String oper,String keyword,Integer pageNo,HttpServletRequest req) {

        System.out.println(req);
        HttpSession session = req.getSession();
        if(pageNo == null){
            pageNo = 1;
        }
        if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
            //说明是点击表单查询发送过来的请求
            //此时,pageNo应该还原为1,keyword应该从请求参数中获取
            pageNo = 1;
            if(StringUtil.isEmpty(keyword)){
                keyword = "";
            }
            session.setAttribute("keyword",keyword);
        }else{
            Object keywordObj = session.getAttribute("keyword");
            if(keywordObj!=null){
                keyword = (String) keywordObj;
            }else{
                keyword = "";
            }
        }

        session.setAttribute("pageNo",pageNo);
        FruitDAO fruitDAO = new FruitDAOImpl();
        List fruitList = fruitDAO.getFruitList(keyword,pageNo);
        //保存到session作用域
        session.setAttribute("fruitList",fruitList);

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

//        super.processTemplate("index",req,resp);
        return "index";
    }
}

④ 修改DispatcherServlet获取参数

package com.example.myssm.myspringmvc;

import com.example.myssm.util.StringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
    private Map beanMap = new HashMap<>();

    public DispatcherServlet(){
    }

    public void init() throws ServletException {
        super.init();
        try {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
            //1.创建DocumentBuilderFactory
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            //2.创建documentBuilder对象
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;
            //3.创建Document对象
            Document document = documentBuilder.parse(inputStream);

            //4.获取所有的bean节点
            NodeList beanNodeList = document.getElementsByTagName("bean");

            for(int i = 0;i < beanNodeList.getLength();i++){
                Node beanNode = beanNodeList.item(i);
                if(beanNode.getNodeType() == Node.ELEMENT_NODE){
                    Element beanElement = (Element) beanNode;
                    String beanId = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    Object beanObj = Class.forName(className).newInstance();

                    beanMap.put(beanId,beanObj);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置编码
        req.setCharacterEncoding("utf-8");
        //假设url是 http://localhost:8080/hello.do
        //那么servletPath是:/hello.do
        //思路是:
        //1./hello.do -> hello
        //2.hello -> HelloController
        String servletPath = req.getServletPath();
//        System.out.println("servletPath = " + servletPath); //servletPath = /hello.do
        int lastDotIndex = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(1,lastDotIndex);

//        System.out.println(servletPath); //hello

        Object controllerBeanObj = beanMap.get(servletPath);

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

        try {
            Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
            for (Method method : methods) {
                if(operate.equals(method.getName())){
                    //1.统一获取请求参数
                    //获取当前方法的参数,返回参数数组
                    Parameter[] parameters = method.getParameters();
                    //parameterValues 用来承载参数的值
                    Object[] parameterValues = new Object[parameters.length];
                    for(int i = 0;i < parameters.length;i++){
                        Parameter parameter = parameters[i];
                        String parameterName = parameter.getName();
                        if("req".equals(parameterName)){
                            //如果参数名是req,resp,session 那么久不是通过请求中获取参数的方式了
                            parameterValues[i] = req;
                        }else if("resp".equals(parameterName)) {
                            parameterValues[i] = resp;
                        }else if("session".equals(parameterName)) {
                            parameterValues[i] = req.getSession();
                        }else{
                            //从请求中获取参数值
                            String parameterValue = req.getParameter(parameterName);

                            //类型转换 避免错误: IllegalArgumentException: argument type mismatch
                            String typeName = parameter.getType().getName();
                            Object parameterObj = parameterValue;
                            if(parameterObj != null){
                                if("java.lang.Integer".equals(typeName)){
                                    parameterObj = Integer.parseInt(parameterValue);
                                }
                            }
                            parameterValues[i] = parameterObj;
                        }
                    }

                    //2.Controller组件中的方法调用
                    method.setAccessible(true);
                    Object returnObj = method.invoke(controllerBeanObj,parameterValues);

                    //3.视图处理
                    String methodReturnStr = (String) returnObj;
                    if(methodReturnStr.startsWith("redirect:")){//如:redirect:fruit.do
                        String redirectStr = methodReturnStr.substring("redirect:".length());
                        resp.sendRedirect(redirectStr);
                    }else{
                        super.processTemplate(methodReturnStr,req,resp); //如:"edit"
                    }
                }
            }

//            }else{
//                throw new RuntimeException("operate值非法");
//            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

⑤ 启动tomcat容器,访问:http://localhost:8080/fruit.do
若出现问题:java.lang.IllegalArgumentException: InputStream cannot be null
将applicationContext.xml移动到resources包下

回顾
  1. 最初的做法是: 一个请求对应一个Servlet,这样存在的问题是servlet太多了
  2. 把一些列的请求都对应一个Servlet, IndexServlet/AddServlet/EditServlet/DelServlet/UpdateServlet -> 合并成FruitServlet
    通过一个operate的值来决定调用FruitServlet中的哪一个方法
    使用的是switch-case
  3. 在上一个版本中,Servlet中充斥着大量的switch-case,试想一下,随着我们的项目的业务规模扩大,那么会有很多的Servlet,也就意味着会有很多的switch-case,这是一种代码冗余
    因此,我们在servlet中使用了反射技术,我们规定operate的值和方法名一致,那么接收到operate的值是什么就表明我们需要调用对应的方法进行响应,如果找不到对应的方法,则抛异常
  4. 在上一个版本中我们使用了反射技术,但是其实还是存在一定的问题:每一个servlet中都有类似的反射技术的代码。因此继续抽取,设计了中央控制器类:DispatcherServlet
    DispatcherServlet这个类的工作分为两大部分:
    1.根据url定位到能够处理这个请求的controller组件:
    1)从url中提取servletPath : /fruit.do -> fruit
    2)根据fruit找到对应的组件:FruitController , 这个对应的依据我们存储在applicationContext.xml中
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/919961.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号