jsp浏览图像bean原理分析与改良-JSP实用教程(第三版)耿祥义 张跃平编著第4章例题4_9-动态获取文件夹中的文件并返回

JSP 专栏收录该内容
2 篇文章 0 订阅

前言

下面我要给大家讲解的是《JSP实用教程(第三版)耿祥义 张跃平编著》的第4章(JSP与Javabean)中例题4_9,这个例子所实现的功能是编写一个类和一个jsp文件,动态获取项目中一个文件夹下面所有的图片文件并将路径存储到对象中,当我们点击jsp页面中的上一张和下一张按钮时,重新向服务器提交请求,服务器返回新的html页面从而达到切换图片的效果。

1.效果展示

(注意:这里的上面的按钮是“上一张”,下面的按钮是下一张,哈哈,没想到我自己居然打错字了,而且是等文章快写好的时候才发现写错字的,不过问题应该不大,大家明白这个意思就好了,我就不重新截图了,麻烦地很!!)
效果展示

2.知识点讲解

2.1什么是javabean?

bean的本意是豆子,而在java ee的开发中,一般我们把一些可重用的组件称为一个javabean,简单的来说,javabean就是一个类,当有一些信息需要我们进行存储或者在不同的程序之间传递时,封装成一个javabean会是一个很好的选择,例如:
javabean简介

2.2javabean代码示例

package tom.jiafei;

import java.util.Date;

public class UserInfo {
	//这里的用户的信息存储在UserInfo类的成员变量里,类UserInfo就是一个javabean
	public String id;
	private String password;
	public String name;
	public int sex;//0未知 1男 2女
	public String phone;
	public String email;
	public Date registerTime;
	public boolean vip;
	//一般我们会为javabean中的每个属性编写一个对应的set方法和get方法,不过时候后也会故意不写,例如:
	public String getId() {return id;}
	public void setId(String i) {id=i;}
	public String getName() {return name;}
	public void setName(String name) {this.name = name;}
	//jsp页面调用<jsp:getProperty/>和</jsp:setProperty/>来获取和设置javabean中的成员时,bean中必须存在对应的is方法或get方法或set方法,否则会出错
	public boolean isVip() {
		return vip;
	}
	public void setVip(boolean vip) {
		this.vip = vip;
	}
	//其他的东西我就不写了,大家随便看看就好了
}

2.3 File类的使用

File类是java.io包中一个操作磁盘上的文件或目录的类,这里我简单介绍一下File类的使用以及背后的原理。直接上代码,在代码中解释吧。我在我电脑的D盘中新建了一个test.java。内容如下:

package com;
import java.io.File;
public class test{
	public static void main(String args[]){
		//File类使用方法1.使用绝对路径,路径分隔符可以是\\或/
		File f1 = new File("d:/test1.txt");//1.1文件
		File f2 = new File("c:\\test");//1.2目录
		//注意,上面的这两个路径都是不存在的,File中只是存储了路径信息,
		//如果需要判断文件是否存在或者创建文件的话,需要调用File类中的方法。
		if(f1.exists()){
			System.out.println("文件存在");
		}else{
			try{
				f1.createNewFile();//创建新文件
			}catch(Exception e){System.out.println(e);}
		}
		
		//File类使用方法2.使用相对路径
		File f3 = new File("");//这个目录就是当前目录,具体是啥我后面再解释
		File f4 = new File("test3.txt");
		System.out.println("f3 "+f3.getAbsolutePath());
		System.out.println("f4 "+f4.getAbsolutePath());
	}
}

下面简单看一下运行结果:
运行结果
上面的File类的示例还是比较简单的,唯一容易产生疑问的就是File类中相对路径的参照到底是怎么来的。从上面的图我们可以看到,java中File类获取到的相对路径和我们执行java命令时的工作目录是一致的,下面我再给大家详细讲讲这里。

2.3.1 File类的相对路径

根据JDK的官方文档,java.io包中的所有类都将相对路径名解释为起始于用户的当前工作目录,可以通过调用System.getProperty(“user.dir”) 来获得,这个user.dir属性,简单来说就是执行java命令的工作目录的路径,下面我用代码给大家验证一下,将上个例子中的代码精简如下:

