对前端传入的json对象解析成多个对象

在我们的项目中可以看到很多类似的multiRequestBodyDemo(@MultiRequestBody(“dog”) Dog dog, @MultiRequestBody(“user”) User user)的注解,那么这些注解是Spring MVC自带的吗?当然不是,spring MVC中自带的是@RequestBody的注解,这个注解有什么作用呢?这个注解可以将前端传进来的json数据进行解析成json数据。而如果我们没有采样@MultiRequestBody时,通常的做法是将其首先转成json首先转成json,然后进行json数据解析,然后对相关的属性进行逐一获取。下面的例子来源于网上,同时也是我们常用的解析方式之一。但是,如果我们获取属性过多,必然就会带来一个问题,对于代码会显得很长,不够优雅。那还有一种方式那就是采样对象去接收,但是对象接收,但是如果是多个对象呢?那怎么解决这个问题?此时就可以用到multiRequestBodyDemo(@MultiRequestBody(“dog”) Dog dog, @MultiRequestBody(“user”) User user)这种方式进行接收了。但spring boot是不支持这种方式的。因此,就需要自己写一个解析器来解析这样的传入方式和接收的方式。通常,比如我们有分页和对象时,就可以采用这种方式进行接收。

/**
     * 修改或者新增热门搜索
     * @param hotSearch
     * @param request
     * @return
     */
    @RequestMapping(value = "/servehotselectiveajax")
    @ResponseBody
    public int servehotselectiveajax(HttpServletRequest req,HttpServletResponse resp,@RequestBody JSONObject obj) {
        int count=0;
        int countAddHotSearch=0;
        int countEditHotSearch=0;
    	LOGGER.info("data:"+obj.toJSONString());
    	//data:{"createArr":[{"hotSearchId":"","keyword":"ss","sort":"5","tempid":"21"}],"modifyArr":[{"hotSearchId":"205","keyword":"华为","sort":"2","tempid":"21"},{"hotSearchId":"206","keyword":"游戏本","sort":"3","tempid":"21"},{"hotSearchId":"207","keyword":"平板电视","sort":"3","tempid":"21"},{"hotSearchId":"208","keyword":"连衣裙","sort":"4","tempid":"21"}]}
    	String data=obj.toJSONString();
    	//解析json数据
    	JSONObject json = JSON.parseObject(data);
    	String createArr=json.getString("createArr");
    	String modifyArr=json.getString("modifyArr");
    	
    	if(StringUtils.isNotEmpty(createArr)){
    		JSONArray createArray=JSONArray.parseArray(createArr);
    		for(int i=0;i<createArray.size();i++){
                Long tempId=JSONObject.parseObject(JSONObject.toJSONString(createArray.get(i))).getLong("tempId");
                String keyword=JSONObject.parseObject(JSONObject.toJSONString(createArray.get(i))).getString("keyword");
                Integer sort=JSONObject.parseObject(JSONObject.toJSONString(createArray.get(i))).getInteger("sort");
                //创建热门搜索对象
    	    	HotSearch hotSearch=new HotSearch();
    	    	hotSearch.setTempid(tempId);
    	    	hotSearch.setKeyword(keyword);
    	    	hotSearch.setSort(sort);
    	    	hotSearch.setCreateDate(new Date());
    	    	hotSearch.setDelFlag("0");
    	    	//添加热门搜索信息
    	        countAddHotSearch = hotSearchService.addHotSearchSelective(hotSearch);       
            }
    	}
    	
    	if(StringUtils.isNotEmpty(modifyArr)){
    		JSONArray modifyArray=JSONArray.parseArray(modifyArr);
            for(int i=0;i<modifyArray.size();i++){
            	Long hotSearchId=JSONObject.parseObject(JSONObject.toJSONString(modifyArray.get(i))).getLong("id");
                Long tempId=JSONObject.parseObject(JSONObject.toJSONString(modifyArray.get(i))).getLong("tempId");
                String keyword=JSONObject.parseObject(JSONObject.toJSONString(modifyArray.get(i))).getString("keyword");
                Integer sort=JSONObject.parseObject(JSONObject.toJSONString(modifyArray.get(i))).getInteger("sort");
                //创建热门搜索对象
    	    	HotSearch hotSearch=new HotSearch();
    	    	hotSearch.setHotSearchId(hotSearchId);
    	    	hotSearch.setTempid(tempId);
    	    	hotSearch.setKeyword(keyword);
    	    	hotSearch.setSort(sort);
    	    	//修改热门搜索信息
    	        countEditHotSearch = hotSearchService.modifyHostSearchSelectiveById(hotSearch);   
            }
    	}
 
    	//判断修改或者新增成功
        if(countAddHotSearch>0 || countEditHotSearch>0){
        	count=1;
        }
		return count;
    }

