解决在Filter中读取Request中的流后, 然后在Controller中@RequestBody的参数无法注入而导致 400 错误

Spring Boot Controller测试:Postman与MockMvc的选型与实践指南 在Web服务开发中,API接口的稳定性和正确性是保障系统质量的关键。Controller层作为HTTP请求的入口,其测试验证涉及从请求参数解析、业务逻辑调用到响应组装的全链路。单元测试与集成测试是两种核心的软件测试方法,前者关注模块内部逻辑的快速验证,后者则确保各组件协同工作的正确性。在Spring Boot生态中,MockMvc框架通过模拟HTTP请求与响应,支持对Controller进行细粒度的单元测试,能快速验证参数绑定、数据校验等逻辑;而Postman作为API客户端工具,则擅长模拟真实网络请求,用 阅读详情

摘要: 大家知道, StringMVC中@RequestBody是读取的流的方式, 如果在之前有读取过流后, 发现就没有了.

我的Filter为了验证请求参数(包括Request Payload的数据)是否有非法符号(sql注入)

package com.ks.tow.common.filter;


import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;


import org.apache.commons.io.IOUtils;
import org.springframework.web.util.ContentCachingRequestWrapper;


import com.alibaba.fastjson.JSONObject;
import com.ks.shop.util.secure.CheckSQLInjectionUtil;
import com.ks.tow.common.enums.HttpStatus;
import com.ks.tow.util.StringUtil;


/**
 * 防sql注入攻击过滤
 * @author LIU
 *
 */
public class CheckSQLInjectionFilter implements Filter {
	
	private List<String> excludes = new ArrayList<>();
	
	public void setExcludes(List<String> excludes) {
		this.excludes = excludes;
	}
	public List<String> getExcludes() {
		return excludes;
	}


	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		String excludes = filterConfig.getInitParameter("excludes");
		if (StringUtil.isNotBlank(excludes)) {
			String[] array = excludes.split(",");
			for (String url : array) {
				this.excludes.add(url);
			}
		}
	}


	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest)request;
		HttpServletResponse resp = (HttpServletResponse)response;
		String requestPath = req.getRequestURI();
		requestPath = requestPath.substring(req.getContextPath().length() + 1);
		while (requestPath.endsWith("/")){ //预防uri末尾有 ‘/’
			requestPath = requestPath.substring(0, requestPath.length()-1);
		}
		for (String str : excludes) {
			if (str.endsWith("*")) {
				if (requestPath.startsWith(str.substring(0, str.length() - 1))){
					chain.doFilter(req, resp);
					return;
				}
			}
			if(str.equals(requestPath)) {
				chain.doFilter(req, resp);
				return;
			}
		}
		Map<String, Object> paramMap = new HashMap<>();
		String type = req.getContentType();
		ServletRequest requestWrapper = null;  
	    if(req instanceof HttpServletRequest) {  
	    	   requestWrapper = new ReaderReuseHttpServletRequestWrapper(req); 
	    }
		Reader reader = requestWrapper.getReader();
		// 读取Request Payload数据
		String Payload = IOUtils.toString(reader);
		if (type != null && type.startsWith("application/json")){
			JSONObject jsonObject = JSONObject.parseObject(Payload);
			if (jsonObject != null) {
				for(Map.Entry<String, Object> entry : jsonObject.entrySet()) {
					paramMap.put(entry.getKey(), entry.getValue());
				}
			}
		} else if(type != null && type.startsWith("text/plain")) {
			String[] kvs = Payload.split("&");
			for (String kv : kvs) {
				String[] lf = kv.split("=");
				paramMap.put(lf[0], lf[1]);
			}
			
		}
		// 获取请求参数
		Enumeration en = req.getParameterNames();
		while(en.hasMoreElements()) {
			String name = (String) en.nextElement();
			String value = req.getParameter(name);
			paramMap.put(name, value);
		}
		for(Map.Entry<String, Object> node : paramMap.entrySet()) {
			boolean valid = true;
			if (node.getValue() instanceof String)
				valid = CheckSQLInjectionUtil.validate((String)node.getValue());
			if (!valid) {
				resp.setContentType("application/json;charset=UTF-8");
				PrintWriter writer = resp.getWriter();
				writer.write("{\"success\":false,\"msg\":\""+HttpStatus.SECURITY.getName()+"\",\"code\":"+HttpStatus.SECURITY.getCode()+"}");
				writer.flush();
				return;
			}
		}
		chain.doFilter(requestWrapper, resp);
	}


	@Override
	public void destroy() {
		
	}
	
	/**
	 * 两个方法都注明方法只能被调用一次,由于RequestBody是流的形式读取,
	 * 那么流读了一次就没有了,所以只能被调用一次。
	 * 既然是因为流只能读一次的原因,那么只要将流的内容保存下来,就可以实现反复读取了
	 * @author LIU
	 *
	 */
	public static class ReaderReuseHttpServletRequestWrapper extends HttpServletRequestWrapper 	{


	    private final byte[] body;  
	      
	    public ReaderReuseHttpServletRequestWrapper(HttpServletRequest request)   
	    		throws IOException {  
	        super(request);
	        body = IOUtils.toString(request.getReader()).getBytes(Charset.forName("UTF-8"));
	    }  
	  
	    @Override  
	    public BufferedReader getReader() throws IOException {  
	        return new BufferedReader(new InputStreamReader(getInputStream()));  
	    }  
	  
	    @Override  
	    public ServletInputStream getInputStream() throws IOException {  
	        final ByteArrayInputStream bais = new ByteArrayInputStream(body);  
	        return new ServletInputStream() {


	            @Override
	            public int read() throws IOException {
	                return bais.read();
	            }
	
	        }; 
	    }  
	}
}

