最近开发需要用到一个下载功能,本人记性不好,脑主存估计只剩下索引了,无奈。
所以下载想用到spring封装好的,使用简单。于是copy到:
/**
* 下载
*/
@RequiresPermissions("pa:in:kpiData:view")
@RequestMapping(value = { "/downloadAtt" })
public ResponseEntity<byte[]> downloadAtt(Model model , HttpServletRequest request)throws Exception {
HttpHeaders headers = new HttpHeaders();
String url = request.getParameter("attUrl");
int num = url.lastIndexOf("\\");
String fileName = url.substring((num + 1), url.length());
fileName=new String(fileName.getBytes("UTF-8"),"iso-8859-1");//为了解决一些浏览器的中文名称乱码问题
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", fileName);
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(new File(url)),
headers, HttpStatus.CREATED);
}
嗯……关键是最后三行,其余没有技术含量。
我这一看,吓一跳,因为以前给某市联通做过绩效,写过上传下载,因为是第n次开发所以代码风格很乱,我也就用了最传统的写法(我才不会告诉你当时太菜鸟,能写出功能就满意,没有甄别的实力)。当时至少还多一倍的代码行数。
spring果然牛,封装得很优雅,搞得我这种脑容量的人都觉得下载是如此简单。然后不禁看了部分源码(推荐直接看试验结果):
public class HttpHeaders implements MultiValueMap<String, String>, Serializable {
private static final long serialVersionUID = -8578554704772377436L;
public static final String ACCEPT = "Accept";
public static final String ACCEPT_CHARSET = "Accept-Charset";
public static final String ACCEPT_ENCODING = "Accept-Encoding";
public static final String ACCEPT_LANGUAGE = "Accept-Language";
public static final String ACCEPT_RANGES = "Accept-Ranges";
public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
public static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
public static final String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method";
public static final String AGE = "Age";
public static final String ALLOW = "Allow";
public static final String AUTHORIZATION = "Authorization";
public static final String CACHE_CONTROL = "Cache-Control";
public static final String CONNECTION = "Connection";
public static final String CONTENT_ENCODING = "Content-Encoding";
public static final String CONTENT_DISPOSITION = "Content-Disposition";
public static final String CONTENT_LANGUAGE = "Content-Language";
public static final String CONTENT_LENGTH = "Content-Length";
public static final String CONTENT_LOCATION = "Content-Location";
public static final String CONTENT_RANGE = "Content-Range";
public static final String CONTENT_TYPE = "Content-Type";
public static final String COOKIE = "Cookie";
.........
哦,header封装的还算好理解。
public class ResponseEntity<T> extends HttpEntity<T> {
private final Object statusCode;
public ResponseEntity(HttpStatus status) {
this((Object)null, (MultiValueMap)null, (HttpStatus)status);
}
public ResponseEntity(T body, HttpStatus status) {
this(body, (MultiValueMap)null, (HttpStatus)status);
}
public ResponseEntity(MultiValueMap<String, String> headers, HttpStatus status) {
this((Object)null, headers, (HttpStatus)status);
}
public ResponseEntity(T body, MultiValueMap<String, String> headers, HttpStatus status) {
super(body, headers);
Assert.notNull(status, "HttpStatus must not be null");
this.statusCode = status;
}.........
ResponseEntity看的有点不知所述,最后一行我传了文件实体,响应头,状态。而这里,实体和响应头交给父类方法处理,状态赋值给了本类的final常量。再看:
public class HttpEntity<T> {
public static final HttpEntity<?> EMPTY = new HttpEntity();
private final HttpHeaders headers;
private final T body;
protected HttpEntity() {
this((Object)null, (MultiValueMap)null);
}
public HttpEntity(T body) {
this(body, (MultiValueMap)null);
}
public HttpEntity(MultiValueMap<String, String> headers) {
this((Object)null, headers);
}
public HttpEntity(T body, MultiValueMap<String, String> headers) {
this.body = body;
HttpHeaders tempHeaders = new HttpHeaders();
if(headers != null) {
tempHeaders.putAll(headers);
}
this.headers = HttpHeaders.readOnlyHttpHeaders(tempHeaders);
}
这个类直接将文件实体赋值给本类final实体,响应头经过处理也同样交给本类final响应头。
看到这里似乎就结束,也没看出个所以然……以本人耐心,我没追究,接着就是试验代码是否正确,于是得到如下:
似乎没问题,然后就打开文件……然后……然后就坑爹了。文件乱码,图片打开失败!
然后只能求助度娘,某同志给出这样一个答案:
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<!-- 将Jackson2HttpMessageConverter的默认格式化输出为false -->
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
<property name="prettyPrint" value="false"/>
<property name="objectMapper">
<bean class="com.csstj.plateform.common.mapper.JsonMapper"></bean>
</property>
</bean>
ByteArrayHttpMessageConverter放在json配置前,如果没有就添加一个。
再试果然ok了。
至于为什么,暂搁置,容我再探究下。