xml建模

1.xml建模的目的及分析过程

假如有一个xml文件的内容如下:

<config>
	<action path="/regAction" type="test.RegAction">
		<forward name="failed" path="/reg.jsp" redirect="false" />
		<forward name="success" path="/login.jsp" redirect="true" />
	</action>

	<action path="/loginAction" type="test.LoginAction">
		<forward name="failed" path="/login.jsp" redirect="false" />
		<forward name="success" path="/main.jsp" redirect="true" />
	</action>
</config>

需求1:程序员张三需要通过/loginAction获取type=test.LoginAction,下面我们来分析一下这个过程:
步骤一加载资源文件xxx..class.getResourceAsStream("类名.xml");
步骤二通过xpath解析获取到所有的action元素标签列表
步骤三遍历,如果action标签的path属性等于/loginAction,那么就是我们要找的action标签
步骤四找到的action,我们就可以获取到对应的action标签的type属性值

现在呢,又有一个叫李四的程序员有这样的需求:程序员李四需要通过/regAction获取type=test.RegAction,下面我们来分析一下这个过程:
步骤一加载资源文件xxx..class.getResourceAsStream("类名.xml");
步骤二通过xpath解析获取到所有的action元素标签列表
步骤三遍历,如果action标签的path属性等于/regAction,那么就是我们要找的action标签
步骤四找到的action,我们就可以获取到对应的action标签的type属性值

通过上面两个需求以及分析的过程来看,我们可以很清楚看到两个需求的步骤基本上是相同的,只需要修改条件就OK,假如还有一个王五也想要一个通过/regAction获取type=test.RegAction这样的需求,这个过程与张三李四都是重复的,那么我们是不是可以写活用的方法去调用方法,那么是不是很方便,所以我们要学习xml建模,xml建模不仅是一个知识也是一种解决方案,如果每一个需求都需要去解析一次,那必定会重复很多的代码,这比较繁琐,所以我们要学习建模来简化xml解析的过程

附上xml解析的分析过程图
在这里插入图片描述

对上述进行图解

建模案例1

下面我们来分析一下 怎样进行xml建模呢?

xml建模的核心思想就是利用java面向对象的特性,用操作对象的方式来操作xml

还是与上述一样,假如有一个xml文件的内容如下:

<config>
	<action path="/regAction" type="test.RegAction">
		<forward name="failed" path="/reg.jsp" redirect="false" />
		<forward name="success" path="/login.jsp" redirect="true" />
	</action>

	<action path="/loginAction" type="test.LoginAction">
		<forward name="failed" path="/login.jsp" redirect="false" />
		<forward name="success" path="/main.jsp" redirect="true" />
	</action>
</config>

我们可以把config、action 、forward 看作是一个对象,及一个标签对应一个对象,所以这个xml中我们可以分析出有三个对象(对象也是类,比如猫,狗呀):
下面我们来看一下分析xml建模的思路图(附):
在这里插入图片描述

既然我们分析完了,接下来我们来从下往上开始动手写代码(建模)

写代码时我们需要注意的事项:
1、建模必须从里到外开始建模
在这里插入图片描述

既然是从里到外建模,首先我们先建ForwardModel类(forward标签)

package com.xiaoqing.model;

public class ForwardModel {
//		<forward name="failed" path="/login.jsp" redirect="false" />
	
	private String name;
	private String path;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPath() {
		return path;
	}
	public void setPath(String path) {
		this.path = path;
	}
	
}

接下来我们建ActionModel类(action标签):

package com.xiaoqing.model;

import java.util.HashMap;
import java.util.Map;