请注意这里的编码, 最好将其转换成UTF-8的编码格式, 不然你获取到的中文则会使乱码的. 我自己也习惯于UTF-8的编码.

这样子就应该差不多了哦~

以下是校验sql注入的关键代码

public final class CheckSQLInjectionUtil {
	private static final String sqlReg = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|"  
            + "(\\b(select|update|and|or|delete|insert|trancate|char|into|substr|"
            + "ascii|declare|exec|count|master|into|drop|execute)\\b)";
	
	private static Pattern pattern = Pattern.compile(sqlReg, Pattern.CASE_INSENSITIVE);
	
	/**
	 * 检查SQL注入
	 * @param str
	 */
	public static boolean validate(String str) {
		if (pattern.matcher(str).find()) {
			return false;
		}
		return true;
	}
	/**
	 * 检查SQL注入
	 * @param strs
	 */
	public static boolean validate(String[] strs) {
		for (String str : strs) {
			if (pattern.matcher(str).find()) {
				return false;
			}
		}
		return true;
	}
	
}


Spring Boot集成SM4国密算法:基于Servlet Filter的统一加解密方案 在Web应用开发中,数据传输安全是核心需求之一,对称加密算法是保障数据机密性的关键技术。SM4作为我国商用密码标准算法,采用分组密码原理,通过多轮非线性变换实现数据加密,其安全性与国际通用的AES算法相当。在技术价值上,SM4能满足金融、政务等对国密算法有合规要求的场景,实现自主可控的数据安全保护。应用场景广泛,尤其适用于HTTP API接口中敏感数据的传输加密。本文聚焦于如何在Spring Boot框架中,通过Servlet Filter这一标准组件,以非侵入方式实现请求与响应的统一SM4加解密,从而将加 阅读详情

相关推荐

ASP.NET MVC与WebAPI混合架构实战:路由、控制器与依赖注入的解决方案

