SpringBoot项目配置国际化

SpringBoot国际化配置流程(超详细) *** 国际化消息源*/@Resource/*** 区域解析器,供消息源@MessageSource根据不同的区域@java.util.Locale读取不同的properties文件*/@Bean// 设置默认区域:简体中文/*** 使用自定义LocalValidatorFactoryBean,* 设置Spring国际化消息源,用户jsr303验证信息实现自定义国际化*/@Bean: Locale对象表示特定的地理、政治或文化区域,用以区分区域。 阅读详情
AI摘要

本文介绍了Spring Boot项目配置国际化的方法。首先说明Spring Boot用MessageSource + LocaleResolver抽离可变文案到外部资源文件实现国际化。接着详细阐述步骤,包括新建国际化文件夹及配置文件、替换响应体等的消息格式、实现自定义区域解析器等,还提及将通过注解注入用户会话信息的更新预告。

目录

1. 引言

2. 步骤

2.1 新建国际化文件夹(i18n)到resources目录下,分别添加对应的国际化文件配置

2.1.1 messages.properties

2.1.2 message_en_US.properties

2.1.3 yml配置文件新增

2.2 将前面博客中的自定义响应体、响应码枚举类、统一异常码中的message替换成引用格式, 而非具体的中文消息

2.2.1 国际化后的自定义响应体

2.2.2 国际化后的响应码枚举类

2.2.3 国际化后的统一异常码

2.3 实现LocaleResolver实现自定义区域解析器

2.4 实现WebMvcConfigure,把自定义区域解析器添加到容器中

2.5 通过消息工具类MessageUtils,根据前端language的参数实现消息语言切换

3. 测试

4. 更新预告--->通过自定义注解根据请求头注入用户会话信息

4.1 Controller

4.2 ServiceImpl

4.3 控制台


1. 引言

前面我们讲到了

SpringBoot项目自定义统一响应体设计_附上完整测试代码-优快云博客

和SpringBoot项目企业级全局异常处理-优快云博客。

今天我们来讲讲国际化。

Spring Boot 项目里谈“国际化”(Internationalization,简称 i18n),并不是再写一堆 if-else 判断语言,而是用 Spring 自带的 MessageSource + LocaleResolver 把“可变文案”全部抽离到外部资源文件,运行时根据请求自动切换语言。下面从“是什么、怎么做、好在哪”三个维度做一个系统的介绍。

先来示例:

根据前一篇文章中代码示例, 当订单id为空的时候会抛出异常:
中文显示为

请求头设置语言为英文时, 抛出异常为对应的英文:

2. 步骤

注:其余代码在引言提到的前两篇博客么么哒!

2.1 新建国际化文件夹(i18n)到resources目录下,分别添加对应的国际化文件配置

注意文件夹名不要错误必须是i18n,这个文件夹可以自动被springboot识别的,里面文件是K=V形式,点击Resource Bundle进行添加三语言消息配置,如果没有这个选项File -> Settings -> Plugins 搜索 Resource Bundle Editor安装如图所示:

分别为默认配置、英文配置、中文配置

2.1.1 messages.properties

message.success=成功
message.fail=失败
message.request.bad=请求错误
message.token.unauthorized=未授权
message.method.not.allow=请求方法不允许
message.enum.constant.systemError=系统错误
message.enum.invalidRequestMethod=无效的请求方法
message.enum.accessDenied=访问未授权
message.enum.userSessionNotFound=用户会话信息未找到
message.enum.common.error.code.order.id.is.empty = 订单id为空

2.1.2 message_en_US.properties

message.success=Success
message.fail=Fail
message.request.bad=The request is bad
message.token.unauthorized=Unauthorized
message.method.not.allow= The request method is not allowed
message.enum.constant.systemError=systemError
message.enum.invalidRequestMethod=invalidRequestMethod
message.enum.accessDenied=accessDenied
message.enum.userSessionNotFound=userSessionNotFound
message.enum.common.error.code.order.id.is.empty = The orderId is empty

2.1.3 yml配置文件新增

spring:
  messages:
    # 国际化资源文件前缀
    basename: i18n.messages

2.2 将前面博客中的自定义响应体、响应码枚举类、统一异常码中的message替换成引用格式, 而非具体的中文消息

注:里面有新增的消息工具类用于解析消息, 见后面章节:

2.2.1 国际化后的自定义响应体

package com.rehse.common;

import com.rehse.util.SpringBeanUtils;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;

import java.util.Locale;

/**
 * @author: Rehse
 * @description: Result
 * @date: 2025/8/14
 */
