This commit is contained in:
ran.shang
2025-06-11 09:42:13 +08:00
commit 7e38b8d971
1935 changed files with 132836 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
package com.newyetai.usercenter.district.constants;
/**
* @author czy
* @date 2021-07-08
*/
public interface DistrictConstants {
Long DEFAULT_DISTRICT_ID = 0l;
String CACHE_KEY_DISTRICT_ID = "#districtId";
interface CacheNames {
/** 省 **/
String DISTRICT_PROVINCE = "district:province";
/** 市 **/
String DISTRICT_CITY = "district:city";
/** 区 **/
String DISTRICT_AREA = "district:area";
/** 街 **/
String DISTRICT_STREET = "district:street";
}
}

View File

@@ -0,0 +1,61 @@
package com.newyetai.usercenter.district.controller;
import com.newyetai.common.AlitaResult;
import com.newyetai.usercenter.district.constants.DistrictConstants;
import com.newyetai.usercenter.district.dto.DistrictDTO;
import com.newyetai.usercenter.district.dto.DistrictTreeQueryDTO;
import com.newyetai.usercenter.district.entity.District;
import com.newyetai.usercenter.district.service.IDistrictService;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
* 省份城市 前端控制器
* </p>
*
* @author Carlye
* @since 2021-01-25
*/
@RestController
@RequestMapping("/anon/district")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class DistrictController {
private final IDistrictService districtService;
@GetMapping("/tree")
@ApiOperation("创建用户附件")
public AlitaResult<List<DistrictDTO>> tree(DistrictTreeQueryDTO queryDTO) {
return AlitaResult.success(districtService.treeList(queryDTO));
}
@GetMapping("/list")
@ApiOperation("获取指定Id下的城市列表(不传就默认查省列表)")
public AlitaResult<List<DistrictDTO>> loadDataById(@RequestParam(value = "districtId", required = false) Long districtId) {
if (districtId == null) {
districtId = DistrictConstants.DEFAULT_DISTRICT_ID;
}
return AlitaResult.success(districtService.queryListById(districtId));
}
@GetMapping("/all")
@ApiOperation("获取全部")
public AlitaResult<List<District>> all(@RequestParam(value = "level") Integer level) {
return AlitaResult.success(districtService.all(level));
}
}

View File

@@ -0,0 +1,23 @@
package com.newyetai.usercenter.district.dao;
import com.newyetai.usercenter.district.dto.DistrictDTO;
import com.newyetai.usercenter.district.entity.District;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
/**
* <p>
* 省份城市 Mapper 接口
* </p>
*
* @author Carlye
* @since 2021-01-25
*/
public interface DistrictMapper extends BaseMapper<District> {
List<DistrictDTO> queryById(Long districtId);
String queryNameByCode(@Param("codes") List<String> codes);
}

View File

@@ -0,0 +1,80 @@
package com.newyetai.usercenter.district.dto;
import com.google.common.collect.Lists;
import com.newyetai.common.dto.BaseDTO;
import com.newyetai.common.util.TreeNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import java.util.List;
import java.util.Objects;
/**
* <p>
* 省份城市
* </p>
*
* @author Carlye
* @since 2021-01-25
*/
@ApiModel("省份城市树形DTO")
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class DistrictDTO extends BaseDTO implements TreeNode<Long, DistrictDTO> {
private static final long serialVersionUID = -3042079366109391854L;
@ApiModelProperty("城市名称")
private String name;
@ApiModelProperty("上级城市ID")
private Long parentId;
@ApiModelProperty("首字母")
private String initial;
@ApiModelProperty("简拼")
private String initials;
@ApiModelProperty("全拼")
private String pinyin;
@ApiModelProperty("特别行政区")
private String extra;
@ApiModelProperty("后缀")
private String suffix;
@ApiModelProperty("城市编码")
private String code;
@ApiModelProperty("区域编码")
private String areaCode;
@ApiModelProperty("排序")
private Integer districtOrder;
private Integer level;
@ApiModelProperty("下级")
private List<DistrictDTO> childrenSet;
public List<DistrictDTO> getChildrenSet() {
if (Objects.isNull(this.childrenSet)) {
this.childrenSet = Lists.newArrayList();
}
return this.childrenSet;
}
@Override
public void addChildren(DistrictDTO node) {
getChildrenSet().add(node);
}
}

