短链接day4

短链接管理

创建短链接数据库表

URI、URL和URN区别 :

URI 指的是一个资源 ;URL 用地址定位一个资源; URN 用名称定位一个资源。

举个例子: 去寻找一个具体的人(URI);如果用地址:XX省XX市XX区...XX单元XX室的主人 就是URL;如果用身份证号+名字去找就是URN(身份证号+名字 无法确认资源的地址) 。 在Java类库中,URI类不包含任何访问资源的方法,只能标识资源。URL类可以访问资源,可以获取指定资源的流信息。

新增短链接

由于describe在java中属于关键字,所以在实体对象中,对于describe属性应当:

记住是加了反引号的!

    /**
    * 描述
    */
    @TableField("`describe`")
    private String describe;

短链接区分大小写:将utf8m64改成utf8,相应的配置也改成utf8 bin。

将长连接hash模到短链接一定会存在冲突的问题,怎么解决?

重置。为了防止死循环,需要设置一个最大的重置次数。

由于海量数据,并且为了防止多次查询数据库,需要去查缓存,所以需要用分布式锁,从而这个用布隆过滤器实现(在用户注册时,同样使用了)。

private final RBloomFilter<String> shortUriCreateCachePenetrationBloomFilter;
    /**
     * 创建短链接
     *
     * @param requestParam
     * @return
     */
    @Override
    public ShortLinkCreateRespDTO createShortLink(ShortLinkCreateReqDTO requestParam) {
        String shortLinkSuffix=generateSuffix(requestParam);
        String fullShortUrl=requestParam.getDomain()+"/"+shortLinkSuffix;
        ShortLinkDO shortLinkDO=ShortLinkDO.builder()
                .domain(requestParam.getDomain())
                .originUrl(requestParam.getOriginUrl())
                .gid(requestParam.getGid())
                .createdType(requestParam.getCreatedType())
                .validDateType(requestParam.getValidDateType())
                .validDate(requestParam.getValidDate())
                .describe(requestParam.getDescribe())
                .shortUri(shortLinkSuffix)
                .enableStatus(0)
                .fullShortUrl(fullShortUrl)
                .build();
        try{
            //数据库如果存在,则会报错,进入catch
            baseMapper.insert(shortLinkDO);
        }catch (DuplicateKeyException exp){
            //TODO 已经误判的短链接如何处理
            //第一种,短链接确实真实存在缓存中
            //第二种,短链接不一定存在缓存中

            //检查是否存在于数据库中,如果没存在,则说明布隆过滤器误判了。
            LambdaQueryWrapper<ShortLinkDO> queryWrapper = Wrappers.lambdaQuery(ShortLinkDO.class)
                    .eq(ShortLinkDO::getFullShortUrl, fullShortUrl);
            ShortLinkDO hasShortLinkDO = baseMapper.selectOne(queryWrapper);
            if(hasShortLinkDO!=null){
                log.warn("短链接:{} 重复入库",fullShortUrl);
                throw new ServiceException("短链接生成重复");
            }
        }
        shortUriCreateCachePenetrationBloomFilter.add(fullShortUrl);
        return ShortLinkCreateRespDTO.builder()
                .fullShortUrl(shortLinkDO.getFullShortUrl())
                .originUrl(requestParam.getOriginUrl())
                .gid(requestParam.getGid())
                .build();
    }

    /**
     * 获取短链接的后缀
     * @param requestParam
     * @return
     */
    private String generateSuffix(ShortLinkCreateReqDTO requestParam){
        int customGenerateCount=0;
        String shortUri;
        String originUrl = requestParam.getOriginUrl();
        while(true){
            if(customGenerateCount>10){
                throw new ServiceException("短链接频繁生成,请稍后再试");
            }
            //减小当前冲突的可能
            originUrl+=System.currentTimeMillis();

            shortUri=HashUtil.hashToBase62(originUrl);
            if(!shortUriCreateCachePenetrationBloomFilter.contains(requestParam.getDomain()+"/"+shortUri)){
                break;
            }
            customGenerateCount++;
        }
        return shortUri;
    }

 开发用户登录验证拦截器返回友好提示信息:

@RequiredArgsConstructor
public class UserTransmitFilter implements Filter {
    private final StringRedisTemplate stringRedisTemplate;
    private static final List<String> IGNORE_URI= Lists.newArrayList(
            "/api/short-link/admin/v1/user/login",
            "/api/short-link/admin/v1/user/has-username"
    );
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String requestURI=httpServletRequest.getRequestURI();
        if(!IGNORE_URI.contains(requestURI)){
            String method=httpServletRequest.getMethod();
            if(!(Objects.equals(requestURI,"/api/short-link/admin/v1/user")&&Objects.equals(method,"POST"))){
                String username = httpServletRequest.getHeader("username");
                String token = httpServletRequest.getHeader("token");
                if (!StrUtil.isAllNotBlank(username,token)){
                    returnJson(servletResponse,JSON.toJSONString(Results.failure(new ClientException(USER_TOKEN_FAIL))));
                    return;
                }
                Object userInfoJsonStr = null;
                try{
                    userInfoJsonStr=stringRedisTemplate.opsForHash().get("login_" + username, token);
                    if(userInfoJsonStr==null){
                        throw new ClientException(USER_TOKEN_FAIL);
                    }
                }catch (Exception exp){
                    returnJson(servletResponse,JSON.toJSONString(Results.failure(new ClientException(USER_TOKEN_FAIL))));
                    return;
                }
                UserInfoDTO userInfoDTO = JSON.parseObject(userInfoJsonStr.toString(), UserInfoDTO.class);
                UserContext.setUser(userInfoDTO);
            }
        }
        try {
        filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            UserContext.removeUser();
        }
    }
    private void returnJson(ServletResponse response, String json) {
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.print(json);
        } catch (IOException e) {
        } finally {
            if (writer != null)
                writer.close();
        }
    }

}

打包工具,在admin和project的pom中添加,用于联调前端,这个打包插件会让打包有一个直接可以启动的spring文件。 