public class ActionModel {
/**
 * <action path="/loginAction" type="test.LoginAction">
 * 
 */
	private String path;
	private String type;
	/**
	 * 因为action标签下有多个子标签,所以我们用map集合来存储
	 * @return
	 */
	private  Map<String, ForwardModel> foMap=new HashMap<>();
	public String getPath() {
		return path;
	}
	public void setPath(String path) {
		this.path = path;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	
	/**
	 * 两个行为
	 */
	
	/**
	 * 将指定的forwardModel压入当前actionModel对象中
	 * 把<forward/>放入<action></action>
	 * @param forwardModel
	 */
	public void push(ForwardModel forwardModel) {
		foMap.put(forwardModel.getName(),forwardModel);
	}
	
	
}

再接下来建ConfigModel类(config标签,最外层):

package com.xiaoqing.model;

import java.util.HashMap;
import java.util.Map;

public class ConfigModel {
	
	private Map<String, ActionModel> acMap=new HashMap<String, ActionModel>();
	
	/**
	 * 新增Action对象的行为:
	 * 将指定的actionModel放入当前ConfigModel对象中
	 * 把<action></action>放入<config></config>
	 * @param actionModel
	 */
	public void push(ActionModel actionModel) {
		acMap.put(actionModel.getPath(),actionModel);
	}
	/**
	 * 通过action对象name属性查找对应的Forward对象的行为
	 * @param name
	 * @return
	 */
	public ActionModel  pop(String path) {
		return acMap.get(path);
	}

}

xml中有三个标签,我们现在也将这三个标签建模建好了,现在我们要把他们集合到一起,所以最后我们要建一个工厂类把他们封装起来,相当于吃汉堡那个案例,前面在自定义MVC时思维导图中的xml建模那部分有说到过
工厂模式解决的问题:将代码封装易用,提高代码的复用性(类比汉堡的获取方式:肯德基直接购买,原材料自己制作)

一般工厂类一定会有一个方法,就是生产指定模型对象的方法

package com.xiaoqing.model;

import java.io.InputStream;
import java.util.List;



import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 23 种设计模式之工厂模式
 * 
 * 
 * 工厂模式解决的问题,将代码封装,提高代码的复用性
 * 类比汉堡的获取方式(肯德基直接购买,原材料自己制作)
 * 
 * 
 * 一般工厂类一定会有一个方法,就是生产指定模型对象的方法
 * 一般方法名为:build   newInstance
 * 
 * 
 * 注意:
 * 一般在工厂类中会有两个以上的构建方法,一个是默认框架路径的模型对象构建方法(无参的方法,是固定的),
 * 还有一个是动态读取任意位置下的框架配置文件(有参的方法,是活用的)
 * @author 晴sister
 *
 * https://i.csdn.net/#/uc/profile
 */
public class ConfigModelFactory {
	
	/**
	 * 通过资源文件构建对应的模型对象
	 * @param path   具体的资源文件路径
	 * @return
	 * @throws Exception 
	 */
	public static ConfigModel build(String path) throws Exception {
		//path=/config.xml
		InputStream in = ConfigModelFactory.class.getResourceAsStream(path);
		SAXReader reader=new SAXReader();
		//config.xml里的内容
		Document doc = reader.read(in);
		
		//接下来就做一件事情--->把内容填充到configModel对象中(doc.asXML--->configModel)
		ConfigModel configModel=new ConfigModel();
		ActionModel actionModel=null;
		ForwardModel forwardModel=null;
		List<Element> actionEles = doc.selectNodes("/config/action");
		for (Element actionEle : actionEles) {
			actionModel=new ActionModel();
			actionModel.setPath(actionEle.attributeValue("path"));
			actionModel.setType(actionEle.attributeValue("type"));
			//给actionModel中放入ForwardModel对象??
			//拿到forward标签内容
			List<Element> forwardEles = actionEle.selectNodes("forward");
			for (Element forwardEle : forwardEles) {
				forwardModel=new ForwardModel();
				forwardModel.setName(forwardEle.attributeValue("name"));
				forwardModel.setPath(forwardEle.attributeValue("path"));
				//redirect属性是Boolean的
				//需求:只有config.xml中redirect属性值填写雷亮false,它才代表转发(不填或者填其他的都代表重定向)
				//forwardEle.attributeValue("redirect")获取到config中的redirect属性值,那个字符串
				forwardModel.setRedirect(!"false".equals(forwardEle.attributeValue("redirect")));
				actionModel.push(forwardModel);
			}
			configModel.push(actionModel);
		}
		return  configModel;
	}
	/**
	 * 默认框架路径的模型对象构建方法
	 * @return
	 * @throws Exception 
	 */
	public static ConfigModel build() throws Exception {
		return build("/config.xml");
	}
	