package com;
import java.io.File;
public class test{
	public static void main(String args[]){
		System.out.println(new File("").getAbsolutePath());
		System.out.println(System.getProperty("user.dir"));
	}
}

相对路径

2.3.2 列举出目录中的所有文件

File类中提供的列举目录中的文件的方法有2个分别是list()和listFiles();在源码中它们的定义如下:
list方法
下面我简单示范一下:

package com;
import java.io.File;
import java.util.Arrays;
public class test{
	public static void main(String args[]){
		//用法1.list方法列举出所有文件和目录,获取到的是字符串
		File f = new File("d:\\cordova");//注意这里的必须传入一个目录的值才能使用list方法
		String [] list = f.list();
		System.out.println(Arrays.toString(list));
		//用法2.listFiles方法列举出所有文件和目录,打印出绝对路径
		File[] fs = f.listFiles();
		System.out.println(Arrays.toString(fs));
		//错误用法1.往File中传入空字符串后,使用list方法将返回null,因为文件或目录不存在
		//这里传入file的值是空字符串,虽然getAbsolutePath()方法依然能获取到相对路径本身,但是无法使用list方法
		System.out.println(Arrays.toString(new File("").list()));
	}
}

list方法
书上例题4_9的代码就是调用list方法获取一个目录下的所有图片文件,所以大家只要知道list方法的用法就好了。

3.原例题代码的正确运行示范和易错点解析

3.1例题代码

com.ob.Play.java

package com.ob;
import java.io.*;
import java.net.URISyntaxException;
public class Play {
	int imageNumber = 0,max;
	String pictureName[],playImage;
	String webDir = "";
	String tomcatDir;
	public Play() {
		File f = new File("");
		String path = f.getAbsolutePath();
		int index = path.indexOf("bin");
		tomcatDir = path.substring(0,index);
	}
	public void setWebDir(String s) {
		webDir  = s;
		if(pictureName == null) {
			File dirImage = new File(tomcatDir+"/wtpwebapps/"+webDir+"/image");
			pictureName = dirImage.list();
		}
		if(pictureName!=null) max = pictureName.length;
	}
	public void setImageNumber(int n) {
		if(n<0) n = max-1;
		if(n==max) n=0;
		imageNumber = n;
	}
	public int getImageNumber() {
		return imageNumber;
	}
	public String getPlayImage() {
		if(pictureName!=null) playImage = pictureName[imageNumber];
		return playImage;
	}
}

example4_9.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.io.File" %>
<jsp:useBean id="play" class="com.ob.Play" scope="session"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>example4_9.jsp</title>
</head>
<body style="background:cyan;font-size:small;">
	<%String webDir = request.getContextPath();
	webDir = webDir.substring(1);
	%>
	<jsp:setProperty name="play" property="webDir" value="<%=webDir %>"/>
	<jsp:setProperty name="play" property="imageNumber" param="imageNumber"/>
	<img src="image/<jsp:getProperty name="play" property="playImage"/>" style="width:120px;height:90px;" alt="这是当前显示的图像">
	<br>单击“上一张”或“下一张”按钮浏览图像
	 <form action="" method="post">
	 <input	type="submit" name="ok" value="上一张">
	 <input type="hidden" name="imageNumber" value="<%=play.getImageNumber()-1%>">
	 </form>
	 <form action="" method="post">
	 <input	type="submit" name="ok" value="下一张">
	 <input type="hidden" name="imageNumber" value="<%=play.getImageNumber()+1%>">
	 </form>
</body>
</html>

3.2易错点解析

