使用@RequestBody传递数据变为LinkedHashMap解决方案

先说结论

既然数据结构变了,同样也是个k-v的形式,手动写个反射解析一下即可。代码如下:

public Item convertUserFromLinkedHashMap(LinkedHashMap<String, Object> map) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Item item = new Item();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            String keyName = key.substring(0,1).toUpperCase() + key.substring(1);
            String setter = "set" + keyName;
            String getter = "get" + keyName;
            item.getClass().getMethod(setter, item.getClass().getDeclaredMethod(getter).getReturnType())
                    .invoke(item, entry.getValue());
        }
        return item;
    }

说说思路

问题背景

出现问题的代码形式如下:

@RequestMapping("edit")
    public Response edit(@RequestBody Map<String, Object> params) {
        Item item;
        item = (Item) params.get("params");
        return itemService.edit(item);
    }

在使用上面的代码处理业务时,抛出ClassCastException,大致意思为无法将LinkedHashMap对象转换成Item对象。

前端传入的数据样例如下:

{"params":{"param1":"pararm1","param2":2}}

产生原因

大概是因为接收到的参数会默认存放进LinkedHashMap的子类ModelMap中,但在一定情况下直接返回了LinkedHashMap而没有进行封装。

可能解决方案

1.引入FastJSON解析输入数据(未解决问题)

从前端传递进来的数据是JSON格式,出现问题的数据结构也是一种K-V结构,很自然就想到了FastJSON来解决问题。

但其实忽略了一个问题,标准的JSON格式的key和value的格式为"key":"value",但在出现问题的LinkedHashMap中依然不符合JSON的格式,故FastJSON无法胜任工作。

2. 对于每个实体写一串if逻辑写入逻辑

是一种可以临时运行的方案,但对于程序的扩展与维护并不友好。样例代码如下:

public Item convertUserFromLinkedHashMap(LinkedHashMap<String, Object> map) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Item item = new Item();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            if ("param1".equals(key)) {
                item.setParam1(entry.getValue());
            } else if("param2".equals(key)) {
                item.setParam2(entry.getValue());
            }
        }
        return item;
    }

当然也可以写成switch-case的结构,但总体类似。

3. 使用反射的方式实现一个类似JSON解析的方法

其实在第二种解决方案中可以发现一个共性问题,通过key的值来进行判断,并set对应的属性,其实可以借助于Java的反射机制来完成工作。核心代码已在文章最初进行展示,这里不再赘述,这里只对代码思路进行一定的解释。

最终我们是要调用set方法,对于set方法有一个入参,诚然,可以反射可以获取方法列表的类型,但这需要我们先获取到对应方法才可以获取参数类型,此时我们并没有获取到set方法,所以直接获取参数类型的方案就需要进行变通。get方法通常和set方法成对出现,而get方法的返回值类型就是set方法的参数类型,可以通过这一特点获取get方法的返回参数当做set方法的参数类型,这样就完成了反射方法调用参数的声明。

至于如何获取set方法和get方法,这里利用了一个开发公约,即“set方法以set开头随后以对应属性的大驼峰表示法拼接形成方法名,get方法同理”,大驼峰和小驼峰的方法仅有首字母不同,故将首位字母设定为大写并在前面拼接set或者get生成方法名。

如此一来就获取到了对应的方法并可以进行调用。

遗留问题

  1. 对于问题成因部分存疑,后面会进行考证。
  2. 给出的方法返回值类型写定了,简单尝试过使用范型的方式,但范型不能进行new,或许还有其他实现方案,可以实现更加优雅的实现。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值