Java零基础教学文档servlet(3)

【AJax】

1.传统开发模式的不足

传统开发模式基于浏览器数据传输功能,页面填写数据/展示数据。浏览器通过访问一个URL地址,将页面的数据提交给服务器。服务器将需要展示的数据返回给浏览器,浏览器再进行数据解析,将数据呈现在用户面前。这种模式主要依赖于浏览器的渲染功能,并且浏览器每次渲染是都是整个页面进行渲染。整个页面包含:样式文件,图片资源,DOM标签.每次浏览器渲染时都要进行重新统一渲染,重新请求一些重复的资源数据.但是实际上变化的只是页面上的数据,一些静态资源没有发生变化.这种统一的重新渲染,导致以下不足:

  1. 操作服务器额外的负担,因为浏览器重新请求重复数据,服务器又不记录是否发送过,导致服务器重新发送,网络/磁盘读写都造成额外的负担.

  2. 浏览器重复解析数据,浏览器本身也产生了额外的开销.

程序的设计者,提出了一个理念,能不能只返回想要的数据?如果做到了根据需要返回数据,减少了服务器和浏览器的负担.提出了异步交互的理念.浏览器本身在渲染时,浏览器是占用状态,无法做其它事情的.异步交互,就是指浏览器在渲染时,将渲染的等待时间利用起来,做其它行为.就像同时在做多件事情.

1.1 什么是同步交互
首先用户向HTTP服务器提交一个处理请求。接着服务器端接收到请求后,按照预先编写好的程序中的业务逻辑进行处理,比如和数据库服务器进行数据信息交换。最后,服务器对请求进行响应,将结果返回给客户端,返回一个HTML在浏览器中显示,通常会有CSS样式丰富页面的显示效果。
在这里插入图片描述

如果浏览器在使用中,用户都是等待状态.用户全程的参与了整个请求到数据渲染的过程.类似早期排队充值话费/打饭.

1.2 同步交互的不足

  1. 同步交互的不足之处,会给用户一种不连贯的体验,当服务器处理请求时,用户只能等待状态,页面中的显示内容只能是空白。

  2. 因为已经跳转到新的页面,原本在页面上的信息无法保存,好多信息需要重新填写

  3. 这种交互的方式对于服务器和浏览器而言都存在压力.存在性能的损耗

2.异步交互的概念

指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待。例如:在支付宝上充值话费.
在这里插入图片描述

在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式。将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。异步不用等所有操作等做完,就响应用户请求。即先响应用户请求,然后慢慢去写数据库,用户体验较好.类似于多个线程在进行运行.

3.什么是AJax

Ajax是基于异步交互思想,诞生的复合的前端技术.其核心浏览器厂商约定的一套用于进行网络请求数据交互的API.浏览器厂商通过Javascript暴露了一套API,可以用于使用JS时就能通过网络从服务器获取特定的数据,然后在利用DOM技术和CSS技术,实现页面的数据变化.

由于AJax技术是浏览器厂商提供的API,浏览器厂商各自早期没有统一规范,还由于浏览器技术一直在迭代.前端技术一直在更新.市面上就出现了一些对原生ajax技术进行封装的插件.比较早期就是jQuery插件,现在比较流行的axios插件.由于现在前端推荐DOM操作,比较推崇MVVM思想,而jQuery中很大比重的都是在进行DOM操作,很多企业中,提出了去”j”的理念.

3.1 jQuery中的ajax
由于原生的Ajax存在一些不足,浏览器的兼容性,整个请求需要分为5个步骤相对繁琐.基于这样的原因.jQuery插件对原生ajax进行了封装.简化了ajax的使用.

在使用ajax时,开发者主要请求地址和请求参数及返回的数据.jQuery中的ajax在使用时,主要只需要定义请求地址,参数及返回数据的处理即可.

3.1.1 jQuery中ajax使用

  1. 在页面引入jQuery的JS

  2. 编写前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/jQuery-3.6.0.js"></script>
<style>
    p{
        color: red;
    }
</style>
</head>
<body>

<p id="msg"></p>
<button type="button" id="ajaxBtn">jQuery ajax简单案例</button>

<script>
    /* jQuery ajax 简单案例 */
    $("#ajaxBtn").click(function () {
        // 请求的url
        let url = "ajax.do";
        // 请求参数
        let param = {name:"韩梅梅",age:18};
        $.get(url,param,function (rs) {
            console.log("返回数据为:",rs);
            $("#msg").html(rs);
        })
    });
