使用普通类简单模拟Servlet

使用普通类简单模拟Servlet

  • 需求
  • 步骤
    • 配置访问路径xml
    • 解析配置文件,结果放入map
    • 访问拦截处理

需求

通过使用普通类+过滤器来模拟实现前端页面向后端发送请求时Servlet的工作

步骤

配置访问路径xml

为了能够灵活的匹配到用户想要访问的路径,我们将自定义的资源类的类名、资源类的完全限定名以及默认访问的方法,保存到路径映射文件中。之后再解析此配置xml文件。
路径配置文件
我这里简单模拟了两个资源类,怎么样看这里是不是有种似曾相识的感觉。

解析配置文件,结果放入map

自定义过滤器类,并在web.xml中配置我们的过滤器,拦截所有的请求
使用普通类简单模拟Servlet_第1张图片
当服务器启动加载时,会加载过滤器,在过滤器的初始化方法中解析我们的访问配置文件:这里使用的是dom4j+Xpath解析,

public void init(FilterConfig arg0) throws ServletException {
		/**
		 *  为了灵活的获取到用户想要访问的类,配置xml文件,配置路径名、类完全限定名、默认访问方法
		 *  在服务器加载、过滤器初始化时就解析配置文件
		 *  
		 *  	使用dom4j解析xml
		 *  	用一个对象存储解析出的name、class、method等属性的值
		 *  	使用map存储对象	
		 */
		try {
			SAXReader reader = new SAXReader();
			//使用类加载器以输入流形式将配置文件加载
			InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("config.xml");
			Document read = reader.read(stream);
			
			
			//使用Xpath获取bean节点    '//bean'找到文档中所有bean节点,无视层级
			//使用Xpath要导入jar包  jaxen
			List list = read.selectNodes("//bean");
			//遍历元素集合
			for (Element element : list) {
				Config config = new Config();
				
				//获取到要访问的类
				String name = element.attributeValue("name");
				String className = element.attributeValue("class");
				String method = element.attributeValue("method");
				config.setName(name);
				config.setClassName(className);
				config.setMethod(method);
				
				**hashMap.put(name, config);** //将要访问的资源名作为key,解析结果封装的对象作为value装入一个map中
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}

将解析结果封装到一个对象之中,这里我自定义了一个用于封装的对象,并且将要访问的资源名作为key,解析结果封装的对象作为value装入一个map中。我自定义的资源类其字段有 类名,类完全限定名,类方法名,类具体结构如下:

public class Config {
	//类名
	private String name;
	//类的完全限定名,用于反射创建对象
	private String className;
	//类中的方法名
	private String method;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getClassName() {
		return className;
	}
	public void setClassName(String className) {
		this.className = className;
	}
	public String getMethod() {
		return method;
	}
	public void setMethod(String method) {
		this.method = method;
	}
	@Override
	public String toString() {
		return "Config [name=" + name + ", className=" + className + ", method=" + method + "]";
	}
	
	
}

访问拦截处理

当用户在前端发送请求之后,过滤器拦截到请求,在过滤器的过滤方法中,我们先将请求对象从ServletRequest转为HttpServletRequest因为我们要使用这个Http请求对象的getRequestURI方法来获取到用户的请求路径,通过字符串操作将路径中用户想要访问的资源名给提取出来。这里就只用遍历我们之前在过滤器初始化方法中使用的map中是否存在用户想要访问的资源

  • 如果不存在就直接放行
  • 如果存在:通过资源名在map中拿到该资源名对应的资源类的完全限定名,通过完全限定名创建对象,之后我们再从map中拿到方法名,通过之前创建的对象执行该方法完成对该资源类的访问

过滤器过滤方法:

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
			throws IOException, ServletException {
		try {
			//将请求对象转为httpServletRequest对象
			HttpServletRequest request = (HttpServletRequest) req;
			
			//获取请求路径
			String uri = request.getRequestURI();
			int index = uri.lastIndexOf("/");
			//得到访问的类
			String name = uri.substring(index+1);
			//请求到map中对应的name
			if (hashMap.containsKey(name)) {
				//拿到对应name的完全限定名
				Config c = (Config) hashMap.get(name);
				String className = c.getClassName();
				//通过字节码对象使用完全限定名创建对象
				Class clazz = Class.forName(className);
				Object obj = clazz.newInstance();
				//获得方法
				Method method = clazz.getMethod(c.getMethod());
				method.invoke(obj);
			}else {
				//如果map中没有对应的路径,就放行
				chain.doFilter(req, resp);
				
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

你可能感兴趣的:(基础)