Java第三阶段之Struts2国际化、验证框架、文件上传和下载、防重复提交

六Struts2 国际化

国际化简介

国际化(Internationlization),通俗地讲,就是让软件实现对多种语言的支持;

Struts2 国际化设置

<constantname=“struts.custom.i18n.resources"value=“java1234”>
<s:textname=”"></s:text> 访问国际化资源

新建项目HeadFirstStruts2Chap06
->struts.xml

<struts>
	
  <constant name="struts.custom.i18n.resources" value="java1234"></constant>
 
</struts>

->新建java1234.properties 这是用unicode编码

userName=\u7528\u6237\u540d
password=\u5bc6\u7801
login=\u767b\u5f55

->新建java1234_en_US.properties

userName=userName
password=password
login=login

->新建java1234_zh_CN.properties

userName=\u7528\u6237\u540d
password=\u5bc6\u7801
login=\u767b\u5f55

->新建login.jsp OGNL标签记得引入

<table>
	<tr>
		<td><s:text name="userName"></s:text></td>
		<td>
			<input type="text"/>
		</td>
	</tr>
	<tr>
		<td><s:text name="password"></s:text></td>
		<td>
			<input type="text"/>
		</td>
	</tr>
	<tr>
		<td>
			<input type="button" value="<s:text name='login'></s:text>"/>
		</td>
	</tr>
</table>

->启动项目http://localhost:8080/HeadFirstStrutsChap06/login.jsp
在英文环境下面显示英文 在中文环境下显示中文

在国际化页面里设参数

->新建java1234.properties 这是用unicode编码

userName=\u7528\u6237\u540d
password=\u5bc6\u7801
login=\u767b\u5f55
welcomeInfo=\u6b22\u8fce{0}

->新建java1234_en_US.properties

userName=userName
password=password
login=login
welcomeInfo=welcome{0}

->新建java1234_zh_CN.properties

userName=\u7528\u6237\u540d
password=\u5bc6\u7801
login=\u767b\u5f55
welcomeInfo=\u6b22\u8fce{0}

->新建welcome.jsp

<s:text name="welcomeInfo">
	<s:param>Jack</s:param>
</s:text>

->启动项目http://localhost:8080/HeadFirstStrutsChap06/welcom.jsp
在英文环境下面显示英文 在中文环境下显示中文

七Struts2 验证框架

Struts2 验证简介

Struts2 基于 Struts2 拦截器,为开发者提供了一套易用的验证框架,并可扩展;一般的验证都支持;
Struts2验证有手动验证和验证码验证,Struts推荐采用配置文件的方式进行数据校验
下面为步骤:
a.继承ActionSupport类
b.修改struts2.xml文件:删除method属性
c.在需要验证的Action类的相同包下,写一个"类名-validation.xml"文件
d.加入头信息以具有提示功能

注意两点:
1在这里插入图片描述
2在这里插入图片描述

Struts2 内置验证

1普通字段验证;
2验证表达式;
新建项目HeadFirstStruts2Chap07
新建model User.java

package com.java1234.model;

public class User {

	private String userName;
	private String name;
	private int age;
	private String email;
	private String homePage;
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getHomePage() {
		return homePage;
	}
	public void setHomePage(String homePage) {
		this.homePage = homePage;
	}
	@Override
	public String toString() {
		return "User [userName=" + userName + ", name=" + name + ", age=" + age
				+ ", email=" + email + ", homePage=" + homePage + "]";
	}
	
	
}

->新建Action RegisterAction.java

package com.java1234.action;

import com.java1234.model.User;
import com.opensymphony.xwork2.ActionSupport;

public class RegisterAction extends ActionSupport{
	private static final long serialVersionUID = 1L;
	
	private User user;

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	@Override
	public String execute() throws Exception {
		System.out.println("传入的用户:"+user);
		return SUCCESS;
	}
	
	

}

->struts.xml

<struts>
	
	<package name="manager" extends="struts-default">
		
		<action name="registerAction" class="com.java1234.action.RegisterAction">
			<result name="input">/register.jsp</result>  //验证失败
			<result name="success">/success.jsp</result>  //验证成功
		</action>
		
	</package>
 
