SpringBoot一个接口同时支持form表单、form-data、json的优雅写法

前言

小程序向 app 转化,发现小程序是
@RequestParam --- from 表单形式
app 里面常用
@RequestBody ---- json 形式

如果在用app 有些接口得重新 写了。所以写一个
SpringBoot一个接口同时支持form表单、form-data、json的优雅写法
开始

效果

1、get 方法用json


image.png

2、get 方法form 提交

image.png

3、post 方法用json


image.png

4、post方法 form 提交


image.png

动图

GIF 2022-7-22 17-08-24.gif

实现方法

开始地方


image.png

这个是住 切片吗?之前老说只能做log 日志的方法,今天用上了。

import java.lang.annotation.*;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AppRequestParam {
}

开始配置 里面添加

image.png

具体实现


import com.netty.app.annotation.AppRequestParam;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;

import javax.servlet.ServletRequest;
import java.util.ArrayList;
import java.util.List;

public class RequestMethodProcessor implements HandlerMethodArgumentResolver {

    private RequestResponseBodyMethodProcessor jsonResolver;
    private ServletModelAttributeMethodProcessor formResolver;

    public RequestMethodProcessor() {
        List> messageConverters = new ArrayList<>();
        RequestMessageConverter RequestMessageConverter = new RequestMessageConverter();
        messageConverters.add(RequestMessageConverter);

        jsonResolver = new RequestResponseBodyMethodProcessor(messageConverters);
        formResolver = new ServletModelAttributeMethodProcessor(true);
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        AppRequestParam ann = parameter.getParameterAnnotation(AppRequestParam.class);
        return (ann != null);
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        ServletRequest servletRequest = nativeWebRequest.getNativeRequest(ServletRequest.class);
        String contentType = servletRequest.getContentType();
        if (contentType == null) {
            throw new IllegalArgumentException("不支持contentType");
        }

        if (contentType.contains("application/json")) {
            return jsonResolver.resolveArgument(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
        }

        if (contentType.contains("application/x-www-form-urlencoded")) {
            return formResolver.resolveArgument(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
        }

        if (contentType.contains("multipart")) {
            return formResolver.resolveArgument(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
        }

        throw new IllegalArgumentException("不支持contentType");
    }
}

代码是从


image.png

这里复制的。。程序员不骗程序员

这里 RequestMessageConverter 是个啥。然后开始了解他了,

看到AbstractNamedValueMethodArgumentResolver 原来接口加密和解密的时候有了解过。
忘记太快了。

全部代码 在下面


public class RequestMessageConverter implements HttpMessageConverter {

    @Override
    public boolean canRead(Class clazz, MediaType mediaType) {
        System.out.println("canRead");
        return true;
    }

    @Override
    public boolean canWrite(Class clazz, MediaType mediaType) {
        System.out.println("canWrite" + mediaType.getType());
        return true;
    }

    @Override
    public List getSupportedMediaTypes() {
        System.out.println("getSupportedMediaTypes");
//        ArrayList list = Lists.newArrayList();
//        list.add(MediaType.parseMediaType(MediaType.APPLICATION_JSON_VALUE));
//        list.add(MediaType.parseMediaType(MediaType.MULTIPART_FORM_DATA_VALUE));
        /*这样就可以了*/
        return Lists.newArrayList();
    }

    @Override
    public Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        System.out.println("read");
        InputStream body = inputMessage.getBody();
        String json = StreamUtils.copyToString(body, Charset.forName("UTF-8"));
        return JSONUtil.toBean(json, clazz);
    }

    @Override
    public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        System.out.println("write");
    }
}

这个真的可以运行。

@Override
 public boolean canRead(Class clazz, MediaType mediaType) {
     System.out.println("canRead");
     return true;
 }

这个有用,没他方法不走。
getSupportedMediaTypes 放回去空就行,在后面已经用if 判断了
read 的是把body 转class 返回去就行了。

感谢

https://mp.weixin.qq.com/s/ElOssSGDo3RUPmsYotsWmA
搜索一堆都是这个,不知道那个是原创了。

你可能感兴趣的:(SpringBoot一个接口同时支持form表单、form-data、json的优雅写法)