@Data
@Builder
@AllArgsConstructor
public class Result<T> {
    private String code;
    private String message;
    private T data;

    public Result(){
        this.code = ResultCodeEnum.SUCCESS.getCode();
        this.message = getMessage(ResultCodeEnum.SUCCESS);
    }
    public Result(ResultCodeEnum codeEnum) {
        this.code = codeEnum.getCode();
        this.message = getMessage(codeEnum);
    }

    public Result(ResultCodeEnum codeEnum, T data) {
        this.code = codeEnum.getCode();
        this.message = getMessage(codeEnum);
        this.data = data;
    }

    public static <T> Result<T> success() {
        Result<T> result = new Result<>();
        result.setCode(ResultCodeEnum.SUCCESS.getCode());
        result.setMessage(getMessage(ResultCodeEnum.SUCCESS));
        return result;
    }

    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode(ResultCodeEnum.SUCCESS.getCode());
        result.setMessage(getMessage(ResultCodeEnum.SUCCESS));
        result.setData(data);
        return result;
    }

    public static <T> Result<T> fail(String msg) {
        Result<T> result = new Result<>();
        result.setCode(ResultCodeEnum.FAIL.getCode());
        result.setMessage(msg);
        return result;
    }

    public static <T> Result<T> fail(String code, String message) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(message);
        return result;
    }
    // 重点
    public static String getMessage(ResultCodeEnum code) {
        // 获取bean
        MessageSource messageSource = SpringBeanUtils.getBean(MessageSource.class);
        String messageHolder = code.getMessage();
        Locale locale = LocaleContextHolder.getLocale();
        return messageSource.getMessage(messageHolder, null, locale);
    }

}

2.2.2 国际化后的响应码枚举类

package com.rehse.common;
import java.util.Objects;
import java.util.stream.Stream;
/**
 * @author: Rehse
 * @description: ResultCodeEnum
 * @date: 2025/8/13
 */
public enum ResultCodeEnum {
    SUCCESS("10000", "message.success"),
    FAIL("100001", "message.fail"),
    BAD_REQUEST("400", "message.request.bad"),
    UNAUTHORIZED("401", "message.token.unauthorized"),
    METHOD_NOT_ALLOWED("405", "message.method.not.allow");


    private String code;            // 状态码
    private String message;          // 消息

    ResultCodeEnum(String code, String message) {
        this.code = code;
        this.message = message;
    }

    public String getCode() {
        return this.code;
    }

    public String getMessage() {
        return this.message;
    }

    public static ResultCodeEnum valueof(String code) {
        return Stream.of(values())
                .filter(option -> Objects.equals(option.code, code))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("No matching enum value for [" + code + "]"));
    }

}

2.2.3 国际化后的统一异常码

package com.rehse.exception;

import com.rehse.util.MessageUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;


@Getter
@AllArgsConstructor
public enum CommonErrorCode implements ErrorCode {


    SUCCESS("A10001", "message.success"),

    ORDER_ID_IS_EMPTY("A20001", "message.enum.common.error.code.order.id.is.empty");

    private final String code;
    private final String message;

    // 重点
    public String getMessage() {
        return MessageUtils.getMessage(this.message);
    }
}

2.3 实现LocaleResolver实现自定义区域解析器

继承LocaleResolver实现自定义区域解析器,如下代码:

package com.rehse.config;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.LocaleResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

/**
 * @author: Rehse
 * @description: 自定义区域信息解析器
 * @date: 2025/8/13
 */
@Slf4j
public class MyLocalResolver implements LocaleResolver {

    //进行配置区域解析器
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        //从请求头取出当前的语言
        String language = request.getHeader("lang");
        //获取默认的区域语言
        Locale locale = Locale.getDefault();
        if (StrUtil.isNotEmpty(language)) {
            String[] str = language.split("_");
            locale = new Locale(str[0], str[1]);
        }
        log.info("当前的系统语言是:" + language);
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }

}

2.4 实现WebMvcConfigure,把自定义区域解析器添加到容器中

package com.rehse.config;

import com.rehse.interceptor.BusinessOperatorArgumentResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.util.List;

/**
 * @author: Rehse
 * @description: WebMvcConfig
 * @date: 2025/8/13
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    /**
     * 解析请求中的区域设置:从HTTP请求中提取用户的区域设置信息。
     * 设置响应中的区域设置:在响应中设置适当的区域设置,以便返回用户偏好语言的内容。
     * @return LocaleResolver
     */
    @Bean
    public LocaleResolver localeResolver() {
        return new MyLocalResolver();
    }
}

