网站开发多长时间,微信小程序源代码大全,做网站一定要虚拟主机吗,南宁网站建设Java学习篇#xff08;一#xff09;| 如何生成分布式全局唯一ID 一、使用场景二、常用方法1、UUID #xff08;尽量不要用#xff09;2、数据库自增 #xff08;用的最多-但不适合做分布式ID#xff09;3、Redis 生成ID #xff08;可用#xff09;1、原因2、通过代码… Java学习篇一| 如何生成分布式全局唯一ID 一、使用场景二、常用方法1、UUID 尽量不要用2、数据库自增 用的最多-但不适合做分布式ID3、Redis 生成ID 可用1、原因2、通过代码实现分布式全局唯一ID工具 正式使用3、编写获取工具4、测试获取工具5、总结 4、雪花算法SnowFlake可用1.雪花算法概念2.雪花算法的缺点方式一自定义的雪花算法 该工具类已做了回拨处理方式二基于hutool工具类第一步引入hutool工具依赖包第二步Springboot整合具体代码实现 方式三使用 百度 Uidgenerator基于SnowFlake算法改造的方式四使用 美团Leaf基于SnowFlake算法改造的  三、前端直接使用发生精度丢失参考文章 一、使用场景 全局唯一ID在电商购物、社交网络、金融系统、分布式数据库和缓存、物联网等场景下都尤为重要。 它确保了数据的唯一性、一致性、安全性和高效性是现代软件开发和系统设计中不可或缺的一部分。 二、常用方法 解决方案根据自己项目需求进行设计调整 1、UUID 尽量不要用 UUID Universally Unique Identifier通用唯一识别码的缩写。UUID是由一组32位数的16进制数字所构成所以UUID理论上的总数为 16^322^128约等于 3.4 x 10^38。也就是说若每纳秒产生1兆个UUID要花100亿年才会将所有UUID用完。 生成的UUID是由 8-4-4-4-12格式的数据组成其中32个字符和4个连字符’ - 一般我们使用的时候会将连字符删除 uuid.toString().replaceAll(-,)。 目前UUID的产生方式有5种版本每个版本的算法不同应用范围也不同。 
版本1基于时间的UUID 这个一般是通过当前时间随机数和本地Mac地址来计算出来可以通过 org.apache.logging.log4j.core.util包中的 UuidUtil.getTimeBasedUuid()来使用或者其他包中工具。由于使用了MAC地址因此能够确保唯一性但是同时也暴露了MAC地址私密性不够好。版本2 DCEDistributed Computing Environment DCE安全的UUID 安全的UUID和基于时间的UUID算法相同但会把时间戳的前4位置换为POSIX的UID或GID。这个版本的UUID在实际中较少用到。版本3基于名字的UUIDMD5- 版本3 基于名字的UUID通过计算名字和名字空间的MD5散列值得到。这个版本的UUID保证了相同名字空间中不同名字生成的UUID的唯一性不同名字空间中的UUID的唯一性相同名字空间中相同名字的UUID重复生成是相同的。版本4随机UUID -根据随机数或者伪随机数生成UUID。这种UUID产生重复的概率是可以计算出来的但是重复的可能性可以忽略不计因此该版本也是被经常使用的版本。JDK中使用的就是这个版本。版本5基于名字的UUIDSHA1 - 版本5 和基于名字的UUID算法类似只是散列值计算使用SHA1Secure Hash Algorithm 1算法。 
Java中 JDK自带的 UUID产生方式就是版本4根据随机数生成的 UUID 和版本3基于名字的 UUID有兴趣的可以去看看它的源码。 public static void main(String[] args) {//获取一个版本4根据随机字节数组的UUID。UUID uuid  UUID.randomUUID();System.out.println(uuid.toString().replaceAll(-,));//获取一个版本3(基于名称)根据指定的字节数组的UUID。byte[] nbyte  {1, 2, 3};UUID uuidFromBytes  UUID.nameUUIDFromBytes(nbyte);System.out.println(uuidFromBytes.toString().replaceAll(-,));}优点属于本地解决方案无网络消耗 
缺点 
不易于存储UUID太长16字节128位通常以36长度的字符串表示很多场景不适用MAC 地址提供了唯一性的保证但也带来安全风险最糟的是它是字符串形式占用空间大查询性能低无法保证趋势递增ID作为主键时在特定的环境会存在一些问题比如做DB主键的场景下UUID就非常不适用 MySQL官方有明确的建议主键要尽量越短越好36个字符长度的UUID不符合要求对MySQL索引不利如果作为数据库主键在InnoDB引擎下UUID的无序性可能会引起数据位置频繁变动严重影响性能  
2、数据库自增 用的最多-但不适合做分布式ID 这种方式也是我们用的最多的方式通常使用数据库自增不同数据库自增命令可能不同 以MySQL为例直接设置AUTO_INCREMENT就可以使主键自增。 优点 
单体项目实现简单命令即可设置成本小有DBA专业维护生成的ID有序可以实现一些对ID有特殊要求的业务。 
缺点 
不同数据库语法或实现不同数据库迁移的时候需要处理在单个数据库或读写分离或一主多从多情况下只有一个主库可以生成ID有单点故障的风险在性能达不到要求的情况下比较难以扩展数据迁移或者系统数据合并比较麻烦分库分表时会比较麻烦ID发号性能瓶颈限制在单台MySQL的读写性能 
3、Redis 生成ID 可用 
1、原因 1、数据库自增ID是有序增长的很容易就被人猜到比如我现在下一单看到的订单ID为999那么就知道你的系统里最多只有999单 2、这种自增ID没有意义而且不同业务的自增ID是重合的对于信息区分度很低而且考虑到多业务交互和用户端展示也都是不合适的想想看要是你在某宝下单订单ID是999或者在对接别人订单系统时给你的订单ID是999是不是很奇怪。 3、当存在分库分表设计时,自增ID的操作就会导致无法实现唯一性 那应该如何通过Redis来设计一个分布式全局唯一ID生成工具 用户下单调用下单逻辑先进行业务逻辑处理然后携带订单ID标识通过分布式全局唯一ID工具获取一个唯一的订单ID这个订单ID标识就是用于区分业务的获取到订单ID后将数据组装入库分布式全局唯一ID工具可以做成一个内嵌的utils也可以封装成一个独立的jar还可以做成一个分布式全局唯一ID生成服务供其它业务服务调用。 使用 Redis 计数器实现 
Redis的String结构提供了计数器自增功能类似Java中的原子类还要优于Java的原子类 因为Redis是单线程执行的缓存读写本身就是线程安全的也不用进行原子类的乐观锁操作 每一次获取分布式全局唯一ID时就将自增序列加1。 
# 给key为GENERATEID:NO的value自增1如果这key不存在则会添加到Redis中并且设置value为1
## GENERATEIDkey前缀
## NO订单ID标识
127.0.0.1:6379 incr GENERATEID:NO
(integer) 1使用 Redis Hash结构实现 
Redis Hash结构中的每一个field也可以进行自增操作可以用一个Hash结构存储所有的标识信息和自增序列方便管理比较适合并发不高的小项目所有服务都是用的一个Redis如果并发较高就不合适了毕竟Redis操作普通String结构肯定比操作Hash结构快。 
# 给key为GENERATEIDfield为no的value自增1如果这key不存在则会添加到Redis中并且设置value为1
## GENERATEID分布式全局唯一ID Hash key
## NOHash结构中的field
127.0.0.1:6379 hincrby GENERATEID NO 1
(integer) 12、通过代码实现分布式全局唯一ID工具 正式使用 这里使用Redis 计数器实现自增序列以天为单位存储 在实际业务中比如生成订单编号组成规则都类似NO1699631999000-1业务标识key当前时间戳自增序列这个规则可以自己定义保证最终生成的订单编号不重复即可不建议直接一个自增序列干到底。 订单编号这类型的数据都是有长度限制的或者是要求生成20字符的订单编号如果增长的过长反而不好处理。 3、编写获取工具 
Component
public class RedisGenerateIDUtils {Resourceprivate RedisTemplateString, Object redisTemplate;// key前缀private String PREFIX  GENERATEID:;/*** 获取全局唯一ID* param key 业务标识key*/public String generateId(String key) {// 获取对应业务自增序列Long incr  getIncr(key);// 组装最后的结果这里可以根据需要自己定义这里是按照业务标识key当前时间戳自增序列进行组装String resultID  key  System.currentTimeMillis()  -  incr;return resultID;}/*** 获取对应业务自增序列*/private Long getIncr(String key) {String cacheKey  getCacheKey(key);Long increment  0L;// 判断Redis中是否存在这个自增序列如果不存在添加一个序列并且设置一个过期时间if (!redisTemplate.hasKey(cacheKey)) {// 这里存在线程安全问题需要加分布式锁这里做简单实现String lockKey  cacheKey  _LOCK;// 设置分布式锁boolean lock  redisTemplate.opsForValue().setIfAbsent(lockKey, 1, 30, TimeUnit.SECONDS);if (!lock) {// 如果没有拿到锁进行自旋return getIncr(key);}increment  redisTemplate.opsForValue().increment(cacheKey);// 我这里设置24小时可以根据实际情况设置当前时间到当天结束时间的插值redisTemplate.expire(cacheKey, 24, TimeUnit.HOURS);// 释放锁redisTemplate.delete(lockKey);} else {increment  redisTemplate.opsForValue().increment(cacheKey);}return increment;}/*** 组装缓存key*/private String getCacheKey(String key) {return PREFIX  key  :  getYYYYMMDD();}/*** 获取当前YYYYMMDD格式年月日*/private String getYYYYMMDD() {LocalDate currentDate  LocalDate.now();int year  currentDate.getYear();int month  currentDate.getMonthValue();int day  currentDate.getDayOfMonth();return   year  month  day;}
} 
4、测试获取工具 
RunWith(SpringRunner.class)
SpringBootTest(classes  RedisUniqueIdDemoApplication.class)
class RedisUniqueIdDemoApplicationTests {Resourceprivate RedisGenerateIDUtils redisGenerateIDUtils;Testpublic void test() throws InterruptedException {// 定义一个线程池 设置核心线程数和最大线程数都为100队列根据需要设置ThreadPoolExecutor executor  new ThreadPoolExecutor(100, 100, 10, TimeUnit.SECONDS, new LinkedBlockingQueue(10000));CountDownLatch countDownLatch  new CountDownLatch(10000);long beginTime  System.currentTimeMillis();// 获取10000个全局唯一ID 看看是否有重复CopyOnWriteArraySetString ids  new CopyOnWriteArraySet();for (int i  0; i  10000; i) {executor.execute(() - {// 获取全局唯一IDlong beginTime02  System.currentTimeMillis();String orderNo  redisGenerateIDUtils.generateId(NO);System.out.println(orderNo);System.out.println(获取单个ID耗时 time  (System.currentTimeMillis() - beginTime02));if (ids.contains(orderNo)) {System.out.println(重复ID  orderNo);} else {ids.add(orderNo);}countDownLatch.countDown();});}countDownLatch.await();// 打印获取到的全局唯一ID集合数量System.out.println(获取到全局唯一ID count  ids.size());System.out.println(耗时毫秒 time  (System.currentTimeMillis() - beginTime));}
} 
知识小贴士关于countdownlatch 这是在模拟100个请求并发获取1w个后再结束的操作所涉及的 多线程相关 知识点和 获取分布式唯一id 没有直接关系哦 countdownlatch名为信号枪主要的作用是同步协调在多线程的等待于唤醒问题 我们如果没有CountDownLatch 那么由于程序是异步的当异步程序没有执行完时主线程就已经执行完了然后我们期望的是分线程全部走完之后主线程再走所以我们此时需要使用到CountDownLatch CountDownLatch 中有两个最重要的方法 countDownawait await 方法 是阻塞方法我们担心分线程没有执行完时main线程就先执行所以使用await可以让main线程阻塞那么什么时候main线程不再阻塞呢当CountDownLatch 内部维护的 变量变为0时就不再阻塞直接放行那么什么时候CountDownLatch 维护的变量变为0 呢我们只需要调用一次countDown 内部变量就减少1我们让分线程和变量绑定 执行完一个分线程就减少一个变量当分线程全部走完CountDownLatch 维护的变量就是0此时await就不再阻塞统计出来的时间也就是所有分线程执行完后的时间。 5、总结 
通过线程池 我们模拟了100个请求同时去获取全局唯一ID是没问题的 而且获取单个ID耗时在10-20毫秒左右一般的业务已经完全够用这个耗时也要看Redis性能和项目配置决定的。 
4、雪花算法SnowFlake可用 
1.雪花算法概念 
雪花算法Snowflake是一种生成唯一ID的算法主要应用于分布式系统中。它可以在不依赖于数据库等其他存储设施的情况下生成全局唯一的ID。 
雪花算法生成的ID为64位整数二进制全是0和1组成具体的格式如下 1位符号位 二进制数据中首位表示正负这里是0不可变41位的时间戳 41位用来标识时间戳最大值可容纳是2的41次方( 2199023255552 )换算转成时间的话就是可以用69年从1970年开始算所以建议在设置起始时间戳时请用上线的时间这样子就可以保证该系统69年的唯一id获取。10位的机器位 机器位最大为10位一般做法是5位用于机房id的标识5位用于机器id的标识。这样无论是机房和机器都可以最大容纳2的五次方减131的数量。不过实际使用时可以根据实际情况进行调整因为机房数量一般也到不了31就是机器数量到达31的也不多。所以可以根据实际情况来进行调整机器位10个bit的分配。12位的随机数 12位的随机数最大可以表示2的12次方减1的数据4095所以也就是说最大我们可以在1ms内产生4095个id时间戳位是ms那么1s内就是4095000≈400W。而且这是单台机器上的每秒可产生的不重复id如果横向扩展机器的话这个值还会更大。所以12位的随机数位是肯定够用的了当然真正使用时是不能使用随机数的而是应该进行整数的自增这样才能保证不重复。 实际情况下我们是需要把这个二进制转成十进制来作为id使用的哦 
2.雪花算法的缺点 
由于Snowflake算法生成的ID包含时间戳等信息因此在使用时需要保证系统时间的准确性。 如果系统时间发生回拨或者误差较大可能会导致生成的ID出现重复或者乱序的问题。 
方式一自定义的雪花算法 该工具类已做了回拨处理 注意注意注意以下代码亲测过并有详细的注释解说直接拿走不谢 public class SnowFlakeUtil {/*** 初始时间戳可以根据业务需求更改时间戳*/private final long twepoch  11681452025134L;/*** 机器ID所占位数长度为5位*/private final long workerIdBits  5L;/*** 数据标识ID所占位数长度位5位*/private final long datacenterIdBits  5L;/*** 支持的最大机器id结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)*/private final long maxWorkerId  -1L ^ (-1L  workerIdBits);/*** 支持的最大数据标识id结果是31*/private final long maxDatacenterId  -1L ^ (-1L  datacenterIdBits);/*** 序列在id中占的位数*/private final long sequenceBits  12L;/*** 工作机器ID向左移12位*/private final long workerIdShift  sequenceBits;/*** 数据标识id向左移17位(125)*/private final long dataCenterIdShift  sequenceBits  workerIdBits;/*** 时间截向左移22位(5512)*/private final long timestampLeftShift  sequenceBits  workerIdBits  datacenterIdBits;/*** 序列号最大值; 生成序列的掩码这里为4095 (0b1111111111110xfff4095)*/private final long sequenceMask  -1L ^ (-1L  sequenceBits);/*** 工作机器ID(0~31)2进制5位  32位减掉1位 31个*/private volatile long workerId;/*** 数据中心ID(0~31)2进制5位  32位减掉1位 31个*/private volatile long datacenterId;/*** 毫秒内序列(0~4095)2进制12位 4096 - 1  4095个*/private volatile long sequence  0L;/*** 上次时间戳初始值为负数*/private volatile long lastTimestamp  -1L;// Constructors/*** 有参构造* param workerId 工作机器ID(0~31)* param datacenterId 数据中心ID(0~31)* param sequence 毫秒内序列(0~4095)*/public SnowFlakeUtil(long workerId, long datacenterId, long sequence){// sanity check for workerIdif (workerId  maxWorkerId || workerId  0) {throw new IllegalArgumentException(String.format(worker Id cant be greater than %d or less than 0,maxWorkerId));}if (datacenterId  maxDatacenterId || datacenterId  0) {throw new IllegalArgumentException(String.format(datacenter Id cant be greater than %d or less than 0,maxDatacenterId));}System.out.printf(worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d,timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);this.workerId  workerId;this.datacenterId  datacenterId;this.sequence  sequence;}// Methods/*** 获得下一个ID (该方法是线程安全的)*  如果一个线程反复获取Synchronized锁那么synchronized锁将变成偏向锁。* return 生成的ID*/public synchronized long nextId() {// 获取当前时间的时间戳单位毫秒long timestamp  timeGen();// 获取当前时间戳如果小于上次时间戳则表示时间戳获取出现异常if (timestamp  lastTimestamp) {System.err.printf(当前时间戳不能小于上次时间戳上次时间戳为 %d., lastTimestamp);throw new RuntimeException(String.format(当前时间戳不能小于上次时间戳生成ID失败. 时间戳差值 %d milliseconds,lastTimestamp - timestamp));}// 获取当前时间戳如果等于上次时间戳同一毫秒内则在序列号加一否则序列号赋值为0从0开始。if (lastTimestamp  timestamp) {/* 逻辑意思是说一个毫秒内最多只能有4096个数字无论你传递多少进来这个位运算保证始终就是在4096这个范围内避免你自己传递个sequence超过了4096这个范围 */// sequence毫秒内序列(0~4095);  sequenceMask: 序列号最大值;sequence  (sequence  1)  sequenceMask;/* 逻辑当某一毫秒的时间产生的id数 超过4095系统会进入等待直到下一毫秒系统继续产生ID */if (sequence  0) {timestamp  tilNextMillis(lastTimestamp);}} else {sequence  0;}// 将上次时间戳值刷新逻辑记录一下最近一次生成id的时间戳单位是毫秒lastTimestamp  timestamp;/* 核心逻辑生成一个64bit的id先将当前时间戳左移放到41 bit那儿将机房id左移放到5 bit那儿将机器id左移放到5 bit那儿将序号放最后12 bit最后拼接起来成一个64 bit的二进制数字转换成10进制就是个long型 *//** 返回结果* (timestamp - twepoch)  timestampLeftShift) 表示将时间戳减去初始时间戳再左移相应位数* (datacenterId  datacenterIdShift) 表示将数据id左移相应位数* (workerId  workerIdShift) 表示将工作id左移相应位数* | 是按位或运算符例如x | y只有当xy不为0的时候结果才为0其它情况结果都为1。* 因为个部分只有相应位上的值有意义其它位上都是0所以将各部分的值进行 | 运算就能得到最终拼接好的id*/return ((timestamp - twepoch)  timestampLeftShift) |(datacenterId  dataCenterIdShift) |(workerId  workerIdShift) |sequence;}/*** 上次时间戳与当前时间戳进行比较* 逻辑当某一毫秒的时间产生的id数 超过4095系统会进入等待直到下一毫秒系统继续产生ID* param lastTimestamp 上次时间戳* return 若当前时间戳小于等于上次时间戳时间回拨了则返回最新当前时间戳 否则返回当前时间戳*/private long tilNextMillis(long lastTimestamp) {long timestamp  timeGen();while (timestamp  lastTimestamp) {timestamp  timeGen();}return timestamp;}/*** 获取系统时间戳* return 当前时间的时间戳 14位*/private long timeGen(){return System.currentTimeMillis();}public static void main(String[] args) {SnowFlakeUtil snowFlakeUtil  new SnowFlakeUtil(1,1,0);System.out.println(snowFlakeUtil.timeGen());for (int i  0; i  100; i) {System.out.println(雪花算法生成第【(i1)】个ID: snowFlakeUtil.nextId());}}}以上代码执行结果 
雪花算法生成第【1】个ID:-5049534853385416704
雪花算法生成第【2】个ID:-5049534853385416703
雪花算法生成第【3】个ID:-5049534853385416702
雪花算法生成第【4】个ID:-5049534853385416701
雪花算法生成第【5】个ID:-5049534853385416700
雪花算法生成第【6】个ID:-5049534853385416699
雪花算法生成第【7】个ID:-5049534853385416698
雪花算法生成第【8】个ID:-5049534853385416697
雪花算法生成第【9】个ID:-5049534853385416696
雪花算法生成第【10】个ID:-5049534853385416695
……
……
…… 之后的结果就不一一展示了以上代码在遇到时间回拨的情况下仍然能够获取到唯一的ID。 在常规的时间回拨场景下如NTP同步导致的轻微时间调整这段代码是足够健壮的。 方式二基于hutool工具类 
第一步引入hutool工具依赖包 
!-- hutool工具类 --
dependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion5.3.1/version
/dependency第二步Springboot整合具体代码实现 
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.IdUtil;import javax.annotation.PostConstruct;/*** SpringtBoot整合雪花算法 (基于hutool工具类)*/
public class SnowFlakeHutoolTestController {/*** 工作机器ID(0~31)2进制5位  32位减掉1位 31个*/private long workerId  0;/*** 数据中心ID(0~31)2进制5位  32位减掉1位 31个*/private long datacenterId  1;/*** 雪花算法对象*/private Snowflake snowFlake  IdUtil.createSnowflake(workerId, datacenterId);PostConstructpublic void init() {try {// 将网络ip转换成longworkerId  NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());} catch (Exception e) {e.printStackTrace();}}/*** 获取雪花ID默认使用网络IP作为工作机器ID* return ID*/public synchronized long snowflakeId() {return this.snowFlake.nextId();}/*** 获取雪花ID* param workerId 工作机器ID* param datacenterId 数据中心ID* return ID*/public synchronized long snowflakeId(long workerId, long datacenterId) {Snowflake snowflake  IdUtil.createSnowflake(workerId, datacenterId);return snowflake.nextId();}public static void main(String[] args) {SnowFlakeHutoolTestController snowFlakeDemo  new SnowFlakeHutoolTestController();for (int i  0; i  20; i) {int finalI  i;new Thread(() - {System.out.println(雪花算法生成第【(finalI 1)】个ID: snowFlakeDemo.snowflakeId());}, String.valueOf(i)).start();}}}以上代码执行结果 
雪花算法生成第【2】个ID:1646777064113700865
雪花算法生成第【5】个ID:1646777064113700868
雪花算法生成第【3】个ID:1646777064113700866
雪花算法生成第【4】个ID:1646777064113700867
雪花算法生成第【1】个ID:1646777064113700864
雪花算法生成第【11】个ID:1646777064113700873
雪花算法生成第【10】个ID:1646777064113700872
雪花算法生成第【8】个ID:1646777064113700871
雪花算法生成第【7】个ID:1646777064113700870
雪花算法生成第【6】个ID:1646777064113700869
雪花算法生成第【16】个ID:1646777064113700877
雪花算法生成第【13】个ID:1646777064113700876
雪花算法生成第【12】个ID:1646777064113700875
雪花算法生成第【9】个ID:1646777064113700874
雪花算法生成第【17】个ID:1646777064113700881
雪花算法生成第【19】个ID:1646777064113700880
雪花算法生成第【15】个ID:1646777064113700879
雪花算法生成第【14】个ID:1646777064113700878
雪花算法生成第【20】个ID:1646777064113700883
雪花算法生成第【18】个ID:1646777064113700882方式三使用 百度 Uidgenerator基于SnowFlake算法改造的 
待记录 
方式四使用 美团Leaf基于SnowFlake算法改造的 
待记录 
三、前端直接使用发生精度丢失 
如果前端直接使用服务端生成的long 类型 id会发生精度丢失的问题因为 JS 中Number是16位的指的是十进制的数字 而雪花算法计算出来最长的数字是19位的这个时候需要用 String 作为中间转换输出到前端即可。 
参考文章 
【1】分布式全局唯一ID生成方案附源码 【2】redis实现分布式全局唯一id 【3】使用 Redis 实现生成分布式全局唯一ID使用SpringBoot环境实现 【4】分布式Id生成之雪花算法SnowFlake 【5】SpringBoot实战设备唯一ID生成【雪花算法、分布式应用】 文章转载自: http://www.morning.nrxsl.cn.gov.cn.nrxsl.cn http://www.morning.ywgrr.cn.gov.cn.ywgrr.cn http://www.morning.kyjpg.cn.gov.cn.kyjpg.cn http://www.morning.ypbp.cn.gov.cn.ypbp.cn http://www.morning.pclgj.cn.gov.cn.pclgj.cn http://www.morning.mzwqt.cn.gov.cn.mzwqt.cn http://www.morning.knlgk.cn.gov.cn.knlgk.cn http://www.morning.sjmxh.cn.gov.cn.sjmxh.cn http://www.morning.tyjnr.cn.gov.cn.tyjnr.cn http://www.morning.rrhfy.cn.gov.cn.rrhfy.cn http://www.morning.kxbdm.cn.gov.cn.kxbdm.cn http://www.morning.jkpnm.cn.gov.cn.jkpnm.cn http://www.morning.qbrdg.cn.gov.cn.qbrdg.cn http://www.morning.ahlart.com.gov.cn.ahlart.com http://www.morning.tjwfk.cn.gov.cn.tjwfk.cn http://www.morning.ffdyy.cn.gov.cn.ffdyy.cn http://www.morning.phxdc.cn.gov.cn.phxdc.cn http://www.morning.fllfz.cn.gov.cn.fllfz.cn http://www.morning.wsxly.cn.gov.cn.wsxly.cn http://www.morning.jwrcz.cn.gov.cn.jwrcz.cn http://www.morning.bpmth.cn.gov.cn.bpmth.cn http://www.morning.wmfr.cn.gov.cn.wmfr.cn http://www.morning.ybgcn.cn.gov.cn.ybgcn.cn http://www.morning.llqky.cn.gov.cn.llqky.cn http://www.morning.pphgl.cn.gov.cn.pphgl.cn http://www.morning.ohmyjiu.com.gov.cn.ohmyjiu.com http://www.morning.wjjxr.cn.gov.cn.wjjxr.cn http://www.morning.ctlbf.cn.gov.cn.ctlbf.cn http://www.morning.htbsk.cn.gov.cn.htbsk.cn http://www.morning.bxhch.cn.gov.cn.bxhch.cn http://www.morning.qflwp.cn.gov.cn.qflwp.cn http://www.morning.dhpjq.cn.gov.cn.dhpjq.cn http://www.morning.lwdzt.cn.gov.cn.lwdzt.cn http://www.morning.ndlww.cn.gov.cn.ndlww.cn http://www.morning.bfycr.cn.gov.cn.bfycr.cn http://www.morning.nyqxy.cn.gov.cn.nyqxy.cn http://www.morning.ggjlm.cn.gov.cn.ggjlm.cn http://www.morning.jqllx.cn.gov.cn.jqllx.cn http://www.morning.hfrbt.cn.gov.cn.hfrbt.cn http://www.morning.syxmx.cn.gov.cn.syxmx.cn http://www.morning.ho-use.cn.gov.cn.ho-use.cn http://www.morning.jlxqx.cn.gov.cn.jlxqx.cn http://www.morning.mrfnj.cn.gov.cn.mrfnj.cn http://www.morning.lfmwt.cn.gov.cn.lfmwt.cn http://www.morning.rpstb.cn.gov.cn.rpstb.cn http://www.morning.sbwr.cn.gov.cn.sbwr.cn http://www.morning.pkmcr.cn.gov.cn.pkmcr.cn http://www.morning.ykrkq.cn.gov.cn.ykrkq.cn http://www.morning.ztqj.cn.gov.cn.ztqj.cn http://www.morning.grxyx.cn.gov.cn.grxyx.cn http://www.morning.fmqw.cn.gov.cn.fmqw.cn http://www.morning.kxqpm.cn.gov.cn.kxqpm.cn http://www.morning.dbfp.cn.gov.cn.dbfp.cn http://www.morning.hyxwh.cn.gov.cn.hyxwh.cn http://www.morning.nxstj.cn.gov.cn.nxstj.cn http://www.morning.qxdrw.cn.gov.cn.qxdrw.cn http://www.morning.nwnbq.cn.gov.cn.nwnbq.cn http://www.morning.cfpq.cn.gov.cn.cfpq.cn http://www.morning.llsrg.cn.gov.cn.llsrg.cn http://www.morning.fewhope.com.gov.cn.fewhope.com http://www.morning.ydmml.cn.gov.cn.ydmml.cn http://www.morning.hjssh.cn.gov.cn.hjssh.cn http://www.morning.pmsl.cn.gov.cn.pmsl.cn http://www.morning.swwpl.cn.gov.cn.swwpl.cn http://www.morning.dtrz.cn.gov.cn.dtrz.cn http://www.morning.bbyqz.cn.gov.cn.bbyqz.cn http://www.morning.rwcw.cn.gov.cn.rwcw.cn http://www.morning.gqfbl.cn.gov.cn.gqfbl.cn http://www.morning.nzhzt.cn.gov.cn.nzhzt.cn http://www.morning.cfrz.cn.gov.cn.cfrz.cn http://www.morning.routalr.cn.gov.cn.routalr.cn http://www.morning.yhjrc.cn.gov.cn.yhjrc.cn http://www.morning.cpgdy.cn.gov.cn.cpgdy.cn http://www.morning.nqrfd.cn.gov.cn.nqrfd.cn http://www.morning.mmtjk.cn.gov.cn.mmtjk.cn http://www.morning.spxsm.cn.gov.cn.spxsm.cn http://www.morning.slwqt.cn.gov.cn.slwqt.cn http://www.morning.rswtz.cn.gov.cn.rswtz.cn http://www.morning.coffeedelsol.com.gov.cn.coffeedelsol.com http://www.morning.qsy37.cn.gov.cn.qsy37.cn