SpringBoot拦截器_初级程序猿→中级程序猿必经之路_一蓑烟雨任平生

SpringBoot对WebSocket添加拦截器——自定义注解 对WebSocket添加拦截器,并自定义注解 阅读详情


前言

刚毕业的时候感觉设计模式是优秀程序猿的分水岭,还有拦截器,还有过滤器,还有JVM,还有多线程,多进程,等等吧,在我印象里这些都感觉是大牛才擅长的,结果工作时间越久感觉这些东西每天都在接触,也并没有那么难的,废话不多说,今天总结下拦截器吧

一、拦截器原理

拦截器的原理很简单,是 AOP 的一种实现,专门拦截对动态资源的后台请求,即拦截对控制层的请求。使用场景比较多的是判断用户是否有权限请求后台,更拔高一层的使用场景也有,比如拦截器可以结合 websocket 一起使用,用来拦截 websocket 请求,然后做相应的处理等等。拦截器不会拦截静态资源,Spring Boot 的默认静态目录为 resources/static,该目录下的静态页面、js、css、图片等等,不会被拦截(也要看如何实现,有些情况也会拦截,我在下文会指出)。


二、拦截器的快速使用步骤

1.定义拦截器

定义拦截器只需要实现 HandlerInterceptor 接口,HandlerInterceptor 接口是所有自定义拦截器或者 Spring Boot 提供的拦截器的鼻祖,所以,首先来了解下该接口。该接口中有三个方法preHandle(……)、postHandle(……) 和 afterCompletion(……) 。

  • preHandle(……) 方法:该方法的执行时机是,当某个 url 已经匹配到对应的 Controller中的某个方法,且在这个方法执行之前。所以 preHandle(……) 方法可以决定是否将请求放行,这是通过返回值来决定的,返回 true则放行,返回 false 则不会向后执行。
  • postHandle(……) 方法:
    该方法的执行时机是,当某个 url 已经匹配到对应的 Controller中的某个方法,且在执行完了该方法,但是在 DispatcherServlet 视图渲染之前。所以在这个方法中有个 ModelAndView参数,可以在此做一些修改动作。
  • afterCompletion(……)方法:
    顾名思义,该方法是在整个请求处理完成后(包括视图渲染)执行,这时做一些资源的清理工作,这个方法只有在 preHandle(……)被成功执行后并且返回 true 才会被执行。

了解了该接口,接下来自定义一个拦截器。

/**
 * 自定义拦截器
 * @author 一蓑烟雨任平生
 * @date 2021/02/25
 */
public class MyInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(MyInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        String methodName = method.getName();
        logger.info("====拦截到了方法:{},在该方法执行之前执行====", methodName);
        // 返回true才会继续执行,返回false则取消当前请求
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.info("执行完方法之后进执行(Controller方法调用之后),但是此时还没进行视图渲染");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.info("整个请求都处理完咯,DispatcherServlet也渲染了对应的视图咯,此时我可以做一些清理的工作了");
    }
}
@Configuration
public class MyInterceptorConfig extends WebMvcConfigurationSupport {

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
}

2.配置拦截器

  • 在 Spring Boot 2.0 之前,我们都是直接继承WebMvcConfigurerAdapter 类,然后重写addInterceptors 方法来实现拦截器的配置。但是在 Spring Boot 2.0之后,该方法已经被废弃了(当然,也可以继续用),取而代之的是 WebMvcConfigurationSupport 方法,如下:
@Configuration
public class MyInterceptorConfig extends WebMvcConfigurationSupport {

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
        super.addInterceptors(registry);
    }
}
  • 在该配置中重写 addInterceptors 方法,将我们上面自定义的拦截器添加进去,addPathPatterns
    方法是添加要拦截的请求,这里我们拦截所有的请求。这样就配置好拦截器了,接下来写一个 Controller 测试一下:
@Controller
@RequestMapping("/interceptor")
public class InterceptorController {

    @RequestMapping("/test")
    public String test() {
        return "hello";
    }
}
  • 让其跳转到 hello.html 页面,直接在 hello.html 中输出 hello interceptor
    即可。启动项目,在浏览器中输入 localhost:8080/interceptor/test 看一下控制台的日志:
====拦截到了方法:test,在该方法执行之前执行====  
执行完方法之后进执行(Controller方法调用之后),但是此时还没进行视图渲染  
整个请求都处理完咯,DispatcherServlet也渲染了对应的视图咯,此时我可以做一些清理的工作了

三 、解决问题

