自定义MVC引用XML配置文件实现

简介: 自定义MVC引用XML配置文件实现

前言

     在这篇 自定义MVC框架思想 中我已详细描述了工作原理及流程,本篇主要在此基础上继续做出优化,实现步骤如下:

自定义MVC实现

1. 导入XML配置文件

<?xml version="1.0" encoding="UTF-8"?>
<config>
  <action path="/order" type="com.ycxw.servlet.OrderAction">
    <forward name="success" path="/index.jsp" redirect="true" />
    <forward name="failed" path="/register.jsp" redirect="false" />
  </action>
  <action path="/book" type="com.ycxw.servlet.BookAction">
    <forward name="List" path="/book.jsp" redirect="false" />
    <forward name="toList" path="/index.jsp" redirect="true" />
  </action>
</config>

将其部署到Source Folder文件中

 

 

2. 导入XML解析建模

这里就不一一详细解说了,可以去 XML建模 中了解详细建模实例。

 

3. 优化中央控制器

3.1 修改DisPathServlet中init初始化方法

在DisPathServlet的init方法中将原有Map集合方式替换成XML建模方式  

// 通过xml建模方法进行储存

   private ConfigModel configModel;

   @Override

   public void init() throws ServletException {

       /**

        * 初始化存值就是给每个施工员根据施工证进行存档:

        */

       try {

           // configModel包含了所有的子控制器

           configModel = ConfigModelFactory.build();

       } catch (Exception e) {

           e.printStackTrace();

       }

   }

3.2 修改ActionServlet逻辑处理流程

根据请求路径名获取ActionModel

这里如果查不到指定对象,请认真检查xml文件的配置,以及截取的内容是否与xml配置相同

/**
     * 获取请求路径
     */
    String uri = request.getRequestURI();
    // 截取book
    uri = uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf("."));
    // 要通过uri->> /book,在configModel对象中找
    ActionModel actionModel = configModel.pop(uri);
    // 判断没找对象等于空就抛出异常
    if (actionModel == null)
      throw new RuntimeException("action not config");
    /**
     * 获取config文件中action标签的type属性值
     * type指java类
     * com.ycxw.servlet.BookAction
     */
    String type = actionModel.getType();

3.3  通过反射机制实例化子控制器类

package com.ycxw.framework;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 子控制器(action) 处理浏览器请求的类
 * 
 * @author 云村小威
 *
 * 2023年6月29日 下午8:30:32
 */
public class Action {
  public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 获取methodName值,这里指前端点击功能传来的方法名
    String methodName = request.getParameter("methodName");
    //定义一个变量来保存返回值
    String res = "";
    /**
     * this--->BookAction/BlogAction/PermissionAction...可能是很多对象
     * 所以需要通过反射找到对象带request,response参数的methidName方法
     */
    Method m = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
    m.setAccessible(true);
    // 动态调用其方法
    res = (String) m.invoke(this, request, response);
    return res ;
  }
}

3.4 中央控制器将请求委托给子控制器处理

Action instance = (Action) Class.forName(type).newInstance();

// 业务代码执行后返回值

String execute = instance.execute(request, response);

3.5 根据请求结果码跳转页面

        // 通过返回值拿到,该方法结果是重定向还是转发,还是跳转哪个页面
      ForwardModel forwardModel = actionModel.pop(execute);
      if (forwardModel != null) {
        // 获取forwardModel是否从定向值
        boolean redirect = forwardModel.isRedirect();
        /**
         * 获取xml元素path值   
         */
        String path = forwardModel.getPath();
        // 判断是否为重定向
        if (redirect) {
          response.sendRedirect(request.getContextPath() + "/" + path);
        } else {
          request.getRequestDispatcher(path).forward(request, response);
        }
      }

4. 反射赋值

4.1 创建接口DriverModel<T>

package com.ycxw.framework;
/**
 * 模型驱动接口
 * Book book = new Book();
 * @author 云村小威
 *
 * @param <T>
 */
public interface ModelDriver<T> {
  T getModel();
}

4.2 实现接口类

针对需要进行反射赋值的具体子控制器类,实现该接口DriverModel。

package com.ycxw.servlet;
import java.io.IOException;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ycxw.entity.Book;
import com.ycxw.framework.Action;
import com.ycxw.framework.ModelDriver;
/**
 * 施工类 继承子控制器
 * 
 * @author 云村小威
 *
 * @2023年6月29日 下午8:32:59
 */
