作为服务端

最好要设置编码方式的解析,url的解析

作为客户端

下载url需要取请求服务端
如果是浏览器访问的话,相当于浏览器帮你做了url的encode是可以下载的
如果用代码的话,一般如下:

  1. public static String downLoadFromUrl(String urlStr, String fileName, String savePath) {
  2. try {
  3. URL url = new URL(urlStr);
  4. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  5. // 设置超时间为30秒
  6. conn.setConnectTimeout(60 * 1000);
  7. // 防止屏蔽程序抓取而返回403错误
  8. conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
  9. // 得到输入流
  10. InputStream inputStream = conn.getInputStream();
  11. // 获取自己数组
  12. byte[] getData = readInputStream(inputStream);
  13. // 文件保存位置
  14. File saveDir = new File(savePath);
  15. if (!saveDir.exists()) {
  16. saveDir.mkdir();
  17. }
  18. File file = new File(saveDir + File.separator + fileName);
  19. FileOutputStream fos = new FileOutputStream(file);
  20. fos.write(getData);
  21. if (fos != null) {
  22. fos.close();
  23. }
  24. if (inputStream != null) {
  25. inputStream.close();
  26. }
  27. return saveDir + File.separator + fileName;
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. }
  31. return "";
  32. }

第十行会报错FileNotFound.类似这样

  1. java.io.FileNotFoundException: http://www.zzgcjyzx.com:8087/Front/AttachStorage/202101/J070/ff6ee790-137a-4807-bab0-6622339e0321/[E3506010601800136042001]国泰新点测试项目20210118新接口测试项目-1.ZZZF
  2. at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1896)
  3. at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1498)
  4. at com.dfit.api.junziqian.service.SignFileUtils.downLoadFromUrl(SignFileUtils.java:29)
  5. at com.dfit.api.basic.controller.ProcessControllerTest.t2(ProcessControllerTest.java:55)
  6. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  7. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  8. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  9. at java.lang.reflect.Method.invoke(Method.java:498)
  10. at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
  11. at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
  12. at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
  13. at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
  14. at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
  15. at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
  16. at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
  17. at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
  18. at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
  19. at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
  20. at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
  21. at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
  22. at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
  23. at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
  24. at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
  25. at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
  26. at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
  27. at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
  28. at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
  29. at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
  30. at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

解决办法

方法1:url特殊部分进行encode

  1. @Test
  2. public void t3() throws Exception {
  3. String a = "http://www.zzgcjyzx.com:8087/Front/AttachStorage/202101/J070/ff6ee790-137a-4807-bab0-6622339e0321/";
  4. String b = "[E3506010601800136042001]国泰新点测试项目20210118新接口测试项目-1.ZZZF";
  5. String realUrl=a+URLEncoder.encode(b,"UTF-8");
  6. System.out.println(realUrl);
  7. String fileName = StringUtils.substringAfterLast(urls,"/");
  8. SignFileUtils.downLoadFromUrl(realUrl, fileName, fileDir);
  9. }

方法2:用http直接请求

hutool请求

  1. String urls = "http://www.zzgcjyzx.com:8087/Front/AttachStorage/202101/J070/ff6ee790-137a-4807-bab0-6622339e0321/[E3506010601800136042001]国泰新点测试项目20210118新接口测试项目-1.ZZZF";
  2. String fileDir = "d:/filestore/";
  3. @Test
  4. public void t1() throws Exception {
  5. String fileName = StringUtils.substringAfterLast(urls,"/");
  6. HttpUtil.downloadFile(urls, fileDir+fileName);
  7. }

总结

两种思路都有一定局限性
方法1好像不知道特殊的符号在哪里
方法2暂时还不知道有啥问题
方法1优化:

  1. HuTool URLUtil的方法可以帮我们对url进行转义
  2. public static String normalize(String url, boolean isEncodePath) {
  3. if (StrUtil.isBlank(url)) {
  4. return url;
  5. }
  6. final int sepIndex = url.indexOf("://");
  7. String protocol;
  8. String body;
  9. if (sepIndex > 0) {
  10. protocol = StrUtil.subPre(url, sepIndex + 3);
  11. body = StrUtil.subSuf(url, sepIndex + 3);
  12. } else {
  13. protocol = "http://";
  14. body = url;
  15. }
  16. final int paramsSepIndex = StrUtil.indexOf(body, '?');
  17. String params = null;
  18. if (paramsSepIndex > 0) {
  19. params = StrUtil.subSuf(body, paramsSepIndex);
  20. body = StrUtil.subPre(body, paramsSepIndex);
  21. }
  22. if (StrUtil.isNotEmpty(body)) {
  23. // 去除开头的\或者/
  24. //noinspection ConstantConditions
  25. body = body.replaceAll("^[\\\\/]+", StrUtil.EMPTY);
  26. // 替换多个\或/为单个/
  27. body = body.replace("\\", "/").replaceAll("//+", "/");
  28. }
  29. final int pathSepIndex = StrUtil.indexOf(body, '/');
  30. String domain = body;
  31. String path = null;
  32. if (pathSepIndex > 0) {
  33. domain = StrUtil.subPre(body, pathSepIndex);
  34. path = StrUtil.subSuf(body, pathSepIndex);
  35. }
  36. if (isEncodePath) {
  37. path = encode(path);
  38. }
  39. return protocol + domain + StrUtil.nullToEmpty(path) + StrUtil.nullToEmpty(params);
  40. }

在方法1放url的地方,对url部分进行转义即可,还是同事老哥厉害