最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用自定義參數(shù)解析器同一個(gè)參數(shù)支持多種Content-Type

 更新時(shí)間:2021年08月18日 09:53:43   作者:DDF_YiChen  
這篇文章主要介紹了使用自定義參數(shù)解析器同一個(gè)參數(shù)支持多種Content-Type的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一堆廢話

事出有因, 原先上線的接口現(xiàn)在被要求用Java重寫(xiě),按照原暴露出去的文檔然后毫無(wú)疑問(wèn)的,按照J(rèn)ava的慣例,

一定是@RequestBody然后去接收application/json;charset=utf-8,然后一通參數(shù)接收處理邏輯。

結(jié)果測(cè)試都通過(guò)了,上線的時(shí)候,剛把原接口切到新接口上,日志就狂飆

application/x-www-form-urlencoded;charset=utf-8 NOT SUPPORT

What?然后就一通問(wèn)號(hào)臉。趕緊把接口切回到老接口,然后跑去問(wèn)PHP的同事,什么情況,原對(duì)接參數(shù)不是json嗎?

然后才明白,草,原來(lái)要同時(shí)支持application/json;charset=utf-8和application/x-www-form-urlencoded;charset=utf-8

PHP咱是不懂的,但是Java對(duì)這個(gè)需求的原生支持卻不是很好,印象中沒(méi)有現(xiàn)成的。

因?yàn)橐话阄覀兌x對(duì)象接收參數(shù),如果使用了@RequestBody接收,那么傳參一定要使用post+一個(gè)對(duì)應(yīng)的參數(shù)解析器一個(gè)可讀的流,按照現(xiàn)在的情況即application/json;charset=utf-8。

要么是直接一個(gè)對(duì)象接收,不要加任何注解,這個(gè)時(shí)候?qū)?yīng)的Content-Type是application/x-www-form-urlencoded;charset=utf-8則參數(shù)可正常解析。

但是這兩種情況是矛盾的,如果一個(gè)加了@RequestBody的參數(shù)對(duì)應(yīng)的Content-Type是application/x-www-form-urlencoded;charset=utf-8, 則最終無(wú)法解析。反過(guò)來(lái)如果一個(gè)未加@RequestBody的參數(shù)對(duì)應(yīng)的Content-Type是application/json;charset=utf-8則也無(wú)法解析。

那么現(xiàn)在就只能來(lái)看一下如何定義一個(gè)自定義的參數(shù)解析器來(lái)完成這個(gè)需求了。但是這個(gè)自定義的參數(shù)解析器還有點(diǎn)不太一樣,因?yàn)閿?shù)據(jù)格式本身不是我們自定義的,本身就存在對(duì)應(yīng)標(biāo)準(zhǔn)的解析器。只是SpringMVC在根據(jù)參數(shù)去找對(duì)應(yīng)解析器的時(shí)候沒(méi)有對(duì)應(yīng)起來(lái)。我們現(xiàn)在只要讓自己的解析器能夠讓這個(gè)參數(shù)轉(zhuǎn)發(fā)到對(duì)應(yīng)可以解析的參數(shù)解析器上就可以了。

探究Springmvc參數(shù)解析器工作流程

現(xiàn)在就要不怕麻煩的還看一下原來(lái)的參數(shù)解析器是如何工作的,畢竟不知道它怎么寫(xiě)的我也不知道怎么抄。

SpringMVC項(xiàng)目,二話不說(shuō),直接找到org.springframework.web.servlet.DispatcherServlet#doDispatch這個(gè)方法,看整個(gè)處理器的流程,這里直接簡(jiǎn)化找到最終映射到方法后的執(zhí)行

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

方法跳轉(zhuǎn)流程如下

public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
 @Override
 @Nullable
 public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
   throws Exception {
  return handleInternal(request, response, (HandlerMethod) handler);
 }
}

