JavaWeb杂记

JavaWeb

1、基本概念

1.1、前言

web开发

web:网页的意思:www.baidu.com

静态web

比如:html,css

提供给所有人看的,数据始终不会发生变化!

动态web

比如: 淘宝、B站,几乎所有的网站

提供给所有人看的,数据始终会发生变化(如B站的推荐),每个人在不同的时间,不同的地点看到的信息各不相同!

动态web的技术栈一般有Servlet/JSP,ASP,PHP

在Java中,动态web资源开发的技术统称为JavaWeb。

1.2、web应用程序

web应用程序:可以提供浏览器访问的程序;
a.html、b.html…多个web资源,这些web资源可以被外界访问,对外界提供服务。
我们能访问的任何一个页面或者资源(如:种子),都存在以这个世界上的某一个角落的计算机上。
URL:统一资源定位符
这个统一的web资源会被放在同一个文件夹下,web应用程序–(依赖)–>Tomcat:服务器
一个web应用由多部分组成(静态web,动态web)
html,css,js
jsp,servlet
java程序
jar包
配置文件(.properties)

web应用程序编写完成之后,若想提供给外界访问:需要一个服务器来统一管理;

1.3、静态web

.htm,.html 这些都是网页的后缀,如果服务器上一直存在这些东西,我们就可以直接进行读取。
静态web存在的缺点:
Web页面无法动态更新,所有用户看到的都是同一个页面
* 轮播图,点击特效:伪动态
* JavaScript[实际开发中用得最多]
* VBScript
无法和数据库交互(数据无法持久化,数据无法交互)

1.4、动态web

页面会动态展示:“Web页面展示的额效果因人而异”。
缺点:
假如服务器的动态web资源出现了错误,我们需要需要重写编写我们的“后台程序”,重新发布;
要停机维护。
Web页面可以动态更新,所有用户看到的都不是同一个页面
可以和数据库交互(数据持久化:注册,商品信息,用户信息(等可以往里存)…)

2、web服务器

2.1、技术讲解

ASP
介绍

ASP 是一项微软公司的技术,国内最早流行的动态web技术就是ASP!它在HTML中嵌入了VB的脚本,ASP + COM。

ASP即Active Server Pages,是Microsoft公司开发的服务器端脚本环境,可用来创建动态交互式网页并建立强大的web应用程序。

优点

简单、好用、开发效率高、速度快。

缺点

在ASP开发中,基本一个页面都有几千行的业务代码,页面及其混乱;维护成本高!

PHP
介绍

PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。PHP 是免费的,并且使用非常广泛。

优点

PHP开发速度很快,功能很强大,跨平台,代码很简单(70%的网站,WP去做的)。

WordPress是使用PHP语言开发的博客平台,用户可以在支持PHP和MySQL数据库的服务器上架设属于自己的网站。

缺点

无法承载大访问量的情况(局限性)

JSP/Servlet
介绍

JSP全称Java Server Pages,是一种动态网页开发技术。

Servlet 是一种服务器端的Java应用程序,具有独立于平台和协议的特性,可以生成动态的Web页面。

实际上jsp的本质还是servlet

2.2、web服务器

服务器是一种被动的操作,用来处理一些用户的请求和给用户一些相应信息;

IIS

IIS是微软公司的Web服务器。主要支持ASP语言环境。

Tomcat

Tomcat是Apache软件基金会的jakarta项目中的一个核心项目,最新的Servlet和JSP规范总能在Tomcat中得到体现,是目前比较流行的Web应用服务器。

Tomcat服务器是一个免费的开放源代码的Web应用程序,属于轻量级应用服务器。

可以配置启动的端口号
  • tomcat的默认端口号为:8080
  • mysql:3306
  • http:80
  • https:443
可以配置主机的名称
  • 默认的主机名为:localhost --> 127.0.0.1
  • 默认的网站应用存放的位置为:webapps文件夹
高难度面试题:
请您谈一谈网站是如何进行访问的?
  1. 输入一个域名,然后回车
  2. 检查本机的C:\Windows\System32\drivers\etc\hosts配置文件夹有没有这个域名映射
  • 有:直接返回对应的ip地址,有就直接访问
  • 没有:去DNS服务器找,找到的话就返回,找不到就返回找不到