</struts>

->新建register.jsp

<s:actionerror/>//这个是用来验证表达式时要加上的
用户注册
<s:form action="/registerAction" method="post">
	<s:textfield name="user.userName" label="用户名"></s:textfield>
	<s:textfield name="user.name" label="真实姓名"></s:textfield>
	<s:textfield name="user.age" label="年龄"></s:textfield>
	<s:textfield name="user.email" label="邮件"></s:textfield>
	<s:textfield name="user.homePage" label="主页"></s:textfield>
	<s:submit value="注册"></s:submit>
</s:form>

->新建success.jsp
注册成功
->新建配置文件RegisterAction-validation.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
//上面这行得加上
<validators>
    <field name="user.userName">
        <field-validator type="requiredstring">
            <message>请输入用户名</message>
        </field-validator>
         <field-validator type="stringlength">
         	<param name="minLength">6</param>
         	<param name="maxLength">10</param>
            <message>用户名必须在${minLength}和${maxLength}之间</message>
        </field-validator>
    </field>
    <field name="user.name">
    	<field-validator type="requiredstring">
            <message>请输入姓名</message>
        </field-validator>
    </field>
    <field name="user.age">
    	<field-validator type="int">
    		<param name="min">18</param>
            <message>年龄必须满18周岁</message>
        </field-validator>
    </field>
    <field name="user.email">
    	<field-validator type="requiredstring">
            <message>请输入邮件</message>
        </field-validator>
        <field-validator type="email">
            <message>邮件格式不对</message>
        </field-validator>
    </field>
    <field name="user.homePage">
    	<field-validator type="requiredstring">
            <message>请输入主页</message>
        </field-validator>
        <field-validator type="url">
            <message>主页格式不对</message>
        </field-validator>
    </field>
    
    //验证表达式
    <validator type="expression">
    	<param name="expression"><![CDATA[!user.name.equals(user.userName)]]></param>
    	<message>用户名和真实姓名不能相同</message>
    </validator>
</validators>

->启动程序:http://localhost:8080/HeadFirstStruts2Chap07/register.jsp
执行结果
当输入信息不满足条件时,点击提交,会给出相应的验证信息

自定义验证

struts2为我们提供了一种很好的范式,我们直接引入,也可以自己写
原理:先去找validators.xml
->复制validators.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator Config 1.0//EN"
        "http://struts.apache.org/dtds/xwork-validator-config-1.0.dtd">
<validators>
    <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>
    <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>
    <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/>
    <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/>
    <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/>
    <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/>
    <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/>
    <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/>
    <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/>
    <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/>
    <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/>

->自己写一个关键字验证器
->新建包com.java1234.validators
新建SensitiveWordValidators.java

package com.java1234.validators;

import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport;

public class SensitiveWordValidators extends FieldValidatorSupport{
//要继承FieldValidatorSupport,重写方法
	@Override
	public void validate(Object object) throws ValidationException {
	//这里面要写要检查哪个字段
		String fieldName=this.getFieldName();
		String value=this.getFieldValue(fieldName, object).toString();
		if(!check(value)){
		//相当于添加错误信息,转发到页面
			this.addFieldError(fieldName, object);
		}
	}
	
	public boolean check(String value){
		String sensitiveWords[]={"操","你妈"};
		for(int i=0;i<sensitiveWords.length;i++){
			if(value.indexOf(sensitiveWords[i])>-1){
			//
				return false;
			}
		}
		return true;
	}

}

->要把上面写的验证器加到validators.xml里面

    <validator name="sensitive" class="com.java1234.validators.SensitiveWordValidators"/>
</validators>

->写action
新建ValidationAction.java

package com.java1234.action;

import com.java1234.model.User;
import com.opensymphony.xwork2.ActionSupport;

public class ValidationAction extends ActionSupport{

	private static final long serialVersionUID = 1L;
	
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String execute() throws Exception {
		System.out.println("姓名:"+name);
		return SUCCESS;
	}
}

