Cookie和Session

第1章 会话的基本概念

1.1 什么是会话
在日常生活中,从拨通电话到挂断电话之间的一连串的你问我答的过程就是一个会话。Web应用中的会话过程类似于生活中的打电话过程,它指的是一个客户端(浏览器)与Web服务器之间连续发生的一系列请求和响应过程,例如,一个用户在某网站上的整个购物过程就是一个会话。在打电话过程中,通话双方会有通话内容,同样,在客户端与服务器端交互的过程中,也会产生一些数据。例如,用户甲和乙分别登录了购物网站,甲购买了一个Nokia手机,乙购买了一个Ipad,当这两个用户结账时,Web服务器需要对用户甲和乙的信息分别进行保存。在前面章节讲解的域对象中,HttpServletRequest对象和ServletContext对象都可以对数据进行保存,但是这两个对象都不可行,具体原因如下:
(1)客户端请求Web服务器时,针对每次HTTP请求,Web服务器都会创建一个HttpServletRequest对象,该对象只能保存本次请求所传递的数据。由于购买和结账是两个不同的请求,因此,在发送结账请求时,之前购买请求中的数据将会丢失。
(2)使用ServletContext对象保存数据时,由于同一个Web应用共享的是同一个ServletContext对象,因此,当用户在发送结账请求时,由于无法区分哪些商品是哪个用户所购买的,而会将该购物网站中所有用户购买的商品进行结算,这显然也是不可行的。
(3)为了保存会话过程中产生的数据,在Servlet技术中,提供了两个用于保存会话数据的对象,分别是Cookie和Session。关于Cookie和Session的相关知识,将在下面的小节进行详细讲解。

在这里插入图片描述

Servlet的会话技术主要有cookie与session两种 。

第2章 cookie

2.1 cookie的概念
2.1.1 什么是cookie
浏览器端的会话技术,它通过在浏览器中记录一些服务器传递过来的数据,解决会话从什么时候开始,到什么时候结束。
2.2 cookie的应用场景
1. 记住用户名

在这里插入图片描述

2. 自动登录(记住用户名和密码)

在这里插入图片描述

2.3 cookie的基本使用
2.3.1 cookie常用的方法介绍
Cookie:
Cookie(String name, String value) 创建cookie对象
String getName() 获取cookie的名称
String getValue() 获取cookie的值
void setPath(String uri) 设置cookie的路径——浏览器根据这个路径判断那些cookie要发送给服务器
HttpServletResponse:
void addCookie(Cookie cookie) 将cookie发送给
HttpServletRequest:
Cookie[] getCookies() 获取浏览器发送的cookie
注意:
cookie主要是通过名称和路径来确定他的唯一性的 .
例如:以下表示的是两个cookie,虽然名字一样 , 但是路径不同 , 所以两个cookie可以同时存在。
/day04/a/b/cookie1
/day04/a/cookie1
如果路径和名称一样,后添加的cookie将覆盖前者
2.3.2 使用步骤
1. 在CookieServlet1创建cookie
2. 在CookieServlet1设置cookie路径为当前项目根路径:“/day04”
3. 在CookieServlet1使用response对象将cookie发送给浏览器
4. 在CookieServlet2通过request对象获取浏览器发送的cookie
5. 打印在控制台上
2.3.3 演示代码
CookieServlet1:
package cn.itcast.web;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//urlPatterns = "/cookie1"
public class CookieServlet1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
//创建cookie
Cookie cookie = new Cookie("username","tom");
//设置cookie的路径——浏览器根据这个路径判断那些cookie要发送给服务器
cookie.setPath("/day04");
//将cookie发送给浏览器
response.addCookie(cookie);
}
}
CookieServlet2:
package cn.itcast.web;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//urlPatterns = "/cookie2"
public class CookieServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
//获取浏览器发送的cookie
Cookie[] cookies = request.getCookies();
if(cookies != null){
for (Cookie coo : cookies) {
if("username".equals(coo.getName())){
//打印cookie的名称和值
System.out.println(coo.getName()+":"+coo.getValue());
}
}
}
}
}
2.3.4 cookie技术原理分析

在这里插入图片描述

