View Javadoc
1   package com.foxinmy.weixin4j.util;
2   
3   import java.nio.ByteBuffer;
4   import java.nio.charset.Charset;
5   import java.util.BitSet;
6   
7   /**
8    * 
9    * @className URLEncodingUtil
10   * @author jinyu(foxinmy@gmail.com)
11   * @date 2015年8月15日
12   * @since JDK 1.6
13   * @see
14   */
15  public final class URLEncodingUtil {
16  	/**
17  	 * Unreserved characters, i.e. alphanumeric, plus: {@code _ - ! . ~ ' ( ) *}
18  	 * <p>
19  	 * This list is the same as the {@code unreserved} list in <a
20  	 * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>
21  	 */
22  	private static final BitSet UNRESERVED = new BitSet(256);
23  	/**
24  	 * Punctuation characters: , ; : $ & + =
25  	 * <p>
26  	 * These are the additional characters allowed by userinfo.
27  	 */
28  	private static final BitSet PUNCT = new BitSet(256);
29  	/**
30  	 * Characters which are safe to use in userinfo, i.e. {@link #UNRESERVED}
31  	 * plus {@link #PUNCT}uation
32  	 */
33  	private static final BitSet USERINFO = new BitSet(256);
34  	/**
35  	 * Characters which are safe to use in a path, i.e. {@link #UNRESERVED} plus
36  	 * {@link #PUNCT}uation plus / @
37  	 */
38  	private static final BitSet PATHSAFE = new BitSet(256);
39  	/**
40  	 * Characters which are safe to use in a fragment, i.e. {@link #RESERVED}
41  	 * plus {@link #UNRESERVED}
42  	 */
43  	private static final BitSet FRAGMENT = new BitSet(256);
44  
45  	/**
46  	 * Reserved characters, i.e. {@code ;/?:@&=+$,[]}
47  	 * <p>
48  	 * This list is the same as the {@code reserved} list in <a
49  	 * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a> as augmented by
50  	 * <a href="http://www.ietf.org/rfc/rfc2732.txt">RFC 2732</a>
51  	 */
52  	private static final BitSet RESERVED = new BitSet(256);
53  
54  	/**
55  	 * Safe characters for x-www-form-urlencoded data, as per
56  	 * java.net.URLEncoder and browser behaviour, i.e. alphanumeric plus
57  	 * {@code "-", "_", ".", "*"}
58  	 */
59  	private static final BitSet URLENCODER = new BitSet(256);
60  
61  	static {
62  		// unreserved chars
63  		// alpha characters
64  		for (int i = 'a'; i <= 'z'; i++) {
65  			UNRESERVED.set(i);
66  		}
67  		for (int i = 'A'; i <= 'Z'; i++) {
68  			UNRESERVED.set(i);
69  		}
70  		// numeric characters
71  		for (int i = '0'; i <= '9'; i++) {
72  			UNRESERVED.set(i);
73  		}
74  		UNRESERVED.set('_'); // these are the charactes of the "mark" list
75  		UNRESERVED.set('-');
76  		UNRESERVED.set('.');
77  		UNRESERVED.set('*');
78  		URLENCODER.or(UNRESERVED); // skip remaining unreserved characters
79  		UNRESERVED.set('!');
80  		UNRESERVED.set('~');
81  		UNRESERVED.set('\'');
82  		UNRESERVED.set('(');
83  		UNRESERVED.set(')');
84  		// punct chars
85  		PUNCT.set(',');
86  		PUNCT.set(';');
87  		PUNCT.set(':');
88  		PUNCT.set('$');
89  		PUNCT.set('&');
90  		PUNCT.set('+');
91  		PUNCT.set('=');
92  		// Safe for userinfo
93  		USERINFO.or(UNRESERVED);
94  		USERINFO.or(PUNCT);
95  
96  		// URL path safe
97  		PATHSAFE.or(UNRESERVED);
98  		PATHSAFE.set('/'); // segment separator
99  		PATHSAFE.set(';'); // param separator
100 		PATHSAFE.set(':'); // rest as per list in 2396, i.e. : @ & = + $ ,
101 		PATHSAFE.set('@');
102 		PATHSAFE.set('&');
103 		PATHSAFE.set('=');
104 		PATHSAFE.set('+');
105 		PATHSAFE.set('$');
106 		PATHSAFE.set(',');
107 
108 		RESERVED.set(';');
109 		RESERVED.set('/');
110 		RESERVED.set('?');
111 		RESERVED.set(':');
112 		RESERVED.set('@');
113 		RESERVED.set('&');
114 		RESERVED.set('=');
115 		RESERVED.set('+');
116 		RESERVED.set('$');
117 		RESERVED.set(',');
118 		RESERVED.set('['); // added by RFC 2732
119 		RESERVED.set(']'); // added by RFC 2732
120 
121 		FRAGMENT.or(RESERVED);
122 		FRAGMENT.or(UNRESERVED);
123 	}
124 
125 	private static final int RADIX = 16;
126 
127 	public static String encoding(final String content, final Charset charset,
128 			final boolean blankAsPlus) {
129 		if (content == null) {
130 			return null;
131 		}
132 		StringBuilder buf = new StringBuilder();
133 		ByteBuffer bb = charset.encode(content);
134 		while (bb.hasRemaining()) {
135 			int b = bb.get() & 0xff;
136 			if (URLENCODER.get(b)) {
137 				buf.append((char) b);
138 			} else if (blankAsPlus && b == ' ') {
139 				buf.append('+');
140 			} else {
141 				buf.append("%");
142 				char hex1 = Character.toUpperCase(Character.forDigit(
143 						(b >> 4) & 0xF, RADIX));
144 				char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF,
145 						RADIX));
146 				buf.append(hex1);
147 				buf.append(hex2);
148 			}
149 		}
150 		return buf.toString();
151 	}
152 }