http://localhost:8080/docs/ tomcat文档页面
http://localhost:8080/examples/ tomcat各种例子(点击Source查看源码),建议参考

3、发布一个web网站

不会就先模仿

将自己写的网站,放到服务器(Tomcat)中指定的web应用的文件夹(webapps)下,就可以访问

网站应该有的结构:

--webapps:Tomcat服务器的web目录
  -study(自己写的一个网站的目录名)
     -WEB-INF:
        -classes:放java程序
	-lib:web应用所依赖的jar包
     	-web.xml:网站的配置文件
     -index.html:默认的首页
     -static:
	-css
	  -style.css
	-js
	-img
     -...

4、Http

4.1、什么是Http

Http:超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。

  • 文本:html,字符串,…
  • 超文本:图片,音乐,视频,定位,地图,…

HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。

4.2、两个时代

http1.0

http/1.0:客户端可以与web服务器连接后,只能获得一个web资源,否则断开连接。

http2.0

http/1.1:客户端可以与web服务器连接后,可以获得多个web资源。

4.3、Http请求

以百度为例:

Request URL: https://www.baidu.com/	# 请求地址
Request Method: GET	# 请求方法(get/post)
Status Code: 200 OK	# 状态码
Remote(远程) Address: 183.232.231.174:443
Referrer Policy: unsafe-url	Referrer的策略

unsafe-url策略:任意情况下,都发送当前页的全部地址到 Referrer,最宽松和不安全的策略。

1、请求行

请求行中的方式:GET
请求方式:Get,Post,HEAD,DELETE,PUT,TRACT,…
get:请求能够携带的参数比较少,大小有限制;会在浏览器的URL地址栏显示数据内容,不安全,但高效
post:请求能够携带的参数没有限制,大小没有有限制;不会在浏览器的URL地址栏显示数据内容,安全,但不高效

2、请求头/消息头
  • Accept:告诉浏览器,它所支持的数据类型
  • Accept-Encoding:支持哪种编码格式
  • Accept-Language:告诉浏览器,它的语言环境
  • Cache-Control:缓存控制
  • Connection:告诉浏览器,是断开还是保持连接
  • Host: 主机​

4.4、Http响应

服务器–响应给(Response)–>客户端

以百度为例:

Response Headers
Bdpagetype: 1
Bdqid: 0xd6af2b47000eb155
Cache-Control: private	# 缓存控制
Connection: keep-alive  # 连接:keep-alive保持连接
Content-Encoding: gzip	# 编码
Content-Type: text/html;charset=utf-8	# 类型
Date: Wed, 01 Sep 2021 14:30:11 GMT
Expires: Wed, 01 Sep 2021 14:30:11 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=19; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=34442_34496_31253_33848_34092_34106_26350_34425; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 1630506611054653569015469630828984578389
Transfer-Encoding: chunked
X-Frame-Options: sameorigin
X-Ua-Compatible: IE=Edge,chrome=1
1、响应体
  • Accept:告诉浏览器,它所支持的数据类型
  • Accept-Encoding:支持哪种编码格式
  • Accept-Language:告诉浏览器,它的语言环境
  • Cache-Control:缓存控制
  • Connection:告诉浏览器,是断开还是保持连接
  • Host: 主机
  • Reflush:告诉客户端,多久刷新一次
  • Location:让网页重新定位
2、响应状态码(重点)
  • 200:请求响应成功 200

  • 3xx:请求重定向位置去

  • 4xx:找不到资源

    • 404:资源不存在
  • 5xx:服务器代码错误 500 502(网关错误)

常见面试题

当您的浏览器中地址栏输入地址并回车的一瞬间到页面能够展示回来,经历了什么?

5、Maven

Maven(Java包管理工具)。

为什么要学习Maven这个技术?

  1. 在JavaWeb开发中,需要使用大量的jar包,这些jar包需要我们手动导入;
  2. 如何能够让一个东西自动帮我导入和配置这些jar包。
  3. 由此,Maven诞生了!

