Как сравнить два URL-адреса в java?
вот простая проблема-учитывая два URL-адреса, есть ли какой-то встроенный метод или библиотека Apache, которая решает, равны ли они (логически)?
например, эти два URL-адреса равны:
http://stackoverflow.com
http://stackoverflow.com/
4 ответов
пока URI.equals()
(а также проблематично URL.equals()
) делает не возвращение true
для этих конкретных примеров я думаю, что это единственный случай, когда можно предположить эквивалентность (потому что в протоколе HTTP нет пустого пути).
Ресурсов http://stackoverflow.com/foo
и http://stackoverflow.com/foo/
can не считаются эквивалентными.
может быть, вы можете использовать URI.equals()
завернула в служебный метод, который обрабатывает этот конкретный случай явно.
URL urlOne = new URL("http://stackoverflow.com");
URL urlTwo = new URL("http://stackoverflow.com/");
if( urlOne.equals(urlTwo) )
{
// ....
}
Примечание из docs -
два объекта URL равны, если они имеют тот же протокол, ссылаются на эквивалентные хосты, имеют тот же номер порта на хосте и тот же файл и фрагмент файла.
два хоста считаются эквивалентными, если оба имени хоста могут быть разрешены в те же IP-адреса; иначе, если любое имя хоста не может быть разрешено, имена хостов должны быть равны без в отношении case; или оба имени хоста равны null.
поскольку сравнение хостов требует разрешения имен, эта операция является операцией блокировки.
Примечание: определенное поведение для equals, как известно, несовместимо с виртуальным хостингом в HTTP.
Итак, вместо этого вы должны предпочесть URI:: equals reference как предложил @Joachim.
следующее может работать для вас - он проверяет, что 2 url-адреса равны, позволяет параметрам поставляться в разных порядках и позволяет настраивать различные параметры, а именно:
- чувствителен ли регистр хоста
- в случае пути чувствительное
- параметры строки запроса чувствительны к регистру
- значения строки запроса чувствительны к регистру
- чувствительна ли схема к регистру
Вы можете проверить это вот так:
class Main {
public static void main(String[] args)
{
UrlComparer urlComparer = new UrlComparer();
expectResult(false, "key a case different", urlComparer.urlsMatch("//test.com?A=a&B=b", "//test.com?a=a&b=b"));
expectResult(false, "key a case different", urlComparer.urlsMatch("https://WWW.TEST.COM?A=1&b=2", "https://www.test.com?b=2&a=1"));
expectResult(false, "key a value different", urlComparer.urlsMatch("/test?a=2&A=A", "/test?a=A&a=2"));
expectResult(false, "key a value different", urlComparer.urlsMatch("https://WWW.TEST.COM?A=a&b=2", "https://www.test.com?b=2&A=1"));
expectResult(false, "null", urlComparer.urlsMatch("/test", null));
expectResult(false, "null", urlComparer.urlsMatch(null, "/test"));
expectResult(false, "port different", urlComparer.urlsMatch("//test.com:22?A=a&B=b", "//test.com:443?A=a&B=b"));
expectResult(false, "port different", urlComparer.urlsMatch("https://WWW.TEST.COM:8443", "https://www.test.com"));
expectResult(false, "protocol different", urlComparer.urlsMatch("http://WWW.TEST.COM:2121", "https://www.test.com:2121"));
expectResult(false, "protocol different", urlComparer.urlsMatch("http://WWW.TEST.COM?A=a&b=2", "https://www.test.com?b=2&A=a"));
expectResult(true, "both null", urlComparer.urlsMatch(null, null));
expectResult(true, "host and scheme different case", urlComparer.urlsMatch("HTTPS://WWW.TEST.COM", "https://www.test.com"));
expectResult(true, "host different case", urlComparer.urlsMatch("https://WWW.TEST.COM:443", "https://www.test.com"));
expectResult(true, "identical urls", urlComparer.urlsMatch("//test.com:443?A=a&B=b", "//test.com:443?A=a&B=b"));
expectResult(true, "identical urls", urlComparer.urlsMatch("/test?a=A&a=2", "/test?a=A&a=2"));
expectResult(true, "identical urls", urlComparer.urlsMatch("https://www.test.com", "https://www.test.com"));
expectResult(true, "parameter order changed", urlComparer.urlsMatch("https://www.test.com?a=1&b=2&c=522%2fMe", "https://www.test.com?c=522%2fMe&b=2&a=1"));
expectResult(true, "parmeter order changed", urlComparer.urlsMatch("https://WWW.TEST.COM?a=1&b=2", "https://www.test.com?b=2&a=1"));
}
public static void expectResult(boolean expectedResult, String msg, boolean result)
{
if (expectedResult != result)
throw new RuntimeException(msg);
}
}
UrlComparer.java
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
public class UrlComparer
{
private boolean hostIsCaseSensitive = false;
private boolean pathIsCaseSensitive = true;
private boolean queryStringKeysAreCaseSensitive = true;
private boolean queryStringValuesAreCaseSensitive = false;
private boolean schemeIsCaseSensitive = false;
public boolean urlsMatch(String url1, String url2)
{
try
{
if (Objects.equals(url1, url2))
return true;
URI uri1 = new URI(url1);
URI uri2 = new URI(url2);
// Compare Query String Parameters
Map<String, String> mapParams1 = getQueryStringParams(uri1);
Map<String, String> mapParams2 = getQueryStringParams(uri2);
if (!mapsAreEqual(mapParams1, mapParams2, getQueryStringValuesAreCaseSensitive()))
return false;
// Compare scheme (http or https)
if (!stringsAreEqual(uri1.getScheme(), uri2.getScheme(), getSchemeIsCaseSensitive()))
return false;
// Compare host
if (!stringsAreEqual(uri1.getHost(), uri2.getHost(), getHostIsCaseSensitive()))
return false;
// Compare path
if (!stringsAreEqual(uri1.getPath(), uri2.getPath(), getPathIsCaseSensitive()))
return false;
// Compare ports
if (!portsAreEqual(uri1, uri2))
return false;
return true;
}
catch (Exception e)
{
return false;
}
}
protected Map<String, String> getQueryStringParams(URI uri)
{
Map<String, String> result = getListAsMap(URLEncodedUtils.parse(uri, "UTF-8"), getQueryStringKeysAreCaseSensitive());
return result;
}
protected boolean stringsAreEqual(String s1, String s2, boolean caseSensitive)
{
// Eliminate null cases
if (s1 == null || s2 == null)
{
if (s1 == s2)
return true;
return false;
}
if (caseSensitive)
{
return s1.equals(s2);
}
return s1.equalsIgnoreCase(s2);
}
protected boolean mapsAreEqual(Map<String, String> map1, Map<String, String> map2, boolean caseSensitiveValues)
{
for (Map.Entry<String, String> entry : map1.entrySet())
{
String key = entry.getKey();
String map1value = entry.getValue();
String map2value = map2.get(key);
if (!stringsAreEqual(map1value, map2value, caseSensitiveValues))
return false;
}
for (Map.Entry<String, String> entry : map2.entrySet())
{
String key = entry.getKey();
String map2value = entry.getValue();
String map1value = map2.get(key);
if (!stringsAreEqual(map1value, map2value, caseSensitiveValues))
return false;
}
return true;
}
protected boolean portsAreEqual(URI uri1, URI uri2)
{
int port1 = uri1.getPort();
int port2 = uri2.getPort();
if (port1 == port2)
return true;
if (port1 == -1)
{
String scheme1 = (uri1.getScheme() == null ? "http" : uri1.getScheme()).toLowerCase();
port1 = scheme1.equals("http") ? 80 : 443;
}
if (port2 == -1)
{
String scheme2 = (uri2.getScheme() == null ? "http" : uri2.getScheme()).toLowerCase();
port2 = scheme2.equals("http") ? 80 : 443;
}
boolean result = (port1 == port2);
return result;
}
protected Map<String, String> getListAsMap(List<NameValuePair> list, boolean caseSensitiveKeys)
{
Map<String, String> result;
if (caseSensitiveKeys)
{
result = new HashMap<String, String>();
}
else
{
result = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
}
for (NameValuePair param : list)
{
if (caseSensitiveKeys)
{
if (!result.containsKey(param.getName()))
result.put(param.getName(), param.getValue());
}
else
{
result.put(param.getName(), param.getValue());
}
}
return result;
}
public boolean getSchemeIsCaseSensitive()
{
return schemeIsCaseSensitive;
}
public void setSchemeIsCaseSensitive(boolean schemeIsCaseSensitive)
{
this.schemeIsCaseSensitive = schemeIsCaseSensitive;
}
public boolean getHostIsCaseSensitive()
{
return hostIsCaseSensitive;
}
public void setHostIsCaseSensitive(boolean hostIsCaseSensitive)
{
this.hostIsCaseSensitive = hostIsCaseSensitive;
}
public boolean getPathIsCaseSensitive()
{
return pathIsCaseSensitive;
}
public void setPathIsCaseSensitive(boolean pathIsCaseSensitive)
{
this.pathIsCaseSensitive = pathIsCaseSensitive;
}
public boolean getQueryStringKeysAreCaseSensitive()
{
return queryStringKeysAreCaseSensitive;
}
public void setQueryStringKeysAreCaseSensitive(boolean queryStringKeysAreCaseSensitive)
{
this.queryStringKeysAreCaseSensitive = queryStringKeysAreCaseSensitive;
}
public boolean getQueryStringValuesAreCaseSensitive()
{
return queryStringValuesAreCaseSensitive;
}
public void setQueryStringValuesAreCaseSensitive(boolean queryStringValuesAreCaseSensitive)
{
this.queryStringValuesAreCaseSensitive = queryStringValuesAreCaseSensitive;
}
}
sameFile
public boolean sameFile (URL other)сравнивает два URL,
исключая компонент фрагмента. Возвращает true, если этот URL-адрес и другой аргумент равны без учета компонента фрагмента.
параметры: другое-URL для сравнения. Возвращается: true, если они ссылаются на один и тот же удаленный объект; false в противном случае.
также, пожалуйста, перейдите по этой ссылке
http://download.oracle.com/javase/6/docs/api/java/net/URL.html#sameFile(java.net.URL)
поскольку я не могу добавить комментарий, браузер бросает ошибку Javascript. поэтому я добавляю свой комментарий здесь. сожалею о своем невежестве.
//это то, что я suggeted
>URL url1 = new URL("http://stackoverflow.com/foo");
>URL url2 = new URL("http://stackoverflow.com/foo/");
>System.out.println(url1.sameFile(url2));
// this is suggested by Joachim Sauer
>URI uri = new URI("http://stackoverflow.com/foo/");
>System.out.println(uri.equals("http://stackoverflow.com/foo"));
// Both are giving same result
Так Йоахим Зауэр проверить один раз.