我想在开发Web项目的过程中,免不了的功能,应该就是上传和下载了吧。虽然这个功能很常见,但是我想,遇到坑的也不是一两个了吧。所以,就用这篇文章来写一写,在这开发中的问题。
关于上传的问题,这个还算好解决,没有什么大问题,在上传的时候,路径的话,可以选择为本地路径,或者为服务器的路径,如果是公司开发项目的话,这个肯定是放在服务器的某个目录下面的,或者放在存储云上(比如,七牛云存储,这个个人还是觉得比较好的),所以,上传的问题不是很多,而且在我的另外的文章中,对这个已经进行了几种方法的代码演示,所以这里就不进行过多描述了,如果不是很明白的,可以看看另外一篇文章“手把手教你玩转SpringMvc”。。。
咳咳,好了,进入本篇文章的正题了。关于下载文件的话,也同样有两种,一种就是下载本地的路径上的文件。比如:”C:\helloworld.pdf“,另外一种就是从远程服务器进行下载对应url的文件,就比如http://p09v5ioet.bkt.clouddn.com/797ec79c-56c2-4d7d-98d9-aeaa705fd336.pdf,其实就是网络资源。。好了,重点来了,发现两种路径有啥最大的不同了吗?是的,如果是本地的话,那么其实运用下载的时候使用的就是file协议,而当进行的是网络资源的时候,那么就会出现http,或者https这类似的协议(这两种用得是最多的)。所以,协议都不一样,那么通过不同的方法,肯定实现的方法也就会有差别了。下面的话,就介绍针对不同的情况,来进行文件的下载。
第一种:下载本地路径的文件
如果想实现的是这种情况的文件下载的话,可以采取最初的servlet的文件流下载的代码,这个不是很难,可以直接百度就可以明白。这里,说一下,如何基于SpringMVC框架的一种很清晰,明了的一种写法。
@ResponseBody
@RequestMapping(value = "/downloadcontract")
public ResponseEntity<byte[]> downLoadCurrentContract(Long id , String fileUrl , HttpServletRequest request,
HttpServletResponse response) throws Exception {
//这种方法只能读本地的文件,切记切记切记
try {
File file=new File(fileUrl);
HttpHeaders headers = new HttpHeaders();
String fileName = "合同文件.doc";
fileName = new String(fileName.getBytes("UTF-8"),"iso-8859-1");//为了解决中文名称乱码问题
headers.setContentDispositionFormData("attachment", fileName);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),
headers, HttpStatus.CREATED);
} catch (Exception e) {
e.printStackTrace();
//throw new RuntimeException("文件流内容读取错误");
}
return null;
这种方法是不是很简单呢?但是。请特别的记住一下,如果用这样的方式去请求下载一个网络资源的url的文件的话,那么在使用这个方法的时候,就会报一个”文件路径无法不存在“的错误,但是呢,直接在浏览器通过url进行访问的话,就会直接下载了对应的文件,这是为什么呢?其实,很简单,这是由于这种方法,它只能够进行本地文件的下载。所以,使用的时候注意一下就好了。
第二种:远程文件下载
直接上代码吧。远程的含义就不多说了,就是网络资源路径。。。。。。。。。
方法一:
@ResponseBody
@RequestMapping(value = "/downloadcontract")
public void downLoadCurrentContract(Long id , String fileUrl , HttpServletRequest request, HttpServletResponse response) throws Exception {
int pointIndex = fileUrl.lastIndexOf(".");
BufferedInputStream bis ;
//如果有找到符号".",
if(pointIndex != -1) {
String fileName = "合同文件" + fileUrl.substring(pointIndex, fileUrl.length());
URL url = new URL(fileUrl);
URLConnection conn = url.openConnection();
int filesize = conn.getContentLength(); // 取数据长度
bis = new BufferedInputStream(conn.getInputStream());
// 清空response
response.reset();
// 文件名称转换编码格式为utf-8,保证不出现乱码,这个文件名称用于浏览器的下载框中自动显示的文件名
response.addHeader("Content-Disposition",
"attachment;filename=" + new String(fileName.getBytes("utf-8"), "iso8859-1"));
response.addHeader("Content-Length", "" + filesize);
BufferedOutputStream os = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
// 从输入流中读入字节流,然后写到文件中
byte[] buffer = new byte[1024];
int nRead;
while ((nRead = bis.read(buffer, 0, 1024)) > 0) { // bis为网络输入流
os.write(buffer, 0, nRead);
}
bis.close();
os.flush();
os.close();
}
大家可以看到,这种方法就能够实现远程文件的下载了,其实就是用的原生的Java网络编程中的URLConnection对象来进行的,之前在学习的时候确实没怎么关注,只是单纯的知道这么个对象,现在回头看看,这才是靠近底层的内容,其他的框架封装的下载方法,很多都是基于这样的一种方法的。
另外,通过这种方法的话,默认下载的地方就是浏览器下载内容的保存地方,而且如果使用的是谷歌浏览器的话,是不会弹出一个对话框的,这是谷歌浏览器默认情况;如果是使用的火狐浏览器的话,那么就会弹出一个对话框来提示用户是否确认进行下载,还是下载完成后直接打开的选择。这是一个需要区分的地方。。
咳咳,还有,就是可能会碰到一个需求就是说,默认将下载的内容,放在一个地方,这样的话,就方便以后对下载文件内容的管理,比如就是想放在”C盘”,那么还可以利用下面的方法进行,其实类似上面的方法,只是提供给需要的人看看好了。
@ResponseBody
@RequestMapping(value = "/downloadcontract")
public void downLoadCurrentContract(Long id , String fileUrl , HttpServletRequest request,
URL theURL = new URL(fileUrl);
String filePath = "C:\\";
URLConnection con = theURL.openConnection();
String urlPath = con.getURL().getFile();
String fileFullName = "合同.doc";
if(fileFullName !=null){
byte[] buffer = new byte[4*1024];
int read;
String path = filePath + "/" +fileFullName;
File fileFolder = new File(filePath);
if(!fileFolder.exists()){
fileFolder.mkdirs();
}
InputStream in = con.getInputStream();
FileOutputStream os = new FileOutputStream(path);
while((read = in.read(buffer)) > 0){
os.write(buffer, 0, read);
}
os.close();
in.close();
}
}
三:网络编程的一些知识点
(1)首先说一下关于网络的两种协议,TCP与UDP