某马旅游网站开发(登录注册退出功能的实现)

前言:此项目篇是对基础知识的复习与巩固,不涉及后端框架的知识,仅使用maven项目管理工具

技术选型

  • 网络层
  • servlet:前端控制器
  • html:视图
  • filter:过滤器
  • beanUtils:数据封装
  • jackson:json序列化工具
  • 服务层
  • javamail:java发送邮件工具
  • redis:nosql内存数据库
  • jedis:java的redis客户端
  • dao层
  • mysql:数据库
  • druid:数据库连接池
  • jdbcTemplate:jdbc工具

目录

0.注册功能实现

0.0准备

0.0.0用户实体类创建

0.0.1用户表的创建

0.0.2注册前端页面效果

 0.0.3前端注册界面代码(js部分)

0.1.0注册逻辑分析

 0.2.0后端代码实现

0.2.1编写UserDao以及UserDaoimp

0.2.2编写UserService以及UserServiceImpl

0.2.3编写RegistUserServlet

0.2.4编写ActiveUserServlet

1.登录功能实现

1.0分析

1.0.0页面效果

 1.1代码实现

1.1.0dao层

1.1.1server层

1.1.2web层

1.1.3前端代码

2.退出功能实现

2.0准备

2.0.0页面效果

2.1前端代码实现 

2.1.0修改header.html

2.2后端代码实现

2.2.0exitServlet


0.注册功能实现


0.0准备

各级文件创建如下

0.0.0用户实体类创建

package com.sixstar.travel.domain;

import java.io.Serializable;

/**
 * 用户实体类
 */
public class User implements Serializable {
    private int uid;//用户id
    private String username;//用户名,账号
    private String password;//密码
    private String name;//真实姓名
    private String birthday;//出生日期
    private String sex;//男或女
    private String telephone;//手机号
    private String email;//邮箱
    private String status;//激活状态,Y代表激活,N代表未激活
    private String code;//激活码(要求唯一)

    /**
     * 无参构造方法
     */
    public User() {
    }

    /**
     * 有参构方法
     * @param uid
     * @param username
     * @param password
     * @param name
     * @param birthday
     * @param sex
     * @param telephone
     * @param email
     * @param status
     * @param code
     */
    public User(int uid, String username, String password, String name, String birthday, String sex, String telephone, String email, String status, String code) {
        this.uid = uid;
        this.username = username;
        this.password = password;
        this.name = name;
        this.birthday = birthday;
        this.sex = sex;
        this.telephone = telephone;
        this.email = email;
        this.status = status;
        this.code = code;
    }

    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    .............................
    public void setCode(String code) {
        this.code = code;
    }
}

