一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 基于@RequestBody注解只能注入對象和map的解決

基于@RequestBody注解只能注入對象和map的解決

2022-02-25 00:56WoddenFish Java教程

這篇文章主要介紹了@RequestBody注解只能注入對象和map的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

@RequestBody注解只能注入對象和map的問題

前后端分離開發模式下,前后端數據交互全部采用json,所以在后端在采用spring框架的時候都會使用@ResponseBody(后端返回參數封裝為json格式)和@RequestBody(前端請求攜帶json參數解析)注解。

但是在實際開發中,往往@RequestBody的使用會比較令人難受(超級難受),因為它spring官方只支持到將json解析為一個定義好的對象或者是一個通用性的map,而我們實際項目中經常傳遞的參數僅僅是一個或者是兩個參數,這樣的參數封裝程對象總是有點大材小用的感覺,并且還消耗性能,而使用map又感覺操作比較繁瑣,那這樣的話可不可以使用簡單的類似于@PathVariable(value="")這樣的模式取請求數據呢????當然可以!!

1、自定義一個適應于這種情況的注解@RequestJson

package cn.annotation; 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; 
/**
* Title:      RequestJson
* @date       2018年9月10日
* @version    V1.0
* Description: 自定義請求json數據解析注解(主要解決單參數傳遞)
*/
@Target(ElementType.PARAMETER)//使用在參數上
@Retention(RetentionPolicy.RUNTIME)//運行時注解
public @interface RequestJson {
  /**
   * 是否必須出現的參數
   */
  boolean required() default true;

  /**
   * 當value的值或者參數名不匹配時,是否允許解析最外層屬性到該對象
   */
  boolean parseAllFields() default true;

  /**
   * 解析時用到的JSON的key
   */
  String value() default "";
}

2、自定義RequestJsonHandlerMethodArgumentResolver

實現HandlerMethodArgumentResolver(spring解析數據的接口)

package cn.config; 
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; 
import cn.annotation.RequestJson; 
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer; 
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;

/**
* Title:      RequestJsonHandlerMethodArgumentResolver
* @date       2018年9月10日
* @version    V1.0
* Description: 自定義解析json數據
*/
public class RequestJsonHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
private static final String JSONBODY_ATTRIBUTE = "JSON_REQUEST_BODY";

  /**
   * 設置支持的方法參數類型
   * @param parameter 方法參數
   * @return 支持的類型
   */
  @Override
  public boolean supportsParameter(MethodParameter parameter) {
      // 支持帶@RequestJson注解的參數
      return parameter.hasParameterAnnotation(RequestJson.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);
      // 根據@RequestJson注解value作為json解析的key
      RequestJson parameterAnnotation = parameter.getParameterAnnotation(RequestJson.class);
      //注解的value是JSON的key
      String key = parameterAnnotation.value();
      Object value = null;
      // 如果@RequestJson注解沒有設置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);
      }


      Class<?> parameterType = parameter.getParameterType();
      // 通過注解的value或者參數名解析,能拿到value進行解析
      if (value != null) {
          if (isBasicDataTypes(parameterType)) {
              return value;
          }
          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;
          }
      }

      Object result = parameterType.newInstance();
      // 非基本類型,不允許解析所有字段,返回null
      if (!parameterAnnotation.parseAllFields()) {
          // 如果是必傳參數拋異常
          if (parameterAnnotation.required()) {
              throw new IllegalArgumentException(String.format("required param %s is not present", key));
          }
          // 否則返回空對象
          return result;
      }
     // 非基本類型,允許解析,將外層屬性解析
      result = JSON.parseObject(jsonObject.toString(), parameterType);
      // 如果非必要參數直接返回,否則如果沒有一個屬性有值則報錯
      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;
      }
  }

  /**
   * 基本數據類型直接返回
   */
  @SuppressWarnings("rawtypes")
  private boolean isBasicDataTypes(Class clazz) {
Set<Class> classSet = new HashSet<>();
      classSet.add(String.class);
      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(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;
}
}