在.NET企业级应用开发中,ASP.NET MVC和WebAPI是构建Web服务的两大核心框架。MVC遵循模型-视图-控制器的设计模式,专注于服务端渲染动态页面;而WebAPI基于RESTful原则,专为构建HTTP数据接口而生。两者的核心差异在于路由机制、控制器基类与请求处理管道。在技术价值层面,混合使用二者能复用代码库并快速交付全功能Web应用,但不当的融合会引发路由冲突、依赖注入混乱等架构问题。典型的应用场景包括历史项目现代化改造、内部管理系统以及需要同时支持网页与API接口的中后台应用。本文聚焦于混

weixin_30924239的博客 402

拦截器与过滤器(二)拦截器集成与使用

业务中,我们经常需要自定义拦截器来记录用户行为日志,普通的参数可以从request的getParameterMap中获取,而@RequestBody的参数需要从request的InputStream中获取,但是InputStream只能读取一次,如果拦截器读取了参数,controler层就读取不到参数了,所以这类参数需要单独获取,可以把request封装一下,copy一份requet,一个用于在拦...

w_t_y_y的博客 8326

云服务器SQL注入七层防御实战:从参数化查询到权限隔离

SQL注入是一种利用应用程序未过滤用户输入、将恶意SQL代码拼接到查询语句中执行的安全漏洞,其本质是输入与执行逻辑的边界失控。防护原理在于切断‘动态拼接→数据库执行’的信任链,核心是参数化查询、最小权限、输入白名单、错误脱敏与全链路审计。技术价值体现在避免数据泄露、保障业务连续性、满足等保与GDPR合规要求。典型应用场景包括Web登录接口、API搜索功能、后台管理系统的条件查询等。本文聚焦云环境(AWS/阿里云/腾讯云)下可落地的七层纵深防御体系,涵盖Nginx前置过滤、Express服务端校验、Postg

weixin_34232744的博客 408

【Bug】使用Filter替换@RequestBody注解参数中的指定字符无效

项目中前后端交互数据类型使用json字符串,由于显示原因需要对指定字符进行转义处理,以前的处理方式是将HttpServletRequest重新封装,重写getParameter()等取值方法,在重写的取值方法获取到参数值后对该值进行处理。使用Filter将request对象转换成我们之定义的HttpServletRequest对象。这样当我们使用request对象取值时就会对指定的字符进行处理。 ...

不务正业的野猴子 1863

Spring MVC @RequestMapping 深度解析:从路径映射到生产避坑

@RequestMapping 是 Spring MVC 请求分发的核心机制,其本质是 DispatcherServlet 对 URL 路径、HTTP 方法、请求头与查询参数的多维匹配引擎。它基于类级与方法级映射的树状组合实现 API 版本管理与模块隔离,通过 headers 和 params 属性支持内容协商与请求分流,并与 @PathVariable、@RequestParam 共同构成参数绑定体系。该机制直接影响接口健壮性、可维护性与灰度发布能力,在金融、IoT、电商等高要求场景中尤为关键。本文聚焦真

Eric.Net的专栏 423

Claude API vs Cursor深度对比:面向真实开发流的上下文韧性评测

在AI编程辅助工具选型中,'代码生成准确率'只是表象,真正决定长期生产力的是模型与IDE工作流的深度协同能力。本文从开发流(而非问答流)视角切入,解析上下文保鲜、错误恢复韧性、内联反馈延迟等工程级指标——这些正是影响TypeScript重构、跨文件依赖推导、Zustand状态迁移等高频场景的核心因素。结合AST解析器适配、三阶段提示工程、Redis上下文继承等实操方案,揭示Claude API如何通过可控上下文注入弥补远程调用短板,而Cursor又为何在中文标识符支持、本地模型热切换等环节暴露架构局限。适合

weixin_34074740的博客 467

SpringBoot之Filter拦截器的使用 — 获取requestBody解决nested exception is java.io.IOException: Stream closed

直接问题处理过程; 异常如下: 异常摘要:I/O error while reading input message; nested exception is java.io.IOException: Stream closed org.springframework.http.converter.HttpMessageNotReadableException: I/O error whil...

