《Spring Boot in Action》【3. 自定义配置】

Spring Boot 3.3.4升级后Logback日志回滚失效解决方案 日志回滚是Java应用日志管理中的核心机制,通过TimeBasedRollingPolicy等策略实现日志文件的自动分割与归档。在Spring Boot生态中,Logback作为默认日志框架,其配置方式随版本迭代不断优化。最新Logback 1.5.3版本对滚动策略进行了架构重构,要求显式声明timeBasedFileNamingAndTriggeringPolicy组件,这对升级Spring Boot至3.3.4版本的开发者带来了配置适配挑战。本文针对fileNamePattern和SizeAndTime 阅读详情

3 自定义配置

3.1 覆盖Spring Boot的自动配置

我们将向reading-list项目中加入Spring Security,很简单,加入security starter即可:

compile("org.springframework.boot:spring-boot-starter-security")

然后你再运行项目,访问浏览器,就会有一个HTTP Basic认证的对话框,用户名填“user”,密码需要在启动日志里找,像这样的一行:

Using default security password: 297af950-707a-48d1-a2cb-cc29909080f3

显然,大部分情况下这不是我们想要的样子,我们可能需要一个登录页面,然后利用数据库认证用户,所以Spring Boot关于security的自动配置不满足我们的要求,我们需要自定义security配置。

我们只需要提供一个继承了WebSecurityConfigurerAdapter的配置类SecurityConfig就可以覆盖自动配置了:

package readinglist;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private ReaderRepository readerRepository;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
        .antMatchers("/").access("hasRole('READER')")
        .antMatchers("/**").permitAll()
      .and()
        .formLogin()
        .loginPage("/login")
        .failureUrl("/login?error=true");
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(new UserDetailsService() {
      @Override
      public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return readerRepository.findOne(username);
      }
    });
  }
}

加了这个类之后,Spring Boot会跳过security自动配置而使用这个配置类。当然,还需要加入Reader类和ReaderRepository接口:

package readinglist;
import java.util.Arrays;
import java.util.Collection;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

@Entity
public class Reader implements UserDetails {
  @Id
  private String username;
  private String fullname;
  private String password;
  // getters and setters

  // UserDetails methods
  @Override
  public Collection<? extends GrantedAuthority> getAuthorities() {
    return Arrays.asList(new SimpleGrantedAuthority("READER"));
  }

  @Override
  public boolean isAccountNonExpired() {
    return true;
  }

  @Override
  public boolean isAccountNonLocked() {
    return true;
  }

  @Override
  public boolean isCredentialsNonExpired() {
    return true;
  }

  @Override
  public boolean isEnabled() {
    return true;
  }
}
package readinglist;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ReaderRepository extends JpaRepository<Reader, String> {
}

首先,Spring Boot会优先考虑应用提供的配置类,然后才是自动配置类,其次,多亏了SecurityConfig的@EnableWebSecurity注解,这个注解会import WebSecurityConfiguration,然后自动配置的SpringBootWebSecurityConfiguration这个类因为不满足@ConditionalOnMissingBean(WebSecurityConfiguration.class)而不生效。

3.2 使用properties外化配置

很多情况下我们不会完全不用自动配置,而是需要修改某几个配置属性,Spring Boot提供了超过300个属性,通过属性来修改自动配置的bean参数会是种更方便的选择,可以通过环境变量、Java系统属性、JNDI、命令行参数或属性文件来提供。

有这些地方可以配置属性,优先级从高到低(列表靠前的覆盖靠后的):

  1. 命令行参数
  2. JNDI属性 from java:comp/env
  3. JVM系统属性
  4. 操作系统环境变量
  5. random.*前缀的随机生成的值(设置其他属性时引用的,如${random.long})
  6. 应用外部的application.properties或application.yml文件
  7. 应用内部的application.properties或application.yml文件
  8. @PropertySource指定的属性源
  9. 默认属性

