mvc-servlet

博客围绕Java Servlet展开,指出网页不同请求对应多个Servlet会导致混乱,可采用一个Servlet内多方法响应。介绍了用反射改写switch语句,使用dispatcherServlet作为中央控制器接收并转发请求,还提及提取视图资源和在中央控制器处理参数等优化MVC架构的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        网页每发一个不同的请求都需要一个servlet去响应,这样servlet很多很乱。可以只写一个servlet对请求作响应,但是servlet内部可以有很多方法,对不同请求作响应。

        如下,使用一个operation参数记录网页要求的操作,然后用switch语句转向不同函数进行处理:

 //设置编码方式防止汉字乱码
        req.setCharacterEncoding("UTF-8");
        //根据发送的请求中的operation字段选择方法
        String oper=req.getParameter("operation");
        if (oper==null){
            oper="index";
        }
        switch (oper){
            case "index":
                indexServlet(req,resp);
                break;
            case "edit":
                editServlet(req,resp);
                break;
            case "del":
                delServlet(req,resp);
                break;
            case "insert":
                insertServlet(req,resp);
                break;
            case "update":
                updateServlet(req,resp);
                break;
            default:
                throw new RuntimeException("illegal value for operation");
        }

   一、dispatcherServlet

        如果网页请求很多,那switch...case...语句会很长。使用反射改写:

 //获取当前类中的所有方法(反射),如果方法名和operation参数相同,就调用该方法
        Method[] methods=this.getClass().getDeclaredMethods();
        for (Method m:methods){
            System.out.println(m.getName());
        }
        for (Method m:methods){
            if(oper.equals(m.getName())){
                try {
                    m.invoke(this,req,resp);
                    return;
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }

Notations;(1)声明的方法名要和operation值相等;(2)getDeclaredMethods才是获取自己声明的方法。

        而在实际中,会有很多servlet类,而每个之中会有很多方法。会有一个dispatcherServlet(中央控制器)来接收前端的请求,然后进行转发到各个类进行处理。可以将对某个请求的所有操作写在一个Controller里面,然后使用一个中央控制器将请求转发给处理它的Controller。

        现在src下新建一个xml,将请求和Controller的对应关系写到一个标签里面:      

<?xml version="1.0" encoding="UTF-8" ?>
<!--xml表示可扩展的标记语言,HTML是xml的子集
其包含三个部分:XML声明;DTD文档类型定义;XML正文
XML声明必须在第一行
-->
<!--因为是可扩展的,里面的标签可以自己定义-->
<beans>
    <!--这个标签将dispathcher中的名字与类对应起来-->
  <bean id="fruit" class="com.controllers.FruitController"/>
</beans>

         然后建立一个中央控制器,获得该文件中的bean标签的对应关系,用一个map存储,这个map称为容器。然后接收到请求后,通过反射查询相应Controller中的所有方法。

//*是通配符。表示拦截所有结尾.do的请求
//通配符不能只写一个*
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {

    //创建一个Map用来存放xml的bean标签中的id和class对应。Object是其中class的实例对象
    Map<String,Object> beanMap=new HashMap<String, Object>();
    //在构造方法中解析xml配置文件
    public DispatcherServlet() throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        //打开配置文件的流
        InputStream is=getClass().getClassLoader().getResourceAsStream("applicationController.xml");
        //创建一个 DocumentBuilder对象
        DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
        DocumentBuilder db=dbf.newDocumentBuilder();
        //创建Document对象
        Document doc=db.parse(is);
        //获取xml中所有的bean节点
        NodeList beanList=doc.getElementsByTagName("bean");
        for(int i=0;i<beanList.getLength();i++) {
            Node beanNode = beanList.item(i);
            //将beanNode强转为Element,为了使用里面的getAttribute方法
            if (beanNode.getNodeType()==Node.ELEMENT_NODE){
                Element nodeElement=(Element) beanNode;
                String beanId=nodeElement.getAttribute("id");
                String beanClass=nodeElement.getAttribute("class");
                //运用反射得到class对应的实例对象
                Object beanObj=Class.forName(beanClass).newInstance();
                beanMap.put(beanId,beanObj);
            }
        }
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        String servletPath=req.getServletPath();
      //把请求中的第一个/和后面的.do去掉
        servletPath=servletPath.substring(1,servletPath.lastIndexOf(".do"));
        //这就把beanMap里存放的xml文件里的对应关系给找了出来,也是找到了跟网页请求相对应的Controller对象
        Object beanObject=beanMap.get(servletPath);

        String oper=req.getParameter("operation");
        if (oper==null){
            oper="index";
        }

        //有了beanObject对象后,其对应的Controller应该有很多方法,对应执行不同的操作
        //通过反射查找该方法,传入参数为oper和req\resp对应的类
        try {
            //oper去匹配函数名字,后面是参数对象的class
            Method m=beanObject.getClass().getDeclaredMethod(oper,HttpServletRequest.class,HttpServletResponse.class);
            if(m!=null){
                m.invoke(beanObject,req,resp);
            }else{
                throw new RuntimeException("oper值非法");
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }
}

  二、提取视图资源

       在经过Controller的方法处理请求后,一般方法最后会进行重定向或者对当前页面渲染。可以在中央控制器对此集中处理,让方法只返回一个字符串。这样方法可以少抛出异常,也可以不用传入response参数。如下所示:

  //oper去匹配函数名字,后面是参数对象的class
            Method m=beanObject.getClass().getDeclaredMethod(oper,HttpServletRequest.class);
                m.setAccessible(true);
                if(m!=null){
                    if(m.invoke(beanObject,req)!=null){
                        String redirectStr=(String) m.invoke(beanObject,req);
                        //将该str截取,只保留后面的请求名称
                        if(redirectStr.startsWith("redirect:")){
                            redirectStr=redirectStr.substring("redirect:".length());
                            //重定向
                            resp.sendRedirect(redirectStr);
                        }else{
                            super.processTemplate(redirectStr,req,resp);
                        }
                    }
            }else{
                throw new RuntimeException("oper值非法");
            }

三、在中央控制器处理参数

        在Controller的每个函数中都有获取请求中函数的操作,那么可以将此直接在中央控制器处理。如下:

                   //获取参数,先反射获取所有参数
                    Parameter[] p=m.getParameters();
                    //保存参数请求request中各个参数的值,所以函数的参数名要和前端发射的请求的参数名称一样
                    Object[] parameterValue=new Object[p.length];
                    //如果参数是request,response,session就是直接获取
                    for (int i=0;i<p.length;i++){
                        if(p[i].getName().equals("request")){
                            parameterValue[i]=req;
                        }else if(p[i].getName().equals("response")){
                            parameterValue[i]=resp;
                        }else if(p[i].getName().equals("session")){
                            parameterValue[i]=req.getSession();
                        }else {
                            parameterValue[i] = req.getParameter(p[i].getName());
                        }
                    }

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值