第5章 会话及会话技术

本文详细介绍了Cookie和Session在Web程序中的使用,包括它们的工作原理、创建与设置方法,以及在用户会话跟踪中的具体应用。通过示例展示了如何使用Cookie保存用户访问时间和访问次数,以及Session在购物车功能和用户登录状态维持中的实现。同时,讨论了Cookie和Session的存储位置、有效期和限制。
摘要由CSDN通过智能技术生成

Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份Session通过在服务器端记录信息确定用户身份

5.1 cookie

5.1.1 cookie详解

特点

Cookie技术:会话数据保存在浏览器客户端。

Cookie技术核心:Cookie类:用于存储会话数据

1)构造Cookie对象

Cookie(java.lang.String name, java.lang.String value)

2)设置cookie

void setPath(java.lang.String uri)   :设置cookie的有效访问路径

void setMaxAge(int expiry) : 设置cookie的有效时间

void setValue(java.lang.String newValue) :设置cookie的值

3)发送cookie到浏览器端保存

void response.addCookie(Cookie cookie)  : 发送cookie

4)服务器接收cookie

Cookie[] request.getCookies()  : 接收cookie

Cookie原理

1)服务器创建cookie对象,把会话数据存储到cookie对象中。

new Cookie("name","value");

2) 服务器发送cookie信息到浏览器

response.addCookie(cookie);

举例: set-cookie: name=eric  (隐藏发送了一个set-cookie名称的响应头)

3)浏览器得到服务器发送的cookie,然后保存在浏览器端。

4)浏览器在下次访问服务器时,会带着cookie信息

举例: cookie: name=eric  (隐藏带着一个叫cookie名称的请求头)

5)服务器接收到浏览器带来的cookie信息

request.getCookies();

 Cookie的细节

1)void setPath(java.lang.String uri)   :设置cookie的有效访问路径。有效路径指的是cookie的有效路径保存在哪里,那么浏览器在有效路径下访问服务器时就会带着cookie信息,否则不带cookie信息。

2)void setMaxAge(int expiry) : 设置cookie的有效时间。

正整数:表示cookie数据保存浏览器的缓存目录(硬盘中),数值表示保存的时间。

负整数:表示cookie数据保存浏览器的内存中。浏览器关闭cookie就丢失了!!

零:表示删除同名的cookie数据

3)Cookie数据类型只能保存非中文字符串类型的。可以保存多个cookie,但是浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。

在下面查了下,cookie也可以存中文字符串,可以用URLEncoder类中的encode方法编码,然后用URLDecoder.decode方法解码


5.1.1 cookie案例:显示用户上次访问时间和访问次数

package chapter05;

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;

/**
 * Servlet implementation class LastAccessServlet
 */
@WebServlet("/LastAccessServlet")
public class LastAccessServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private int cnt = 0;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public LastAccessServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//response.getWriter().append("Served at: ").append(request.getContextPath());
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=utf-8");
		
		cnt++; //记录用户访问次数
		//获取所有cookie
        Cookie[] cookies=request.getCookies();
        /* cookies =null 错误处理 System.out.println(cookies);*/
        if(cookies==null ){
            //设置cookie的value
            //获取当前时间的字符串,重新设置cookie的值,重新发送cookie
            Date date=new Date();
            SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
            String str_date=sdf.format(date);
            System.out.println("编码前:"+str_date);
            //URL编码
            str_date= URLEncoder.encode(str_date,"utf-8");
            System.out.println("编码后:"+str_date);
            Cookie cookie=new Cookie("lastTime",str_date);
            //设置cookie存活时间
            cookie.setMaxAge(60*60*24*30);//一个月
            response.addCookie(cookie);
            response.getWriter().write("您好,欢迎您首次访问");
        }
        else
        {
            //遍历cookie数组
            if(cookies.length > 0)
            {
                for(Cookie cookie:cookies) {
                    //获取cookie的名称
                    String name=cookie.getName();
                    //判断名称是否是lastTime
                    if("lastTime".equals(name)){
                        //响应数据
                        //获取cookie的value时间
                        String value=cookie.getValue();
                        System.out.println("解码前:"+value);
                        //URL解码
                        value= URLDecoder.decode(value, "utf-8");
                        System.out.println("解码后:"+value);
                        response.getWriter().write("欢迎回来,您上次访问时间为:" + value +"这是您第" + cnt + "次访问!");
                        //设置cookie的value
                        //获取当前时间的字符串,重新设置cookie的值,重新发送cookie
                        Date date=new Date();
                        SimpleDateFormat timesdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
                        String str_time=timesdf.format(date);
                        System.out.println("编码前:"+str_time);
                        //URL编码
                        str_time=URLEncoder.encode(str_time, "utf-8");
                        System.out.println("编码后:"+str_time);
                        cookie.setValue(str_time);
                        //设置cookie存活时间
                        cookie.setMaxAge(60*60*24*30);	//一个月
                        //加入当前cookie请求时间
                        response.addCookie(cookie);
                        
                        cookie.setPath("/firstweb");
                        response.getWriter().println("<br/>" + cookie.getPath() );
                        break;
                    }
                }
            }
        }
        
        
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