相信很多同学在把书上的例题4_9的代码在eclispe中运行的时候都会遇到图片无法显示或者无法切换的错误,错误情况如图:(这是直接在eclipse的项目中点击Run之后的结果)run
然后就出现了,图片无法显示,并且点击切换也没有效果,这是为什么呢?
error
这里看到的错误是有点抽象的,我们可以用chrome浏览打开这个页面然后用开发者工具查看一下到底是哪里出了问题。(右键浏览器点击检查或按F12键,得到信息如下:)
null
这里img标签的src中文件名为null,说明后台没有获取到图片的文件名。为什么呢?错误的原因其实就是我们在2.3.1提到的File类相对路径的问题。
例题的代码中,获取图片所在的目录的关键代码为这几句.
关键代码
其中File f = new File("");String path = f.getAbsolutePath();这两句是为了得到tomcat安装路径的bin目录的绝对路径。什么意思呢?
这里我有必要给大家简单说一下tomcat,一个解压后的tomcat目录结构如下:(注:tomcat8.5和6.0的目录结构稍有区别,一切以实际为准)
tomcat
如果我们要在把编译好web项目放进tomcat里运行,那么我们只需要把项目放进wtpwebapps里面,然后双击bin目录下的startup.bat就可以运行了。如图:
bin
所以,刚才我们说的File file = new File("");String path = f.getAbsolutePath();实际上我们期望得到的path的值是"D:\work\apache-tomcat-8.5.37\bin"(因为我把tomcat放在D:\work里面了)。
而且,只要我们是按照我图片上的操作去运行web项目的,那么我们就可以得到正确的tomcat路径,接下来,例题代码中用int index = path.indexOf(“bin”);tomcatDir = path.substring(0,index);这两行代码得到tomcatDir为"D:\work\apache-tomcat-8.5.37",然后通过字符串连接最终得到D:\work\apache-tomcat-8.5.37\wtpwebapps\section4\image这个路径(分析省略,自己看代码去吧),最后用这个绝对路径new一个File对象,使用List方法得到文件名。
image内的图片如下:
image
正确运行时,chrome开发者模式看到的信息如下:
right
那么为什么直接在eclipse中点击Run运行这个例题的代码会出错呢?eclipse中File类相对路径的基路径又定位到哪里去了呢?我们在String path = f.getAbsolutePath();后面加一句System.out.println(“path”);并且把tomcatDir = path.substring(0,index);注释掉,然后来看一下:
out
relative
我们可以看到,运行在eclipse中的java程序,File类获取到的相对路径基路径是eclispe的启动路径,因为我直接从桌面快捷方式打开了eclipse,所以识别到的路径是我桌面的路径C:\Users\weibin\Desktop,假如我们关掉eclipse,然后进入eclipse的安装路径再打开eclispe再测试的话,那么识别到的路径也会跟着改变,如图:
change
获取到的路径不同的原因在于,我打开时eclipse的用户路径不一样,即直接桌面快捷方式打开,和手动进入安装路径打开。所以,你把快捷方式移动到哪个目录打开,识别到的路径就是哪个。
eclipse
所以,使用File类的相对路径去获取项目目录的绝对路径这种方法是存在极大的漏洞的,这里先教大家怎么解决,然后再教一下更好的解决方案。

3.3 eclipse的默认发布路径

为了解决上面这个问题,我给大家提供2种解决办法,不过在讲之前,其实还有些知识点我们需要补充一下。
1.eclipse安装tomcat之后,我们点击run运行项目时,默认会把项目发布到eclipse的内部数据文件夹.metadata的子文件夹里面,而不会直接发布到tomcat的安装路径。
这里,我们双击server视图中当前已经创建好的server可以查看发布项目时的路径设置:
默认是长这样的:
one
不知道怎么开启server视图的请参考百度经验-eclipse中的Servers面板不见了怎么办
metadata其实就是这里,我随便发布一个项目给大家看一下。我电脑上的路径是这样的,不同的电脑可能会有差别。(C:\Users\weibin\eclipse-workspace.metadata.plugins\org.eclipse.wst.server.core\tmp2\wtpwebapps)
metadata
注意:metadata中是没有bin目录或者其他只存在于tomcat安装路径的东西的,有的只是存放项目的wtpwebapps和几个xml配置文件。所以,为了兼容例题中的代码,我们必须把eclipse中的server location改成第二个,即tomcat installation。

3.4 解决方案

