文章目录

  • 前言
  • 建模分析
  • 建模过程
  • 代码实现
  • 总结


前言

为什么需要xml建模?

        1.因为项目发布后xml基本不会变了,如果不建模每次都要去读资源,这样会造成系统资源的浪费、服务器的压力、同时造成了不必要的麻烦。

        2.建模的话只把读取文件的那一步只读取一遍,然后放到静态块里面,把每个xml标签转为java对象,去内存里面读取java对象,通过工厂方法生产最大java对象(这里相当于xml里面的根元素)。

        3.小结:它是一种解决方案、数据模型、同时也提高了代码的复用性、性能、而且xml解析的过程只会有一次了。

建模分析

核心思想:利用java面向对象的特性,用操作对象的方式操作xml。

用例:

XWPFTemplate Java填充模板 斜杠 失效_java


        首先我们要理清思路,基于以上xml文档我们可以得出基于根元素config节点下面有俩个元素标签。

1.属性

  • config 根元素标签:有且只有一个(无属性,有行为)
  • action 元素标签 : path属性、type属性 (有属性,有行为)
  • forward 元素标签:name属性、path属性、redirect属性 (有属性,无行为)
  • 注: forward 元素标签无行为是因为本身就是一个自闭标签,无标签体

2.创建对象

  • 根据元素标签创建元素对象,注:model表示对象模型!
  • config->ConfigModel类
  • action->ActionModel类
  • forward->ForwardModel类

2.行为
实现:用map实现增加,查询行为

  1. 压入:push()
  2. 查询:pop()根据键获取值—》键:name,值:type

XWPFTemplate Java填充模板 斜杠 失效_建模_02


对应的关系相当于: 小箱子–>中箱子–>大箱子

XWPFTemplate Java填充模板 斜杠 失效_java_03

建模过程

  1. 获取到资源文件进行加载
  2. 分析xml标签,将其看成对象,分析该对象的属性及行为创建对应的实体
  3. 解析出xml资源文件中的所有内容也就是一个文档对象
  4. 建模的核心部分(将xml资源文件中的内容填充到各个标签对应的模型对象ActionModel)
  5. 将子模型对象填充到父模型中

附加增强功能:

  • throw new RuntimeException("["+path+"]已存在!");这个异常我们经常用。
  • 把路径写活。
  • 优化变量,凡是循环或者遍历的变量都可以声明在外面。
  • action的path的规范: containsKey, 正则,都抛出了异常。

代码实现

1.ForwardModel 实体类

package com.liyingdong;
/**
 * 
 * @author 李瀛东
 *
 * 2020年5月23日
 */
public class ForwardModel {

	private String name;
	private String path;
	private boolean redirect;
	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;
	}
	public boolean isRedirect() {
		return redirect;
	}
	public void setRedirect(boolean redirect) {
		this.redirect = redirect;
	}
}

2.ActionModel 实体类

package com.liyingdong;

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

/**
 * 
 * @author 李瀛东
 *
 *         2020年5月23日
 */
public class ActionModel {

	private String path;
	private String type;
	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 c存值 将指定的forwardModel压入当前actionmodel 对象中 <forward />
	 * 放入<action></action>
	 * 
	 * @param forwardModel
	 */
	public void push(ForwardModel forwardModel) {
		foMap.put(forwardModel.getName(), forwardModel);
	}

	// forwardModel 取值 根据名字取值
	public ForwardModel pop(String name) {
		return foMap.get(name);
	}

}

3.ConfigModel 实体类

package com.liyingdong;
/**
 * 
 * @author 李瀛东
 *
 * 2020年5月23日
 */

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ConfigModel {

	private Map<String, ActionModel> acMap = new HashMap<String, ActionModel>();

	/**
	 * 将指定的actionModel压入当前ConfigModel 对象中 <forward /> 放入<config></config>
	 * 
	 * @param actionModel
	 */

	// actionModel存值
	public void push(ActionModel actionModel) {
		// 优化path的规范
		String path = actionModel.getPath();
		// 判断不能重复
		if (acMap.containsKey(path)) {
			/**
			 * 运行时异常 经常用到 有问题的时候,此异常就让程序死掉 开发者看到就解决bug "主要是让问题暴露出来,让开发者解决掉"
			 */
			throw new RuntimeException("[" + path + "]已存在!");
		}
		// 判断path是否已斜杠开头
		throwPathException(path);

		acMap.put(actionModel.getPath(), actionModel);
	}

	public ActionModel pop(String path) {
		return acMap.get(path);
	}

	// 正则表达式
	public void throwPathException(String path) {
		Pattern compile = Pattern.compile("^/.+$");
		Matcher matcher = compile.matcher(path);
		boolean b = matcher.matches();
		if (!b) {
			throw new RuntimeException("{" + path + "}必须已斜杠开头!");
		}
	}

}

4.ConfigModelFactory 生产类+main方法测试

package com.liyingdong;

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 李瀛东
 *
 *         2020年5月23日
 */
public class ConfigModelFactory {
	/**
	 * 通过资源文件构建对应的模型对象
	 * 
	 * @param path
	 *            具体的资源文件路径
	 * @return
	 * @throws DocumentException
	 */
	public static ConfigModel build(String path) throws DocumentException {
		// 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> selectNodes = doc.selectNodes("/config/action");
		for (Element actionEle : selectNodes) {
			actionModel = new ActionModel();
			actionModel.setPath(actionEle.attributeValue("path"));
			actionModel.setType(actionEle.attributeValue("type"));
			// 给action中放入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,它才代表转发
				forwardModel.setRedirect(!"false".equals(forwardEle.attributeValue("redirect")));
				actionModel.push(forwardModel);
			}
			configModel.push(actionModel);
		}
		return configModel;
	}

	/**
	 * 默认框架路径的模型对象构建方法
	 * 
	 * @return
	 * @throws DocumentException
	 */
	public static ConfigModel build() throws DocumentException {
		return build("/config.xml");
	}

	public static void main(String[] args) throws DocumentException {
		ConfigModel model = ConfigModelFactory.build();
		// ActionModel actionModel = model.pop("/regAction");
		// System.out.println(actionModel.getType());

		// 需求:获取/loginAction下的success结果码对应的页面/main.js
		ActionModel actionModel = model.pop("/loginAction");
		ForwardModel p = actionModel.pop("success");
		System.out.println(p.getPath());
		System.out.println(actionModel.getType());

		/*
		 * ForwardModel forwardModel = actionModel.pop("success");
		 * System.out.println(forwardModel.getPath());
		 */
	}

}

测试结果:

XWPFTemplate Java填充模板 斜杠 失效_建模_04


加入正则之后的好处:

我们先修改一下xml

XWPFTemplate Java填充模板 斜杠 失效_xml_05


这样直接定位到错误

XWPFTemplate Java填充模板 斜杠 失效_java_06

总结

好了今天xml建模就到此结束了,每天努力加油搬砖哈哈哈!!!