java for 的几种用法 复习

5.2 Session

5.2.1Session概述

cookie是一种在客户端记录用户信息的技术,因为http协议是无状态的,为了解决这个问题而产生了cookie。记录用户名等一些应用数据。session是一种在服务端记录用户信息的技术,一般session用来在服务器端共享数据,

cookie的工作原理?session的工作原理?

cookie工作原理,cookie是由服务器端创建发送回浏览器端的,并且每次请求服务器都会将cookie带过去,以便服务器知道该用户是哪一个。其cookie中是使用键值对来存储信息的,并且一个cookie只能存储一个键值对。所以在获取cookie时,是会获取到所有的cookie,然后从其中遍历。

session的工作原理就是依靠cookie来做支撑,第一次使用request.getSession()时session被创建,并且会为该session创建一个独一无二的sessionid存放到cookie中,然后发送会浏览器端,浏览器端每次请求时,都会带着这个sessionid,服务器就会认识该sessionid,知道了sessionid就找得到哪个session。以此来达到共享数据的目的。 这里需要注意的是,session不会随着浏览器的关闭而死亡,而是等待超时时间。

由于关闭浏览器不会导致session被删除,迫使服务器为seesion设置了一个失效时间,一般是30分钟,当距离客户端上一次使用session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。

5.2.2 购物车+用户登录

Cake的类

package chapter05;

public class Cake {
    private String id;
    private String name;
    public Cake() {
    }
    public Cake(String id, String name) {
        this.id = id;
        this.name = name;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

}

CakeDB的类,该类用于模拟保存所有蛋糕的数据库

package chapter05;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

public class CakeDB {
	private static Map<String, Cake> cakes = new LinkedHashMap<String, Cake>();
    static {
    	cakes.put("1", new Cake("1", "A类蛋糕"));// key 和 cake id 都为1 是为了后期方便操作  获取name
    	cakes.put("2", new Cake("2", "B类蛋糕"));
    	cakes.put("3", new Cake("3", "C类蛋糕"));
    	cakes.put("4", new Cake("4", "D类蛋糕"));
    	cakes.put("5", new Cake("5", "E类蛋糕"));
    }
    // 获得所有的蛋糕
    public static Collection<Cake> getAll() {
        return cakes.values();
    }
    // 根据指定的id获蛋糕
    public static Cake getCake(String id) {
        return cakes.get(id);
    }

}

ListCakeServlet的Servlet类,该Servlet用于显示所有可购买蛋糕的列表,通过单击“购买”链接,便可将指定的蛋糕添加到购物车中

package chapter05;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ListCakeServlet
 */
@WebServlet("/ListCakeServlet")
public class ListCakeServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ListCakeServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//response.getWriter().append("Served at: ").append(request.getContextPath());
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=utf-8");