MultiRequestBody解析器
解决的问题:

 1、单个字符串等包装类型都要写一个对象才可以用@RequestBody接收;
 2、多个对象需要封装到一个对象里才可以用@RequestBody接收。
主要优势:
 1、支持通过注解的value指定JSON的key来解析对象。
 2、支持通过注解无value,直接根据参数名来解析对象
 3、支持基本类型的注入
 4、支持GET和其他请求方式注入
 5、支持通过注解无value且参数名不匹配JSON串key时,根据属性解析对象。
 6、支持多余属性(不解析、不报错)、支持参数“共用”(不指定value时,参数名不为JSON串的key)
 7、支持当value和属性名找不到匹配的key时,对象是否匹配所有属性。

其思路是将前端传入的数据进行获取,也即jsonbody, 获取请求体JSON字符串。获取之后,将其转成jsonObject。获取自定义元注解@MultiRequestBody中的value,如果@MultiRequestBody注解没有设置value,则取参数名FrameworkServlet作为json解析的key。默认是没有的,因此需要获取controller中的注解value值信息作为key,然后通过key拿到属性信息。进行相应的解析。下面是作者 Wangyang Liu的解析具体实现,具体代码可以到github上去获取,https://github.com/chujianyun/Spring-MultiRequestBody

/**
 * MultiRequestBody解析器
 * 解决的问题:
 * 1、单个字符串等包装类型都要写一个对象才可以用@RequestBody接收;
 * 2、多个对象需要封装到一个对象里才可以用@RequestBody接收。
 * 主要优势:
 * 1、支持通过注解的value指定JSON的key来解析对象。
 * 2、支持通过注解无value,直接根据参数名来解析对象
 * 3、支持基本类型的注入
 * 4、支持GET和其他请求方式注入
 * 5、支持通过注解无value且参数名不匹配JSON串key时,根据属性解析对象。
 * 6、支持多余属性(不解析、不报错)、支持参数“共用”(不指定value时,参数名不为JSON串的key)
 * 7、支持当value和属性名找不到匹配的key时,对象是否匹配所有属性。
 *
 * @author Wangyang Liu  QQ: 605283073
 * @date 2018/08/27
 */
public class MultiRequestBodyArgumentResolver implements HandlerMethodArgumentResolver {

    private static final String JSONBODY_ATTRIBUTE = "JSON_REQUEST_BODY";

