欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring boot中自定義Json參數(shù)解析器的方法

 更新時(shí)間:2019年01月04日 11:24:16   作者:不懂是非  
這篇文章主要介紹了Spring boot中自定義Json參數(shù)解析器的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

一、介紹

用過(guò)springMVC/spring boot的都清楚,在controller層接受參數(shù),常用的都是兩種接受方式,如下

/**
  * 請(qǐng)求路徑 http://127.0.0.1:8080/test 提交類(lèi)型為application/json
  * 測(cè)試參數(shù){"sid":1,"stuName":"里斯"}
  * @param str
  */
 @RequestMapping(value = "/test",method = RequestMethod.POST)
 public void testJsonStr(@RequestBody(required = false) String str){
  System.out.println(str);
 }
 /**
  * 請(qǐng)求路徑 http://127.0.0.1:8080/testAcceptOrdinaryParam?str=123
  * 測(cè)試參數(shù)
  * @param str
  */
 @RequestMapping(value = "/testAcceptOrdinaryParam",method = {RequestMethod.GET,RequestMethod.POST})
 public void testAcceptOrdinaryParam(String str){
  System.out.println(str);
 }

第一個(gè)就是前端傳json參數(shù),后臺(tái)使用RequestBody注解來(lái)接受參數(shù)。第二個(gè)就是普通的get/post提交數(shù)據(jù),后臺(tái)進(jìn)行接受參數(shù)的方式,當(dāng)然spring還提供了參數(shù)在路徑中的解析格式等,這里不作討論

本文主要是圍繞前端解析Json參數(shù)展開(kāi),那@RequestBody既然能接受json參數(shù),那它有什么缺點(diǎn)呢,

原spring 雖然提供了@RequestBody注解來(lái)封裝json數(shù)據(jù),但局限性也挺大的,對(duì)參數(shù)要么適用jsonObject或者javabean類(lèi),或者string,

1、若使用jsonObject 接收,對(duì)于json里面的參數(shù),還要進(jìn)一步獲取解析,很麻煩

2、若使用javabean來(lái)接收,若接口參數(shù)不一樣,那么每一個(gè)接口都得對(duì)應(yīng)一個(gè)javabean若使用string 來(lái)接收,那么也得需要自己解析json參數(shù)

3、所以琢磨了一個(gè)和get/post form-data提交方式一樣,直接在controller層接口寫(xiě)參數(shù)名即可接收對(duì)應(yīng)參數(shù)值。

重點(diǎn)來(lái)了,那么要完成在spring給controller層方法注入?yún)?shù)前,攔截這些參數(shù),做一定改變,對(duì)于此,spring也提供了一個(gè)接口來(lái)讓開(kāi)發(fā)者自己進(jìn)行擴(kuò)展。這個(gè)接口名為HandlerMethodArgumentResolver,它呢 是一個(gè)接口,它的作用主要是用來(lái)提供controller層參數(shù)攔截和注入用的。spring 也提供了很多實(shí)現(xiàn)類(lèi),這里不作討論,這里介紹它的一個(gè)比較特殊的實(shí)現(xiàn)類(lèi)HandlerMethodArgumentResolverComposite,下面列出該類(lèi)的一個(gè)實(shí)現(xiàn)方法

@Override
 @Nullable
 public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
   NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

  HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
  if (resolver == null) {
   throw new IllegalArgumentException(
     "Unsupported parameter type [" + parameter.getParameterType().getName() + "]." +
       " supportsParameter should be called first.");
  }
  return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
 }

是不是感到比較驚訝,它自己不去執(zhí)行自己的resplveArgument方法,反而去執(zhí)行HandlerMethodArgumentResolver接口其他實(shí)現(xiàn)類(lèi)的方法,具體原因,我不清楚,,,這個(gè)方法就是給controller層方法參數(shù)注入值得一個(gè)入口。具體的不多說(shuō)啦!下面看代碼

二、實(shí)現(xiàn)步驟

