Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
  • 如何设计一个短链系统
  • 新Get的开发技巧
  • 项目通用工具

  • 用户模块

  • 短链模块

    • 短链接分组

    • 短链接管理

      • 持久层
      • 短链接管理CRUD
      • 后管联调
        • 后管分页查询短链接
        • 后管创建短链接
        • 中台短链分组统计
        • 后管短链分组统计
        • 默认分组
        • 修改分组
      • 短链接跳转
      • 短链管理之今日历史访问统计
    • 回收站管理

    • 短链接监控

  • 流量风控
  • 如何获取用户IP?
  • SaaS短链接系统
  • 短链模块
  • 短链接管理
Nreal
2024-01-11
目录

后管联调

# 后管分页查询短链接

接口:

@RestController
public class ShortLinkController {

    ShortLinkRemoteService shortLinkRemoteService = new ShortLinkRemoteService() {
    };

    /**
     * 分页查询短链接
     */
    @GetMapping("/api/short-link/admin/v1/page")
    public Result<IPage<ShortLinkPageRespDTO>> pageShortLink(ShortLinkPageReqDTO requestParam) {
        return shortLinkRemoteService.pageShortLink(requestParam);
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface ShortLinkRemoteService {
    default Result<IPage<ShortLinkPageRespDTO>> pageShortLink(ShortLinkPageReqDTO requestParam) {
        Map<String, Object> requestMap = new HashMap<>();
        requestMap.put("gid", requestParam.getGid());
        requestMap.put("orderTag", requestParam.getOrderTag());
        requestMap.put("current", requestParam.getCurrent());
        requestMap.put("size", requestParam.getSize());
        String resultPageStr = HttpUtil.get("http://127.0.0.1:8001/api/short-link/v1/page", requestMap);
        return JSON.parseObject(resultPageStr, new TypeReference<>() {
        });
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 后管创建短链接

接口:

@PostMapping("/api/short-link/admin/v1/create")
public Result<ShortLinkCreateRespDTO> createShortLink(@RequestBody ShortLinkCreateReqDTO requestParam) {
    return shortLinkRemoteService.createShortLink(requestParam);
}
1
2
3
4
default Result<ShortLinkCreateRespDTO> createShortLink(ShortLinkCreateReqDTO requestParam) {
    String resultBodyStr = HttpUtil.post("http://127.0.0.1:8001/api/short-link/v1/create", JSON.toJSONString(requestParam));
    return JSON.parseObject(resultBodyStr, new TypeReference<>() {
    });
}
1
2
3
4
5

# 中台短链分组统计

接口:

@GetMapping("/api/short-link/v1/count")
public Result<List<ShortLinkGroupCountQueryRespDTO>> listGroupShortLinkCount(@RequestParam("requestParam") List<String> requestParam) {
    return Results.success(shortLinkService.listGroupShortLinkCount(requestParam));
}
1
2
3
4
// 请求参数为gid 数组
@Override
public List<ShortLinkGroupCountQueryRespDTO> listGroupShortLinkCount(List<String> requestParam) {
    QueryWrapper<ShortLinkDO> queryWrapper = Wrappers.query(new ShortLinkDO())
            .select("gid as gid,count(*) as shortLinkCount")
            .in("gid",requestParam)
            .eq("enable_status", 0)
            .eq("del_flag", 0)
            .eq("del_time", 0L)
            .groupBy("gid");
    List<Map<String, Object>> shortLinkDOList = baseMapper.selectMaps(queryWrapper);
    return BeanUtil.copyToList(shortLinkDOList, ShortLinkGroupCountQueryRespDTO.class);
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 后管短链分组统计

后管中/ShortLinkRemoteService添加:

default Result<List<ShortLinkGroupCountQueryRespDTO>> listGroupShortLinkCount(List<String> requestParam) {
    Map<String, Object> requestMap = new HashMap<>();
    requestMap.put("requestParam", requestParam);
    String resultPageStr = HttpUtil.get("http://127.0.0.1:8001/api/short-link/v1/count", requestMap);
    return JSON.parseObject(resultPageStr, new TypeReference<>() {
    });
}
1
2
3
4
5
6
7

/GroupController#listGroup()中每个用户的分组添加统计字段:

@Override
public List<ShortLinkGroupRespDTO> listGroup() {
    LambdaQueryWrapper<GroupDO> queryWrapper = Wrappers.lambdaQuery(GroupDO.class)
            .eq(GroupDO::getDelFlag, 0)
            .eq(GroupDO::getUsername, UserContext.getUsername())
            .orderByDesc(GroupDO::getSortOrder, GroupDO::getUpdateTime);
    List<GroupDO> groupDOList = baseMapper.selectList(queryWrapper);
    Result<List<ShortLinkGroupCountQueryRespDTO>> listResult = shortLinkRemoteService
            .listGroupShortLinkCount(groupDOList.stream().map(GroupDO::getGid).toList());
    List<ShortLinkGroupRespDTO> shortLinkGroupRespDTOList = BeanUtil.copyToList(groupDOList, ShortLinkGroupRespDTO.class);
    shortLinkGroupRespDTOList.forEach(each -> {
        Optional<ShortLinkGroupCountQueryRespDTO> first = listResult.getData().stream()
                .filter(item -> Objects.equals(item.getGid(), each.getGid()))
                .findFirst();
        first.ifPresent(item -> each.setShortLinkCount(first.get().getShortLinkCount()));
    });
    return shortLinkGroupRespDTOList;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 默认分组

UserServiceImpl中修改:

@Override
public void register(UserRegisterReqDTO requestParam) {
    if(!hasUsername(requestParam.getUsername())){
        throw new ClientException(USER_NAME_EXIST);
    }
    RLock lock = redissonClient.getLock(LOCK_USER_REGISTER_KEY+requestParam.getUsername());
    try {
        if(lock.tryLock()){
            // 布隆过滤器误判,捕捉异常
            try {
                // 获得锁 插入数据库
                int inserted = baseMapper.insert(BeanUtil.toBean(requestParam, UserDO.class));
                if(inserted < 1){
                    throw new ClientException(USER_SAVE_ERROR);
                }
            } catch (DuplicateKeyException ex) {
                throw new ClientException(USER_EXIST);
            }
            userRegisterCachePenetrationBloomFilter.add(requestParam.getUsername());
            /*
            * 添加默认分组;
            */
            groupService.saveGroup(requestParam.getUsername(),"默认分组");
            return ;
        }
        throw new ClientException(USER_NAME_EXIST);
    } finally {
        lock.unlock();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 修改分组

根据fullShortUrl更改原始链接;

需要判断是不是同一个gid,分类讨论,是则直接update,否则先删再插入;

接口:

@PostMapping("/api/short-link/v1/update")
public Result<Void> updateShortLink(@RequestBody ShortLinkUpdateReqDTO requestParam) {
    shortLinkService.updateShortLink(requestParam);
    return Results.success();
}
1
2
3
4
5
@Transactional(rollbackFor = Exception.class)
@Override
public void updateShortLink(ShortLinkUpdateReqDTO requestParam) {
    LambdaQueryWrapper<ShortLinkDO> queryWrapper = Wrappers.lambdaQuery(ShortLinkDO.class)
            .eq(ShortLinkDO::getGid, requestParam.getGid())
            .eq(ShortLinkDO::getFullShortUrl, requestParam.getFullShortUrl())
            .eq(ShortLinkDO::getDelFlag, 0)
            .eq(ShortLinkDO::getEnableStatus, 0);
    ShortLinkDO hasShortLinkDO = baseMapper.selectOne(queryWrapper);
    if (hasShortLinkDO == null) {
        throw new ClientException("短链接记录不存在");
    }
    ShortLinkDO shortLinkDO = ShortLinkDO.builder()
            .domain(hasShortLinkDO.getDomain())
            .shortUri(hasShortLinkDO.getShortUri())
            .clickNum(hasShortLinkDO.getClickNum())
            .favicon(hasShortLinkDO.getFavicon())
            .createdType(hasShortLinkDO.getCreatedType())
            .gid(requestParam.getGid())
            .originUrl(requestParam.getOriginUrl())
            .describe(requestParam.getDescribe())
            .validDateType(requestParam.getValidDateType())
            .validDate(requestParam.getValidDate())
            .build();
    if (Objects.equals(hasShortLinkDO.getGid(), requestParam.getGid())) {
        LambdaUpdateWrapper<ShortLinkDO> updateWrapper = Wrappers.lambdaUpdate(ShortLinkDO.class)
                .eq(ShortLinkDO::getFullShortUrl, requestParam.getFullShortUrl())
                .eq(ShortLinkDO::getGid, requestParam.getGid())
                .eq(ShortLinkDO::getDelFlag, 0)
                .eq(ShortLinkDO::getEnableStatus, 0)
                .set(Objects.equals(requestParam.getValidDateType(), VailDateTypeEnum.PERMANENT.getType()), ShortLinkDO::getValidDate, null);
        baseMapper.update(shortLinkDO, updateWrapper);
    } else {
        LambdaUpdateWrapper<ShortLinkDO> updateWrapper = Wrappers.lambdaUpdate(ShortLinkDO.class)
                .eq(ShortLinkDO::getFullShortUrl, requestParam.getFullShortUrl())
                .eq(ShortLinkDO::getGid, hasShortLinkDO.getGid())
                .eq(ShortLinkDO::getDelFlag, 0)
                .eq(ShortLinkDO::getEnableStatus, 0);
        baseMapper.delete(updateWrapper);
        baseMapper.insert(shortLinkDO);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

后管远程调用:

default void updateShortLink(ShortLinkUpdateReqDTO requestParam) {
    HttpUtil.post("http://127.0.0.1:8001/api/short-link/v1/update", JSON.toJSONString(requestParam));
}
1
2
3
短链接管理CRUD
短链接跳转

← 短链接管理CRUD 短链接跳转→

Theme by Vdoing | Copyright © 2021-2024
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式