SpringMVC文件(图片)上传,下载

终于忍不住想把上传下载记录下来了,因为IO流部分还是有些生疏。

springMVC上传文件依赖包spring-web-xx.xx.jar(根据自己spring版本而定)

1、在springMVC中配置处理上传文件的信息

 <!-- 配置springMVC处理上传文件的信息 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="utf-8"/>
        <property name="maxUploadSize" value="10485760000"/>
        <property name="maxInMemorySize" value="40960"/>
    </bean>

2、文件(图片)上传下载controller


public class ImgController{

	Logger log = Logger.getLogger(ImgController.class);
	
	
	/**
     * 文件上传
     * @param files 待上传文件		[单个文件]
     * @return 上传的文件 文件名
     * @throws Exception
     */
    @RequestMapping(value = "/upload")
	@ResponseBody
	public void upload(@RequestParam("file")CommonsMultipartFile file,HttpServletRequest request,HttpServletResponse response) throws IOException{
    	AppReply<T> reply = new AppReply<T>();
		try {
				String fileName=file.getOriginalFilename();
				//fileName=UuidUtil.get32UUID()+fileName.substring(fileName.lastIndexOf("."), fileName.length());
				FileUpload.upload(file,HTTPUtil.getPath(request), fileName);
				reply.setCode(AppReply.SUCCESS_CODE);
		} catch (Exception e) {
				reply.setCode(AppReply.EORRO_CODE);
				e.printStackTrace();
		}
		ConvertObject2Json.writeJson(reply, request, response);
	}
    
    
	/**
	 * 从本地磁盘上读取图片信息。
	 * 文件下载
	 * @param request
	 * @param response
	 * @throws Exception
	 */
	@RequestMapping(value="/getImg",method=RequestMethod.GET)
	public void readImg(HttpServletRequest request,HttpServletResponse response) throws Exception{
		ServletOutputStream sos = response.getOutputStream(); 
		InputStream in = null;
		try{
			String imgUrl=request.getParameter("url");
			String url=HTTPUtil.getPath(request);
			imgUrl = URLEncoder.encode(imgUrl, "UTF-8");
			response.reset();  
			response.setHeader("Content-Type","image/*");
			response.setHeader("Content-Disposition", "attachment; filename=\"" + imgUrl + "\"");  
		    response.setContentType("application/octet-stream;charset=UTF-8");
		    File myFile = new File(url+"/"+imgUrl);
		    if(!myFile.exists()){
		    	//如果本地没有这个图片,默认从服务器中读取默认图片
		    	String os = System.getProperty("os.name");  
		    	if(os.toUpperCase().contains("WINDOWS")){
		    		String dir = request.getServletContext().getRealPath("\\");
		    		imgUrl = dir+"views\\common\\images\\default_image.jpg";
		    	}else{
		    		String dir = request.getServletContext().getRealPath("//");
		    		imgUrl = dir+"views/common/images/default_image.jpg";
		    	}
		    	in=new BufferedInputStream(new FileInputStream(new File(imgUrl)));
		    }else{
		    	in=new BufferedInputStream(new FileInputStream(new File(url+"/"+imgUrl)));
		    	}
			byte [] content=new byte[1024];
			int length;
			while ((length=in.read(content,0,content.length)) !=-1){
				sos.write(content,0,length);
			}
			sos.flush();
		} catch(Exception e){
			e.printStackTrace();
		}finally{
			sos.close(); 
		}
	}
	
	
	 /**
     * 文件上传
     * @param files 待上传文件		[多个文件]
     * @return 上传的文件 文件名
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/filesUpload")
    public void upload(@RequestParam("files") CommonsMultipartFile[] files,HttpServletRequest request, HttpServletResponse response) throws Exception{
    	AppReply<Object> reply = new AppReply<Object>();
        try {
            for (CommonsMultipartFile file : files) {
            	String fileName=file.getOriginalFilename();
				//fileName=UuidUtil.get32UUID()+fileName.substring(fileName.lastIndexOf("."), fileName.length());
				FileUpload.upload(file,HTTPUtil.getPath(request), fileName);
            }
            reply.setCode(AppReply.SUCCESS_CODE);
        } catch (Exception e) {
        	reply.setCode(AppReply.EORRO_CODE);
        	e.printStackTrace();
        }
        ConvertObject2Json.writeJson(reply, request, response);
    }
    
    
    /**
     * 下载文件(支持单点续传下载)
     * 
     * @param request
     * @param fileId
     * @throws IOException
     */
    @RequestMapping(value = "/downloadImg", method = RequestMethod.GET)
    public void download3(HttpServletRequest request, HttpServletResponse response, @RequestParam("fileName") String fileName)
            throws IOException {
	    	String imgUrl=request.getParameter("fileName");
			String url=HTTPUtil.getPath(request);
			imgUrl = URLEncoder.encode(imgUrl, "UTF-8");
			response.reset();  
			response.setHeader("Content-Type","image/*");
			response.setHeader("Content-Disposition", "attachment; filename=\"" + imgUrl + "\"");  
		    response.setContentType("application/octet-stream;charset=UTF-8");
		    File downloadFile = new File(url+"/"+imgUrl);
		    if(!downloadFile.exists()){
	    	//如果本地没有这个图片,默认从服务器中读取默认图片
	    	String dir = request.getServletContext().getRealPath("\\");
	    	imgUrl = dir+"views\\common\\images\\default_image.png";
	    	downloadFile = new File(imgUrl);
			   }
	        // 记录文件大小
	        long fileLength = downloadFile.length();
	        // 记录已下载文件大小
	        long pastLength = 0;
	        // 0:从头开始的全文下载;
	        // 1:从某字节开始的下载(bytes=1000-);
	        // 2:从某字节开始到某字节结束的下载(bytes=1000-2000)
	        int rangeSwitch = 0;
	        // 记录客户端需要下载的字节段的最后一个字节偏移量(比如bytes=1000-2000,则这个值是为2000)
	        long toLength = 0;
	        // 客户端请求的字节总量
	        long contentLength = 0;
	        // 记录客户端传来的形如“bytes=1000-”或者“bytes=1000-2000”的内容
	        String rangeBytes = "";
	        // 负责读取数据
	        RandomAccessFile raf = null;
	        // 写出数据
	        OutputStream os = null;
	        // 缓冲
	        OutputStream out = null;
	        // 暂存容器
	        byte b[] = new byte[1024];
	
	        if (request.getHeader("Range") != null) {
	            // 客户端请求的下载的文件块的开始字节
	            response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);
	            rangeBytes = request.getHeader("Range").replaceAll("bytes=", "");
	            if (rangeBytes.indexOf('-') == rangeBytes.length() - 1) {
	                // 如:bytes=1000-
	                rangeSwitch = 1;
	                rangeBytes = rangeBytes.substring(0, rangeBytes.indexOf('-'));
	                pastLength = Long.parseLong(rangeBytes.trim());
	                // 客户端请求的是 1000之后的字节
	                contentLength = fileLength - pastLength;
	            } else {
	                // 如:bytes=1000-2000
	                rangeSwitch = 2;
	                String temp0 = rangeBytes.substring(0, rangeBytes.indexOf('-'));
	                String temp2 = rangeBytes.substring(rangeBytes.indexOf('-') + 1, rangeBytes.length());
	                // bytes=1000-2000,从第1000个字节开始下载
	                pastLength = Long.parseLong(temp0.trim());
	                // bytes=1000-2000,到第2000个字节结束
	                toLength = Long.parseLong(temp2);
	                // 客户端请求的是1000-2000之间的字节
	                contentLength = toLength - pastLength;
	            }
	        } else {
	            // 从开始进行下载,客户端要求全文下载
	            contentLength = fileLength;
	        }
	
