今天要实现的一个功能是在页面上上传文件到后台,文件是txt格式,每行是一个url,后台读取后,对路径中的中文进行url编码
如下是我的代码:
Pattern chinesePattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
MultipartFile file = null;
try {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
file = multipartRequest.getFile("file");
String line = null;
Set<String> urlOrNameSet = new HashSet<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(file.getInputStream(), "GB18030"));//这里其实默认也是用GB18030编码读入
while ((line = reader.readLine()) != null) {
if(StringUtils.isNotBlank(line)) {
line = line.trim();
Matcher matcher = chinesePattern.matcher(line);
while (matcher.find()) {
line = line.replaceAll(matcher.group(), URLEncoder.encode(matcher.group());
}
urlOrNameSet.add(line);
}
}
}
} catch (Exception e) {
logger.error("batch import fail: {}", e);
}
但是发现一个诡异的问题,编码后的路径,是错误的,根本访问不了,见鬼,于是我做了一个单元测试:
@Test
public void testUrl() throws Exception {
String url = "https://baike.baidu.com/item/乒乓球台/2565939";
Pattern chinesePattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
Matcher matcher = chinesePattern.matcher(url);
while (matcher.find()) {
url = url.replaceAll(matcher.group(), URLEncoder.encode(matcher.group()));
}
System.out.println(url);
}
可以看到代码和上面是一模一样的,但是这种方式编码后的路径就可以正常访问,而且的确可以看到,上面编码后的路径和这里单元测试编码后的路径不一样
真是见鬼,代码明明一样,为什么结果不一样,首先想到的应该是编码问题,可是这两个地方的url都是UTF-8的,所以url的编码是一致的,问题不在url这里
最后我想到是否可能是在URLEncoder.encode的过程中出了问题,于是我先进去源码可以看到:
@Deprecated
public static String encode(String s) {
String str = null;
try {
str = encode(s, dfltEncName);
} catch (UnsupportedEncodingException e) {
// The system should always have the platform default
}
return str;
}
可以看到这是个过时的方法,当然这不是重点,重点是这里有一个默认编码dfltEncName,于是我debug看了下,单元测试的地方,这里的默认编码是UTF-8,但是我的项目里面这里居然是GBK,于是我改成了如下代码:
line = line.replaceAll(matcher.group(), URLEncoder.encode(matcher.group(), "UTF-8"));
问题终于得到了解决