	public static void main(String[] args) throws Exception {
		ConfigModel model=ConfigModelFactory.build();
	//	ActionModel actionModel = model.pop("/regAction");
		//System.out.println(actionModel.getType());
		//需求:获取/loginAction下的success结果码对应的页面/main.js
		ActionModel actionModel = model.pop("/loginAction");
		System.out.println(actionModel.getType());
		
		ForwardModel forwardModel = actionModel.pop("success");
		System.out.println(forwardModel.getPath());
	}
}

注意:

  • 一般在工厂类中会有两个以上的构建方法,一个是默认框架路径的模型对象构建方法(无参的方法,是固定的),
  • 还有一个是动态读取任意位置下的框架配置文件(有参的方法,是活用的)

建模案例2

通过上面详细讲解的案例,现在我们自己独立完成一个完整xml建模思路及代码
有一个web.xml文件的内容如下:

<web-app>
  <servlet>
  	<servlet-name>jrebelServlet</servlet-name>
  	<servlet-class>com.zking.xml.JrebelServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>jrebelServlet</servlet-name>
  	<url-pattern>/jrebelServlet</url-pattern>
  </servlet-mapping>
  
  <servlet>
  	<servlet-name>jrebelServlet2</servlet-name>
  	<servlet-class>com.zking.xml.JrebelServlet2</servlet-class>
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>jrebelServlet2</servlet-name>
  	<url-pattern>/jrebelServlet2</url-pattern>
  	<url-pattern>/jrebelServlet3</url-pattern>
  </servlet-mapping>
</web-app>

首先我们先来分析一下需求:
在这里插入图片描述
需求已经出来了,接下来我们来分析xml建模的过程:
在这里插入图片描述

首先先做好准备工作:
导入 架包:
在这里插入图片描述
导入web.xml文件,这里我放在源文件夹下
在这里插入图片描述

代码实现:
先建url_patternModel类(标签url-pattern)

package com.xiaoqing.webmodel;

public class Url_PatternModel {

	private String val;

	public String getVal() {
		return val;
	}

	public void setVal(String val) {
		this.val = val;
	}
	
	
}

然后继续往上走,建servlet-classModel类(标签servlet-class)

package com.xiaoqing.webmodel;

public class Servlet_ClassModel {
	private String val;

	public String getVal() {
		return val;
	}

	public void setVal(String val) {
		this.val = val;
	}
}

继续向上走,建servlet-nameModel类:(标签servlet-name)

package com.xiaoqing.webmodel;

public class Servlet_NameModel {
	private String val;

	public String getVal() {
		return val;
	}

	public void setVal(String val) {
		this.val = val;
	}
	
}

继续向上走,建servlet-mappingModel类:(标签servlet-mapping)

package com.xiaoqing.webmodel;

import java.util.HashMap;
import java.util.Map;

import com.xiaoqing.model.ActionModel;

public class Servlet_MappingModel {

	private Servlet_NameModel servlet_NameModel;//<servlet-mapping>中的子标签<servlet-name>,只能有一个,所以不能用集合
	
	private Map<String,Url_PatternModel> urlMap=new HashMap<String, Url_PatternModel>();//<servlet-mapping>中的子标签<url-pattern>
	
	public Servlet_NameModel getServlet_NameModel() {
		return servlet_NameModel;
	}

