<cite id="ffb66"></cite><cite id="ffb66"><track id="ffb66"></track></cite>
      <legend id="ffb66"><li id="ffb66"></li></legend>
      色婷婷久,激情色播,久久久无码专区,亚洲中文字幕av,国产成人A片,av无码免费,精品久久国产,99视频精品3
      網(wǎng)易首頁(yè) > 網(wǎng)易號(hào) > 正文 申請(qǐng)入駐

      SpringBoot 還在用 if 校驗(yàn)參數(shù)?那真的太 low 了,老司機(jī)都是這么玩的!

      0
      分享至

      Java精選面試題(微信小程序):5000+道面試題和選擇題,真實(shí)面經(jīng)簡(jiǎn)歷模版,包含Java基礎(chǔ)、并發(fā)、JVM、線程、MQ系列、Redis、Spring系列、Elasticsearch、Docker、K8s、Flink、Spark、架構(gòu)設(shè)計(jì)、大廠真題等,在線隨時(shí)刷題!


      在項(xiàng)目開(kāi)發(fā)中我們經(jīng)常會(huì)遇到各種參數(shù)校驗(yàn),尤其是表單參數(shù)的校驗(yàn)。當(dāng)參數(shù)不多時(shí)我們可以在控制器中手動(dòng)校驗(yàn),但是一旦遇到需要校驗(yàn)的參數(shù)較多的post接口時(shí),還去一個(gè)個(gè)的校驗(yàn)的話那會(huì)累死個(gè)人。

      其實(shí),Spring框架給我們提供了對(duì)象校驗(yàn)的API,可以幫助我們省去逐一手動(dòng)校驗(yàn)接口參數(shù)的煩惱。

      本文就和大家一起系統(tǒng)學(xué)習(xí)一下Spring Validation的使用,并搞懂其中的原理。


      簡(jiǎn)單使用

      Java API規(guī)范(JSR303)定義了Bean校驗(yàn)的標(biāo)準(zhǔn)validation-api,但沒(méi)有提供實(shí)現(xiàn)。hibernate validation是對(duì)這個(gè)規(guī)范的實(shí)現(xiàn),并增加了校驗(yàn)注解如@Email@Length等。

      Spring Validation是對(duì)hibernate validation的二次封裝,用于支持spring mvc參數(shù)自動(dòng)校驗(yàn)。接下來(lái),我們以spring-boot項(xiàng)目為例,介紹Spring Validation的使用。

      引入依賴

      如果spring-boot版本小于2.3.x,spring-boot-starter-web會(huì)自動(dòng)傳入hibernate-validator依賴。如果spring-boot版本大于2.3.x,則需要手動(dòng)引入依賴:

      
           
      
       org.hibernate groupId>     
      
       hibernate-validator artifactId>     
      
       6.0.1.Final version> dependency>
      
      
      
      

      對(duì)于web服務(wù)來(lái)說(shuō),為防止非法參數(shù)對(duì)業(yè)務(wù)造成影響,在Controller層一定要做參數(shù)校驗(yàn)的!大部分情況下,請(qǐng)求參數(shù)分為如下兩種形式:

      • POSTPUT請(qǐng)求,使用requestBody傳遞參數(shù);

      • GET請(qǐng)求,使用requestParam/PathVariable傳遞參數(shù)。

      實(shí)際上,不管是requestBody參數(shù)校驗(yàn)還是方法級(jí)別的校驗(yàn),最終都是調(diào)用Hibernate Validator執(zhí)行校驗(yàn),Spring Validation只是做了一層封裝。下面我們簡(jiǎn)單介紹下requestBodyrequestParam/PathVariable的參數(shù)校驗(yàn)實(shí)戰(zhàn)!

      requestBody參數(shù)校驗(yàn)

      POSTPUT請(qǐng)求一般會(huì)使用requestBody傳遞參數(shù),這種情況下,后端使用DTO對(duì)象進(jìn)行接收。只要給DTO對(duì)象加上@Validated注解就能實(shí)現(xiàn)自動(dòng)參數(shù)校驗(yàn)。比如,有一個(gè)保存User的接口,要求userName長(zhǎng)度是2-10,accountpassword字段長(zhǎng)度是6-20。如果校驗(yàn)失敗,會(huì)拋出MethodArgumentNotValidException異常,Spring默認(rèn)會(huì)將其轉(zhuǎn)為400(Bad Request)請(qǐng)求。

      DTO表示數(shù)據(jù)傳輸對(duì)象(Data Transfer Object),用于服務(wù)器和客戶端之間交互傳輸使用的。在spring-web項(xiàng)目中可以表示用于接收請(qǐng)求參數(shù)的Bean對(duì)象。

      在DTO字段上聲明約束注解

      @Data publicclass UserDTO {     private Long userId;     @NotNull     @Length(min = 2, max = 10)     private String userName;     @NotNull     @Length(min = 6, max = 20)     private String account;     @NotNull     @Length(min = 6, max = 20)     private String password; }

      在方法參數(shù)上聲明校驗(yàn)注解

      @PostMapping("/save") public Result saveUser(@RequestBody @Validated UserDTO userDTO) {     // 校驗(yàn)通過(guò),才會(huì)執(zhí)行業(yè)務(wù)邏輯處理     return Result.ok(); }

      這種情況下,使用@Valid@Validated都可以。

      requestParam/PathVariable參數(shù)校驗(yàn)

      GET請(qǐng)求一般會(huì)使用requestParam/PathVariable傳參。如果參數(shù)比較多(比如超過(guò)6個(gè)),還是推薦使用DTO對(duì)象接收。面試寶典:https://www.yoodb.com/

      否則,推薦將一個(gè)個(gè)參數(shù)平鋪到方法入?yún)⒅小T谶@種情況下,必須在Controller類上標(biāo)注@Validated注解,并在入?yún)⑸下暶骷s束注解(如@Min等)。如果校驗(yàn)失敗,會(huì)拋出ConstraintViolationException異常。

      代碼示例如下:

      @RequestMapping("/api/user") @RestController @Validated publicclass UserController {     // 路徑變量     @GetMapping("{userId}")     public Result detail(@PathVariable("userId") @Min(10000000000000000L) Long userId) {         // 校驗(yàn)通過(guò),才會(huì)執(zhí)行業(yè)務(wù)邏輯處理         UserDTO userDTO = new UserDTO();         userDTO.setUserId(userId);         userDTO.setAccount("11111111111111111");         userDTO.setUserName("xixi");         userDTO.setAccount("11111111111111111");         return Result.ok(userDTO);     }     // 查詢參數(shù)     @GetMapping("getByAccount")     public Result getByAccount(@Length(min = 6, max = 20) @NotNull String  account) {         // 校驗(yàn)通過(guò),才會(huì)執(zhí)行業(yè)務(wù)邏輯處理         UserDTO userDTO = new UserDTO();         userDTO.setUserId(10000000000000003L);         userDTO.setAccount(account);         userDTO.setUserName("xixi");         userDTO.setAccount("11111111111111111");         return Result.ok(userDTO);     } }

      統(tǒng)一異常處理

      前面說(shuō)過(guò),如果校驗(yàn)失敗,會(huì)拋出MethodArgumentNotValidException或者ConstraintViolationException異常。在實(shí)際項(xiàng)目開(kāi)發(fā)中,通常會(huì)用統(tǒng)一異常處理來(lái)返回一個(gè)更友好的提示。

      比如我們系統(tǒng)要求無(wú)論發(fā)送什么異常,http的狀態(tài)碼必須返回200,由業(yè)務(wù)碼去區(qū)分系統(tǒng)的異常情況。

      @RestControllerAdvice publicclass CommonExceptionHandler {     @ExceptionHandler({MethodArgumentNotValidException.class})     @ResponseStatus(HttpStatus.OK)     @ResponseBody     public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {         BindingResult bindingResult = ex.getBindingResult();         StringBuilder sb = new StringBuilder("校驗(yàn)失敗:");         for (FieldError fieldError : bindingResult.getFieldErrors()) {             sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");         }         String msg = sb.toString();        return Result.fail(BusinessCode.參數(shù)校驗(yàn)失敗, msg);     }     @ExceptionHandler({ConstraintViolationException.class})     @ResponseStatus(HttpStatus.OK)     @ResponseBody     public Result handleConstraintViolationException(ConstraintViolationException ex) {         return Result.fail(BusinessCode.參數(shù)校驗(yàn)失敗, ex.getMessage());     } }
      進(jìn)階使用

      在實(shí)際項(xiàng)目中,可能多個(gè)方法需要使用同一個(gè)DTO類來(lái)接收參數(shù),而不同方法的校驗(yàn)規(guī)則很可能是不一樣的。這個(gè)時(shí)候,簡(jiǎn)單地在DTO類的字段上加約束注解無(wú)法解決這個(gè)問(wèn)題。因此,spring-validation支持了分組校驗(yàn)的功能,專門用來(lái)解決這類問(wèn)題。

      還是上面的例子,比如保存User的時(shí)候,UserId是可空的,但是更新User的時(shí)候,UserId的值必須**>=10000000000000000L**;其它字段的校驗(yàn)規(guī)則在兩種情況下一樣。這個(gè)時(shí)候使用分組校驗(yàn)的代碼示例如下:

      約束注解上聲明適用的分組信息groups

      @Data publicclass UserDTO {     @Min(value = 10000000000000000L, groups = Update.class)     private Long userId;     @NotNull(groups = {Save.class, Update.class})     @Length(min = 2, max = 10, groups = {Save.class, Update.class})     private String userName;     @NotNull(groups = {Save.class, Update.class})     @Length(min = 6, max = 20, groups = {Save.class, Update.class})     private String account;     @NotNull(groups = {Save.class, Update.class})     @Length(min = 6, max = 20, groups = {Save.class, Update.class})     private String password;     /**      * 保存的時(shí)候校驗(yàn)分組      */     publicinterface Save {     }     /**      * 更新的時(shí)候校驗(yàn)分組      */     publicinterface Update {     } }

      @Validated注解上指定校驗(yàn)分組

      @PostMapping("/save") public Result saveUser(@RequestBody @Validated(UserDTO.Save.class) UserDTO userDTO) {     // 校驗(yàn)通過(guò),才會(huì)執(zhí)行業(yè)務(wù)邏輯處理     return Result.ok(); } @PostMapping("/update") public Result updateUser(@RequestBody @Validated(UserDTO.Update.class) UserDTO userDTO) {     // 校驗(yàn)通過(guò),才會(huì)執(zhí)行業(yè)務(wù)邏輯處理     return Result.ok(); }

      前面的示例中,DTO類里面的字段都是基本數(shù)據(jù)類型和String類型。但是實(shí)際場(chǎng)景中,有可能某個(gè)字段也是一個(gè)對(duì)象,這種情況先,可以使用嵌套校驗(yàn)。

      比如,上面保存User信息的時(shí)候同時(shí)還帶有Job信息。需要注意的是,此時(shí)DTO類的對(duì)應(yīng)字段必須標(biāo)記@Valid注解。

      @Data publicclass UserDTO {     @Min(value = 10000000000000000L, groups = Update.class)     private Long userId;     @NotNull(groups = {Save.class, Update.class})     @Length(min = 2, max = 10, groups = {Save.class, Update.class})     private String userName;     @NotNull(groups = {Save.class, Update.class})     @Length(min = 6, max = 20, groups = {Save.class, Update.class})     private String account;     @NotNull(groups = {Save.class, Update.class})     @Length(min = 6, max = 20, groups = {Save.class, Update.class})     private String password;     @NotNull(groups = {Save.class, Update.class})     @Valid     private Job job;     @Data     publicstaticclass Job {         @Min(value = 1, groups = Update.class)         private Long jobId;         @NotNull(groups = {Save.class, Update.class})         @Length(min = 2, max = 10, groups = {Save.class, Update.class})         private String jobName;         @NotNull(groups = {Save.class, Update.class})         @Length(min = 2, max = 10, groups = {Save.class, Update.class})         private String position;     }     /**      * 保存的時(shí)候校驗(yàn)分組      */     publicinterface Save {     }     /**      * 更新的時(shí)候校驗(yàn)分組      */     publicinterface Update {     } }

      嵌套校驗(yàn)可以結(jié)合分組校驗(yàn)一起使用。還有就是嵌套集合校驗(yàn)會(huì)對(duì)集合里面的每一項(xiàng)都進(jìn)行校驗(yàn),例如List 字段會(huì)對(duì)這個(gè)list里面的每一個(gè)Job對(duì)象都進(jìn)行校驗(yàn)

      如果請(qǐng)求體直接傳遞了json數(shù)組給后臺(tái),并希望對(duì)數(shù)組中的每一項(xiàng)都進(jìn)行參數(shù)校驗(yàn)。此時(shí),如果我們直接使用java.util.Collection下的list或者set來(lái)接收數(shù)據(jù),參數(shù)校驗(yàn)并不會(huì)生效!我們可以使用自定義list集合來(lái)接收參數(shù):

      包裝List類型,并聲明@Valid注解

      public class ValidationList
      
        implements List
      
        {     @Delegate // @Delegate是lombok注解     @Valid // 一定要加@Valid注解     public List list =  new ArrayList<>();     // 一定要記得重寫(xiě)toString方法     @Override     public String toString() {         return list.toString();     } }
      
      

      @Delegate注解受lombok版本限制,1.18.6以上版本可支持。如果校驗(yàn)不通過(guò),會(huì)拋出NotReadablePropertyException,同樣可以使用統(tǒng)一異常進(jìn)行處理。SpringBoot系列教程:https://www.yoodb.com/spring/spring-annotate.html

      比如,我們需要一次性保存多個(gè)User對(duì)象,Controller層的方法可以這么寫(xiě):

      @PostMapping("/saveList") public Result saveList(@RequestBody @Validated(UserDTO.Save.class) ValidationList userList)  {     // 校驗(yàn)通過(guò),才會(huì)執(zhí)行業(yè)務(wù)邏輯處理     return Result.ok(); }

      業(yè)務(wù)需求總是比框架提供的這些簡(jiǎn)單校驗(yàn)要復(fù)雜的多,我們可以自定義校驗(yàn)來(lái)滿足我們的需求。

      自定義spring validation非常簡(jiǎn)單,假設(shè)我們自定義加密id(由數(shù)字或者a-f的字母組成,32-256長(zhǎng)度)校驗(yàn),主要分為兩步:

      自定義約束注解

      @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER}) @Retention(RUNTIME) @Documented @Constraint(validatedBy = {EncryptIdValidator.class}) public @interface EncryptId {     // 默認(rèn)錯(cuò)誤消息     String message() default "加密id格式錯(cuò)誤";     // 分組     Class [] groups() default {};     // 負(fù)載     Class [] payload() default {}; }

      實(shí)現(xiàn)ConstraintValidator接口編寫(xiě)約束校驗(yàn)器

      public class EncryptIdValidator implements ConstraintValidator
      
        {     privatestaticfinal Pattern PATTERN = Pattern.compile("^[a-f\d]{32,256}$");     @Override     public boolean isValid(String value, ConstraintValidatorContext context) {         // 不為null才進(jìn)行校驗(yàn)         if (value != null) {             Matcher matcher = PATTERN.matcher(value);             return matcher.find();         }         returntrue;     } }
      

      這樣我們就可以使用@EncryptId進(jìn)行參數(shù)校驗(yàn)了!

      編程式校驗(yàn)

      上面的示例都是基于注解來(lái)實(shí)現(xiàn)自動(dòng)校驗(yàn)的,在某些情況下,我們可能希望以編程方式調(diào)用驗(yàn)證。這個(gè)時(shí)候可以注入javax.validation.Validator對(duì)象,然后再調(diào)用其api。

      @Autowired private javax.validation.Validator globalValidator; // 編程式校驗(yàn) @PostMapping("/saveWithCodingValidate") public Result saveWithCodingValidate(@RequestBody UserDTO userDTO) {     Set > validate = globalValidator.validate(userDTO, UserDTO.Save .class);     // 如果校驗(yàn)通過(guò),validate為空;否則,validate包含未校驗(yàn)通過(guò)項(xiàng)     if (validate.isEmpty()) {         // 校驗(yàn)通過(guò),才會(huì)執(zhí)行業(yè)務(wù)邏輯處理     } else {         for (ConstraintViolation userDTOConstraintViolation : validate) {             // 校驗(yàn)失敗,做其它邏輯             System.out.println(userDTOConstraintViolation);         }     }     return Result.ok(); }

      快速失敗(Fail Fast)

      Spring Validation默認(rèn)會(huì)校驗(yàn)完所有字段,然后才拋出異常。可以通過(guò)一些簡(jiǎn)單的配置,開(kāi)啟Fali Fast模式,一旦校驗(yàn)失敗就立即返回。

      @Bean public Validator validator() {     ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)             .configure()             // 快速失敗模式             .failFast(true)             .buildValidatorFactory();     return validatorFactory.getValidator(); }
      Validator實(shí)現(xiàn)原理

      spring-mvc中,RequestResponseBodyMethodProcessor是用于解析@RequestBody標(biāo)注的參數(shù)以及處理@ResponseBody標(biāo)注方法的返回值的。顯然,執(zhí)行參數(shù)校驗(yàn)的邏輯肯定就在解析參數(shù)的方法resolveArgument()中:

      public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {     @Override     public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,                                   NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {         parameter = parameter.nestedIfOptional();         //將請(qǐng)求數(shù)據(jù)封裝到DTO對(duì)象中         Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());         String name = Conventions.getVariableNameForParameter(parameter);         if (binderFactory != null) {             WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);             if (arg != null) {                 // 執(zhí)行數(shù)據(jù)校驗(yàn)                 validateIfApplicable(binder, parameter);                 if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {                     thrownew MethodArgumentNotValidException(parameter, binder.getBindingResult());                 }             }             if (mavContainer != null) {                 mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());             }         }         return adaptArgumentIfNecessary(arg, parameter);     } }

      可以看到,resolveArgument()調(diào)用了validateIfApplicable()進(jìn)行參數(shù)校驗(yàn)。

      protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {     // 獲取參數(shù)注解,比如@RequestBody、@Valid、@Validated     Annotation[] annotations = parameter.getParameterAnnotations();     for (Annotation ann : annotations) {         // 先嘗試獲取@Validated注解         Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);         //如果直接標(biāo)注了@Validated,那么直接開(kāi)啟校驗(yàn)。         //如果沒(méi)有,那么判斷參數(shù)前是否有Valid起頭的注解。         if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {             Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));             Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});             //執(zhí)行校驗(yàn)             binder.validate(validationHints);             break;         }     } }

      可以看到,resolveArgument()調(diào)用了validateIfApplicable()進(jìn)行參數(shù)校驗(yàn)。

      protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {     // 獲取參數(shù)注解,比如@RequestBody、@Valid、@Validated     Annotation[] annotations = parameter.getParameterAnnotations();     for (Annotation ann : annotations) {         // 先嘗試獲取@Validated注解         Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);         //如果直接標(biāo)注了@Validated,那么直接開(kāi)啟校驗(yàn)。         //如果沒(méi)有,那么判斷參數(shù)前是否有Valid起頭的注解。         if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {             Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));             Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});             //執(zhí)行校驗(yàn)             binder.validate(validationHints);             break;         }     } }

      看到這里,大家應(yīng)該能明白為什么這種場(chǎng)景下@Validated@Valid兩個(gè)注解可以混用。我們接下來(lái)繼續(xù)看WebDataBinder.validate()實(shí)現(xiàn)。

      @Override public void validate(Object target, Errors errors, Object... validationHints) {     if (this.targetValidator != null) {         processConstraintViolations(             //此處調(diào)用Hibernate Validator執(zhí)行真正的校驗(yàn)             this.targetValidator.validate(target, asValidationGroups(validationHints)), errors);     } }

      最終發(fā)現(xiàn)底層最終還是調(diào)用了Hibernate Validator進(jìn)行真正的校驗(yàn)處理。

      方法級(jí)別的參數(shù)校驗(yàn)實(shí)現(xiàn)原理

      上面提到的將參數(shù)一個(gè)個(gè)平鋪到方法參數(shù)中,然后在每個(gè)參數(shù)前面聲明約束注解的校驗(yàn)方式,就是方法級(jí)別的參數(shù)校驗(yàn)。

      實(shí)際上,這種方式可用于任何Spring Bean的方法上,比如Controller/Service等。其底層實(shí)現(xiàn)原理就是AOP,具體來(lái)說(shuō)是通過(guò)MethodValidationPostProcessor動(dòng)態(tài)注冊(cè)AOP切面,然后使用MethodValidationInterceptor對(duì)切點(diǎn)方法織入增強(qiáng)。

      public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessorimplements InitializingBean {     @Override     public void afterPropertiesSet() {         //為所有`@Validated`標(biāo)注的Bean創(chuàng)建切面         Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);         //創(chuàng)建Advisor進(jìn)行增強(qiáng)         this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));     }     //創(chuàng)建Advice,本質(zhì)就是一個(gè)方法攔截器     protected Advice createMethodValidationAdvice(@Nullable Validator validator) {         return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());     } }

      接著看一下MethodValidationInterceptor:

      public class MethodValidationInterceptor implements MethodInterceptor {     @Override     public Object invoke(MethodInvocation invocation) throws Throwable {         //無(wú)需增強(qiáng)的方法,直接跳過(guò)         if (isFactoryBeanMetadataMethod(invocation.getMethod())) {             return invocation.proceed();         }         //獲取分組信息         Class [] groups = determineValidationGroups(invocation);         ExecutableValidator execVal = this.validator.forExecutables();         Method methodToValidate = invocation.getMethod();         Set > result;         try {             //方法入?yún)⑿r?yàn),最終還是委托給Hibernate Validator來(lái)校驗(yàn)             result = execVal.validateParameters(                 invocation.getThis(), methodToValidate, invocation.getArguments(), groups);         }         catch (IllegalArgumentException ex) {             ...         }         //有異常直接拋出         if (!result.isEmpty()) {             thrownew ConstraintViolationException(result);         }         //真正的方法調(diào)用         Object returnValue = invocation.proceed();         //對(duì)返回值做校驗(yàn),最終還是委托給Hibernate Validator來(lái)校驗(yàn)         result = execVal.validateReturnValue(invocation.getThis(), methodToValidate, returnValue, groups);         //有異常直接拋出         if (!result.isEmpty()) {             thrownew ConstraintViolationException(result);         }         return returnValue;     } }

      實(shí)際上,不管是requestBody參數(shù)校驗(yàn)還是方法級(jí)別的校驗(yàn),最終都是調(diào)用Hibernate Validator執(zhí)行校驗(yàn),Spring Validation只是做了一層封裝。

      作者:鼓樓丶

      https://juejin.cn/post/7080419992386142215

      公眾號(hào)“Java精選”所發(fā)表內(nèi)容注明來(lái)源的,版權(quán)歸原出處所有(無(wú)法查證版權(quán)的或者未注明出處的均來(lái)自網(wǎng)絡(luò),系轉(zhuǎn)載,轉(zhuǎn)載的目的在于傳遞更多信息,版權(quán)屬于原作者。如有侵權(quán),請(qǐng)聯(lián)系,筆者會(huì)第一時(shí)間刪除處理!

      最近有很多人問(wèn),有沒(méi)有讀者交流群!加入方式很簡(jiǎn)單,公眾號(hào)Java精選,回復(fù)“加群”,即可入群!

      文章有幫助的話,點(diǎn)在看,轉(zhuǎn)發(fā)吧!

      特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。

      Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

      相關(guān)推薦
      熱點(diǎn)推薦
      總有人納悶,王健林就算只剩100億,為啥王思聰花錢還是那么大方

      總有人納悶,王健林就算只剩100億,為啥王思聰花錢還是那么大方

      小光侃娛樂(lè)
      2025-12-10 22:10:04
      瓜帥:我不想以被解雇的方式離開(kāi),我想好好結(jié)束

      瓜帥:我不想以被解雇的方式離開(kāi),我想好好結(jié)束

      懂球帝
      2025-12-20 15:09:22
      何穗忙完工作一天也不想帶娃!回家換完衣跑去看展覽,當(dāng)媽后多愁

      何穗忙完工作一天也不想帶娃!回家換完衣跑去看展覽,當(dāng)媽后多愁

      趕山的姑娘
      2025-12-20 21:23:24
      湘潭一村民組開(kāi)會(huì)決議將“外嫁女”所得法院執(zhí)行款項(xiàng)從其親屬頭上扣除,村支書(shū):對(duì)決議不知情,未簽字批準(zhǔn)

      湘潭一村民組開(kāi)會(huì)決議將“外嫁女”所得法院執(zhí)行款項(xiàng)從其親屬頭上扣除,村支書(shū):對(duì)決議不知情,未簽字批準(zhǔn)

      紅星新聞
      2025-12-20 00:33:11
      北京阿姨20年守茅臺(tái)股票:90萬(wàn)本金,分紅326萬(wàn),成本歸零!

      北京阿姨20年守茅臺(tái)股票:90萬(wàn)本金,分紅326萬(wàn),成本歸零!

      趣文說(shuō)娛
      2025-12-20 18:29:20
      少一人仍不輸,47歲蘭帕德率隊(duì)1-1,狂攬48分領(lǐng)跑+領(lǐng)先米堡6分

      少一人仍不輸,47歲蘭帕德率隊(duì)1-1,狂攬48分領(lǐng)跑+領(lǐng)先米堡6分

      側(cè)身凌空斬
      2025-12-20 22:31:10
      上海迪士尼突發(fā)一幕,演出被迫中斷!網(wǎng)友:她還在笑,心太大了

      上海迪士尼突發(fā)一幕,演出被迫中斷!網(wǎng)友:她還在笑,心太大了

      環(huán)球網(wǎng)資訊
      2025-12-20 09:29:14
      我外交部突然發(fā)出警告,如果外媒消息屬實(shí),中日事態(tài)將會(huì)相當(dāng)嚴(yán)重

      我外交部突然發(fā)出警告,如果外媒消息屬實(shí),中日事態(tài)將會(huì)相當(dāng)嚴(yán)重

      芊芊子吟
      2025-12-20 14:07:18
      人類文明現(xiàn)在只有0.73級(jí),宇宙中的7級(jí)文明有多可怕?

      人類文明現(xiàn)在只有0.73級(jí),宇宙中的7級(jí)文明有多可怕?

      觀察宇宙
      2025-12-20 20:55:31
      金正恩做出重大舉動(dòng),矛頭直指高市早苗

      金正恩做出重大舉動(dòng),矛頭直指高市早苗

      回京歷史夢(mèng)
      2025-12-21 02:40:04
      阿房宮遺址考古取得突破性進(jìn)展

      阿房宮遺址考古取得突破性進(jìn)展

      環(huán)球網(wǎng)資訊
      2025-12-20 15:09:09
      金毛事件大反轉(zhuǎn)!為減刑出賣白三姐,20萬(wàn)轉(zhuǎn)賬記錄撕開(kāi)人性遮羞布

      金毛事件大反轉(zhuǎn)!為減刑出賣白三姐,20萬(wàn)轉(zhuǎn)賬記錄撕開(kāi)人性遮羞布

      魔都姐姐雜談
      2025-12-20 04:48:09
      咖啡再次被關(guān)注!醫(yī)生發(fā)現(xiàn):高血壓患者經(jīng)常喝咖啡,或有5改善

      咖啡再次被關(guān)注!醫(yī)生發(fā)現(xiàn):高血壓患者經(jīng)常喝咖啡,或有5改善

      牛鍋巴小釩
      2025-12-20 16:45:23
      中央明確規(guī)定:從明年起,將對(duì)普通高中進(jìn)行擴(kuò)招。

      中央明確規(guī)定:從明年起,將對(duì)普通高中進(jìn)行擴(kuò)招。

      百態(tài)人間
      2025-12-18 05:00:04
      于東來(lái)回應(yīng)高薪招聘英才:哪怕年薪2000萬(wàn)都無(wú)所謂,給的不是財(cái)富,是尊重

      于東來(lái)回應(yīng)高薪招聘英才:哪怕年薪2000萬(wàn)都無(wú)所謂,給的不是財(cái)富,是尊重

      都市快報(bào)橙柿互動(dòng)
      2025-12-20 11:30:57
      努諾:丟球過(guò)早讓一切變得困難,幾個(gè)丟球我們都可以做得更好

      努諾:丟球過(guò)早讓一切變得困難,幾個(gè)丟球我們都可以做得更好

      懂球帝
      2025-12-21 02:00:07
      王楚欽傳來(lái)壞消息:背傷診斷結(jié)果曝光!林詩(shī)棟17天打3站,不休息

      王楚欽傳來(lái)壞消息:背傷診斷結(jié)果曝光!林詩(shī)棟17天打3站,不休息

      侃球熊弟
      2025-12-20 00:15:03
      池莉:半輩子過(guò)去了,自己盡是不體面和不高貴,遍體鱗傷

      池莉:半輩子過(guò)去了,自己盡是不體面和不高貴,遍體鱗傷

      尚曦讀史
      2025-12-18 09:46:21
      市監(jiān)局通報(bào)“南極磷蝦油”事件:已成立聯(lián)合調(diào)查組進(jìn)駐北京同仁堂(四川)健康藥業(yè)有限公司開(kāi)展調(diào)查,已對(duì)該企業(yè)立案

      市監(jiān)局通報(bào)“南極磷蝦油”事件:已成立聯(lián)合調(diào)查組進(jìn)駐北京同仁堂(四川)健康藥業(yè)有限公司開(kāi)展調(diào)查,已對(duì)該企業(yè)立案

      極目新聞
      2025-12-20 19:28:56
      底層無(wú)貴人,社交無(wú)意義

      底層無(wú)貴人,社交無(wú)意義

      詩(shī)詞中國(guó)
      2025-12-19 20:34:22
      2025-12-21 03:40:49
      Java精選
      Java精選
      一場(chǎng)永遠(yuǎn)也演不完的戲
      1764文章數(shù) 3859關(guān)注度
      往期回顧 全部

      科技要聞

      許四清:具身智能的"ChatGPT時(shí)刻"還未到來(lái)

      頭條要聞

      臺(tái)北致4人身亡嫌犯被指是"大陸籍" 蔣萬(wàn)安回應(yīng)

      頭條要聞

      臺(tái)北致4人身亡嫌犯被指是"大陸籍" 蔣萬(wàn)安回應(yīng)

      體育要聞

      我開(kāi)了20年大巴,現(xiàn)在是一名西甲主帥

      娛樂(lè)要聞

      2026央視跨年晚會(huì)陣容曝光,豪華陣仗

      財(cái)經(jīng)要聞

      求解“地方財(cái)政困難”

      汽車要聞

      嵐圖推進(jìn)L3量產(chǎn)測(cè)試 已完成11萬(wàn)公里實(shí)際道路驗(yàn)證

      態(tài)度原創(chuàng)

      本地
      時(shí)尚
      游戲
      手機(jī)
      公開(kāi)課

      本地新聞

      云游安徽|訪黃山云海古村,讀一城山水風(fēng)骨

      最顯腿細(xì)的騎士靴,誰(shuí)穿誰(shuí)是腿精

      逆天!LCK頒獎(jiǎng)Faker無(wú)緣獎(jiǎng)項(xiàng),LPL解說(shuō)炮轟開(kāi)罵直播間差點(diǎn)被封

      手機(jī)要聞

      vivo X200T再曝,天璣 9400+芯片加持

      公開(kāi)課

      李玫瑾:為什么性格比能力更重要?

      無(wú)障礙瀏覽 進(jìn)入關(guān)懷版 主站蜘蛛池模板: 潞城市| 日韩亚洲欧美中文高清| 狠狠躁天天躁中文字幕| 中文字幕不卡在线播放| 亚洲最大的成人网站| 91福利姬| 在线综合人妻| 亚洲第一成人网站| 国产精品99久久免费| 樱桃视频影院在线播放| 夜夜夜影院| 人妻成人网| 国产粉嫩高中无套进入| 免费VA国产高清大片在线| 日韩丨亚洲丨制服|痴汉| 铁岭县| 日本丰满熟妇videossex一| 国产69精品久久久久久久| 亚洲不卡视频| 宁都县| 操操人妻| 狠狠色AV一区二区| 国产麻豆精品一区二区三区v视界 久久99精品久久久久久 | 成在人线av无码免费高潮水老板| 久久久久久久久久8888| 97精品人妻系列无码人妻老牛| 国产伦精品一区二区三区免费迷| 国产va免费精品观看| 午夜精品偷拍| 当雄县| 免费一区二区无码东京热| 亚洲国产精品久久青草无码| 亚洲熟妇无码成人A片| 利津县| 成人天堂资源www在线| 国产av一区二区三区无码野战| 久久不见久久见免费影院www日本| 日韩人妻精品无码制服| 松下纱荣子被c到高潮下不了床 | ,国产乱人伦无码视频| 另类 专区 欧美 制服|