1.解决静态资源被拦截问题

上文中已经介绍了拦截器的定义和配置,但是这样是否就没问题了呢?其实不然,如果使用上面这种配置的话,我们会发现一个缺陷,那就是静态资源被拦截了。可以在 resources/static/ 目录下放置一个图片资源或者 html 文件,然后启动项目直接访问,即可看到无法访问的现象。

也就是说,虽然 Spring Boot 2.0 废弃WebMvcConfigurerAdapter,但是 WebMvcConfigurationSupport 又会导致默认的静态资源被拦截,这就需要我们手动将静态资源放开。

如何放开呢?除了在 MyInterceptorConfig 配置类中重写addInterceptors方法外,还需要再重写一个addResourceHandlers,将静态资源放开:

/**
 * 用来指定静态资源不被拦截,否则继承WebMvcConfigurationSupport这种方式会导致静态资源无法直接访问
 * @param registry
 */
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
    super.addResourceHandlers(registry);
}

这样配置好之后,重启项目,静态资源也可以正常访问了。如果你是个善于学习或者研究的人,那肯定不会止步于此,没错,上面这种方式的确能解决静态资源无法访问的问题,但是,还有更方便的方式来配置。

我们不继承 WebMvcConfigurationSupport 类,直接实现 WebMvcConfigurer 接口,然后重写 addInterceptors 方法,将自定义的拦截器添加进去即可,如下:

@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 实现WebMvcConfigurer不会导致静态资源被拦截
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
    }
}

这样就非常方便了,实现 WebMvcConfigure 接口的话,不会拦截 Spring Boot 默认的静态资源。

这两种方式都可以,具体他们之间的细节,感兴趣的读者可以做进一步的研究,由于这两种方式的不同,继承 WebMvcConfigurationSupport 类的方式可以用在前后端分离的项目中,后台不需要访问静态资源(就不需要放开静态资源了);实现 WebMvcConfigure 接口的方式可以用在非前后端分离的项目中,因为需要读取一些图片、css、js文件等等。


2.拦截器使用实例

一般用户登录功能我们可以这么做,要么往 session 中写一个 user,要么针对每个 user 生成一个 token,第二种要更好一点,那么针对第二种方式,如果用户登录成功了,每次请求的时候都会带上该用户的 token,如果未登录,则没有该 token,服务端可以检测这个 token 参数的有无来判断用户有没有登录,从而实现拦截功能。我们改造一下 preHandle 方法,如下:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    HandlerMethod handlerMethod = (HandlerMethod) handler;
    Method method = handlerMethod.getMethod();
    String methodName = method.getName();
    logger.info("====拦截到了方法:{},在该方法执行之前执行====", methodName);

    // 判断用户有没有登陆,一般登陆之后的用户都有一个对应的token
    String token = request.getParameter("token");
    if (null == token || "".equals(token)) {
        logger.info("用户未登录,没有权限执行……请登录");
        return false;
    }

    // 返回true才会继续执行,返回false则取消当前请求
    return true;
}

重启项目,在浏览器中输入 localhost:8080/interceptor/test 后查看控制台日志,发现被拦截,如果在浏览器中输入localhost:8080/interceptor/test?token=123 即可正常往下走。


2.取消拦截操作(自定义注解)

根据上文,如果我要拦截所有 /admin 开头的 url 请求的话,需要在拦截器配置中添加这个前缀,但是在实际项目中,可能会有这种场景出现:某个请求也是 /admin 开头的,但是不能拦截,比如 /admin/login 等等,这样的话又需要去配置。那么,可不可以做成一个类似于开关的东西,哪里不需要拦截,我就在哪里弄个开关上去,做成这种灵活的可插拔的效果呢?

是可以的,我们可以定义一个注解,该注解专门用来取消拦截操作,如果某个 Controller 中的方法我们不需要拦截掉,即可在该方法上加上我们自定义的注解即可,下面先定义一个注解:

/**
 * 该注解用来指定某个方法不用拦截
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UnInterception {
}

然后在 Controller 中的某个方法上添加该注解,在拦截器处理方法中添加该注解取消拦截的逻辑,如下:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    HandlerMethod handlerMethod = (HandlerMethod) handler;
    Method method = handlerMethod.getMethod();
    String methodName = method.getName();
    logger.info("====拦截到了方法:{},在该方法执行之前执行====", methodName);

    // 通过方法,可以获取该方法上的自定义注解,然后通过注解来判断该方法是否要被拦截
    // @UnInterception 是我们自定义的注解
    UnInterception unInterception = method.getAnnotation(UnInterception.class);
    if (null != unInterception) {
        return true;
    }
    // 返回true才会继续执行,返回false则取消当前请求
    return true;
}

Controller 中的方法代码可以参见源码,重启项目在浏览器中输入 http://localhost:8080/interceptor/test2?token=123 测试一下,可以看出,加了该注解的方法不会被拦截。


总结

文末了,如果上面的没看懂也没事,说点简单朴实的大白话

先看项目属于前后台分离还是前后台一体

如果:
前后分离,使用继承(extend)WebMvcConfigurationSupport(拦截静态资源)

如果:
想前后分离还想用继承(extend)WebMvcConfigurationSupport
那么addResourceHandlers

如果:
前后台一体,实现(implements)WebMvcConfigure (非前后端分离,前后台一体)(不拦截静态资源)

在这里插入图片描述

SpringBoot关于接口版本的一个处理方法 作为一个程序猿,对应项目需求的变更似乎已经免疫,加班。加班能解决一切! 有一种需求,接口的升级,即某个接口过时了,不用了,但是却不能删除,需要创建个新的接口,且访问url仅仅只是将api/v1/test改成api/v2/test,SpringBoot在没做处理前,是不允许同一个url访问路径的,在启动时就会报错,当然这是没做处理,处理其实很简单,我们来看一段代码: @ApiOperati... 阅读详情

相关推荐

手把手教你用GEM-2多频电磁仪找地下管道(附真实数据图)

本文详细解析了使用GEM-2多频电磁仪精准定位地下管线的全流程,包括设备调试、频率选择、现场扫描技巧及数据解读。通过真实案例展示了如何应对复杂干扰环境,提升管线检测效率与准确性,特别适合市政工程和地下管线普查。

weixin_42565652的博客 396

springboot创建WebMvcConfigurationSupport后接口没有响应

springboot版本问题。

紫月7575的博客 235

FDTD Solutions-入射波长模式

经常在文献中看到仿真光源使用TM/TE模式,这个确定是十分必要的,决定了仿真结果。 但是也不能局限于选择TM/TE,因为不同领域、不同软件之间的使用习惯和命名可能不同。并且在现代光波导器件中,几乎全部 都是混合模式,或者称之为quasi-TE(准TE模式)和quasi-TM(准TM模式),多数情况下都简称为TE模式和TM模式。要知道 到底是TE模式还是TM模式,需要查看其电场的主分量(即振幅...

HECHUANWANG的博客 1万+

Spring Boot 拦截器

Spring Boot 拦截器是 AOP 的一种实现,专门拦截对控制层的请求,主要应用于判断用户权限,拦截webSocket请求。SpringBoot中的拦截器实现和spring mvc中是一样的,它的大致流程是,先自己定义一个拦截器类,并将这个类实现一个类,或者是继承,都可以实现拦截器的定义。然后将自己定义的拦截器注入到适配器中,也有两种方式,一种是实现接口,一种是继承。

菜鸡的博客 2059

扩视机器视觉—Halcon机器视觉48个实战项目六(检测定位角度)

此项目halcon检测检测定位角度问题,并显示。

qq_21516871的博客 1092

飞塔防火墙之Link Monitor

Link Monitor类似于SLA,飞塔防火墙线路质量探测的一个功能。

weixin_41903258的博客 2404

Springboot实现拦截器功能

preHandle 预先处理,在目标的controller方法执行之前,进行处理 postHandle 在目标的controller方法执行之后,进行处理 afterCompletion 在页面渲染之后进行处理方法

weixin_52875557的博客 1万+

Python3.8下MvCameraControl.dll加载失败?3种方法彻底解决FileNotFoundError

本文针对Python3.8及以上版本在Windows平台调用MvCameraControl.dll时出现的FileNotFoundError问题,深入剖析了其根源在于Python 3.8引入的DLL加载安全机制变更。文章提供了三种核心解决方案:显式指定DLL完整路径、使用os.add_dll_directory()添加可信目录,以及利用ctypes的winmode参数进行精细控制,并给出了工程化封装建议,帮助开发者彻底解决此兼容性问题。

weixin_29093017的博客 189

Springboot集成WebSocket

Slf4j@Component/*** 管理用户信息* @return*/@Override// 从头信息中获取的数据进行分割// 获取到用户信息并set进实体类中System.out.println("socket连接失败 ---> token过期 --->"+info);@Slf4j@Component/*** webSocket连接创建后调用*/@Override// 获取用户信息。

