Jsp与Servlet(三)之EL 与 JSTL

一、EL表达式基本语法

  1.EL 表达式语法非常简单,它以“${“开头,以”}"结束,中间为合法的表达式,具体的语法格式如下:

${expression}

  expression:用于指定要输出的内容,可以是字符串,也可以是由 EL 运算符组成的表达式。在 EL 表达式中要输出一个字符串,可以将此字符串放在一对单引号或双引号内。

  注意:由于 EL 表达式的语法以"KaTeX parse error: Expected '}', got 'EOF' at end of input: …如果在 JSP 网页中要显示"{" 字符串,必须 在前面加上\”符号,即"${“来输出”${" 符号。

  2.EL 的保留关键字

  在为变量命名时,应该避免使用这些关键字,包括使用 EL输出已经保存在作用城范围内的变量,也不能使用关键字,如果已经定义了,那么需要修改为其他 的变量名。

  gt eq or and div empty instanceof false ge le It not

  3.通过 EL 访问数据

通过 EL 提供的“[]”和“.”运算符可以访问数据。通常情况下,“[]“和“.”运算符是等价的,可以相互代替。

${user.id}
${user['.name']}

  但是也不是所有情况下都可以相互替代,例如,当对象的属性名中包括一些特殊的符号(-或.)时,就只能使用“[”运算符来访问对象的属性。例如,${userInfo[‘user-id’]} 是正确的,而 ${userIfo.user-name} 则是错误的。另外,EL 的“[”运算符还有一个用途,就是用来获取数组或者 List 集合中的数据,下面进行详细介绍。

  4.数组元素的获取

  应用“[”运算符可以获取数组的指定元素,但是“.”运算符则不能。

${arrBook[0]}

案例:

在 request 域中存入四本书,使用循环将编号和书名输出到页面上。

<%
    String[] arr = {"java", "ui", "大数据", "新媒体"};
  
%>
<%
    for (String s : arr) {
        request.setAttribute("b", s);
%>
<p>${b}</p>
<%
    }
%>

  在 EL 中,也可以进行算术运算,同 Java 语言一样,EL 提供了加、减、乘、除和求余 5 种算术运 算符。

+ - * /(div) %(mod)

  5.EL 判断非空

  在 EL 中,判断对象是否为空,可以通过 empty 运算符实现,该运算符是一个前缀(prefix) 运算符,即 empty 运算符位于操作数前方,用来确定一个对象或变量是否为 null 或空。另外,empty 运算符也可以与 not 运算符结合使用,用于判断一个对象或变量是否为非空。

${empty expression}
${not empty expression}

  6.EL 运算符

  在 EL 中,提供了 6 种关系运算符。这6种关系运算符不仅可以用来比较整数和浮点数,还可以用来比较字符串。关系运算符的使用格式如下:

==或eq       等于
!=或ne       不等于
<或lt        小于
>或gt        大于
<=或le       小于等于
>=或ge       大于等于

  在进行比较运算时,如果涉及两个或两个以上的判断条件时,就需要应用逻辑运算符。逻辑运算符的条件表达式的值必须是 Boolean 型或是可以转换为Boolean 型的字符串,并且返回的结果也是 Boolean 型。

&&或and        与
||或or         或
!或not         非

  7.EL 字符串类型的变量拼接时,不能使用 +,需要使用 concat() 方法。

${"2"+"1"}                    得到结果为3
${"hello"+" world!"}          报错 java.lang.NumberFormatException: For input string: "hello"
${"hello".concat(" world")}   得到结果为hello world

二、EL 隐含对象

  在 EL 中提供了 4 个用于访问作用域范围的隐含对象,即 pageScope、requestScope、sessionScope 和 applicationScope。运用这 4 个隐含对象指定所要查找的标识符的作用域后,系统将不再按照默认的顺序 page、request、session 及 application 来查找相应的标识符。它们与 JSP 中的 page、request、session 及 application 内置对象类似。只不过这 4 个隐含对象只能用来取得 setAttribute 范围内的属性值,而不能取得其他相关信息。

<%
    pageContext.setAttribute("id", 8);
    session.setAttribute("id", 2);
    request.setAttribute("id", 1);
    application.setAttribute("id", 3);

%>
${sessionScope.id}

  为了能够获得 Web 应用程序中的相关数据,EL 提供了多个隐含对象,这些对象类似于 JSP 的内置对象,也是直接通过对象名进行操作。在 EL 的隐含对象中,除 pageContext 是 JavaBean 对象,其他的隐含对象都对应于 java.util.Map 类型。

  pageContext 可以访问 JSP 内置对象(如 request、response、out、session、exception 和 page 等。在获取到这些内置对象后,就可以获取其属性值。这些属性与对象的 getXXX() 方法相对应,在使用时,去掉方法名中的 get,并将首字母改为小写即可。

  1.访问 request 对象

  通过pageContext获取JSP内置对象中的request对象,可以使用下面的语句:

${pageContext.request}

  获取到 request 对象后,就可以通过该对象获取与客户端相关的信息。例如,HTTP 报头信息、客户信息提交方式、客户端主机 IP 地址和端口号等。

${pageContext.request.severPort}

  2.访问 response 对象

  通过 pageContext 获取JSP内置对象中的 response 对象,可以使用下面的语句:

${pageContext.response}

  获取到 response 对象后,就可以通过该对象获取与响应相关的信息。 ${pageContext.response.contentType}这句代码将返回响应的内容类型。

  3.访问 out 对象

  通过 pageContext 获取 JSP 内置对象中的 out 对象,可以使用下面的语句:

${pageContext.out}

  获取到 out 对象后,就可以通过该对象获取与输出相关的信息。  ${pageContext.out.bufferSize } 这句代码将返回输出缓冲区的大小。

  4.访问 session 对象

  通过 pageContext 获取JSP内置对象中的 session 对象,可以使用下面的语句:

${pageContext.session}

  获取到 session 对象后,就可以通过该对象获取与session相关的信息。 ${pageContext.session.maxlnactiveInterval} 这句代码将返回 session 的有效时间。

  5.访问 exception 对象

  通过 pageContext 获取JSP内置对象中的 exception 对象,可以使用下面的语句:

$(pageContext.exception}

  获取到 exception 对象后,就可以通过该对象获取 JSP 页面的异常信息。 ${pageContext.excepion.message}

  6.访问 page 对象

  通过 pageContext 获取 JSP 内置对象中的 page 对象,可以使用下面的语句:

${pageContext.page}

  获取到 page 对象后,就可以通过该对象获取当前页面的类文件。${pageContext.page.class} 这句代码将返回当前页面的类文件。

  7.访问 servletContext 对象

  通过 pageContext 获取 JSP 内置对象中的 servletContext 对象,可以使用下面的语句: ${pageContext.servletContext}

  获取到 servletContext 对象后,就可以通过该对象获取 servlet 上下文信息。 ${pageContex.request.contextPath} 这句代码将返回当前页面的上下文路径。

  8.param 可以获取请求里面的参数。如:${param.id} 可以获取请求 XXX?id=12 的这种参数。

三、相对路径与绝对路径

  绝对路径:绝对路径就是你的主页上的文件或目录在硬盘上真正的路径,(URL和物理路径)

  例如: C://xyz/test.txt 代表了 test.txt 文件的绝对路径。http://www.sun.com/index.html 也代表了一个 URL 的绝对路径。

  相对路径:相对与某个基准目录的路径。包含 Web 的相对路径(HTML 中的相对目录),例如:在 Servlet 中,"/"代表 Web 应用的跟目录。和物理路径的相对表示。

  例如:"./" 代表当前目录,"…/"代表上级目录。这种类似的表示,也是属于相对路径。

  注意 JSP/Servlet 中的相对路径分为服务端和客户端路径。

1.服务器端的地址

  服务器端的相对地址指的是相对于 web 应用的地址,这个地址是在服务器端解析的(不同于 html 和 javascript 中的相对地址,他们是由客户端浏览器解析的)也就是说这时候在 jsp 和 servlet 中的相对地址应该是相对于 web 应用,即相对于 http: //192.168.0.1/webapp/ 的。

  其用到的地方有:

  转发:servlet 中的 request.getRequestDispatcher(address);这个 address 是在服务器端解析的,所以,要转发到 jsp/a.jsp 应该这么写:request.getRequestDispatcher(“/jsp/a.jsp”) 前面 / 相对于当前的 web 应用 webapp,其绝对地址就是:http://192.168.0.1/webapp/jsp/a.jsp。

  重定向:在 jsp 或 Servlet 中 response.sendRedirect("/上下文路径/jsp/a.jsp");

2.客户端的地址

  所有的 html 页面中的相对地址都是相对于服务器根目录(http://192.168.0.1/)的,而不是(跟目录下的该 Web 应用的目录)http://192.168.0.1/webapp/ 的。 Html 中的 form 表单的 action 属性的地址应该是相对于服务器根目录(http://192.168.0.1/)的,所以,如果提交到 a.jsp 为:action="/webapp/user/a.jsp"或 action=“上下文路径/user/a.jsp; 提交到 servlet 为 actiom=”/webapp/handleservlet" Javascript 也是在客户端解析的,所以其相对路径和 form 表单一样。 因此,一般情况下,在 JSP/HTML 页面等引用的 CSS,Javascript 等属性前面最好都加上上下文路径,以确保所引用的文件都属于 Web 应用中的目录。另外,应该尽量避免使用类似"."、"./"、"…/…/" 等类似的相对该文件位置的相对路径,这样当文件移动时,很容易出问题。

<img src="${pageContext.request.contextPath}/img/1.jpg">
<form action="${pageContext.request.contextPath}/login">
    <input type="submit" value="提交">
</form>

四、ajax 提交数据

  ajax 提交数据一般需要 jquery,而且页面不再使用 submit 类型的按钮,数据在点击按钮时便会使用 jquery 发送请求。发送的数据会找到对应的 Servlet 获得后台返回的数据,并且调用回调方法将数据放在 response 变量中。

<form>
    <input name="name" id="name">
    <input name="password" id="password">
    <p id="msg"></p>
    <input type="button" value="提交" onclick="sub()">
</form>
<script>
    function sub(){
        let name = $("#name").val();
        let password = $("#password").val();
        //回调
        $.post("login", {name, password}, function (response) {
            $("#msg").html(response)
        })
    }
</script>

LoginServlet

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("utf-8");
        String name = req.getParameter("name");
        String password = req.getParameter("password");
        System.out.println(name);
        System.out.println(password);
        resp.getWriter().write("登录成功");
    }
}

案例:全 HTML 的登录退出系统

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<h1>欢迎<span id="user"></span>登录!</h1>
<a href="logout">退出登录</a>
<script>
    $.post("userInfo", {}, function (response) {
        $("#user").html(response)
    })
</script>
</body>
</html>

login.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<form>
    <input name="name" id="name">
    <input name="password" id="password">
    <p id="msg"></p>
    <input type="button" value="提交" onclick="sub()">
</form>
<script>
    function sub() {
        let name = $("#name").val();
        let password = $("#password").val();
        //回调
        $.post("login", {name, password}, function (response) {
            if (response.trim() == '登录成功') {
                location.href = "index.html";
            } else {
                $("#msg").html(response)
            }
        })
    }
</script>
</body>
</html>

loginServlet

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("utf-8");
        String name = req.getParameter("name");
        String password = req.getParameter("password");
        if ("123".equals(password)) {
            req.getSession().setAttribute("userInfo", name);
            resp.getWriter().println("登录成功");
        } else {
            resp.getWriter().println("账号或密码错误");
        }
    }
}

LogoutServlet

@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getSession().invalidate();
        resp.sendRedirect("login.html");
    }
}

UserInfoServlet

@WebServlet("/userInfo")
public class UserInfoServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("utf-8");
        resp.getWriter().println(req.getSession().getAttribute("userInfo"));
    }
}

