记一次后台RestTemplate模拟form表单提交

3,557 阅读2分钟

需求

前后端分离项目,前端通过post请求封装成application/json数据请求后端。后端通过签名模仿form表单用RestTemplate调用第三方平台格式为application/x-www-form-urlencoded。

通过反射需要将对象转成MultiValueMap

因为RestTemplate调用form表单提交只能用MultiValueMap,我用的Fastjson不能直接将实例对象转换成key-value的MultiValueMap。反射对象转MultiValueMap如下:

/***
     * @Description:传入参数为实例对象一般是XXXDTO就是请求对象
     * @Param: [obj]
     * @return: java.util.Map<java.lang.String, java.lang.reflect.Field>
     * @Author: 
     * @Date: 2021-03-12
     */
public static MultiValueMap<String, Object> getMultiValueMap(Object obj) {
        MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        try {
            for (Field field : fields) {
                if (needFilterField(field)) {
                    continue;
                }
                 //意思就是该方式是用来设置获取权限的。
                //如果 accessible 标志被设置为true,那么反射对象在使用的时候,不会去检查Java语言权限控制(private之类的);
                //如果设置为false,反射对象在使用的时候,会检查Java语言权限控制。
                //需要注意的是,设置为true会引起安全隐患。
                field.setAccessible(true);
                multiValueMap.add(field.getName(), field.get(obj));
            }
            getParentMap(clazz, multiValueMap, obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return multiValueMap;
    }
    
     /**
     * 过滤不需要属性
     *
     * @param field
     * @return
     */
    private static Boolean needFilterField(Field field) {
        // 过滤静态属性
        if (Modifier.isStatic(field.getModifiers())) {
            return true;
        }
        // 过滤transient 关键字修饰的属性
        if (Modifier.isTransient(field.getModifiers())) {
            return true;
        }
        return false;
    }

如果是需要父类的属性需要通过反射递归调用父类

/**
     * 递归所有父类属性
     *
     * @param clazz
     * @param multiValueMap
     */
    private static void getParentMap(Class<?> clazz, MultiValueMap<String, Object> multiValueMap, Object obj) {
        Class<?> superClazz = clazz.getSuperclass();
        if (superClazz != null) {
            Field[] superFields = superClazz.getDeclaredFields();
            try {
                for (Field field : superFields) {
                    if (needFilterField(field)) {
                        continue;
                    }
                    field.setAccessible(true);
                    multiValueMap.add(field.getName(), field.get(obj));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            getParentMap(clazz, multiValueMap, obj);
        }
    }

这样传入的对象就会转成key-value模式传入的对象

image.png 转完之后的MultiValueMap对象

image.png

RestTemplate调用

代码如下:

 @Autowired
 private RestTemplate restTemplate;
/***
    * @Description:RetResponse为自己封装的统一返回对象
    * @Param: [returnStr]
    * @return: cn.thinkjoy.springboot.logicunified.dto.response.RetResponse
    * @Author: leichunhong
    * @Date: 2021-02-23
    */
    @Override
    public RetResponse getRetResponse(String url, MultiValueMap<String, Object> multiValueMap) {
        RetResponse retResponse=new RetResponse();
        try{
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(multiValueMap, httpHeaders);
            ResponseEntity<String> response = restTemplate.postForEntity(getPath(url), requestEntity, String.class);
            retResponse = JSONObject.parseObject(response, RetResponse.class);
            return retResponse;
        }catch (Exception e){
            logger.error(e.getMessage(), e);
            retResponse.setRet(-1);
            retResponse.setMsg("http请求错误");
            return retResponse;
        }
    }