上传和下载
1.文件上传原理:将表单的内容以二进制的方式上传到后台,用流的读取和写入.
1.1:表单的上传方式:method=“post”
1.2:表单的以二进制编码方式上传内容:enctype=“multipart/form-data”
1.3:表单上传文件:
2.commons-fileupload:是apach公司开源项目,专门用来实现文件.
2.1:导包:commons-fileupload-1.3.1.jar 和commons-io-2.4.jar
2.2:常用接口和类:
2.2.1:DiskFileItemFactory解析器工厂类
常用方法:
setRepository();//设置上传文件临时仓库
setSizeThreshold();//设置上传临时仓库大小
2.2.2:ServletFileUpload解析器类
常用方法:
isMultipartContent(request) //静态方法,判断请求上传的内容是否是二进制
setFileSizeMax(fileSizeMax);//设置单个文件最大上传大小
setSizeMax(sizeMax);//设置上传总文件的大小
parseRequest(request);//解析上传表单元素
2.2.3:FileItem表单元素类
常用方法:
isFormField();//判断是否是普通表单元素(除了文件域元素)
getFieldName();//获得普通表单name属性名
getString(“utf-8”);//获得普通表单value属性值
getName();//获得上传的文件名
write(上传后的路径+文件名);//文件上传的方法
3.解决文件上传重名:
3.1:UUID+原文件名
3.2:系统时间+原文件名
3.3:UUID+系统时间+原文件名
4.单个文件上传:
eg:/**
* 实现common-fileupload上传
* 1.解决上传文件大小限制
* 2.限制上传文件类型
* 3.上传后文件重名
*/
@WebServlet("/UploadServlet1")
public class UploadServlet1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {
//设置响应内容类型和编码
response.setContentType("text/html;charset=utf-8");
//设置请求编码
request.setCharacterEncoding("utf-8");
//1.创建解析器工厂对象
DiskFileItemFactory factory=new DiskFileItemFactory();
//2.用解析器工厂对象作为参数创建解析器
ServletFileUpload sfu=new ServletFileUpload(factory);
//设置单个文件上传的大小
sfu.setFileSizeMax(1024*20);
//3.判断表单是否是以二进制的方式上传
if (ServletFileUpload.isMultipartContent(request)){
try {
//4.用解析器对象来解析表单元素
List<FileItem> fs=sfu.parseRequest(request);
//5.遍历解析出的表单元素
for (FileItem f:fs){
if (f.isFormField()){//普通表单
//获得普通表单的name属性名
String fieldName=f.getFieldName();
//获得普通表单的value属性值
String fieldValue=f.getString("utf-8");
System.out.println("name属性名:"+fieldName+",value属性值:"+fieldValue);
}else{//文件域表单
//获得上传的文件名
String fileName=f.getName();
//限制上传文件类型
if (fileName.endsWith(".jpg")||fileName.endsWith(".png")){
//获得上传路径
String path=request.getServletContext().getRealPath("upload");
//解析文件名上传重名问题
//第一种:uuid+"#"+fileName
fileName= UUID.randomUUID()+"#"+fileName;
//第二种:系统时间+"#"+fileName
//fileName=System.nanoTime()+"#"+fileName;
//第三种:uuid+系统时间+"#"+fileName00
//第四种:根据文件名算出子文件夹名,根据文件名调用hashcode进行位与运算,再右移4,
// 作用将文件名调用hash算法进行打散生成子文件夹
String childPath=String.valueOf(((fileName.hashCode()&0xf0)>>4));
//上传的文件路径
File path1=new File(path,childPath);
//如果上传的路径不存在就创建目录再上传
if (!path1.exists()){
path1.mkdirs();
}
//调用文件上传的方法
//f.write(new File(path1,fileName));
//用工具类实现文件上传
IOUtils.copy(f.getInputStream(),new FileOutputStream(new File(path1,fileName)));
response.getWriter().write("上传成功!");
}else{
response.getWriter().write("你上传的文件类型有误,只支持上传.jpg和.png的文件");
}
}
}
}catch (FileUploadBase.FileSizeLimitExceededException e1){
response.getWriter().write("你上传的文件的大小超过20K,上传失败!");
}catch (Exception e) {
e.printStackTrace();
}
}else{
response.getWriter().write("上传表单编码有误!");
}
}
}
5.用commons-fileupload上传完整表单
eg:/**
* 带头像的完整表单的注册(上传)
*/
@WebServlet("/UploadServlet2")
public class UploadServlet2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//1.创建解析器工厂对象
DiskFileItemFactory factory=new DiskFileItemFactory();
//2.用解析器工厂对象作为参数创建解析器
ServletFileUpload sfu=new ServletFileUpload(factory);
//3.判断整个表单是否是以二进制的方式上传
if (ServletFileUpload.isMultipartContent(request)){
//声明一个学生对象,用来接收请求中数据
Student stu1=new Student();
//获得上传文件路径
File path=new File(request.getServletContext().getRealPath("upload"));
//判断上传的路径是否存在,不存在就创建
if (!path.exists()){
path.mkdirs();
}
try {
//获得用户的反射对象
Class clazz=Class.forName("com.qf.day48.entity.Student");
//获得表单的name属性名,前提name属性名与用户类中属性名一一对应
String fieldName=null;
//获得表单的value属性值或图片上传路径名+文件名
String fieldValue=null;
//4.用解析器对象解析上传表单每个表单元素
List<FileItem> fs=sfu.parseRequest(request);
for (FileItem f:fs){
if (f.isFormField()){//普通表单
//获得表单的name属性名,前提name属性名与用户类中属性名一一对应
fieldName=f.getFieldName();
//获得表单的value属性值
fieldValue=f.getString("utf-8");
}else{//文件表单
//表单name属性值,前提name属性名与用户类中属性名一一对应
fieldName=f.getFieldName();
//获得上传的文件名
String fileName=f.getName();
//判断上传文件的格式
if (fileName.endsWith(".jpg")||fileName.endsWith(".png")||fileName.endsWith(".gif")){
//对文件名处理下,防止重名
fileName= UUID.randomUUID()+"#"+fileName;
//上传文件
f.write(new File(path,fileName));
//上传的路径+文件名
fieldValue=path.getPath()+File.separator+fileName;
}else{
response.getWriter().write("上传图像格式有误!");
}
}
//获得当前属性
Field field1=clazz.getDeclaredField(fieldName);
//设置属性访问权限
field1.setAccessible(true);
//判断当前对象这个属性是否有值,如果有就拼接
if (field1.get(stu1)==null){
//用属性反射对象给实例对象设置属性值
field1.set(stu1,fieldValue);
}else{//防止表单name属性名相同时,value值覆盖
//用属性反射对象给实例对象设置属性值
field1.set(stu1,field1.get(stu1)+","+fieldValue);
}
}
System.out.println(stu1);
//省略将学生对象数据添加到数据步骤
response.getWriter().write("注册成功");
} catch (Exception e) {
e.printStackTrace();
}
}else{
response.getWriter().write("上传编码有误!");
}
}
}
6.Servlet3.0及以后支持文件上传:将表单以多部分上传的.
注意::Part类代表从 multipart/form-data格式的 POST请求中接收到的一个部分或表 单项。每个 part都可 通过 Part.getInputStream方法访问头部,相关的内容 类型和内容。
对于表单数据的 Content-Disposition,即使没有文件名,也可使用 part 的名 称通过HttpServletRequest 的 getParameter和 getParameterValues方法得 到 part的字符值。
6.1:Servlet3.0实现上传多个文件.
eg:/**
* Sevlet3.0上传,支持将表单以多部分上传,每个部分part
* 1.对上传的文件作大小限制
* 2.对上传的文件作类型限制
* 3.解决上传的文件的重名
*/
@WebServlet("/UploadServlet3")
@MultipartConfig()//支持表单上传
public class UploadServlet3 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//获得上传的路径
File path=new File(request.getServletContext().getRealPath("upload"));
if (!path.exists()){
path.mkdirs();
}
//接收表单上传的多部分
Collection<Part> parts=request.getParts();
//遍历上传的每个部分(一个表单项)
for (Part p:parts){
//判断每个上传的部分有没有超过上传的大小限制
if(p.getSize()>1024*20){
response.getWriter().write("你上传的文件超过20K,上传失败<br/>");
continue;
}
//获得上传头部
String headContent= p.getHeader("Content-Disposition");
//从上传的头部获得文件名
String fileName=headContent.substring(headContent.lastIndexOf("=")+2,headContent.length()-1);
System.out.println("****"+fileName);
//判断上传的文件类型
if (fileName.endsWith(".jpg")||fileName.endsWith(".png")){
//防止上传的文件重名
fileName= UUID.randomUUID()+"#"+fileName;
//上传文件
p.write(path.getPath()+File.separator+fileName);
response.getWriter().write("上传成功!<br/>");
}else{
response.getWriter().write("上传文件类型有误,上传失败!<br/>");
}
}
}
}
6.2:Servlet3.0上传完整的表单,包括文件
eg:/**
* 用servlet3.0来实现上传整个表单,将表单的每个表单项以part方式提交
*/
@WebServlet("/UploadServlet4")
@MultipartConfig()//注解表示要Servlet3.0进行上传
public class UploadServlet4 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//统一设置编码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//获得上传路径
File path=new File(request.getServletContext().getRealPath("upload"));
if (!path.exists()){
path.mkdirs();
}
//声明用户对象,用来存数据
Student stu2=new Student();
try {
/*1.上传三个图像文件,并将图像上传地址存在用户对象中*/
//上传,并得到上传路径+文件名
String img1Path = fileUpload1("img1", path, request,response);
//将当前路径路径+文件名存在学生对象中
stu2.setImg1(img1Path);
//上传,并得到上传路径+文件名
String img2Path=fileUpload1("img2",path, request,response);
//将当前路径路径+文件名存在学生对象中
stu2.setImg2(img2Path);
//上传,并得到上传路径+文件名
String img3Path=fileUpload1("img3",path, request,response);
//将当前路径路径+文件名存在学生对象中
stu2.setImg3(img3Path);
/*2.获得上传普通表单的值*/
stu2.setName(request.getParameter("name"));
stu2.setPassword(request.getParameter("password"));
stu2.setCity(request.getParameter("city"));
stu2.setEmail(request.getParameter("email"));
stu2.setSex(request.getParameter("sex"));
stu2.setHobby(Arrays.toString(request.getParameterValues("hobby")));
System.out.println("###"+stu2);
//省略业务层和dao层对数据库的操作
response.getWriter().write("注册成功!");
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 获得每个上传的部分实现文件上传
* @param name
* @param path
* @param response
* @throws Exception
* @return String 上传后的文件路径名+文件名
*/
public String fileUpload1(String name,File path,HttpServletRequest request,HttpServletResponse response) throws Exception {
//通过name名称获得指定部分
Part p = request.getPart(name);
//判断每个上传文件的大小
if (p.getSize()>1024*20) {
response.getWriter().write("上传的头像超过20K,上传失败<br/>");
return null;
}else {
//获得当前这部分上传的头部信息
String headContent=p.getHeader("Content-Disposition");
System.out.println("headContent:"+headContent+","+p.getName());
//获得当前这部分上传的文件名
String fileName=headContent.substring(headContent.lastIndexOf("=")+2,headContent.length()-1);
if (fileName.endsWith(".jpg")||fileName.endsWith(".png")||fileName.endsWith(".gif")){
//防止文件重名
fileName= UUID.randomUUID()+"#"+fileName;
//上传
p.write(path.getPath()+File.separator+fileName);
response.getWriter().write("上传成功");
//将上传图像路径及文件名存在学生对象中
return path.getPath()+File.separator+fileName;
}else{
response.getWriter().write("上传的头像格式有误,上传失败");
return null;
}
}
}
}
7.文件下载
7.1:图片下载:选中图片右键另存为->保存到指定路径.
7.2:文件/压缩包下载:
<a href="upload/常用图片.zip">常用图片.zip</a>
<a href="upload/48.2单个文件上传的限制.mp4">48.2单个文件上传的限制.mp4</a>
7.3:中文名文件下载:原理流的读写
eg:<a href="DownloadServlet?fileName=刚哥.txt">刚哥.txt</a>
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置响应内容类型和编码
response.setContentType("text/html;charset=utf-8");
//设置请求编码
request.setCharacterEncoding("utf-8");
//获得下载的文件名
String fileName=request.getParameter("fileName");
//获得下载的文件路径
String path=request.getServletContext().getRealPath("upload");
//设置响应头部信息,如果文件名是中文,浏览器会解码,为了抵消浏览器的解码,我先编码
response.setHeader("Content-Disposition","attachment;fileName="+ URLEncoder.encode(fileName,"utf-8"));
//下载的本质将文件从服务器端读取,写入给客户端
IOUtils.copy(new FileInputStream(path+ File.separator+fileName),response.getOutputStream());
}