개발 관련/Java

HTTP 주소를 URL 인코딩하기.

snoworca 2017. 8. 31. 11:06

JAVA 에서 특정 URL 경로로 데이터를 가져오기 위하여 URL Encoding 을 해야할 때 여간 귀찮은 것이 아니다.

그래서 아래처럼 URLEncoder 클래스를 수정한 BorwerURLEncoder 를 만들었다.


사용법은 URLEncoder 와 동일하며, 마치 브라우저 창에서 URL 주소를 입력해 놓은 것처럼 출력되도록 하였다.

 


BrowserURLEncoder.java 

import java.io.CharArrayWriter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.BitSet;

public class BrowserURLEncoder {

	static BitSet dontNeedEncoding;
	static final int caseDiff = ('a' - 'A');
	static String dfltEncName = "utf-8";
	
	static {
		dontNeedEncoding = new BitSet(256);
		int i;
		for (i = 'a'; i <= 'z'; i++) {
			dontNeedEncoding.set(i);
		}
		for (i = 'A'; i <= 'Z'; i++) {
			dontNeedEncoding.set(i);
		}
		for (i = '0'; i <= '9'; i++) {
			dontNeedEncoding.set(i);
		}
		
		dontNeedEncoding.set('#');
		dontNeedEncoding.set('?');
		dontNeedEncoding.set(':');
		dontNeedEncoding.set('@');
		
		dontNeedEncoding.set('-');
		dontNeedEncoding.set('_');
		dontNeedEncoding.set('.');
		dontNeedEncoding.set('*');
		dontNeedEncoding.set('!');
		dontNeedEncoding.set('$');
		dontNeedEncoding.set('&');
		dontNeedEncoding.set('(');
		dontNeedEncoding.set(')');
		dontNeedEncoding.set('/');
		dontNeedEncoding.set('*');
		dontNeedEncoding.set('+');
		dontNeedEncoding.set(',');
		dontNeedEncoding.set(';');
		dontNeedEncoding.set('=');

	}

	
	public static String encode(String url) {
		return encode(url, dfltEncName);
	}

	public static String encode(String urlString, String encoding) {
		try {
			URL url = new URL(urlString);
			StringBuilder urlStrBuilder = new StringBuilder();
			int port = url.getPort();
			String path = url.getPath();
			String query = url.getQuery();
			urlStrBuilder.append(url.getProtocol())
							.append("://")
							.append(url.getHost())
							.append(port > 0 ? ":" + port : "");
			
			if (path != null && !path.isEmpty()) {
				path = encodeString(path, encoding);
				urlStrBuilder.append(path);
			}
			if (query != null && !query.isEmpty()) {
				query = encodeString(query, encoding);
				urlStrBuilder.append("?").append(query);
			}
			return urlStrBuilder.toString();
		} catch (Exception e) {
			return urlString;
		}
	}

	private static String encodeString(String s, String enc) throws UnsupportedEncodingException {
		boolean needToChange = false;
		StringBuffer out = new StringBuffer(s.length());
		Charset charset;
		CharArrayWriter charArrayWriter = new CharArrayWriter();
		if (enc == null)
			throw new NullPointerException("charsetName");
		try {
			charset = Charset.forName(enc);
		} catch (IllegalCharsetNameException e) {
			throw new UnsupportedEncodingException(enc);
		} catch (UnsupportedCharsetException e) {
			throw new UnsupportedEncodingException(enc);
		}

		for (int i = 0; i < s.length();) {
			int c = (int) s.charAt(i);
			if (dontNeedEncoding.get(c)) {
				out.append((char) c);
				i++;
			} else {
				do {
					charArrayWriter.write(c);
					if (c >= 0xD800 && c <= 0xDBFF) {
						if ((i + 1) < s.length()) {
							int d = (int) s.charAt(i + 1);
							if (d >= 0xDC00 && d <= 0xDFFF) {
								charArrayWriter.write(d);
								i++;
							}
						}
					}
					i++;
				} while (i < s.length() && !dontNeedEncoding.get((c = (int) s.charAt(i))));

				charArrayWriter.flush();
				String str = new String(charArrayWriter.toCharArray());
				byte[] ba = str.getBytes(charset);
				for (int j = 0; j < ba.length; j++) {
					out.append('%');
					char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
					if (Character.isLetter(ch)) {
						ch -= caseDiff;
					}
					out.append(ch);
					ch = Character.forDigit(ba[j] & 0xF, 16);
					if (Character.isLetter(ch)) {
						ch -= caseDiff;
					}
					out.append(ch);
				}
				charArrayWriter.reset();
				needToChange = true;
			}
		}
		return (needToChange ? out.toString() : s);
	}

}