qq_31957463的博客 699

Python 爬虫实战:全面解析雪球网用户投资组合数据采集

本文介绍了如何使用 Python 爬虫技术,抓取雪球网用户的投资组合信息。通过模拟登录、解析页面内容等步骤,获取了用户的持仓数据。未来,可以进一步探索以下方向:

2201_76125261的博客 1303

告别定位不准!Inner-IoU助力YOLOv11边界框回归精度飙升

Inner-IoU 凭借辅助边框的创新设计,成功解决了传统 IoU 损失在小目标、遮挡场景下的收敛难题,为 YOLOv11 注入了更强的定位能力。从原理剖析到代码集成,本教程已为你铺就了一条“精度提升”的实战路径。现在,不妨亲自上手尝试,让你的目标检测模型在各类数据集上都能交出一份“精度优异”的答卷——相信我,当你看到检测框精准贴合目标的那一刻,你会明白这份尝试的价值。

FJN110的博客 188

springboot 拦截器与文件上传

使用IDEA创建Spring Boot项目,会默认创建出classpath:/static/目录,静态资源一般放在这个目录下即可。 如果默认的静态资源过滤策略不能满足开发需求,也可以自定义静态资源过滤策略。 在application.properties中直接定义过滤规则和静态资源位置

程序猿追的博客 1万+

第三方 API 调用 OpenClaw 出现 LLM request timed out 的解决方案

本文主要介绍了第三方 API 调用 OpenClaw 出现 LLM request timed out 的解决方案,希望能对使用OpenClaw的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 8万+

Spring Boot中的拦截器配置

在Spring Boot中,拦截器用于在请求到达控制器之前和请求完成之后进行一些预处理和后处理操作。拦截器是Spring Boot中非常强大的功能,可以帮助我们在请求处理过程中执行各种预处理和后处理操作。通过合理地使用拦截器,我们可以简化控制器代码,提高应用的可维护性和可扩展性。拦截器(Interceptor)是一种动态拦截处理机制,允许在请求到达控制器之前和请求返回视图之后执行特定的逻辑。拦截器与过滤器的不同之处在于,拦截器是基于框架(如Spring MVC)的,而过滤器则是基于Servlet规范的。

微赚开发者技术分享博客 2124

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Springboot 系列(六)Spring Boot web 开发之拦截器和三大组件

1. 拦截器 Springboot 中的 Interceptor 拦截器也就是 mvc 中的拦截器,只是省去了 xml 配置部分。并没有本质的不同,都是通过实现 HandlerInterceptor 中几个方法实现。几个方法的作用一一如下。 preHandle 进入 Habdler 方法之前执行,一般用于身份认证授权等。 postHandle 进入 Handler 方法之后返回 modelAnd...

未读代码 2045

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

《程序猿入职必会(3) · SpringBoot 各层功能完善 》

第一篇博文《程序猿入职必会(1) · 搭建拥有数据交互的 SpringBoot 》,我们已完成了后端服务的搭建,开发并且对外提供了查询教师列表的数据接口,但要按照一开始制定的需求目标,要完整的教师CURD功能,现有接口方法还是远远不够的(まだまだだね)。本篇博文,有几个目标要完成,回顾一下之前两篇文章,一些知识点补充一下针对需求内容,把后端服务的接口方法丰富起来适当考虑一下代码的封装,将一些共性的方法抽取到基类中,方便后续开发功能完善过程中,分享一些实战开发中的后端经验。

山人行 2363

SpringBoot整合流行框架(上) 究其原理 去其糟粕 如何快速上手所有流行框架整合的方法一文足以~

本篇内容:SpringBoot整合流行框架(上)~ 文章专栏:SpringBoot微服务 其原理与项目开发 最近更新:2022年1月26日 SSM框架整合Druid由浅入深到SpringBoot接管Druid配置~ 学习SpringBoot的接管思路与思想 个人简介:一只二本院校在读的大三程序猿,本着注重基础,打卡算法,分享技术作为个人的经验总结性的博文博主,虽然可能有时会犯懒,但是还是会坚持下去的,如果你很喜欢博文的话,建议看下面一行~(疯狂暗示QwQ) 点赞

Alascanfu的博客 632

SpringSecurity如何理解学习常用拦截器——举例进行学习——从0到1教会方法自行学习~