我再跳

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
  implements BeanFactoryAware, InitializingBean {
 /**
  * 參數(shù)解析器列表
  */
 @Nullable
 private HandlerMethodArgumentResolverComposite argumentResolvers;
 
 @Override
 protected ModelAndView handleInternal(HttpServletRequest request,
   HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  ModelAndView mav;
  checkRequest(request);
  // 這里刪除了大量相關(guān)判斷方法,只關(guān)注實(shí)際跳轉(zhuǎn)執(zhí)行方法
  // No synchronization on session demanded at all...
  mav = invokeHandlerMethod(request, response, handlerMethod); 
 }
 
 /**
  * 上面跳到了這里
  */
 @Nullable
 protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
   HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  // 這里又刪除了大量的代碼
  ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
  // 將本類(lèi)自己的參數(shù)解析器列表賦值給ServletInvocableHandlerMethod 
  if (this.argumentResolvers != null) {
   invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
  }
  if (this.returnValueHandlers != null) {
   invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
  }
  invocableMethod.setDataBinderFactory(binderFactory);
  invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
  // 帶著使命繼續(xù)往下執(zhí)行
  invocableMethod.invokeAndHandle(webRequest, mavContainer);
 }
}

接著跳到了

org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
 public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
   Object... providedArgs) throws Exception {
  Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
  // 再刪除無(wú)關(guān)代碼
 }
}

這里總算看到了一些關(guān)鍵信息了

org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest
public class InvocableHandlerMethod extends HandlerMethod {
 @Nullable
 public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
   Object... providedArgs) throws Exception {
  // 這里就是解析參數(shù)
  Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
  if (logger.isTraceEnabled()) {
   logger.trace("Arguments: " + Arrays.toString(args));
  }
  return doInvoke(args);
 }
 
 /**
  * 上面方法跳到了這里
  */
 protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
   Object... providedArgs) throws Exception {
  // 這里就是獲取入?yún)⒌膮?shù)類(lèi)型,如單個(gè)字符串的每個(gè)參數(shù),或者是某個(gè)對(duì)象參數(shù),甚至是HttpServletRequest
  MethodParameter[] parameters = getMethodParameters();
  if (ObjectUtils.isEmpty(parameters)) {
   return EMPTY_ARGS;
  }
  
  Object[] args = new Object[parameters.length];
  // 下面就是遍歷每個(gè)參數(shù)類(lèi)型,然后挨個(gè)解析
  for (int i = 0; i < parameters.length; i++) {
   MethodParameter parameter = parameters[i];
   parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
   args[i] = findProvidedArgument(parameter, providedArgs);
   if (args[i] != null) {
    continue;
   }
   // org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#supportsParameter
   // 后面就貼出了這個(gè)方法的內(nèi)部,就是遍歷所有的參數(shù)解析器判斷是否能夠解析當(dāng)前參數(shù)
   if (!this.resolvers.supportsParameter(parameter)) {
    throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
   }
   try {
       // 獲取參數(shù)解析器,解析當(dāng)前參數(shù)
    args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
   }
   catch (Exception ex) {
    // Leave stack trace for later, exception may actually be resolved and handled...
    if (logger.isDebugEnabled()) {
     String exMsg = ex.getMessage();
     if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
      logger.debug(formatArgumentError(parameter, exMsg));
     }
    }
    throw ex;
   }
  }
  return args;
 }
}

上面關(guān)于找到參數(shù)解析器的關(guān)鍵代碼