至于application.properties和application.yml,它们可以位于任意4个位置:

  1. 外部,应用运行目录的/config子目录下
  2. 外部,应用运行目录下
  3. 内部,config包下
  4. 内部,classpath根路径下

上面的列表也是优先级从高到低的,当application.properties和application.yml同时存在于同一优先级目录时,yml会覆盖properties文件的属性。

下面介绍一些常用的配置属性。

关闭模板缓存

当你修改Thymeleaf模板的时候,你会发现每次都需要重启才会生效,原因就在于,为了提高性能,默认会缓存模板(只需编译一次),你可以通过设置spring.thymeleaf.cache为false来关闭模板缓存,比如通过命令行参数:

java -jar readinglist-0.0.1-SNAPSHOT.jar --spring.thymeleaf.cache=false

或者通过application.yml:

spring:
  thymeleaf:
    cache: false

不过务必确保在生产环境上不要关闭模板缓存,以免影响性能,当然你也可以通过环境变量:

export spring_thymeleaf_cache=false

注意把.(点)和-(横杠)替换成_(下划线)

配置内置服务器

配置HTTPS,首先是使用JDK的keytool工具创建一个keystore:

keytool -keystore mykeys.jks -genkey -alias tomcat -keyalg RSA

你会被问及一些问题,比如名字、组织等(无关紧要的),但是密码很重要,得记住,比如我用“letmein”作为密码,然后在application.yml中配置属性:

server:
  port: 8443
  ssl:
    key-store: file:///path/to/mykeys.jks
    key-store-password: letmein
    key-password: letmein

这里key-store的位置,可以用file://来指定文件系统的位置(比如file:///Users/coldcutter/mykeys.jks),但是如果keystore文件被打包进了JAR包,得用classpath:来引用它。

配置Log

Spring Boot默认使用Logback,打日志到控制台,日志级别为INFO,如果你不想使用Logback(使用log4j),可以这么配置:

configurations {
  all*.exclude group:'org.springframework.boot', module:'spring-boot-starter-logging'
}

compile("org.springframework.boot:spring-boot-starter-log4j")

想进一步配置log,可以在classpath根路径下(src/main/resources)创建一个logback.xml,例子:

<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>
        %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
      </pattern>
    </encoder>
  </appender>
  <logger name="root" level="INFO"/>
  <root level="INFO">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

尽管如此,我们常见的对于log的配置无非就是修改日志级别和日志打到什么地方,我们可以借助Spring Boot的配置属性(不用创建logback.xml),配置日志级别:

logging:
  level:
    root: WARN
    org:
      springframework:
        security: DEBUG

把root的日志级别设为WARN,Spring Security的日志级别设为DEBUG,你可以把Spring Security的包名写在一行:

logging:
  level:
    root: WARN
    org.springframework.security: DEBUG

你还可以配置log的输出路径和文件(得确保应用有那个路径的写权限):

logging:
  path: /var/logs/
  file: BookWorm.log

配置log配置文件的位置,一般就用默认的logback.xml好了,不过当你需要根据不同的profile使用不同的日志配置时会很有用:

logging:
  config:
    classpath:logging-config.xml

配置数据源

比如MySQL,这么配:

spring:
  datasource:
    url: jdbc:mysql://localhost/readinglist
    username: dbuser
    password: dbpass
    driver-class-name: com.mysql.jdbc.Driver

driver-class-name其实没有必要,Spring Boot会根据url来推断。Spring Boot会使用这些配置来自动配置DataSource bean,DataSource会被池化,如果Tomcat的pooling DataSource在classpath下,就用它,否则会使用其他连接池实现:

  • HikariCP
  • Commons DBCP
  • Commons DBCP 2

还可以通过JNDI:

spring:
  datasource:
    jndi-name: java:/comp/env/jdbc/readingListDS

如果你设置了spring.datasource.jndi-name属性,其他datasource连接属性会被忽略。

