文章目录
- 前言
- 建模分析
- 建模过程
- 代码实现
- 总结
前言
为什么需要xml建模?
1.因为项目发布后xml基本不会变了,如果不建模每次都要去读资源,这样会造成系统资源的浪费、服务器的压力、同时造成了不必要的麻烦。
2.建模的话只把读取文件的那一步只读取一遍,然后放到静态块里面,把每个xml标签转为java对象,去内存里面读取java对象,通过工厂方法生产最大java对象(这里相当于xml里面的根元素)。
3.小结:它是一种解决方案、数据模型、同时也提高了代码的复用性、性能、而且xml解析的过程只会有一次了。
建模分析
核心思想:利用java面向对象的特性,用操作对象的方式操作xml。
用例:
首先我们要理清思路,基于以上xml文档我们可以得出基于根元素config节点下面有俩个元素标签。
1.属性
- config 根元素标签:有且只有一个(无属性,有行为)
- action 元素标签 : path属性、type属性 (有属性,有行为)
- forward 元素标签:name属性、path属性、redirect属性 (有属性,无行为)
- 注: forward 元素标签无行为是因为本身就是一个自闭标签,无标签体
2.创建对象
- 根据元素标签创建元素对象,注:model表示对象模型!
- config->ConfigModel类
- action->ActionModel类
- forward->ForwardModel类
2.行为
实现:用map实现增加,查询行为
- 压入:push()
- 查询:pop()根据键获取值—》键:name,值:type
对应的关系相当于: 小箱子–>中箱子–>大箱子
建模过程
- 获取到资源文件进行加载
- 分析xml标签,将其看成对象,分析该对象的属性及行为创建对应的实体
- 解析出xml资源文件中的所有内容也就是一个文档对象
- 建模的核心部分(将xml资源文件中的内容填充到各个标签对应的模型对象ActionModel)
- 将子模型对象填充到父模型中
附加增强功能:
- 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());
*/
}
}
测试结果:
加入正则之后的好处:
我们先修改一下xml
这样直接定位到错误
总结
好了今天xml建模就到此结束了,每天努力加油搬砖哈哈哈!!!