liaonanfeng88的优快云博客 3万+

Spring Boot 3 RESTful实战:从URL设计到生产级错误处理

RESTful Web Services 是一种基于 HTTP 协议、强调资源建模与无状态交互的架构风格,其核心在于统一接口、自描述消息与可演化契约。在 Java 生态中,Spring Boot 凭借自动配置、依赖收敛与运行时治理能力,成为构建 RESTful 服务的事实标准。它通过 `@RestController`、`@Valid` 校验、`ResponseEntity` 响应封装及 `@ControllerAdvice` 全局异常处理等机制,将 RFC 约束落地为可调试、可监控、可演化的工程实践。尤其

weixin_30553777的博客 394

XssFilter过滤之后导致@RequestBody无法解析的参数的问题

问题: 我们遇到的问题是,使用XssFilter对请求参数过滤之后,接口无法再接受到请求参数。 原因:在工程中定义了处理请求的MessageConverter。而定义的Converter对编码有要求。 本质:(以下为个人理解) spring在处理消息时,先循环内部的messageConverter,找出可用的并且可读的。然后根据对应的解析类去解析对应的输入流。我们使用fastJsonMessag...

SugarSunset的博客 4039

Dell R730安装Windows Server 2008 R2

一、RAID驱动准备  在安装Windows server2008 R2操作系统时,如果没有发现硬盘,请将下面的阵列卡驱动先解压(在下载的.exe文件,双击点下一步会自动解压),解压后把那文件夹复制到U盘中。阵列卡 PERC9 H330 - H730 - H730P - H830 Controllers for Windows Server 2008 R2二、系统安装方法方法一:光盘安装  ①请您...

MarshLin 2万+

【创作赢红包】Gurobi学术版证书更新与Python环境配置全攻略

本文详细解析了Gurobi学术版证书过期后的完整更新流程与Python环境配置方法。从彻底清理旧版残留、手把手注册获取新许可证,到软件安装、证书激活,最后重点讲解如何将gurobipy接口正确配置到Python的site-packages目录,并提供了常见问题排查方案,帮助用户高效解决证书与配置难题。

efc1234567的博客 613

web篇(一)过滤器、拦截器、监听器

项目中之前也都用过这些东西,现在写出来,一是记录在项目中的使用,二是全面认识一下三大利器。思来想去,我认为这三大利器总的目的是为了解耦,让代码更加简洁可读,所以问题来了,它是怎样实现的呢?这种方式是不是我也可以用到我自己编码的过程中呢?这都要自己一点点去探索,可能这篇不能马上解决这个问题,但在后续的文章会慢慢解读。 目录 一、过滤器和拦截器的区别 二、监听器 三、使用场景 四、总结 ...

一切安好 1707

MAX96724解串器拨码配置实战:从COAX/GMSL2模式到IIC地址设定

本文详细解析了MAX96724解串器的拨码配置方法,涵盖电源管理模式、I2C地址设定及COAX/GMSL2视频传输模式。通过实战案例和故障排查技巧,帮助工程师快速掌握xcDeserializer4.0版本的配置要点,避免常见错误,提升车载摄像头和工业视觉系统的调试效率。

weixin_29243279的博客 577

SpringBoot @RequestBody接收字符串:从消息转换器到编码陷阱的完整指南

在Web开发中,HTTP请求体数据的处理是基础且关键的一环。其核心原理依赖于HTTP协议的消息转换机制,通过Content-Type头与消息转换器的协同工作,实现字节流到Java对象的转换。这一机制的技术价值在于提供了统一、可扩展的数据绑定方案,极大简化了服务端开发。在实际应用场景中,无论是处理RESTful API的JSON数据、接收第三方回调,还是解析物联网设备的文本流,都离不开对消息转换器的深入理解。本文将聚焦于SpringBoot中通过@RequestBody接收字符串这一常见操作,深入剖析其背后的