org.springframework.web.method.support.HandlerMethodArgumentResolverComposite
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
  private final List<HandlerMethodArgumentResolver> argumentResolvers = new LinkedList<>();
 private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
   new ConcurrentHashMap<>(256);
 
 /**
  * 判斷參數(shù)是否能夠找到對(duì)應(yīng)的參數(shù)解析器
  */
 @Override
 public boolean supportsParameter(MethodParameter parameter) {
  return getArgumentResolver(parameter) != null;
 }
 
 @Nullable
 private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
  // 這里指向一個(gè)本地緩存,如果一個(gè)參數(shù)類(lèi)型可以被某個(gè)參數(shù)解析器解析,則緩存下次無(wú)須遍歷
  HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
  if (result == null) {
      // 遍歷所有的參數(shù)解析器,判斷是否支持當(dāng)前參數(shù)類(lèi)型
   for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
    if (resolver.supportsParameter(parameter)) {
     result = resolver;
     // 如果支持則放入本地緩存,下次直接從緩存中取
     this.argumentResolverCache.put(parameter, result);
     break;
    }
   }
  }
  return result;
 }
 
 @Override
 @Nullable
 public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
   NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
  // 獲取該參數(shù)類(lèi)型對(duì)應(yīng)的參數(shù)解析器
  HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
  if (resolver == null) {
   throw new IllegalArgumentException("Unsupported parameter type [" +
     parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
  }
  // 解析參數(shù)
  return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
 } 
}

通過(guò)對(duì)

org.springframework.web.method.support.HandlerMethodArgumentResolverComposite#getArgumentResolver

的調(diào)試, 我們貼出幾張圖來(lái)說(shuō)明系統(tǒng)中目前所有的參數(shù)解析器,以及我們目前需要的用來(lái)解析@RequestBody和application/x-www-form-urlencoded對(duì)應(yīng)的參數(shù)解析器

application/x-www-form-urlencoded對(duì)應(yīng)的解析器為ServletModelAttributeMethodProcessor
@RequestBody application/json對(duì)應(yīng)的解析器為RequestResponseBodyMethodProcessor
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
 @Override
 public boolean supportsParameter(MethodParameter parameter) {
     // 可以看到必須要有RequestBody這個(gè)注解,該參數(shù)解析器才會(huì)工作
  return parameter.hasParameterAnnotation(RequestBody.class);
 }
}

順便說(shuō)下為什么我們?cè)赾ontroller方法入?yún)⒌臅r(shí)候?qū)慔ttpServletRequest和HttpServletResponse也能夠入?yún)⑦M(jìn)來(lái),就是因?yàn)橛袑?duì)應(yīng)的參數(shù)解析器,這里也給找出來(lái)了

org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver
org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver

不想看廢話的可以直接進(jìn)結(jié)果

定義一個(gè)注解用于標(biāo)注在參數(shù)上,用以標(biāo)識(shí)這個(gè)參數(shù)希望用我們的參數(shù)解析器進(jìn)行解析

import java.lang.annotation.*;
/**
 * <p>標(biāo)識(shí)參數(shù)可以被多個(gè)參數(shù)解析器嘗試進(jìn)行參數(shù)解析</p >
 *
 * 同一個(gè)參數(shù)支持application/json和application/x-www-form-urlencoded
 *
 * @see com.company.content.risk.order.common.handle.MultiArgumentResolverMethodProcessor
 * @author Snowball
 * @version 1.0
 * @date 2020/08/31 18:57
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MultiArgumentResolver {
}

實(shí)現(xiàn)一個(gè)自定義參數(shù)解析器,要實(shí)現(xiàn)接口org.springframework.web.method.support.HandlerMethodArgumentResolver。在解析方法里我們?nèi)ヅ袛喈?dāng)前客戶端傳入的Content-Type, 如果是application/json則將參數(shù)解析交給RequestResponseBodyMethodProcessor, 如果是application/x-www-form-urlencoded, 則將參數(shù)解析交給ServletModelAttributeMethodProcessor。

HandlerMethodArgumentResolver接口要實(shí)現(xiàn)兩個(gè)方法

  • supportsParameter 判斷當(dāng)前解析器是否支持入?yún)?duì)象
  • resolveArgument 解析邏輯
import com.company.content.risk.order.common.annotation.MultiArgumentResolver;
import com.google.common.collect.ImmutableList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.web.HttpMediaTypeNotSupportedException;
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.HandlerMethodArgumentResolverComposite;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * 自定義參數(shù)解析器用以支持同一個(gè)參數(shù)支持application/json和application/x-www-form-urlencoded解析
 *
 * @see MultiArgumentResolver
 * @author Snowball
 * @version 1.0
 * @date 2020/08/31 19:00
 */
