SherryLang / javalearning

while(Java){ learn !! }
3 stars 1 forks source link

文件上传问题&Spring通信相关常用注解 #9

Open SherryLang opened 7 years ago

SherryLang commented 7 years ago

遇到的第一个难题:文件上传

问题一:无法读到文件内容

Javabean也配置了,前端也设置了content-type,后端也试了好几种注解方式……(参考网上各种示例),参考的github代码avinashbabudonthu/SpringBootFileUpload可以运行,正确的数据格式如下: http request

对照发现自己前端发的数据格式并没有问题,但是后端的接口中一直读不到文件的数据(file=null)…… fileupload-FILE=NULL 于是找后端的接口问题,重建controller也没搞定,于是在师父指导下查找对照环境配置,发现application.properties中有两个变量没有加,分别是:

spring.http.multipart.max-file-size=10MB
spring.http.multipart.max-request-size=10MB

同时删除之前从网上copy的config文件,代码如下:

package com.hikvision.rensu.cert.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
@Configuration
public class FileUploadConfig {
    @Bean(name = "multipartResolver")
    public MultipartResolver multipartResolver(){
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setDefaultEncoding("UTF-8");
        resolver.setResolveLazily(true);
        resolver.setMaxInMemorySize(40960);
        resolver.setMaxUploadSize(50*1024*1024);
        return resolver;
    } 
}

操作之后就读到文件了。之前带文件的http请求肯定是因为不符合某些条件被拦截了。 后来发现单独删除config文件就可以搞定,和application.properties中的配置无关(不过还是加上比较好,毕竟对文件大小限制了一下更加可靠咯。

问题二:返回数据格式错误415

然而还没结束。使用前后端分离架构之后,函数返回的字符串是对了(“file upload success”),但是前端依旧是报错415。

error:"Unsupported Media Type"
exception:"org.springframework.web.HttpMediaTypeNotSupportedException"
message:"Content type 'multipart/form-data;boundary=----WebKitFormBoundaryXmBj0U01YEMQfmml;charset=UTF-8' not supported"
path:"/inspections/save.do"
status:415
timestamp:1495022474079

后端的整个过程都正常,返回String对象也很合理,肯定是不符合前端处理的数据格式,看了一下以前工程的代码,是包装成Json数据返回,于是找办法包装成Json对象。

查了半天,还是segmentfault的一个帖子解决了我的问题,兴奋!

在你的Controller上加上@RestController注解就行了,springboot会自动帮你转换为json; 用上述方法,整个controller里都会返回Json,在方法上加上@ResponseBody,就只有方法返回Json对象

想起以前做前端的时候,接口中写上@ResponseBody的,都是以Json数据返回,这次问题解决之后真是印象深刻了。

后续问题

如何包装Json数据,加入status状态码、错误信息等内容?

自定义返回结果类,继承Json对象?

常见注解 @RequestMapping, @RequestParam, @RequestBody

另外,几个controller中的注解作用如下:

@RequestMapping

RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

RequestMapping注解有六个属性,下面分成三类进行说明:

1. value, method

value: 指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明); method: 指定请求的method类型, GET、POST、PUT、DELETE等;

2. consumes,produces

consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html; produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;

3. params,headers

params: 指定request中必须包含某些参数值是,才让该方法处理。 headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。

@RequestParam

这个注解用来绑定单个请求数据,既可以是url中的参数,也可以是表单提交的参数和上传的文件 它有三个属性,value用于设置参数名,defaultValue用于对参数设置默认值,required为true时,如果参数为空,会报错 springMVC默认根据参数名字来绑定,而不是参数位置 使用包装类型,否则如果不传值,会报错 使用@RequestParam(value="")来改变参数名字 使用@RequestParam(defaultValue=""),不传参时,使用默认值 使用@RequestParam(required=true),强制必须传参数 示例:

@RequestMapping(value = "/hello1.htm")
public String hello1(ModelMap modelMap,Integer param1, int param2) {
    modelMap.addAttribute("param1", param1);
    modelMap.addAttribute("param2", param2);
    return "hello";
}

请求为:http://localhost:8080/hello1.htm?param1=1&param2=2 如果页面上表单里的参数和代码里的参数名不一样,用注解@RequestParam:

@RequestMapping(value = "/hello1.htm")
public String hello1(ModelMap modelMap, @RequestParam(value = "paramTest") Integer param1, Integer param2) {
    modelMap.addAttribute("param1", param1);
    modelMap.addAttribute("param2", param2);
    return "hello";
}

@RequestBody

该注解常用来处理Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等; 它是通过使用HandlerAdapter 配置的HttpMessageConverters来解析post data body,然后绑定到相应的bean上的。 示例代码

// JS代码
var cartId = 1;
$.ajax({
    url: ctx + '/management/cart/delete',
    async: false,
    cache: false,
    type: "POST",
    contentType: "application/json",
    data: cartId,
    success: function (data) {  },
   error: function (xhr) {   }
});

// Java代码
@ResponseBody
@RequestMapping(value = "/delete", method = RequestMethod.POST)
public int delete(@RequestBody Integer id) {
    return 0;
}

@RequestBody 接收的是一个Json对象的字符串,而不是一个Json对象。 然而在ajax请求往往传的都是Json对象,后来发现用 JSON.stringify(data)的方式就能将对象变成字符串。同时ajax请求的时候也要指定contentType:"application/json"这样就可以轻易的将一个对象或者List传到Java端,使用@RequestBody即可绑定对象或者List.

var  params = [1,2,3];
$.ajax({
    url: ctx + '/management/cart/delete',
    async: false,
    cache: false,
    type: "POST",
    contentType: "application/json",
    data: JSON.stringify(params),
    success: function (data) { },
    error: function (xhr) { } 
});
@ResponseBody
@RequestMapping(value = "/deletes", method = RequestMethod.POST)
public int deletes(@RequestBody List<Integer> ids) {
    return 0;
}

参考资料: http://www.cnblogs.com/samwang88/p/6598919.html http://blog.csdn.net/walkerjong/article/details/7946109 http://blog.csdn.net/u010412719/article/details/69710480 http://www.cnblogs.com/nicekk/p/6072130.html