配置自己的组件

你可以在某个bean上加上@ConfigurationProperties注解来注入自定义的属性,比如:

@Controller
@RequestMapping("/")
@ConfigurationProperties(prefix = "amazon")
public class ReadingListController {

  private String associateId;

  public void setAssociateId(String associateId) {
    this.associateId = associateId;
  }

  // omitted
}

这样这个associateId(前缀amazon)属性会通过setter方法注入进来,Spring Boot的属性解析器足够智能,配置属性的时候驼峰(amazon.associateId)、连字符(amazon.associate-id)、下划线(amazon.associate_id)都可以。

当然你最好把相关属性聚合到一个类中,比如:

package readinglist;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("amazon")
public class AmazonProperties {

  private String associateId;

  public void setAssociateId(String associateId) {
    this.associateId = associateId;
  }

  public String getAssociateId() {
    return associateId;
  }
}

配置profiles

不同的环境需要不同的属性,Spring 3.1引入了基于profile的配置,profiles其实就是一种条件配置,根据运行时哪些profiles被激活来决定使用或忽略哪些beans和配置类,比如可以加注解@Profile(“production”)表示只在production profile激活的时候才应用配置。你可以使用spring.profiles.active来配置激活哪些profiles。

Spring Boot提供了基于profile的属性配置,更加方便。

如果你使用properties文件,你可以创建特定profile的配置文件,文件格式为:“application-{profile}.properties”,比如dev环境的属性可以放在application-dev.properties文件里,prod环境的属性放在application-prod.properties文件里,同时,不与特定profile有关的(default)属性还是放在application.properties文件里。

如果你是用YAML配置文件,你一样可以按照上面的文件命名方式来配置,不过你还有一中选择,就是把所有profile的属性都配置在一个application.yml文件里,比如:

logging:
  level:
    root: INFO
---
spring:
  profiles: development
logging:
  level:
    root: DEBUG
---
spring:
  profiles: production
logging:
  path: /tmp/
  file: BookWorm.log
  level:
    root: WARN

不同的配置section用“—”分隔。

3.3 自定义错误页面

Spring Boot默认提供一个“whitelabel”错误页,默认的错误处理器会寻找一个名为“error”的视图,如果没找到,就使用默认错误页,这个视图根本上是由视图解析器决定的:

  • bean id是“error”且实现了Spring View接口的bean(Spring的BeanNameViewResolver)
  • 如果是Thymeleaf,则为error.html
  • 如果是FreeMarker,则为error.ftl
  • 如果是Velocity,则为error.vm
  • 如果是JSP,则为error.jsp

比如Thymeleaf,我们在src/main/resources/templates下创建一个error.html:

<html>
  <head>
    <title>Oops!</title>
    <link rel="stylesheet" th:href="@{/style.css}"></link>
  </head>
  <body>
    <div class="errorPage">
      <span class="oops">Oops!</span><br/>
      <img th:src="@{/MissingPage.png}"></img>
      <p>There seems to be a problem with the page you requested
         (<span th:text="${path}"></span>).</p>
      <p th:text="${'Details: ' + message}"></p>
    </div>
  </body>
</html>

我们可以在error模板中直接使用如下信息:

  • timestamp,错误发生的时间
  • path,错误发生的URL路径
  • status,HTTP状态码
  • error,错误原因
  • exception,异常类名
  • message,异常消息
  • trace,异常堆栈追踪
  • errors,BindingResult异常的errors
Spring Boot In Action Spring Boot In Action 高清版本。非扫描版本。 立即下载

相关推荐

SpringBoot in Action高清版

Spring Boot in Action高清版本,可复制里面文字,基于的版本是1.3

SpringBoot in Action——初识SpringBoot