View File

@@ -0,0 +1,31 @@
package com.newyetai.usercenter.district.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* <p>
* 省份城市
* </p>
*
* @author Carlye
* @since 2021-01-25
*/
@ApiModel("省份城市树形查询DTO")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DistrictTreeQueryDTO {
private static final long serialVersionUID = -3042079366109391854L;
@ApiModelProperty("省份编码")
private String code;
}

View File

@@ -0,0 +1,56 @@
package com.newyetai.usercenter.district.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.newyetai.common.entity.BaseEntity;
import lombok.*;
import lombok.experimental.Accessors;
/**
* 省份城市
*
* @author Carlye
* @since 2021-01-25
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("xs_district")
public class District extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 城市名称 */
private String name;
/** 上级城市ID */
private Long parentId;
/** 首字母 */
private String initial;
/** 简拼 */
private String initials;
/** 全拼 */
private String pinyin;
/** 特别行政区 */
private String extra;
/** 后缀 */
private String suffix;
/** 城市编码 */
private String code;
/** 区域编码 */
private String areaCode;
/** 排序 */
private Integer districtOrder;
private Integer level;
}

View File

@@ -0,0 +1,30 @@
<?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="com.newyetai.usercenter.district.dao.DistrictMapper">
<select id="queryNameByCode" resultType="string">
SELECT
WM_CONCAT( name ) as addressName
FROM
xs_district
WHERE
deleted = 0
AND code IN
<foreach open="(" separator="," close=")" collection="codes" index="index" item="code" >
#{code}
</foreach>
ORDER BY code ASC
</select>
<select id="queryById" resultType="com.newyetai.usercenter.district.dto.DistrictDTO">
SELECT
*
FROM
xs_district
WHERE
deleted = 0
and parent_id=#{districtId}
ORDER BY code ASC
</select>
</mapper>

View File

@@ -0,0 +1,24 @@
package com.newyetai.usercenter.district.mapstruct;
import com.newyetai.usercenter.district.dto.DistrictDTO;
import com.newyetai.usercenter.district.entity.District;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* 用户映射器附件地图
*
* @author Carlye
* @date 2021/01/12
*/
@Mapper
public interface DistrictMapMapper {
DistrictMapMapper INSTANCE = Mappers.getMapper(DistrictMapMapper.class);
DistrictDTO exchange(District district);
DistrictDTO exchange(DistrictDTO districtDTO);
}

View File

@@ -0,0 +1,28 @@
package com.newyetai.usercenter.district.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.newyetai.usercenter.district.dto.DistrictDTO;
import com.newyetai.usercenter.district.dto.DistrictTreeQueryDTO;
import com.newyetai.usercenter.district.entity.District;
import java.util.List;
/**
* 省份城市 服务类
*
* @author Carlye
* @since 2021-01-25
*/
public interface IDistrictService extends IService<District> {
/**
* 树列表
*
* @return {@link List<DistrictDTO>}
*/
List<DistrictDTO> treeList(DistrictTreeQueryDTO queryDTO);
List<DistrictDTO> queryListById(Long districtId);
List<District> all(Integer level);
}

View File