LoginFilter

@WebFilter("/*")
public class LoginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        if (request.getRequestURI().contains("login")) {
            filterChain.doFilter(request, response);
            return;
        }
        if (request.getSession().getAttribute("userInfo") != null) {
            filterChain.doFilter(request, response);
            return;
        }
        response.sendRedirect("login.html");
    }

    @Override
    public void destroy() {
    }
}

五、JSTL 常用标签库

  JSTL 全称为 JSP Standard [ˈstændəd] Tag Library [ˈlaɪbrəri]即 JSP 标准标签库。JSTL 作为最基本的标签库,提供了一系列的 JSP 标签,实现了基本的功能:集合的遍历、数据的输出、字符串的处理、数据的格式化等等。使用 JSTL 标签库步骤如下:

  1.导入 jstl-1.2.jar 开发包。

  2.在 JSP 页面中用 tablib 指令引入需要用到的 JSTL 标签。

  core 标签库

  core 标签库是 JSTL 的核心标签库,实现了最基本的功能:流程控制、迭代输出等操作。core 标签库的前缀一般是 c

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

c:out
在这里插入图片描述
案例:

<%
    request.setAttribute("name", "zhongfucheng");
%>

//<c:out/>标签支持标签体,default属性上的数据可以写在标签体中
//<c:out value="${name}" escapeXml="true">您要的数据找不着</c:out>