2.5 通过消息工具类MessageUtils,根据前端language的参数实现消息语言切换

其中的SpringBeanUtils工具类在下方

package com.rehse.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;

import java.util.Locale;

/**
 * @author: Rehse
 * @description: MessageUtils
 * @date: 2025/8/13
 */
@Slf4j
public class MessageUtils {

    /**
     * 获取国际化数据
     *
     * @param holder 占位符key
     * @return 返回国际化数据
     */
    public static String getMessage(String holder) {
        return getMessage(holder, null);
    }

    /**
     * 根据key获取国际化数据
     *
     * @param messageHolder 占位符key
     * @param defaultMsg    默认
     * @return 返回国际化数据
     */
    public static String getMessage(String messageHolder, String defaultMsg) {
        MessageSource messageSource = SpringBeanUtils.getBean(MessageSource.class);
        if (null == messageSource) {
            log.info("MessageSource is empty, please config confirm i18n configuration.");
            return defaultMsg;
        }
        Locale locale = LocaleContextHolder.getLocale();
        return messageSource.getMessage(messageHolder, null, locale);
    }

}

其中根据bean的类型获取消息源对象的工具类代码为:

package com.rehse.util;


import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;


/**
 * @author: Rehse
 * @description: SpringBeanUtils
 * @date: 2025/8/13
 */
@Component
public class SpringBeanUtils implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {

    private static ApplicationContext applicationContext;

    /**
     * @param applicationContext the ApplicationContext object to be used by this object
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringBeanUtils.applicationContext = applicationContext;
    }

    /**
     * 刷新SpringContext上下文
     *
     * @param event the event to respond to
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ApplicationContext context = event.getApplicationContext();
        SpringBeanUtils.applicationContext = context;
    }

    /**
     * 获取Bean
     *
     * @param clazz 类类型
     * @param <T>
     * @return Bean对象
     * @throws BeansException
     */
    public static <T> T getBean(Class<T> clazz) throws BeansException {
        T bean = applicationContext.getBean(clazz);
        return bean;
    }


    /**
     * 获取Bean
     *
     * @param name Bean名称
     * @return Bean对象
     * @throws BeansException
     */
    public static Object getBean(String name) throws BeansException {
        return applicationContext.getBean(name);
    }

}

3. 测试

根据请求头传入的语言为中文还是英文, 返回不同的响应消息。

示例:

设置请求头中的语言为英文, 当传入订单id为空时, 返回异常为相应的英文。

当响应成功时:

4. 更新预告--->通过自定义注解根据请求头注入用户会话信息

感谢宝宝们看完这篇博客, 感觉有帮助的话一键三连么么哒!

25届Java小登已入职, 入职后也要继续提升哇,猪咪将会不定期分享学习笔记!

重铸Java荣光, 我辈义不容辞!

强烈建议这几篇博客一起看, 因为我是一天写完的, 

为了保持优快云活跃度, 我打算一天一发, 下一篇将会于2025年8月20日08:30:00自动更新。

接下来将会更新自动根据请求头注入用户会话信息, 会用上建造者设计模式, 请关注跟进吧么么哒!

在某个用户在平台上面进行操作的时候, 会存在很多用户会话信息:包括用户id, 用户姓名, 用户邮箱等。

后续将会更新通过一个注解@UserSession, 一步注入用户会话信息。

示例:

4.1 Controller

在接口里面添加了注解@UserSession

  @PostMapping("/saveOrder")
    public Result<Boolean> saveOrder(@UserSession UserSessionInfo userSessionInfo, @RequestBody Order order){
        return Result.success(orderService.saveOrder(order));
    }

4.2 ServiceImpl

@Override
    public Boolean saveOrder(Order order) {
        UserSessionInfo userSessionInfo = SessionThreadLocalUtil.getCurrentUserInfo();
        System.out.println("当前的UserSessionInfo为 : " + userSessionInfo);
        Order orderNew = new Order();
        BeanUtils.copyProperties(order, orderNew);
        orderNew.setUserId(String.valueOf(userSessionInfo.getUserId()));
        orderNew.setOrderId(String.valueOf(UUID.randomUUID()).replace("-", ""));
        orderNew.setCreateTime(new Date());
        orderNew.setUpdateTime(new Date());
        orderNew.setStatus(0);
        return save(orderNew);
    }

4.3 控制台