Maven是一个采用纯Java编写的开源项目管理工具。Maven采用了一种被称之为**project object model (POM)**概念来管理项目,所有的项目配置信息都被定义在一个叫做POM.xml的文件中,通过该文件,Maven可以管理项目的整个声明周期,包括编译,构建,测试,发布,报告等等。目前Apache下绝大多数项目都已经采用Maven进行管理。而Maven本身还支持多种插件,可以方便更灵活的控制项目。一句话:Maven是一个项目管理和构建工具,主要做编译、测试、报告、打包、部署等操作完成项目的构建。Maven不仅是构建工具,还是一个依赖管理工具和项目管理工具,它提供了中央仓库,能帮我自动下载构件。

5.1、Maven项目架构管理工具

我们目前用它来就是方便导入jar包的。Maven核心思想:约定大于配置。

有约束,不要去违反,Maven会要求你如何去编写我们的java代码,必须按照这个规范!

5.2、下载安装Maven

官网:https://maven.apache.org/

下载:https://maven.apache.org/download.cgi

下载完成后解压即可

5.3、配置环境变量

在我们的系统环境变量中,按如下配置进行配置:

  • M2_HOME Maven:目录下的bin目录
  • MAVEN_HOME :Maven的目录
  • 在系统的Path中配置 %MAVEN_HOME%\bin

测试Maven是否安装成功,保证必须配置完毕:cmd下键入mvn -version命令。

5.4、配置镜像

配置镜像(镜像(Mirroring)是一种文件存储形式,是冗余的一种类型,一个磁盘上的数据在另一个磁盘上存在一个完全相同的副本即为镜像。),使用默认仓库下载jar包会比较慢,所以配置一个阿里云镜像

作用:加速我们的下载,国内建议使用阿里云镜像。

5.5、本地仓库

建立一个仓库:localRepository

<localRepository>E:\apache-maven-3.8.2\maven-repo</localRepository>

5.6、在IDEA中使用Maven

  1. 启动IDEA
  2. 创建一个MavenWeb项目(使用模板)
  3. 等待初始化完毕
  4. 查看maven仓库中多了什么东西
  5. IDEA中的maven设置
  6. 到这里为止,Maven在IDEA中的配置和使用就OK了!

5.7、创建一个普通的Maven项目(干净的,不勾选模板)

5.8、标记文件夹功能

5.9、在IDEA中配置Tomcat

1.Edit Configurations
2.点击+号,选择Tomcat(local)
3.解决警告问题

为什么有这个问题:我们访问一个网站,需要指定一个文件夹的名字。

4.启动tomcat

5.10、pom文件

pom.xml是Maven的核心配置文件

5.11、IDEA操作

maven由于是约定大于配置,所以可能遇到我们写的配置文件,无法被导出或者生效的问题,解决方法:

在pom.xml文件中,通过<build>中配置<resources>

<!--在build中配置resources , 来防止我们资源导出失败的问题-->
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>

5.12、IDEA中Maven项目的目录树

5.13、解决遇到的问题

1.Maven与JDK版本不兼容,导致无法导入东西
2.Tomcat闪退
3.IDEA中每次都要重复配置Maven 在IDEA的全局默认配置中去配置
4.Maven项目中Tomcat无法配置
5.Maven默认web项目中的web.xml版本问题
6.替换成IDEA中tomcat版本((IDEA生成的中的web.xml))和webapps(中的web.xml)一致
7.Maven仓库的使用

Maven公共仓库地址:https://mvnrepository.com/

6、Servlet

6.1、Servlet简介

Servlet就是SUN公司开发动态web的一门技术。SUN公司在这些API中提供了一个接口叫做:Servlet

如果你想开发一个Servlet程序,只需要完成两个小步骤:

1、编写一个类,继承Servlet接口

2、把开发好的Java类部署到web服务器中

把实现了Servlet接口的Java程序叫做:Servlet

6.2、HelloServlet

Servlet接口在SUN公司有两个默认的实现类:HttpServlet和GenericServlet

  1. 构建一个Maven项目,删除里面的src目录,以后我们的学习就在这个项目里面建立Moudel
  2. 关于Maven父子工程的理解:

父项目中有:

<modules>
    <module>servlet-01</module>
</modules>