    /**
     * 设置支持的方法参数类型
     *
     * @param parameter 方法参数
     * @return 支持的类型
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // 支持带@MultiRequestBody注解的参数
        return parameter.hasParameterAnnotation(MultiRequestBody.class);
    }

    /**
     * 参数解析,利用fastjson
     * 注意:非基本类型返回null会报空指针异常,要通过反射或者JSON工具类创建一个空对象
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        String jsonBody = getRequestBody(webRequest);

        JSONObject jsonObject = JSON.parseObject(jsonBody);
        // 根据@MultiRequestBody注解value作为json解析的key
        MultiRequestBody parameterAnnotation = parameter.getParameterAnnotation(MultiRequestBody.class);
        //注解的value是JSON的key
        String key = parameterAnnotation.value();
        Object value;
        // 如果@MultiRequestBody注解没有设置value,则取参数名FrameworkServlet作为json解析的key
        if (StringUtils.isNotEmpty(key)) {
            value = jsonObject.get(key);
            // 如果设置了value但是解析不到,报错
            if (value == null && parameterAnnotation.required()) {
                throw new IllegalArgumentException(String.format("required param %s is not present", key));
            }
        } else {
            // 注解为设置value则用参数名当做json的key
            key = parameter.getParameterName();
            value = jsonObject.get(key);
        }

        // 获取的注解后的类型 Long
        Class<?> parameterType = parameter.getParameterType();
        // 通过注解的value或者参数名解析,能拿到value进行解析
        if (value != null) {
            //基本类型
            if (parameterType.isPrimitive()) {
                return parsePrimitive(parameterType.getName(), value);
            }
            // 基本类型包装类
            if (isBasicDataTypes(parameterType)) {
                return parseBasicTypeWrapper(parameterType, value);
                // 字符串类型
            } else if (parameterType == String.class) {
                return value.toString();
            }
            // 其他复杂对象
            return JSON.parseObject(value.toString(), parameterType);
        }

        // 解析不到则将整个json串解析为当前参数类型
        if (isBasicDataTypes(parameterType)) {
            if (parameterAnnotation.required()) {
                throw new IllegalArgumentException(String.format("required param %s is not present", key));
            } else {
                return null;
            }
        }

        // 非基本类型,不允许解析所有字段,必备参数则报错,非必备参数则返回null
        if (!parameterAnnotation.parseAllFields()) {
            // 如果是必传参数抛异常
            if (parameterAnnotation.required()) {
                throw new IllegalArgumentException(String.format("required param %s is not present", key));
            }
            // 否则返回null
            return null;
        }
        // 非基本类型,允许解析,将外层属性解析
        Object result;
        try {
            result = JSON.parseObject(jsonObject.toString(), parameterType);
        } catch (JSONException jsonException) {
            // TODO:: 异常处理返回null是否合理?
            result = null;
        }

        // 如果非必要参数直接返回,否则如果没有一个属性有值则报错
        if (!parameterAnnotation.required()) {
            return result;
        } else {
            boolean haveValue = false;
            Field[] declaredFields = parameterType.getDeclaredFields();
            for (Field field : declaredFields) {
                field.setAccessible(true);
                if (field.get(result) != null) {
                    haveValue = true;
                    break;
                }
            }
            if (!haveValue) {
                throw new IllegalArgumentException(String.format("required param %s is not present", key));
            }
            return result;
        }
    }

    /**
     * 基本类型解析
     */
    private Object parsePrimitive(String parameterTypeName, Object value) {
        final String booleanTypeName = "boolean";
        if (booleanTypeName.equals(parameterTypeName)) {
            return Boolean.valueOf(value.toString());
        }
        final String intTypeName = "int";
        if (intTypeName.equals(parameterTypeName)) {
            return Integer.valueOf(value.toString());
        }
        final String charTypeName = "char";
        if (charTypeName.equals(parameterTypeName)) {
            return value.toString().charAt(0);
        }
        final String shortTypeName = "short";
        if (shortTypeName.equals(parameterTypeName)) {
            return Short.valueOf(value.toString());
        }
        final String longTypeName = "long";
        if (longTypeName.equals(parameterTypeName)) {
            return Long.valueOf(value.toString());
        }
        final String floatTypeName = "float";
        if (floatTypeName.equals(parameterTypeName)) {
            return Float.valueOf(value.toString());
        }
        final String doubleTypeName = "double";
        if (doubleTypeName.equals(parameterTypeName)) {
            return Double.valueOf(value.toString());
        }
        final String byteTypeName = "byte";
        if (byteTypeName.equals(parameterTypeName)) {
            return Byte.valueOf(value.toString());
        }
        return null;
    }