->新建与action同名的xml文件 ValidationAction-validation.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">

<validators>
    <field name="name">
        //系统的验证器
        <field-validator type="requiredstring">
            <message>请输入姓名</message>
        </field-validator>
        //自定义的的验证器
        <field-validator type="sensitive">
            <message>有敏感词汇</message>
        </field-validator>
    </field>
    
</validators>

->配置struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
	
	<package name="manager" extends="struts-default">

		<action name="validationAction" class="com.java1234.action.ValidationAction">
			<result name="input">/validation.jsp</result>
			<result name="success">/success.jsp</result>
		</action>
		
	</package>
 
</struts>

->新建validation.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<!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">
<title>Insert title here</title>
</head>
<body>
简单自定义验证
<s:form action="/validationAction" method="post">
	<s:textfield name="name" label="姓名"></s:textfield>
	<s:submit value="提交"></s:submit>
</s:form>
</body>
</html>

->启动程序http://localhost:8080/HeadFirstSrtuts2Chap07/validation.jsp
运行结果:
若不填姓名就提交,同页面上会提示:请输入姓名
若姓名中含有上面那两个关键字, 同页面上会提示:有敏感词汇,控制器上打印出“姓名:XXX”
若输入正常的名字,会跳转到success.jsp页面,显示登录成功。

八Struts2 文件上传和下载

一Struts2 文件上传

Struts2 文件上传基于 Struts2 拦截器实现;
Struts2 文件上传使用的是 fileupload 组件;
Form 配置 enctype=“multipart/form-data”; //表示以二进制的形式进行上传
Struts2 获取上传文件:name (name 是文件表单的 name);
Struts2 获取上传文件名:name+FileName; Struts2 获取上传文件的类型name+ContentType;
新建项目HeadFirstStruts2Chap08
->新建fileupload.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<!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">
<title>Insert title here</title>
</head>
<body>
<s:fielderror></s:fielderror>
<form action="upload" method="post" enctype="multipart/form-data">
	文件:<input type="file" name="java1234"/><br/>
	<input type="submit" value="提交"/>
</form>
</body>
</html>

->新建success.jsp
文件上传成功
->新建actiom FileUploadAction.java

package com.java1234.action;

import java.io.File;

import org.apache.commons.io.FileUtils;

import com.opensymphony.xwork2.ActionSupport;

public class FileUploadAction extends ActionSupport{
	private static final long serialVersionUID = 1L;
	
	private File java1234; // 文件
	
	private String java1234FileName;  // 文件名
	
	private String java1234ContentType;  // 文件类型

	public File getJava1234() {
		return java1234;
	}

	public void setJava1234(File java1234) {
		this.java1234 = java1234;
	}

	public String getJava1234FileName() {
		return java1234FileName;
	}

	public void setJava1234FileName(String java1234FileName) {
		this.java1234FileName = java1234FileName;
	}

	public String getJava1234ContentType() {
		return java1234ContentType;
	}

	public void setJava1234ContentType(String java1234ContentType) {
		this.java1234ContentType = java1234ContentType;
	}

	@Override
	public String execute() throws Exception {
		System.out.println("文件名:"+java1234FileName);
		System.out.println("文件类型:"+java1234ContentType);
		String filePath="C:/"+java1234FileName;
		File saveFile=new File(filePath);
		FileUtils.copyFile(java1234, saveFile);
		//相当于把文件copy到本地去
		return SUCCESS;
	}
}

->struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
	
	<package name="manager" extends="struts-default">
		
		<action name="upload" class="com.java1234.action.FileUploadAction">
			<result name="success">/success.jsp</result>
			<result name="input">/fileupload.jsp</result>
			
			<!-- <interceptor-ref name="fileUpload">
				<param name="allowedTypes">image/bmp,image/x-png,image/gif,image/jpg,image/jpeg</param>
				<param name="maximumSize">81101</param>
			</interceptor-ref>
			
			<interceptor-ref name="defaultStack"></interceptor-ref> -->
		</action>
		
	</package>
 
</struts>