修改server location这里我就先不说了,大家记得把旧的server删掉,新建一个server才能设置server location。(当server中已经发布了项目则只能查看,不能修改server locations,想要修改的话需要再tomcat中删除重建一个tomcat server选项,然后再双击就可以修改了,这里已经把server location改成tomcat的安装路径了)
see
设置好了之后,我们再次右键项目run到这个新建的server上,run成功再点击stop关掉。
这样,tomcat安装路径中就会有编译好的项目文件了。
如图:
build
接下来,我们只要去tomcat的bin目录下,启动tomcat,然后我们的例题4_9就能正常运行了。
结合我们在3.2中讲的两种运行tomcat的方式,这里我们可以有两种启动tomcat的方案。
3.4.1 关掉eclipse,把eclipse的快捷方式复制一份到tomcat的bin目录后再打开,此时打开的eclipse,相对路径的基目录是tomcat的bin目录,所以例题4_9能正常运行,如图:
solve1
3.4.1 关掉eclipse,然后双击bin目录中的startup.bat,再去浏览器输入网址打开例题4_9,结果也是正常的。因为运行bat的目录就是bin目录,所以以此为基础运行的java程序识别到的相对路径基目录就是bin目录,(同理,如果你把startup.bat发送到桌面快捷方式再去桌面打开的话,那么识别到的相对路径就又变成了桌面),这里我就不示范了,上面已经讲过了。

4.路径获取的改良方案

因为使用File类或者其他基于System.getProperty(“user.dir”)的方式获取到的路径经常都是变化的,所以在实际开发中,我们建议大家不要使用这种方式去存取文件,而可以使用另外一个方式,即使用类的getResource()方法去读取文件,getResource方法的使用大家可以参考: 关于Class.getResource和ClassLoader.getResource的路径问题
这里我用代码简单的给大家做一个示范:

package com;
import java.io.File;
import java.net.URISyntaxException;

public class Test {
	public static void main(String args[]) {
		// class.getResource接收一个字符串类型的变量,返回一个java.net.URL类型的对象
		// 用法1.使用 类名.class.getResource("文件路径")获取与当前类字节码文件同目录的文件
		// Test.class.getResource("1.txt");//这里是获取不到1.txt的,只是做一个用法示范

		// 用法2.使用 类名.class.getResource("/文件路径")获取与当前类字节码文件最上层包(即与com文件夹)同目录的文件
		System.out.println(Test.class.getResource("/1.txt"));
		// 上面能获取到1.txt,不过要注意被读取的1.txt并不是src目录下的原件,而是编译后的classes目录下的1.txt的副本

		// 用法3.使用 对象名.getClass().getResource()代替 类名.class.getResource();
		A a = new A();
		System.out.println(a.getClass().getResource("/1.txt"));

		// 用法4. 将getResource方法和File类结合获取目录的绝对路径
		// java中URL类、File类和URI类可以进行便捷的转换
		try {
			// 这里调用URL类的toURI方法的getPath来获取绝对路径
			System.out.println(new File(Test.class.getResource("/").toURI()
					.getPath()).getAbsolutePath());
			// 调用toURI方法时可能发生异常,需要用try catch捕捉
		} catch (URISyntaxException e) {
			System.out.println(e);
		}
	}
}

class A {
}

运行结果如图:
在这里插入图片描述(注意:这篇教程写的比较久,所以后面的东西我都是在另外一台电脑上截图的,上面那个截图的路径是另外一台电脑上myeclipse的项目发布路径,总之原理是一样的,后面的代码也是能正确运行的,希望大家不要被绕晕)
所以上面的例题4_9的代码,获取图片文件的方式可以修改成这样:
com.ob.Play.java