<c:out value="${name}" default="您要的数据找不着" escapeXml="true"/>

  我们发现上面的代码实现的效果和 EL 表达式是一样的,它出色的地方就多了两个属性 default 和 escapeXml [ɪˈskeɪp]属性。如果我们用到这两个属性,我们就使用该标签,如果没有用到这两个属性就用 EL 表达式就可以了。

c:if
在这里插入图片描述
  JSTL 提供了 if 标签完成分支语句的实现,test 属性是不可或缺的。 var 和 scope 属性我看来好像没什么用的(保存执行结果有什么用?)

案例:

<%--如果带过来的名字是zhongfucheng,那么可以登陆--%>
<c:if test="${param.name=='zhongfucheng'}">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登陆">
</c:if>

c:choose
  if 标签没有 else 的功能,如果需要类似于 java 中的 if else 流程就需要使用 choose 标签。 choose 标签需要联合 when 和 otherwise 标签一起使用!

  案例:

<c:choose>
    <c:when test="${param.name=='zhongfucheng'}">
        你好啊,zhongfucheng
    </c:when>
    <c:when test="${param.name=='ouzicheng'}">
        你好啊,ouzicheng
    </c:when>
    <c:otherwise>
        你是谁啊?别随便过来!
    </c:otherwise>
</c:choose>