        PrintWriter out = response.getWriter();
        Collection<Cake> cakes = CakeDB.getAll();
        out.write("本站提供的蛋糕有:<br>");
        for (Cake cake : cakes) {
            String url = "/firstweb/PurchaseServlet?id=" + cake.getId();
            out.write(cake.getName() + "<a href='" + url + "'>点击购买</a><br>");
        }
        
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

PurchaseServlet的Servlet类,该类实现了两个功能,一个是将用户购买的蛋糕信息保存到Session对象中,一个是在用户购买蛋糕结束后,将页面重定向到用户已经购买的蛋糕列表

package chapter05;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

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 javax.servlet.http.HttpSession;

/**
 * Servlet implementation class PurchaseServlet
 */
@WebServlet("/PurchaseServlet")
public class PurchaseServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public PurchaseServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//response.getWriter().append("Served at: ").append(request.getContextPath());
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=utf-8");
		
		// 获得用户购买的商品
        String id = request.getParameter("id");
        if (id == null) {
            // 如果id为null,重定向到ListBookServlet页面
            String url = "/firstweb/ListBookServlet";
            response.sendRedirect(url);
            return;
        }
        Cake myCake = CakeDB.getCake(id);
        // 创建或者获得用户的Session对象
        HttpSession session = request.getSession();
        // 从Session对象中获得用户的购物车
        
		@SuppressWarnings("unchecked")
		List<Cake> cart = (List<Cake>) session.getAttribute("cart");
        if (cart == null) {
            // 首次购买,为用户创建一个购物车(List集合模拟购物车)
            cart = new ArrayList<Cake>();
            // 将购物城存入Session对象
            session.setAttribute("cart", cart);
        }
        // 将商品放入购物车
        cart.add(myCake);
        // 创建Cookie存放Session的标识号
        Cookie cookie = new Cookie("JSESSIONID", session.getId());
        cookie.setMaxAge(60 * 30);
        cookie.setPath("/firstweb");
        response.addCookie(cookie);
        // 重定向到购物车页面
        String url = "/firstweb/CartServlet";
        response.sendRedirect(url);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

CartServlet的Servlet类,该类主要用于展示用户已经购买的蛋糕列表

package chapter05;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

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;

/**
 * Servlet implementation class CartServlet
 */
@WebServlet("/CartServlet")
public class CartServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public CartServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	@SuppressWarnings("unchecked")
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//response.getWriter().append("Served at: ").append(request.getContextPath());
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=utf-8");
		
		PrintWriter out = response.getWriter();
        // 变量cart引用用户的购物车
        List<Cake> cart = null;
        // 变量pruFlag标记用户是否买过商品
        boolean purFlag = true;
        // 获得用户的session
        HttpSession session = request.getSession(false);  //false 不会创建新的session,如果有则获取,否则返回null
        // 如果session为null,purFlag置为false
        if (session == null) {
            purFlag = false;
        } else {
            // 获得用户购物车
            cart = (List<Cake>) session.getAttribute("cart");
            // 如果用的购物车为null,purFlag置为false
            if (cart == null) {
                purFlag = false;
            }
        }
        /*
         * 如果purFlag为false,表明用户没有购买蛋糕  重定向到ListServlet页面
         */
        if (!purFlag) {
            out.write("对不起!您还没有购买任何商品!<br>");
        } else {
            // 否则显示用户购买蛋糕的信息
            out.write("您购买的蛋糕有:<br>");
            double price = 0;
            for (Cake cake : cart) {
                out.write(cake.getName() + "<br>");
            }
        }
    }

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

同时和用户登录模块结合起来:

User的类

package chapter05;

public class User {
    private String username;
    private String password;
    private String sessionid;
    
    
    public User() {
	}

	public User(String username, String password, String sessionid) {
		this.username = username;
		this.password = password;
		this.sessionid = sessionid;
	}
    
	public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
	public String getSessionid() {
		return sessionid;
	}
	public void setSessionid(String sessionid) {
		this.sessionid = sessionid;
	}
    

}