	        /**
	         * 如果设设置了Content -Length,则客户端会自动进行多线程下载。如果不希望支持多线程,则不要设置这个参数。 响应的格式是:
	         * Content - Length: [文件的总大小] - [客户端请求的下载的文件块的开始字节]
	         * ServletActionContext.getResponse().setHeader("Content- Length", new
	         * Long(file.length() - p).toString());
	         */
	        response.reset();
	        // 告诉客户端允许断点续传多线程连接下载,响应的格式是:Accept-Ranges: bytes
	        response.setHeader("Accept-Ranges", "bytes");
	        // 如果是第一次下,还没有断点续传,状态是默认的 200,无需显式设置;响应的格式是:HTTP/1.1 200 OK
	
	        if (pastLength != 0) {
	            // 不是从最开始下载,响应的格式是:
	            // Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小]
	            String contentRange = "";
	            switch (rangeSwitch) {
	            case 1:
	                // 针对 bytes=1000- 的请求
	                contentRange = new StringBuffer("bytes ").append(new Long(pastLength).toString()).append("-")
	                        .append(new Long(fileLength - 1).toString()).append("/").append(new Long(fileLength).toString())
	                        .toString();
	                response.setHeader("Content-Range", contentRange);
	                break;
	            case 2:
	                // 针对 bytes=1000-2000 的请求
	                contentRange = rangeBytes + "/" + new Long(fileLength).toString();
	                response.setHeader("Content-Range", contentRange);
	                break;
	            default:
	                break;
	            }
	        } 
	        try {
	            response.addHeader("Content-Disposition", "attachment; filename=\"" + downloadFile.getName() + "\"");
	            // 设置 MIME 类型.
	            response.setContentType(CommonUtil.setContentType(downloadFile.getName()));
	            response.addHeader("Content-Length", String.valueOf(contentLength));
	            os = response.getOutputStream();
	            out = new BufferedOutputStream(os);
	            raf = new RandomAccessFile(downloadFile, "r");
	
	            int readNum = 0;
	            long readLength = 0;
	            try {
	                switch (rangeSwitch) {
	                case 0:
	                    // 普通下载,或者从头开始的下载,同1
	                case 1:
	                    // 针对 bytes=1000- 的请求
	                    // 形如 bytes=1000- 的客户端请求,跳过 1000 个字节
	                    raf.seek(pastLength);
	                    readNum = 0;
	                    while ((readNum = raf.read(b, 0, 1024)) != -1) {
	                        out.write(b, 0, readNum);
	                    }
	                    break;
	                case 2:
	                    // 针对 bytes=2000-3000 的请求
	                    // 形如 bytes=2000-3000 的客户端请求,找到第 2000 个字节
	                    raf.seek(pastLength);
	                    readNum = 0;
	                    readLength = 0; // 记录已读字节数
	                    while (readLength <= contentLength - 1024) {
	                        // 大部分字节在这里读取
	                        readNum = raf.read(b, 0, 1024);
	                        readLength += 1024;
	                        out.write(b, 0, readNum);
	                    }
	                    if (readLength <= contentLength) {
	                        // 余下的不足 1024 个字节在这里读取
	                        readNum = raf.read(b, 0, (int) (contentLength - readLength));
	                        out.write(b, 0, readNum);
	                    }
	                    break;
	                default:
	                    break;
	                }
	                out.flush();
	            } catch (IOException ie) {
	                /**
	                 * 在写数据的时候, 对于 ClientAbortException 之类的异常,
	                 * 是因为客户端取消了下载,而服务器端继续向浏览器写入数据时,抛出这个异常,这个是正常的。
	                 */
	            }
	        } catch (Exception e) {
	            log.error(e.getMessage(), e);
	        } finally {
	            if (out != null) {
	                try {
	                    out.close();
	                } catch (IOException e) {
	                    // 远程主机或者本机强制关闭
	                    // log.error(e.getMessage(), e);
	                } finally {
	                    out = null;
	                }
	            }
	            if (raf != null) {
	                try {
	                    raf.close();
	                } catch (IOException e) {
	                    log.error(e.getMessage(), e);
	                } finally {
	                    raf = null;
	                }
	            }
	        }
	    }
}


HTTPUtil.getPath(request)从配置文件中读取路径地址。

ConvertObject2Json.writeJson(reply, request, response),输出的一种方式,可以随意替换。


文中的下载只支持单线程下载,多线程下载请查看:

http://www.cnblogs.com/live365wang/archive/2013/03/02/2939994.html

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值