c:forEach
在这里插入图片描述
forEach 为循环标签,相当于 Java 中的 while 和 for

案例:

<%
    List list = new ArrayList<>();
    list.add("zhongfucheng");
    list.add("ouzicheng");
    list.add("xiaoming");

    request.setAttribute("list", list);
%>

<c:forEach  var="list" items="${list}" >
    ${list}<br>
</c:forEach>

  遍历Map对象有稍微地不一样,我们来看一下,var 属性保存的不是每个迭代的对象,而是 Map.Entry。

<%
    Map map = new HashMap();
    map.put("1", "zhongfucheng");
    map.put("2", "xiaohong");
    map.put("3", "xiaoming");
    request.setAttribute("map",map);
%>

<c:forEach  var="me" items="${map}" >
    ${me.key}  ${me.value}<br>
</c:forEach>

begin 默认从 0 开始、end 默认为集合的最后一个元素、step 默认为 1

案例:

<c:forEach var="i" begin="1" end="10" step="1"> 
    <c:out value="${i}" /><br> 
</c:forEach>

varStatus 代表着当前对象被迭代的信息,它有以下的属性。
在这里插入图片描述
案例:

<c:forEach  var="list" items="${list}" varStatus="varStatus" >
    ${list}您的下标是:${varStatus.index}<br>