现在,我们里利用了整本书的篇幅来介绍Spring。尽管Spring带来的主要益处就是简化Java开发,但本章将会介绍Spring Boot如何让这项任务变得更简单。 Spring Boot在Spring之上,构建了全新的开发模式,移除了开发Spring应用中很多单调乏味的东西。 我们首先整体了解一下Spring Boot,看它是怎么简化Spring的。 Spring Boot简介 在Spring家...

No_Game_No_Life_的博客 1770

SPRING in action(第三版中文版).pdf

对于想了解学习SPRING 的童鞋是个不错的选择。

《Spring Boot in Action》【2. 开发第一个应用】

2 开发第一个应用2.1 项目骨架从本章开始,我们要开发一个简单的reading-list应用,用来维护一个reading-list,包括录入书的信息,查看阅读列表,删除书等操作。技术上,Spring MVC处理Web请求,Thymeleaf作为模板引擎编写页面,Spring Data JPA操作数据库,使用内置H2数据库,用Gradle管理项目。使用Spring Initializer生成生成的项

极客神殿 907

记一次Redis出问题及解决方案

Q1: redis服务关闭前确认数据还是在的,重启后发现一条数据都没了,key* 查也是空的 A1: 经仔细检查发现redis.conf配置文件配置的数据存储目录配置的是dir ./ 也就是相对目录,也就是说在哪个目录执行redis-server redis.config启动命令 redis数据就会存到哪个目录,同样就会加载哪个目录下的数据文件(dump.rdb),前后两次启动命令的位置不一样导致第二次启动没有加载到(dump.rdb)文件,从而导致查不出数据 Q2:springboot 集成r

u010013928的博客 3058

STM32与HT7038的高精度电能计量系统设计与实现

本文详细介绍了基于STM32微控制器与HT7038三相电能计量芯片的高精度电能计量系统设计与实现。文章从项目选型出发,深入剖析了硬件电路设计、SPI驱动开发、芯片校准及系统集成等关键环节,为智能电表、能源监控等应用提供了高性价比且稳定的国产化解决方案。

pytorch8learner的博客 389

《Spring Boot in Action》【1. 起步】

1 起步 Spring 1.0,改变了企业级Java应用开发。依赖注入和声明式事务。 Spring 2.0,自定义XML命名空间。 Spring 2.5,面向注解的依赖注入模型,@Component和@Autowired,以及Spring MVC编程模型。无需显式声明组件,无需继承一些基础控制器类。 Spring 3.0,全新的基于Java的配置方式,从Spring 3.1开始的@Enable打头的

极客神殿 2240

Python爬虫获取Shopee店铺的所有商品?

通过上述代码示例,我们可以轻松实现获取Shopee店铺所有商品信息的功能。Python爬虫不仅具有强大的功能和稳定性,还可以通过丰富的库支持实现高效的数据抓取和解析。希望这篇文章能为你提供一些启发和帮助。如果你对爬虫开发有更多兴趣,可以尝试探索更复杂的功能,如多线程爬取、数据可视化等。如果你在实践中遇到任何问题,欢迎随时交流和讨论。让我们一起用技术的力量,解锁更多可能!

2401_87195067的博客 1542

Spring Boot 实战攻略

Spring Boot 实战攻略 去发现同类优质开源项目:https://gitcode.com/ 《Spring Boot in Action》是由Manning Publications于2015年出版的开发者导向指南,旨在帮助开发者使用Spring Boot编写应用程序。通过本书,您将学习如何跳过繁琐的配置步骤,从而专注于应用程序的行为。 关于资源 本书是一本面向开发者的实践指南,涵盖以下内...

gitblog_06737的博客 260

C语言实现AES加解密

C语言实现AES加解密 #include<stdio.h> #include<string.h> #include<time.h> #include<windows.h> #define Nb 4 //数据块行数 #define Nk 4 //密码块行数 #define Nr 10 //轮加密次数 unsigned char RoundKey[4*Nb*(Nr+1)]; //轮密钥 unsigned char Key[17];

qq_44310495的博客 8889