public class MultiArgumentResolverMethodProcessor implements HandlerMethodArgumentResolver  {
    @Autowired
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
    private static final String CONTENT_TYPE_JSON = "application/json";
    private static final String CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded";
    /**
     * 支持的content_type
     */
    private static final ImmutableList<String> SUPPORT_CONTENT_TYPE_LIST = ImmutableList.of(CONTENT_TYPE_JSON, CONTENT_TYPE_FORM_URLENCODED);
    /**
     * 參考這個(gè)寫(xiě)法, 同一個(gè)類(lèi)型的參數(shù)解析后緩存對(duì)應(yīng)的參數(shù)解析器,不過(guò)這里的key改為了Content-Type
     * @see HandlerMethodArgumentResolverComposite#argumentResolverCache
     */
    private final Map<String, HandlerMethodArgumentResolver> argumentResolverCache =
            new ConcurrentHashMap<>(8);
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameter().isAnnotationPresent(MultiArgumentResolver.class);
    }
    /**
     * 解析參數(shù)
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String contentType = webRequest.getHeader("Content-Type");
        isSupport(contentType);
        List<HandlerMethodArgumentResolver> argumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers();
        HandlerMethodArgumentResolver handlerMethodArgumentResolver = argumentResolverCache.get(contentType);
        if (handlerMethodArgumentResolver != null) {
            return handlerMethodArgumentResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
        }
        for (HandlerMethodArgumentResolver argumentResolver : argumentResolvers) {
            if (isJson(contentType) && argumentResolver instanceof RequestResponseBodyMethodProcessor) {
                argumentResolverCache.put(contentType, argumentResolver);
                return argumentResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
            } else if (isFormUrlEncoded(contentType) && argumentResolver instanceof ServletModelAttributeMethodProcessor) {
                argumentResolverCache.put(contentType, argumentResolver);
                return argumentResolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
            }
        }
        return null;
    }
    private boolean isJson(String contentType) {
        return contentType.contains(CONTENT_TYPE_JSON);
    }
    private boolean isFormUrlEncoded(String contentType) {
        return contentType.contains(CONTENT_TYPE_FORM_URLENCODED);
    }
    /**
     * 判斷當(dāng)前參數(shù)解析器是否支持解析當(dāng)前的Content-Type
     * @param contentType
     * @return
     * @throws HttpMediaTypeNotSupportedException
     */
    private boolean isSupport(String contentType) throws HttpMediaTypeNotSupportedException {
        if (contentType == null) {
            throw new HttpMediaTypeNotSupportedException("contentType不能為空");
        }
        boolean isMatch = false;
        for (String item : SUPPORT_CONTENT_TYPE_LIST) {
            if (contentType.contains(item)) {
                isMatch = true;
                break;
            }
        }
        if (!isMatch) {
            throw new HttpMediaTypeNotSupportedException("支持Content-Type" + SUPPORT_CONTENT_TYPE_LIST.toString());
        }
        return true;
    }

將參數(shù)解析器注冊(cè)成bean,添加到系統(tǒng)參數(shù)解析器列表即可

import com.company.content.risk.order.common.handle.MultiArgumentResolverMethodProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
 * <p>web核心配置</p >
 *
 * @author Snowball
 * @version 1.0
 * @date 2020/08/31 18:57
 */