2.4 Cookie的分类
会话级别的Cookie:默认的.关闭了浏览器Cookie就销毁了.
持久级别的Cookie:可以设置指定cookie在浏览器的存活时间 , Cookie就不会随着浏览器关闭而销毁了.
2.4.1 API介绍
void setMaxAge(int expiry) 设置cookie的最大生存时间(单位:秒),超过了该时间后Cookie会自动销毁。
注意 : 当时间为0的时候 , 意思为立即删除此Cookie(前提:path和name必须一致)。
2.4.2 使用步骤
1. 创建cookie对象
2. 设置生存时间
3. 设置cookie的路径
4. 发送cookie给浏览器
注意事项 : 要删除已经存在的cookie,用来覆盖的cookie的名称与路径必须与原来的cookie一致
2.4.3 演示代码
package cn.itcast.web;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//urlPatterns = "/maxage"
public class MaxAgeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
//创建cookie
/* Cookie cookie = new Cookie("name","tom");
//设置cookie的生存时间
cookie.setMaxAge(60*60*24*7);
//设置cookie的路径
cookie.setPath("/day04");
//发送cookie给浏览器
response.addCookie(cookie);*/
//=====如果需要立刻删除cookie======
//创建空数据的cookie,名称保持一致
Cookie cookie = new Cookie("name","");
//设置cookie的生存时间为0立刻死亡
cookie.setMaxAge(0);
//设置cookie的路径,与原来的cookie路径保持一致
cookie.setPath("/day04");
//发送cookie给浏览器
response.addCookie(cookie);
}
}
2.5 案例:记录用户上一次访问时间
2.5.1 案例需求
展示用户上一次访问服务器的时间
2.5.2 案例分析

在这里插入图片描述

2.5.3 实现代码
package cn.itcast.web;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//urlPatterns = "/time"
public class TimeServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
//第一次访问操作
// 1 获取用户当前访问的时间
Date date = new Date();
//格式化时间数据(注意:在cookie值中不能使用分号(;)、逗号(,)以及空格,否则会出现异常)
SimpleDateFormat format = new SimpleDateFormat("yyyy‐MM‐dd/hh:mm:ss");
String format1 = format.format(date);
System.out.println(format1);
// 2 将数据存入cookie
Cookie cookie = new Cookie("time", format1);
cookie.setMaxAge(60*60*24);
// 3 将数据发送给浏览器
response.addCookie(cookie);
//第二次访问操作
//获取cookie数组
Cookie[] cookies = request.getCookies();
if(cookies != null) {
for (Cookie cookie2 : cookies) {
//选择获取名称为time的cookie
if("time".equals(cookie2.getName())) {
//将数据发送页面
response.getWriter().write(cookie2.getValue());
}
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request, response);
}
}
2.5.4 注意事项
在上面的案例中我们给cookie添加数据的时候需要注意数据的内容,在cookie值中不能使用分号(;)、逗号(,)、空格。如果存入的数据不合法,会出现一个错误:
java.lang.IllegalArgumentException:
An invalid character [32] was present in the Cookie value
那么如果我们一定要保存非法数据在cookie中,该如何操作呢?
答:cookie对于基本符号、数字、和字母是可以存储的,因此,我们只需要将非法数据转换成符号、数字、和字母形式存储,要使用的时候再转换成正常的数据(解码)即可。
那么,最后的问题就是,我们如何对这些数据进行编码和解码呢?我们需要来学习一些新的对象和方法。
2.5.4.1 API介绍
URLEncoder类:
static String encode(String s, String enc) 将指定的字符串,按指定的编码表编码
URLDecoder类:
static String decode(String s, String enc) 将指定的字符串,按指定的编码表解码
2.5.4.2 使用步骤
1. 在创建cookie之前将数据编码
2. 将编码后的数据存入cookie
3. 获取到cookie之后,解码数据,获取正常中文内容
2.5.4.3 注意事项
1. 编码解码两次操作要使用同一个编码表
2.5.4.4 演示代码
package cn.itcast.web;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//urlPatterns = "/time"
public class TimeServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
//第一次访问操作
// 1 获取用户当前访问的时间
Date date = new Date();
// 2 格式化时间数据(时间转换成含有非法字符形式)
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 hh时mm分ss秒");
String format1 = format.format(date);
System.out.println(format1);
// 3 将数据进行编码
String encode = URLEncoder.encode(format1, "utf‐8");
// 4 将数据存入cookie
Cookie cookie = new Cookie("time",encode );
cookie.setMaxAge(60*60*24);
// 5 将数据发送给浏览器
response.addCookie(cookie);
//第二次访问操作
//获取cookie数组
Cookie[] cookies = request.getCookies();
if(cookies != null) {
for (Cookie cookie2 : cookies) {
//选择获取名称为time的cookie
if("time".equals(cookie2.getName())) {
//由于数据之前经过编码,现在要还原的中文数据
String decode = URLDecoder.decode(cookie2.getValue(), "utf‐8");
//将数据发送页面
response.setContentType("text/html;charset=utf‐8");
response.getWriter().write(decode);
}
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request, response);
}
}

第3章 session

