您的位置:首页 > 娱乐 > 明星 > 短链接day4

短链接day4

2025/3/10 6:28:53 来源:https://blog.csdn.net/weixin_63374588/article/details/140314816  浏览:    关键词:短链接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*/@Overridepublic 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{//数据库如果存在,则会报错,进入catchbaseMapper.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");@Overridepublic 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*/@Overridepublic 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*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com