</script>
</body>
</html>

3.1.2 jQuery中核心方法
在这里插入图片描述

3.1.3 ajax方法核心配置参数
在这里插入图片描述

3.1.3.1 ajax方法的演示
3.1.3.1.1 前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/jQuery-3.6.0.js"></script>
<style>
    p{
        color: red;
    }
</style>
</head>
<body>

<p id="msg"></p>
<button type="button" id="ajaxBtn">jQuery ajax简单案例</button>
<button type="button" id="ajax">ajax方法演示</button>


<script>
    /* jQuery ajax 简单案例 */
    $("#ajaxBtn").click(function () {
        // 请求的url
        let url = "ajax.do";
        // 请求参数
        let param = {name:"韩梅梅",age:18};
        $.get(url,param,function (rs) {
            console.log("返回数据为:",rs);
            $("#msg").html(rs);
        })
    });

    /* 演示ajax 方法 */
    $("#ajax").click(function () {
        let m = 10;
        let settings = {
            url:"jquery.do",// 请求地址
            type:"post",// 请求方法
            timeout:1000,// 超时时间  1秒
            data:{ // 请求参数
                name:"韩梅梅",
                age:18
            },
            async:false,// 是否异步   如果是异步 则 ajax 函数没有执行完成就能执行之后的程序.如果非异步则必须等待ajax程序执行完成才能执行之后的程序
            // 如果ajax函数中的数据要参与之后程序的运算,必须设置非异步  false
            dataType:"json", // 期望返回的数据类型,一般浏览器会将返回的数据当做自己期望的类型,如果不是期望类型则程序会异常,通过火狐浏览器查看
            beforeSend:function () {
                console.log("我要请求了!!!!")
                //
                console.log("加载中....在转圈圈...")
            },
            success:function (data,req,xh) { // 请求成功时调用的方法
                console.log(data) // 返回的数据
                console.log(req) // 消息
                console.log(xh) // XMLHttpRequest 对象
                // 将数据放入到 p 标签
                $("#msg").html(data);
                // 改变 m的值
                m = m + 100;
            },
            complete:function () {
                // 标识请求完成调用的函数  不论成功还是失败都会调用
                console.log("取消转圈圈...")
            },
            error:function (xh,status) { // error 两种情况触发 :1. url地址错误  2.服务器内部程序异常
                console.log("xh:",xh)  // ajax 对象
                console.log("status:",status) // 错误信息
            }
        };
        $.ajax(settings);
        console.log("m的值:",m);
    });
</script>
</body>
</html>

3.1.3.1.2 后端代码

package com.powernode;

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

@WebServlet("/jquery.do")
public class JQueryAjaxServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   /*     try {
            // 线程休眠 5 秒
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }*/
        String name = req.getParameter("name");
        String age = req.getParameter("age");
        System.out.println(name +" " +age);
        PrintWriter writer = resp.getWriter();
        /* html   head  body   p   style */
        writer.print("{\"name\":\"Hello jQuery ajax\"}");
        writer.flush();
        writer.close();
    }
}

3.1.4 get/post方法演示

在实际使用中,开发者只关注2个点,请求信息和返回的数据.jQuery提供一些方法对ajax方法进行简化,如:get(url,[param],function)/post(url,[param],function).分别表示get类型的异步请求和post异步请求(比较常用).

3.1.4.1 演示案例

/**
 *  演示 get 方法
 */
$("#get").click(function () {
    $.get("jquery.do",{name:"韩梅梅",age:18},function (rs) {
        console.log(rs)
        $("#msg").html(rs);
    })
});
/**
 *  演示 post 方法
 */
$("#post").click(function () {
    $.post("jquery.do",{name:"韩梅梅",age:18},function (rs) {
        console.log(rs)
        $("#msg").html(rs);
    })
});

3.2 axios的使用

首先要在页面引入axios的js插件.参考:axios中文网.

3.2.1 axios应用
3.2.1.1 后端代码

package com.powernode;

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

@WebServlet("/axios.do")
public class AxiosServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
//        ServletInputStream inputStream = req.getInputStream();
//        byte[] b = new byte[1024];
//        int len = inputStream.read(b);
//        System.out.println(new String(b,0,len,"UTF-8"));
        String name = req.getParameter("name");
        String age = req.getParameter("age");
        // 将字符串转 对象
        System.out.println(name +" " +age);
        PrintWriter writer = resp.getWriter();
        /* html   head  body   p   style */
        writer.print("{\"name\":\"Hello axios ajax\"}");
        writer.flush();
        writer.close();
    }
}