	public void setServlet_NameModel(Servlet_NameModel servlet_NameModel) {
		this.servlet_NameModel = servlet_NameModel;
	}



	/**
	 * 放入servlet对象中
	 * <servlet-mapping>放入<servlet>中
	 * @param url_PatternModel
	 */
	public void push(Url_PatternModel url_PatternModel,Servlet_NameModel servlet_NameModel) {
		urlMap.put(servlet_NameModel.getVal(), url_PatternModel);
	}
	/**
	 * 取
	 * @param val
	 * @return
	 */
	public Url_PatternModel pop(String val) {
		return urlMap.get(val);
	}
	
}

建servlet类:标签(servlet)

package com.xiaoqing.webmodel;

public class ServletModel {

	private Servlet_NameModel servlet_NameModel;//<servlet>中的子标签<servlet-name>
	private Servlet_ClassModel servlet_ClassModel;//<servlet>中的子标签<servlet-class>
	public Servlet_NameModel getServlet_NameModel() {
		return servlet_NameModel;
	}
	public void setServlet_NameModel(Servlet_NameModel servlet_NameModel) {
		this.servlet_NameModel = servlet_NameModel;
	}
	public Servlet_ClassModel getServlet_ClassModel() {
		return servlet_ClassModel;
	}
	public void setServlet_ClassModel(Servlet_ClassModel servlet_ClassModel) {
		this.servlet_ClassModel = servlet_ClassModel;
	}
	
	
	
	
}

然后就是web-app类:(标签web-app)

package com.xiaoqing.webmodel;

import java.util.HashMap;
import java.util.Map;

public class Web_AppModel {
	
	private Map<String, ServletModel> servletMap=new HashMap<String, ServletModel>();//<web-app>中的子标签<servlet>
	private Map<String, Servlet_MappingModel> servletMappingMap=new HashMap<String, Servlet_MappingModel>();//<web-app>中的子标签<servlet-mapping>
	
	
	/**
	 * 放入servlet对象中
	 * <servlet>放入<web-app>中
	 * @param servletModel
	 */
	public void pushServlet(ServletModel servletModel) {
		servletMap.put(servletModel.getServlet_NameModel().getVal(), servletModel);
	}
	
	public ServletModel popServlet(String servlet_NameModel) {
		return servletMap.get(servlet_NameModel);
	}

	/**
	 * 放入servlet对象中
	 * <servlet-mapping>放入<web-app>中
	 * @param Servlet_MappingModel
	 */
	public void pushServletMapping(Servlet_MappingModel servlet_MappingModel) {
		servletMappingMap.put(servlet_MappingModel.getServlet_NameModel().getVal(), servlet_MappingModel);
	}
	