@Configuration
@Order
public class CoreWebConfig implements WebMvcConfigurer {
    /**
     * 注冊(cè)自定義參數(shù)解析器
     * @return
     */
    @Bean
    public MultiArgumentResolverMethodProcessor multiArgumentResolverMethodProcessor() {
        return new MultiArgumentResolverMethodProcessor();
    }
    /**
     * 添加自定義參數(shù)解析器
     * @param resolvers
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(0, multiArgumentResolverMethodProcessor());
    }
}

使用,將@MultiArgumentResolver標(biāo)識(shí)在controller方法的某個(gè)入?yún)?duì)象即可

@PostMapping(value = "text/submit")
public OutApiResponse<OutTextResponseBody> submitText(@MultiArgumentResolver OutTextRequest outTextRequest) {
}

補(bǔ)充

在上面自定義參數(shù)解析器的類(lèi)中,注入了一個(gè)bean,類(lèi)為RequestMappingHandlerAdapter, 目的是為了從這個(gè)類(lèi)中獲取到目前系統(tǒng)中已有的參數(shù)解析器列表。那么如何知道這個(gè)類(lèi)里面包含了哪些參數(shù)解析器呢?摘錄相關(guān)代碼如下。這個(gè)類(lèi)實(shí)現(xiàn)了接口InitializingBean,在bean初始化完成后調(diào)用afterPropertiesSet,然后在里面判斷加入了默認(rèn)的參數(shù)解析器列表

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
		implements BeanFactoryAware, InitializingBean {
	@Nullable
	private HandlerMethodArgumentResolverComposite argumentResolvers;
	
	@Override
	public void afterPropertiesSet() {
		// Do this first, it may add ResponseBody advice beans
		initControllerAdviceCache();
		if (this.argumentResolvers == null) {
			List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
			this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
		}
	}
	private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
		// Annotation-based argument resolution
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
		resolvers.add(new RequestParamMapMethodArgumentResolver());
		resolvers.add(new PathVariableMethodArgumentResolver());
		resolvers.add(new PathVariableMapMethodArgumentResolver());
		resolvers.add(new MatrixVariableMethodArgumentResolver());
		resolvers.add(new MatrixVariableMapMethodArgumentResolver());
		resolvers.add(new ServletModelAttributeMethodProcessor(false));
		resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
		resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
		resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new RequestHeaderMapMethodArgumentResolver());
		resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
		resolvers.add(new SessionAttributeMethodArgumentResolver());
		resolvers.add(new RequestAttributeMethodArgumentResolver());
		// Type-based argument resolution
		resolvers.add(new ServletRequestMethodArgumentResolver());
		resolvers.add(new ServletResponseMethodArgumentResolver());
		resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
		resolvers.add(new RedirectAttributesMethodArgumentResolver());
		resolvers.add(new ModelMethodProcessor());
		resolvers.add(new MapMethodProcessor());
		resolvers.add(new ErrorsMethodArgumentResolver());
		resolvers.add(new SessionStatusMethodArgumentResolver());
		resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
		// Custom arguments
		if (getCustomArgumentResolvers() != null) {
			resolvers.addAll(getCustomArgumentResolvers());
		}
		// Catch-all
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
		resolvers.add(new ServletModelAttributeMethodProcessor(true));
		return resolvers;
	}
}

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot返回對(duì)象時(shí),如何將Long類(lèi)型轉(zhuǎn)換為String

    SpringBoot返回對(duì)象時(shí),如何將Long類(lèi)型轉(zhuǎn)換為String

    這篇文章主要介紹了SpringBoot返回對(duì)象時(shí),實(shí)現(xiàn)將Long類(lèi)型轉(zhuǎn)換為String,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java使用easyExcel導(dǎo)出excel數(shù)據(jù)案例

    Java使用easyExcel導(dǎo)出excel數(shù)據(jù)案例

    這篇文章主要介紹了Java使用easyExcel導(dǎo)出excel數(shù)據(jù)案例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • maven中的scope與systemPath用法

    maven中的scope與systemPath用法

    這篇文章主要介紹了maven中的scope與systemPath用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 美化java代碼,從合理注釋開(kāi)始

    美化java代碼,從合理注釋開(kāi)始

    在Java的編寫(xiě)過(guò)程中我們需要對(duì)一些程序進(jìn)行注釋,除了自己方便閱讀,更為別人更好理解自己的程序,可以是編程思路或者是程序的作用,總而言之就是方便自己他人更好的閱讀。下面我們來(lái)一起學(xué)習(xí)一下吧
    2019-06-06
  • Java中File、Base64、MultipartFile之間相互轉(zhuǎn)換的代碼詳解

    Java中File、Base64、MultipartFile之間相互轉(zhuǎn)換的代碼詳解

    File、Base64和MultipartFile都是在編程中常用的類(lèi)或者數(shù)據(jù)類(lèi)型,用于處理文件和數(shù)據(jù)的存儲(chǔ)、傳輸和轉(zhuǎn)換等操作,本文將給大家介紹了Java中File、Base64、MultipartFile之間相互轉(zhuǎn)換,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下
    2024-04-04
  • 基于SpringBoot實(shí)現(xiàn)輕量級(jí)的動(dòng)態(tài)定時(shí)任務(wù)調(diào)度的方法

    基于SpringBoot實(shí)現(xiàn)輕量級(jí)的動(dòng)態(tài)定時(shí)任務(wù)調(diào)度的方法

    本文介紹了如何在SpringBoot框架中實(shí)現(xiàn)輕量級(jí)的動(dòng)態(tài)定時(shí)任務(wù)調(diào)度,通過(guò)將任務(wù)以類(lèi)為基礎(chǔ)單位,并通過(guò)配置數(shù)據(jù)進(jìn)行任務(wù)讀取和反射生成任務(wù)對(duì)象,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • Java多線程 Guarded Suspension設(shè)計(jì)模式

    Java多線程 Guarded Suspension設(shè)計(jì)模式

    這篇文章主要介紹了Java多線程 Guarded Suspension設(shè)計(jì)模式,Guarded Suspension意為保護(hù)暫停,其核心思想是僅當(dāng)服務(wù)進(jìn)程準(zhǔn)備好時(shí),才提供服務(wù),文章圍繞Java多線程 Guarded Suspension展開(kāi)內(nèi)容,需要的朋友可以參考一下
    2021-10-10
  • MyBatis批量插入的三種方式比較總結(jié)

    MyBatis批量插入的三種方式比較總結(jié)

    由于項(xiàng)目需要生成多條數(shù)據(jù),并保存到數(shù)據(jù)庫(kù)當(dāng)中,所以就用到了MyBatis批量插入,下面這篇文章主要給大家介紹了關(guān)于MyBatis批量插入的三種方式的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • 如何基于java實(shí)現(xiàn)Gauss消元法過(guò)程解析

    如何基于java實(shí)現(xiàn)Gauss消元法過(guò)程解析

    這篇文章主要介紹了如何基于java實(shí)現(xiàn)Gauss消元法過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • SpringBoot獲取ApplicationContext的3種方式

    SpringBoot獲取ApplicationContext的3種方式

    這篇文章主要為大家詳細(xì)介紹了SpringBoot獲取ApplicationContext的3種方式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09

最新評(píng)論

宣城市| 阳信县| 民权县| 蓬溪县| 兰溪市| 嘉善县| 汶上县| 德安县| 建宁县| 武安市| 搜索| 石嘴山市| 定远县| 灌阳县| 宿州市| 都江堰市| 沐川县| 荃湾区| 临沭县| 吴桥县| 曲周县| 永泰县| 崇义县| 青铜峡市| 秀山| 兴宁市| 银川市| 吐鲁番市| 南充市| 雷山县| 互助| 汝南县| 重庆市| 镇赉县| 海安县| 从江县| 综艺| 崇明县| 隆回县| 仙桃市| 望谟县|