3.2.1.2 前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="js/axios.js"></script>
</head>
<body>
<p id="msg"></p>
<button id="get">不带参数的get请求</button>
<button id="getParam">带参数的get请求</button>
<button id="post">post请求</button>
<script>
    /**
     *  演示 axios 的get 请求
     *   axios 默认就是  get 请求
     */
    document.getElementById("get").onclick = function () {
        axios.get("axios.do")
            // 请求完成时调用的函数
            .then(function (response) {
                // 整个响应数据对象
                console.log(response);
                // 默认的axios的配置信息
                console.log(response.config);
                // service 方法返回的具体的数据
                console.log(response.data);
                // 返回的响应头信息
                console.log(response.headers);
                // http 响应码
                console.log(response.status);
            }) // 请求发生异常时调用的函数
            .catch(function (error) {
            console.log(error);
        });
    }

    /**
     * 带参数的get 请求
     */
    document.getElementById("getParam").onclick = function () {
        axios.get("axios.do",{
            params:{
                name:"韩梅梅",
                age:18
            }
        })
            // 请求完成时调用的函数
            .then(function (response) {
                // 整个响应数据对象
                console.log(response);
                // 默认的axios的配置信息
                console.log(response.config);
                // service 方法返回的具体的数据
                console.log(response.data);
                // 返回的响应头信息
                console.log(response.headers);
                // http 响应码
                console.log(response.status);
            }) // 请求发生异常时调用的函数
            .catch(function (error) {
                console.log(error);
            });
    }

    /**
     *  post 请求
     */
    document.getElementById("post").onclick = function () {
        axios.post("axios.do",{
                name:"韩梅梅",
                age:18
            },{
            // 为 post 请求 兼容表单 URL参数编码问题
            transformRequest: [function (data, headers) {
                console.log(" 数据格式处理.....")
                console.log(data)
                // 对 data 进行任意转换处理
                // {name:"hanmeimei",age:18}   ---> name=韩梅梅&age=18
                let formData = new Array();
                // 循环对象
                for(name in data){
                   // item 对象中的属性  : name   age
                    // 根据动态的属性名 获取对应的值
                    let value = data[name];
                    console.log(name,"=",value)
                    formData.push(name+"="+value)
                }
                console.log(formData)
                formData = formData.join("&");
                console.log(formData)
                return formData;
            }],
            }
        )
            // 请求完成时调用的函数
            .then(function (response) {
                // 整个响应数据对象
                console.log(response);
                // 默认的axios的配置信息
               // console.log(response.config);
                // service 方法返回的具体的数据
                //console.log(response.data);
                // 返回的响应头信息
                //console.log(response.headers);
                // http 响应码
                //console.log(response.status);
            }) // 请求发生异常时调用的函数
            .catch(function (error) {
                console.log(error);
            });
    }

</script>

</body>
</html>

4.浏览器跨域访问

在Ajax请求中,JS是基于浏览器进行网络通信的.这种功能必须依附浏览器,出于安全的考虑,浏览器会对JS通信的数据进行检查.浏览器对数据检查通过之后,才会将通信数据移交给JS程序.浏览器最基本检查策略叫同源策略.是一种最基本安全保护机制

4.1 同源策略
在网络访问中,必须存在3种数据:协议/域名/端口.如果3种数据一致就标识同源访问,如果不一致就是非同源访问.默认浏览器只支持同源访问.

以下就是非同源访问的浏览器异常信息.也被称之为跨域访问.
在这里插入图片描述

当前浏览器访问地址:http://localhost:8080/ajax_crud/index.html

ajax的访问地址:http://127.0.0.1:8080/ajax_crud/user.do

由于当前浏览器地址的域名:localhost,但是ajax的地址是127.0.0.1虽然都是标识同一个地址,但是浏览器检测时认为和自己的不一致,所以进行抛出了异常,认为存在跨域访问.

4.2 跨域解决
跨域问题解决方案比较多,例如:jsonp,服务器允许跨域访问设置.浏览器既然会检查数据,服务器返回数据时,直接通知浏览器本次访问是允许跨域访问的.需要通过响应头通知浏览器.

// 允许跨域访问  * 任何访问源
resp.addHeader("Access-Control-Allow-Origin","*");

5.Ajax综合案例

利用ajax 实现增/删除/查/改.

5.1 后端代码
5.1.1 servlet

