java web项目上传文件失败 (javaweb文件上传到ftp服务器)

javaweb文件上传教程,javaweb文件如何导出

便携式计算机和文件

一、如何保*务证**器服的安全(关键的)

1、一般来说,都喜欢把文件放到工程目录下,然后通过url直接请求静态资源。(不安全的)

解决:我们要把上传的文件转移至通过静态资源访问不到的地方(放到WEB-INF下)

举例:既不是放在WEB-INF,也不是用nginx,我们自己指定一个文件服务器存储目录

二、中文乱码问题

首先要统一编码,页面和服务器工程编码要统一

用过滤器处理字符,达到统一编码的目的

跨域问题,过滤器可以使用

三、重名文件被覆盖的问题

uuid

文件名+时间是不可取的(因为解决不了并发问题),时间戳+随机数

四、如何分目录存储上传的文件

根据具体业务来分文件夹。可以每天生成一个文件夹(为什么?)

操作系统存储文件,每个文件夹存储文件的数据量是有极限的

举例:先按用户、然后再按日期

五、限制用户上传的文件类型(不要简单地判断文件后缀)

实际上是要获取ContentType(),来判断这个文件类型

六、限制用户上传文件的大小(服务器端,不要等到上传完了才判断)

抓取异常信息来判断

FileSizeLimitException

七、删除临时文件的问题

临时文件对于我们的实际数据是没有什么意义的,它就相当于上传时的缓存

那么,上传完了以后,临时文件可以删掉,可以节省出一下磁盘空间

一定要在关闭流之后再删

八、多文件上传的问题

主要解决,没有文件上传,如何去判断

文件个数限制

九、如何监听上传进度(我相信很多人都没有去想办法解决过)

添加ServletUpload监听,重写update方法

实现接口ProgressListener(从服务端来监听文件上传进度,客户端是用定时器去不断 地请求后台,获取上传进度)

import java.io.File;

import java.io.IOException;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Iterator;

import java.util.List;

import java.util.UUID;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItem;

import org.apache.commons.fileupload.disk.DiskFileItemFactory;

import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class UploadServlet extends HttpServlet {

private static final long serialVersionUID = -3100028422371321159L;

private boolean isAllowed;

private String upFileName;

//定义合法后缀名的数组

private String[] allowedExtName=new String[]

{"zip","rar",//压缩文件

"txt","doc","wps","docx","java",//文本

"xls","xlsx",//表格

"ppt","pptx",//幻灯片

"pdf",//pdf

"jpg","jpeg","bmp","gif","png"//图片

};

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doPost(request, response);

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//设置编码格式为utf-8

request.setCharacterEncoding("utf-8");

response.setCharacterEncoding("utf-8");

//获取session,保存进度和上传结果,上传开始为nok,当为Ok表示上传完成

HttpSession session=request.getSession();

session.setAttribute("result", "nok");

session.setAttribute("error", "");

String error="";

upFileName="";

isAllowed=false;

//给上传的文件设一个最大值,这里是不得超过100MB

int maxSize=100*1024*1024;

//创建工厂对象和文件上传对象

DiskFileItemFactory factory=new DiskFileItemFactory();

ServletFileUpload upload=new ServletFileUpload(factory);

//创建上传监听器和设置监听器

UploadListener listener=new UploadListener();

session.setAttribute("LISTENER", listener);

upload.setProgressListener(listener);

//上传路径

String path = request.getSession().getServletContext().getRealPath("/upload");

String requestPath = request.getSession().getServletContext().getContextPath()+"/upload";

File dirFile =new File(path); //System.out.println(request.getSession().getServletContext().getContextPath());

//如果文件夹不存在则创建

if (!dirFile .exists() && !dirFile .isDirectory())

{

dirFile .mkdir();

}

//根据日期创建文件夹,保存到对应日期的文件夹下

Date date=new Date();

SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMdd");

String subDirName=sdf.format(date);

File subDirFile=new File(path+"/"+subDirName);

if (!subDirFile .exists() && !subDirFile .isDirectory())

{

subDirFile .mkdir();

}

try {

//解析上传请求

List<FileItem> items=upload.parseRequest(request);

Iterator<FileItem> itr=items.iterator();

while(itr.hasNext()){

FileItem item=(FileItem)itr.next();

//判断是否为文件域

if(!item.isFormField()){ if(item.getName()!=null&&!item.getName().equals("")){

//获取上传文件大小和文件名称

long upFileSize=item.getSize();

String fileName=item.getName();

//获取文件后缀名

String[] splitName=fileName.split("\\.");

String extName=splitName[splitName.length-1];

//检查文件后缀名

for(String allowed:allowedExtName)

{

if(allowed.equalsIgnoreCase(extName))

{

isAllowed=true;

}

}

if(!isAllowed){

error="上传文件格式不合法!";

break;

}

if(upFileSize>maxSize){

error="您上传的文件太大了,请选择不超过100MB的文件!";

break;

}

//此时文件暂存在服务器的内存中,构造临时对象

File tempFile=new File(makeFileName(fileName));

//指定文件上传服务器的目录及文件名称

File file=new File(path+"/"+subDirName+"/",tempFile.getName());

item.write(file);//第一种写文件方法

upFileName=requestPath+"/"+subDirName+"/"+tempFile.getName();

if(upFileName.equals("")){

error="没选择上传文件!";

}

System.out.println(upFileName);

/*//构造输入流读文件 第二种写文件方法

InputStream is=item.getInputStream();

int length=0;

byte[] by=new byte[1024];

FileOutputStream fos=new FileOutputStream(file);

while((length=is.read(by))!=-1){

fos.write(by, 0, length);

//Thread.sleep(10);

}

fos.close();

//Thread.sleep(1000);*/

}else{

error="没选择上传文件!";

}

}

}

} catch (Exception e) {

e.printStackTrace();

error="上传文件出现错误:"+e.getMessage();

}

if(!error.equals("")){

System.out.println(error);

session.setAttribute("error", error);

}else{

session.setAttribute("result", "OK");

session.setAttribute("filename",upFileName);

}

}

