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

news2024/11/25 7:25:48

目录

前言

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【运维工程师学习】低级格式化磁盘

【运维工程师学习】低级格式化磁盘 1、查看需要格式化的磁盘2、下载低级格式化工具3、打开低级格式化工具&#xff0c;选择目标磁盘&#xff0c;并操作 1、查看需要格式化的磁盘 找不到目标磁盘的话需要到磁盘管理去找&#xff0c;这边我要低级格式话的磁盘是磁盘0 2、下载低级…

BPMNJS 在HTML中的引入与使用

BPMNJS 在HTML中的引入与使用 在网上看到的大多是基于vue使用BPMN的示例或者教程&#xff0c;竟然没有在HTML使用的示例&#xff0c;有也是很简单的介绍核心库的引入和使用&#xff0c;并没有涉及到扩展库。于是简单看了下&#xff0c;真的是一波三折&#xff0c;坎坎坷坷。不过…

vue使用mapbox地图

1、下载依赖 npm install --save mapbox-gl mapbox/mapbox-gl-language 2、引入mapBox&#xff0c;将引入的内容封装为js文件 在api/map文件夹下新建mapbox.js文件 代码&#xff1a; import mapboxgl from mapbox-gl import mapbox-gl/dist/mapbox-gl.css import MapboxLang…

vue表单验证的时候提示 async-validator:‘‘xxx is not a string“

对vue不是很熟悉&#xff0c;在做vue开发的时候&#xff0c;遇到一个很奇怪的问题&#xff0c;输入框涉及到number类型的时候会提示 is not a string 这块的代码是这样的&#xff1a; v-decorator"[ fraction, { rules: [{ required: true, type: number, message: 请输入…

SQL Server中如何将累积数值拆解

概要 本文通过一个计算汽车每日里程数的例子&#xff0c;展现如何通过汽车每日的总里程数&#xff0c;来计算汽车每日的里程数。 代码及实现 每辆汽车中都有一个里程数表&#xff0c;记录汽车从出场到当前行驶的里程数&#xff0c;下表是一样汽车的里程数表&#xff0c;该表…

Elastic Stack之Logstash Beats

文章目录 Logstash简介&运行流程使用&#xff08;日志采集&#xff09;常用操作查看线程 BeatFilebeat Logstash 简介&运行流程 教程 一文快速上手Logstash 使用&#xff08;日志采集&#xff09; 配置logstash使用elasticsearch作为logstash后端 在logstash\bin目录…

Spring容器获取Bean的9种方式 | 京东云技术团队

1 前言 随着SpringBoot的普及&#xff0c;Spring的使用也越来越广&#xff0c;在某些场景下&#xff0c;我们无法通过注解或配置的形式直接获取到某个Bean。比如&#xff0c;在某一些工具类、设计模式实现中需要使用到Spring容器管理的Bean&#xff0c;此时就需要直接获取到对…

postgres数据库基础操作-ok

文章目录 1. 链接数据库2. 库操作2.1 创建库2.2 查看数据库2.3 切换数据库2.4 修改库名2.5 删除数据库 3. 表操作3.1 创建表3.2 查看table list3.3 删除表 4. 数据操作4.1 插入数据4.2 查询数据4.3 删除数据 5. 用户&权限5.1 创建用户5.2 查看用户5.3 删除用户5.4 修改用户…

spring cloud +java企业工程管理系统源码之提高工程项目管理软件的效率

高效的工程项目管理软件不仅能够提高效率还应可以帮你节省成本提升利润 在工程行业中&#xff0c;管理不畅以及不良的项目执行&#xff0c;往往会导致项目延期、成本上升、回款拖后&#xff0c;最终导致项目整体盈利下降。企企管理云业财一体化的项目管理系统&#xff0c;确保…

5.设计模式之思维导图整理

1.七大原则 2.分类 3.23大设计模式 //展开 ![ 在这里插入图片描述](https://img-blog.csdnimg.cn/070e9ba070a54a22ab4a05653ae1cf27.png)

钡铼技术多功能RTUS475:稳定可靠的油田数据采集解决方案