</c:forEach>

练习:
1.创建项目 demo8,使用安全 jsp 与 servlet 完成用户登录(登录时账号密码回填)。登录成功后才能上传图片的图片管理系统。上传图片的操作在 servlet 中操作即可,登录用户采用前面案例的数据库表。再增加一张 image 表里面的字段有:id、original_file_name(原始名字)、relative_paths(相对地址),create_time(上传时间),user_id (上传用户的id)。

2.用户搜索分页练习:创建项目 user-test,准备如下测试数据 100 条,使用注解 Servlet 与 jsp 结合的方式完成单表的分页和搜索,搜索时要保证也能分页,每页默认显示 15 条数据。暂时不用完成添加、修改和删除,大致效果如下:

步骤如下:

一、根据页面设计数据表并编写实体。

二、根据图中显示编写 dao 层业务逻辑(1.分页查询集合。2.根据名字的模糊匹配分页查询集合。3.查询全部数量。4.根据名字模糊查询数量)。

三、根据设计图编写 service 层代码,同时封装分页对象返回 Servlet 层,方便 Servlet 与 jsp 配合渲染页面。

四、jsp 与 Servlet 相互配合完成分页及条件查询。
在这里插入图片描述
3.阅读项目:智原用户系统(zy-user-system)。参照码云上的项目,完成相应的操作。码云地址

第一步:下载对应数据库脚本分析数据结构。

第二步:下载项目源码并,测试相关的数据方法 dao 层是否可用,及其作用。

第三步:查看相应的 jsp 页面所用到的 jstl 和 el 的语法。

第四步:根据浏览器的请求路径查看对应 servlet 中所做的事。

第五步:参照该项目的写法完成一个简单的员工管理业务,员工 employee(id 自增主键,name 姓名,age 年龄,dept 部门,create_time 创建时间,update_time 修改时间,add_user 添加的用户名,update_user 最后修改用户的用户名)。

六、JSTL 扩展标签库(自)

c:forTokens
  该标签类似于 String 类的 split() 和 for 循环的一种集合 它与 forEach 标签非常相似,都有 begin、end、step、items、var、varStatus 属性,不同的是forTokens 标签的 items 属性里面是字符串,这个字符串会被 delims 属性的内容分割成多个字符串!

案例:

<c:forTokens items="zhongfucheng,ouzicheng,xiaoming,xiaohong" var="name" delims="," >
    ${name}
</c:forTokens>

c:set
在这里插入图片描述
  该标签有5个属性,用起来有稍微有些复杂了!现在要记住的就是:var属性操作的是Integer、Double、Float、String等类型的数据,target属性操作的是JavaBean或Map对象的数据,scope代表的是Web域,value是值,property是对象的属性!

  使用 var 属性

  既然var属性只能操作Integer、Double、String等类型,那么存在var属性就一定没有property属性(property代表的是对象的成员属性,Integer、String这些类型哪来的成员变量呀)

  下面的案例是这样的:创建了一个name的变量,设置的值为zhongfucheng,范围是page

<c:set var="name" value="fucheng" scope="page"/>
${name}

当然了,set标签也支持标签体,value的值可以写在标签体里边

<c:set var="name" scope="page">
    zhongfucheng
</c:set>

使用 var 属性和 scope 属性实现计数器

<%--由于下面变量需要做加法运算,所以要定义出来,不然服务器是不知道我的变量是Integer类型的--%>
<%
    Integer sessionCount = 0;
    Integer applicationCount = 0;
%>
<c:set var="sessionCount" value="${sessionCount+1}" scope="session"/>

