原文地址
前言
我们在开发中经常会用到行政区划,尤其是对于B端业务的用户信息管理,所以我们需要有个服务或者数据表可以维护一个对于系统内所有服务统一的行政区划结构,用于减少服务之间沟通成本,减少异常数据,提高维护效率
方案
首先,我们需要拿到行政区划数据,如果需要比较详细或者比较新的行政区划数据,建议还是去官网拿。这个给到两个网站中华人民共和国民政部以及国家统计局,直接在检索栏搜索行政区划
,我这里没有直接给行政区划页面网址的原因是,他们没有一个latest/division.html
这样的网址,还是直接检索比较省心
如果不追求极致的及时性和准确性,那么我可以直接从Gihub
上拿好哥哥们已经整理好的资源,比如province-city-china或者China_Province_City这种
拿到Json
数据后,我们需要根据自己的数据表方案进行数据注入,这里简单写个数据表结构,以level.json为例,我们在postgresql
下的设计如下
CREATE TABLE public.admin_division (
division_code varchar(8) NOT NULL,
full_name varchar(50) NOT NULL,
division_level int4 NOT NULL,
division_name varchar(20) NOT NULL,
province varchar(20) NOT NULL,
city varchar(20) NULL,
district varchar(20) NULL,
CONSTRAINT division_code PRIMARY KEY (division_code)
);
以Java
为例,我们将Json
解析,写入数据库
//参数对象
@Data
public class DivisionParam {
private String code;
private String name;
private String province;
private String city;
private String area;
private List<DivisionParam> children;
}
//数据表对象
@Data
public class AdminDivision {
/**
* code
*/
@Id
private String divisionCode;
/**
* name
*/
private String divisionName;
/**
* province + city + district
*/
private String fullName;
/**
* province 0 city 1 district 2
*/
private Integer divisionLevel;
/**
* province
*/
private String province;
/**
* city
*/
private String city;
/**
* district
*/
private String district;
}
插入
//controller
@RestController
@RequestMapping("/division")
public class AdminDivisionController {
@Resource
private IAdminDivisionService adminDivisionService;
@PostMapping("/reset")
public ResultObj<Object> reset(@RequestBody List<DivisionParam> param) {
adminDivisionService.reset(param);
return ResultObj.success();
}
}
//serviceImpl
@Service
@Slf4j
public class AdminAdminDivisionImpl implements IAdminDivisionService {
@Resource
private AdminDivisionMapper adminDivisionMapper;
/**
* reset division code map
*
* @param param divisionList
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void reset(List<DivisionParam> param) {
if (CollectionUtils.isEmpty(param)) {
return;
}
//todo delete all
//correct
List<AdminDivision> adminDivisionList = new ArrayList<>();
correctDivision(null, null, null, adminDivisionList, param);
//todo insert
}
private void correctDivision(String province, String city, String district,
List<AdminDivision> adminDivisionList,
List<DivisionParam> currentList) {
if (CollectionUtils.isEmpty(currentList)) {
return;
}
for (DivisionParam division : currentList) {
AdminDivision adminDivision = new AdminDivision();
adminDivision.setDivisionCode(division.getCode());
adminDivision.setDivisionName(division.getName());
int level = DivisionLevelEnum.PROVINCE;
if (!ObjectUtils.isEmpty(division.getCity())) {
++level;
}
if (!ObjectUtils.isEmpty(division.getArea())) {
++level;
}
adminDivision.setDivisionLevel(level);
switch (level) {
case DivisionLevelEnum.DISTRICT -> district = division.getName();
case DivisionLevelEnum.CITY -> city = division.getName();
default -> province = division.getName();
}
adminDivision.setProvince(province);
adminDivision.setCity(city);
adminDivision.setDistrict(district);
adminDivision.setFullName(Stream.of(province, city, district)
.filter(Objects::nonNull).collect(Collectors.joining()));
adminDivisionList.add(adminDivision);
if (CollectionUtils.isEmpty(division.getChildren())) {
continue;
}
correctDivision(province, city, district, adminDivisionList, division.getChildren());
}
}
}