/**

* 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名

* @param filename 原文件名

* @return 生成的唯一文件名

*/

private String makeFileName(String filename){

return UUID.randomUUID().toString() + "_" + filename;

}

}

其中需要引入commons-fileupload-1.3.1.jar,commons-io-2.4.jar 上传过程中,我们需要实时获取上传进度等信息,引入的库里为我们添加了一个ProgressListener接口,我们再写一个类实现这个接口,上面类中添加该接口

//创建工厂对象和文件上传对象
 DiskFileItemFactory factory=new DiskFileItemFactory();
 ServletFileUpload upload=new ServletFileUpload(factory);
 //创建上传监听器和设置监听器
 UploadListener listener=new UploadListener();
 session.setAttribute("LISTENER", listener);
 upload.setProgressListener(listener);

下面是这个监听类的具体实现代码

import org.apache.commons.fileupload.ProgressListener;
public class UploadListener implements ProgressListener{
 private volatile long 
 bytesRead = 0L,//上传的字节数
 contentLength = 0L,//总字节数
 item = 0L; 
 public UploadListener() 
 {
 super();
 }
 @Override
 public void update(long aBytesRead, long aContentLength, int anItem) {
 bytesRead = aBytesRead;
 contentLength = aContentLength;
 item = anItem;
 }
 public long getBytesRead() 
 {
 return bytesRead;
 }
 public long getContentLength() 
 {
 return contentLength;
 }
 public long getItem() 
 {
 return item;
 }
}

十、如何避免已经上传的文件重复上传到服务器

计算文件的 MD5 值,文件的MD5值可以代表一个文件的唯一标示,如果两个文件的MD5值相等,可以认为文件是一致的; (已上传的文件的md5的值可以存储到数据库,每上传一个文件的时候对比下已上传的文件md5有没有在数据库中存在,上传完成再保存md5值,删除文件去删除数据库中的MD5值就行了)

