`
mayday85
  • 浏览: 46237 次
  • 性别: Icon_minigender_1
  • 来自: 污点星狗屎国
文章分类
社区版块
存档分类
最新评论

Spring MVC 文件下载最佳实践

 
阅读更多

不知道起这个标题是不是因为我有妄想症
坐等拍砖

私以为
在使用一个框架时,程序员分为三种级别
1.看demo开发
2.看文档开发
3.看源码开发

明显1不如2,2不如3
但是考虑时间成本3不如2,2不如1

我的原则是
有好的demo不看文档,有好的文档不看源码

对于文件下载,再简单不过了,但我比较傻,不会自己写
于是在google搜索"Spring mvc 3 download",demo版本都差不多

        @RequestMapping("download")
        public void download(HttpServletResponse res) throws IOException {
            OutputStream os = res.getOutputStream();
            try {
                res.reset();
                res.setHeader("Content-Disposition", "attachment; filename=dict.txt");
                res.setContentType("application/octet-stream; charset=utf-8");
                os.write(FileUtils.readFileToByteArray(getDictionaryFile()));
                os.flush();
            } finally {
                if (os != null) {
                    os.close();
                }
            }
        }


因为鄙人强烈的精神洁癖,心中大骂
“这样的狗屁代码也贴在网上?”

既然使用了mvc,怎么还能暴露HttpServletResponse这样的j2ee接口出来!

我相信spring提供了更好的方式,于是开始翻阅文档,得出如下代码

    @RequestMapping("download")
    public ResponseEntity<byte[]> download() throws IOException {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", "dict.txt");
        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(getDictionaryFile()),
                                          headers, HttpStatus.CREATED);
    }


理论上没问题,实现上很优雅
但是文件下载后内容如下

"YWEJMQ0KdnYJMg0KaGgJMw=="


正确内容为
aa	1
vv	2
hh	3


我把代码改为
ResponseEntity<String>


输出如下
"aa    1\n\tvv	   2\n\thh	3"


相信很多人看到这已经知道了发生了什么
但是因为本人狗屎一样的基础知识,又浪费了几小时

先去看了ByteArrayHttpMessageConverter的源码
        public ByteArrayHttpMessageConverter() {
		super(new MediaType("application", "octet-stream"), MediaType.ALL);
	}
        ...
        protected void writeInternal(byte[] bytes, HttpOutputMessage outputMessage) throws IOException {
		FileCopyUtils.copy(bytes, outputMessage.getBody());
	}

没感觉到有任何问题

捉耳挠腮了一阵子,又去看AnnotationMethodHandlerAdapter

        public AnnotationMethodHandlerAdapter() {
		// no restriction of HTTP methods by default
		super(false);

		// See SPR-7316
		StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
		stringHttpMessageConverter.setWriteAcceptCharset(false);
		this.messageConverters = new HttpMessageConverter[]{new ByteArrayHttpMessageConverter(), stringHttpMessageConverter,
				new SourceHttpMessageConverter(), new XmlAwareFormHttpMessageConverter()};
	}

        public void setMessageConverters(HttpMessageConverter<?>[] messageConverters) {
		this.messageConverters = messageConverters;
	}


再去看MappingJacksonHttpMessageConverter
extends AbstractHttpMessageConverter[color=red]<Object>[/color]


突然有一种自己是个傻逼的感觉,浪费了大概3、4个小时

修改xml

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                [color=red]<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>[/color]
                <bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" >
                    <property name = "supportedMediaTypes">
                        <list>
                            <value>text/plain;charset=UTF-8</value>
                        </list>
                    </property>
                </bean>
            </list>
        </property>
    </bean>


终于如我所愿了

记录一下我这几个小时干的蠢事
顺便想说,每个例子和demo最好都以最佳实践去写
这样我这种菜鸟程序员就没机会去看源码了~
分享到:
评论
14 楼 cy3456 2018-01-20  
xiejx618 写道
用你的狗屁代码在IE8不能下,在chrome可以下,用你贴出来别人的代码是行的哦

楼主的代码有一处小错误而已,返回码给的是201,改成返回200也就是HttpStatus.OK后在ie下就好了
13 楼 wangxin_cool 2014-01-20  
LZ,我在弄一个Excel下载,发现,Excel名称是中文名时,文件名称筹码了,但内容是正确了,弄了半天没结果。能给点提示么。
12 楼 wangxin_cool 2014-01-16  
LZ我也是在别处看到你这帖子,然后找原贴来顶你。
11 楼 hongyuan19 2013-11-21  
zp820705 写道
请问:ResponseEntity<byte[]> 和 FileUtils.readFileToByteArray(getDictionaryFile())这样操作是不是先在服务器端把所有文件数据先LOAD到内存在输出到客户端!?如果文件有20G或200G的一个文件(云存储系统这很正常),咋办?可以使用流吗,在SPRINGMVC的官方文档中我在寻找中,还没有找到,请教下,想偷下懒!~


应该是先load到内存,而且FileUtils.readFileToByteArray本身也是有限制的,测试了一个5G多的文件,直接超出限制了,还是得用response直接来操作
10 楼 xingchensuifeng 2013-07-15  
    好吧,路过,说点看法,当然,我是初学者。
    首先呢,个人觉得,不要随意批评一个人的代码(指愿意在网上分享自己解决问题代码的,或许,你不认为,人家的代码不管是否优雅,但或许给你启示,或许能暂时帮你解决问题,是否使用,是个人的选择,学会感恩。),
    其次呢,看了你分享的代码,怎么说呢,建议,在分享代码的时候,写完整的成功的例子,不要中途把你出错的搞出来,思路太乱了,别人不是来看你怎么出错,怎么解决的,一堆写着,人都绕晕了。
    完整的成功的例子,解释参数,选项,配置,参考文档等等。有序的、清晰的,是否会觉得优雅些?或许有人看了你的成功的例子会出错,别人会提问,你或许愿意,可以选择再针对回答。
    最后呢,个人也不喜欢凌乱的代码,凌乱的思维。当然,有时候,没办法,为了实现某些东西,而技术又不到家,只能写出很垃圾的代码来实现。
    好吧,感谢你分享这篇文章。
9 楼 xiejx618 2013-07-06  
用你的狗屁代码在IE8不能下,在chrome可以下,用你贴出来别人的代码是行的哦
8 楼 kesun_shy 2013-06-26  
怎么进入方法。返回是去找根据视图解析配置去找jsp
7 楼 mayday85 2013-03-06  
zp820705 写道
mayday85 写道
zp820705 写道
请问:ResponseEntity<byte[]> 和 FileUtils.readFileToByteArray(getDictionaryFile())这样操作是不是先在服务器端把所有文件数据先LOAD到内存在输出到客户端!?如果文件有20G或200G的一个文件(云存储系统这很正常),咋办?可以使用流吗,在SPRINGMVC的官方文档中我在寻找中,还没有找到,请教下,想偷下懒!~


我没试过这么大的文件啊……你试过之后能告诉我一下么?


我是这样看的:
1.虽然可能单个文件下,如果并发高的时候,比如并发秒级1K,10K,100K,这种情况,可能你服务器的内存有点HOLD不住。
2.原来做云存储的时候,20G的文件是常见情况,规格里面都需要明确的。因为现在一个1080P的电影,很容易就20G。其他专业文件可能更大。
我这里也正在为现在的公司封装基础框架,其中也有下载,一般文件下载,我喜欢指定缓存大小,直接通过文件输入流向servlet输出流输出,这样可以控制服务器使用内存大小。


这么专业的功能可能还是用原生的更好,做通用的东西,难免到最后不伦不类
不过你有没有研究一下只用spring的接口能不能控制缓存大小?
6 楼 zp820705 2013-02-26  
mayday85 写道
zp820705 写道
请问:ResponseEntity<byte[]> 和 FileUtils.readFileToByteArray(getDictionaryFile())这样操作是不是先在服务器端把所有文件数据先LOAD到内存在输出到客户端!?如果文件有20G或200G的一个文件(云存储系统这很正常),咋办?可以使用流吗,在SPRINGMVC的官方文档中我在寻找中,还没有找到,请教下,想偷下懒!~


我没试过这么大的文件啊……你试过之后能告诉我一下么?


我是这样看的:
1.虽然可能单个文件下,如果并发高的时候,比如并发秒级1K,10K,100K,这种情况,可能你服务器的内存有点HOLD不住。
2.原来做云存储的时候,20G的文件是常见情况,规格里面都需要明确的。因为现在一个1080P的电影,很容易就20G。其他专业文件可能更大。
我这里也正在为现在的公司封装基础框架,其中也有下载,一般文件下载,我喜欢指定缓存大小,直接通过文件输入流向servlet输出流输出,这样可以控制服务器使用内存大小。
5 楼 mayday85 2013-02-26  
zp820705 写道
请问:ResponseEntity<byte[]> 和 FileUtils.readFileToByteArray(getDictionaryFile())这样操作是不是先在服务器端把所有文件数据先LOAD到内存在输出到客户端!?如果文件有20G或200G的一个文件(云存储系统这很正常),咋办?可以使用流吗,在SPRINGMVC的官方文档中我在寻找中,还没有找到,请教下,想偷下懒!~


我没试过这么大的文件啊……你试过之后能告诉我一下么?
4 楼 tv151579 2013-01-26  
感谢楼主帖子解决我的难题!特此一顶!
3 楼 zp820705 2013-01-22  
请问:ResponseEntity<byte[]> 和 FileUtils.readFileToByteArray(getDictionaryFile())这样操作是不是先在服务器端把所有文件数据先LOAD到内存在输出到客户端!?如果文件有20G或200G的一个文件(云存储系统这很正常),咋办?可以使用流吗,在SPRINGMVC的官方文档中我在寻找中,还没有找到,请教下,想偷下懒!~
2 楼 mayday85 2013-01-04  
hoarhoar 写道
超赞,我在别处看到你的帖子,特找到出处,来顶你。


谢谢……写了以后一直无人问津呢,你是正好遇到这样的问题么?
1 楼 hoarhoar 2012-12-29  
超赞,我在别处看到你的帖子,特找到出处,来顶你。

相关推荐

    Spring MVC 文件上传下载 后端 - Java.zip

    通过阅读"Spring MVC 文件上传下载 后端 - Java.doc"文档,你可以深入理解如何在实际项目中实现这些功能,包括具体的代码示例、配置细节和最佳实践。这份文档可能会涵盖以上所有知识点,帮助开发者更好地掌握Spring ...

    Spring MVC jar包

    而`spring-framework-2.5.6-with-docs.zip`可能包含了Spring 2.5.6的源码和文档,帮助开发者了解Spring MVC的内部实现和最佳实践。 总之,这个压缩包提供了开发基于Spring MVC和Hibernate的Java Web应用所需要的...

    【面试资料】-(机构内训资料)看透Spring MVC源代码分析与实践.zip

    这份【面试资料】-(机构内训资料)看透Spring MVC源代码分析与实践.zip文件很可能是为了帮助求职者准备相关面试问题而设计的,包含了对Spring MVC工作原理、关键组件和源码解读的详尽解析。 1. **Spring MVC基本...

    Spring MVC 4.2.4.RELEASE 中文文档v

    综上所述,Spring MVC 4.2.4.RELEASE 中文文档详细阐述了如何使用 Spring MVC 构建企业级 Web 应用程序,并且提供了全面的指导和最佳实践。对于希望深入学习和掌握 Spring MVC 的开发者而言,这是一份宝贵的学习资料...

    简单实用spring MVC教程

    常见问题与最佳实践** - 使用 ModelAttribute 绑定复杂对象时,要考虑数据验证。 - 使用 RESTful 风格的 URL 设计,提高可读性和可维护性。 - 了解并合理使用各种注解,避免过度配置。 通过这个简单的 Spring MVC ...

    《精通Spring MVC 4》源码

    通过仔细阅读和分析这些源代码,开发者不仅可以提升对Spring MVC框架的理解,还能学习到设计模式、性能优化和最佳实践,从而在实际项目中更有效地应用Spring MVC。无论是初学者还是经验丰富的开发者,都应该充分利用...

    Spring mvc整合mybatis例子

    7. **最佳实践** - 使用@Autowired注解进行依赖注入,减少XML配置。 - 利用Spring的AOP实现事务管理,确保数据一致性。 - 使用MyBatis的动态SQL功能,使SQL更易于维护和调整。 综上所述,整合Spring MVC和...

    Spring MVC 4.2.4.RELEASE 中文文档

    Web 安全的介绍部分涉及了安全方面的配置和最佳实践。"约定优于配置"的概念意味着在 Spring MVC 中有一些约定俗成的默认行为,减少了配置的工作量。 HTTP 缓存支持是关于如何在 Spring MVC 中使用 HTTP 缓存控制头...

    基于spring mvc、spring、hibernate、bootstrap、maen开发的企业级项目,导入即可运行

    在本项目中,这些技术的整合使用体现了现代企业级应用开发的最佳实践。Spring MVC和Spring负责后端逻辑,Hibernate处理数据库操作,Bootstrap则为前端界面提供美观的设计。Maven作为项目管理工具,确保所有依赖项...

    spring-mvc-showcase

    首先,"spring-mvc-showcase" 是 SpringSource 提供的一个示例应用,用于展示 Spring MVC 的各种特性和最佳实践。这个项目包含了一系列精心设计的示例,涵盖了从基本请求处理到复杂业务逻辑的多种场景,是学习 ...

    Spring MVC与MYBatis企业应用实战.pdf

    5. **最佳实践** - 数据库设计:遵循正常化原则,优化表结构和索引。 - SQL优化:避免全表扫描,合理使用JOIN,减少子查询。 - 分页查询:使用MyBatis的LIMIT分页,避免内存溢出。 - 缓存策略:结合Redis或 ...

    Spring mvc指南+Spring mvc入门

    本指南将深入探讨 Spring MVC 的核心概念、配置、控制器、数据绑定、视图解析以及实际应用中的最佳实践。 首先,我们来理解 MVC 设计模式。MVC 将应用程序分为三个主要部分:模型(Model)、视图(View)和控制器...

    spring mvc示例

    6. **最佳实践** - 使用注解驱动,减少XML配置。 - 遵循单一职责原则,保持Controller方法简洁。 - 利用Spring Data简化数据访问层。 - 使用ModelAndView谨慎,尽量避免直接返回视图名,以提高代码的可...

    springmvc项目源码

    通过深入学习这个 Spring MVC 项目源码,你可以掌握 MVC 设计模式的运用,了解 Spring 框架的组件协同工作方式,以及在实际项目中的最佳实践。这将有助于提升你的 Java Web 开发技能,更好地理解和使用 Spring MVC。

    spring MVC完整jar包 内含基本springMVC架构所必需的jar包文件夹

    5. **最佳实践** - 使用Maven或Gradle进行依赖管理,避免手动添加和更新jar包。 - 利用Spring Boot简化Spring MVC的配置,自动配置大部分功能。 - 使用注解驱动开发,减少XML配置。 - 采用RESTful风格设计API,...

    Spring MVC整合shiro

    7. **最佳实践** - 将Shiro配置与Spring的Bean管理相结合,便于维护和扩展。 - 在Web层进行权限控制,避免过多的业务逻辑与权限相关代码混合。 - 合理设计权限体系,避免过度复杂导致管理困难。 以上就是关于...

    《Java EE企业级应用开发教程Spring+Spring MVC+MyBatis》_源代码.zip

    7. **Chapter 12** - Spring MVC高级特性和最佳实践:探讨Spring MVC的高级特性,如上传下载、拦截器、异步处理和模板引擎。同时,提供一些在实际项目中提高代码质量和可维护性的最佳实践。 8. **Chapter 15** - ...

Global site tag (gtag.js) - Google Analytics