标题&#xff1a;S475在油田数据采集中的应用 摘要&#xff1a;本文介绍了钡铼技术多功能RTUS475在油田数据采集中的应用。该设备基于高性能微处理器MCU和嵌入式实时操作系统&#xff0c;支持Modbus Slave和Modbus Master功能&#xff0c;并能通过无线网络实现短信报警和数据传…

华为OD机试真题 Python 实现【木板】【2023 B卷 100分】,附详细解题思路

目录 一、题目描述二、输入描述三、输出描述四、Python算法源码五、效果展示1、输入2、输出3、说明 一、题目描述 小明有n块木板&#xff0c;第块木板的长度为a_i。 小明买了一块长度为m的木料&#xff0c;这块木料可以切割成任意块&#xff0c;拼接到已有的木板上&#xff0…

虚机Centos忘记密码如何重置 -- 小黑日常超细教学

有时候虚机太多&#xff0c;会忘记有一些虚机的密码&#xff0c;当启动机器的时候那我们可以尝试重置虚机密码然后登录。 日常的小技能记述&#xff01;&#xff01; 目录 一、 演示虚机为centos7系列 二、进入开机前的页面&#xff0c;选中第一个&#xff0c;按“e”键&…

idea中如何过滤某些文件不提交

文章目录 前言设置.gitignore文件解决方案 设置新的忽略文件具体步骤如下 常用过滤文件 前言 在开发过程中&#xff0c;经常会遇到一些文件是我们不想提交的内容。那么应该如何过滤掉&#xff1f;不去提交到我们的git仓库&#xff1f; 比如&#xff0c;我们常用的一些配置文件…

MBD开发 STM32 UASRT

目录 轮询 ptintf 中断方式 DMA方式 轮询 串口要加入这两个文件 bug在于接到10个后会一直发送 ptintf function buffPtr convert(buff)if coder.target(Sfun)%固定句式%Executing in MATLAB, Buff is nullbuffPtr uint32(0); elsecoder.cinclude(getBuffPtr.h);%加入头…

Apikit 自学日记:智能 Mock 规则

功能入口&#xff1a;API管理应用 / 公共资源菜单 / 智能 Mock 设置 二级菜单在编写API文档返回结果时&#xff0c;若参数字段和类型匹配智能Mock规则&#xff0c;系统则会自动填入对应的Mock值。该功能提供无感的快速mock值配置&#xff0c;减轻mock规则配置的工作负担。 智能…

Dubbo学习记录

Dubbo学习记录 一、Dubbo架构二、Provider启动Dubbo1.实现类的Service注解2.Dubbo的配置信息3.引入web.xml&#xff0c;加载Spring核心配置文件&#xff0c;才可以扫描到Dubbo的配置信息 二、Consumer启动Dubbo1.Autowired改为Reference2.qos介绍&#xff1a;Dubbo远程监控和控…

LeetCode 打卡day54-55 动态规划之编辑距离问题

一个人的朝圣 — LeetCode打卡第54-55天 知识总结 Leetcode 392. 判断子序列题目说明代码说明 Leetcode 115. 不同的子序列题目说明代码说明 Leetcode 583. 两个字符串的删除操作题目说明代码说明 Leetcode 72. 编辑距离题目说明代码说明 知识总结 今天学习动态规划里面的编辑…

《零基础学PIC单片机》目录

《零基础学PIC单片机》目录 1.《零基础学PIC单片机》&#xff0c;作者&#xff1a;赵化启 1.1芯片架构和指令 芯片架构和指令需要较多时间消化。 PIC单片机系统结构&#xff0c;讲解各模块的结构和功能&#xff1b;PIC汇编指令 1.2具有参考价值的内容 第3章&#xff1a;电…

批发零售行业应该如何选择进销存软件?

一、什么是进销存软件 进&#xff1a;需要将产品采购入库&#xff0c;自动生成采购明细台账同时关联财务生成付款账单&#xff1b; 销&#xff1a;是指对客户的销售订单记录&#xff0c;汇总生成产品销售明细及回款计划&#xff1b; 存&#xff1a;库存的日常盘点与统计&…