1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > java 自定义注解 生成json_SpringBoot:自定义注解实现后台接收Json参数

java 自定义注解 生成json_SpringBoot:自定义注解实现后台接收Json参数

时间:2022-08-16 00:45:35

相关推荐

java 自定义注解 生成json_SpringBoot:自定义注解实现后台接收Json参数

0.需求

在实际的开发过程中,服务间调用一般使用Json传参的模式,SpringBoot项目无法使用@RequestParam接收Json传参

只有@RequestBody支持Json,但是每次为了一个接口就封装一次实体类比较麻烦

如果使用Map来进行参数接收,则会导致参数不可控,会在接口中新增较多判断进行入参控制

其次,在实际的开发过程中,我们偶尔会传入两个实体类,如果使用@RequestBody也会出错

因为传入的参数只能够读取一次,一般这里也会封装一次实体类,不够方便

也有重写HttpServletRequestWrapper的处理办法,但不能解决上一个问题

1.思路

因为一个注解只能读取一次,按照重写HttpServletRequestWrapper的思路,将请求中的Json参数进行缓存

另外自定义一个注解,来把参数进行注入。

1.1.自定义@JsonFmt注解

import java.lang.annotation.*;

@Target(ElementType.PARAMETER)

@Retention(RetentionPolicy.RUNTIME)

@Documentedpublic @interfaceJsonFmt {/*** 值*/String value()default "";/*** 是否必须*/

boolean require() default true;

}

这里的值,不是给参数的默认值(defaultValue),而是类似于@RequestParam注解中的value、name,是用来指定入参的key

1.2.自定义注解的实现类

importcom.alibaba.fastjson.JSON;importcom.alibaba.fastjson.JSONObject;importcom.fasterxml.jackson.databind.ObjectMapper;importlombok.extern.slf4j.Slf4j;importorg.springframework.core.MethodParameter;importorg.springframework.util.StringUtils;importorg.springframework.web.bind.support.WebDataBinderFactory;importorg.springframework.web.context.request.NativeWebRequest;importorg.springframework.web.method.support.HandlerMethodArgumentResolver;importorg.springframework.web.method.support.ModelAndViewContainer;importjavax.servlet.http.HttpServletRequest;importjava.io.BufferedReader;importjava.util.HashMap;importjava.util.Map;

@Slf4jpublic class JsonFmtHandlerMethodArgumentResolver implementsHandlerMethodArgumentResolver {//自定义key

private static final String KEY = "TEST_JSON_BODY_KEY";private static ObjectMapper objectMapper = newObjectMapper();

@Overridepublic booleansupportsParameter(MethodParameter parameter) {return parameter.hasParameterAnnotation(JsonFmt.class);

}

@Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throwsException {

JsonFmt jsonFmt= parameter.getParameterAnnotation(JsonFmt.class);

JSONObject jsonObject=getJsonObject(webRequest);

String value=getParamName(parameter,jsonFmt);boolean require =jsonFmt.require();

Object paramValue=getParamValue(jsonObject,value);if (paramValue == null &&require) {throw new Exception("parameter[" + value + "]不能为空。");

}if (paramValue == null) {return null;

}

Class> classType =parameter.getParameterType();if (paramValue.getClass().equals(JSONObject.class)){

paramValue=objectMapper.readValue(paramValue.toString(),classType);

}returnparamValue;

}privateString getParamName(MethodParameter parameter, JsonFmt jsonFmt) {

String value=jsonFmt.value();if(StringUtils.isEmpty(value)) {

value=parameter.getParameterName();

}returnvalue;

}privateObject getParamValue(JSONObject jsonObject,String value) {for(String key: jsonObject.keySet()) {if(key.equalsIgnoreCase(value)){returnjsonObject.get(key);

}

}return null;

}private JSONObject getJsonObject(NativeWebRequest webRequest) throwsException {

String jsonBody=(String) webRequest.getAttribute(KEY, NativeWebRequest.SCOPE_REQUEST);if(StringUtils.isEmpty(jsonBody)){

HttpServletRequest request= webRequest.getNativeRequest(HttpServletRequest.class);

BufferedReader reader=request.getReader();

StringBuilder sb= newStringBuilder();char[] buf = new char[1024];intrd;while ((rd = reader.read(buf)) != -1) {

sb.append(buf,0, rd);

}

jsonBody=sb.toString();if(StringUtils.isEmpty(jsonBody)){

Map params =request.getParameterMap();

Map tmp= newHashMap();for (Map.Entryparam:params.entrySet()) {if(param.getValue().length == 1){

tmp.put(param.getKey(),param.getValue()[0]);

}else{

tmp.put(param.getKey(),param.getValue());

}

}

jsonBody=JSON.toJSONString(tmp);

}

webRequest.setAttribute(KEY, jsonBody, NativeWebRequest.SCOPE_REQUEST);

}returnJSONObject.parseObject(jsonBody);

}

}

方法说明:

supportsParameter:说明支持的注解,只要方法参数有@JsonFmt就启用该实现类

resolveArgument:解决方法,注解的具体实现

getJsonObject:获取请求体,这里的实现逻辑就是从请求中获取Json体,如果没有获取到,则从请求参数中获取(兼容From模式),将请求体封装为JsonObject

getParamName:获取注解参数的key,先获取注解的value,如果为空,则使用方法参数的名称

getParamValue:这个可以不加,我这里是为了让key不区分大小写,如果需要区分,直接使用jsonObject.get(key)即可

1.3.加入自定义注解

importcom.example.demo.jsonfmt.JsonFmtHandlerMethodArgumentResolver;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.method.support.HandlerMethodArgumentResolver;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;importjava.util.List;

@Configurationpublic class AppConfig implementsWebMvcConfigurer {

@Overridepublic void addArgumentResolvers(Listresolvers) {

resolvers.add(newJsonFmtHandlerMethodArgumentResolver());

}

}

2.使用

到这里我们就能愉快的使用我们的自定义注解@JsonFmt来进行参数接收了

目前在Json传参中,能完美的接收实体类、List、Map以及其他基础类型

在Form传参中,能够支持List、Map以及其他基础类型,对于实体类暂时还不能兼容

因为后台接收到的是Map,不容易区分哪些是实体类的字段,无法进行填充,这种建议使用@RequestBody

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。