package com.ob;
import java.io.File;
import java.net.URISyntaxException;
public class Play {
	int imageNumber = 0,max;
	String pictureName[],playImage;
	public Play() {
		try {
			String dir = new File(this.getClass().getResource("/").toURI().getPath()).getAbsolutePath();
			pictureName = new File(dir.substring(0, dir.indexOf("WEB-INF"))+"image").list();
			if(pictureName!=null) max = pictureName.length;
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
	}
	public void setImageNumber(int n) {
		if(n<0) n = max-1;
		if(n==max) n=0;
		imageNumber = n;
	}
	public int getImageNumber() {
		return imageNumber;
	}
	public String getPlayImage() {
		if(pictureName!=null) playImage = pictureName[imageNumber];
		return playImage;
	}
}

example4_9.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.io.File" %>
<jsp:useBean id="play" class="com.ob.Play" scope="session"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>example4_9.jsp</title>
</head>
<body style="background:cyan;font-size:small;">
	<jsp:setProperty name="play" property="imageNumber" param="imageNumber"/>
	<img src="image/<jsp:getProperty name="play" property="playImage"/>" style="width:120px;height:90px;" alt="这是当前显示的图像">
	<br>单击“上一张”或“下一张”按钮浏览图像
	 <form action="" method="post">
	 <input	type="submit" name="ok" value="上一张">
	 <input type="hidden" name="imageNumber" value="<%=play.getImageNumber()-1%>">
	 </form>
	 <form action="" method="post">
	 <input	type="submit" name="ok" value="下一张">
	 <input type="hidden" name="imageNumber" value="<%=play.getImageNumber()+1%>">
	 </form>
</body>
</html>

上面移除了setWebDir方法,结合class.getResource来直接列出文件的名字,运行效果我这里就不贴图了,测试了一下是正常的。

5. 效率提升改良方案

在上面的例子中,当我们点击上一张和下一张按钮时,实际上每一次点击的时候我们都服务器提交了一个请求,服务器返回了一个新的html页面才实现了图片切换,所以,这样的实现方式存在这两个问题:

  1. 服务器请求堆积,切换图片是会频繁触发的动作,特别是当用户量增大时,每次切换图片都向服务器重新提交请求的话会占用太多服务器时间执行不必要的计算。
  2. 客户端频繁刷新页面导致用户体验变差,当一个网页做的比较大的时候,频繁地刷新重载页面会导致效率低下,一般我们只对需要更新的内容执行更新,而不能整个页面进行重载。

解决的方案:
服务器将所有图片的相对路径存储在一个数组中,jsp页面中采用js监听点击事件执行图片切换。修改后的代码如下:
com.ob.Play.java

package com.ob;
import java.io.File;
import java.net.URISyntaxException;
public class Play {
	public String pictureName[];
	String id = "image";
	public Play() {
		try {
			String dir = new File(this.getClass().getResource("/").toURI().getPath()).getAbsolutePath();
			pictureName = new File(dir.substring(0, dir.indexOf("WEB-INF"))+id).list();
			for(int i=0;i<pictureName.length;i++){
				pictureName[i] = "\""+id+"/"+pictureName[i]+"\"";//将形如1.jpg变为"image/1.jpg"
			}
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
	}
	public String[] getpictureName() {
		return pictureName;
	}
}

example4_9.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.Arrays" %>
<jsp:useBean id="play" class="com.ob.Play" scope="session"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>example4_9.jsp</title>
</head>
<body style="background:cyan;font-size:small;">
	<img src="" style="width:120px;height:90px;" alt="这是当前显示的图像" data-id="0" id="img">
	<br>单击“上一张”或“下一张”按钮浏览图像<br>
	<input	type="button" id="prev" value="上一张"><br>
	<input	type="button" id="next" value="下一张">
<script>
	//将javabean获取的值转化为字面量数组。
	var images = <%=Arrays.toString(play.getpictureName())%>;
	var img = document.querySelector('#img');
	//切换图片的函数
	function play(offset){
		var temp = offset;//
		offset = parseInt(offset);
		if(isNaN(offset)){
			cosole.error("param"+temp+" is not a number!");
			return;
		}
		var index = parseInt(img.dataset.id);//获取存储在节点上的信息
		index += offset;//加上偏移量,例如下一张图片则为当前index+1
		index %= images.length;//求余得到数组下标
		//当index为负数时,不同编程语言求余得到的结果会有两种情况,一种是负数,一种是正数,因为数组下标一定是正数,这里我做一下兼容
		if(index<0) index += images.length;
		//执行图片切换
		img.dataset.id = index;
		img.src = images[index];
	}
	//显示第一张图片
	play(0);
	//监听点击事件
	document.querySelector('#next').addEventListener('click',function(){play(1);});
	document.querySelector('#prev').addEventListener('click',function(){play(-1);});
</script>
</body>
</html>

这里的代码我也已经测试过啦,是可以的,但是运行结果还是跟之前一模一样,只是运行效率提升了而已,就不贴图了。

结语

到这里,这个例题所涉及到的知识点和改良的方案我已经讲的差不多了,虽然界面还是很丑,不过界面的设计这个并不是我们学习jsp主要考虑的问题,我就不去改界面了。今天就写到这里吧,本文作者郑伟斌,写于2019/4/25,转载请注明出处,另外走过路过不要忘记点个赞哦。

