完善中央控制器

本文详细介绍了如何构建一个基于XML配置的MVC框架,包括请求分发、子控制器配置以及请求参数处理。首先,通过中央控制器实现请求分发,接着将子控制器的配置移到XML文件中,提高灵活性。然后,引入了请求参数的处理,例如读取CSV数据。最后,提出了在Action中使用反射机制处理多种请求方法,使得一个Action实例可以处理多个请求。
摘要由CSDN通过智能技术生成

文章目录

  • 前言
  • 一、请求分发功能
  • 二、使用配置文件配置action
  • 三、请求参数处理


前言

为了便于理解,我们可以分步骤的,循序渐进的完善中央控制器:

  • 编写简单的请求分发实现功能
  • 实现通过配置文件来配置子控制器的功能
  • 完善请求参数处理功能

提示:以下是本篇文章正文内容,下面案例可供参考

一、请求分发功能

为了在中央控制器中完成请求的分发,需要在中央控制器中维护所有子控制器的实例,并且能够依据请求路径,将请求转发给与其关联的子控制器。

二、使用配置文件配置action

在上面的示例中,在中央控制器中直接创建action子控制器,如果新增一个子控制器需要在中央控制器中添加,这样并不实用。 为了增加灵活性,可以将action转移到配置文件中配置,中央控制器通过配置来初始化action子控制器。

1)此时需要将config.xml文件的解析和建模项目的功能集成进来。
(ConfigModel,ActionModel,ForwardModel,ConfigModelFactory)

2)在项目的src目录下加入如下配置文件(config.xml)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config[
	<!ELEMENT config (action*)>
	<!ELEMENT action (forward*)>
	<!ELEMENT forward EMPTY>
	<!ATTLIST action
	  path CDATA #REQUIRED
	  type CDATA #REQUIRED
	>
	<!ATTLIST forward
	  name CDATA #REQUIRED
	  path CDATA #REQUIRED
	  redirect (true|false) "false"
	>
]>
<config>
	<action path="/studentAction" type="org.lisen.mvc.action.StudentAction">
		<forward name="students" path="/students/studentList.jsp" redirect="false"/>
	</action>
</config>

3) 完善中央处理器,通过配置文件来获取子控制器配置

@WebServlet("*.action")
public class ActionDispatchServlet extends HttpServlet {
	
	//用于保存path与action子控制器的映射
	//public static Map<String, Action> actionMap = new HashMap<>();
	
	private static ConfigModel configModel;
	
	static {
		//actionMap.put("/students", new StudentAction());
		//actionMap.put("/books", new BookAction());
		configModel  = ConfigModelFactory.getConfigModel();
	}
	
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws IOException, ServletException {
		doPost(request, response);
	}
	
	@Override
	public void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws IOException, ServletException {
		
		String servletPath = request.getServletPath();
		String path = servletPath.split("\\.")[0];
		
		Action action = getActionByPath(path);
		String name = action.exeute(request, response);
		
		ForwardModel forwardModel = getForwardModel(path, name);
		if (forwardModel.isRedirect()) {
			response.sendRedirect(request.getContextPath() + "/" + forwardModel.getPath());
		} else {
			request.getRequestDispatcher(forwardModel.getPath()).forward(request, response);
		}
	}
	
	//通过请求路径获取对应的action实例
	private Action getActionByPath(final String path) {
		ActionModel action = configModel.find(path);
		try {
			Class<?> clazz = Class.forName(action.getType());
			return (Action)clazz.newInstance();
		} catch (Exception e) {
			throw new RuntimeException("创建Action实例异常"+e.getMessage(), e);
		}
	}
	
	public ForwardModel getForwardModel(String path, String name) {
		return configModel.find(path).find(name);
	}

}

注: 本例的实现中Action子控制器是多例模式的,及每个请求对应一个Action实例

三、请求参数处理

1. 定义接口

代码如下(示例):

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context

