Servlet之JSP_03 JSTL/EL 表达式

[size=medium][b][color=brown]准备工作:在JSP 中启用 EL 表达式[/color] [/b][/size]

<%@ page isELIgnored="false"%>

[size=medium][b]一、什么是 JSTL/EL [/b][/size]
JSTL : jsp 标准标签库(Jsp Standard Tag Library)
EL: 表达式语言 (Expression Language)

JSTL/EL 提供了一些通用的核心功能,如:设置变量的 scope,判断,迭代等。
使JSP开发者提高了开发效率。


[size=medium][b]二、 JSTL 与 EL 的区别和联系 [/b][/size]
EL 表达式最初只用于 JSTL 标签(或其它自定义标签)的属性中。
在后来的 JSP 定义版本中,允许 EL 单独在 JSP 中使用,用于简单属性的输出。

例如: ${user.id} 可以把 user 对象的 id 属性写入到 jsp 中。但这并不表明 JSTL 就没有用处了,JSTL 可以提供:条件判断,循环输出,html 标签过滤,URLs,日期格、数字式化等功能。


[size=medium][b]三、什么对象可以在 EL 表达式中使用?[/b][/size]

问题:
在 jsp 页面中的 Java 代码块 <% %> 中定义的 java 对象,可以直接在 [color=olive]EL 表达式 [/color]中使用吗?

回答:
不可以。访问不到。

[color=olive]EL 表达式 [/color]只会调用这四个对象(page, request, session, application)的 getAtrribute(string) 方法,来获取表达式中的对象。
这就是所谓的 EL 内置 scope 对象 —— 它们分别对应四个 jsp 的内置对象。
如果 page 对象中没有,则会到 request 对象寻找。依次向更大 scope 的对象中寻找。

所以在 Java 代码块 <% %> 中新建类对象,需要使用上述 scope 对象的 setAttribute() 方法,将新建的对象绑定到 scope 对象中。才能被 [color=olive] EL 表达式 [/color] 引用到。


例子:

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page import="com.test.pojo.User" %>
<html>
<head>
<title>Hello World</title>
</head>
<body>

<%
/***********************************************
Pay Attention:
===============================================

When using EL or JSTL, the following

User user = new User();

will not work.

==============================================

*/
pageContext.setAttribute("user", new User());

//request.setAttribute("user", new User());

%>


<h4>Using EL</h4>
<p>${user.name }</p>
<p>${user.getName() }</p>

<h4>Using JSTL</h4>
<p><c:out value="${user.name}" /></p>
<p><c:out value="${user.getName()}" /></p>



<%
String hello = "Hello World!";
%>
<h4>Using JSP Expression</h4>
<p><%=hello%></p>

</body>
</html>


User.java

package com.test.pojo;
public class User {
private String name ="default";
public String getName(){
return "Welcome to JSTL!";
}
}



结果输出:[quote]
[b]Using EL[/b]
Welcome to JSTL!
Welcome to JSTL!

[b]Using JSTL[/b]
Welcome to JSTL!
Welcome to JSTL!

[b]Using JSP Expression[/b]
Hello World!
[/quote]


[b]生成的 JSP 源码:[/b]


/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/7.0.78
* Generated at: 2017-06-21 19:40:24 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import com.test.pojo.User;

public final class home_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {

private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();

private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fc_005fout_0026_005fvalue_005fnobody;

private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}

public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}

public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}

public void _jspInit() {
_005fjspx_005ftagPool_005fc_005fout_0026_005fvalue_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
}

public void _jspDestroy() {
_005fjspx_005ftagPool_005fc_005fout_0026_005fvalue_005fnobody.release();
}