Springboot与国际化(i18n) 一、什么是国际化? 国际化就是在不修改内部代码的情况下,根据不同语言及地区显示相应的语言界面。 i18n的由来→internationalization,数一下,首字母i和末位字母之间有18个字母。类似的命名还有很多,例如k8s。 Springboot已经对i18n国际化做了自动配置,自动配置类。 org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration 如果想自定义国际化,通过@Autow 阅读详情

相关推荐

Spring Boot 架构中的国际化支持实践—— Spring Boot 全球化解决方案

背景Spring Boot 主要通过 Maven 或 Gradle 这样的构建系统以继承方式添加依赖,同时继承了 Spring 框架中的优秀元素,减少了 Spring MVC 架构中的复...

AI天才研究院 1万+

Spring Boot之国际化

i18n 国际化 Spring Boot

qq_33594592的博客 5795

【微服务】SpringBoot 国际化适配方案使用详解

SpringBoot 国际化使用详解

congge 9730

如何使用Spring Boot轻松实现国际化和本地化

轻松实现国际化

做一个有思想的技术人 4108

SpringBoot国际化配置完整源码实战项目

是Java平台标准的属性文件格式,采用键值对(key-value pair)方式存储文本内容,每行表示一个翻译条目。其基本语法如下:该文件必须位于类路径(classpath)下,通常放置于目录中。Spring Boot默认会从该路径加载名为messages的资源基名(basename),并根据区域后缀自动匹配对应语言版本。每个键(key)应具有全局唯一性,且建议使用语义清晰、层级分明的命名方式,例如通过点号分隔模块与功能,如。

weixin_42466857的博客 1042

SpringBoot 国际化配置,SpringBoot Locale 国际化

NULL 博文链接:https://fanshuyao.iteye.com/blog/2414640

SpringBoot 国际化配置项目实战(三)

springboot 项目中实战演练,功能有参数非空校验、默认国际化、正常返回参数国际化、抛异常后信息国际化、全局异常后继续切面拦截国际化、动态参数国际化等后端各个方面的实战。 1、新建springboot微服务,pom中jar的基本引用 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactI

nandao158的博客 735

AXI backpressure反压机制代码

本文将xilinx的axi读写代码进行修改,实现吞吐量达到50%

m0_64636251的博客 1763

java web 国际化配置_基于Springboot实现Java Web项目的国际化

说明本文旨在讲解基于Springboot实现国际化的方法,对于前后端分离的架构并不适用(因为前后端分离一般在前端实现国际化),用于Java后端初学者学习使用。环境Springboot:2.1.5.RELEASEJdk:1.8.0_211pom.xml引入web和freemarker的starter包即可:xsi:schemaLocation="http://maven.apache.org/POM...

weixin_39820910的博客 288

机械工程师如何用Codex实现CAD自动化:从重复劳动到智能设计

在机械设计领域,CAD二次开发长期面临学习门槛高、维护成本大的难题。随着AI编程助手如Codex的出现,通过自然语言生成可执行代码,工程师无需精通编程即可实现图纸批量处理、BOM表自动生成、参数化建模等任务。这种技术将重复性操作自动化,显著提升设计效率,让工程师聚焦于核心创新。应用场景涵盖批量修改图纸属性、跨软件数据流转、自动打印等。本文分享机械工程师利用Codex落地自动化的实战经验与避坑指南。

weixin_32296621的博客 354

NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver. 最全解决方案!详细!

真的折磨了我整整一天,从网上的资料到GPT都翻遍了,终于是解决了!以下方案希望能帮助到你们。

weixin_44124632的博客 1万+

5.SpringBoot简易项目商品模块之valid验证和国际化配置valid和新建ValidationConfig