要攔截一個(gè)參數(shù),肯定得給這個(gè)參數(shù)一個(gè)標(biāo)記,在攔截的時(shí)候,判斷有沒(méi)有這個(gè)標(biāo)記,有則攔截,沒(méi)有則方向,這也是一種過(guò)濾器/攔截器原理,談到標(biāo)記,那肯定非注解莫屬,于是一個(gè)注解類(lèi)就產(chǎn)生了

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestJson {

 /**
  * 字段名,不填則默認(rèn)參數(shù)名
  * @return
  */
 String fieldName() default "";

 /**
  * 默認(rèn)值,不填則默認(rèn)為null。
  * @return
  */
 String defaultValue() default "";
}

這個(gè)注解也不復(fù)雜,就兩個(gè)屬性,一個(gè)是fieldName,一個(gè)是defaultValue。有了這個(gè),下一步肯定得寫(xiě)該注解的解析器,而上面又談到HandlerMethodArgumentResolver接口可以攔截controller層參數(shù),所以這個(gè)注解的解析器肯定得寫(xiě)在該接口實(shí)現(xiàn)類(lèi)里,

@Component
public class RequestJsonHandler implements HandlerMethodArgumentResolver {

 /**
  * json類(lèi)型
  */
 private static final String JSON_CONTENT_TYPE = "application/json";


 @Override
 public boolean supportsParameter(MethodParameter methodParameter) {
  //只有被reqeustJson注解標(biāo)記的參數(shù)才能進(jìn)入
  return methodParameter.hasParameterAnnotation(RequestJson.class);
 }

 @Override
 public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
 // 解析requestJson注解的代碼
  
 }

一個(gè)大致模型搭建好了。要實(shí)現(xiàn)的初步效果,這里也說(shuō)下,如圖

 

要去解析json參數(shù),那肯定得有一些常用的轉(zhuǎn)換器,把json參數(shù)對(duì)應(yīng)的值,轉(zhuǎn)換到controller層參數(shù)對(duì)應(yīng)的類(lèi)型中去,而常用的類(lèi)型如 八種基本類(lèi)型及其包裝類(lèi),String、Date類(lèi)型,list/set,javabean等,所有可以先去定義一個(gè)轉(zhuǎn)換器接口。

public interface Converter {

 /**
  * 將value轉(zhuǎn)為clazz類(lèi)型
  * @param clazz
  * @param value
  * @return
  */
 Object convert(Type clazz, Object value);
}

有了這個(gè)接口,那肯定得有幾個(gè)實(shí)現(xiàn)類(lèi),在這里,我將這些轉(zhuǎn)換器劃分為 ,7個(gè)陣營(yíng)

1、Number類(lèi)型轉(zhuǎn)換器,負(fù)責(zé)Byte/Integer/Float/Double/Long/Short 及基礎(chǔ)類(lèi)型,還有BigInteger/BigDecimal兩個(gè)類(lèi)

2、Date類(lèi)型轉(zhuǎn)換器,負(fù)責(zé)日期類(lèi)型

3、String類(lèi)型轉(zhuǎn)換器,負(fù)責(zé)char及包裝類(lèi),還有string類(lèi)型

4、Collection類(lèi)型轉(zhuǎn)換器,負(fù)責(zé)集合類(lèi)型

5、Boolean類(lèi)型轉(zhuǎn)換器,負(fù)責(zé)boolean/Boolean類(lèi)型

6、javaBean類(lèi)型轉(zhuǎn)換器,負(fù)責(zé)普通的的pojo類(lèi)

7、Map類(lèi)型轉(zhuǎn)換器,負(fù)責(zé)Map接口

這里要需引入第三方包google,在文章末尾會(huì)貼出來(lái)。

代碼在這里就貼Number類(lèi)型和Date類(lèi)型,其余完整代碼,會(huì)在github上給出,地址  github鏈接

Number類(lèi)型轉(zhuǎn)換器

public class NumberConverter implements Converter{