Flutter 直接调用so动态库,或调用C/C++源文件内函数

我把 .so 文件尝试放过好几个目录/lib/,最终都会报这个错误,现在才知道库文件需要放在你根本想象不到的地方!!!尝试了一些方法还是不行后我放弃了 ffi,想着用 Flutter 的 MethodChannel 桥接 android/ios 原生,再让原生去调 native 层。一顿操作把Android端的搞定了,当然中间涉及到 Kotlin和C++ 层的数据类型映射的痛苦,而且业务函数也不像一个 helloworld 那么简单,别提有多痛苦了。

开发以大橘为重 8349

【亲测免费】 Spring Boot in Action 英文版电子书下载

Spring Boot in Action 英文版电子书获取 【下载地址】SpringBootinAction英文版电子书下载 《Spring Boot in Action》是一本深入浅出地介绍Spring Boot开发技术的英文版电子书,适合希望快速掌握Spring Boot核心概念和最佳实践的开发者。书中详细阐述了开...

gitblog_06772的博客 663

目标检测YOLO实战应用案例100讲-基于YOLOv7的番茄采摘机械手场景感知及试验(下)

根据软件系统的设计需求,制定系统的可行性方案分析,编写系统的相关程序和 调试运行环境,对系统进行测试,以实现对番茄数据的采集及监测。登陆界面登陆后,进入选择界面,菜单包括了对番茄种植棚室的固定相机数据的监测、 对番茄采摘机械手的双目相机采集的番茄的静态、动态数据的获取、对番茄静态、动态数 据处理的功能菜单等选项。与利用人工去进行对于番茄果实的识别和数目的统计相比,番茄视觉系统自动记录番 茄数量以及红色已经成熟的番茄、青色未成熟番茄的数量,减轻人工记录的工作量,减少 人工记录的误差,从经济方面是可行的。

qq_36130719的博客 811

Racket 仓库内嵌 lz4(1) 命令手册深度解读:压缩、解压、多线程与全部选项实战指南