import java.io.File;
import java.io.FileInputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
public class FileDigest {
 /**
 * 获取单个文件的MD5值!
 * @param file
 * @return
 */
 public static String getFileMD5(File file) {
 if (!file.isFile()){
 return null;
 }
 MessageDigest digest = null;
 FileInputStream in=null;
 byte buffer[] = new byte[1024];
 int len;
 try {
 digest = MessageDigest.getInstance("MD5");
 in = new FileInputStream(file);
 while ((len = in.read(buffer, 0, 1024)) != -1) {
 digest.update(buffer, 0, len);
 }
 in.close();
 } catch (Exception e) {
 e.printStackTrace();
 return null;
 }
 BigInteger bigInt = new BigInteger(1, digest.digest());
 return bigInt.toString(16);
 }
 /**
 * 获取文件夹中文件的MD5值
 * @param file
 * @param listChild ;true递归子目录中的文件
 * @return
 */
 public static Map<String, String> getDirMD5(File file,boolean listChild) {
 if(!file.isDirectory()){
 return null;
 }
 //<filepath,md5>
 Map<String, String> map=new HashMap<String, String>();
 String md5;
 File files[]=file.listFiles();
 for(int i=0;i<files.length;i++){
 File f=files[i];
 if(f.isDirectory()&&listChild){
 map.putAll(getDirMD5(f, listChild));
 } else {
 md5=getFileMD5(f);
 if(md5!=null){
 map.put(f.getPath(), md5);
 }
 }
 }
 return map;
 }
 public static void main(String[] args) {
 File file1 = new File("a.txt");
 File file2 = new File("b.txt");
 System.out.println(getFileMD5(file1).equals(getFileMD5(file2)));
 }
}

开发环境:

后台框架:SpringMVC

文件上传的客户端:HTML表单提交(不是jQuery插件,也不是Flash)

UI:BootStrap

读写分离,分摊到两台服务器上去(随着访问量的增加,数据库查询也越来越慢)

分表:数据行是有极限的(把一张表拆成多张表)

分库:按一定的规则把一个库分传给你多个库(服务器磁盘也是有限的)

考虑分布式存储方案(不管数据量怎么增加,我可以跟实际情况来调整)

数据多访问量达,加机器

访问量少,减机器

平均算法

10T数据

2台机器,5T,访问速度比较慢的

5 2T ,访问速度肯定会提升

10 1T,相当于是双十一的状态(阿里云服务器,出租)

MapReduce

map() 主要是用来计算数据如何平均地分配到集群下的每一台机器上去

reduce() 如何从集群服务器读取数据的

Hadoop、分布式文件存储框架

十一.文件*载下**

文件*载下**很简单,主要是*载下**时各大浏览器可能会出现文件名 乱码的问题,下面代码通过解码后重新编码基本上解决所有浏览器乱码问题

先说下*载下**代码的逻辑步骤

主要就是response设置*载下**时的响应头信息不设置,浏览器不知道你是在干啥

然后获取输入流

response获取输出流

输入流数据写入到输出流

刷新输出流

关闭流

 public void getDownLoad(String fileName, HttpServletRequest request, HttpServletResponse response) {
 response.reset();
 // response.setContentType("application/vnd.ms-excel;charset=utf-8");
 // 设置文件*载下**的格式
 // response.setContentType("application/x-excel");
 response.setContentType("application/octet-stream");
// response.setHeader("content-disposition", "attachment;
//filename*=utf-8'zh_cn'" + URLEncoder.encode(fileName, "UTF-8"));
// setFileDownloadHeader(response, fileName);
 String fileName2 = fileName;
 try {
 String userAgent = request.getHeader("User-Agent"); 
 byte[] bytes = userAgent.contains("MSIE") ? fileName.getBytes() : fileName.getBytes("UTF-8");
 // name.getBytes("UTF-8")处理safari的乱码问题 
 // 各浏览器基本都支持ISO编码 
 fileName = new String(bytes, "ISO-8859-1");
 // 文件名外的双引号处理firefox的空格截断问题 
 response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", fileName));
 //获取输入流 todo
 //获取输出流
 //输入流数据写入输出流
 //下面是伪代码 
 FileInputStream inputStream = new FileInputStream(file); 
 
 //3.通过response获取ServletOutputStream对象(out) 
 out = response.getOutputStream(); 
 
 int b = 0; 
 byte[] buffer = new byte[512]; 
 while (b != -1){ 
 b = inputStream.read(buffer); 
 //4.写到输出流(out)中 
 out.write(buffer,0,b); 
 } 
 inputStream.close(); 
 out.close(); 
 out.flush(); 
 } catch (UnsupportedEncodingException e1) {
 e1.printStackTrace();
 }
}