SpringMVC 完美解决PUT请求参数绑定问题(普通表单和文件表单)

一 解决方案

修改web.xml配置文件 将下面配置拷贝进去(在原有的web-app节点里面配置 其它配置不变)

<!-- 处理PUT提交参数(只对基础表单生效) -->
<filter>
    <filter-name>httpPutFormContentFilter</filter-name>
    <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>httpPutFormContentFilter</filter-name>
    <!-- 拦截所有 -->
    <url-pattern>/*</url-pattern>
</filter-mapping>

写一个PostAndPutCommonsMultipartResolver继承CommonsMultipartResolver 重写isMultipart()

/**
 * 处理PUT提交参数(只对文件表单生效)
 * Created by Hy on 2018/9/30.
 */
public class PostAndPutCommonsMultipartResolver extends CommonsMultipartResolver {

    @Override
    public boolean isMultipart(HttpServletRequest request) {
        if ("POST".equalsIgnoreCase(request.getMethod()) || "PUT".equalsIgnoreCase(request.getMethod())) {
            return FileUploadBase.isMultipartContent(new ServletRequestContext(request));
        }
        return false;
    }

}

修改spring-mvc.xml配置文件 将下面配置拷贝进去(在原有的beans节点里面配置 其它配置不变)

<!-- 配置文件上传实现类 -->
<bean id="multipartResolver" class="com.hy.mm.manager.resolver.PostAndPutCommonsMultipartResolver">
    <!-- 设定默认编码 -->
    <property name="defaultEncoding" value="UTF-8" />
    <!-- 文件上传大小(单位B) 30M = 30 * 1024 * 1024 -->
    <property name="maxUploadSize" value="31457280" />
</bean>

写一个Controller

/**
 * PUT请求
 * Created by Hy on 2018/9/30.
 */
@Controller
public class PutController {

    @PutMapping("/put/normal") @ResponseBody
    public String normalForm(String name, Integer age) {
        System.out.println("name = " + name);
        System.out.println("age = " + age);
        return "ok";
    }

    @PutMapping("/put/file") @ResponseBody
    public String fileForm(String name, MultipartFile file) throws Exception {
        System.out.println("name = " + name);
        if (null != file && !file.isEmpty()) {
            System.out.println("file = " + file.getSize());
            // 保存图片
            String fileName = UUID.randomUUID().toString().replace("-", ""); //文件名
            String extension = FilenameUtils.getExtension(file.getOriginalFilename()); //扩展名 不包含(.)
            file.transferTo(new File("/Users/HUANGYI/Downloads/" + fileName + "." + extension));
            return "ok";
        }
        return "error";
    }

}

以上就能完美解决PUT请求参数绑定问题 赶时间的老哥可以忽略下文

 

二 解决思路

先bb一下起因

我最近再重构一个自己的项目 打算把接口交互修改成RESTful风格 浅显的说一下RESTful风格 增删改查对应POST DELETE PUT GET请求

环境

客户端: Android 使用Retrofit发起请求

服务端: Java 使用SpringMVC处理请求

思路

客户端使用PUT请求发送表单数据 不管是普通表单还是文件表单 服务端Controller层参数绑定均为null

但是 客户端使用PUT请求发送非文件数据携带在Url上(类似GET请求) 服务端Controller层参数就能接收到

为了避免重复造轮子 我用Google解决了普通表单数据接收不到 也就是使用上面说的org.springframework.web.filter.HttpPutFormContentFilter就可以解决该问题

但是 文件表单数据还是接收不到 Google也不好用了 不知道是不是我姿势不对

自己尝试解决吧

先验证文件表单数据到底写入请求体没有?

我用logging-interceptor和Charles观察了好几遍请求 确认了数据确实已经写入了请求体

那么 问题肯定就出现在SpringMVC的文件参数绑定上

仔细观察org.springframework.web.multipart.commons.CommonsMultipartResolver

其中 isMultipart()是一个比较重要的方法 用来判断请求是否包含多部分内容 也就是判断是否是文件表单 深入观察一下该方法的实现

真相大白 该方法默认POST请求才可能包含多部分内容

使用上面说的PostAndPutCommonsMultipartResolver就可以解决该问题

Android客户端核心代码

/**
 * ...
 * Created by Hy on 2018/9/30.
 */
public interface PutApi {

    @PUT("/put/normal") @FormUrlEncoded
    Call<ResponseBody> normal(@Field("name") String name, @Field("age") Integer age);

    @PUT("/put/file") @Multipart
    Call<ResponseBody> file(@Part("name") String name, @Part MultipartBody.Part file);
}
@Override
public void onClick(View view) {
    switch (view.getId()) {
        case R.id.normal:
            Call<ResponseBody> normalCall = mApi.normal("黄祎", 18);
            normalCall.enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                    try {
                        Log.i("HUANG", "code = " + response.code());
                        if (null != response.body())
                            Log.i("HUANG", "body = " + response.body().string());

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onFailure(Call<ResponseBody> call, Throwable t) {
                    Log.i("HUANG", "t = " + t.getMessage());
                }
            });

            break;

        case R.id.file:
            RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), copy());
            MultipartBody.Part body = MultipartBody.Part.createFormData("file", "a.mp4", fileBody);
            Call<ResponseBody> fileCall = mApi.file("黄祎", body);
            fileCall.enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                    try {
                        Log.i("HUANG", "code = " + response.code());
                        if (null != response.body())
                            Log.i("HUANG", "body = " + response.body().string());

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onFailure(Call<ResponseBody> call, Throwable t) {
                    Log.i("HUANG", "t = " + t.getMessage());
                }
            });
            break;
    }
}

总结

虽然只是寥寥几句 但是我走完这几步也花了一下午时间 哈哈哈 技术有限技术有限

希望能帮助到你 如果你的问题得到解决 请给个推荐点个赞 这样能帮助到更多人 毕竟搜索不到解决方案的时候太痛苦了

 

转载于:https://www.cnblogs.com/huangyi-427/p/9742000.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值