 @Override
 public Object convert(Type type, Object value){
  Class<?> clazz = null;
  if (!(type instanceof Class)){
   return null;
  }
  clazz = (Class<?>) type;
  if (clazz == null){
   throw new RuntimeException("類(lèi)型不能為空");
  }else if (value == null){
   return null;
  }else if (value instanceof String && "".equals(String.valueOf(value))){
   return null;
  }else if (!clazz.isPrimitive() && clazz.getGenericSuperclass() != Number.class){
   throw new ClassCastException(clazz.getTypeName() + "can not cast Number type!");
  }
  if (clazz == int.class || clazz == Integer.class){
   return Integer.valueOf(String.valueOf(value));
  }else if (clazz == short.class || clazz == Short.class){
   return Short.valueOf(String.valueOf(value));
  }else if (clazz == byte.class || clazz == Byte.class){
   return Byte.valueOf(String.valueOf(value));
  }else if (clazz == float.class || clazz == Float.class){
   return Float.valueOf(String.valueOf(value));
  }else if (clazz == double.class || clazz == Double.class){
   return Double.valueOf(String.valueOf(value));
  }else if (clazz == long.class || clazz == Long.class){
   return Long.valueOf(String.valueOf(value));
  }else if (clazz == BigDecimal.class){
   return new BigDecimal(String.valueOf(value));
  }else if (clazz == BigInteger.class){
   return new BigDecimal(String.valueOf(value));
  }else {
   throw new RuntimeException("This type conversion is not supported!");
  }
 }
}

Date類(lèi)型轉(zhuǎn)換器

/**
 * 日期轉(zhuǎn)換器
 * 對(duì)于日期校驗(yàn),這里只是簡(jiǎn)單的做了一下,實(shí)際上還有對(duì)閏年的校驗(yàn),
 * 每個(gè)月份的天數(shù)的校驗(yàn)及其他日期格式的校驗(yàn)
 * @author: qiumin
 * @create: 2018-12-30 10:43
 **/
public class DateConverter implements Converter{

 /**
  * 校驗(yàn) yyyy-MM-dd HH:mm:ss
  */
 private static final String REGEX_DATE_TIME = "^\\d{4}([-]\\d{2}){2}[ ]([0-1][0-9]|[2][0-4])(:[0-5][0-9]){2}$";

 /**
  * 校驗(yàn) yyyy-MM-dd
  */
 private static final String REGEX_DATE = "^\\d{4}([-]\\d{2}){2}$";

 /**
  * 校驗(yàn)HH:mm:ss
  */
 private static final String REGEX_TIME = "^([0-1][0-9]|[2][0-4])(:[0-5][0-9]){2}";

 /**
  * 校驗(yàn) yyyy-MM-dd HH:mm
  */
 private static final String REGEX_DATE_TIME_NOT_CONTAIN_SECOND = "^\\d{4}([-]\\d{2}){2}[ ]([0-1][0-9]|[2][0-4]):[0-5][0-9]$";

 /**
  * 默認(rèn)格式
  */
 private static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss";


 /**
  * 存儲(chǔ)數(shù)據(jù)map
  */
 private static final Map<String,String> PATTERN_MAP = new ConcurrentHashMap<>();

 static {
  PATTERN_MAP.put(REGEX_DATE,"yyyy-MM-dd");
  PATTERN_MAP.put(REGEX_DATE_TIME,"yyyy-MM-dd HH:mm:ss");
  PATTERN_MAP.put(REGEX_TIME,"HH:mm:ss");
  PATTERN_MAP.put(REGEX_DATE_TIME_NOT_CONTAIN_SECOND,"yyyy-MM-dd HH:mm");
 }

 @Override
 public Object convert(Type clazz, Object value) {
  if (clazz == null){
   throw new RuntimeException("type must be not null!");
  }
  if (value == null){
   return null;
  }else if ("".equals(String.valueOf(value))){
   return null;
  }
  try {
   return new SimpleDateFormat(getDateStrPattern(String.valueOf(value))).parse(String.valueOf(value));
  } catch (ParseException e) {
   throw new RuntimeException(e);
  }
 }

 /**
  * 獲取對(duì)應(yīng)的日期字符串格式
  * @param value
  * @return
  */
 private String getDateStrPattern(String value){
  for (Map.Entry<String,String> m : PATTERN_MAP.entrySet()){
   if (value.matches(m.getKey())){
    return m.getValue();
   }
  }
  return DEFAULT_PATTERN;
 }
}

具體分析不做過(guò)多討論,詳情看代碼。