3.1 session的基本概念
当人们去医院就诊时,就诊病人需要办理医院的就诊卡,该卡上只有卡号,而没有其它信息。但病人每次去该医院就诊时,只要出示就诊卡,医务人员便可根据卡号查询到病人的就诊信息。Session技术就好比医院发放给病人的就医卡和医院为每个病人保留病例档案的过程。当浏览器访问Web服务器时,Servlet容器就会创建一个Session对象和ID属性,其中,Session对象就相当于病历档案,ID就相当于就诊卡号。当客户端后续访问服务器时,只要将标识号传递给服务器,服务器就能判断出该请求是哪个客户端发送的,从而选择与之对应的Session对象为其服务。
  	需要注意的是,由于客户端需要接收、记录和回送Session对象的ID,因此,通常情况下,Session是借助Cookie技术来传递ID属性的。为了使读者更好的理解Session,接下来,以网站购物为例,通过一张图来描述Session保存用户信息的原理,具体如下图所示。

在这里插入图片描述

Session保存用户信息的过程
在上图中,用户甲和乙都调用buyServlet将商品添加到购物车,调用payServlet进行商品结算。由于甲和乙购买商品的过程类似,在此,以用户甲为例进行详细说明。当用户甲访问购物网站时,服务器为甲创建了一个Session对象(相当于购物车)。当甲将Nokia手机添加到购物车时,Nokia手机的信息便存放到了Session对象中。同时,服务器将Session对象的ID属性以Cookie (Set-Cookie: JSESSIONID=111)的形式返回给甲的浏览器。当甲完成购物进行结账时,需要向服务器发送结账请求,这时,浏览器自动在请求消息头中将Cookie (Cookie: JSESSIONID=111)信息回送给服务器,服务器根据ID属性找到为用户甲所创建的Session对象,并将Session对象中所存放的Nokia手机信息取出进行结算。
3.1.1 什么要存在Session
使用servlet生成验证码时,我们需要在服务器记录一份生成的随机字符,当用户提交填写的数据时,将用户输入的数据和服务器缓存的数据进行比对。
问:将随机字符串保存在ServletContext中或者request中是否可以?
答:将数据存放到ServletContext,多个用户共享一个验证码。

在这里插入图片描述

答:将数据存放到request作用域,多次请求不能共享数据

在这里插入图片描述

我们发现将数据保存到ServletContext和request中是存在问题的,那么就需要使用会话技术保存用户的私有信息.
3.2 session的与cookie的区别
																		cookie 				session
会话数据保存的位置 										浏览器 			服务器
数据的安全性 													不安全 			安全
存储数是否有限制 											有 					无
3.3 session的应用场景
1. 保存购物车数据
2. 保存用户浏览器记录数据
3. 保存用户登录信息数据
4. 保存验证码
3.4 session的基本使用
3.4.1 session存储数据与 获取数据
3.4.1.1 API介绍
1.ttpServletRequest
HttpSession getSession() 获取session对象
2.HttpSession
void setAttribute(String name, Object value) 在session中保存数据
Object getAttribute(String name) 从session中获取数据
void removeAttribute(String name) 从session中移除数据
3.4.1.2 使用步骤
1. 在SessionServlet通过request对象获取session对象
2. 在SessionServlet调用session的setAttribute保存数据
3. 在SessionServlet调用session的getAttribute获取数据
4. 在SessionServlet1通过request对象获取session对象
5. 在SessionServlet1调用session的removeAttribute移除数据
6. 在SessionServlet1调用session的getAttribute获取数据
3.4.1.3 注意事项
1. getAttribute方法返回值是Object,因此需要将返回值强制转换才能方便使用。
3.4.1.3 演示代码
SessionServlet:
package cn.itcast.web;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
//urlPatterns = "/session"
public class SessionServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
//获取session对象
HttpSession session = request.getSession();
//添加数据
session.setAttribute("addr","广州");
}
}
SessionServlet1:
package cn.itcast.web;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
//urlPatterns = "/session1"
public class SessionServlet1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
//获取session对象
HttpSession session = request.getSession();
//获取数据
String addr = (String) session.getAttribute("addr");
System.out.println(addr);
//移除数据
session.removeAttribute("addr");
//再次获取,查看效果
String addr1 = (String) session.getAttribute("addr");
System.out.println(addr1);
}
}
3.4.2 session的原理分析

在这里插入图片描述

3.5 案例:使用session存储验证码完成登录功能
3.5.1 案例需求
1. 在登录页面用户登录的时候要查看到验证码,如图所示:

在这里插入图片描述

2. 在生成页面验证码图片的同时,使用session存储验证码
3. 在处理用户登录请求的时候,首先校验验证码
4. 校验通过才能执行登录操作
3.5.2 案例效果
用户提交验证码,与session中保存验证码校验一致才能登录
3.5.3 案例分析

在这里插入图片描述