public class BookAction extends Action implements ModelDriver<Book>{
  //创建表对应的属性对象
  Book book = new Book();
  @Override
  public Book getModel() {
    // TODO Auto-generated method stub
    return book;
  }
  public String load(HttpServletRequest req, HttpServletResponse resp) {
    //获取所有的参数
    Map<String, String[]> map = req.getParameterMap();
    System.out.println("Book查询的业务逻辑");
    try {
      resp.sendRedirect("index.jsp");
    } catch (IOException e) {
      e.printStackTrace();
    }
    return "List";
  }
  public String query(HttpServletRequest req, HttpServletResponse resp) {
    System.out.println("Book查询的业务逻辑");
    try {
      resp.sendRedirect("index.jsp");
    } catch (IOException e) {
      e.printStackTrace();
    }
    return "List";
  }
  public String edit(HttpServletRequest req, HttpServletResponse resp) {
    System.out.println("Book修改的业务逻辑");
    try {
      resp.sendRedirect("index.jsp");
    } catch (IOException e) {
      e.printStackTrace();
    }
    return "toList";
  }
  public String delete(HttpServletRequest req, HttpServletResponse resp) {
    System.out.println("Book删除的业务逻辑");
    try {
      resp.sendRedirect("index.jsp");
    } catch (IOException e) {
      e.printStackTrace();
    }
    return "toList";
  }
  public String add(HttpServletRequest req, HttpServletResponse resp) throws Exception {
    System.out.println("Book新增的业务逻辑");
    req.getRequestDispatcher("index.jsp").forward(req, resp);
    return "toList";
  }
}

只要实现了DriverModel接口,则必须要对实体类进行初始化,并在getModel()方法中返回实例化后的对象。

 

4.3  反射对象赋值

再次修改ActionServlet中的业务逻辑处理流程,在反射调用方法之前,请先进行反射参数赋值操作。