->启动程序:http://localhost:8080/HeadFirstStruts2Chap08/fileupload.jsp
选择图片上传
发现c盘的规定路径下有了图片
控制台打印出“文件名:XXX.jpg 文件类型:image/jpeg”

二配置文件的大小及类型

<paramname="allowedTypes">image/bmp,image/x-png,image/gif,image/jpg,image/jpeg</param> <paramname="maximumSize">81101</param>
<s:fielderror></s:fielderror>

->struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

	<package name="manager" extends="struts-default">
		
		<action name="upload" class="com.java1234.action.FileUploadAction">
			<result name="success">/success.jsp</result>
			<result name="input">/fileupload.jsp</result>
			//错误的话,底层返回的是input
			//规定上传文件的类型和大小
			<interceptor-ref name="fileUpload">
				<param name="allowedTypes">image/bmp,image/x-png,image/gif,image/jpg,image/jpeg</param>
				<param name="maximumSize">81101</param>
			</interceptor-ref>
			
			<interceptor-ref name="defaultStack"></interceptor-ref> 
		</action>
		
	</package>
 
</struts>
执行结果:上传一个正常的图片,跳转到success.jsp,文件上传成功
上传一个超过大小的图片,报错

三大文件上传

Struts2 文件上传大小默认是 2M;
在struts.xml中package前面加上下面这句!

<constantname="struts.multipart.maxSize"value="20000000"></constant>

四多文件上传

新建filesupload.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<!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">
<title>Insert title here</title>
</head>
<body>
<s:fielderror></s:fielderror>
<form action="uploads" method="post" enctype="multipart/form-data">
	文件1:<input type="file" name="java1234"/><br/>
	文件2:<input type="file" name="java1234"/><br/>
	文件3:<input type="file" name="java1234"/><br/>
	<input type="submit" value="提交"/>
</form>
</body>
</html>

->新建FilesUploadAction.java

package com.java1234.action;

import java.io.File;

import org.apache.commons.io.FileUtils;

import com.opensymphony.xwork2.ActionSupport;

public class FilesUploadAction extends ActionSupport{

	private static final long serialVersionUID = 1L;
	
	private File[] java1234; // 文件
	
	private String[] java1234FileName;  // 文件名
	
	private String[] java1234ContentType;  // 文件类型

	public File[] getJava1234() {
		return java1234;
	}

	public void setJava1234(File[] java1234) {
		this.java1234 = java1234;
	}

	public String[] getJava1234FileName() {
		return java1234FileName;
	}

	public void setJava1234FileName(String[] java1234FileName) {
		this.java1234FileName = java1234FileName;
	}

	public String[] getJava1234ContentType() {
		return java1234ContentType;
	}

	public void setJava1234ContentType(String[] java1234ContentType) {
		this.java1234ContentType = java1234ContentType;
	}

	@Override
	public String execute() throws Exception {
		for(int i=0;i<java1234.length;i++){
			System.out.println("文件名:"+java1234FileName[i]);
			System.out.println("文件类型:"+java1234ContentType[i]);
			String filePath="C:/"+java1234FileName[i];
			File saveFile=new File(filePath);
			FileUtils.copyFile(java1234[i], saveFile);			
		}
		return SUCCESS;
	}
	}

->struts.xml

 <action name="uploads" class="com.java1234.action.FilesUploadAction">
			<result name="success">/success.jsp</result>
			<result name="input">/filesupload.jsp</result>
		</action>

->执行结果:
上传三个文件,跳转到success.jsp显示文件上传成功。

五Struts2 文件下载

返回的是文件流 <paramname=“contentDisposition”>attachment;filename=${fileName}
返回的方法里面
InputStreamgetInputStream()
->新建FileDownloadAction.java

package com.java1234.action;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import com.opensymphony.xwork2.ActionSupport;

public class FileDownloadAction extends ActionSupport{

	private static final long serialVersionUID = 1L;
	
	private String fileName;

	public String getFileName() throws Exception{
		fileName=new String(fileName.getBytes(),"ISO8859-1");
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}
	