package com.powernode.servlet;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.powernode.dao.UserDao;
import com.powernode.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;
import java.io.PrintWriter;
import java.util.List;

/**
 *   在servlet中 默认只有service 能够提供服务
 *   那么出现 同类请求存在多个  例如 : 用户的请求  新增  删除  修改  查询 等等  难道创建多个 ?
 *   通过设计的方式解决问题:
 *      每个操作中,要求额外传递一个参数 标识是什么操作. 例如 : 如果是新增  则  传递 service = add
 *      删除 则传递  service = delete
 *      修改 则传递 service = update
 *      查询 则传递service = query
 *   在service 方法中 根据 service 参数的值  进行 分条件调用
 */
@WebServlet("/user.do")
public class UserServlet  extends HttpServlet {

    UserDao userDao = new UserDao();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        String service = req.getParameter("service");
        if (StrUtil.equals(service,"add")){
            // 处理 新增的方法
            add(req,resp);
        }else if (StrUtil.equals(service,"delete")){
            // 处理 新增的方法
            delete(req,resp);
        }else if (StrUtil.equals(service,"query")){
            // 处理 新增的方法
            query(req,resp);
        }else if (StrUtil.equals(service,"update")){
            // 处理 新增的方法
            update(req,resp);
        }
    }

    /**
     *  处理更新请求
     * @param req
     * @param resp
     */
    private void update(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String id = req.getParameter("id");
        String realname = req.getParameter("realname");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        userDao.update(Integer.parseInt(id),username,password,realname);
        // 使用UTF-8格式处理字节数据
        resp.setCharacterEncoding("UTF-8");
        PrintWriter writer = resp.getWriter();
        //输出数据
        writer.write("success");
        writer.flush();
        writer.close();
    }

    /**
     * 处理查询请求
     * @param req
     * @param resp
     */
    private void query(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 获取输入的姓名
        String realname = req.getParameter("realname");
        List<User> users = userDao.selectAll(realname);
        // 使用JSON格式输出
        // 表示返回json格式数据
        resp.setContentType("text/json;charset=utf-8");
        // 使用UTF-8格式处理字节数据
        resp.setCharacterEncoding("UTF-8");
        PrintWriter writer = resp.getWriter();
        // 将 List 转 JSON字符串
        String data = JSON.toJSONString(users);
        //输出数据
        writer.write(data);
        writer.flush();
        writer.close();
    }

    /**
     * 处理删除请求
     * @param req
     * @param resp
     */
    private void delete(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String id = req.getParameter("id");
        userDao.delete(Integer.parseInt(id));
        resp.setCharacterEncoding("UTF-8");
        PrintWriter writer = resp.getWriter();
        //输出数据
        writer.write("success");
        writer.flush();
        writer.close();

    }

    /**
     * 处理新增请求
     * @param req
     * @param resp
     */
    private void add(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String realname = req.getParameter("realname");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        userDao.add(username,password,realname);
        // 使用UTF-8格式处理字节数据
        resp.setCharacterEncoding("UTF-8");
        PrintWriter writer = resp.getWriter();
        //输出数据
        writer.write("success");
        writer.flush();
        writer.close();
    }
}

5.1.2 dao

package com.powernode.dao;

import cn.hutool.core.util.StrUtil;
import com.powernode.domain.User;

import java.util.List;

/**
 * 用户表操作类
 */
public class UserDao extends BaseDao {

    /**
     *  新增用户
     * @param username
     * @param password
     * @param realname
     */
    public void add(String username, String password,String realname) {
        String sql = "insert into user (username,password,realname) value(?,?,?)";
        super.executeUpdate(sql,username,password,realname);
    }

    /**
     * 删除用户
     * @param id
     */
    public void delete(Integer id) {
        String sql = "delete from user where id=?";
        super.executeUpdate(sql,id);
    }

    /**
     * 修改用户
     * @param id
     * @param username
     * @param password
     * @param realname
     */
    public void update(Integer id, String username, String password,String realname) {
        String sql = "update user set username = ?,password=? ,realname=? where id = ?";
        super.executeUpdate(sql,username,password,realname,id);
    }

    /**
     * 查询所有的用户
     * @param realname
     * @return
     */
    public List<User> selectAll(String realname) {
        // TODO 多个条件 该如何拼接  动态SQL
        String sql = "select id,username,password,realname from user";
        if (StrUtil.isNotBlank(realname)){
            sql = sql +"  where realname like '%"+realname+"%' ";
        }
        return super.executeQueryList(sql,User.class);
    }
}