/**
     * 获取config文件中action标签的type属性值
     * type指java类
     * com.ycxw.servlet.BookAction
     */
    String type = actionModel.getType();
    // 通过反射创建对象
    Action instance;
    try {
      instance = (Action) Class.forName(type).newInstance();
      // 判断bookAction有没有实现ModelDriver接口
      if (instance instanceof ModelDriver) {
        // 向下转型获取接口方法
        ModelDriver md = (ModelDriver) instance;
        Object bean = md.getModel();
        // 把获取的参数保存到该对象中
        BeanUtils.populate(bean, request.getParameterMap());
      }

5. 完整优化中央控制器实例

5.1 完整 DisPathServlet类代码

package com.ycxw.framework;
import java.io.IOException;
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 org.apache.commons.beanutils.BeanUtils;
import com.ycxw.framework.model.ActionModel;
import com.ycxw.framework.model.ConfigModel;
import com.ycxw.framework.model.ConfigModelFactory;
import com.ycxw.framework.model.ForwardModel;
/**
 * 中央控制器(ActionServlet)
 * 
 * @author 云村小威
 *
 * @2023年6月29日 下午8:14:38
 */
@WebServlet("*.action")
public class DisPathServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;
  // 通过xml建模方法进行储存
  private ConfigModel configModel;
  @Override
  public void init() throws ServletException {
    /**
     * 初始化存值就是给每个施工员根据施工证进行存档:
     */
    try {
      // configModel包含了所有的子控制器
      configModel = ConfigModelFactory.build();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    doPost(request, response);
  }
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    // http://localhost:8080/MVC_project/book.action?methodName=delete...
    /**
     * 获取请求路径
     */
    String uri = request.getRequestURI();
    // 截取book
    uri = uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf("."));
    // 要通过uri->> /book,在configModel对象中找
    ActionModel actionModel = configModel.pop(uri);
    // 判断没找对象等于空就抛出异常
    if (actionModel == null)
      throw new RuntimeException("action not config");
    /**
     * 获取config文件中action标签的type属性值
     * type指java类
     * com.ycxw.servlet.BookAction
     */
    String type = actionModel.getType();
    // 通过反射创建对象
    Action instance;
    try {
      instance = (Action) Class.forName(type).newInstance();
      // 判断bookAction有没有实现ModelDriver接口
      if (instance instanceof ModelDriver) {
        // 向下转型获取接口方法
        ModelDriver md = (ModelDriver) instance;
        Object bean = md.getModel();
        // 把获取的参数保存到该对象中
        BeanUtils.populate(bean, request.getParameterMap());
      }
      // 业务代码执行后返回值
      String execute = instance.execute(request, response);
      // 通过返回值拿到,该方法结果是重定向还是转发,还是跳转哪个页面
      ForwardModel forwardModel = actionModel.pop(execute);
      if (forwardModel != null) {
        // 获取forwardModel是否从定向值
        boolean redirect = forwardModel.isRedirect();
        /**
         * 获取xml元素path值   
         */
        String path = forwardModel.getPath();
        // 判断是否为重定向
        if (redirect) {
          response.sendRedirect(request.getContextPath() + "/" + path);
        } else {
          request.getRequestDispatcher(path).forward(request, response);
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

5.2 测试JSP页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试</title>
</head>
<body>
  <a href="${pageContext.request.contextPath }/book.action?methodName=add&bid=1&bname=aa&price=13">增加</a>
  <a href="${pageContext.request.contextPath }/book.action?methodName=delete">删除</a>
  <a href="${pageContext.request.contextPath }/book.action?methodName=edit">修改</a>
  <a href="${pageContext.request.contextPath }/book.action?methodName=query">查询</a>
  <a href="${pageContext.request.contextPath }/book.action?methodName=load">回显</a>
</body>
</html>

5.3 论证反射对象赋值

1. 通过debug调试,运行到当前通过反射拿到指定对象时为空

 

2. 执行完populate方法后将自定赋值等效于遍历对象一个个赋值

BeanUtils.populate(bean, request.getParameterMap());

 

最后在讲解一下populate方法的解释:

6. populate方法详解

 

BeanUtils.populate(Object bean, Map properties)

BeanUtils位于org.apache.commons.beanutils.BeanUtils下,populate是BeanUtils工具类的一个方法。

作用:

      这个方法会遍历map<key, value>中的key,如果bean中有这个属性,就把这个key对应的value值赋给bean的属性

相关文章
|
11月前
|
XML 设计模式 前端开发
自定义MVC---引用XML
自定义MVC---引用XML
50 0
|
XML 开发框架 算法
【C#本质论 十一】合式类型(二)程序集引用、XML注释、垃圾回收和资源清理
【C#本质论 十一】合式类型(二)程序集引用、XML注释、垃圾回收和资源清理
142 0
|
XML 数据格式
【Tip】如何让引用的dll随附的xml注释文档、pdb调试库等文件不出现在项目输出目录中
原文:【Tip】如何让引用的dll随附的xml注释文档、pdb调试库等文件不出现在项目输出目录中 项目输出目录(bin/debug|release)中经常是这个样子: main.exemain.pdb a.dll a.xml b.dll b.pdb b.xml ... 其中xml是同名dll的注释文档,pdb是调试库。
948 0
|
前端开发 JavaScript .NET
ASP.NET MVC路径引用总结
原文:ASP.NET MVC路径引用总结 1、关于路径: (1)绝对路径 包含站点路径的路径:百度 站点改变路径失效; (2)相对路径 相同目录: 上级目录相同: 跟高的父级目录: (3)根路径 相对路径和绝对路径的折中,以/开头   2、关于ASP.
2062 0
|
XML Java 数据格式
Spring中引用不同xml中的bean
想要在Spring-Common.xml中引用 Spring-Output.xml中定义的bean 需要使用&lt;ref bean="XXX"/&gt;标签,如果是同一个xml文件中引用则使用&lt;ref local="XXX"/&gt;标签。 package com.spring.output; public class OutputHelper {
1628 0
|
XML 数据格式
XML实体引用
在 XML 中,一些字符拥有特殊的意义。 如果你把字符 "
887 0
|
前端开发
MVC layout 命名空间引用问题
虽然用MVC做了很多项目,但是都是在别人搭好的框架上实现 今天碰到一个很简单的命名空间引用问题 如图所示,Scripts和Styles 都没有引用命名空间 解决方法一:  直接使用 System.
870 0
|
XML 数据格式 数据库
XML 实体引用、注释、命名规则
实体引用 在 XML 中,一些字符拥有特殊的意义。 如果你把字符 "&lt;" 放在 XML 元素中,会发生错误,这是因为解析器会把它当作新元素的开始。 这样会产生 XML 错误: &lt;message&gt;if salary &lt; 1000 then&lt;/message&gt; 为了避免这个错误,请用实体引用来代替 "&lt;" 字符: &lt;mes
1563 0