IndexServlet类,该类用于显示网站的首界面

此类中 增加显示用户购物信息的代码

package chapter05;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

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 javax.servlet.http.HttpSession;

/**
 * Servlet implementation class IndexServlet
 */
@WebServlet("/IndexServlet")
public class IndexServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public IndexServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//response.getWriter().append("Served at: ").append(request.getContextPath());
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=utf-8");
		
		
		
		// 创建或者获取保存用户信息的Session对象
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        if (user == null) {
            response.getWriter().print(
                    "您还没有登录,请<a href='http://localhost:8080/firstweb/login.html'>登录</a>");
        } else {
            response.getWriter().println("您已登录,欢迎你," + user.getUsername() + "!<br/>");
            response.getWriter().println(
                    "<a href='/firstweb/ListCakeServlet'>购买蛋糕</a><br/>");
            response.getWriter().println(
                    "<a href='/firstweb/LogoutServlet'>退出</a><br/>");
            
            response.getWriter().println("///<br/>");
            // 变量cart引用用户的购物车
            List<Cake> cart = null;
            // 变量pruFlag标记用户是否买过商品
            boolean purFlag = true;
            // 获得用户的session
            session = request.getSession(false);  //false 不会创建新的session,如果有则获取,否则返回null
            // 如果session为null,purFlag置为false
            if (session == null) {
                purFlag = false;
            } else {
                // 获得用户购物车
                cart = (List<Cake>) session.getAttribute("cart");
                // 如果用的购物车为null,purFlag置为false
                if (cart == null) {
                    purFlag = false;
                }
            }
            /*
             * 如果purFlag为false,表明用户没有购买蛋糕  重定向到ListServlet页面
             */
            if (!purFlag) {
                //out.write("对不起!您还没有购买任何商品!<br>");
            } else {
                // 否则显示用户购买蛋糕的信息
            	response.getWriter().write("您购买的蛋糕有:<br>");
                double price = 0;
                for (Cake cake : cart) {
                	response.getWriter().write(cake.getName() + "<br>");
                }
            }
            
            // 创建Cookie存放Session的标识号
            Cookie cookie = new Cookie("JSESSIONID", session.getId());
            cookie.setMaxAge(60 * 30);
            cookie.setPath("/chapter05");
            response.addCookie(cookie);
        }
        
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

CakeLoginServlet,该Servlet用于显示用户登录成功后的界面

package chapter05;

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;

/**
 * Servlet implementation class CakeLoginServlet
 */
@WebServlet("/CakeLoginServlet")
public class CakeLoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public CakeLoginServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//response.getWriter().append("Served at: ").append(request.getContextPath());
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=utf-8");
		
		String username = request.getParameter("username");
        String password = request.getParameter("password");
        PrintWriter pw = response.getWriter();
        //假设正确的用户名 是itcast 密码是123
        if (("itcast").equals(username) && ("123").equals(password)) {
            User user = new User();
            user.setUsername(username);
            user.setPassword(password);
            request.getSession().setAttribute("user", user);
            response.sendRedirect("/firstweb/IndexServlet");
        } else {
            pw.write("用户名或密码错误,登录失败");
        }
        
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

LogoutServlet  将Session对象中的User对象移除,实现用户注销

package chapter05;

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

/**
 * Servlet implementation class LogoutServlet
 */
@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public LogoutServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//response.getWriter().append("Served at: ").append(request.getContextPath());
		// 将Session对象中的User对象移除
        request.getSession().removeAttribute("user");
        response.sendRedirect("/firstweb/IndexServlet");
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

login.html 用户登录界面

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
<!-- 注意提交的 地址 否则容易出错 -->
<form action="http://localhost:8080/firstweb/CakeLoginServlet" method="get">
    用户名: <input type="text" name="username" /><br />
    密&nbsp;&nbsp;&nbsp;码:<input type="password" name="password"/><br />
    <input type="submit" value="登录" />
</form>
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值