SpringBoot简易项目商品模块之valid验证和国际化配置valid和新建ValidationConfig 完成:第一遍 1.如何对ProductForm进行valid验证? ProductForm package com.cherry.product.form; import javax.validation.constraints.NotEmpty; public class ProductForm { @NotEmpty(message="{id.valid}") private Str

ADbyCool的博客 1013

解决windows10下无法安装.net framework 3.5(包括.net2.0和3.0)

入域电脑,win10系统中安装 .net framework 3.5(包括.net2.0和3.0)

God_me_1的博客 4万+

IntelliJ+SpringBoot项目实战(27)--实现国际化项目开发

本文介绍在SpringBoot中如何进行国际化的开发,包括在Thymeleaf使用标签获取国际化的内容,以及在javascript中如果根据不同的语种获取对应的语种的文字,在需要支持多语种的项目中,可参考本文介绍的知识进行国际化功能的开发。

baozhengw的专栏 1399

PMD相位偏折术实战:如何用Python处理条纹图,让金属外壳的划痕无处遁形

本文详细介绍了PMD相位偏折术在金属外壳划痕检测中的应用,通过Python实现条纹图处理和局部特征增强技术,显著提升微小缺陷的检出率。文章涵盖从四步相移条纹图采集到形状图局部增强的完整流程,特别适合工业质检场景,帮助实现高精度、高效率的自动化检测。

weixin_29291573的博客 508

飞牛fnNAS同步微信微信聊天记录

微信聊天记录如何备份到NAS?本文介绍了利用NAS虚拟机和同步工具实现微信记录自动备份的方法。通过在NAS上搭建"云电脑"长期运行微信PC端,并配置微力同步将聊天记录文件夹自动同步到NAS存储,解决了传统电脑备份的安全性问题。操作步骤包括:1)在NAS上安装虚拟机系统;2)登录微信PC端并同步手机记录;3)配置同步工具将微信记录文件夹同步到NAS。该方法尤其适合不常使用PC微信的用户,可实现记录永久保存和远程查看,更换手机时也能快速恢复历史记录。

dgnankai的专栏 4288

java配置文件取值的几种方式(一般项目,国际化项目,springboot项目)

1.一般项目 1.1 :demo结构如下: 1.2 :取值 import java.io.InputStream; import java.util.Properties; public class JavaConfigTest { private static final String CONFIG_FILE= "config.properties"; //java jdk提供读取配置...

weixin_43078114的博客 1263

Electron vue3 - 使用SerialPort与串口交互教程,计算机串行端口(COM口、USB转串口等)进行通信连接读取或写入Arduino、单片机、PLC、扫码枪、打印机、老式调制解调器!

实战Electron使用SerialPort与串口交互详细全过程,Electron-vue3与串口交互示例,Electron vue使用serialport实现串口交互通讯,Electron-vue使用serialport连接本地串口,electron-vue 台称串口对接 SerialPort,electron串口调试工具,electron+vue+serialport实现串口通信,串口通信serialport使用和调试,electron-vue使用serialport串口通信及踩过的坑(已解决!)ele

🏆 前端领域优质创作者 4637

2.SpringBoot简易项目商品模块之add.html添加form表单和配置国际化文件和新建一个ProductForm和新建ProductController

SpringBoot简易项目商品模块之add.html添加form表单和配置国际化文件和新建一个ProductForm和新建ProductController 完成:第一遍 1.如何在add.html中添加一个form表单? <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title th:text="#{product.add.title}">Add Product&lt

ADbyCool的博客 640

600份国家自然基金申报书--模板

600份国家自然基金申报书--模板

需要远程指导仿真实验、代码有问题的,请后台私信或者关注公众号 4183

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

08-SpringBoot-页面国际化

1、关于I18N 国际化(Internationalization) 指的是同一个网站可以支持多种不同的语言, 以方便不同国家, 不同语种的用户访问。 关于国际化我们想到的最简单的方案就是为不同的国家创建不同的网站 , 比如苹果公司,他的英文官网是 :http://www.apple.com 而中国官网是 http://www.apple.com/cn 苹果公司这种方案并不适合全部公司, 而我们希望相同的一个网站, 而不同人访问的时候可以根据用户所在的区域显示不同的语言文字, 而网站的布局样式等不发生改变

qq_45632660的博客 190

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SpringBoot国际化

配置文件 spring.properties # 默认的 8080 我们将它改成 9090 server.port=8888 # 未定义上下文路径之前 地址是 http://localhost:8080 定义了后 http://localhost:9090/chapter1 你能在tomcat做的事情,配置文件都可以 #server.servlet.context-path=/chapter1...

小布1994的博客 251

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

springboot获取html的数据库,springboot项目实现数据库读取国际化配置

importcom.mbuyy.servicemobile.mapper.ConfigI18nMapper;importcom.mbuyy.servicemobile.model.ConfigI18n;importcom.mbuyy.servicemobile.util.ValidateUtils;importorg.slf4j.Logger;importorg.slf4j.LoggerFacto...

weixin_29737207的博客 650

SprinBoot之Login国际化配置

1 创建一个新的SpringBoot项目 2 引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter- web</artifactId> ...

蒯厅博客 485

springboot实现web国际化

springboot国际化

qq_45720234的博客 254
上一篇: SpringBoot项目企业级全局异常处理
下一篇: SpringBoot项目通过自定义注解根据请求头注入用户会话信息_企业级方案
bugMaker_Rehse
博客等级 码龄1年 133粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值