5.2 列表页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户列表</title>
</head>
<body>
<p><input id="realname"/>
    <button id="searchBtn">查询</button>
</p>
<hr>
<a href="add.html">新增</a>
<hr>
<table id="dataTable">
    <tr>
        <td>ID</td>
        <td>登录名</td>
        <td>密码</td>
        <td>姓名</td>
        <td>操作</td>
    </tr>
</table>
<script src="js/jQuery-3.6.0.js"></script>
<script>
    // 全局性的存储 当前table 用户信息
    let globalUser ;
    /**
     * 渲染表格
     */
    function renderTable() {
        // 获取搜索的关键词
        let realname = $("#realname").val();
        $.get("user.do", {service: "query", realname: realname}, function (rs) {
            // 数组长度如果为 0 表示没有数据
            if (rs.length == 0) {
                // 结束程序
                return false;
            }
            globalUser = rs;
            // 获取表格dom 对象
            let table = $("#dataTable");
            // 清空表格
            // 获取所有 tr 但是 索引大于 0
            $("tr:gt(0)").remove();
            for (let user of rs) {
                let id = user.id;
                let username = user.username;
                let password = user.password;
                let realname = user.realname;
                tr ="<tr><td>"+id+"</td>"+"<td>"+username+"</td>"+"<td>"+password+"</td>"+"<td>"+realname+"</td><td><button οnclick='del("+id+")'>删除</button><button οnclick='update("+id+")'>修改</button></td></tr>"
                table.append(tr);
            }

        });
    }
    $("#searchBtn").click(function () {
        renderTable();
    });
    renderTable();

    /**
     *  删除方法
     * @param id
     */
    function del(id) {
        $.get("user.do",{service:"delete",id:id},function (rs) {
            if (rs == "success"){
                renderTable();
                return false;
            }
            alert("删除失败")
        })
    }

    function update(id) {
        // 循环所有的用户
        for (let user of globalUser) {
            // 如果id一直 说明 就是要修改的用户的
            if (user.id == id){
                // user 本身是 object
                // sessionStorage 存储的 字符串类型
                // JSON.stringify(user) 将对象转化为 json 字符串
                sessionStorage.setItem("user",JSON.stringify(user))
            }
        }
        // 跳转到更新页面
        location.href='update.html';
    }
</script>
</body>
</html>

 

**5.3 新增列表**

```c

```c
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form >
    <p>姓名:<input name="realname" id="realname" /></p>
    <p>用户名:<input name="username" id="username" /></p>
    <p>密码:<input name="password" id="password" /></p>
    <button type="button" id="subBtn">提交</button>
    <button type="button" id="back">返回</button>
</form>
<script src="js/jQuery-3.6.0.js"></script>
<script>
    $("#subBtn").click(function () {
        let realname = $("#realname").val();
        let username = $("#username").val();
        let password = $("#password").val();
        $.post("user.do",{service:"add",realname:realname,username:username,password:password},function (rs) {
            // 如果返回值 success 表示添加成功
            // 返回到 index页面
            if (rs == 'success'){
                location.href = "index.html";
                return false;
            }
            alert("添加失败!");
        })

    });
    $("#back").click(function () {
        location.href = "index.html";
    });
</script>
</body>
</html>

**5.4 修改页面**

```c
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form >
  <p>姓名:<input name="realname" id="realname" /></p>
  <p>用户名:<input name="username" id="username" /></p>
  <p>密码:<input name="password" id="password" /></p>
  <button type="button" id="subBtn">提交</button>
  <button type="button" id="back">返回</button>
</form>
<script src="js/jQuery-3.6.0.js"></script>
<script>
    let user ;
    //向表单填充数据
    function initForm() {
        user = sessionStorage.getItem("user");
        console.log(user)
        // 将字符串转对象
        user = JSON.parse(user);
        $("#realname").val(user.realname);
        $("#username").val(user.username);
        $("#password").val(user.password);
    }
    initForm();
    $("#subBtn").click(function () {
        let realname = $("#realname").val();
        let username = $("#username").val();
        let password = $("#password").val();
        $.post("user.do",{service:"update",id:user.id,realname:realname,username:username,password:password},function (rs) {
            // 如果返回值 success 表示添加成功
            // 返回到 index页面
            if (rs == 'success'){
                location.href = "index.html";
                return false;
            }
            alert("修改失败!");
        })
    });
    $("#back").click(function () {
        location.href = "index.html";
    });
</script>
</body>
</html>
  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值