Java实现短网址应用


1.背景介绍

相信很多人手机上都收到过一些营销短信,短信里面有时候会附带一些网址,如下图

这些网址往往都是非常短,就是我们常说的短网址(短域名)。所以短网址(短域名)服务就是把普通网址,转换成比较短的网址。在微博以及短信这些限制字数的应用里。好处不言而喻。短、字符少、美观、便于发布、传播。

2.原理和应用

其实很简单 ,系统把一个长的地址 如 http://www.xxx.com/ddd/xxx/a.html?dsada 
首先用一个算法转换成 短地址 http://t.cn/Afafhe 
然后把  Afafhe-->http://www.xxx.com/ddd/xxx/a.html?dsada 的关系保存下来
当用户访问 http://t.cn/Afafhe网址时,系统找到对应的原来的长URL地址,实现跳转 

3.Java简单实现的代码

import com.daqsoft.common.constant.Constants;

import java.security.MessageDigest;
import java.util.Random;

/**
* 短连接生成工具
*
* @author fanhj
* @version V1.0.0
* @date 2020-09-09
*/
public class ShortUrlUtils {

/**
* 会使用到的常量
*/
public static final long LONG_0X3FFFFFFF = 0x3FFFFFFF;
public static final long LONG_0X0000003D = 0x0000003D;
public static final int LONG_0XFF = 0xFF;

public static void main(String[] args) {
// 原始链接
String sLongUrl = "http://www.51bi.com/bbs/_t_278433840/";
System.out.println("长链接:" + sLongUrl);
// 将产生4组6位字符串
String[] aResult = shortUrl(sLongUrl);
// 打印出结果
for (int i = Constants.INDEX_0; i < aResult.length; i++) {
System.out.println("[" + i + "]:" + aResult[i]);
}
Random random = new Random();
// 生成4以内随机数
int j = random.nextInt(Constants.INDEX_4);
// 随机取一个作为短链
System.out.println("短链接:" + aResult[j]);
}

public static String[] shortUrl(String url) {
// 可以自定义生成 MD5 加密字符传前的混合 KEY
String key = "jkb66.com";
// 要使用生成 URL 的字符
String[] chars = new String[]{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p",
"q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
"B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z"
};
// 对传入网址进行 MD5 加密
String hex = md5ByHex(key + url);

String[] resUrl = new String[Constants.INDEX_4];
for (int i = Constants.INDEX_0; i < Constants.INDEX_4; i++) {
// 把加密字符按照 8 位一组 16 进制与 0x3FFFFFFF 进行位与运算
String sTempSubString = hex.substring(i * Constants.INDEX_8, i * Constants.INDEX_8 + Constants.INDEX_8);
// 这里需要使用 long 型来转换,因为 Integer.parseInt() 只能处理 31 位 , 首位为符号位 ,如果不用long,则会越界
long lHexLong = LONG_0X3FFFFFFF & Long.parseLong(sTempSubString, Constants.INDEX_16);
String outChars = "";
for (int j = Constants.INDEX_0; j < Constants.INDEX_6; j++) {
// 把得到的值与 0x0000003D 进行位与运算,取得字符数组 chars 索引
long index = LONG_0X0000003D & lHexLong;
// 把取得的字符相加
outChars += chars[(int) index];
// 每次循环按位右移 5 位
lHexLong = lHexLong >> Constants.INDEX_5;
}
// 把字符串存入对应索引的输出数组
resUrl[i] = outChars;
}
return resUrl;
}

/**
* MD5加密(32位大写)
*
* @param src 原始字符串
* @return 加密之后的字符串
*/
private static String md5ByHex(String src) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] b = src.getBytes();
md.reset();
md.update(b);
byte[] hash = md.digest();
StringBuffer buffer = new StringBuffer();
String stmp = "";
for (int i = Constants.INDEX_0; i < hash.length; i++) {
stmp = Integer.toHexString(hash[i] & LONG_0XFF);
if (stmp.length() == Constants.INDEX_1) {
buffer.append("0" + stmp);
} else {
buffer.append(stmp);
}
}
return buffer.toString().toUpperCase();
} catch (Exception e) {
return "";
}
}
}

 

4.Java解析短网址解析与跳转

import com.alibaba.fastjson.JSONObject;
import com.daqsoft.common.constant.Constants;
import com.daqsoft.common.utils.DateUtil;
import com.daqsoft.framework.support.AbstractCommonController;
import com.daqsoft.framework.support.DataResponse;
import com.daqsoft.zytf.constant.ZytfConstant;
import com.daqsoft.zytf.utils.ShortUrlUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
* 短连接请求接受处理Controller
*
* @author fanhj
* @version 1.0.0
* @date 2020-09-09
* @since JDK 1.8
*/
@RestController
@RequestMapping("/push")
@CrossOrigin(allowCredentials = "true")
public class PushShortUrlController extends AbstractCommonController {

@Autowired
private RedisTemplate redisTemplate;


/**
* 前端调用,将原来前端自己拼接成的下载链接地址,转为短连接返回到前端
*
* @param request request请求对象
* @param longUrl 原来前端自己拼接成的下载链接地址
* @return 最近一周数据倒序显示
*/
@RequestMapping("/getShortUrl")
@ResponseBody
public DataResponse getShortUrl(HttpServletRequest request, String longUrl) {
String server = "http://" + request.getServerName();
String[] shortUrlArray = ShortUrlUtils.shortUrl(longUrl);
String shortUrl = server + "/push/" + shortUrlArray[Constants.INDEX_4];
ValueOperations<String, Map> opsForValue = redisTemplate.opsForValue();
Map<String, Object> map = new HashMap<String, Object>(Constants.INDEX_4);
// 缓存的短连接 对应的原始链接
map.put("longUrl", longUrl);
// 缓存的短连接的创建时间
map.put("createTime", DateUtil.getCurrentDateTime());
// 缓存的短连接的字符串内容
map.put("shortUrl", shortUrl);
// 缓存7天 也可以在此记录短网址的点击量等数据
opsForValue.set("short_url_" + shortUrl, map, Constants.INDEX_7, TimeUnit.DAYS);
JSONObject resultJson = new JSONObject();
resultJson.put("shortUrl", shortUrl);
return succeed(resultJson);
}

/**
* 短连接请求接受处理处
*
* @param id 短连接内容
* @param request request请求对象
* @param response response输出对象
* @throws IOException 抛出的异常
*/
@RequestMapping(value = "/{id}")
public void url(@PathVariable String id, HttpServletRequest request,
HttpServletResponse response) throws IOException {
//获得客户端发送请求的完整url 即我们的短连接
String shortUrlStr = request.getRequestURL().toString();
ValueOperations<String, Map> opsForValue = redisTemplate.opsForValue();
Map<String, Object> map = opsForValue.get("short_url_" + shortUrlStr);
if (map == null) {
response.sendError(ZytfConstant.INDEX_404, "链接已过期失效");
return;
}
String longUrl = map.get("longUrl").toString();
if (StringUtils.isEmpty(longUrl)) {
response.sendError(ZytfConstant.INDEX_404, "链接已过期失效");
return;
} else {
response.sendRedirect(longUrl);
return;
}
}
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM