一、文件上传

先创建工程,写一个简易的JSP:

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body><h3>文件上传</h3><form action="" method="POST">账号:<input type="text" name="username"/><br/>邮箱:<input type="text" name="email"/><br/>头像:<input type="file" name="pic" accept="image/*"/><br/><input type="submit" value=" 注册 "/><br/></form>
</body>
</html>

在上传的头像那里,类型改为 file ,后面的 accept 可以用来更改选择文件的类型(为图片类型),效果如下:


要点:

  1. 上传控件所在的表单method必须为 POST,因为GET方式传入的数据大小不能超过2KB,而POST大小没有限制。
  2. 上传控件的类型为 file.

使用一个Servlet来接收参数,并打印表单中的内容,如下:

@WebServlet("/upload")
public class UploadServlet extends HttpServlet {private static final long serialVersionUID = 3067915922682828536L;protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {req.setCharacterEncoding("UTF-8");System.out.println(req.getParameter("username"));System.out.println(req.getParameter("email"));System.out.println(req.getParameter("pic"));}
}


显然这里的图片是字符串。

因此表单的编码必须是二进制编码
因此我们需要用到表单中的 enctype 属性中的 multipart/form-data

再提交一遍:

全部为 NULL 了。

这是因为在使用二进制编码 multipart/form-data 后,在Servlet中再也不能通过request.getParameter 方法来获得参数了,设置编码都没有效果了。

没有设置二进制编码时,POST为:

在设置了二进制编码后的请求头:

红色框框里的就是图片的二维码信息。
我们打印一下:

@WebServlet("/upload")
public class UploadServlet extends HttpServlet {private static final long serialVersionUID = 3067915922682828536L;protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {Scanner sc = new Scanner(req.getInputStream());while (sc.hasNextLine()) {System.out.println(sc.nextLine());}}
}

基于 Apache FileUpload 组件

Apache commons-fileupload 的jar包下载
Apache commons-io 的jar包下载
我们按照官方文档的提示来进行文件上传操作:

@WebServlet("/upload")
public class UploadServlet extends HttpServlet {private static final long serialVersionUID = 3067915922682828536L;protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {//检查是否有文件上传请求:请求方法为POST,请求编码为multipart/form-databoolean isMultipart = ServletFileUpload.isMultipartContent(req);if (!isMultipart) {return;}try {//1.创建FileItemFactory对象//FileItemFactory是用来创建FileItem对象的//FileItem对象相当于form表单中的表单控件的封装DiskFileItemFactory factory = new DiskFileItemFactory();//2.创建一个新的文件上传处理程序(文件上传处理器)ServletFileUpload upload = new ServletFileUpload(factory);//3.解析请求List<FileItem> items = upload.parseRequest(req);System.out.println(items);} catch (FileUploadException e) {e.printStackTrace();}}
}

运行发现报错:找不到类:

缺少IO包,添加之后,运行结果如下:

我们参照文档,将表单里面的内容提取并将文件内容写到磁盘中的文件里:

@WebServlet("/upload")
public class UploadServlet extends HttpServlet {private static final long serialVersionUID = 3067915922682828536L;protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {//检查是否有文件上传请求:请求方法为POST,请求编码为multipart/form-databoolean isMultipart = ServletFileUpload.isMultipartContent(req);if (!isMultipart) {return;}try {//1.创建FileItemFactory对象//FileItemFactory是用来创建FileItem对象的//FileItem对象相当于form表单中的表单控件的封装DiskFileItemFactory factory = new DiskFileItemFactory();//2.创建一个新的文件上传处理程序(文件上传处理器)ServletFileUpload upload = new ServletFileUpload(factory);//3.解析请求List<FileItem> items = upload.parseRequest(req);for (int i = 0; i < items.size(); i++) {System.out.println(items.get(i));}//4.迭代出每一个FileItemfor (FileItem item : items) {//获取表单属性名称String fieldName = item.getFieldName();if (item.isFormField()) {//普通表单控件String value = item.getString("UTF-8");//获取当前普通表单控件的参数值System.out.println(fieldName + "-" + value);} else {//上传文件控件System.out.println(fieldName + "-" + item.getName());//字段名-上传的文件名item.write(new File("E:/", item.getName()));//把二进制文件写到哪个文件中}}} catch (Exception e) {e.printStackTrace();}}
}

最终结果如下:

文件上传的文件名处理

文件名

IE6 中,通过 FileItem.getName 方法获取到的文件名会带有完整路径,因此要进行处理。
我们可以用 FilenameUtils.getName(item.getName())进行转化
解释如下:

public class FileNameUtilsTest {public static void main(String[] args) {String path = "E:/Judy.png";//获取文件名称System.out.println(FilenameUtils.getName(path));//获取文件名称,不包括拓展名System.out.println(FilenameUtils.getBaseName(path));//获取文件拓展名System.out.println(FilenameUtils.getExtension(path));}
}

上传的文件名问题

我们要给上传的文件起一个唯一的名称:通过UUID

String fileName = UUID.randomUUID().toString() + "." +FilenameUtils.getExtension(item.getName());
item.write(new File("E:/", fileName));

上传文件的保存路径

如果我们想将文件保存在应用中,可以用super.getServletContext().getRealPath()函数获得真实路径:

String dir = super.getServletContext().getRealPath("/upload");
System.out.println(dir);
item.write(new File(dir, fileName));

这样就可以在浏览器中访问项目中的文件了,就不必从磁盘中访问了。
注意:在写文件的时候只能写到文件中,不能写到文件夹中。

缓存大小和临时目录

当文件大小超过 10KB 就不能放在缓存中了。
文件不放在内存中,其实放在了所谓的 “临时目录”,在 Tomcat 根目录中的 temp 文件夹下。

DiskFileItemFactory factory = new DiskFileItemFactory();
//设置缓存大小
factory.setSizeThreshold(20 * 1024);
//设置临时目录
factory.setRepository(repository);

文件类型约束

//允许接收的图片类型
private static final String ALLOWED_IMAGE_TYPE = "jpg;png;jpeg;gif";
String[] allowedImageType = ALLOWED_IMAGE_TYPE.split(";");
String ext = FilenameUtils.getExtension(item.getName());
List<String> list = Arrays.asList(allowedImageType);
//上传文件类型不合法
if (!list.contains(ext)) {req.setAttribute("errorMsg", "上传文件类型错误");req.getRequestDispatcher("/input.jsp").forward(req, resp);System.out.println("Invalid Type!");return;
}

jsp中:

<span style="color: red">${errorMsg}</span>

或者更通用的办法是通过上传文件的 mime-type 进行判断是否为 image 类型:

String mimeType = super.getServletContext().getMimeType(FilenameUtils.getName(item.getName()));

抽取FileUtil工具类

在工具类中,因为要复用代码,因此应该具有一般性,并尽可能简洁,我们可以删掉方法中响应参数,并且通过抛出自定义异常来让调用者接收:

if (!list.contains(ext)) {throw new LogicException("上传文件类型错误,请上传图片文件...");
}
...
catch (LogicException e) {throw e;
}

调用类 UploadServlet:

@WebServlet("/upload")
public class UploadServlet extends HttpServlet {private static final long serialVersionUID = 3067915922682828536L;protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {try {FileUtil.upload(req);} catch (LogicException e) {String errorMsg = e.getMessage();req.setAttribute("errorMsg", errorMsg);req.getRequestDispatcher("/input.jsp").forward(req, resp);}}
}

这样就重构了 FileUtil

文件大小约束问题

情况一:单个文件超过指定大小;

upload.setFileSizeMax(2*1024*1024);  //2M

否则会报出 FileUploadBase$FileSizeLimitExceededException 的异常

因为是异常,我们要再次捕捉这个异常:

catch (FileSizeLimitExceededException e) {throw new LogicException("文件大小超过2M,请重试", e);
}

情况二:该次请求的全部数据超过指定大小

upload.setSizeMax(10 * 1024 * 1024); //10M

否则会报出 SizeLimitExceededException 异常
继续接受这个异常并抛出:

catch (SizeLimitExceededException e) {throw new LogicException("该次请求信息量超过10M,请重试", e);
}

效果如下:

使用Map封装请求信息

我们想要将表单中的值封装到一个对象中,例如 User 类,我们可以在 upload 方法中加入 User 参数,将 Servlet 中创建的类的实例对象作为参数传递进来。:
User类

public class User {private String username;private String email;private String imageUrl;//图片路径private String imageName;//图片原始名称
}
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {private static final long serialVersionUID = 3067915922682828536L;protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {try {User user = new User();  //新建User实例  FileUtil.upload(req, user);//作为参数传递System.out.println(user);} catch (LogicException e) {e.printStackTrace();String errorMsg = e.getMessage();req.setAttribute("errorMsg", errorMsg);req.getRequestDispatcher("/input.jsp").forward(req, resp);}}
}

将User赋值

if ("username".equals(fieldName)) {user.setUsername(value);
} else if ("email".equals(fieldName)) {user.setEmail(value);
}

但是这样并不能处理通用情况,因此我们可以考虑设置一个Map进行传递,而我们知道类和接口对象都是引用传递,类似于C中的指针,因此得到Map中的值后再设置到User中。但是Map不能封装图片、复选框等需要有多个信息的控件。
如果还要用Map进行封装的话,我们可以将图片的两个信息(imageUrl和imageName)再用一个类进行封装,例如 CFile 类,然后作为 Map 的参数传递进去:
CFile类:

@Data
public class CFile {private String imageUrl;//图片路径private String imageName;//图片原始名称CFile(String imageUrl, String imageName) {this.imageName = imageName;this.imageUrl = imageUrl;};
}
Map<String, CFile> binaryMap = new HashMap<>();
FileUtil.upload(req, fieldMap, binaryMap);
binaryMap.put(fileName, new CFile("/upload" + fileName, FilenameUtils.getName(item.getName())));

设置值到 User 中,并共享到 show.jsp

user.setUsername(fieldMap.get("username"));
user.setEmail(fieldMap.get("email"));
user.setImageName(binaryMap.get("pic").getImageName());
user.setImageUrl(binaryMap.get("pic").getImageUrl());
req.setAttribute("user", user);
req.getRequestDispatcher("/show.jsp").forward(req, resp);

然后我们在网页中显示:

<body>注册名称:${user.username}</br>注册邮箱:${user.email}</br>头像原始名称:${user.imageName}</br>头像:<img src="${user.imageUrl}">
</body>

结果如下:

完整代码

UploadServlet.java:

package com.cherry.upload;import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;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 javax.xml.transform.Templates;import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FilenameUtils;@WebServlet("/upload")
public class UploadServlet extends HttpServlet {private static final long serialVersionUID = 3067915922682828536L;protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {try {User user = new User();          //封装普通表单的数据//key:参数名称//value:参数的值Map<String, String> fieldMap = new HashMap<>();Map<String, CFile> binaryMap = new HashMap<>();FileUtil.upload(req, fieldMap, binaryMap);//再从fieldMap中设置到User中System.out.println(fieldMap);System.out.println(binaryMap);user.setUsername(fieldMap.get("username"));user.setEmail(fieldMap.get("email"));user.setImageName(binaryMap.get("pic").getImageName());user.setImageUrl(binaryMap.get("pic").getImageUrl());req.setAttribute("user", user);req.getRequestDispatcher("/show.jsp").forward(req, resp);System.out.println(user);} catch (LogicException e) {e.printStackTrace();String errorMsg = e.getMessage();req.setAttribute("errorMsg", errorMsg);req.getRequestDispatcher("/input.jsp").forward(req, resp);}}
}

FileUtil.java

package com.cherry.upload;import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FilenameUtils;import lombok.Value;public class FileUtil {//允许接收的图片类型private static final String ALLOWED_IMAGE_TYPE = "jpg;png;jpeg;gif;pdf";public static void upload(HttpServletRequest req, Map<String, String> fieldMap,Map<String, CFile> binaryMap) {//检查是否有文件上传请求:请求方法为POST,请求编码为multipart/form-databoolean isMultipart = ServletFileUpload.isMultipartContent(req);if (!isMultipart) {return;}try {//1.创建FileItemFactory对象//FileItemFactory是用来创建FileItem对象的//FileItem对象相当于form表单中的表单控件的封装DiskFileItemFactory factory = new DiskFileItemFactory();//设置缓存大小//factory.setSizeThreshold(20 * 1024);//设置临时目录//factory.setRepository(repository);//2.创建一个新的文件上传处理程序(文件上传处理器)ServletFileUpload upload = new ServletFileUpload(factory);//设置单个文件上传的大小限制upload.setFileSizeMax(2 * 1024 * 1024); //2M//设置所有请求的总数据的大小upload.setSizeMax(4 * 1024 * 1024); //10M//3.解析请求List<FileItem> items = upload.parseRequest(req);/*for (int i = 0; i < items.size(); i++) {System.out.println(items.get(i));}*///4.迭代出每一个FileItemfor (FileItem item : items) {//获取表单属性名称String fieldName = item.getFieldName();if (item.isFormField()) {//普通表单控件String value = item.getString("UTF-8");//获取当前普通表单控件的参数值System.out.println(fieldName + "-" + value);fieldMap.put(fieldName, value);} else {//当前上传文件的mime类型/*String mimeType = req.getServletContext().getMimeType(FilenameUtils.getName(item.getName()));System.out.println(mimeType);*/String[] allowedImageType = ALLOWED_IMAGE_TYPE.split(";");String ext = FilenameUtils.getExtension(item.getName()).toLowerCase();List<String> list = Arrays.asList(allowedImageType);//上传文件类型不合法if (!list.contains(ext)) {throw new LogicException("上传文件类型错误,请上传图片文件...");}//上传文件控件System.out.println(fieldName + "-" + FilenameUtils.getName(item.getName()));//字段名-上传的文件名String fileName = UUID.randomUUID().toString() + "."+ FilenameUtils.getExtension(item.getName());String dir = req.getServletContext().getRealPath("/upload");item.write(new File(dir, fileName));//把二进制文件写到哪个文件中//是否存储在内存中System.out.println(item.isInMemory());binaryMap.put(fieldName, new CFile("/upload/" + fileName,FilenameUtils.getName(item.getName())));}}} catch (FileSizeLimitExceededException e) {throw new LogicException("文件大小超过2M,请重试", e);} catch (SizeLimitExceededException e) {throw new LogicException("该次请求信息量超过10M,请重试", e);} catch (LogicException e) {throw e;} catch (Exception e) {e.printStackTrace();}}
}

User.java:

package com.cherry.upload;import lombok.Data;@Data
public class User {private String username;private String email;private String imageUrl;//图片路径private String imageName;//图片原始名称
}

CFile.java:

package com.cherry.upload;import lombok.Data;@Data
public class CFile {private String imageUrl;//图片路径private String imageName;//图片原始名称CFile(String imageUrl, String imageName) {this.imageName = imageName;this.imageUrl = imageUrl;};
}

input.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body><h3>文件上传</h3><span style="color: red">${errorMsg}</span><form action="/upload" method="POST" enctype="multipart/form-data">账号:<input type="text" name="username"/><br/>邮箱:<input type="text" name="email"/><br/>头像:<input type="file" name="pic" accept="image/*"/><br/><input type="submit" value=" 注册 "/><br/></form>
</body>
</html>

show.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!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>注册名称:${user.username}</br>注册邮箱:${user.email}</br>头像原始名称:${user.imageName}</br>头像:<img src="${user.imageUrl}">
</body>
</html>

二、文件下载

没什么好说的,需要注意的是,下载资源不能暴露在 WEB-INF 外面,必须通过 Servlet 响应下载,直接上代码:

DownloadServlet.java

package com.cherry._02_download;import java.io.IOException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@WebServlet("/down")
public class DownloadServlet extends HttpServlet {private static final long serialVersionUID = -6406195121839970110L;protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {//权限检查等//1.获取被下载的资源文件名String fileName = req.getParameter("filename");System.out.println(fileName);if (hasLength(fileName)) {fileName = new String(fileName.getBytes("ISO-8859-1"), "UTF-8");}//2.从服务器中找到被下载资源的绝对路径String realPath = super.getServletContext().getRealPath("/WEB-INF/download/" + fileName);System.out.println(realPath);//①不要让浏览器打开文件,而是要弹出下载框并保存文件resp.setContentType("application/x-msdownload");//②设置下载文件的建议文件名String userAgent = req.getHeader("User-Agent");if (userAgent.contains("MSIE")) {//IEfileName = URLEncoder.encode(fileName, "UTF-8");} else {//非IEfileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");}resp.setHeader("Content-Disposition", "attachment; filename =" + fileName);//3.通过文件输出流将磁盘中的文件读取到程序中,然后输出响应到浏览器Files.copy(Paths.get(realPath), resp.getOutputStream());}private boolean hasLength(String str) {return str != null && "".equals(str.trim());}
}

download.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!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><h3>下载资源列表</h3><a href="/down?filename=Judy.zip">Judy.zip</a></br><a href="/down?filename=Tom猫.zip">Tom猫.zip</a></br>
</body>
</html>

JavaWeb世界(九):文件上传与下载相关推荐

  1. JavaWeb学习总结——文件上传和下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  2. JavaWeb -- Struts1 多文件上传与下载 DownloadAction, DispatchAction

    1. 多文件上传与下载 上传下载jsp: <%@ page language="java" import="java.util.*" pageEncodi ...

  3. .net fileupload批量上传可删除_【JavaWeb基础】文件上传和下载(修订版)

    前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 什么是文件上传? 文件上传就是把用户的信息保存起来. ...

  4. JavaWeb学习总结(五十)——文件上传和下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  5. JavaWeb 文件上传和下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  6. Java Web项目中遇到的文件上传与下载问题

    (转发自:https://www.cnblogs.com/xdp-gacl/p/4200090.html)   在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中 ...

  7. java web 文件上传和下载

     在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直 ...

  8. apache的开源工具common-fileupload实现文件上传和下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  9. JavaWeb:实现文件上传与下载

    JavaWeb:实现文件上传与下载 文件上传前端处理 本模块使用到的前端Ajax库为Axio,其地址为GitHub官网. 关于文件上传 上传文件就是把客户端的文件发送给服务器端. 在常见情况(不包含文 ...

  10. Javaweb之文件上传与下载

    Javaweb之文件上传与下载 1. 文件上传下载概述 1.1. 什么是文件上传下载 所谓文件上传下载就是将本地文件上传到服务器端,从服务器端下载文件到本地的过程.例如目前网站需要上传头像.上传下载图 ...

最新文章

  1. C# 中对COOKIES的操作
  2. 我今天的收获,必备stadio 插件
  3. [Diary][pic]毕业聚餐-笑容灿烂
  4. 嵌入式Linux系统中的.lds链接脚本基础
  5. 如何让鼠标跑不出来_洗衣机常年不清洗脏过马桶,教你一窍门,脏东西自己跑出来...
  6. Python验证和可视化冰雹猜想、角谷猜想、考拉兹猜想
  7. Oracle EBS 两个严重漏洞可导致企业金融记录遭篡改
  8. js获取窗口宽度高度
  9. vmWare配置静态ip-net模式
  10. 计算机硬盘转速多少比较好,电脑硬盘的转速是什么意思?越快就越好么?
  11. 【数据挖掘】从“文本”到“知识”:信息抽取(Information Extraction)
  12. 计算机管理器鼠标不见了怎么办,电脑的鼠标光标消失了怎么回事?
  13. 90年代自学C,独立研发中文编辑器和输入法,被称小说圈中的Geek,你一定不知道这样的王小波!
  14. 读《所谓情商高,就是会说话》笔记
  15. 【ESP 保姆级教程】疯狂毕设篇 —— 案例:基于物联网的GY906红外测温门禁刷卡系统
  16. windows 10 git bash 提速方法
  17. Caffeine一级缓存介绍和应用
  18. 最新30个漂亮的个人作品集网页设计案例
  19. HGOI 20190821 慈溪一中互测
  20. 扇贝编程python认知课_‎扇贝编程-人人能学会的python课 in de App Store

热门文章

  1. 使用C#对Word进行读写、搜索、插入图片等操作
  2. 关于去耦电容和旁路电容
  3. IIS10(WinServer2019自带)如何限制网站的流量带宽
  4. 五险一金都是指什么--摘录
  5. STM32使用EMWin实现中文字体显示
  6. 南华大学计算机专业研究生导师,南华大学计算机科学与技术学院研究生导师简介-刘朝晖...
  7. python用turtle输入数字_Python02 标准输入输出、数据类型、变量、随记数的生成、turtle模块详解...
  8. 大厂面试常考的前端算法面试题,建议尽早学会
  9. linux下赋予普通用户root权限
  10. 【深度学习原理】神经网络结构 符号约定