使用普通類簡單模擬Servlet

需求

通過使用普通類+過濾器來模擬實現前端頁面向後端發送請求時Servlet的工作

步驟

配置訪問路徑xml

爲了能夠靈活的匹配到用戶想要訪問的路徑,我們將自定義的資源類的類名、資源類的完全限定名以及默認訪問的方法,保存到路徑映射文件中。之後再解析此配置xml文件。
路徑配置文件
我這裏簡單模擬了兩個資源類,怎麼樣看這裏是不是有種似曾相識的感覺。

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

自定義過濾器類,並在web.xml中配置我們的過濾器,攔截所有的請求
web.xml配置過濾器
當服務器啓動加載時,會加載過濾器,在過濾器的初始化方法中解析我們的訪問配置文件:這裏使用的是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<Element> 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();
		}
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章