仿springmvc流程自写DispatcherServlet

spring框架中的web模块,可以让我们更好的管理servlet来进行交互操作。

8.1 配置文件

利用XML进行配置,xml是可扩展的标记语言。

XML包含3个部分:

1)XML声明,必须在XML的第一行

2)DTD声明

3)XML正文

利用java读入xml内容,利用反射实现类,这样可以使解耦合无法扩大,更加的利于代码维护。

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="fruit" class="online.fatotaku.controller.FruitController"></bean>
</beans>

8.2 DispatcherServlet

有了xml,我们需要利用java将xml内容读取,在我们没有实现spring-mvc.jar之前,我们手写了一个模仿DispatcherServlet的类。

8.2.1读取XML

我们写到可以提前运行的位置,也就是init方法当中。

//我们让dispatcherServlet读取出xml里面的bean来声明出来我们需要使用的controller
//输入流
InputStream inputStream =getClass().getClassLoader().getResourceAsStream("ApplicationContext.xml");
//文档工厂创建
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            try {
                //文档创建者 创建
                DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
                //文档创建
                Document document = documentBuilder.parse(inputStream);
                //从文档中获取标签为bean的内容
                NodeList beans = document.getElementsByTagName("bean");
                //遍历并把它放入MAP当中
                for (int i=0;i<beans.getLength();i++){
                    Node bean = beans.item(i);
                    if (bean.getNodeType()==Node.ELEMENT_NODE){
                        Element element=(Element) bean;
                        String id = element.getAttribute("id");
                        String className = element.getAttribute("class");
                        Object controllerClass =Class.forName(className).getDeclaredConstructor().newInstance();
                        controllers.put(id,controllerClass);
                    }
                

8.2.2 反射创建类

我们在service方法中利用网址的内容通过反射实现类的实现与方法的调用。

//从MAP当中获取你需要的类 
Object fruitController = controllers.get("fruit");
        String action = req.getParameter("action");
        try {
            //利用这个类反射调用你需要的方法
            Method method = fruitController.getClass().getDeclaredMethod(action,HttpServletRequest.class,HttpServletResponse.class);
            //实现方法
            method.invoke(fruitController,req, resp);
            Method setContext = fruitController.getClass().getDeclaredMethod("setContext", ServletContext.class);
           //实现方法
            setContext.invoke(fruitController,this.getServletContext());
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }

8.2.3 问题

当我们将本身的controller类取消掉Servlet类后,他失去了实现父类ViewBaseServlet的init方法,那我们的servletContext便无法通过init获取到值,所以需要改变一些内容。将dispatcherServlet里面的servletContext通过反射发给我们的Controller,在通过执行父类方法,传入我们的servletContext来实现重新编译。

            Method setContext = fruitController.getClass().getDeclaredMethod("setContext", ServletContext.class);
            setContext.invoke(fruitController,this.getServletContext());

    private ServletContext context;

    public void setContext(ServletContext context) {
        this.context = context;
        try {
            super.init(context);
        } catch (ServletException e) {
            e.printStackTrace();
        }

    }
 public void init(ServletContext context) throws ServletException {
        servletContext=context;
        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
 }

8.2.4统一方法参数

可以看到目前所使用的controller类中方法参数一样,并且十分臃肿,如果可以将它整体搬运到dispatcherServlet中进行统一放入,那将完成更好的松耦合。

//我们利用反射获取到的那个方法进行对于这个方法的参数获取。
 Method[] methods = controllerClass.getMethods();
            Method method = null;
            for (Method m : methods) {
                if (m.getName().equals(action)) {
                    method=m;
                    method.setAccessible(true);
                }
            }
            //所有参数
            assert method != null;
            Parameter[] parameters = method.getParameters();
            Object[] parameterValues=new Object[parameters.length];
            for (int i = 0; i < parameterValues.length; i++) {
                String paraName = parameters[i].getName();
                if (paraName.equals("req")) {
                    parameterValues[i]=req;
                }else if(paraName.equals("session")){
                    parameterValues[i]=req.getSession();
                }else{
                    parameterValues[i]=req.getParameter(paraName);
                }
            }

这里可以看到所调用的内容我们统一放在了object数组中,那在参数使用的方法中,他们是不同数据类型的参数,这就会引起报错。
我们该如何解决这个问题呢?

//我们获取参数类型进行判断
String paraTypeName = parameters[i].getType().getName();
 if (paraTypeName.equals("java.lang.Integer")) {
                        parameterValues[i]=Integer.parseInt(req.getParameter(paraName));
                    }else{
                        parameterValues[i]=req.getParameter(paraName);
                    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值