本篇技术指南以 Racket 仓库中 ChezScheme 子系统内嵌的 lz4 项目 [programs/lz4.1.md](https://link.gitcode.com/i/79a2b7e8e9c3c3d51f1127bd6d02712b) 命令手册为核心骨架,结合同目录下的 CLI 源码、库实现与测试脚本,系统讲解 `lz4` / `unlz4` / `lz4cat` 三个命令的完整用法

gitblog_00188的博客 965

在 SAP BTP 上为应用开启多租户能力:基于 SaaS Provisioning 和 XSUAA 的完整实践指南

本文介绍了在SAP BTP上配置多租户应用的实战指南。主要内容包括: 多租户架构概述:解释provider子账户、consumer子账户和tenant的概念,以及数据隔离机制。 安全配置:在xs-security.json中设置tenant-mode为shared,并为SaaS Provisioning服务添加回调scope授权。 路由配置:通过manifest.yml设置TENANT_HOST_PATTERN来定义多租户访问模式,确保不同租户通过不同子域名访问同一应用。 服务绑定:将XSUAA和SaaS

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 144

搞懂 SAPUI5 Fiori 应用的 OData 授权维护:从 IWSG、IWSV 到 S_SERVICE 的完整实践

本文探讨了SAP Fiori项目中常见的授权问题及其解决方案。文章指出,开发人员常误将OData服务访问问题归咎于前端代码或配置,而实际上多因授权默认值未正确带入角色所致。详细分析了IWSG(前端服务组元数据)和IWSV(后端业务服务)两个关键对象的作用机制,强调应通过PFCG角色的Authorization Default入口维护服务对象,而非直接修改S_SERVICE授权对象。文章还提供了前后端授权配置的具体操作步骤,并特别提醒需同时配置前端和后端授权,才能确保应用完整可用性。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 203

Spring-boot IN Action(1)

之前在写Spring入门的学习笔记,但是深深感受到单单是“硬学”,即便有穿插一些生动的小例子,还是远远不能用好Spring,更不用谈掌握其核心,深入理解它的思想了。不得不承认,项目是进步的原动力,很复杂的思想、理念,经历几个项目,相信大家都能用的很熟,也会有一定的理解了,辅之以一些参考文档,大神的思想解析,便能够做到游刃有余地利用Spring,而不是被Spring的各种配置,各种思想、各种模式搞得

积跬步,至千里 1434

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

20210401#《Spring in action 5》

目录

qq_17079255的博客 2116

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Spring Boot in Action

先导知识: 1. Spring IoC容器      IoC:控制反转      DI:依赖注入 Spring框架负责控制对象的生命周期和对象间的关系。 IoC使对象只需要关心业务逻辑本身,这些互相依赖的对象的创建和协调等工作交给Spring容器来做。对象如何得到它的协作对象的责任就被反转给Spring了。告诉Spring容器这里需要某个bean,它就会丢个实例过来。 容器中的每个be...

小语733 754

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

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

Spring Boot logback日志

slf4j和log4j、log4j2、logback 之间的关系 log4j(作者Ceki Gülcü)出来时就等到了广泛的应用(注意这里是直接使用),是Java日志事实上的标准,并成为了Apache的项目 Apache要求把log4j并入到JDK,SUN拒绝,并在jdk1.4版本后增加了JUL(java.util.logging) 毕竟是JDK自带的,JUL也有很多人用。同时还有其他日志组件,如SimpleLog等。这时如果有人想换成其他日志组件,如log4j换成JUL,因为api完全不同,就需要改动代

这个需求,做不了 2338

Spring In Action 4

在线学习连接:spring in action 4 关键词解释 名词 解释 EJB Enterprise JavaBean,企业级JavaBean POJO Plain Old Java Object,简单老式Java对象 J2EE Java 2 Enterprise Edition,Java2企业版 DI Dependency Injection,依赖注入,获取对象的过程被反转,获得依赖对象的过程由自身管理变成由IOC容器主动注入 IOC Inversion of Cont

Ranger的博客 1万+

Spring Integration in Action 开源项目教程

Spring Integration in Action 开源项目教程 欢迎来到 Spring Integration in Action 的开源项目指南。本教程旨在为您提供一个快速上手的指导,帮助您理解项目结构、启动机制以及配置细节。请注意,指定的GitHub链接实际上指向了一个可能不直接关联到实际项目代码的路径,但基于常见实践,我们将构建一个理论上的框架来说明这些核心部分。 1. 项目目录结构...

gitblog_00320的博客 859

《Spring in Action》第1章-开始使用Spring

开始使用Spring 1、构建一个Spring应用 使用Spring Initializr构建应用: http://start.spring.io 为Eclipse安装插件,并使用Eclipse创建 在IntelliJ IDEA中创建 2、构建后的应用结构 在构建项目时我们选择以下的依赖: 生成的项目结构如下: mvnw和mvnw.cmd是maven的打包脚本,及时我们没有安装mav...

风萧水寒的博客 502

Spring Microservices in Action

关于这本书 Spring Microservices in Action是为Java / Spring开发人员编写的,他们需要动手建议以及有关如何构建和操作基于微服务的应用程序的示例。当我写这本书时,我希望它基于核心微服务模式,并与展示了实际模式的Spring Boot和Spring Cloud示例保持一致。这样,您将在几乎每一章中找到讨论的特定微服务设计模式,以及使用Spring B...

大强博客 1224

SPRING IN ACTION: 春天在行动-PART 1

提供有关春天新事物的指南!PART 1 FOUNFATIONAL SPRING

Username1898625 572
上一篇: 《Spring Boot in Action》【2. 开发第一个应用】
下一篇: 《Spring Boot in Action》【4. 测试】
.NET跨平台
博客等级 码龄15年 6066粉丝 738原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值