那寫(xiě)完轉(zhuǎn)換器,那接下來(lái),我們肯定要從request中拿到前端傳的參數(shù),常用的獲取方式有request.getReader(),request.getInputStream(),但值得注意的是,這兩者者互斥。即在一次請(qǐng)求中使用了一者,然后另一個(gè)就獲取不到想要的結(jié)果。具體大家可以去試下。如果我們直接在解析requestJson注解的時(shí)候使用這兩個(gè)方法中的一個(gè),那很大可能會(huì)出問(wèn)題,因?yàn)槲覀円脖WC不了在spring中某個(gè)方法有使用到它,那肯定最好結(jié)果是不使用它或者包裝它(提前獲取getReader()/getInputStream()中的數(shù)據(jù),將其存入一個(gè)byte數(shù)組,后續(xù)request使用這兩個(gè)方法獲取數(shù)據(jù)可以直接從byte數(shù)組中拿數(shù)據(jù)),不使用肯定不行,那得進(jìn)一步去包裝它,在java ee中有提供這樣一個(gè)類(lèi)HttpServletRequestWrapper,它就是httpsevletRequest的一個(gè)子實(shí)現(xiàn)類(lèi),也就是意味httpservletRequest的可以用這個(gè)來(lái)代替,具體大家可以去看看源碼,spring提供了幾個(gè)HttpServletRequestWrapper的子類(lèi),這里就不重復(fù)造輪子,這里使用ContentCachingRequestWrapper類(lèi)。對(duì)request進(jìn)行包裝,肯定得在filter中進(jìn)行包裝

public class RequestJsonFilter implements Filter {


 /**
  * 用來(lái)對(duì)request中的Body數(shù)據(jù)進(jìn)一步包裝
  * @param req
  * @param response
  * @param chain
  * @throws IOException
  * @throws ServletException
  */
 @Override
 public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException, ServletException {
  ServletRequest requestWrapper = null;
  if(req instanceof HttpServletRequest) {
   HttpServletRequest request = (HttpServletRequest) req;
   /**
    * 只是為了防止一次請(qǐng)求中調(diào)用getReader(),getInputStream(),getParameter()
    * 都清楚inputStream 并不具有重用功能,即多次讀取同一個(gè)inputStream流,
    * 只有第一次讀取時(shí)才有數(shù)據(jù),后面再次讀取inputStream 沒(méi)有數(shù)據(jù),
    * 即,getReader(),只能調(diào)用一次,但getParameter()可以調(diào)用多次,詳情可見(jiàn)ContentCachingRequestWrapper源碼
    */
   requestWrapper = new ContentCachingRequestWrapper(request);
  }
  chain.doFilter(requestWrapper == null ? req : requestWrapper, response);
 }

實(shí)現(xiàn)了過(guò)濾器,那肯定得把過(guò)濾器注冊(cè)到spring容器中,

@Configuration
@EnableWebMvc
public class WebConfigure implements WebMvcConfigurer {


 @Autowired
 private RequestJsonHandler requestJsonHandler;

 // 把requestJson解析器也交給spring管理
 @Override
 public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
  resolvers.add(0,requestJsonHandler);
 }

 @Bean
 public FilterRegistrationBean filterRegister() {
  FilterRegistrationBean registration = new FilterRegistrationBean();
  registration.setFilter(new RequestJsonFilter());
  //攔截路徑
  registration.addUrlPatterns("/");
  //過(guò)濾器名稱(chēng)
  registration.setName("requestJsonFilter");
  //是否自動(dòng)注冊(cè) false 取消Filter的自動(dòng)注冊(cè)
  registration.setEnabled(false);
  //過(guò)濾器順序,需排在第一位
  registration.setOrder(1);
  return registration;
 }

 @Bean(name = "requestJsonFilter")
 public Filter requestFilter(){
  return new RequestJsonFilter();
 }
}

萬(wàn)事具備,就差解析器的代碼了。

對(duì)于前端參數(shù)的傳過(guò)來(lái)的json參數(shù)格式,大致有兩種。

一、{"name":"張三"}

二、[{"name":"張三"},{"name":"張三1"}]