	public Servlet_MappingModel popMapping(String servlet_NameModel) {
		return servletMappingMap.get(servlet_NameModel);
	}
}

最后建一个web-app工厂类

package com.xiaoqing.webmodel;

import java.io.InputStream;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

public class Web_AppModelFactory {
	/**
	 * 通过资源文件构建对应的模型对象
	 * @param path   具体的资源文件路径
	 * @return
	 * @throws Exception 
	 */
	public static Web_AppModel build(String path) throws Exception {
		//path=/web.xml
		InputStream in = Web_AppModelFactory.class.getResourceAsStream(path);
		SAXReader reader=new SAXReader();
		//web.xml里的内容
		Document doc = reader.read(in);
		//System.out.println(doc.asXML());
		
		Web_AppModel web_AppModel=new Web_AppModel();
		ServletModel servletModel=null;
		Servlet_MappingModel servlet_MappingModel=null;
		/*
		 * 将servlet的标签内容填充进WebApp
		 */
		 List<Element> servletEles = doc.selectNodes("/web-app/servlet");
		for (Element servletEle : servletEles) {
			/*
			 * 给ServletModel填充xml的内容
			 */
			
			servletModel=new ServletModel();
			//查找单节点
			Element servletNameEle = (Element)servletEle.selectSingleNode("servlet-name");
			Element servletClassEle = (Element)servletEle.selectSingleNode("servlet-class");
		
			Servlet_NameModel servlet_NameModel=new Servlet_NameModel();
			Servlet_ClassModel servlet_ClassModel=new Servlet_ClassModel();
			
			servlet_NameModel.setVal(servletNameEle.getText());
			servlet_ClassModel.setVal(servletClassEle.getText());
			//将<servlet-name>,<servlet-class>放入servlet中,别忘了,正因为这个原因报了很久的空指针异常
			servletModel.setServlet_ClassModel(servlet_ClassModel);
			servletModel.setServlet_NameModel(servlet_NameModel);
			web_AppModel.pushServlet(servletModel);
		//System.out.println(servletModel.getServlet_NameModel().getVal());
			//
		}
		
		
		/*
		 * 将servlet-mapping的标签内容填充进WebApp
		 */
		List<Element>  servlet_MappingEles = doc.selectNodes("/web-app/servlet-mapping");
		//System.err.println("---------------");
		for (Element servlet_MappingEle : servlet_MappingEles) {
			servlet_MappingModel=new Servlet_MappingModel();
			/*
			 * 给ServletMappingModel填充xml的内容
			 */
			Element servletNameEle =(Element) servlet_MappingEle.selectSingleNode("servlet-name");
			Servlet_NameModel servlet_NameModel=new Servlet_NameModel();
			servlet_NameModel.setVal(servletNameEle.getText());
			servlet_MappingModel.setServlet_NameModel(servlet_NameModel);
			
			List<Element>  urlPatternEles = servlet_MappingEle.selectNodes("url-pattern");
			for (Element urlPatternEle : urlPatternEles) {
				Url_PatternModel url_PatternModel=new Url_PatternModel();
				url_PatternModel.setVal(urlPatternEle.getText());
				servlet_MappingModel.push(url_PatternModel,servlet_NameModel);
			}
			web_AppModel.pushServletMapping(servlet_MappingModel);
		}
		return  web_AppModel;
	}
	
	public static Web_AppModel build() throws Exception {
		return build("/web.xml");
	}
}

下面我们来测试一下:

public static void main(String[] args) throws Exception {
		Web_AppModel wm=Web_AppModelFactory.build();
		ServletModel servletModel=wm.popServlet("jrebelServlet");
		Servlet_MappingModel servlet_MappingModel = wm.popMapping("jrebelServlet2");
		Url_PatternModel urlpattern = servlet_MappingModel.pop(servlet_MappingModel.getServlet_NameModel().getVal()) ;
		
		System.out.println("servlet-name:"+servletModel.getServlet_NameModel().getVal());
		System.out.println("servlet-class:"+servletModel.getServlet_ClassModel().getVal());
		System.out.println();
		
		System.out.println("servlet-mapping(name):"+servlet_MappingModel.getServlet_NameModel().getVal());
		System.out.println("servlet-mapping(url-mapping):"+urlpattern.getVal());
	}

最终的结果:
在这里插入图片描述

2.总结

1.为什么需要xml建模?

1.代码封装,提高复用性
2.提高性能,xml解析的过程只会有一次了

2.建模的过程

1.获取到资源文件
2.分析xml标签,将其看成对象,分析该对象的属性及行为
3.解析出xml资源文件中的所有内容
4.建模的核心部分:将xml资源文件中的内容填充到各个标签"<action>"对应的模型对象ActionModel
5.注意要将子模型对象填充到父模型中
6.最后测试

小编留言:一个bug找了差不多半天,一直报空指针异常,原来是servlet没有对象,这次吸取了教训,希望广大的码农别像我一样哦!希望能帮到大家,欢迎大家留言评论!谢谢

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值