2.在中央处理器中加入请求参数的处理能力

代码如下(示例):

data = pd.read_csv(
    'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())

 3.处理请求参数中的null及空字符串转换问题
为了更方面的处理请求参数中的null及空字符串,转换为数值型数据的问题,加入一个监听器,在应用启动时注册转换器。

/**
 * ServletContextListener接口为Servlet API中的接口,用于监听ServletContext对象的生命周期。
 * 当Servlet 容器启动或终止Web 应用时,会触发ServletContextEvent事件,该事件由
 * ServletContextListener来处理。
 * @author Administrator
 */
@WebListener
public class BeanUtilsListener implements ServletContextListener {

	/**
	 * 当Servlet 容器终止Web 应用时调用该方法。在调用该方法之前,
	 * 容器会先销毁所有的Servlet和Filter 过滤器。
	 */
	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		// TODO Auto-generated method stub
	}

	/**
	 * 当Servlet 容器启动Web应用时调用该方法。
	 * 在调用完该方法之后,容器再对Filter 初始化,
	 * 并且对那些在Web应用启动时就需要被初始化的Servlet进行初始化。
	 */
	@Override
	public void contextInitialized(ServletContextEvent arg0) {
		ConvertUtils.register(new IntegerConverter(null), Integer.class);
		ConvertUtils.register(new FloatConverter(null), Float.class);
		ConvertUtils.register(new DoubleConverter(null), Double.class);
		ConvertUtils.register(new LongConverter(null), Long.class);
		ConvertUtils.register(new BigDecimalConverter(null), BigDecimal.class);
	}

}

四。完善Action

每个Action只能有一个execute方法,如果处理一个模块的增删改查则需要单独编写多个Action,这样会比较麻烦。如果在一个Action实例中可以处理多个请求方法,则框架会更加灵活。

  • 规定请求参数中必须包含一个“methodName”参数,用于指定处理请求的Action中的方法
  • 构建一个抽象类,该类实现Action子控制器接口,通过反射机制调用其子类中的方法,方法名有请求参数“methodName”指定。
  • 需要开发的Action子控制器,集成上一步构建的抽象类,编写的用于处理请求的方法名要与请求参数“methodName”指定的方法名匹配,同时需要HttpServletRequest和HttpServletResponse两个参数(保留该参数主要为了方面对请求的处理)

1) 构建抽象类

public abstract class AbstractDispatchAction implements Action {

	@Override
	public String exeute(HttpServletRequest request, HttpServletResponse response) {
		
		String methodName = request.getParameter("methodName");
		Class<? extends AbstractDispatchAction> clazz = this.getClass();
		try {
			Method method = clazz.getDeclaredMethod(
					methodName, 
					HttpServletRequest.class,
					HttpServletResponse.class);
			return (String)method.invoke(this, request,response);
		} catch (Exception e) {
			throw new RuntimeException("在调用Action中的["+methodName+"]方法是异常", e);
		} 
	}

}

2) 自定义的Action子控制器示例:

public class StudentAction extends AbstractDispatchAction implements ModelDrive {
	
	private Student student = new Student();
	
	@Override
	public Object getModel() {
		return student;
	}

	/*@Override
	public String exeute(HttpServletRequest request, HttpServletResponse response) {		
		System.out.println("StudentAction = " + student);	
		return "students";
	}*/
	
	public String getStudents(HttpServletRequest request, HttpServletResponse response) {	
		System.out.println("getStudents");
		System.out.println("StudentAction = " + student);
		return "students";
	}
	
	public String addStudent(HttpServletRequest request, HttpServletResponse response) {
		System.out.println("addStudent");
		System.out.println("add student = " + student);
		return "students";
	}

}

3)发送请求,示例
http://localhost:8080/mvc/studentAction.action?methodName=addStudent&sid=100&age=23&addr=aabbcc

注意:在请求中需要添加一个methodName的固定参数,该参数指定了需要调用的Action中的方法的名称。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值