父项目中的java子项目可以直接使用,类似于:son extends father

  1. Maven环境优化

    1. 修改web.xml文件为最新的
    2. 将maven的结构构建搭配完整
  2. 编写一个Servlet程序

    1. 编写一个普通类
    2. 这个普通类去继承Servlet接口,这里我们直接继承HttpServlet
  3. 编写Servlet的映射

    为什么要写映射?

    我们写的是Java程序,但是要通过浏览器去访问,而浏览器需要连接web服务器,所以需要在web服务中(在webapps目录下的web.xml文件中)注册我们写的Servlet,还需要给它写一个浏览器能够访问的路径。

  4. 配置Tomcat
    注意:需要配置项目发布的路径

  5. 启动测试

6.3、Servlet原理

Servlet是由Web服务器调用,web服务器在收到浏览器请求之后,会:

Servlet原理

6.4、Mapping问题

  1. 一个Servlet请求可以指定一个映射 /hello
  2. 一个Servlet请求可以指定多个映射 /hello/test
  3. 一个Servlet请求可以指定通用映射 /hello/
  4. 默认请求路径 /
  5. 指定一些后缀或者前缀等 .do
  6. 优先级问题

指定了固有的映射优先级最高(/hello),如果找不到就会走默认的处理请求(/)

6.5、ServletContext

web容器启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表当前的web应用

1、共享数据

在这个Servlet中保存的数据可以在另一个Servlet中拿到。

1.创建一个放置数据的Servlet类
context.setAttribute("username",username);// 将一个数据存在了ServletContext中;名字为:"username",值为:username
2.再创建一个读取数据的Servlet类
String username = (String) context.getAttribute("username");
resp.getWriter().print("名字:" + username);
3.配置web.xml
4.测试访问结果
2、获取(web.xml中的)初始化参数

在web.xml配置初始化参数,在Servlet类中获取初始化参数

<!--配置一些web应用初始化参数-->
<context-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql://localhost:3306/jbpowernode</param-value>
</context-param>
3、请求转发
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   
    System.out.println("进入了ServletDemo04");
    ServletContext context = this.getServletContext();
    /*RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gP");//"/gP"为转发的请求路径
	requestDispatcher.forward(req,resp);//调用forward方法实现转发*/
    context.getRequestDispatcher("/gP").forward(req,resp);
}
RequestDispatcher接口的include()方法与forward()方法的区别:
  • RequestDispatcher接口所定义的forward()方法可以将HTTP请求转送给其他Web资源(例如Servlet、JSP或HTML)进行处理,并产生HTTP回应。

  • RequestDispatcher接口的include()方法与forward()方法非常类似,唯一的不同在于:利用include()方法将HTTP请求转送给其他Servlet后,被调用的Servlet虽然可以处理这个HTTP请求,但是最后的主导权仍然是在原来的Servlet。

  • RequestDispatcher是一个Web资源的包装器,可以用来把当前request传递到该资源,或者把新的资源包括到当前响应中。

由于jsp:include只能指定固定的jsp文件名,不能动态指定jsp文件名。我们需要把jsp:include翻译为Java code - RequestDispatcher.include();

4、读取资源文件
Properties

在java目录下新建properties

在resources目录下新建properties

发现都被打包到了同一个路径下:classes,我们俗称这个路径为classpath

6.6、HttpServletResponse

web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的HttpServletRequest对象。

1、简单分类

负责向浏览器发送数据的方法:

ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;

负责向浏览器发送响应头的方法:

void setCharacterEncoding(String var1);

void setContentLength(int var1);

void setContentLengthLong(long var1);

void setContentType(String var1);

void setDateHeader(String var1, long var2);

void addDateHeader(String var1, long var2);

void setHeader(String var1, String var2);

void addHeader(String var1, String var2);

void setIntHeader(String var1, int var2);

void addIntHeader(String var1, int var2);
响应的状态码
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
2、常见应用
1.向浏览器输出消息
2.下载文件
1.获取下载文件的路径

2.下载的文件名是什么

3.设置想办法让浏览器能够支持下载我们需要的东西

4.获取下载文件的输出流

5.创建缓冲区

6.获取OutputStream对象

7.将FileOutputStream流写到buffer缓冲区