所以解析的時(shí)候,要對(duì)這兩種情況分情況解析。

@Override
 public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {

  HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
  String contentType = request.getContentType();
  // 不是json
  if (!JSON_CONTENT_TYPE.equalsIgnoreCase(contentType)){
   return null;
  }
  Object obj = request.getAttribute(Constant.REQUEST_BODY_DATA_NAME);
  synchronized (RequestJsonHandler.class) {
   if (obj == null) {
    resolveRequestBody(request);
    obj = request.getAttribute(Constant.REQUEST_BODY_DATA_NAME);
    if (obj == null) {
     return null;
    }
   }
  }
  RequestJson requestJson = methodParameter.getParameterAnnotation(RequestJson.class);
  if (obj instanceof Map){
   Map<String, String> map = (Map<String, String>)obj;
   return dealWithMap(map,requestJson,methodParameter);
  }else if (obj instanceof List){
   List<Map<String,String>> list = (List<Map<String,String>>)obj;
   return dealWithArray(list,requestJson,methodParameter);
  }
  return null;
 }

 /**
  * 處理第一層json結(jié)構(gòu)為數(shù)組結(jié)構(gòu)的json串
  * 這種結(jié)構(gòu)默認(rèn)就認(rèn)為 為類(lèi)似List<JavaBean> 結(jié)構(gòu),轉(zhuǎn)json即為L(zhǎng)ist<Map<K,V>> 結(jié)構(gòu),
  * 其余情況不作處理,若controller層為第一種,則數(shù)組里的json,轉(zhuǎn)為javabean結(jié)構(gòu),字段名要對(duì)應(yīng),
  * 注意這里defaultValue不起作用
  * @param list
  * @param requestJson
  * @param methodParameter
  * @return
  */
 private Object dealWithArray(List<Map<String,String>> list,RequestJson requestJson,MethodParameter methodParameter){
  Class<?> parameterType = methodParameter.getParameterType();
  return ConverterUtil.getConverter(parameterType).convert(methodParameter.getGenericParameterType(),JsonUtil.convertBeanToStr(list));
 }
 /**
  * 處理{"":""}第一層json結(jié)構(gòu)為map結(jié)構(gòu)的json串,
  * @param map
  * @param requestJson
  * @param methodParameter
  * @return
  */
 private Object dealWithMap(Map<String,String> map,RequestJson requestJson,MethodParameter methodParameter){
  String fieldName = requestJson.fieldName();
  if ("".equals(fieldName)){
   fieldName = methodParameter.getParameterName();
  }
  Class<?> parameterType = methodParameter.getParameterType();
  String orDefault = null;
  if (map.containsKey(fieldName)){
   orDefault = map.get(fieldName);
  }else if (ConverterUtil.isMapType(parameterType)){
   return map;
  }else if (ConverterUtil.isBeanType(parameterType) || ConverterUtil.isCollectionType(parameterType)){
   orDefault = JsonUtil.convertBeanToStr(map);
  }else {
   orDefault = map.getOrDefault(fieldName,requestJson.defaultValue());
  }
  return ConverterUtil.getConverter(parameterType).convert(methodParameter.getGenericParameterType(),orDefault);
 }

 /**
  * 解析request中的body數(shù)據(jù)
  * @param request
  */
 private void resolveRequestBody(ServletRequest request){
  BufferedReader reader = null;
  try {
   reader = request.getReader();
   StringBuilder sb = new StringBuilder();
   String line = null;
   while ((line = reader.readLine()) != null) {
    sb.append(line);
   }
   String parameterValues = sb.toString();
   JsonParser parser = new JsonParser();
   JsonElement element = parser.parse(parameterValues);
   if (element.isJsonArray()){
    List<Map<String,String>> list = new ArrayList<>();
    list = JsonUtil.convertStrToBean(list.getClass(),parameterValues);
    request.setAttribute(Constant.REQUEST_BODY_DATA_NAME, list);
   }else {
    Map<String, String> map = new HashMap<>();
    map = JsonUtil.convertStrToBean(map.getClass(), parameterValues);
    request.setAttribute(Constant.REQUEST_BODY_DATA_NAME, map);
   }
  } catch (IOException e) {
   e.printStackTrace();
  }finally {
   if (reader != null){
    try {
     reader.close();
    } catch (IOException e) {
     // ignore
     //e.printStackTrace();
    }
   }
  }
 }