<c:set var="applicationCount" value="${applicationCount+1}" scope="application"/>

  使用 target 属性与之配对的是 property 属性,target 属性只能操作 JavaBean 或 Map 对象,property 就是对应的成员变量或 key 了。。

  既然 target 属性操作的是 JavaBean或Map对象,那么一定是通过EL表达式来获取到对象了。taget属性如果获取不到数据会抛出异常!使用target属性就一定没有scope属性(scope属性代表的是保存范围,target的值都是获取来的,难道你还能改变人家的范围?)

<%--创建出JavaBean对象,设置为session范围的属性--%>
<jsp:useBean id="person" scope="session"/>

<%--获取到person对象,设置age属性的值为32--%>
<c:set target="${person}" property="age" value="32"/>

${person.age}

c:remove

  remove标签就相当简单了,只有 var 和 scope 属性,代表的是删除域范围的属性

案例:

<%--创建出JavaBean对象,设置为session范围的属性--%>
<jsp:useBean id="person" scope="session"/>

<%--获取到person对象,设置age属性的值为32--%>
<c:set target="${person}" property="age" value="32"/>

${person.age}
<br>

<%--删除session属性--%>
<c:remove var="person" scope="session"></c:remove>
${person.age==null?"存在session的person对象被删除了!":"我还在呢!"}

c:catch
  该标签主要用来处理程序中产生的异常。 catch标签也十分简单,只有一个var属性,var属性封装了异常的信息!

<%--创建出JavaBean对象,设置为session范围的属性--%>
<jsp:useBean id="person" scope="session"/>

<c:catch var="message">

    <%--target属性只能是EL表达式,现在我是字符串,获取不到对象,肯定会抛出异常的!--%>
    <c:set target="person" property="age" value="32"/>

</c:catch>

${message}

fmt 标签

jsp 页面需引入 fmt 标签:

<taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt">

使用如下代码将字符串型日期转换为日期型 。

<fmt:parseDate value="${personMaster.masterDate}" pattern="yyyy-MM-dd" var="masterDate"/>

使用如下代码对日期进行格式化。

<fmt:formatDate value="${masterDate}" pattern="yyyy-MM-dd" timeZone="GMT+08:00"/>

fn 标签

jsp 页面需引入 fn 标签:

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

使用如下代码将字符串按照逗号切割成数组并遍历 。

<c:set value="${ fn:split('a,b,c,d,', ',') }" var="arr"/>
<c:forEach items="${arr}" var="s">
    <p>${s}</p>
</c:forEach>

项目考核:(5天)

博客系统 blog-system

新闻系统 news-system

项目展示系统 project-display-system

内容管理系统 content-management-system

旅游景区管理系统 travel-system

1.挑选适当的前端页面模板,页面至少包含如下前后台需求,并将其汉化。根据模板设计数据库表(数据库设计文档,在设计时一般增加创建时间、最后修改时间、最后修改人编号、上下线、排序数字等)

2.使用面向对象开发思想完成项目开发,并使用如下的包结构 servlet(控制层),service(服务层),dao(数据库访问层),entity(模型),filter(过滤器层),util(工具类层)

3.挑选合适的后台管理页面模板,对所有的数据表进行增删改查,路径统一放在 /WEB-INF/jsp/admin/ 目录下,所有后台 Servlet 也加上父路径,如:/admin/index。

4.做好相应的权限控制,保证后台管理页面在未登录的情况下不能访问。

前台需求:

1.展示博客列表

2.展示博客详情

3.记录博客评论,注册,登录情况下可以评论

4.留言联系

管理需求:

1.系统大数据统计(博客总数量、上线数量、浏览量 top3、注册人数统计)

2.用户管理(删除,重置密码,锁定和启用)

3.博客管理(增加、删除、修改、上下线,评论管理)

4.留言管理(查看)

最后提交文件:

1.原项目模板

2.数据库设计文档(参考文档)

3.源代码和数据库脚本

4.可运行的项目及脚本

5.专业视频(介绍项目使用,从启动脚本开始演示)

6.专业 ppt

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

faramita_of_mine

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

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

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

打赏作者

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

抵扣说明:

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

余额充值