  • 4
    点赞
  • 0
    评论
  • 10
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

JSP实用教程2版)ppt课件及程序源码,非常适合教学 作 者: 耿祥义张跃平 编著 出 版 社: 清华大学出版社 目录 1 JSP简介  1.1 什么是JSP  1.2 安装配置JSP运行环境  1.3 JSP页面   1.3.1 JSP页面简介   1.3.2 设置Web服务目录  1.4 JSP的运行原理  1.5 JSPJava Servlet的关系  1.6 小结  习题一 2 JSP语法  2.1 JSP页面的基本结构  2.2 变量和方法的声明   2.2.1 声明变量   2.2.2 声明方法  2.3 Java程序片  2.4 Java表达式  2.5 JSP的注释  2.6 JSP指令标记   2.6.1 page指令标记   2.6.2 include指令标记  2.7 JSP动作标记   2.7.1 include动作标记   2.7.2 param动作标记   2.7.3 forward动作标记   2.7.4 plugin动作标记   2.7.5 useBean动作标记  2.8 小结  习题二 3 JSP内置对象  3.1 request对象   3.1.1 获取客户提交的信息   3.1.2 处理汉字信息   3.1.3 常用方法举例   3.1.4 处理HTML标记  3.2 response对象   3.2.1 动态响应contentType属性   3.2.2 response的HTTP文件头   3.2.3 response重定向   3.2.4 response的状态行  3.3 session对象   3.3.1 session对象的ID   3.3.2 session对象URL重写   3.3.3 session对象存储数据   3.3.4 session对象的生存期限   3.3.5 计数器  3.4 application对象   3.4.1 application对象的常用方法   3.4.2 用application制作留言板  3.5 out对象  3.6 小结  习题三 4 JSPJavabean  4.1 编写Javabean和使用Javabean   4.1.1 编写Javabean   4.1.2 保存bean的字节码   4.1.3 创建使用bean  4.2 获取和修改bean的属性   4.2.1 getProperty动作标记   4.2.2 setProperty动作标记  4.3 bean的辅助类  4.4 JSPbean结合的简单例子   4.4.1 三角形bean   4.4.2 四则运算bean   4.4.3 计数器bean   4.4.4 浏览图像bean   4.4.5 成绩单bean   4.4.6 日历bean  4.5 小结  习题四 5 JSP文件操作  5.1 File类  5.2 使用文件字节流读写文件  5.3 使用文件字符流读写文件  5.4 BufferedReader和BufferedWriter类  5.5 文件上传  5.6 文件下载  5.7 分行读取文件  5.8 标准化考试  5.9 小结  习题五 6JSP使用数据库  6.1 SQL Server 2000数据库管理系统  6.2 JDBC  6.3 连接数据库的常用方式   6.3.1 JDBC-ODBC桥接器   6.3.2 使用纯Java数据库驱动程序  6.4 查询操作   6.4.1 顺序查询   6.4.2 随机查询   6.4.3 条件查询   6.4.4 排序查询   6.4.5 模糊查询  6.5 更新、添加删除操作  6.6 分页显示记录  6.7 常见数据库的连接   6.7.1 连接Oracle数据库   6.7.2 连接MySql数据库  6.8 查询Excel电子表格  6.9 使用连接池  6.10 使用预处理语句   6.10.1 预处理语句的优点   6.10.2 使用通配符  6.11 小结  习题六 7 Java Servlet基础  7.1 servlet对象   7.1.1 HttpServlet类   7.1.2 部署servlet   7.1.3 运行servlet  7.2 servlet的工作原理   7.2.1 servlet的生命周期   7.2.2 init方法   7.2.3 service方法   7.2.4 destroy方法  7.3 通
参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

月桦剑士

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值