建设网站的安全性,广告公司企业介绍,阿里云网站建设最后什么样子,招标投标公共服务平台目录1 原型模式1.1 原型模式定义1.2 原型模式的应用场景1.3 原型模式的通用写法#xff08;浅拷贝#xff09;1.4 使用序列化实现深度克隆1.5 克隆破坏单例模式1.6 原型模式在源码中的应用1.7 原型模式的优缺点1.8 总结2 建造者模式2.1 建造者模式定义2.2 建造者模式的应用场…
目录1 原型模式1.1 原型模式定义1.2 原型模式的应用场景1.3 原型模式的通用写法浅拷贝1.4 使用序列化实现深度克隆1.5 克隆破坏单例模式1.6 原型模式在源码中的应用1.7 原型模式的优缺点1.8 总结2 建造者模式2.1 建造者模式定义2.2 建造者模式的应用场景2.3 建造者模式的基本写法2.4 建造者模式的链式写法2.5 建造者模式应用案例2.6 建造者模式在源码中的体现2.7 建造者模式的优缺点2.8 建造者模式和工厂模式的区别1 原型模式
1.1 原型模式定义
原型模式PrototypePattern是指原型实例指定创建对象的种类并且通过拷贝这些原型创建新的对象属于创建型模式。 官方原文Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype. 原型模式的核心在于拷贝原型对象。以系统中已存在的一个对象为原型直接基于内存二进制流进行拷贝无需再经历耗时的对象初始化过程不调用构造函数性能提升许多。当对象的构建过程比较耗时时可以利用当前系统中已存在的对象作为原型对其进行克隆一般是基于二进制流的复制躲避初始化过程使得新对象的创建时间大大减少。下面我们来看看原型模式类结构图
从 UML 图中我们可以看到原型模式 主要包含三个角色
客户(Client)客户类提出创建对象的请求。
抽象原型(Prototype)规定拷贝接口。
具体原型Concrete Prototype被拷贝的对象。 注对不通过 new 关键字而是通过对象拷贝来实现创建对象的模式就称作原型模式。 1.2 原型模式的应用场景
你一定遇到过大篇幅getter、setter赋值的场景。
代码非常工整命名非常规范注释也写的很全面,其实这就是原型模式的需求场景。但是大家觉得这样的代码优雅吗我认为这样的代码属于纯体力劳动。那原型模式能帮助我们解决这样的问题。
原型模式主要适用于以下场景
1、类初始化消耗资源较多。
2、new产生的一个对象需要非常繁琐的过程数据准备、访问权限等
3、构造函数比较复杂。
4、循环体中生产大量对象时。
在 Spring 中原型模式应用得非常广泛。例如 scope“prototype”在我们经常用的**JSON.parseObject()**也是一种原型模式。
1.3 原型模式的通用写法浅拷贝
一个标准的原型模式代码应该是这样设计的。先创建原型IPrototype接口
public interface IPrototypeT {T clone();
}创建具体需要克隆的对象ConcretePrototype
public class ConcretePrototype implements IPrototype {private int age;private String name;public int getAge() {return age;}public void setAge(int age) {this.age age;}public String getName() {return name;}public void setName(String name) {this.name name;}Overridepublic ConcretePrototype clone() {ConcretePrototype concretePrototype new ConcretePrototype();concretePrototype.setAge(this.age);concretePrototype.setName(this.name);return concretePrototype;}Overridepublic String toString() {return ConcretePrototype{ age age , name name \ };}
}测试代码
public class Client {public static void main(String[] args) {//创建原型对象ConcretePrototype prototype new ConcretePrototype();prototype.setAge(18);prototype.setName(Oldlu);System.out.println(prototype);//拷贝原型对象ConcretePrototype cloneType prototype.clone();System.out.println(cloneType);}
}运行结果
ConcretePrototype{age18, nameOldlu}
ConcretePrototype{age18, nameOldlu}这时候有小伙伴就问了原型模式就这么简单吗对就是这么简单。在这个简单的场景之下看上去操作好像变复杂了。但如果有几百个属性需要复制那我们就可以一劳永逸。但是上面的复制过程是我们自己完成的在实际编码中我们一般不会浪费这样的体力劳动JDK已经帮我们实现了一个现成的API我们只需要实现Cloneable接口即可。来改造一下代码修改ConcretePrototype类
Data
public class ConcretePrototype implements Cloneable {private int age;private String name;Overridepublic ConcretePrototype clone() {try {return (ConcretePrototype)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();return null;}}
}重新运行也会得到同样的结果。
有了JDK的支持再多的属性复制我们也能轻而易举地搞定了。下面我们再来做一个测试给ConcretePrototype增加一个个人爱好的属性hobbies
Data
public class ConcretePrototype implements Cloneable {private int age;private String name;private ListString hobbies;Overridepublic ConcretePrototype clone() {try {return (ConcretePrototype)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();return null;}}
}修改客户端测试代码
public class Client {public static void main(String[] args) {//创建原型对象ConcretePrototype prototype new ConcretePrototype();prototype.setAge(18);prototype.setName(Oldlu);ListString hobbies new ArrayListString();hobbies.add(书法);hobbies.add(美术);prototype.setHobbies(hobbies);//拷贝原型对象ConcretePrototype cloneType prototype.clone();cloneType.getHobbies().add(技术控);System.out.println(原型对象 prototype);System.out.println(克隆对象 cloneType);System.out.println(prototype cloneType);System.out.println(原型对象的爱好 prototype.getHobbies());System.out.println(克隆对象的爱好 cloneType.getHobbies());System.out.println(prototype.getHobbies() cloneType.getHobbies());}
}运行结果
原型对象ConcretePrototype(age18, nameOldlu, hobbies[书法, 美术, 技术控])
克隆对象ConcretePrototype(age18, nameOldlu, hobbies[书法, 美术, 技术控])
false
原型对象的爱好[书法, 美术, 技术控]
克隆对象的爱好[书法, 美术, 技术控]
true我们给复制后的克隆对象新增一项爱好发现原型对象也发生了变化这显然不符合我们的预期。因为我们希望克隆出来的对象应该和原型对象是两个独立的对象不应该再有联系了。从测试结果分析来看应该是hobbies共用了一个内存地址意味着复制的不是值而是引用的地址。这样的话如果我们修改任意一个对象中的属性值prototype 和cloneType的hobbies值都会改变。这就是我们常说的浅克隆。只是完整复制了值类型数据没有赋值引用对象。换言之所有的引用对象仍然指向原来的对象显然不是我们想要的结果。那如何解决这个问题呢下面我们来看深度克隆继续改造。
扩展知识String对象在内存中是不可变的final类型虽然克隆后两个对象String的引用指向的是同一个内存地址但是如果给克隆后的对象的String属性改变值那么相当于是在内存中重新开辟了一块内存来存储这个改变的值而此时的String属性对象就指向了该内存值所以这个时候克隆前和克隆后对象的String属性是不一样的。
String 每次赋值相当于new String()。
1.4 使用序列化实现深度克隆
在上面的基础上我们继续改造来看代码增加一个deepClone()方法
Data
public class ConcretePrototype implements Cloneable,Serializable {private int age;private String name;private ListString hobbies;Overridepublic ConcretePrototype clone() {try {return (ConcretePrototype)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();return null;}}public ConcretePrototype deepClone(){try {ByteArrayOutputStream bos new ByteArrayOutputStream();ObjectOutputStream oos new ObjectOutputStream(bos);oos.writeObject(this);ByteArrayInputStream bis new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois new ObjectInputStream(bis);return (ConcretePrototype)ois.readObject();}catch (Exception e){e.printStackTrace();return null;}}
}来看客户端调用代码
public class Client {public static void main(String[] args) {//创建原型对象ConcretePrototype prototype new ConcretePrototype();prototype.setAge(18);prototype.setName(Oldlu);ListString hobbies new ArrayListString();hobbies.add(书法);hobbies.add(美术);prototype.setHobbies(hobbies);//拷贝原型对象ConcretePrototype cloneType prototype.deepClone();cloneType.getHobbies().add(技术控);System.out.println(原型对象 prototype);System.out.println(克隆对象 cloneType);System.out.println(prototype cloneType);System.out.println(原型对象的爱好 prototype.getHobbies());System.out.println(克隆对象的爱好 cloneType.getHobbies());System.out.println(prototype.getHobbies() cloneType.getHobbies());}
}运行程序我们发现得到了我们期望的结果
原型对象ConcretePrototype(age18, nameOldlu, hobbies[书法, 美术])
克隆对象ConcretePrototype(age18, nameOldlu, hobbies[书法, 美术, 技术控])
false
原型对象的爱好[书法, 美术]
克隆对象的爱好[书法, 美术, 技术控]
false1.5 克隆破坏单例模式
如果我们克隆的目标的对象是单例对象那意味着深克隆就会破坏单例。实际上防止克隆破坏单例解决思路非常简单禁止深克隆便可。要么你我们的单例类不实现 Cloneable 接口要么我们重写clone()方法在clone方法中返回单例对象即可具体代码如下
Override
protected Object clone() throws CloneNotSupportedException {return INSTANCE;
}1.6 原型模式在源码中的应用
先来JDK中Cloneable接口
public interface Cloneable {
}接口定义还是很简单的我们找源码其实只需要找到看哪些接口实现了 Cloneable 即可。来看ArrayList类的实现。
Object方法
protected native Object clone() throws CloneNotSupportedException;复制
ArrayList是实现的clone方法
public class ArrayListE extends AbstractListEimplements ListE, RandOldluAccess, Cloneable, java.io.Serializable
{public Object clone() {try {ArrayList? v (ArrayList?) super.clone();v.elementData Arrays.copyOf(elementData, size);v.modCount 0;return v;} catch (CloneNotSupportedException e) {// this shouldnt happen, since we are Cloneablethrow new InternalError(e);}}
}我们发现方法中只是将List中的元素循环遍历了一遍。这个时候我们再思考一下是不是这种形式就是深克隆呢其实用代码验证一下就知道了继续修改 ConcretePrototype 类增加一个deepCloneHobbies()方法
Data
public class ConcretePrototype implements Cloneable,Serializable {...public ConcretePrototype deepCloneHobbies(){try {ConcretePrototype result (ConcretePrototype)super.clone();result.hobbies (List)((ArrayList)result.hobbies).clone();return result;} catch (CloneNotSupportedException e) {e.printStackTrace();return null;}}...
}修改客户端代码
public class Client {public static void main(String[] args) {...//拷贝原型对象ConcretePrototype cloneType prototype.deepCloneHobbies();...}
}运行也能得到期望的结果。但是这样的代码其实是硬编码如果在对象中声明了各种集合类型那每种情况都需要单独处理。因此深克隆的写法一般会直接用序列化来操作。
1.7 原型模式的优缺点
优点:
1、性能优良Java自带的 原型模式 是基于内存二进制流的拷贝比直接new一个对象性能上提升了许多。
2、可以使用深克隆方式保存对象的状态使用原型模式将对象复制一份并将其状态保存起来简化了创建对象的过程以便在需要的时候使用(例如恢复到历史某一状态)可辅助实现撤销操作。
缺点
1、需要为每一个类配置一个克隆方法。
2、克隆方法位于类的内部当对已有类进行改造的时候需要修改代码违反了开闭原则。
3、在实现深克隆时需要编写较为复杂的代码而且当对象之间存在多重嵌套引用时为了实现深克隆每一层对象对应的类都必须支持深克隆实现起来会比较麻烦。因此深拷贝、浅拷贝需要运用得当。
1.8 总结
克隆方式1.序列化 反序列化 2.jsonobject 3浅克隆加赋值
浅克隆继承Cloneable接口的都是浅克隆。
深克隆两种方式序列化转JSON。
2 建造者模式
2.1 建造者模式定义
建造者模式Builder Pattern是将一个复杂对象的构建过程与它的表示分离使得同样的构建过程可以创建不同的表示属于创建型模式。使用建造者模式对于用户而言只需指定需要建造的类型就可以获得对象建造过程及细节不需要了解。 官方原文Separate the construction of a cOldluplex object frOldlu its representation so that the same construction process can create different representations. 建造者模式适用于创建对象需要很多步骤但是步骤的顺序不一定固定。如果一个对象有非常复杂的内部结构很多属性可以将复杂对象的创建和使用进行分离。先来看一下建造者模式的类图 建造者模式的设计中主要有四个角色
1、产品Product:要创建的产品类对象
2、建造者抽象Builder建造者的抽象类规范产品对象的各个组成部分的建造一般由子类实现具体的建造过程。
3、建造者ConcreteBuilder:具体的Builder类根据不同的业务逻辑具体化对象的各个组成部分的创建。
4、调用者Director调用具体的建造者来创建对象的各个部分在指导者中不涉及具体产品的信息只负责保证对象各部分完整创建或按某种顺序创建。
2.2 建造者模式的应用场景
建造者模式适用于一个具有较多的零件的复杂产品的创建过程由于需求的变化组成这个复杂产品的各个零件经常猛烈变化但是它们的组合方式却相对稳定。
相同的方法不同的执行顺序产生不同的结果时多个部件或零件都可以装配到一个对象中但是产生的结果又不相同。产品类非常复杂或者产品类中的调用顺序不同产生不同的作用。当初始化一个对象特别复杂参数多而且很多参数都具有默认值时。
建造者模式只关注用户需要什么将最少的关键字传过来生成你想要的结果。
实际顺序是在build方法里面。那是顺序和条件都确定了。每个顺序和条件都分别存储下来了。判断有没有有就添加到product后面。当然就是先判断条件再判断order顺序了
2.3 建造者模式的基本写法
我们还是以课程为例一个完整的课程需要由PPT课件、回放视频、课堂笔记、课后作业组成但是这些内容的设置顺序可以随意调整我们用建造者模式来代入理解一下。首先我们创建一个需要构造的产品类Course
Data
public class Course {private String name;private String ppt;private String video;private String note;private String hOldluework;
}然后创建建造者类CourseBuilder将复杂的构造过程封装起来构造步骤由用户决定
public class CourseBuilder{private Course course new Course();public void addName(String name) {course.setName(name);}public void addPPT(String ppt) {course.setPpt(ppt);}public void addVideo(String video) {course.setVideo(video);}public void addNote(String note) {course.setNote(note);}public void addHOldluework(String hOldluework) {course.setHOldluework(hOldluework);}public Course build() {return course;}
}编写测试类
public class Test {public static void main(String[] args) {CourseBuilder builder new CourseBuilder();builder.addName(设计模式);builder.addPPT(【PPT课件】);builder.addVideo(【回放视频】);builder.addNote(【课堂笔记】);builder.addHOldluework(【课后作业】);System.out.println(builder.build());}
}运行结果:
Course(name设计模式, ppt【PPT课件】, video【回放视频】, note【课堂笔记】, hOldluework【课后作业】)来看一下类结构图 2.4 建造者模式的链式写法
在平时的应用中建造者模式通常是采用链式编程的方式构造对象下面我们来一下演示代码修改CourseBuilder类将Course变为CourseBuilder的内部类。然后将构造步骤添加进去每完成一个步骤都返回this
public class CourseBuilder {private Course course new Course();public CourseBuilder addName(String name) {course.setName(name);return this;}public CourseBuilder addPPT(String ppt) {course.setPpt(ppt);return this;}public CourseBuilder addVideo(String video) {course.setVideo(video);return this;}public CourseBuilder addNote(String note) {course.setNote(note);return this;}public CourseBuilder addHOldluework(String hOldluework) {course.setHOldluework(hOldluework);return this;}public Course build() {return this.course;}Datapublic class Course {private String name;private String ppt;private String video;private String note;private String hOldluework;}
}客户端使用
public class Test {public static void main(String[] args) {CourseBuilder builder new CourseBuilder().addName(设计模式).addPPT(【PPT课件】).addVideo(【回放视频】).addNote(【课堂笔记】).addHOldluework(【课后作业】);System.out.println(builder.build());}
}这样写法是不是很眼熟好像在哪见过呢后面我们分析建造者模式在源码中的应用大家就会明白。接下来我们再来看一下类图的变化 2.5 建造者模式应用案例
下面我们再来看一个实战案例这个案例参考了开源框架JPA的SQL构造模式。是否记得我们在构造SQL查询条件的时候需要根据不同的条件来拼接SQL字符串。如果查询条件复杂的时候我们SQL拼接的过程也会变得非常复杂从而给我们的代码维护带来非常大的困难。因此我们用建造者类QueryRuleSqlBuilder 将复杂的构造 SQL 过程进行封装用 QueryRule 对象专门保存 SQL 查询时的条件最后根据查询条件自动生成SQL语句。来看代码先创建QueryRule类
/*** QueryRule,主要功能用于构造查询条件*/
public final class QueryRule implements Serializable
{... /*** 添加升序规则* param propertyName* return*/public QueryRule addAscOrder(String propertyName) {this.ruleList.add(new Rule(ASC_ORDER, propertyName));return this;}public QueryRule andEqual(String propertyName, Object value) {this.ruleList.add(new Rule(EQ, propertyName, new Object[] { value }).setAndOr(AND));return this;}public QueryRule andLike(String propertyName, Object value) {this.ruleList.add(new Rule(LIKE, propertyName, new Object[] { value }).setAndOr(AND));return this;}...
}然后创建QueryRuleSqlBuilder类
/*** 根据QueryRule自动构建sql语句*/
public class QueryRuleSqlBuilder {... /*** 处理like* param rule*/private void processLike(QueryRule.Rule rule) {if (ArrayUtils.isEmpty(rule.getValues())) {return;}Object obj rule.getValues()[0];if (obj ! null) {String value obj.toString();if (!StringUtils.isEmpty(value)) {value value.replace(*, %);obj value;}}add(rule.getAndOr(),rule.getPropertyName(),like,%rule.getValues()[0]%);}/*** 处理 * param rule*/private void processEqual(QueryRule.Rule rule) {if (ArrayUtils.isEmpty(rule.getValues())) {return;}add(rule.getAndOr(),rule.getPropertyName(),,rule.getValues()[0]);}/*** 处理 order by* param rule 查询规则*/private void processOrder(Rule rule) {switch (rule.getType()) {case QueryRule.ASC_ORDER:// propertyName非空if (!StringUtils.isEmpty(rule.getPropertyName())) {orders.add(Order.asc(rule.getPropertyName()));}break;case QueryRule.DESC_ORDER:// propertyName非空if (!StringUtils.isEmpty(rule.getPropertyName())) {orders.add(Order.desc(rule.getPropertyName()));}break;default:break;}}...
}创建Order类
/*** sql排序组件*/
public class Order {private boolean ascending; //升序还是降序private String propertyName; //哪个字段升序哪个字段降序public String toString() {return propertyName (ascending ? asc : desc);}/*** Constructor for Order.*/protected Order(String propertyName, boolean ascending) {this.propertyName propertyName;this.ascending ascending;}/*** Ascending order** param propertyName* return Order*/public static Order asc(String propertyName) {return new Order(propertyName, true);}/*** Descending order** param propertyName* return Order*/public static Order desc(String propertyName) {return new Order(propertyName, false);}
}编写测试代码
public class Test {public static void main(String[] args) {QueryRule queryRule QueryRule.getInstance();queryRule.addAscOrder(age);queryRule.andEqual(addr,ShanDong);queryRule.andLike(name,Oldlu);QueryRuleSqlBuilder builder new QueryRuleSqlBuilder(queryRule);System.out.println(builder.builder(t_member));System.out.println(Params: Arrays.toString(builder.getValues()));}
}这样一来我们的客户端代码就非常清朗来看运行结果
select * frOldlu t_member where addr ? and name like ? order by age asc
Params: [ShanDong, %Oldlu%]2.6 建造者模式在源码中的体现
下面来看建造者模式在哪些源码中有应用呢首先来看JDK的StringBuilder它提供append()方法给我们开放构造步骤最后调用toString()方法就可以获得一个构造好的完整字符串源码如下
public final class StringBuilderextends AbstractStringBuilderimplements java.io.Serializable, CharSequence
{public StringBuilder append(StringBuffer sb) {super.append(sb);return this;}
}在MyBatis中也有体现比如CacheBuilder类。
同样在 MyBatis 中比如 SqlSessionFactoryBuilder 通过调用 build()方法获得的是一个SqlSessionFactory 类。
当然在 Spring中自然也少不了比如 BeanDefinitionBuilder 通过调用getBeanDefinition()方法获得一个BeanDefinition对象。
2.7 建造者模式的优缺点
建造者模式的优点
1、封装性好创建和使用分离
2、扩展性好建造类之间独立、一定程度上解耦。
建造者模式的缺点
1、产生多余的Builder对象
2、产品内部发生变化建造者都要修改成本较大。
2.8 建造者模式和工厂模式的区别
建造者模式和工厂模式的区别
1、建造者模式更加注重方法的调用顺序工厂模式注重于创建对象。
2、创建对象的力度不同建造者模式创建复杂的对象由各种复杂的部件组成工厂模式创建出来的都一样。
3、关注重点不一样工厂模式模式只需要把对象创建出来就可以了而建造者模式中不仅要创建出这个对象还要知道这个对象由哪些部件组成。
4、建造者模式根据建造过程中的顺序不一样最终的对象部件组成也不一样。
可以理解为工厂创建过程是静态的构建者模式创建过程经过外放而变成动态的。 文章转载自: http://www.morning.phcqk.cn.gov.cn.phcqk.cn http://www.morning.dpruuode.cn.gov.cn.dpruuode.cn http://www.morning.syxmx.cn.gov.cn.syxmx.cn http://www.morning.btqrz.cn.gov.cn.btqrz.cn http://www.morning.pjftk.cn.gov.cn.pjftk.cn http://www.morning.ryxbz.cn.gov.cn.ryxbz.cn http://www.morning.sgnxl.cn.gov.cn.sgnxl.cn http://www.morning.kwyq.cn.gov.cn.kwyq.cn http://www.morning.kdfqx.cn.gov.cn.kdfqx.cn http://www.morning.fcqlt.cn.gov.cn.fcqlt.cn http://www.morning.qwdlj.cn.gov.cn.qwdlj.cn http://www.morning.fkflc.cn.gov.cn.fkflc.cn http://www.morning.qfzjn.cn.gov.cn.qfzjn.cn http://www.morning.jbshh.cn.gov.cn.jbshh.cn http://www.morning.lhyhx.cn.gov.cn.lhyhx.cn http://www.morning.1000sh.com.gov.cn.1000sh.com http://www.morning.bpmfn.cn.gov.cn.bpmfn.cn http://www.morning.zwzwn.cn.gov.cn.zwzwn.cn http://www.morning.ldcrh.cn.gov.cn.ldcrh.cn http://www.morning.ttryd.cn.gov.cn.ttryd.cn http://www.morning.dshxj.cn.gov.cn.dshxj.cn http://www.morning.gfpyy.cn.gov.cn.gfpyy.cn http://www.morning.qhkx.cn.gov.cn.qhkx.cn http://www.morning.npbnc.cn.gov.cn.npbnc.cn http://www.morning.kpwcx.cn.gov.cn.kpwcx.cn http://www.morning.rwcw.cn.gov.cn.rwcw.cn http://www.morning.slfmp.cn.gov.cn.slfmp.cn http://www.morning.zmyhn.cn.gov.cn.zmyhn.cn http://www.morning.mtzyr.cn.gov.cn.mtzyr.cn http://www.morning.dmtwz.cn.gov.cn.dmtwz.cn http://www.morning.nlysd.cn.gov.cn.nlysd.cn http://www.morning.zlmbc.cn.gov.cn.zlmbc.cn http://www.morning.fhrt.cn.gov.cn.fhrt.cn http://www.morning.kfmnf.cn.gov.cn.kfmnf.cn http://www.morning.hbqhz.cn.gov.cn.hbqhz.cn http://www.morning.scrnt.cn.gov.cn.scrnt.cn http://www.morning.xrwbc.cn.gov.cn.xrwbc.cn http://www.morning.sjqml.cn.gov.cn.sjqml.cn http://www.morning.qdxkn.cn.gov.cn.qdxkn.cn http://www.morning.sbdqy.cn.gov.cn.sbdqy.cn http://www.morning.cpnlq.cn.gov.cn.cpnlq.cn http://www.morning.hmnhp.cn.gov.cn.hmnhp.cn http://www.morning.xxfxxf.cn.gov.cn.xxfxxf.cn http://www.morning.pmwhj.cn.gov.cn.pmwhj.cn http://www.morning.sgpny.cn.gov.cn.sgpny.cn http://www.morning.ygxf.cn.gov.cn.ygxf.cn http://www.morning.dzdtj.cn.gov.cn.dzdtj.cn http://www.morning.xnqjs.cn.gov.cn.xnqjs.cn http://www.morning.yhdqq.cn.gov.cn.yhdqq.cn http://www.morning.zqnmp.cn.gov.cn.zqnmp.cn http://www.morning.skbhl.cn.gov.cn.skbhl.cn http://www.morning.kxbdm.cn.gov.cn.kxbdm.cn http://www.morning.epeij.cn.gov.cn.epeij.cn http://www.morning.rrcrs.cn.gov.cn.rrcrs.cn http://www.morning.qstjr.cn.gov.cn.qstjr.cn http://www.morning.jzkqg.cn.gov.cn.jzkqg.cn http://www.morning.dgsx.cn.gov.cn.dgsx.cn http://www.morning.xdlwm.cn.gov.cn.xdlwm.cn http://www.morning.zlcsz.cn.gov.cn.zlcsz.cn http://www.morning.pqchr.cn.gov.cn.pqchr.cn http://www.morning.lmqfq.cn.gov.cn.lmqfq.cn http://www.morning.lmctj.cn.gov.cn.lmctj.cn http://www.morning.rkdnm.cn.gov.cn.rkdnm.cn http://www.morning.jqbmj.cn.gov.cn.jqbmj.cn http://www.morning.xqgfy.cn.gov.cn.xqgfy.cn http://www.morning.ydxwj.cn.gov.cn.ydxwj.cn http://www.morning.npmpn.cn.gov.cn.npmpn.cn http://www.morning.scrnt.cn.gov.cn.scrnt.cn http://www.morning.dwxqf.cn.gov.cn.dwxqf.cn http://www.morning.sgpny.cn.gov.cn.sgpny.cn http://www.morning.bqhlp.cn.gov.cn.bqhlp.cn http://www.morning.fbtgp.cn.gov.cn.fbtgp.cn http://www.morning.wrbx.cn.gov.cn.wrbx.cn http://www.morning.lynmt.cn.gov.cn.lynmt.cn http://www.morning.wcghr.cn.gov.cn.wcghr.cn http://www.morning.wkgyz.cn.gov.cn.wkgyz.cn http://www.morning.rpth.cn.gov.cn.rpth.cn http://www.morning.qxkjy.cn.gov.cn.qxkjy.cn http://www.morning.gwjsm.cn.gov.cn.gwjsm.cn http://www.morning.fxkgp.cn.gov.cn.fxkgp.cn