0.0.1用户表的创建

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `uid` int(0) UNSIGNED NOT NULL AUTO_INCREMENT,
  `username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `password` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `birthday` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `sex` varchar(2) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `telephone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `email` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `status` varchar(2) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  PRIMARY KEY (`uid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

0.0.2注册前端页面效果

 0.0.3前端注册界面代码(js部分)

/* 表单效验 :
			*	username:/^\w{8,20}/
			*	password:/^\w{8,20}/
			*	email:/^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/
			* */
			// 用户名效验
			function checkUsername(){
				var username = $("#username").val();
				var reg_username = /^\w{8,20}/;
				var flog = reg_username.test(username);
				if (flog){
					$("#username").css("border","")
				}else{
					$("#username").css("border","1px solid red")
				}
				return flog;
			}
			// 密码效验
			function checkPassword(){
				var password = $("#password").val();
				var reg_password = /^\w{8,20}/;
				var flog = reg_password.test(password);
				if (flog){
					$("#password").css("border","")
				}else{
					$("#password").css("border","1px solid red")
				}
				return flog;
			}
			// 邮箱效验
			function checkEmail(){
				var email = $("#email").val();
				var reg_email = /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
				var flog = reg_email.test(email);
				if (flog){
					$("#email").css("border","")
				}else{
					$("#email").css("border","1px solid red")
				}
				return flog;
			}
			// 表单校验函数
			function checkAll() {
				return checkUsername()&&checkPassword()&&checkEmail();
			}
			// 绑定离焦事件
			$("#username").blur(checkUsername());
			$("#password").blur(checkPassword());
            $("#email").blur(checkEmail());
			$(function () {
				$("#registerForm").submit(function () {
					if(checkAll()){
						// 表单项全部验证通过
						$.post("registUserServlet",$(this).serialize(),function (data) {
							if(data.flag){
								location.href="register_ok.html";
							}else {
								$("#errorMsg").html(data.errorMsg);
							}
						});

					}
					// 表单项验证失败,拦截提交请求
					return false;
				})
			})

0.1.0注册逻辑分析

 0.2.0后端代码实现

0.2.1编写UserDao以及UserDaoimp

UserDao

package com.haohao.travel.dao;

import com.haohao.travel.domain.User;

public interface UserDao {
    /**
     * 根据用户名查询用户信息
     * @param username
     * @return
     */

    User findByUsername(String username);

    /**
     * 保存用户信息
     * @param user
     */
    void save(User user);

    /**
     * 通过激活码查找用户
     * @param code
     * @return
     */
    User findByCode(String code);

    /**
     * 修改状态码
     * @param user
     */
    void updataStatus(User user);
}

UserDaoimp

package com.haohao.travel.dao.impl;

import com.haohao.travel.dao.UserDao;
import com.haohao.travel.domain.User;
import com.haohao.travel.util.JDBCUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
public class UserDaoImpl implements UserDao {
//    定义数据库模板,配合Bean对象用于把从数据库中查询出来的列转换为对象
    private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());

    /**
     * 通过用户名查找用户
     * @param username
     * @return
     */
    @Override
    public User findByUsername(String username) {
        User user = null;
        try{
//            定义sql
            String sql = "select * from user where username=?";
//            执行sql
            user = template.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),username);
        }catch (Exception e){

        }
        return user;
    }

    /**
     * 通过user对象保存至数据库中
     * @param user
     */
    @Override
    public void save(User user) {
        //1.定义sql
        String sql = "insert into user(username,password,name,birthday,sex,telephone,email,status,code) values(?,?,?,?,?,?,?,?,?)";
//        执行sql
        template.update(sql,user.getUsername(), user.getPassword(), user.getName(), user.getBirthday(), user.getSex(), user.getTelephone(), user.getEmail(), user.getStatus(), user.getCode() );
    }

    /**
     * 通过激活码查找用户信息
     * @param code
     * @return
     */
    @Override
    public User findByCode(String code) {
        User user = null;
        try{
//            定义sql
            String sql = "select * from user where code=?";
//            执行sql
            user = template.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),code);
        }catch (Exception e){

        }
        return user;
    }

    /**
     * 修改用户的激活状态
     * @param user
     */
    @Override
    public void updataStatus(User user) {
        String sql = " update user set status = 'Y' where uid=?";
        template.update(sql,user.getUid());
    }
}

0.2.2编写UserService以及UserServiceImpl

UserService

package com.haohao.travel.service;

import com.haohao.travel.domain.User;

public interface UserService {
    /**
     * 用户注册
     * @param user
     * @return
     */
    boolean regist(User user);

    /**
     * 用户激活
     * @param code
     * @return
     */
    boolean active(String code);
}

UserServiceImpl

package com.haohao.travel.service.impl;

import com.haohao.travel.dao.UserDao;
import com.haohao.travel.dao.impl.UserDaoImpl;
import com.haohao.travel.domain.User;
import com.haohao.travel.service.UserService;
import com.haohao.travel.util.MailUtils;
import com.haohao.travel.util.UuidUtil;

public class UserServiceImpl implements UserService {
//    用户dao对象
    private UserDao userDao = new UserDaoImpl();

    @Override
    public boolean regist(User user) {
        User u = userDao.findByUsername(user.getUsername());
        if (u!=null){
//            该用户名与已存在,注册失败
            return false;
        }
//        用户名不存在,保存用户到数据库
//        设置激活码与激活状态
        user.setCode(UuidUtil.getUuid());
        user.setStatus("N");
        userDao.save(user);
//        发送激活邮件
        String text = "<a href='http://localhost/travel/activeUserServlet?code="+user.getCode()+"'></a>";
        MailUtils.sendMail(user.getEmail(),text,"激活邮件");
        return true;
    }

    @Override
    public boolean active(String code) {
        User user = userDao.findByCode(code);
        if (user!=null){
//            修改这个用户的激活状态
            userDao.updataStatus(user);
            return true;
        }
        return false;
    }
}

0.2.3编写RegistUserServlet

package com.haohao.travel.web.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.haohao.travel.domain.ResultInfo;
import com.haohao.travel.domain.User;
import com.haohao.travel.service.UserService;
import com.haohao.travel.service.impl.UserServiceImpl;
import org.apache.commons.beanutils.BeanUtils;

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;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

@WebServlet("/registUserServlet")
public class RegistUserServlet extends HttpServlet {

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        图片验证码效验
        String check = req.getParameter("check");
        HttpSession session = req.getSession();
        String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
//        图片验证码用过一次即失效
        session.removeAttribute("CHECKCODE_SERVER");
        if (checkcode_server==null||!checkcode_server.equals(check)){
//            图片验证码校验失败
//            结果信息对象,存储需要返回给前端的数据
            ResultInfo info = new ResultInfo(false,"验证码错误");
//            将信息结果对象转换为json格式
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(info);
//            设置响应头为json格式
            resp.setContentType("application/json;charset=utf-8");
            resp.getWriter().write(json);
            return;
        }
//        图形验证码校验成功,获取请求中的user信息,封装为user对象
        Map<String,String[]> map = req.getParameterMap();
        User user = new User();
        try{
            BeanUtils.populate(user,map);
        } catch (InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }
//        调用UserService中的注册进行注册
        UserService userService = new UserServiceImpl();
        boolean flag = userService.regist(user);
        ResultInfo info = null;
        if (flag){
//            注册成功
            info = new ResultInfo(true);
        }else {
            info = new ResultInfo(false,"注册失败");
        }
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(info);
//            设置响应头为json格式
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().write(json);

    }


    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        this.doPost(req,resp);
        resp.setStatus(404);
        resp.getWriter().write("请求方式非法");
    }
}

0.2.4编写ActiveUserServlet

package com.haohao.travel.web.servlet;


import com.haohao.travel.service.UserService;
import com.haohao.travel.service.impl.UserServiceImpl;

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 ActiveUserServlet extends HttpServlet {

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        this.doGet(req,resp);
        resp.getWriter().write("非法访问");
    }


    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg ="激活失败,请检查激活码是否有效";
        String code = req.getParameter("code");
        if (code!=null){
            UserService userService = new UserServiceImpl();
            boolean flag = userService.active(code);
            if (flag){
//                激活成功
                msg = "激活成功,请<a href='login.html'>登录</a>!";
            }
        }
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write(msg);
    }
}

1.登录功能实现

1.0分析

1.0.0页面效果

 1.1代码实现

1.1.0dao层

userdao

/**
     * 
     * 根据用户名与密码查找用户
     * @param username
     * @param password
     * @return
     */
    
    User findByUsernameAndPassword(String username,String password);
UserDaoImpl
    /**
     * 通过用户名密码查找用户
     * @param username
     * @param password
     * @return
     */
    @Override
    public User findByUsernameAndPassword(String username, String password) {
        User user =null;
        try{
            //            定义sql
            String sql = "select * from tab_user where username=? and password=?";
//            执行sql
            user = template.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),username,password);
        }catch (Exception e){

        }
        return user;
    }

1.1.1server层

userServer

    /**
     * 用户登录
     * @param user
     * @return
     */

    User login(User user);

userServerImpl

    /**
     * 用户登录
     * @param user
     * @return
     */
    @Override
    public User login(User user) {
        return userDao.findByUsernameAndPassword(user.getUsername(),user.getPassword()); ;
    }

1.1.2web层

LoginUserServlet

package com.haohao.travel.web.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.haohao.travel.domain.ResultInfo;
import com.haohao.travel.domain.User;
import com.haohao.travel.service.UserService;
import com.haohao.travel.service.impl.UserServiceImpl;
import org.apache.commons.beanutils.BeanUtils;

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;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

@WebServlet("/loginServlet")
public class LoginUserServlet extends HttpServlet {

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //        图片验证码效验
        String check = req.getParameter("check");
        HttpSession session = req.getSession();
        String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
//        图片验证码用过一次即失效
        session.removeAttribute("CHECKCODE_SERVER");
        if (checkcode_server==null||!checkcode_server.equals(check)){
//            图片验证码校验失败
//            结果信息对象,存储需要返回给前端的数据
            ResultInfo info = new ResultInfo(false,"验证码错误");
//            将信息结果对象转换为json格式
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(info);
//            设置响应头为json格式
            resp.setContentType("application/json;charset=utf-8");
            resp.getWriter().write(json);
            return;
        }
//        图形验证码校验成功,获取请求中的user信息,封装为user对象
        Map<String,String[]> map = req.getParameterMap();
        User user = new User();
        try{
            BeanUtils.populate(user,map);
        } catch (InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }
//        调用UserService中的登录进行登录
        UserService userService = new UserServiceImpl();
//        登陆后的user对象,为null则登陆失败
        user = userService.login(user);
        ResultInfo info = new ResultInfo();
        if (user==null){
//            登陆失败
            info.setFlag(false);
            info.setErrorMsg("用户名或密码不正确");
        }else if(user.getStatus().equals("N")){
            // 用户未激活
            info.setFlag(false);
            info.setErrorMsg("请前往邮箱进行激活");
        }else {
//            成功登录,状态保持
            req.getSession().setAttribute("user",user);
            info.setFlag(true);
        }
//        响应json数据
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(info);
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().write(json);
    }


    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        this.doPost(req,resp);
        resp.getWriter().write("非法访问");
    }
}
findUserServlet
package com.haohao.travel.web.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.haohao.travel.domain.ResultInfo;
import com.haohao.travel.domain.User;

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 java.io.IOException;

@WebServlet("/findUserServlet")
public class FindUserServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        User user = null;
        try{
            user= (User) req.getSession().getAttribute("user");
        }catch (Exception e){

        }
        ResultInfo info=new ResultInfo();
        if(user!=null){
//            登陆过的
            info.setFlag(true);
            info.setData(user.getUsername());
        }else {
            info.setFlag(false);
        }
        ObjectMapper mapper=new ObjectMapper();
        String json = mapper.writeValueAsString(info);
//            设置响应头为json格式
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().write(json);
    }
}

1.1.3前端代码

登陆页面

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>黑马旅游网-登录</title>  
    <link rel="stylesheet" type="text/css" href="css/common.css">
    <link rel="stylesheet" type="text/css" href="css/login.css">
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
      <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
      <!--导入angularJS文件-->
    <script src="js/angular.min.js"></script>
	<!--导入jquery-->
	<script src="js/jquery-3.3.1.js"></script>
	<script>
		$(function () {
			$("#btn_sub").submit(function () {
				$.post("loginServlet",$("#loginForm").serialize(),function (data) {
					if (data.flag){
						// 登陆成功,跳转到首页
						location.href="index.html"
					}else {
						// 登陆失败
						$("#errorMsg").html(data.errorMsg);
						return false;
					}
				});
			});
		});

	</script>
</head>

<body>
<!--引入头部-->
<div id="header"></div>
    <!-- 头部 end -->
    <section id="login_wrap">
        <div class="fullscreen-bg" style="background: url(images/login_bg.png);height: 532px;">
        	
        </div>
        <div class="login-box">
        	<div class="title">
        		<img src="images/login_logo.png" alt="">
        		<span>欢迎登录黑马旅游账户</span>
        	</div>
        	<div class="login_inner">
				
				<!--登录错误提示消息-->
        		<div id="errorMsg" class="alert alert-danger" ></div>
				<form id="loginForm" action="" method="post" accept-charset="utf-8">
        			<input type="hidden" name="action" value="login"/>
					<input name="username" type="text" placeholder="请输入账号" autocomplete="off">
        			<input name="password" type="text" placeholder="请输入密码" autocomplete="off">
        			<div class="verify">
					<input name="check" type="text" placeholder="请输入验证码" autocomplete="off">
					<span><img src="checkCode" alt="" onclick="changeCheckCode(this)"></span>
					<script type="text/javascript">
						//图片点击事件
						function changeCheckCode(img) {
							img.src="checkCode?"+new Date().getTime();
						}
					</script>
			</div>
			<div class="submit_btn">
        				<button type="button" id="btn_sub">登录</button>
        				<div class="auto_login">
        					<input type="checkbox" name="" class="checkbox">
        					<span>自动登录</span>
        				</div>        				
        			</div>        			       		
        		</form>
        		<div class="reg">没有账户?<a href="javascript:;">立即注册</a></div>
        	</div>
        </div>
    </section>
    <!--引入尾部-->
    <div id="footer"></div>
    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="js/jquery-1.11.0.min.js"></script>
    <!-- Include all compiled plugins (below), or include individual files as needed -->
    <script src="js/bootstrap.min.js"></script>
    <!--导入布局js,共享header和footer-->
    <script type="text/javascript" src="js/include.js"></script>
</body>

</html>

首页昵称显示

<script>
    // 获取登陆用户名
    $(function () { $.get("findUserServlet",{},function (data) {
        //{uid:1,name:'李四'}
        if(data.flag){
            // 已登陆
            var msg = "欢迎回来,"+data.name;
            $("#span_username").html(msg);
            $(".login_out").hide()
            $(".login").show()
            
        }else {
            // 未登录
            $(".login").hide()
            $(".login_out").show()
        }

        });
    });
</script>

2.退出功能实现

2.0准备

2.0.0页面效果

点击退出之后删除登录信息,并跳转到登陆界面

2.1前端代码实现 

2.1.0修改header.html

<a href="javascript:location.href='exitServlet';">退出</a>

2.2后端代码实现

2.2.0exitServlet

package com.haohao.travel.web.servlet;

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 java.io.IOException;

@WebServlet("/exitServlet")
public class ExitUserServlet extends HttpServlet {

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        销毁登陆数据
        req.getSession().invalidate();
//        跳转登陆界面
        resp.sendRedirect(req.getContextPath()+"/login.html");
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豪豪喜欢吃猪肉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值