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

目录

前言

自定义MVC实现

1. 导入XML配置文件

2. 导入XML解析建模

3. 优化中央控制器

3.1 修改DisPathServlet中init初始化方法

3.2 修改ActionServlet逻辑处理流程

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

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

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

4. 反射赋值

4.1 创建接口DriverModel

4.2 实现接口类

4.3  反射对象赋值

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

5.1 完整 DisPathServlet类代码

5.2 测试JSP页面

5.3 论证反射对象赋值

6. populate方法详解


前言

       在这篇 自定义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的属性

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/34584.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【物联网无线通信技术】802.11无线安全认证

本文由简入繁介绍了IEEE802.11i无线局域网安全技术的前世今生&#xff0c;帮助路由器开发者对WLAN的加密安全策略有一个概念上的认知&#xff0c;能够更好地分析STA掉线以及漫游等问题。 目录 WEP WPA WPA/WPA2-PSK认证过程 802.11i WEP WEP是Wired Equivalent Privacy的简…

Learning C++ No.30 【lambda表达式实战】

引言&#xff1a; 北京时间&#xff1a;2023/6/9/9:13&#xff0c;今天8:15起床&#xff0c;可能是最近课非常少&#xff0c;导致写博客没什么压力&#xff0c;什么时间都能写&#xff0c;导致7点起不来&#xff0c;哈哈哈&#xff0c;习惯睡懒觉了&#xff0c;但是问题不大&a…

记一次自建靶场域渗透过程

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 环境搭建02 外网突破03 权限提升并维持&#xff08;1&#xff09;获取 meterpreter 会话&#xff08;2&#xff09;尝试开启远程桌面&#xff08;3&#xff09;Msf 派生 Cobalt Strike shell&#…

JumpServer开源堡垒机安装配置

JumpServer开源堡垒机安装与配置 一、简介二、下载与安装2.1、下载2.2、安装2.3、其他 一、简介 JumpServer 堡垒机帮助企业以更安全的方式管控和登录各种类型的资产。 支持 官网地址&#xff1a;https://www.jumpserver.org/index.html JumpServer 采用分层架构&#xff0c;…

Jenkins构建Python项目提示:‘python‘ 不是内部或外部命令,也不是可运行的程序

一、问题描述&#xff08;1&#xff09; 今天Darren洋在jenkins里构建与飞书机器人通知时&#xff0c;用python编写脚本时发现了以下报错&#xff1a;Jenkins构建Python项目提示&#xff1a;‘python‘ 不是内部或外部命令&#xff0c;也不是可运行的程序 二、解决办法 在配置…

【Spark实战】Windows环境下编译Spark2 Linux上部署Spark On Yarn

Windows环境下编译Spark2 环境准备 git-2.14.1maven-3.9.2jdk-1.8scala-2.11.8zinc-0.3.15 主下载地址spark-2.3.4 github官方地址 编译准备 maven远程仓库使用的是阿里云的 解压源码包spark-2.3.4.zip,修改根模块的pom文件。主要目的是为了变更hadoop的版本号&#xff0c;…

在 TypeScript 中有效地使用 keyof 和 typeof 来表示类型

在本文中&#xff0c;我们将学习如何通过组合类型运算符和枚举来提取和声明常量类型typeof&#xff0c;以使您的代码库得到优化。keyof 先决条件 为了获得更好的编码体验&#xff0c;您应该在 IDE 中安装 TypeScript&#xff0c;例如VSCode。它将为您提供许多基本功能&#xff…

【论文导读】- Variational Graph Recurrent Neural Networks(VGRNN)

文章目录 文章信息摘要BackgroundGraph convolutional recurrent networks (GCRN)Semi-implicit variational inference (SIVI) Variational graph recurrent neural network (VGRNN)VGRNN modelSemi-implicit VGRNN (SI-VGRNN) 文章信息 Variational Graph Recurrent Neural …

STM32 串口代码配置

一、首先开发板上关于串口1的引脚配置已经配置好了&#xff0c;位置在SYSTEM的 usart.c 文件中&#xff08;注意&#xff1a;只配置了串口1的&#xff0c;其他使用时需要自己配置&#xff09; 重要的是明白配置的参数都是什么意思&#xff0c;针对实现不同的串口功能有什么影响…