本篇内容:如何理解学习SpringSecurity的常用拦截器——举例进行学习 文章专栏:前后端分离项目(Vue + SpringBoot) 最近更新:2022年2月5日 Nginx 入门到实战案例 配置反向代理、负载均衡、动静分离以及对Nginx高可用的服务器集群 个人简介:一只二本院校在读的大三程序猿,本着注重基础,打卡算法,分享技术作为个人的经验总结性的博文博主,虽然可能有时会犯懒,但是还是会坚持下去的,如果你很喜欢博文的话,建议看下面一行~(疯狂暗示QwQ)

Alascanfu的博客 1648

《学会 SpringBoot 系列 · spring.factories 详解》

spring.factories 文件是 Spring Boot 项目中的一个重要配置文件,用于定义自动配置、环境后处理器和其他 Spring Boot 组件的实现。这个文件通常位于 META-INF 目录下,Spring Boot 在启动时会读取这个文件,以便加载相应的配置和功能。此篇博文分享一下 spring.factories 的相关用法。《程序猿入职必会(1) · 搭建拥有数据交互的 SpringBoot 》《程序猿入职必会(2) · 搭建具备前端展示效果的 Vue》

山人行 2287

《程序猿入职必会(6) · 返回结果统一封装》

本系列博文已连载到第六篇,通过前五篇博文,我们已完成了教师信息的基础增删改查功能,在介绍其他知识专栏之前,先来谈一谈CURD页面的规范问题。前后端分离的开发模式中,后端程序猿有必要与前端程序猿约定一个相对于规范的返回格式,如果仅仅返回数据,有点像裸奔。因此,后端项目需要对返回结果进行统一封装返回,前端也需要封装请求后置拦截器对返回结果处理。按业内约定俗成的规范,返回结果至少包含:code 状态码、data 数据、msg 消息内容、error 错误内容。

山人行 2988

Java 框架的一些文件配置

之前已经记录了Spring、SpringMvc、Mybatis等框架的学习,对于这些框架的 xx 文件配置还是很多的,所以专门写了一篇关于一些常用配置的文,也为后面的SpringBoot 作出铺垫。

程序猿追的博客 1万+

基于Mybatis手撸一个分表插件

大家好,我是摸鱼失败的阿星背景事情是酱紫的,阿星的上级leader负责记录信息的业务,每日预估数据量是15万左右,所以引入sharding-jdbc做分表。上级leader完成业务的开发后,走了一波自测,git push后,就忙其他的事情去了。项目的框架是SpringBoot+Mybaits出问题了阿星负责的业务也开发完了,熟练的git pull,准备自测,单元测试run一下,上个厕所回来收工,就是这么自信。回来后,看下控制台,人都傻了,一片红,内心不禁感叹“如果这是股票基金该多好”。出了问题就要解决,随着

程序猿阿星 3462

SpringAOP配置全局事务(配置类方式)

以下分为一步步来讲解,最后会总结一整段配置类的代码,同时这里讲的不是很详细,我在最后放一个详细讲解的文章链接,看不懂的可以去看一下。 1、创建切面类 @Aspect // 定义切面类,把当前类标识为一个切面供容器读取 @Configuration // 定义配置类,注册到容器中 public class SpringConfigTrans { } 2、创建@Bean修饰的方法,返回事务拦截器(TransactionInterceptor),声明对应方法的事务属性,并且注册到bean中...

m0_51512780的博客 1347

Java-SpringBoot:用户认证(Authentication)和用户授权(Authorization)

Java-SpringBoot-2 学习视频:B站 狂神说Java – https://www.bilibili.com/video/BV1PE411i7CV 学习文档: 微信公众号 狂神说 –https://mp.weixin.qq.com/mp/homepage?__biz=Mzg2NTAzMTExNg==&hid=1&sn=3247dca1433a891523d9e4176c90c499&scene=18&uin=&key=&devicetype=Win

embelfe_segge的博客 8258

SpringBoot笔记

SpringBoot 可以轻松创建独立的、基于Sring的生产级应用程序,而这只需要一些Spring很少的配置。 SpringBoot 是现在最主流的开发框架,它提供一站式的开发体验,大幅度提高我们的开发效率。

白豆五的博客 1869

springboot和mybatisplus 分页查询功能的实现~

大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!!! 本文介绍的是分页功能的实现 实现分页查询功能 request拦截器 request.js (function (win) { axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' // 创建axios实例

m0_51750419的博客 1464
上一篇: Python自学Django_踩坑日记_持续更新_一蓑烟雨任平生
下一篇: Java_Maven配置集成IDEA_一蓑烟雨任平生
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值