JavaWeb世界(九):文件上传与下载
一、文件上传
先创建工程,写一个简易的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 可以用来更改选择文件的类型(为图片类型),效果如下:
要点:
- 上传控件所在的表单method必须为 POST,因为GET方式传入的数据大小不能超过2KB,而POST大小没有限制。
- 上传控件的类型为 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世界(九):文件上传与下载相关推荐
- JavaWeb学习总结——文件上传和下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...
- JavaWeb -- Struts1 多文件上传与下载 DownloadAction, DispatchAction
1. 多文件上传与下载 上传下载jsp: <%@ page language="java" import="java.util.*" pageEncodi ...
- .net fileupload批量上传可删除_【JavaWeb基础】文件上传和下载(修订版)
前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 什么是文件上传? 文件上传就是把用户的信息保存起来. ...
- JavaWeb学习总结(五十)——文件上传和下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...
- JavaWeb 文件上传和下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...
- Java Web项目中遇到的文件上传与下载问题
(转发自:https://www.cnblogs.com/xdp-gacl/p/4200090.html) 在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中 ...
- java web 文件上传和下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直 ...
- apache的开源工具common-fileupload实现文件上传和下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...
- JavaWeb:实现文件上传与下载
JavaWeb:实现文件上传与下载 文件上传前端处理 本模块使用到的前端Ajax库为Axio,其地址为GitHub官网. 关于文件上传 上传文件就是把客户端的文件发送给服务器端. 在常见情况(不包含文 ...
- Javaweb之文件上传与下载
Javaweb之文件上传与下载 1. 文件上传下载概述 1.1. 什么是文件上传下载 所谓文件上传下载就是将本地文件上传到服务器端,从服务器端下载文件到本地的过程.例如目前网站需要上传头像.上传下载图 ...
最新文章
- C# 中对COOKIES的操作
- 我今天的收获,必备stadio 插件
- [Diary][pic]毕业聚餐-笑容灿烂
- 嵌入式Linux系统中的.lds链接脚本基础
- 如何让鼠标跑不出来_洗衣机常年不清洗脏过马桶,教你一窍门,脏东西自己跑出来...
- Python验证和可视化冰雹猜想、角谷猜想、考拉兹猜想
- Oracle EBS 两个严重漏洞可导致企业金融记录遭篡改
- js获取窗口宽度高度
- vmWare配置静态ip-net模式
- 计算机硬盘转速多少比较好,电脑硬盘的转速是什么意思?越快就越好么?
- 【数据挖掘】从“文本”到“知识”:信息抽取(Information Extraction)
- 计算机管理器鼠标不见了怎么办,电脑的鼠标光标消失了怎么回事?
- 90年代自学C,独立研发中文编辑器和输入法,被称小说圈中的Geek,你一定不知道这样的王小波!
- 读《所谓情商高,就是会说话》笔记
- 【ESP 保姆级教程】疯狂毕设篇 —— 案例:基于物联网的GY906红外测温门禁刷卡系统
- windows 10 git bash 提速方法
- Caffeine一级缓存介绍和应用
- 最新30个漂亮的个人作品集网页设计案例
- HGOI 20190821 慈溪一中互测
- 扇贝编程python认知课_扇贝编程-人人能学会的python课 in de App Store
热门文章
- 使用C#对Word进行读写、搜索、插入图片等操作
- 关于去耦电容和旁路电容
- IIS10(WinServer2019自带)如何限制网站的流量带宽
- 五险一金都是指什么--摘录
- STM32使用EMWin实现中文字体显示
- 南华大学计算机专业研究生导师,南华大学计算机科学与技术学院研究生导师简介-刘朝晖...
- python用turtle输入数字_Python02 标准输入输出、数据类型、变量、随记数的生成、turtle模块详解...
- 大厂面试常考的前端算法面试题,建议尽早学会
- linux下赋予普通用户root权限
- 【深度学习原理】神经网络结构 符号约定