一、背景

现在在各种圈的产品各种推广地址,由于URL地址过长,不美观、不方便收藏、发布、传播以及各种发文字数限制等问题,微信、微博都在使用短链接技术。最近由于使用的三方的生成、解析短链接服务开始限制使用以及准备收费、不方便统计分析、不方便流控等问题,决定自建一个短地址服务。

二、原理

比如,http://a.b.com/15uOVS 这个短地址

第1步,浏览器请求这个地址

第2步,通过DNS后到短地址服务端,还原这个短地址对应的原始长地址。

第3步,请求http 301 或302到原始的长地址上

第4步,浏览器拿到原始长地址的响应response

三、实现

短地址服务的核心是短地址和长地址的转化映射算法。

最简单的算法是把原来的长地址做MD5摘要记为key,长地址记为value。把key value放入服务端缓存中比如redis中。

反向解析时通过URL解决出key来,比如上面的短地址key = 15uOVS 。然后通过key去缓存中获取原始长地址value实现URL地址还原。

MD5摘要有几个明显的问题:

1、短地址的长度受限,比如MD5后的数据长度是32位,需要进行分段循环处理,使短地址足够短

2、MD5的哈希碰撞问题,有一定的概率重复,解决此问题,需要不断的提升算法的复杂度,有些得不偿失

当然不止MD5实现算法比较多,大家可以自行谷歌。

笔者的实现原理如下:

1、新建一张表,主要字段包括自增ID【这里有个小技巧,可以给自增ID设置一个漂亮的起步值,使短地址码随机性更好一些,不建议从0开始自增,比如alter table mapping_info  AUTO_INCREMENT=1112345612;】,原始长地址URL等,做一个自增的10进制长整型短地址key,然后把key转化成62进制,映射到0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz这62个字符上,做成6位的短链接码,如开头的例子15uOVS,【6位62进制数,对应的号码空间为62的6次方,约等于568亿,即可以生成586亿的短网址,基本能满足需求】。

2、把短地址码及长地址,通过key value的形式放入redis和数据库中。

3、写一个过滤器ShortUrlMappingFilter过滤器(为什么是过滤器,因为过滤器是对请求进行过滤转发的,不明白自己谷歌)的执行order设为第一个执行,即值最小。

注: 拦截器、过滤器、监听器的执行顺序   --->   监听器 > 过滤器 > 拦截器 > controller执行 > 拦截器 > 过滤器 > 监听器

相关核心代码如下:

(一) 、ShortUrlMappingFilter过滤器如下:

/**

* @author xuzhujack

**/

public class ShortUrlMappingFilter implements Filter {

private static final Logger LOGGER = LoggerFactory.getLogger(ShortUrlMappingFilter.class);

private static final int shortUrlKeyLength = 6;

@Override

public void init(FilterConfig filterConfig) throws ServletException {

LOGGER.info("ShortUrlMappingFilter init ...........");

}

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

LOGGER.info("ShortUrlMappingFilter url mapping start......");

HttpServletRequest request = (HttpServletRequest) servletRequest;

HttpServletResponse response = (HttpServletResponse) servletResponse;

BeanFactory factory = WebApplicationContextUtils

.getRequiredWebApplicationContext(request.getServletContext());

ShortUrlService shortUrlService = (ShortUrlService) factory.getBean("shortUrlService");

if(request.getRequestURI().substring(1).trim().length()== shortUrlKeyLength){

ShortUrlDto query = new ShortUrlDto();

query.setId(ShortUrlUtils.base62Decode(request.getRequestURI().substring(1).trim()));

ShortUrl shortUrl = shortUrlService.queryShortUrl(query);

if (shortUrl == null) {

LOGGER.error("ShortUrlMappingFilter shortUrl is null ...........dto is {}", query);

throw new ServletException();

} else {

String srcUrl = shortUrl.getSrcUrl();

LOGGER.info("ShortUrlMappingFilter shortUrl is not null .shortUrl is {}...........dto is {}", shortUrl, query);

response.sendRedirect(srcUrl);

}

}else{

filterChain.doFilter(request, response);

LOGGER.info("非短链接正常后续的doFilter..........");

}

}

@Override

public void destroy() {

}

}

(二)、 ShortUrlMappingFilter在项目的启动主类中增加如下配置:

@Bean

public FilterRegistrationBean contextFilterRegistrationBean2() {

FilterRegistrationBean registrationBean = new FilterRegistrationBean();

registrationBean.setFilter(new ShortUrlMappingFilter());

registrationBean.addUrlPatterns("/*");

registrationBean.setName("ShortUrlMappingFilter");

registrationBean.setOrder(0);

return registrationBean;

}

(三)、62进制和10进制的相互转换

/**

* 将数字转为62进制

* @param num Long 型数字

* @return 62进制字符串

*/

public static String base62Encode(long num) {

String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

StringBuilder sb = new StringBuilder();

int remainder = 0;

int scale = 62;

while (num > scale - 1) {

remainder = Long.valueOf(num % scale).intValue();

sb.append(chars.charAt(remainder));

num = num / scale;

}

sb.append(chars.charAt(Long.valueOf(num).intValue()));

String value = sb.reverse().toString();

return StringUtils.leftPad(value, 6, '0');

}