8.使用OutputStream将缓冲区的数据输出到客户端
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   

    /* 下载文件*/
    //              1.获取下载文件的路径
    String realPath = "E:\\JavaWeb_Servlet\\Response\\src\\main\\resources\\test.JPG";
    System.out.println("获取的下载文件的路径:" + realPath);
    //          2.下载的文件名是什么
    String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);//极其精妙的方法,注意!
    //          3.设置想办法让浏览器能够支持下载我们需要的东西,中文文件名URLEncoder.encode编码,否则可能乱码
    resp.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName,"UTF-8"));
    //          4.获取下载文件的输出流
    FileInputStream in = new FileInputStream(realPath);
    //          5.创建缓冲区
    int len = 0;
    byte[] buffer = new byte[1024];
    //          6.获取OutputStream对象
    ServletOutputStream out = resp.getOutputStream();
    //          7.将FileOutputStream流写到buffer缓冲区
    //              8.使用OutputStream将缓冲区的数据输出到客户端
    while ((len = in.read(buffer)) > 0) {
   
        out.write(buffer,0,len);
    }
    //              9.关闭流
    in.close();
    out.close();
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   
    doGet(req, resp);
}
3、验证码功能

验证怎么来的?

前端实现
<template>
<div
     class="ValidCode disabled-select"
     :style="`width:${width}; height:${height}`"
     @click="refreshCode"
     >
    <span
          v-for="(item, index) in codeList"
          :key="index"
          :style="getStyle(item)"
          >
        {
  { item.code }}
    </span>
    </div>
</template>

<script>
    export default {
        name: 'ValidCode',
        model: {
            prop: 'value',
            event: 'input',
        },
        props: {
            width: {
                type: String,
                default: '100px',
            },
            height: {
                type: String,
                default: '40px',
            },
            length: {
                type: Number,
                default: 4,
            },
            refresh: {
                type: Number,
            },
        },
        data() {
            return {
                codeList: [],
            }
        },
        watch: {
            refresh() {
                this.createdCode()
            },
        },
        mounted() {
            this.createdCode()
        },
        methods: {
            refreshCode() {
                this.createdCode()
            },
            createdCode() {
                const len = this.length
                const codeList = []
                const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789'
                const charsLen = chars.length
                // 生成
                for (let i = 0; i < len; i++) {
                    const rgb = [
                        Math.round(Math.random() * 220),
                        Math.round(Math.random() * 240),
                        Math.round(Math.random() * 200),
                    ]
                    codeList.push({
                        code: chars.charAt(Math.floor(Math.random() * charsLen)),
                        color: `rgb(${rgb})`,
                        fontSize: `${10 + (+[Math.floor(Math.random() * 10)] + 6)}px`,
                        padding: `${[Math.floor(Math.random() * 10)]}px`,
                        transform: `rotate(${
                        Math.floor(Math.random() * 90) - Math.floor(Math.random() * 90)
                    }deg)`,
                    })
                }
                // 指向
                this.codeList = codeList
                // 将当前数据派发出去
                // console.log(codeList.map(item => item.code).join(''))
                this.$emit('input', codeList.map((item) => item.code).join(''))
            },
            getStyle(data) {
                return `color: ${data.color}; font-size: ${data.fontSize}; padding: ${data.padding}; transform: ${data.transform}`
            },
        },
    }
</script>

<style scoped>
    .ValidCode {
        display: flex;
        justify-content: center;
        align-items: center;
        cursor: pointer;
    }
    .ValidCode span {
        display: inline-block;
    }
</style>
后端实现

需要用到java的图片类,生成一个图片

public class ImageServlet extends HttpServlet {
   
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   

        //如何让浏览器3秒自动刷新一次
        resp.setHeader("refresh","3");

        //在内存中创建一个图片
        BufferedImage image = new BufferedImage(50, 20, BufferedImage.TYPE_INT_RGB);
        //得到图片
        Graphics2D g = (Graphics2D) image.getGraphics(); //笔
        //设置图片背景颜色
        g.setColor(Color.white);
        g.fillRect(0,0,50,20);
        //给图片写数据
        g.setColor(Color.BLUE);
        g.setFont(new Font(null,Font.BOLD,20));
        g.drawString(makeNum(),0,20);

        //告诉浏览器,这个请求用图片的方式打开
        resp.setContentType("image/jpg");
        //网站存在缓存,不让浏览器缓存
        resp.setDateHeader("expires",-1);
        resp.setHeader("Cache.Control","no-cache");
        resp.setHeader("Pragma","no-cache");

        //把图片写给浏览器
        ImageIO.write(image, "jpg", resp.getOutputStream());<
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值