整個(gè)代碼結(jié)構(gòu)就是上面博文,完整代碼在github上,有感興趣的博友,可以看看地址  github鏈接,最后貼下maven依賴(lài)包

<dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-tomcat</artifactId>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>com.google.code.gson</groupId>
   <artifactId>gson</artifactId>
   <version>2.8.4</version>
  </dependency>
 </dependencies>

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java 調(diào)用天氣Webservice詳解及實(shí)例代碼

    Java 調(diào)用天氣Webservice詳解及實(shí)例代碼

    這篇文章主要介紹了Java 調(diào)用天氣Webservice詳解及實(shí)例代碼的相關(guān)資料,這里附實(shí)例代碼,使用java 調(diào)用webservice 的小應(yīng)用,需要的朋友可以參考下
    2016-11-11
  • Java學(xué)習(xí)關(guān)于循環(huán)和數(shù)組練習(xí)題整理

    Java學(xué)習(xí)關(guān)于循環(huán)和數(shù)組練習(xí)題整理

    在本篇文章里小編給各位整理了關(guān)于Java學(xué)習(xí)關(guān)于循環(huán)和數(shù)組練習(xí)題相關(guān)內(nèi)容,有興趣的朋友們跟著參考學(xué)習(xí)下。
    2019-07-07
  • 詳解Java中的鎖Lock和synchronized

    詳解Java中的鎖Lock和synchronized

    鎖是Java并發(fā)編程中最重要的同步機(jī)制,Java提供了種類(lèi)豐富的鎖,每種鎖因其特性的不同,在適當(dāng)?shù)膱?chǎng)景下能夠展現(xiàn)出非常高的效率。本文將詳細(xì)介紹Lock和synchronized
    2021-06-06
  • Java語(yǔ)言的Comparable和Comparator區(qū)別

    Java語(yǔ)言的Comparable和Comparator區(qū)別

    這篇文章主要介紹了Java語(yǔ)言的Comparable和Comparator區(qū)別,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • IDEA?Eval?Reset?使用方法匯總

    IDEA?Eval?Reset?使用方法匯總

    本文給大家介紹了IDEA?Eval?Reset?使用方法,安裝插件包括離線(xiàn)安裝方式和在線(xiàn)安裝方式,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2023-10-10
  • HttpClient詳細(xì)使用示例詳解

    HttpClient詳細(xì)使用示例詳解

    這篇文章主要介紹了HttpClient詳細(xì)使用示例詳解,本文給大家介紹的非常想詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • Java中Spock框架Mock對(duì)象的方法經(jīng)驗(yàn)總結(jié)

    Java中Spock框架Mock對(duì)象的方法經(jīng)驗(yàn)總結(jié)

    這篇文章主要分享了Spock框架Mock對(duì)象的方法經(jīng)驗(yàn)總結(jié),下文分享一些常用項(xiàng)目實(shí)戰(zhàn)說(shuō)明以及代碼,供大家項(xiàng)目中參考,也具有一的的參考價(jià)值,需要的小伙伴可以參考一下
    2022-02-02
  • SpringBoot+Redisson自定義注解一次解決重復(fù)提交問(wèn)題

    SpringBoot+Redisson自定義注解一次解決重復(fù)提交問(wèn)題

    項(xiàng)目中經(jīng)常會(huì)出現(xiàn)重復(fù)提交的問(wèn)題,本文主要介紹了SpringBoot+Redisson自定義注解一次解決重復(fù)提交問(wèn)題,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • Java多線(xiàn)程并發(fā)執(zhí)行demo代碼實(shí)例

    Java多線(xiàn)程并發(fā)執(zhí)行demo代碼實(shí)例

    這篇文章主要介紹了Java多線(xiàn)程并發(fā)執(zhí)行demo代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Java反射如何獲取字段屬性值

    Java反射如何獲取字段屬性值

    這篇文章主要介紹了Java反射如何獲取字段屬性值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07

最新評(píng)論