weixin_30553777的博客 438

3D视觉-结构光测量-线结构光测量

线结构光测量中,由激光器射出的激光光束透过柱面透镜扩束,再经过准直,产生一束片状光。这片光束像刀刃一样横切在待测物体表面,因此线结构光法又被成为光切法。线结构光测量常采用二维面阵CCD作为接受器件,因此只要通过增加垂直于面阵探测器的第三维度方向,就可以实现对三维物体的测量。

qq_20660115的博客 3129

修勾逃生巨人危机v10.9.9修改版:免广告无限内购与GM工具详解

游戏修改技术是通过对原版游戏程序进行代码层面的调整,实现特定功能的增强或限制解除。其核心原理涉及内存修改、资源替换和API拦截等技术手段,能够有效提升用户体验和测试效率。在移动游戏领域,免广告和无限内购是常见的技术实现方向,通过屏蔽广告SDK调用和修改内购验证逻辑,为用户提供更流畅的游戏体验。这类技术特别适合游戏开发者进行功能测试,以及玩家希望完整体验游戏内容而不受商业模式限制的场景。以修勾逃生巨人危机v10.9.9版本为例,该修改版集成了GM工具开启功能,通过特定操作路径即可激活调试面板,实现了广告去除和

weixin_30855099的博客 2599

ASP.NET MVC与Web API进阶配置:路由、模型绑定与依赖注入实战

在Web开发中,框架配置是连接基础概念与工程实践的关键环节。以ASP.NET Core为例,其内置的依赖注入(DI)容器和模型绑定机制,构成了应用架构的核心原理。理解服务生命周期(Singleton、Scoped、Transient)对于管理资源、避免内存泄漏至关重要,这是实现高可用性服务的技术基础。模型绑定则负责将HTTP请求数据自动转换为编程语言对象,其配置直接影响API的数据契约与健壮性。这些配置的价值在于,它们决定了应用在路由解析、请求处理、资源管理等方面的行为与性能,广泛应用于构建RESTful

weixin_30654419的博客 324

西门子PLC编程之⑦编程开始之点位配置及注释

紧接上篇,点位梳理后,进入PLC编程。1、新建工程,配置系统模块2、配置I点并做中文符合,直接上中文,smart支持中文点位编程,用起来很方便。3、配置Q点并做中文符合5、配置AIW模拟量输入点,配置AQW模拟量输出点并做中文符合6、配置手动启动辅助触点,并做中文符合7、 配置自动启动辅助触点,并做中文符合8、 配置传感器浮点型数据变量点位,并做中文符合9、配置系统运行参数设置区点位,做中午符合,做掉电保持.....................

学技术,人生不误——谁也是寂寞宇宙里的流星,只是你的坚持决定了你划过的痕迹。而且,铸造了普遍里的你的唯一。 4889

ASP.NET MVC与Web API核心配置实战:路由、依赖注入与部署避坑指南

在Web应用开发中,框架配置是连接底层原理与上层应用的关键环节,它决定了请求处理、组件协作和系统部署的稳定性。其核心原理在于通过声明式或代码式配置,引导框架在运行时正确加载程序集、解析依赖关系并映射HTTP请求到对应的处理逻辑。深入理解配置机制的技术价值在于,它能将开发从“盲目试错”提升至“精准设计”,显著提升应用的可靠性、可维护性和跨环境部署的一致性。尤其在构建企业级服务或维护遗留系统时,合理的配置策略能有效应对路由冲突、依赖注入和程序集绑定等常见挑战。本文聚焦于ASP.NET MVC与Web API框架

weixin_30824479的博客 388

EtherCAT总线运动控制学习笔记(RXXW_Dor)

说到总线控制,就要说到报文、对象字典、PN通信我们大部分会说报文,EtherCAT通信我们常说对象字典,叫法不一样,但是原理基本一致,下面我们简单认识下上面是对象字典。

RXXW_Dor的博客 5429

