提供三个功能:
根据短网址查找真实地址
删除短网址
获取真实地址的短网址,如果没有,生成一个
思路:将真实地址进行md5加密,并分割生成一个6位的短链接,并保存到xml文件中,当然也可以保存到数据库中。无法实现将短链接反转成真实地址,因为md5的不可逆性。只能根据短链去持久化xml文件中去查找,这样必然会造成效率上的损失。
测试开销如下(xml文本大约80000行,约15000个短网址,读取速度:308ms,写入速度:314ms)。如果有更好的思路,欢迎留言,我将继续尝试
ShortUrlUtil.class
public class ShortUrl {
public static void main(String[] args) {
String longUrl = "http://www.test.com";
String shortUrl = "uUN3E3";
// 转换成的短链接后6位码
Long start=System.currentTimeMillis();
// System.out.println(getLongUrl(shortUrl));
// System.out.println(getShortUrl(longUrl));
System.out.println(deleteUrl(shortUrl));
Long end=System.currentTimeMillis();
System.out.println("重写xml结束"+((end-start)));
}
/**
*根据短网址查找真实地址
*/
public static String getLongUrl(String shortUrl){
String longUrl =getLongUrl(0,shortUrl);
return longUrl;
}
/**
*根据短网址查找真实地址
*/
public static boolean deleteUrl(String shortUrl){
String longUrl =getLongUrl(0,shortUrl);
boolean isSuccess=true;
if(Validate.noNull(longUrl)){
isSuccess=deleteUrl(0,shortUrl);
}
return isSuccess;
}
/**
*获取真实地址的短网址,如果没有,生成一个
*/
public static String getShortUrl(String longUrl){
String shortUrl=getShortUrl(0,longUrl);
if(Validate.isNull(shortUrl)){
final String _shortUrl=shortUrl(longUrl);
new Thread(
new Runnable() {
@Override
public void run() {
createXml(_shortUrl, longUrl);
}
}
).start();
return _shortUrl;
}
return shortUrl;
}
/**
*将请求生成短网址
*/
private static String shortUrl(String url) {
// 可以自定义生成 MD5 加密字符传前的混合 KEY
String key = "";
// 要使用生成 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 sMD5EncryptResult = DigestUtils.md5Hex(key + url);
String hex = sMD5EncryptResult;
String[] resUrl = new String[4];
for (int i = 0; i < 4; i++) {
// 把加密字符按照 8 位一组 16 进制与 0x3FFFFFFF 进行位与运算
String sTempSubString = hex.substring(i * 8, i * 8 + 8);
// 这里需要使用 long 型来转换,因为 Inteper .parseInt() 只能处理 31 位 , 首位为符号位 , 如果不用
// long ,则会越界
long lHexLong = 0x3FFFFFFF & Long.parseLong(sTempSubString, 16);
String outChars = "";
for (int j = 0; j < 6; j++) {
// 把得到的值与 0x0000003D 进行位与运算,取得字符数组 chars 索引
long index = 0x0000003D & lHexLong;
// 把取得的字符相加
outChars += chars[(int) index];
// 每次循环按位右移 5 位
lHexLong = lHexLong >> 5;
}
// 把字符串存入对应索引的输出数组
resUrl[i] = outChars;
}
return resUrl[0];
}
private static void createXml(String shortUrl, String Url) {
//读取xml配置
String ItemNum ="0";
File f;
try {
String proRootPath = new File("").getCanonicalPath();
f = new File(proRootPath+"/src/main/webapp/WEB-INF/url.xml");
SAXReader reader = new SAXReader();
Document doc = reader.read(f);
Element items = doc.getRootElement();
Element item;
Element child;
//生成映射关系
org.dom4j.Document document= DocumentHelper.createDocument();
org.dom4j.Element root=document.addElement("ItemInfo");
org.dom4j.Element ms=root.addElement("ItemStatistics");
ms.setText("长短链映射关系对照");
org.dom4j.Element channel=root.addElement("Items");
for (Iterator i = items.elementIterator("Items"); i.hasNext();) {
item = (Element) i.next();
for (Iterator z = item.elementIterator("Item"); z.hasNext();) {
child = (Element) z.next();
ItemNum=child.elementText("ItemNum");
org.dom4j.Element title=channel.addElement("Item");
org.dom4j.Element value1=title.addElement("ItemNum");
org.dom4j.Element value2=title.addElement("ItemShort");
org.dom4j.Element value3=title.addElement("ItemLong");
value1.setText(child.elementText("ItemNum"));
value2.setText(child.elementText("ItemShort"));
value3.setText(child.elementText("ItemLong"));
}
}
org.dom4j.Element title=channel.addElement("Item");
org.dom4j.Element value1=title.addElement("ItemNum");
org.dom4j.Element value2=title.addElement("ItemShort");
org.dom4j.Element value3=title.addElement("ItemLong");
value1.setText((Integer.parseInt(ItemNum)+1)+"");
value2.setText(shortUrl);
value3.setText(Url);
XMLWriter writer=new XMLWriter(new FileOutputStream(f), OutputFormat.createPrettyPrint());
writer.setEscapeText(false);//字符是否转义,默认true
writer.write(document);
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static String getLongUrl(int num, String Url) {
//读取xml配置
String longUtl = "";
File f;
try {
String proRootPath = new File("").getCanonicalPath();
f = new File(proRootPath + "/src/main/webapp/WEB-INF/url.xml");
SAXReader reader = new SAXReader();
Document doc = reader.read(f);
Element items = doc.getRootElement();
Element item;
Element child;
for (Iterator i = items.elementIterator("Items"); i.hasNext(); ) {
item = (Element) i.next();
for (Iterator z = item.elementIterator("Item"); z.hasNext(); ) {
child = (Element) z.next();
if(Url.equals(child.elementText("ItemShort"))){
longUtl = child.elementText("ItemLong");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return longUtl;
}
private static boolean deleteUrl(int num, String shortUrl) {
//读取xml配置
String longUtl = "";
File f;
try {
String proRootPath = new File("").getCanonicalPath();
f = new File(proRootPath + "/src/main/webapp/WEB-INF/url.xml");
SAXReader reader = new SAXReader();
Document doc = reader.read(f);
Element items = doc.getRootElement();
Element item;
Element child;
for (Iterator i = items.elementIterator("Items"); i.hasNext(); ) {
item = (Element) i.next();
for (Iterator z = item.elementIterator("Item"); z.hasNext(); ) {
child = (Element) z.next();
if(shortUrl.equals(child.elementText("ItemShort"))){
System.out.println("111111111");
child.getParent().remove(child);
}
}
}
OutputFormat outformat = OutputFormat.createPrettyPrint();
// xml自身的编码
outformat.setEncoding(doc.getXMLEncoding());
outformat.setIndent(true);
// 将xmlStr输出到目标路径,使用xml文件的头文件编码
OutputStream out = new FileOutputStream(f);
XMLWriter writer = new XMLWriter(out, outformat);
// 是否转义特殊字符,默认true转义,false表示不转义
writer.setEscapeText(false);
writer.write(doc);
writer.flush();
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
private static String getShortUrl(int num, String Url) {
//读取xml配置
String shortUrl = "";
File f;
try {
String proRootPath = new File("").getCanonicalPath();
f = new File(proRootPath + "/src/main/webapp/WEB-INF/url.xml");
SAXReader reader = new SAXReader();
Document doc = reader.read(f);
Element items = doc.getRootElement();
Element item;
Element child;
for (Iterator i = items.elementIterator("Items"); i.hasNext(); ) {
item = (Element) i.next();
for (Iterator z = item.elementIterator("Item"); z.hasNext(); ) {
child = (Element) z.next();
if(Url.equals(child.elementText("ItemLong"))){
shortUrl = child.elementText("ItemShort");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return shortUrl;
}
}
持久化xml格式:
<?xml version="1.0" encoding="UTF-8"?>
<ItemInfo>
<ItemStatistics>长短链映射关系对照</ItemStatistics>
<Items>
<Item>
<ItemNum>1</ItemNum>
<ItemShort>Ev6JJr</ItemShort>
<ItemLong>http://www.baidu.com</ItemLong>
</Item>
<Item>
<ItemNum>2</ItemNum>
<ItemShort>7vuuqq</ItemShort>
<ItemLong>http://www.sougou.com</ItemLong>
</Item>
</Items>
</ItemInfo>