<build>
        <finalName>s{project.artifactId</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

分页查询短链接列表

    /**
     * 分页查询短链接
     *
     * @param requestParam
     * @return
     */
    @Override
    public IPage<ShortLinkPageRespDTO> pageShortLink(ShortLinkPageReqDTO requestParam) {
        LambdaQueryWrapper<ShortLinkDO> queryWrapper = Wrappers.lambdaQuery(ShortLinkDO.class)
                .eq(ShortLinkDO::getGid, requestParam.getGid())
                .eq(ShortLinkDO::getEnableStatus, 0)
                .eq(ShortLinkDO::getDelFlag, 0);
        IPage<ShortLinkDO> resultPage = baseMapper.selectPage(requestParam, queryWrapper);
        return resultPage.convert(eatch-> BeanUtil.toBean(eatch,ShortLinkPageRespDTO.class));
    }

请求的param有三个:gid、current(当前页)、size(每页数量)

由于返回响应中total有问题,这需要添加一个MySQL数据库分页插件:

@Configuration
public class DataBaseConfiguration {
    /**
     * 分页插件
     * @return
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/793533.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用 Google 的 Generative AI 服务时,请求没有包含足够的认证范围(scopes)

题意&#xff1a; Google generativeai 403 Request had insufficient authentication scopes. [reason: "ACCESS_TOKEN_SCOPE_INSUFFICIENT" 问题背景&#xff1a; I have tried the simple POC for generativeai on its own to do generate_content and it works…

【初阶数据结构】2.顺序表

文章目录 1.线性表2.顺序表2.1 概念与结构2.2 分类2.2.1 静态顺序表2.2.2 动态顺序表 2.3 动态顺序表的实现2.4 顺序表算法题2.4.1 移除元素2.4.2 删除有序数组中的重复项2.4.3 合并两个有序数组 2.5 顺序表问题与思考 1.线性表 线性表&#xff08;linear list&#xff09;是n…

JavaFx+MySql学生管理系统

前言: 上个月学习了javafx和mysql数据库,于是写了一个学生管理系统,因为上个月在复习并且有一些事情,比较忙,所以没有更新博客了,这个项目页面虽然看着有点简陋了,但是大致内容还是比较简单的,于是现在跟大家分享一下我的学生管理系统,希望对这方面有兴趣的同学提供一些帮助 &a…

19185 01背包问题

解决这个问题的关键是使用动态规划的方法。我们可以创建一个二维数组dp[i][j]&#xff0c;其中i表示考虑前i件物品&#xff0c;j表示背包的容量。dp[i][j]的值表示在考虑前i件物品&#xff0c;且背包容量为j时能获得的最大价值。 ### 算法步骤 1. 初始化一个二维数组dp&#x…

Qt常用基础控件总结—容器部件(QGroupBox类)

五、容器部件 按钮框控件QDialogButtonBox 类(很少用) 按钮组控件QButtonGroup 类(很少用) 组框控件QGroupBox 类 QGroupBox 类介绍 QGroupBox(组框),直接继承自 QWidget 类,因此使用该类创建的对象,可作为窗口使用,组框在外观上是可见的。 QGroupBox 类(组框),…

数据平滑处理(部分)

一、 移动平均&#xff08;Moving Average&#xff09; 是一种最简单的数据平滑方法&#xff0c;用于平滑时间序列数据。它通过计算一定窗口内数据点的平均值来减少噪音&#xff0c;同时保留数据的趋势。移动平均包括简单移动平均&#xff08;SMA&#xff09;或指数加权移动平均…

【爬虫】爬虫基础

目录 一、Http响应与请求1、Http请求2、Http响应3、状态码 二、Requests库1、发起GET请求2、发起POST请求3、处理请求头 三、BeautifulSoup库1、解析HTML文档2、查找和提取数据Ⅰ、查找单个元素Ⅱ、查找所有元素Ⅲ、使用CSS选择器Ⅳ、获取元素属性 四、爬取豆瓣电影榜 一、Http…

YOLOv10训练自己的数据集(交通标志检测)

YOLOv10训练自己的数据集&#xff08;交通标志检测&#xff09; 前言相关介绍前提条件实验环境安装环境项目地址LinuxWindows 使用YOLOv10训练自己的数据集进行交通标志检测准备数据进行训练进行预测进行验证 参考文献 前言 由于本人水平有限&#xff0c;难免出现错漏&#xff…

【Linux】日志

日志是记录软件运行过程中发生的事件的一种手段&#xff0c;通常包含以下内容&#xff1a; 时间戳&#xff1a;记录日志条目创建的确切时间。这对于追踪事件发生的时间顺序至关重要。日志级别&#xff1a;表示日志信息的严重性或重要性&#xff0c;常见的级别包括 DEBUG、INFO…

RisingWave 用例:流式 ETL、实时分析、事件驱动应用

RisingWave 非常适合以下类别的用例。 流式 ETL实时分析事件驱动应用 流式 ETL 是实时分析和事件驱动应用的基础。实时分析通过引入数据看板&#xff0c;扩展了流式 ETL&#xff0c;而事件驱动应用则在实时分析的基础上增加了逻辑&#xff0c;以评估条件是否触发后续行动。 …

【测开能力提升-fastapi框架】fastapi模版引擎简单使用

1.6 通过模版引擎返回HTM页面 import uvicorn from fastapi import FastAPI, Request from fastapi.templating import Jinja2Templatesapp FastAPI()# 初始化模版引擎存放位置 templates Jinja2Templates(directory"templates")app.get("/") async def…

2024年西安铁一中集训DAY1---- 杂题选讲

文章目录 牛客练习赛125 E 联谊活动&#xff08;枚举&#xff0c;分讨&#xff09;牛客练习赛125 F 玻璃弹珠&#xff08;类莫队&#xff0c;离线询问&#xff0c;数据结构&#xff09;2024ccpc长春邀请赛 D Parallel Lines&#xff08;随机化&#xff09;2024ccpc长春邀请赛 E…

分布式应用系统设计:即时消息系统

即时消息(IM)系统&#xff0c;涉及&#xff1a;站内消息系统 组件如下&#xff1b; 客户端&#xff1a; WEB页面&#xff0c;IM桌面客户端。通过WebSocket 跟ChatService后端服务连接 Chat Service&#xff1a; 提供WebSocket接口&#xff0c;并保持跟“客户端”状态的维护。…

彻底解决找不到d3dcompiler_43.dll问题,总结几种有效的方法

运行软件时提示找不到d3dcompiler_43.dll无法继续执行代码&#xff0c;如何解决&#xff1f;解决这个问题的方法有很多&#xff0c;但具体问题需要具体分析&#xff0c;有些方法可能并不适用于解决d3dcompiler_43.dll的问题。因此&#xff0c;需要根据实际情况来选择合适的方法…

8627 数独

为了判断数独解是否合法&#xff0c;我们需要遵循以下步骤&#xff1a; 1. **检查每一行**&#xff1a;确保1到9每个数字在每一行中只出现一次。 2. **检查每一列**&#xff1a;确保1到9每个数字在每一列中只出现一次。 3. **检查每个3x3的宫**&#xff1a;确保1到9每个数字在…

模式物种葡萄基因组(T2T)--文献精读29

The complete reference genome for grapevine (Vitis vinifera L.) genetics and breeding 葡萄&#xff08;Vitis vinifera L.&#xff09;遗传学和育种的完整参考基因组 摘要 葡萄是全球最具经济重要性的作物之一。然而&#xff0c;以往版本的葡萄参考基因组通常由成千上万…

星辰考古:TiDB v4.0 进化前夜

前情回顾TiDB v4 时间线TiDB v4 新特性 TiDBTiKVPDTiFlashTiCDCTiDB v4 兼容性变化 TiDBTiKVPD其他TiDB 社区互助升级活动TiDB 3.0.20 升级到 4.0.16 注意事项升级速览直观变化总结素材来源&#x1f33b; 往期精彩 ▼ 前情回顾 在前面的章节中&#xff0c;我们共同梳理了 TiDB …

【刷题汇总 -- 最长回文子串、买卖股票的最好时机(一)、[NOIP2002 普及组] 过河卒】

C日常刷题积累 今日刷题汇总 - day0101、最长回文子串1.1、题目1.2、思路1.3、程序实现 2、买卖股票的最好时机(一)2.1、题目2.2、思路2.3、程序实现2.4、程序实现 -- 优化 3、[NOIP2002 普及组] 过河卒3.1、题目3.2、思路3.3、程序实现 -- dp 4、题目链接 今日刷题汇总 - day0…

一个便捷的web截图库~【送源码】

随着时间的发展&#xff0c;前端开发的范围越来越广&#xff0c;能够实现的功能也越来越多&#xff0c;要实现的功能也五花八门&#xff0c;今天就给大家介绍一个web截图库,让前端也能实现截图功能—— js-web-screen-shot js-web-screen-shot js-web-screen-shot 是一个基于 …

Linux服务器CPU占用率达到100%排查思路

1、找到最耗CPU的进程pid&#xff0c;执行命令 top 2、找到最耗CPU的线程tid // 执行 top -Hp [pid] 定位应用进程对应的线程 tid // 按shift p 组合键&#xff0c;按照CPU占用率排序 > top -Hp 14246 3、将线程pid转化为16进制 // printf "%x\n" [tid] 将tid…