/**

* 62进制字符串转为数字

* @param str 编码后的62进制字符串

* @return 解码后的 10 进制字符串

*/

public static long base62Decode(String str) {

String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

int scale = 62;

str = str.replace("^0*", "");

long num = 0;

int index = 0;

for (int i = 0; i < str.length(); i++) {

index = chars.indexOf(str.charAt(i));

num += (long) (index * (Math.pow(scale, str.length() - i - 1)));

}

return num;

}

java短链接_Java 网址短链接服务原理及解决方案相关推荐

  1. Java 网址短链接服务原理及解决方案

    Java 网址短链接服务原理及解决方案 参考文章: (1)Java 网址短链接服务原理及解决方案 (2)https://www.cnblogs.com/xuzhujack/p/11202364.htm ...

  2. java论坛短信息_JAVA发送短信

    1.[代码]JAVA发送短信 这几天,正好项目的间歇期,就研究了JAVA语言发送手机,呵呵,小有心得,做个笔记: JAVA发送手机短信,流传有几种方法:(1)使用webservice接口发送手机短信, ...

  3. java开发流程图_Java 详解 JVM 工作原理和流程

    作为一名Java使用者,掌握JVM的体系结构也是必须的. 说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成:Java编程语言.Java类文件格式.Java ...

  4. java 短链接url_Java 网址短链接服务原理及解决方案

    一.背景 现在在各种圈的产品各种推广地址,由于URL地址过长,不美观.不方便收藏.发布.传播以及各种发文字数限制等问题,微信.微博都在使用短链接技术.最近由于使用的三方的生成.解析短链接服务开始限制使 ...

  5. java短链接_Java生成短链接

    package com.bjdata.test; import java.security.MessageDigest; import java.util.Random; public class S ...

  6. java短链接_java 生成短链接

    public class shortDemo { public static HttpClient httpclient; static { // 构造 HttpClient httpclient = ...

  7. java 新浪短链接_java生成短连接(调用新浪微博api生成)

    java生成短连接 主要利用新浪微博提供的api生成 import java.io.IOException; import java.util.UUID; import com.alibaba.fas ...

  8. java uuid 第三方_JAVA生成短8位UUID

    java 原创,转载需注明. 短8位UUID思想其实借鉴微博短域名的生成方式,但是其重复概率过高,而且每次生成4个,需要随即选取一个. 本算法利用62个可打印字符,通过随机生成32位UUID,由于UU ...

  9. java 短信_Java发短信Demo

    相信Java初学者开发项目的过程中,经常会遇到向用户发送短信的需求场景.那本文精简的告诉大家,用Java如何实现发送短信的功能. 应用场景 用户注册,请假审批流程提醒,订单消息提醒等需求均会使用到. ...

最新文章

  1. Spring Cloud Gateway的全局异常处理
  2. linux安装weblogic9,linux_weblogic9_安装说明.doc
  3. Oracle数据库使用Analyze提升sql性能
  4. 最大学术出版商妥协!与挪威46所机构签协议,90%出版物免费阅读
  5. LAMP-----2、php-5.3.27编译安装
  6. 利用XPath读取Xml文件
  7. [转载] Python简介、linux上Python及其IDE的安装和详细配置
  8. 【JavaScript】回流(reflow)与重绘(repaint)
  9. 用gcc3.4.5编译c++项目
  10. Spring mvc时间格式处理
  11. 分子动力学模拟算法框架
  12. 【今晚群分享预告】 58集团监控系统实践
  13. 使用regedit导入导出环境变量
  14. java 设置纸张大小设置_Java读取打印机自定义纸张.
  15. 华为商城抢购插件_有赞商城社群接龙全面上线,社群营销玩法升级
  16. DP动态规划--乡村邮局问题-Post Office(POJ-1160)python
  17. HTML+CSS详细知识点(下)
  18. 讲述近十几年的房地产
  19. TCP/IP五层模型详解
  20. html5安卓机判断刘海屏,Android判断是否为刘海屏

热门文章

  1. 初学者好 |如何从头开始创建一个图像识别的AI应用[ctrl:c+v,你就完成了]
  2. [Linux Audio Driver] 移植外部CODEC常见编译报错解决(持续更新)
  3. Python地学分析 — GDAL将多个遥感图像叠加保存为tif文件
  4. android 图片加载 软引用_Android 异步加载网络图片并缓存到本地 软引用 学习分享(转)...
  5. 洛谷P1478 陶陶摘苹果(升级版)【水题】
  6. linux 剪切合并文件夹,使用PDF-Shuffler拆分和合并PDF文件[Linux] | MOS86
  7. 深度伪造检测论文 · Combining EfficientNet and Vision Transformers for Video Deepfake Detection
  8. 微商做引流产品怎么做效果更好?为什么他人的生意这么好而自己没有生意呢?
  9. 报错解决方案参考:《xv6分析与实验》中关于qemu运行报错解决方法
  10. 【论文阅读】 Object Detection in 20 Years: A Survey