3.5.4 代码实现
1. 页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF‐8"%>
<html>
<head>
<meta http‐equiv="Content‐Type" content="text/html; charset=utf‐8">
<title>login</title>
<script type="text/javascript">
function changeCode(){
document.getElementById("img").src = "/day04/checkcode?r="+new
Date().getTime();
}
</script>
</head>
<body>
<form action="/day04/login" method="post">
<table>
<tr><td>用户名:</td><td><input type="text" name="username"></td></tr>
<tr><td>密码:</td><td><input type="password" name="password"></td></tr>
<tr><td>验证码:</td><td><input type="text" name="code"></td></tr>
<!‐‐ 通过向服务器发送请求,从服务器获取验证码数据 ‐‐>
<tr><td></td><td><img id="img" src="/day04/checkcode" onclick="changeCode();"/><a
href="javascript:;" onclick="changeCode();">换一换</a><span><%=
(request.getAttribute("msg")==null?"":request.getAttribute("msg")) %></span></td></tr>
<tr><td></td><td><input type="submit" value="登陆"></td></tr>
</table>
</form>
</body>
</html>
2.配置验证码servlet
package cn.itcast.web;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//urlPatterns = "/checkcode"
public class CheckcodeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
// 创建画布
int width = 120;
int height = 40;
BufferedImage bufferedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
// 获得画笔
Graphics g = bufferedImage.getGraphics();
// 填充背景颜色
g.setColor(Color.white);
g.fillRect(0, 0, width, height);
// 绘制边框
g.setColor(Color.red);
g.drawRect(0, 0, width ‐ 1, height ‐ 1);
// 生成随机字符
// 准备数据
String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
// 准备随机对象
Random r = new Random();
// 声明一个变量 保存验证码
String code = "";
// 书写4个随机字符
for (int i = 0; i < 4; i++) {
// 设置字体
g.setFont(new Font("宋体", Font.BOLD, 28));
// 设置随机颜色
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
String str = data.charAt(r.nextInt(data.length())) + "";
g.drawString(str, 10 + i * 28, 30);
// 将新的字符 保存到验证码中
code = code + str;
}
// 绘制干扰线
for (int i = 0; i < 6; i++) {
// 设置随机颜色
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width),
r.nextInt(height));
}
// 将验证码 打印到控制台
System.out.println(code);
// 将验证码放到session中
request.getSession().setAttribute("code_session", code);
// 将画布显示在浏览器中
ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request, response);
}
}
3.登录servlet
package cn.itcast.web;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.itcast.dao.UserDao;
import cn.itcast.domain.User;
//urlPatterns = "/login"
public class LoginServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
//用户请求中的验证码获取
String code = request.getParameter("code");
//获取session中保存的验证码
String code_session = (String)request.getSession().getAttribute("code_session");
//与session中保存的验证码进行校验
if(!code_session.equalsIgnoreCase(code)){
//验证码错误,告诉用户,页面提示
request.setAttribute("msg","验证码错误");
request.getRequestDispatcher("/login.jsp").forward(request,response);
return;
}
//验证码正确,登录逻辑执行
//获取用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
//调用Service方法,登录用户
UserDao userDao = new UserDao();
User loginUser = userDao.login(username,password);
if(loginUser == null){
request.setAttribute("msg","用户名或则密码错误");
request.getRequestDispatcher("/login.jsp").forward(request,response);
return;
}else{
//登陆成功,跳转主页
response.sendRedirect(request.getContextPath());
return;
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request, response);
}
}
4.dao:
package cn.itcast.dao;
import cn.itcast.domain.User;
import cn.itcast.utils.JDBCUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
public class UserDao {
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
public User login(String username, String password) {
String sql = "select * from user where username = ? and password = ?";
try {
User query = template.queryForObject(sql, new BeanPropertyRowMapper<User>
(User.class), username,password);
return query;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
}

第4章 三个域对象总结

4.1 ServletContext:
针对一个WEB应用。一个WEB应用只有一个ServletContext对象,使用该对象保存的数据在整个WEB应用中都有效。
创建:服务器启动的时候.
销毁:服务器关闭的时候或者项目移除的时候.
4.2 HttpSession
针对一次会话。使用该对象保存数据,一次会话(多次请求)内数据有效。
创建:可以暂且认为在服务器第一次调用getSession()的时候.服务器创建session的对象.因为session销毁后,再次调用getSession()的时候也会创建.
销毁:
非正常关闭服务器
Session过期了,默认时间是30分钟.
手动调用session的invalidate的方法
4.3 HttpServletRequest
针对一次请求。使用该对象保存数据,一次请求(一个页面,如果是请求转发多个页面)内数据有效.
创建:客户端向服务器发送一次请求
销毁:服务器为这次请求作出响应之后,销毁request.
4.4 三个作用域对象操作的API
api都是一样的,完成存取和销毁的操作
存放数据:setAttribute(name,value)
获得数据:getAttribute(name)
删除数据:removeAttribute(name)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值