选择高考志愿:聚焦计算机科学与技术,规避土木工程

选择高考志愿&#xff1a;聚焦计算机科学与技术&#xff0c;规避土木工程 高考季已至&#xff0c;各地高考成绩陆续公布&#xff0c;许多毕业生和家长开始面临疑惑&#xff1a;如何填报志愿、选专业还是选学校、什么专业好就业&#xff1f;张雪峰曾提到&#xff1a;“普通家庭…

从零开始 Spring Boot 60:一个实体映射到多个表

从零开始 Spring Boot 60&#xff1a;一个实体映射到多个表 图源&#xff1a;简书 (jianshu.com) 在之前的文章中我们讨论了 JPA 中的一对一关系&#xff0c;实际上存在一种特殊的一对一关系&#xff0c;即将一个实体映射到多张表&#xff0c;本文会讨论这种关系。 我之前提过…

如何将采购报价请求流程自动化?

在当今快节奏的商业环境中&#xff0c;效率和速度是保持竞争力的关键。在采购管理中&#xff0c;企业经常为简化操作而努力的一个领域是报价请求过程。手动处理请求、与供应商沟通并跟踪答复&#xff0c;可能非常耗时且容易出错。 然而&#xff0c;随着像8Manage SRM等专业电子…

Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库

介绍 Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库&#xff0c;基于 ECMA-376&#xff0c;ISO/IEC 29500 国际标准。可以使用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创建的电子表格文档。支持 XLAM / XLSM / XLSX / XLTM / XLTX 等多种文档格式&a…

Git下载与安装(windows)

文章目录 Git 简介Git 下载Git 安装Git 环境变量配置 Git 简介 Git 是一种分布式版本控制系统&#xff0c;用于快速、高效地处理任何大小规模的项目。它是由 Linus Torvalds 在 2005 年开始开发的&#xff0c;Git 最初是为了管理 Linux 内核源代码而创建的。现在 Git 是一个广…

Spring 是什么框架?

对于一门技术&#xff0c;我们需要从为什么要学、学什么以及怎么学这三个方向入手来学习。那在说Spring这三点之前&#xff0c;我们先看Spring之前要学什么。 Java基础、Java语法进阶、MySQL基础操作、MySQL数据库设计和多表操作、JDBC、Maven基础、MyBatis、HMLCSS、JavaScrip…

PCA主成分分析

PCA降维算法 目前图像特征的提取主要有两种方法&#xff1a;传统图像特征提取方法 和 深度学习方法。 传统的特征提取方法&#xff1a;基于图像本身的特征进行提取&#xff08;PCA&#xff09;&#xff1b;深度学习方法&#xff1a;基于样本自动训练出区分图像的特征分类器&a…

SpringBoot--超时熔断器

需求背景 如果一个服务中有很多涉及需要服务间熔断的地方&#xff0c;就会出现N多下述代码&#xff1a; 1.N个fegnClient接口 FeignClient(name "hello-world-service", fallback HelloWorldFallback.class) public interface HelloWorldService {GetMapping(&q…

Python 学习之NumPy(一)

文章目录 1.为什么要学习NumPy2.NumPy的数组变换以及索引访问3.NumPy筛选使用介绍筛选出上面nb数组中能被3整除的所有数筛选出数组中小于9的所有数提取出数组中所有的奇数数组中所有的奇数替换为-1二维数组交换2列生成数值5—10&#xff0c;shape 为(3,5)的二维随机浮点数 NumP…

Apache Doris (十七) :Doris分区和分桶3-分桶及建议

​​​目录 一、分桶Bucket ​​​​​​​二、分区和分桶数量和数据量的建议 进入正文之前&#xff0c;欢迎订阅专题、对博文点赞、评论、收藏&#xff0c;关注IT贫道&#xff0c;获取高质量博客内容&#xff01; 一、分桶Bucket Doris数据表存储中&#xff0c;如果有分区&…

使用docker搭建mysql集群

一、技术架构 1、架构图 2、解说 mysql_1、mysql_2、mysql_3是一组主从模式,同理mysql_4、mysql_5、mysql_6也是一组主从模式从上面的图可以看出mysql_1和mysql_4是主节点,可以进行增删改查操作,但是子几点只能查询操作如果mysql_1节点出现问题了&#xff0c;有mysql_4节点组…