	public InputStream getInputStream()throws Exception{
		File file=new File("C:/1.jpg");
		this.fileName="1111";
		return new FileInputStream(file);
	}
}

->struts.xml

<action name="download" class="com.java1234.action.FileDownloadAction">
			<result type="stream">
				<param name="contentDisposition">attachment;filename=${fileName}</param>
			</result>
		</action>

->新建filedownload.jsp
文件下载
->执行结果:点击链接,文件下载到C盘了

九Struts2 防重复提交

重复提交示例演示

新建项目HeadFirstStruts2Chap09
->新建Student.java

package com.java1234.model;

public class Student {

	private String name;
	private String age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAge() {
		return age;
	}
	public void setAge(String age) {
		this.age = age;
	}
	
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
}

->新建StudentAction.java

package com.java1234.action;

import java.io.File;

import org.apache.commons.io.FileUtils;

import com.java1234.model.Student;
import com.opensymphony.xwork2.ActionSupport;

public class StudentAction extends ActionSupport{
	private static final long serialVersionUID = 1L;
	
	private Student student;
	
	public Student getStudent() {
		return student;
	}

	public void setStudent(Student student) {
		this.student = student;
	}

	public String add() throws Exception {
		System.out.println("开始添加学生:"+student);
		Thread.sleep(5000);
		System.out.println(student.getName()+"添加完成");
		return SUCCESS;
	}
}

->struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
	<package name="manager" extends="struts-default">
	
		<action name="student" class="com.java1234.action.StudentAction" method="add">
			<result name="success">/success.jsp</result>
		</action>
	</package>
</struts>

->新建success.jsp
学生添加成功
->新建student.jsp

<form action="student" method="post" >
	姓名:<input type="text" name="student.name"/><br/>
	年龄:<input type="text" name="student.age"/><br/>
	<input type="submit" value="提交"/>
</form>

->模拟重复提交
输入姓名和年龄,提交,跳转到成功页面,显示“学生添加成功”。控制台上打印出“开始添加学生:Student[name=张三,age=12] 张三添加完成”。
加上Thread.sleep(5000);
点了两次提交,业务上就不合理。

使用<s:token/>标签防重复提交

<s:token></s:token> :加在 form 里;
使用 token 拦截器:


/student.jsp :在 struts.xml 里配置,假如出现重复提 交,则直接回到页面;
<s:actionerror/>:在页面上显示错误信息;
->student.jsp

<s:actionerror/>//显示错误信息
<form action="student" method="post" >
	<s:token></s:token>  //加上这个,每次提交都有唯一的一个tokenid
	姓名:<input type="text" name="student.name"/><br/>
	年龄:<input type="text" name="student.age"/><br/>
	<input type="submit" value="提交"/>
</form>

->struts.xml

<struts>
	<package name="manager" extends="struts-default">
		<action name="student" class="com.java1234.action.StudentAction" method="add">
			<result name="success">/success.jsp</result>
			<result name="invalid.token">/student.jsp</result>
			<interceptor-ref name="token"></interceptor-ref>
			<interceptor-ref name="defaultStack"></interceptor-ref> 
		</action>
		
	</package>
 
</struts>

->执行结果:
若重复提交,会报错,同页面上显示The form has already been proceed or no token was supplied,please try again.
这种方式的缺点是:有错的的话是显示在页面,但业务上我们需要系统无视重复提交。

使用 tokenSession 拦截器防重复提交

tokenSesssion 拦截器直接无视重复提交的请求;
<interceptor-refname=“tokenSession”>

<interceptor-refname=“defaultStack”>

->struts.xml

<struts>
	<package name="manager" extends="struts-default">
		<action name="student" class="com.java1234.action.StudentAction" method="add">
			<result name="success">/success.jsp</result>
			<interceptor-ref name="tokenSession"></interceptor-ref>
			<interceptor-ref name="defaultStack"></interceptor-ref>
		</action>
		
	</package>
 
</struts>

->执行结果:
重复提交后,点击一次后没有反应,你再点一次没有反应的。后台报错。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值