sql
CREATE TABLE `pc_mdc_address` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`pid` bigint(50) NOT NULL COMMENT '父ID',
`city_code` varchar(50) DEFAULT '' COMMENT '城市编码',
`ad_code` varchar(50) DEFAULT '' COMMENT '区域编码',
`name` varchar(50) NOT NULL DEFAULT '' COMMENT '地址名称',
`level` tinyint(1) NOT NULL COMMENT '级别(省市区县)',
`polyline` varchar(255) DEFAULT '' COMMENT '行政区边界坐标点',
`center` varchar(255) DEFAULT '' COMMENT '城市中心点',
PRIMARY KEY (`id`),
KEY `I_PARENT_ID` (`pid`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=367047247247843329 DEFAULT CHARSET=utf8;
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = Application.class)
public class AddressTest {
@Resource
private PcMdcAddressMapper pcMdcAddressMapper;
public String getCityData() throws IOException {
String result = null;
HttpPost httpPost = new HttpPost("http://restapi.amap.com/v3/config/district");
List<NameValuePair> nvps = new ArrayList<>();
nvps.add(new BasicNameValuePair("key", "3c831a5f6d3fbf3820e067f7********"));
nvps.add(new BasicNameValuePair("keywords", null));
nvps.add(new BasicNameValuePair("subdistrict", "3"));
nvps.add(new BasicNameValuePair("extensions", "base"));
CloseableHttpClient client = HttpClients.createDefault();
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
httpPost.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
CloseableHttpResponse response = client.execute(httpPost);
//获取结果实体
HttpEntity entity = response.getEntity();
if (entity != null) {
//按指定编码转换结果实体为String类型
result = EntityUtils.toString(entity, "utf-8");
}
return result;
}
@Test
public void saveAddress() throws IOException {
String json = getCityData();
Result result = JSON.parseObject(json, Result.class);
System.out.println(result);
List<Districts> districts = result.getDistricts();
// 生成城市数据
for (Districts district : districts) {
buildAddressData(district, 0L);
}
}
final SnowflakeIdWorker idg = new SnowflakeIdWorker(2, 31);
private void buildAddressData(Districts district, Long pid) {
PcMdcAddress address = new PcMdcAddress();
BeanUtils.copyProperties(district, address, "level");
address.setAdCode(district.getAdcode());
address.setCityCode(district.getCitycode());
String level = district.getLevel();
if ("country".equals(level)) {
address.setLevel(0);
} else if ("province".equals(level)) {
address.setLevel(1);
} else if ("city".equals(level)) {
address.setLevel(2);
} else if ("district".equals(level)) {
address.setLevel(3);
} else if ("street".equals(level)) {
address.setLevel(4);
} else {
throw new RuntimeException("数据异常");
}
long id = idg.nextId();
address.setId(id);
address.setPid(pid);
pcMdcAddressMapper.insert(address);
System.out.println(district.getCitycode() + "," + district.getName());
List<Districts> districts1 = district.getDistricts();
for (Districts districts2 : districts1) {
buildAddressData(districts2, id);
}
}
数据实体类
@Data
public class Districts {
private String citycode;
private String adcode;
private String name;
private String polyline;
private String center;
private String level;
/**
* The Districts.
*/
List<Districts> districts;
}
@Data
public class Result {
private String status;
private String info;
private String infocode;
private String count;
private Suggestion suggestion;
private List<Districts> districts;
}
@Data
public class Suggestion {
private String[] keywords;
private String[] cities;
}
雪花算法
package tk.mybatis.springboot.util;
/**
* The class Snowflake id worker.
* Created by paascloud.net@gmail.com
*/
public class SnowflakeIdWorker {
// ==============================Fields===========================================
/**
* 开始时间截 (2015-01-01)
*/
private final long twepoch = 1420041600000L;
/**
* 机器id所占的位数
*/
private final long workerIdBits = 5L;
/**
* 数据标识id所占的位数
*/
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位(12+5)
*/
private final long datacenterIdShift = sequenceBits + workerIdBits;
/**
* 时间截向左移22位(5+5+12)
*/
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
/**
* 生成序列的掩码, 这里为4095 (0b111111111111=0xfff=4095)
*/
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
/**
* 工作机器ID(0~31)
*/
private long workerId;
/**
* 数据中心ID(0~31)
*/
private long datacenterId;
/**
* 毫秒内序列(0~4095)
*/
private long sequence = 0L;
/**
* 上次生成ID的时间截
*/
private long lastTimestamp = -1L;
//==============================Constructors=====================================
/**
* 构造函数
*
* @param workerId 工作ID (0~31)
* @param datacenterId 数据中心ID (0~31)
*/
public SnowflakeIdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
// ==============================Methods==========================================
/**
* 获得下一个ID (该方法是线程安全的)
*
* @return SnowflakeId long
*/
public synchronized long nextId() {
long timestamp = timeGen();
//如果当前时间小于上一次ID生成的时间戳, 说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp) {
throw new RuntimeException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
//如果是同一时间生成的, 则进行毫秒内序列
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
//毫秒内序列溢出
if (sequence == 0) {
//阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}
//时间戳改变, 毫秒内序列重置
else {
sequence = 0L;
}
//上次生成ID的时间截
lastTimestamp = timestamp;
//移位并通过或运算拼到一起组成64位的ID
return ((timestamp - twepoch) << timestampLeftShift) //
| (datacenterId << datacenterIdShift) //
| (workerId << workerIdShift) //
| sequence;
}
/**
* 阻塞到下一个毫秒, 直到获得新的时间戳
*
* @param lastTimestamp 上次生成ID的时间截
*
* @return 当前时间戳
*/
private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 返回以毫秒为单位的当前时间
*
* @return 当前时间(毫秒)
*/
private long timeGen() {
return System.currentTimeMillis();
}
}
数据库对应实体
@Data
@Table(name = "pc_mdc_address")
public class PcMdcAddress {
/**
* ID
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 地址名称
*/
private String name;
/**
* 父ID
*/
private Long pid;
/**
* 城市编码
*/
@Column(name = "city_code")
private String cityCode;
/**
* 级别(省市区县)
*/
private Integer level;
/**
* 区域编码
*/
@Column(name = "ad_code")
private String adCode;
/**
* 行政区边界坐标点
*/
private String polyline;
/**
* 城市中心点
*/
private String center;
}
Mapper
public interface StudentMapper extends MyMapper<Student> {
}
Mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="tk.mybatis.springboot.mapper.PcMdcAddressMapper" >
<resultMap id="BaseResultMap" type="tk.mybatis.springboot.model.PcMdcAddress" >
<!--
WARNING - @mbg.generated
-->
<id column="id" property="id" jdbcType="BIGINT" />
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="pid" property="pid" jdbcType="BIGINT" />
<result column="city_code" property="cityCode" jdbcType="VARCHAR" />
<result column="level" property="level" jdbcType="INTEGER" />
<result column="ad_code" property="adCode" jdbcType="VARCHAR" />
<result column="polyline" property="polyline" jdbcType="VARCHAR" />
<result column="center" property="center" jdbcType="VARCHAR" />
</resultMap>
</mapper>
update pc_mdc_address set city_code='' where city_code='[]';
留个草稿, 以备不时之需, 代码有点小问题 就是一个空数组的问题