Servlet

本文详细讲解了Servlet的工作原理,包括Servlet映射路径的配置,如精确路径、通用路径和前缀/后缀匹配。还介绍了ServletContext的使用,如共享数据和获取初始化参数。此外,涵盖了响应操作,如请求转发、文件下载、验证码和重定向的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. Servlet运行原理

在这里插入图片描述
上图来自:Servlet运行原理

2. Mapping

web.xml详解
servlet映射路径位于
使用‘/’开头,使用‘/’结尾,表示使用路径匹配,比如/foo/bar/

  1. 一个servlet可以指定一个映射路径,即精确路径匹配
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>
  1. 一个servlet可以指定多个映射路径
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello1</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>hello2</servlet-name>
    <url-pattern>/hello2</url-pattern>
  </servlet-mapping>
  1. 一个servlet可以指定通用映射路径
    只使用‘/*’,表示匹配所有的请求;
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
  1. 可以使用前缀或后缀等等
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>.do</url-pattern>
  </servlet-mapping>

在这里插入图片描述

<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

连接成功

  1. url优先级问题
 <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>hello2</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

默认走通用的,但如果指定了对应路径,会优先走指定的路径,而非通用路径。

tips:可以将web.xml的模板内容在项目下新建一个note.md保存起来,方便使用。
在这里插入图片描述

web.xml
```xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">

</web-app>

3.ServletContext

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

3.1 共享数据

在一个Servlet中保存的数据,可以在另一个Servlet中拿到。注意需要先提交保存数据,再访问保存的数据

package org.raylene.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

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

        ServletContext servletContext = this.getServletContext();
        String username = "tom & jerry测试中文";
        servletContext.setAttribute("username",username);
    }
}

package org.raylene.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class GetContext extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset = utf-8");
        ServletContext servletContext = this.getServletContext();
        String username = (String)servletContext.getAttribute("username");
        resp.getWriter().println("名字:"+username);
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0"
         metadata-complete="true">
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>org.raylene.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>getc</servlet-name>
        <servlet-class>org.raylene.servlet.GetContext</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>

    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>getc</servlet-name>
        <url-pattern>/getc</url-pattern>
    </servlet-mapping>

</web-app>


3.2 获取初始化参数getInitParameter

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0"
         metadata-complete="true">
    <context-param>
        <param-name>url</param-name>
        <param-value>jdbc:mysql://localhost:3006/mybatis</param-value>
    </context-param>
      
    <servlet>
        <servlet-name>getpara</servlet-name>
        <servlet-class>org.raylene.servlet.ServletDemo03</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>getpara</servlet-name>
        <url-pattern>/gp</url-pattern>
    </servlet-mapping>
   

</web-app>


package org.raylene.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class ServletDemo03 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();

        String url = servletContext.getInitParameter("url");
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().println("url为:"+url);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}


3.3实现请求转发

<servlet>
        <servlet-name>rd</servlet-name>
        <servlet-class>org.raylene.servlet.ServletDemo04</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>rd</servlet-name>
        <url-pattern>/rd</url-pattern>
    </servlet-mapping>
package org.raylene.servlet;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


public class ServletDemo04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        System.out.println("进入ServletDemo04");
        ServletContext servletContext = this.getServletContext();
        RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/gp");//转发的请求路径
        requestDispatcher.forward(req,resp);//调用forward方法实现转发
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

当我们在浏览器输入rd时,==却收到了ServletDemo03对应的资源,==说明实现了转发
在这里插入图片描述

请求转发:
request.getRequestDispatcher(URL地址).forward(request, response)

处理流程:

  1. 客户端发送请求,Servlet做出业务逻辑处理。
  2. Servlet调用forword()方法,服务器Servlet把目标资源返回给客户端浏览器。

参考链接:https://www.jianshu.com/p/29822c2c1ec0

在这里插入图片描述

3.4 读取资源文件

Properties
关于properties类的一些介绍可以参考这篇博文:Java中Properties类详解

  • 在Java目录下新建properties
  • 在resources目录下新建properties
    发现都被打爆到同一个路径下,target下servlet-02的classes路径下,该路径称为classpath

配置pom文件

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

注册servlet映射

<servlet>
        <servlet-name>prop</servlet-name>
        <servlet-class>org.raylene.servlet.ServletDemo06</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>prop</servlet-name>
        <url-pattern>/prop</url-pattern>
    </servlet-mapping>
package org.raylene.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;


public class ServletDemo06 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
        InputStream is = servletContext.getResourceAsStream("/WEB-INF/classes/db.properties");
        Properties properties = new Properties();
        properties.load(is);
        String usernm = properties.getProperty("username");
        String pwd= properties.getProperty("password");
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().print(usernm+":"+pwd);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}


读取java目录下的文件

InputStream is = servletContext.getResourceAsStream("/WEB-INF/classes/org/raylene/servlet/aa.properties");
        Properties properties = new Properties();
        properties.load(is);

4.HttpServletResponse

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

  • 获取客户端请求过来的参数HttpServletRequest
  • 给用户返回一些信息,用HttpServletResponse对象
    接口HttpServletResponse继承ServletResponse
public interface HttpServletResponse extends ServletResponse
public interface ServletResponse

ServletResponse中的方法有:

String getCharacterEncoding();

    String getContentType();

    ServletOutputStream getOutputStream() throws IOException;

    PrintWriter getWriter() throws IOException;

    void setCharacterEncoding(String var1);

    void setContentLength(int var1);

    void setContentType(String var1);

    void setBufferSize(int var1);

    int getBufferSize();

    void flushBuffer() throws IOException;

    void resetBuffer();

    boolean isCommitted();

    void reset();

    void setLocale(Locale var1);

    Locale getLocale();
    

ServletResponse中常用的方法

ServletOutputStream getOutputStream() throws IOException;

    PrintWriter getWriter() throws IOException;//负责向浏览器发送响应数据
    void setContentType(String var1);

HttpServletResponse中有一些HTTP状态码常量及一些相应的方法
响应状态码

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;

4.1 常见应用

  1. 向浏览器输出消息
  2. 下载文件
    实现方法
    1. 获取下载路径
    2. 下载文件的名称
    3. 浏览器支持下载我们需要的内容
    4. 获取下载文件的输入流
    5. 创建缓存区
    6. 获取OutputStream对象
    7. 将FileOutputStream写入buffer缓存区
    8. 使用OutputStream将缓存区的对象输出到客户端

4.1 Response下载资源

IO流IO
2,3搞懂

package org.raylene.servlet;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;

public class FileServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//   1. 获取下载路径
        //获取资源路径
        //文件输入流读取资源
        String realPath = "G:\\file\\wonder.png";

        System.out.println("文件的下载路径为:"+realPath);
//   2. 下载文件的名称
        //获取文件名
        //substring() 方法返回字符串的子字符串。
        //lastIndexOf() 方法可返回一个指定的字符串值最后出现的位置,
        // 在一个字符串中的指定位置从后向前搜索
        String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);
//   3. 浏览器支持下载我们需要的内容
        //设置消息头,告诉浏览器,我要下载1.png这个图片
        resp.setHeader("Content-Disposition", "attachment; filename="+ URLEncoder.encode(fileName,"UTF-8"));
//   4. 获取下载文件的输入流
        FileInputStream in = new FileInputStream(realPath);

//   5. 创建缓存区
        int len = 0;
        byte[] bytes = new byte[1024];

//   6. 获取OutputStream对象
        ServletOutputStream out = resp.getOutputStream();

//   7. 将FileOutputStream写入buffer缓存区
        while((len=in.read(bytes))>0){
            out.write(bytes, 0, len);
        }
        //关闭资源
        out.close();
        in.close();


    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

4.2 验证码

resp的方法解读,缓存策略解读,图片画笔

package org.raylene.servlet;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //如何让浏览器5秒刷新一次
        //设置一下自动刷新功能
        //下面两个语句均可,选其一
        resp.setHeader("refresh","2");
        //resp.setIntHeader("refresh", 5);
        //在内存新建一个图片
        BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
        //得到图片
        Graphics2D graphics = (Graphics2D) image.getGraphics();
        //设置背景颜色
        graphics.setColor(Color.pink);
        graphics.fillRect(0,0,80,20);
        //给图片写数据
        graphics.setColor(Color.BLUE);
        graphics.setFont(new Font("null",Font.BOLD,20));
        graphics.drawString(makeNum(),0,20);

        resp.setContentType("image/jpeg");
        //浏览器不缓存
        resp.setHeader("Cache-Control", "no-cache");
        resp.setHeader("Cache-Control", "no-store");
        resp.setHeader("Pragma", "no-cache");
        resp.setDateHeader("Expires", 0);

//        或
//
//        response.setHeader("Cache-Control", "no-cache");
//        response.setHeader("Pragma", "no-cache");
//        response.setDateHeader("Expires", 0);
//
        //把图片写给浏览器
        ImageIO.write(image, "jpg", resp.getOutputStream());

    }
    private String makeNum(){
        Random r = new Random();
        String snum = r.nextInt(999999) + "";
        StringBuffer sbuffer = new StringBuffer();
        //防止生成数小于6位,若小于6位,则用0填充
        for (int i = 0; i < 6-snum.length(); i++) {
            sbuffer.append("0");
        }
        String s = sbuffer.toString()+snum;
        return s;

    }
}


4.3 Response重定向

重定向:
response.sendRedirect(URL地址)
处理流程:

客户端发送请求,Servlet做出业务逻辑处理。
Servlet调用response.sendReadirect()方法,把要访问的目标资源作为response响应头信息发给客户端浏览器。
客户端浏览器重新访问服务器资源xxx.jsp,服务器再次对客户端浏览器做出响应。
在这里插入图片描述
参考链接:https://www.jianshu.com/p/29822c2c1ec0


package org.raylene.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("/response_war/img");
    }
}

在这里插入图片描述
注意
当进入该项目时,默认进入index.jsp,当在URL中输入red时,它会告诉浏览器,你去其他的url下找,此时,需要输入项目完整名称(除去localhost:8080这一段的后面全部),也就是重定向可以区定向到不同的项目下。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
重定向到另一个项目下

为什么不能重定向到另一个项目下:此时,若你在tomcat中没有配置你要跳转的项目对应的war包,则无法跳转,若已配置,则可以成功实现跳转。如图2所示

 resp.sendRedirect("/servlet_01_war/hello");

图1
图1
图2
在这里插入图片描述
重定向与转发的区别
相同点:

  • 页面都可以拿到对应资源

不同点

  • 请求转发时,url不会发生变化
  • 重定向时,url会发生变化。

5. HttpServletRequest

关于各类文件乱码:乱码参考
index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<body>
<h2>Hello World!</h2>
<%--这里的提交路径,需要找到项目的路径--%>
<form action="${pageContext.request.contextPath}/login" method="get">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    手机号<input type="tel" name="telp"><br>
    <input type="submit">
</form>
</body>
</html>

success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>success!</h1>
</body>
</html>
package org.raylene.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("进入了这个请求");
        String username = req.getParameter("username");
        String pwd = req.getParameter("password");

        System.out.println(username+":"+pwd);

        resp.sendRedirect("/response_war/success.jsp");
    }
}

5.1 获取参数,请求转发

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>
<h1>登录</h1>
<div style="text-align: center">
<%--    以post方式提交表单,提交的路径/login--%>
    <form action="${pageContext.request.contextPath}/login" method="post">
        用户名:<input type="text" name="username"><br>
        密码:<input type="password" name="password" ><br>
        爱好:
        <input type="checkbox"name="hobby" value="bear">bear
        <input type="checkbox"name="hobby" value="football">football
        <input type="checkbox"name="hobby" value="table tennis">table tennis
        <input type="checkbox"name="hobby" value="basketball">basketball
        <input type="checkbox"name="hobby" value="swimming">swimming
       <input type="submit">
    </form>
</div>

</body>
</html>

succcess.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>
    登录成功
</h1>
</body>
</html>

package org.raylene.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password= req.getParameter("password");
        String[] hobbies = req.getParameterValues("hobby");
        System.out.println("---------------");
        System.out.println(username+":"+password);
        System.out.println(Arrays.toString(hobbies));
        System.out.println("==========================");
//        resp.sendRedirect("/request_war/succcess.jsp");
        //请求转发
        req.setCharacterEncoding("utf-8");
        req.getRequestDispatcher("./succcess.jsp").forward(req,resp);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值