乐趣区

关于spring-mvc:如何使SpringMVC的表单和get请求参数支持json转换

该文章为原创(转载请注明出处):如何使 SpringMVC 的表单和 get 申请参数反对 json 转换?– 简书 (jianshu.com)

实在业务场景

前端申请须要表单传递 json 字符串或者 get 申请参数携带了 json 字符串的数据
后端只能在格局上做斗争?
例如:

前端表单
userJson:{"name":"xxx", "phone":"123"}
前端 Get 申请
/user/test?userJson=%7B%22name%22%3A%22xxx%22%2C%20%22phone%22%3A%22123%22%7D 
后端接管表单 1
@GetMapping("test.do")
public RestResponse<Void> test(@ModelAttribute String userJson) {body.setUser(JSON.parseObject(userJson, User.class));
    // service.handleUser(body);
}
@Data
static class User {
    private String phone;
    private String name;
}
后端接管表单 2
@GetMapping("test.do")
public RestResponse<Void> test(@ModelAttribute TestBody body) {body.setUser(JSON.parseObject(body.getUserJson(), User.class));
    // service.handleUser(body);
} 
@Data
static class TestBody {private String userJson;}
static class User {
    private String phone;
    private String name;
}
后端接管 Get 申请
@GetMapping("test.do")
public RestResponse<Void> test(@RequestParam String userJson) {body.setUser(JSON.parseObject(userJson, User.class));
    // service.handleUser(body);
}
@Data
static class User {
    private String phone;
    private String name;
}

反对 json 的解决方案

利用 springmvc 提供的 @ControllerAdvice 切面,在 WebDataBinder 中退出应用 json 反序列化的形式
来进行 string 与各种类型的转换

package com.nuonuo.accounting.guiding.support.spring;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.TypeUtils;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import java.util.Set;

import static java.util.Collections.singleton;

/**
 * Fastjson 来主动绑定参数
 * 反对表单、get 申请参数
 *
 * @author uhfun
 * @see RequestMappingHandlerAdapter#initControllerAdviceCache()
 * 寻找 @ControllerAdvice 切面下 @InitBinder 注解的办法
 * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#INIT_BINDER_METHODS
 * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getDataBinderFactory(org.springframework.web.method.HandlerMethod)
 * 依据切面构建 InitBinderMethod 办法
 * @see org.springframework.web.method.annotation.InitBinderDataBinderFactory#initBinder
 * 初始化 binder 时反射调用
 * @see ModelAttribute
 */
@ControllerAdvice
public class StringToAnyObjectSupport {

    private static volatile boolean INITIALIZED = false;

    @InitBinder
    public void initStringToAnyObjectConverter(WebDataBinder dataBinder) {
        GenericConversionService conversionService;
        if (dataBinder.getConversionService() instanceof GenericConversionService) {if (!INITIALIZED) {conversionService = (GenericConversionService) dataBinder.getConversionService();
                conversionService.addConverter(new StringToAnyObjectConverter());
                INITIALIZED = true;
            }
        } else {throw new IllegalStateException("dataBinder 的 ConversionService 不是 GenericConversionService 类型实例");
        }
    }

    static class StringToAnyObjectConverter implements GenericConverter {

        @Override
        public Set<ConvertiblePair> getConvertibleTypes() {return singleton(new ConvertiblePair(String.class, Object.class));
        }

        @Override
        public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {Class<?> type = targetType.getType();
            if (TypeUtils.getClassFromMapping(type.getName()) != null) {return TypeUtils.cast(source, type, ParserConfig.getGlobalInstance());
            } else {return JSON.parseObject((String) source, type);
            }
        }
    }
}

如何应用?

后端接管表单 1
@GetMapping("test.do")
public RestResponse<Void> test(@ModelAttribute("userJson") User user) {
} 
static class User {
    private String phone;
    private String name;
}
后端接管表单 2
@GetMapping("test.do")
public RestResponse<Void> test(@ModelAttribute TestBody body) {User user = body.getUserJson();
    // service.handleUser(body);
} 
@Data
static class TestBody {private User userJson;}
static class User {
    private String phone;
    private String name;
}
后端接管 Get 申请
@GetMapping("test.do")
public RestResponse<Void> test(@RequestParam User userJson) { }
@Data
static class User {
    private String phone;
    private String name;
}

该文章为原创(转载请注明出处):如何使 SpringMVC 的表单和 get 申请参数反对 json 转换?– 简书 (jianshu.com)

退出移动版