@@ -0,0 +1,138 @@
package com.newyetai.usercenter.district.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.newyetai.common.exception.util.Assert;
import com.newyetai.common.util.TreeHelper;
import com.newyetai.frame.redis.aop.annotation.AutoUnLock;
import com.newyetai.frame.redis.dto.LockDTO;
import com.newyetai.frame.redis.redisson.RedissonUtils;
import com.newyetai.usercenter.constants.CacheConstants;
import com.newyetai.usercenter.district.constants.DistrictConstants;
import com.newyetai.usercenter.district.dao.DistrictMapper;
import com.newyetai.usercenter.district.dto.DistrictDTO;
import com.newyetai.usercenter.district.dto.DistrictTreeQueryDTO;
import com.newyetai.usercenter.district.entity.District;
import com.newyetai.usercenter.district.mapstruct.DistrictMapMapper;
import com.newyetai.usercenter.district.service.IDistrictService;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
/**
* 省份城市 服务实现类
*
* @author Carlye
* @since 2021-01-25
*/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class DistrictServiceImpl extends ServiceImpl<DistrictMapper, District>
implements IDistrictService {
private final RedisTemplate redisTemplate;
private final DistrictMapper districtMapper;
@Override
@AutoUnLock
public List<DistrictDTO> treeList(DistrictTreeQueryDTO queryDTO) {
List<DistrictDTO> range = redisTemplate.opsForList().range(CacheConstants.DISTRICT_TREE_PROVINCE_KEY, 0, -1);
if (CollectionUtils.isEmpty(range)) {
Assert.isTrue(RedissonUtils.tryLockAutomatically(LockDTO.builder().methodName("treeList").build()), "正在初始化数据,请稍后再试");
List<DistrictDTO> range2 = redisTemplate.opsForList().range(CacheConstants.DISTRICT_TREE_PROVINCE_KEY, 0, -1);
if (CollectionUtils.isEmpty(range2)) {
@SuppressWarnings("unchecked")
List<District> allDistricts =
list(Wrappers.<District>lambdaQuery()
.eq(District::getDeleted, false)
.orderByAsc(District::getParentId, District::getDistrictOrder,
District::getId));
if (CollectionUtils.isEmpty(allDistricts)) {
List<DistrictDTO> districtDTOS = Lists.newArrayList(new DistrictDTO());
redisTemplate.opsForList()
.leftPush(CacheConstants.DISTRICT_TREE_PROVINCE_KEY, districtDTOS);
redisTemplate.expire(CacheConstants.DISTRICT_TREE_PROVINCE_KEY, 5, TimeUnit.MINUTES);
return districtDTOS;
}
//省市区
List<DistrictDTO> allDistrictDTOS = allDistricts.stream()
.map(DistrictMapMapper.INSTANCE::exchange).collect(Collectors.toList());
List<DistrictDTO> districtDTOS = TreeHelper.buildTree(0L, allDistrictDTOS);
//区-街道
List<DistrictDTO> suffix = Lists.newArrayList();
districtDTOS.forEach(districtDTO -> recursiveDistrictDTO(districtDTO, suffix));
for (DistrictDTO districtDTO : suffix) {
String key = String
.join(":", CacheConstants.DISTRICT_TREE_ALL_KEY, districtDTO.getCode());
redisTemplate.delete(key);
redisTemplate.opsForList().rightPushAll(key, districtDTO.getChildrenSet());
redisTemplate.expire(key, 1, TimeUnit.DAYS);
}
redisTemplate.delete(CacheConstants.DISTRICT_TREE_PROVINCE_KEY);
redisTemplate.opsForList()
.rightPushAll(CacheConstants.DISTRICT_TREE_PROVINCE_KEY, districtDTOS);
redisTemplate.expire(CacheConstants.DISTRICT_TREE_PROVINCE_KEY, 1, TimeUnit.DAYS);
range = districtDTOS;
}
}
String code = queryDTO.getCode();
if (StringUtils.isNotEmpty(code)) {
String key = String.join(":", CacheConstants.DISTRICT_TREE_ALL_KEY, code);
return redisTemplate.opsForList().range(key, 0, -1);
}
return range;
}
private static final Integer TAG = 4;
private void recursiveDistrictDTO(DistrictDTO districtDTO,
List<DistrictDTO> suffix) {
int length = districtDTO.getCode().length();
if (length < TAG) {
for (DistrictDTO child : districtDTO.getChildrenSet()) {
recursiveDistrictDTO(child, suffix);
}
}
if (length == TAG) {
suffix.add(DistrictMapMapper.INSTANCE.exchange(districtDTO));
districtDTO.setChildrenSet(null);
}
}
@Override
@Cacheable(cacheNames = DistrictConstants.CacheNames.DISTRICT_PROVINCE,
key = DistrictConstants.CACHE_KEY_DISTRICT_ID)
public List<DistrictDTO> queryListById(Long districtId) {
List<DistrictDTO> districtDTOS = districtMapper.queryById(districtId);
return districtDTOS;
}
@Override
public List<District> all(Integer level) {
List<District> districts = districtMapper.selectList(new LambdaQueryWrapper<District>()
.eq(District::getLevel, level)
.eq(District::getDeleted, false)
.orderByAsc(District::getCode));
return districts;
}
}