    /**
     * 基本类型包装类解析
     */
    private Object parseBasicTypeWrapper(Class<?> parameterType, Object value) {
        if (Number.class.isAssignableFrom(parameterType)) {
            Number number = (Number) value;
            if (parameterType == Integer.class) {
                return number.intValue();
            } else if (parameterType == Short.class) {
                return number.shortValue();
            } else if (parameterType == Long.class) {
                return number.longValue();
            } else if (parameterType == Float.class) {
                return number.floatValue();
            } else if (parameterType == Double.class) {
                return number.doubleValue();
            } else if (parameterType == Byte.class) {
                return number.byteValue();
            }
        } else if (parameterType == Boolean.class) {
            return value.toString();
        } else if (parameterType == Character.class) {
            return value.toString().charAt(0);
        }
        return null;
    }

    /**
     * 判断是否为基本数据类型包装类
     */
    private boolean isBasicDataTypes(Class clazz) {
        Set<Class> classSet = new HashSet<>();
        classSet.add(Integer.class);
        classSet.add(Long.class);
        classSet.add(Short.class);
        classSet.add(Float.class);
        classSet.add(Double.class);
        classSet.add(Boolean.class);
        classSet.add(Byte.class);
        classSet.add(Character.class);
        return classSet.contains(clazz);
    }

    /**
     * 获取请求体JSON字符串
     */
    private String getRequestBody(NativeWebRequest webRequest) {
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);

        // 有就直接获取
        String jsonBody = (String) webRequest.getAttribute(JSONBODY_ATTRIBUTE, NativeWebRequest.SCOPE_REQUEST);
        // 没有就从请求中读取
        if (jsonBody == null) {
            try {
                jsonBody = IOUtils.toString(servletRequest.getReader());
                webRequest.setAttribute(JSONBODY_ATTRIBUTE, jsonBody, NativeWebRequest.SCOPE_REQUEST);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return jsonBody;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aBlmx1mz-1590278445862)(D:\相关图片信息\2020-05-11_145715.png)]

当然还可以:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d7Wm4mGv-1590278445867)(D:\相关图片信息\2020-05-11_150112.png)]

当然还可以:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UT1thEa4-1590278445871)(D:\相关图片信息\2020-05-11_150616.png)]

是不是很好用!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的。您可以使用Java中的Apache POI库来解析Excel文件。以下是一个简单的Java代码示例,演示如何使用Apache POI库将Excel文件解析JSON格式的报文: ```java import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import com.fasterxml.jackson.databind.ObjectMapper; public class ExcelToJsonConverter { public static void main(String[] args) throws IOException { // 读取Excel文件 FileInputStream fileInputStream = new FileInputStream(new File("example.xlsx")); Workbook workbook = WorkbookFactory.create(fileInputStream); // 解析Excel文件 List<Customer> customers = new ArrayList<>(); Sheet sheet = workbook.getSheetAt(0); Iterator<Row> rowIterator = sheet.rowIterator(); while (rowIterator.hasNext()) { Row row = rowIterator.next(); if (row.getRowNum() == 0) { // 跳过表头 continue; } Customer customer = new Customer(); customer.setDocumentType(row.getCell(0).getStringCellValue()); customer.setDocumentNumber(row.getCell(1).getStringCellValue()); customers.add(customer); } // 将解析结果转换为JSON格式的报文 ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(customers); System.out.println(json); // 关闭资源 fileInputStream.close(); workbook.close(); } public static class Customer { private String documentType; private String documentNumber; public String getDocumentType() { return documentType; } public void setDocumentType(String documentType) { this.documentType = documentType; } public String getDocumentNumber() { return documentNumber; } public void setDocumentNumber(String documentNumber) { this.documentNumber = documentNumber; } } } ``` 在上面的代码中,我们首先使用`FileInputStream`类读取Excel文件,然后使用`WorkbookFactory`类将其转换为`Workbook`对象。接下来,我们遍历Excel文件中的每一行,将每一行中的证件类型和证件号码存储到`Customer`对象中。最后,我们使用`ObjectMapper`类将解析结果转换为JSON格式的报文。 需要注意的是,上面的代码仅仅是一个示例,您需要根据具体的业务需求进行修改。例如,如果Excel文件中包含多个表单,您需要通过`Workbook.getSheetAt()`方法获取指定的表单。另外,如果Excel文件中的数据类型不是文本类型,您需要根据实际情况调用`Cell`对象的不同方法来获取数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值