特别章节-0.1 SolidWorks导出机械臂的URDF模型各个关节坐标系设置

通过Solidworks导出机械臂的URDF模型文件,建立机械臂的各个关节坐标系的规则以及注意点,详细步骤

六眼飞鱼的博客 1万+

排序过滤“连环炸”:Spring Boot 查询参数硬编码之死与通用设计涅槃指南

文章摘要 本文针对Spring Boot应用中排序和过滤参数处理的常见问题,深入分析了硬编码泛滥、SQL注入风险、性能陷阱等多重挑战。文章提出了一套完整的通用解决方案,包括:1) 设计统一的请求参数模型;2) 建立严格的安全验证机制(属性白名单和操作符限制);3) 实现与Spring Data JPA的无缝整合,包括排序转换为Sort对象和过滤转换为Specification。通过这套方案,开发者可以构建安全、可扩展的查询接口,避免重复代码和安全漏洞,同时保持良好的性能表现。

深山技术宅的博客 232

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

全网最强SpringMVC教程 | 万字长文爆肝SpringMVC(一)

本文介绍了SpringMVC框架的基本概念和入门案例实现。主要内容包括: SpringMVC概述 基于MVC设计模式的轻量级Web框架 主要处理请求接收、业务转发和响应数据转换 相比Servlet更简单灵活 入门案例实现步骤 创建Maven web项目 导入SpringMVC和Servlet依赖 创建SpringMVC配置类 编写Controller处理请求 配置DispatcherServlet替代web.xml 关键点说明 使用@Controller注解标记控制器类 @RequestMapping定义请

qq_45832461的博客 1145

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

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

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

ASP.NET Core中使用Action Filter实现API请求响应自动加解密

在Web API开发中,数据传输安全是核心关注点,尤其涉及金融支付、身份信息等敏感场景时,需对传输层进行二次加密以满足合规要求。其原理是在HTTP请求处理管道中,通过拦截和修改数据流,在业务逻辑执行前后自动完成加解密操作。这项技术的核心价值在于将安全逻辑与业务逻辑解耦,提升代码的可维护性和复用性。实现上,ASP.NET Core的过滤器(Filters)机制为此提供了理想切入点,特别是Action Filter,能在模型绑定后与结果执行前介入,实现全链路透明加解密。本文以**AES加密**和**国密SM4*

weixin_34411563的博客 290

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Spring Boot获取HTTP请求头的四种方式详解与实战指南

HTTP请求头是Web通信中的核心组成部分,承载着客户端信息、认证令牌、会话标识等关键元数据。其工作原理基于HTTP协议规范,在请求-响应模型中作为元信息传递。理解请求头的处理机制对于实现身份验证、内容协商、缓存控制和跨域资源共享等现代Web功能至关重要。在Spring Boot框架中,高效获取请求头不仅能提升代码可维护性,还能优化安全策略和调试流程。实际应用场景包括API签名验证、用户代理识别、追踪链路ID以及多租户系统标识传递等。本文聚焦于@RequestHeader注解、HttpServletRequ

weixin_30265103的博客 350

ASP.NET Core 10 Minimal APIs实战:无需Controller的轻量Web API开发

在Web API开发中,如何简化接口构建一直是开发者关注的话题。随着ASP.NET Core 10的演进,Minimal APIs借助顶级语句、路由委托映射和自动参数绑定等技术,大幅降低了小规模服务的编码复杂度。它让“一个端点对应一段逻辑”的编写方式成为可能,无需Controller层即可完成依赖注入、分组路由和OpenAPI文档生成,同时更利于AOT发布,适合微服务、敏捷原型、BFF等场景。传统Controller在复杂业务系统中仍然重要,但面对轻量型API,掌握Minimal APIs能显著提升工程效率

weixin_34168880的博客 342
上一篇: 该不该用存储过程
下一篇: curl命令
冷down
博客等级 码龄10年 11粉丝 18原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值