public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {

final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;


try {
response.setContentType("text/html; charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;

out.write("\n");
out.write(" \n");
out.write(" \n");
out.write("<html> \n");
out.write("<head> \n");
out.write("\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
out.write("\t<title>Hello World</title> \n");
out.write("</head> \n");
out.write("<body> \n");
out.write(" \n");
out.write(" ");

/***********************************************
Pay Attention:
===============================================

When using EL or JSTL, the following

User user = new User();

will not work.

==============================================

*/
pageContext.setAttribute("user", new User());
pageContext.setAttribute("user2", new User());

//request.setAttribute("user", new User());


out.write(" \n");
out.write(" \n");
out.write(" \n");
out.write(" <h4>Using EL</h4> \n");
out.write(" <p>");
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${user.name }", java.lang.String.class, (javax.servlet.jsp.PageContext)_jspx_page_context, null, false));
out.write("</p> \n");
out.write(" <p>");
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${user.getName() }", java.lang.String.class, (javax.servlet.jsp.PageContext)_jspx_page_context, null, false));
out.write("</p> \n");
out.write(" \n");
out.write(" <h4>Using JSTL</h4> \n");
out.write(" <p>");
if (_jspx_meth_c_005fout_005f0(_jspx_page_context))
return;
out.write("</p> \n");
out.write(" <p>");
if (_jspx_meth_c_005fout_005f1(_jspx_page_context))
return;
out.write("</p> \n");
out.write(" \n");
out.write(" \n");
out.write(" \n");
out.write(" ");

String hello = "Hello World!";

out.write(" \n");
out.write(" <h4>Using JSP Expression</h4> \n");
out.write(" <p>");
out.print(hello);
out.write("</p> \n");
out.write(" \n");
out.write("</body> \n");
out.write("</html> ");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}

private boolean _jspx_meth_c_005fout_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// c:out
org.apache.taglibs.standard.tag.rt.core.OutTag _jspx_th_c_005fout_005f0 = (org.apache.taglibs.standard.tag.rt.core.OutTag) _005fjspx_005ftagPool_005fc_005fout_0026_005fvalue_005fnobody.get(org.apache.taglibs.standard.tag.rt.core.OutTag.class);
boolean _jspx_th_c_005fout_005f0_reused = false;
try {
_jspx_th_c_005fout_005f0.setPageContext(_jspx_page_context);
_jspx_th_c_005fout_005f0.setParent(null);
// /home.jsp(38,7) name = value type = null reqTime = true required = true fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_c_005fout_005f0.setValue((java.lang.Object) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${user2.name}", java.lang.Object.class, (javax.servlet.jsp.PageContext)_jspx_page_context, null, false));
int _jspx_eval_c_005fout_005f0 = _jspx_th_c_005fout_005f0.doStartTag();
if (_jspx_th_c_005fout_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fc_005fout_0026_005fvalue_005fnobody.reuse(_jspx_th_c_005fout_005f0);
_jspx_th_c_005fout_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_c_005fout_005f0, _jsp_getInstanceManager(), _jspx_th_c_005fout_005f0_reused);
}
return false;
}

private boolean _jspx_meth_c_005fout_005f1(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// c:out
org.apache.taglibs.standard.tag.rt.core.OutTag _jspx_th_c_005fout_005f1 = (org.apache.taglibs.standard.tag.rt.core.OutTag) _005fjspx_005ftagPool_005fc_005fout_0026_005fvalue_005fnobody.get(org.apache.taglibs.standard.tag.rt.core.OutTag.class);
boolean _jspx_th_c_005fout_005f1_reused = false;
try {
_jspx_th_c_005fout_005f1.setPageContext(_jspx_page_context);
_jspx_th_c_005fout_005f1.setParent(null);
// /home.jsp(39,7) name = value type = null reqTime = true required = true fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_c_005fout_005f1.setValue((java.lang.Object) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${user2.getName()}", java.lang.Object.class, (javax.servlet.jsp.PageContext)_jspx_page_context, null, false));
int _jspx_eval_c_005fout_005f1 = _jspx_th_c_005fout_005f1.doStartTag();
if (_jspx_th_c_005fout_005f1.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fc_005fout_0026_005fvalue_005fnobody.reuse(_jspx_th_c_005fout_005f1);
_jspx_th_c_005fout_005f1_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_c_005fout_005f1, _jsp_getInstanceManager(), _jspx_th_c_005fout_005f1_reused);
}
return false;
}
}




[quote]
[b]附: 在 EL 表达式中的变量可以依附的 scope 对象[/b]

只有定义在 scope 对象中的变量,才可以被其它的地方( EL)引用到。

[i][color=blue][b]page[/b][/color][/i]
变量被设置给 page 对象,则只能在本 jsp 内使用,不能在使用 <jsp:include> 调用该 jsp 的上级 jsp 中起作用。
- 使用 <jsp:useBean> 标签创建的变量默认都是 page scope 。
- 另外这些对象也都属于 page scope: out, response, pageContext, config, page, exception。

[i][color=blue][b]request[/b][/color][/i]
变量被设置给 request 对象,可以在本次访问所涉及到的的任何 jsp 页面中使用。
通常多个 jsp 页面共同为一次访问提供结果。

[i][color=blue][b]session[/b][/color][/i]
变量被设置给 session 对象,可以在本次会话中的任意 jsp 页面中访问。

[i][color=blue][b]application[/b][/color][/i]
变量被设置给 applicaation 对象,可以在整个应用的任意 jsp 页面中访问。


[color=purple]注:这种内置对象或上下文的用法在类库或模板设计方法中经常使用。比如, JSP有内置对象,JSTL也有内置对象(语法使用时的上下文环境),Struts 2 的标签也有内置对象及上下文环境(ValueStack)[/color]

[/quote]


[size=medium][b]四、 <c:set> 标签[/b][/size]

[quote]
[color=olive]
我们一直在关心在 scope 范围内怎样灵活设置变量。

除了在 JSP 页面的 Java 代码块 <% %> 中使用四个scope对象的 setAttribute() 方法外(当然,这是最常用和好用的方法),还可以使用: <c:set> 与 <jsp:useBean> 。

使用这两个标签时,都可以指定变量设置在那个 scope 对象中。也就是这两个标签都有一个名为 scope 的属性。
[/color]
[/quote]


[color=green][b]c:set 标签可以设置3种类型的变量到 scope 中(默认为 page Scope):[/b][/color]

[b]1、设置 纯文本字符 到 scope 中:[/b]

<c:set var="cName1" value="My Name"/>


[b]2、设置 本地变量 到 scope 中:[/b]

<c:set var="cName2" value="<%= name %>"/>


[b]3、设置 scope变量 到 scope 中:[/b]

<c:set var="cName3" value="${user.name}"/>



用法示例:

<%@ page isELIgnored="false"%>
<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %>
<%@ page contentType="text/html; charset=utf-8" language="java" %>
<%@ page import="com.eddy.pojo.User"%>
<html>
<body>


<%
String name = "Hello World!";

User user = new User("Admin");
pageContext.setAttribute("user",user);
%>

<c:set var="cName1" value="My Name"/>
<c:set var="cName2" value="<%= name %>"/>
<c:set var="cName3" value="${user.name}"/>

<c:out value="${cName1}"></c:out><br/>
<c:out value="${cName2}"></c:out><br/>
<c:out value="${cName3}"></c:out><br/>

<hr/>

name: <%= name %><br/>

cName2: <%= pageContext.getAttribute("cName2") %><br/>
cName3: <%= pageContext.getAttribute("cName3") %><br/>

</body>
</html>



输出:

My Name
Hello World!
Admin
——————————————
name: Hello World!
cName2: Hello World!
cName3: Admin



[color=green][b]<c:set> 的第二种用法:用于修改 JSP scope 中的对象的某个属性值[/b][/color]

<c:set target="${user}" property="name" value="John"/>

等价于:

user.setName("John");



[size=medium][b]<c:set> 用法示例:[/b][/size]

[b]1、未指定 scope 时,使用 pageContext 对象对 c:set 对变量进行获取。[/b]

<c:set var="streetName" value="${properties.street}" />
<c:set var="cityName" value="${properties.city}" />
<c:set var="stateName" value="${properties.state}" />
<c:set var="startPoint" value="${streetName}, ${cityName}, +${stateName}" />


// 使用 pageContext 对象,对 c:set 对变量进行获取
<% String encodedStartPoint = java.net.URLEncoder.encode(
(String)pageContext.getAttribute("startPoint"), "UTF-8");%>


[b]2、设置代码中的变量到 scope 中,从而在其它 c 标签中使用[/b]

<c:set var="language">
<%= langTemp %>
</c:set>
<c:choose>
<c:when test="${language=='en'}">
<body class="bodytag-en">
</c:when>
<c:otherwise>
<body>
</c:otherwise>
</c:choose>



[b]3、在指定的 scope 中创建一个变量[/b]

<c:set var="currency" value="${user.currency}" scope="session" />



[color=gray][b]注:[/b]
1、使用 <c:remove var="currency"/> 移除所有 scope 中名为 currency 的变量
2、注意在一个jsp中引用其他jsp时(<jsp:include>),使用<c:set />时变量的范围。
一般为当前jsp内起作用,也就是不指定scope时在当前页面中设置的变量,
在子页面中时访问不到的(scope 默认为 page)。
[/color]


[quote][color=olive]
The <c:set> tag sets the value of an EL variable or the property of an EL variable in any of the JSP scopes (page, request, session, or application). If the variable does not already exist, it is created.

The JSP EL variable or property can be set either from the attribute value:

<c:set var="foo" scope="session" value="..."/>
or from the body of the tag:

<c:set var="foo">
...
</c:set>

http://docs.oracle.com/javaee/5/tutorial/doc/bnakh.html
[/color][/quote]


[size=medium][b]五、 <jsp:useBean>标签[/b][/size]

如果变量已经存在 scope 中,可以使用 <c:set> 据此在 scope 中创建一些新的变量。
但是,如果变量根本就不存在呢?
<jsp:useBean>:用于设置或初始化一个 JavaBean 类。如果 bean 已经在指定的 scope 中存在,则不会去创建,否则会新建一个 JavaBean,然后将其设置到 scope 中。

例子:

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page import="com.test.pojo.User" %>
<html>
<head>
<title>Hello World</title>
</head>
<body>
<jsp:useBean id="user" class="com.test.pojo.User"/>

<h4>Using EL</h4>
<p>${user.name }</p>
<p>${user.getName() }</p>


<%
user = (User) pageContext.getAttribute("user");
user.setName("Hello, JSTL!");

%>
<h4>Using JSTL</h4>
<p><c:out value="${user.name}" /></p>
<p><c:out value="${user.getName()}" /></p>

</body>
</html>


User class

package com.test.pojo;
public class User {
private String name = "Welcome, JSTL!";

public String getName(){
return name;
}

public void setName(String name){
this.name = name == null ? "null" : name ;
}
}


结果输出:
[quote]
[b]Using EL[/b]
Welcome, JSTL!
Welcome, JSTL!

[b]Using JSTL[/b]
Hello, JSTL!
Hello, JSTL!
[/quote]


[b]c:set 与 jsp:useBean 的区别[/b]
[quote]
*Difference betweenn c:set and jsp:useBean*

See the basic difference between c:set and jsp:useBean is:

First
c:set is a JSTL tag
while jsp:useBean is a JSP action.

Second thing,
you can use jsp:useBean either to retrieve a bean or create a bean object.
While c:set is used to set the property of an already existing bean not to create a bean or get a bean. c:set works somewhat similar to jsp:setProperty action for java beans.

And third thing,
there is no scope attribute for c:set(when you are using it with target attribute) JSTL tag as it is there for jsp:useBean JSP action.
And if you provide the value of target attribute as an EL expression, searching is from most restrictive scope to least restrictive scope.
[/quote]


[size=medium][b]六、EL 表达式 与 JSTL 标签的不同之处[/b][/size]

[b]问题1:JSTL 与 EL(Expression Language)的区别和联系?[/b]
阅读完“怎样避免在jsp中写逻辑代码”后,我停止了在jsp中写java代码片段的行为。因此我开始阅读和学习 JSTL,结果发现 JSTL 和 EL 之间有联系。但是我并不清楚这种联系。

下面是代码:

<c:set var="test" value="JSTL Core Tags"></c:set>
<c:out value="${test}"></c:out>

我只知道 <c:set 是 JSTL 标签,而 ${test} 是 EL (表达式语言)。

我的困惑是:
1. JSTL 可以单独使用吗?是否必须配合 EL ?如果不是必须,如何解释上面代码?
2. 如何最简单的只使用 EL 表达式?

-----------------------------
Answer:

EL 表达式最初只用于 JSTL 标签(或其它自定义标签)的属性中。
在后来的 JSP 定义版本中,允许 EL 单独在 JSP 中使用,用于简单属性的输出。例如:
${user.id}
可以把 user 对象的 id 属性写入到 jsp 中。但这并不表明 JSTL 就没有用处了,JSTL 可以提供:条件判断,循环输出,html 标签过滤,URLs,日期格、数字式化等功能。


[b]问题2:Are session and sessionScope the same in JSP EL?[/b]


public class LoginAction extends ActionSupport {
private String username;
private String password;

@Override
public String execute() throws Exception {
ActionContext ctx = ActionContext.getContext();
Integer counter = (Integer)ctx.getApplication().get("counter");
// put counter into application
ctx.getApplication().put("counter", counter);
// put username into session
ctx.getSession().put("user", username);
if (getUsername().equals("crazyit.org")
&& getPassword().equals("leegang")) {
ctx.put("tip", "Login Success! ");
return SUCCESS;
}
else {
ctx.put("tip", "Login Falied!");
return ERROR;
}
}
}


I put "counter" in application "user" in session and "tip" in ActionContext. In JSP I can use ${session.user} and ${sessionScope.user} to reference the "user" property. ${request.tip} and ${requestScope.tip} to reference tip.

My questions:

Are session, request, application the same as sessionScope, requestScope, applicationScope in EL?
What's the relationship between ActionContext and request(requestScope)?
P.S.:

I test ${request == requestScope} which is true, this means they are the same?


[b]回答:[/b]


/*


<%--

http://stackoverflow.com/a/17592665/2893073

By default
page,
request,
session,
application

objects are available to JSP pages.
So you can access then using EL syntax.

Except the above objects,
And following table shows IMPLICIT objects available to EL.

Implicit object Description
1. pageScope Scoped variables from page scope
2. requestScope Scoped variables from request scope
3. sessionScope Scoped variables from session scope
4. applicationScope Scoped variables from application scope
5. param Request parameters as strings
6. paramValues Request parameters as collections of strings
7. header HTTP request headers as strings
8. headerValues HTTP request headers as collections of strings
9. initParam Context-initialization parameters
10. cookie Cookie values
11. pageContext The JSP PageContext object for the current page

So session and sessionScope are same but differs in context they are used.
More specifically session is object and sessionScope is map (key, value) of Attribute
and its value.

If you say ${session.sessionAttr} it refers to session object available to JSP page.
If you say ${sessionScope.sessionAttr} it refers to IMPLICIT session object available to EL.
if you just say {attrName} it will search attrName in all scope,
from page to application scope.

--------------

EL duplicates those objects for self style usage.
But it may cause confusion to jsp beginners.

--%>


*/



引用:
Scope of JSP Objects
- http://javapapers.com/jsp/explain-the-scope-of-jsp-objects/

JSTL Core: <c:set> Tag
- http://www.tutorialspoint.com/jsp/jstl_core_set_tag.htm

c:set Examples
- http://javarevisited.blogspot.com/2012/02/jstl-tag-examples-in-jsp-java-j2ee.html

jsp:useBean Action Tag
- http://www.javatpoint.com/jsp-useBean-action

Exact difference and relation between JSTL and expression-language
- http://stackoverflow.com/questions/15848251/


-
转载请注明
原文出处:http://lixh1986.iteye.com/blog/2324611


-
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值