3、將上述配置應用到spring項目中

重寫addArgumentResolvers方法

package cn.config; 
import java.nio.charset.Charset;
import java.util.List; 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
* Title:      WebConfig
* @date       2018年9月10日
* @version    V1.0
* Description: 將自定義注解配置到spring
*/

@Configuration
@SuppressWarnings("deprecation")
public class WebConfig extends WebMvcConfigurerAdapter{
@Override
  public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
      argumentResolvers.add(new RequestJsonHandlerMethodArgumentResolver());
  }

  @Bean
  public HttpMessageConverter<String> responseBodyConverter() {
      return new StringHttpMessageConverter(Charset.forName("UTF-8"));
  }

  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
      super.configureMessageConverters(converters);
      converters.add(responseBodyConverter());
  }
}

4、配置完成了,簡單使用

單參數:(不加value默認為參數名)

基于@RequestBody注解只能注入對象和map的解決

或者:

基于@RequestBody注解只能注入對象和map的解決

多參數:

基于@RequestBody注解只能注入對象和map的解決

 

@RequestBody注解的使用問題

今天遇到的問題:@RequestBody的使用問題

先看一下@RequestBody的作用

基于@RequestBody注解只能注入對象和map的解決

我想獲取json字符串某個字段值,看截圖:

基于@RequestBody注解只能注入對象和map的解決

看一下控制臺的輸出信息:

基于@RequestBody注解只能注入對象和map的解決

what ?這什么情況,為什么拿到的是整個json字符串,然后我繼續測試

基于@RequestBody注解只能注入對象和map的解決

給了一個400

基于@RequestBody注解只能注入對象和map的解決

what ?這又是什么情況 (好像只能有一個@RequestBody)我想參數如果是整形的話能不能獲取,我繼續進行測試代碼:

基于@RequestBody注解只能注入對象和map的解決

傳參:

基于@RequestBody注解只能注入對象和map的解決

又給了一個400 (好像只能是String類型) 測試引用類型對象

基于@RequestBody注解只能注入對象和map的解決

代碼:

基于@RequestBody注解只能注入對象和map的解決

傳參:

基于@RequestBody注解只能注入對象和map的解決

控制臺打印:

基于@RequestBody注解只能注入對象和map的解決

測試成功。

個人總結:

1) 一個方法只能有一個@RequestBody

2) 如果接收參數是字符串類型的,獲取的是整個json字符串

3) 如果接受的參數是引用對象,@requestBody User user 會將json字符串中的值賦予user中對應的屬性上

需要注意的是,json字符串中key必須和User對象的屬性名對應

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/WoddenFish/article/details/82593317

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 公交车揉捏大乳呻吟喘娇 | 欧美国产日本精品一区二区三区 | 好男人资源免费播放在线观看 | 亚洲福利在线观看 | 好逼天天有 | 俄罗斯freeoo性另类 | 国产精品资源在线观看网站 | 国产绳艺在线播放 | youporn在线 | 美女天天色| 国产精品反差婊在线观看 | japanhd粗暴video| 波多野结衣在线看 | 高清女主播一区二区三区 | ady久久 | re99热| 国产中文在线视频 | 国产成人夜色影视视频 | 欧美区视频 | 3d蒂法受辱在线播放 | caonila国产在线观看 | 日本女人www | 国产高清经典露脸3p | 70老妇牲交毛片 | 美女扒开屁股让我桶免费 | 深夜a| 大ji巴好好爽好深网站 | 明星ai人脸替换造梦在线播放 | 催眠白丝舞蹈老师小说 | 四虎在线视频免费观看视频 | 手机国产乱子伦精品视频 | 男女男精品视频 | 91精品国产色综合久久 | 亚洲精品国产福利片 | 免费视频观看 | 色偷偷91久久综合噜噜噜 | 国产高清一区二区 | 古装一级毛片 | 青草草视频在线观看 | 四虎影视黄色 | 美女张开腿黄网站免费精品动漫 |