================================================================

注意:此使用jsp+servlet进行文件的上传与下载测试,以及在ssm框架中进行测试,其他的工具可以直接使用

如果使用框架,不需要配置springmvc的文件上传,因为源码和工具类相似,若配置,会导致读不到数据

<!--SpringMVC上传文件配置-->
<!-- <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
</bean> -->

================================================================

package common.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;

/**
* 文件上传,下载,比较内容是否相同等的工具类
* 支持多文件上传
* 支持多文件和表单内容同时上传
* 支持批量下载,批量下载是压缩后下载
*
* @author huangtao
* 2017年11月23日下午3:44:39
* FileTest
* @parameter
* TODO
*
*/
public class FileUtils {
//文件类型为所有类型
public static final String FILETYPE = "allfiles";
//默认不限制上传文件大小
public static final int UNLIMITEDFILESIZE = -1;
//默认总上传文件大小为10m
public static final int FILESMAXSIZE= 10*1024*1024;
//默认单个上传文件大小为5m
public static final int SINGLEFILEMAXSIZE= 5*1024*1024;
//默认上传文件缓存为10m
public static final int FILECACHE = 10*1024*1024;
//默认文件上传路径,绝对路径
public static final String ABSOLUTEPATH = "E:\\fileTest";
//默认文件临时上传路径,绝对路径
public static final String ABSOLUTETEMPPATH = "E:\\fileTest\\temp";
//默认相对路径
public static final String RELATIVEPATH = "\\upload";
//无参构造
private FileUtils() {

}
//指定总文件大小
public static List<String> upload(HttpServletRequest request,int maxSize){
return upload(request, ABSOLUTEPATH, maxSize, SINGLEFILEMAXSIZE, FILECACHE, FILETYPE , true);
}
//指定总文件大小,文件类型
public static List<String> upload(HttpServletRequest request,int maxSize,String fileType){
return upload(request, ABSOLUTEPATH, maxSize, SINGLEFILEMAXSIZE, FILECACHE, fileType , true);
}
//指定总文件大小,文件类型,单个文件大小(推荐使用)
public static List<String> upload(HttpServletRequest request,int maxSize,int singleFileMaxSize,String fileType){
return upload(request, ABSOLUTEPATH, maxSize, singleFileMaxSize, FILECACHE, fileType , true);
}
//指定总文件大小,文件类型,存储方式true,存在本地,false存在项目的相对路径
public static List<String> upload(HttpServletRequest request,int maxSize,String fileType,boolean flag){
if(flag){
return upload(request, ABSOLUTEPATH, maxSize, SINGLEFILEMAXSIZE, FILECACHE, fileType , true);
}else{
return upload(request, RELATIVEPATH, maxSize, SINGLEFILEMAXSIZE, FILECACHE, fileType , false);
}
}
//指定文件大小,存储方式true,存在本地,false存在项目的相对路径
public static List<String> upload(HttpServletRequest request,int maxSize,boolean flag){
if(flag){
return upload(request, ABSOLUTEPATH, maxSize, SINGLEFILEMAXSIZE, FILECACHE, FILETYPE , true);
}else{
return upload(request, RELATIVEPATH, maxSize, SINGLEFILEMAXSIZE, FILECACHE, FILETYPE , false);
}
}

/**
*
* 文件的下载
*
* 2017年11月22日下午11:40:22
* @param request
* @param response
* @param downloadFilePath 选择下载目标
* @param flag 判断从绝对路径还是相对路径下载,默认绝对路径
* @param List<String> fileNameList 文件名集合
* @parameter
* void
* 例如
* List<String> fileNameList = new ArrayList<String>();
* fileNameList.add("[drcilabo海外]旺旺等级银卡.xlsx");
* FileUtils.download(request, response, "E:\\fileTest",fileNameList,true);
*
*/
public static boolean download(HttpServletRequest request,
HttpServletResponse response, String downloadFilePath,List<String> fileNameList,boolean flag) {
boolean result = true;
try {
//作用是设置对客户端请求进行重新编码的编码。
request.setCharacterEncoding("UTF-8");
//作用是指定对服务器响应进行重新编码的编码。同时,浏览器也是根据这个参数来对其接收到的数据进行重新编码(或者称为解码)。
response.setCharacterEncoding("UTF-8");
//判断从绝对路径还是相对路径下载文件,默认绝对路径
if(flag){
downloadAbsoluePath(request,response,ABSOLUTEPATH,fileNameList,true);
}else{
downloadRelativePath(request,response,RELATIVEPATH,fileNameList,false);
}
} catch (Exception e) {
e.printStackTrace();
result = false;
return result;
}
return result;
}

/**
* 从绝对路径下载
*
* 2017年11月24日下午10:20:07
* @param request
* @param response
* @param downloadFilePath
* @param fileNameList
* @param flag
* @parameter
* void
* 例如
* List<String> fileNameList = new ArrayList<String>();
* fileNameList.add("[drcilabo海外]旺旺等级银卡.xlsx");
* FileUtils.download(request, response, "E:\\fileTest",fileNameList,true);
*/
public static void downloadAbsoluePath(HttpServletRequest request,
HttpServletResponse response, String downloadFilePath,List<String> fileNameList,boolean flag){
System.out.println("开始下载"+DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
try {
if(fileNameList == null){
System.out.println("文件名不能为空!");
return;
}
//开始压缩文件,把所有的文件压缩之后再返回出去一个压缩包
String compressFileName = compressFiles(downloadFilePath,fileNameList);
String fileName = downloadFilePath + "\\" + compressFileName;
fileName = fileName.replace("\\", "/");//统一分隔符格式
File file = new File(fileName);
//如果文件不存在
if (file == null || !file.exists()) {
String msg = "file not exists! -->" + fileName;
System.out.println(msg);
PrintWriter out = response.getWriter();
out.write(msg);
out.flush();
out.close();
return;
}
String suffix = null;
if (fileName.lastIndexOf(".") > -1) {
suffix = fileName.substring(fileName.lastIndexOf("."));
} else { //如果文件没有后缀名,不处理,直接跳过本次循环
System.out.println("文件没有后缀名");
return;
}
String fileType = suffix;
response.setContentType(fileType);
if (fileType == null) {
fileType = "application/octet-stream";
}
response.setContentType(fileType);
System.out.println("文件类型是:" + fileType);
String simpleName = fileName.substring(fileName.lastIndexOf("/")+1);
//如果设置成UTF-8会导致下载的文件名出现乱码,所以要设置为ISO8859-1
//可能对于不同的浏览器也有区别
String newFileName = simpleName;
// String newFileName = new String(simpleName.getBytes(), "ISO8859-1");
String userAgent = request.getHeader("user-agent").toLowerCase();
System.out.println(userAgent);
if (userAgent.contains("mise") || userAgent.contains("trident")) {
//针对IE
newFileName = URLEncoder.encode(simpleName, "UTF-8");
} else {
//针对其他浏览器
newFileName = new String(newFileName.getBytes("UTF-8"), "ISO8859-1");
}
response.setHeader("Content-disposition", "attachment;filename="+newFileName);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());byte[] buffer = new byte[1024];
int length = 0;

while ((length = bis.read(buffer)) != -1) {
bos.write(buffer, 0, length);
}
if (bos != null)
bos.close();
if (bis != null)
bis.close();
System.out.println("下载的文件为:"+simpleName);
//输出之后,删除生成的压缩的文件,不删除会产生越来越来的压缩文件
boolean delResult = delFile(fileName);
System.out.println("删除结果为-->"+delResult);
} catch (Exception e) {
System.out.println("下载出错"+DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
e.printStackTrace();
}
System.out.println("完成下载"+DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
}

/**
* 从相对路径下载
*
* 2017年11月24日下午10:19:50
* @param request
* @param response
* @param downloadFilePath
* @param fileNameList
* @param flag
* @parameter
* void
* 例如
* List<String> fileNameList = new ArrayList<String>();
* fileNameList.add("[drcilabo海外]旺旺等级银卡.xlsx");
* FileUtils.download(request, response, "\\upload",fileNameList,false);
*/
public static void downloadRelativePath(HttpServletRequest request,
HttpServletResponse response, String downloadFilePath,List<String> fileNameList,boolean flag){
System.out.println("开始下载"+DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
try {
if(fileNameList == null){
System.out.println("文件名不能为空!");
return;
}
//获取相对路径
String relativePath = request.getSession().getServletContext()
.getRealPath("/")
+ downloadFilePath;
//开始压缩文件,把所有的文件压缩之后再返回出去一个压缩包
String compressFileName = compressFiles(relativePath,fileNameList);
String fileName = relativePath + "\\" + compressFileName;
fileName = fileName.replace("\\", "/");//统一分隔符格式
File file = new File(fileName);
//如果文件不存在
if (file == null || !file.exists()) {
String msg = "file not exists! -->" + fileName;
System.out.println(msg);
PrintWriter out = response.getWriter();
out.write(msg);
out.flush();
out.close();
return;
}
fileName = fileName.replace("\\", "/");//统一分隔符格式
// String fileType = request.getSession().getServletContext()
// .getMimeType(fileName);
String suffix = null;
if (fileName.lastIndexOf(".") > -1) {
suffix = fileName.substring(fileName.lastIndexOf("."));
} else { //如果文件没有后缀名,不处理,直接跳过本次循环
System.out.println("文件没有后缀名");
return;
}
String fileType = suffix;
if (fileType == null) {
fileType = "application/octet-stream";
}
response.setContentType(fileType);
System.out.println("文件类型是:" + fileType);
String simpleName = fileName.substring(fileName.lastIndexOf("/")+1);
//如果设置成UTF-8会导致下载的文件名出现乱码,所以要设置为ISO8859-1
//可能对于不同的浏览器也有区别
String newFileName = simpleName;
// String newFileName = new String(simpleName.getBytes(), "ISO8859-1");
String userAgent = request.getHeader("user-agent").toLowerCase();
System.out.println(userAgent);
if (userAgent.contains("mise") || userAgent.contains("trident")) {
//针对IE
newFileName = URLEncoder.encode(simpleName, "UTF-8");
} else {
//针对其他浏览器
newFileName = new String(newFileName.getBytes("UTF-8"), "ISO8859-1");
}
response.setHeader("Content-disposition", "attachment;filename="+newFileName);

BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(
response.getOutputStream());

byte[] buffer = new byte[1024];
int length = 0;

while ((length = bis.read(buffer)) != -1) {
bos.write(buffer, 0, length);
}
if (bos != null)
bos.close();
if (bis != null)
bis.close();
} catch (Exception e) {
System.out.println("下载出错"+DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
e.printStackTrace();
}

System.out.println("完成下载"+DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
}

/**
* 压缩文件
*
* 2017年11月24日下午9:01:03
* @param downloadFilePath
* @param fileNameList
* @return
* @parameter
* String
*
*/
public static String compressFiles(String downloadFilePath,List<String> fileNameList) {
//生成的ZIP文件名为yyyyMMddHHmmss-Download
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
//定义压缩文件名,也可以指定生成的压缩文件的格式zip,rar
String tmpFileName = sf.format(new Date()) + "-Download.zip";
//定义压缩文件的全路径
String strZipPath = downloadFilePath + "\\" + tmpFileName;
byte[] buffer = new byte[1024];

try {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(strZipPath));
ZipOutputStream zipOut = new ZipOutputStream(bos);
ZipEntry ze = null;
//遍历文件
for(String fnl:fileNameList){
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(downloadFilePath + "\\" +fnl));
//注意,此处如果输入一个路径,会生成一个文件夹,里面存放的是所有的文件,若只传入文件名,则只有文件
ze = new ZipEntry(fnl);
zipOut.putNextEntry(ze);
//设置压缩文件内的字符编码,不然会变成乱码
zipOut.setEncoding("GBK");
int len;
while ((len = bis.read(buffer)) != -1) {
zipOut.write(buffer, 0, len);
}
bis.close();
}
zipOut.flush();
zipOut.close();
bos.close();
} catch (Exception e) {
System.out.println("压缩文件出错");
e.printStackTrace();
}
return tmpFileName;
}

/**
* 文件上传
*
* @param request HttpServletRequest
* @param relativeUploadPath 上传文件保存的相对路径,例如"upload/",注意,末尾的"/"不要丢了
* @param maxSize 上传的最大文件总尺寸,单位字节
* @param singleFileSize 上传的单个文件的最大尺寸,单位字节
* @param thresholdSize 最大缓存,单位字节
* @param fileTypes 文件类型,会根据上传文件的后缀名判断。<br>
* @param boolean flag 判断保存在绝对路径还是虚拟路径,存储路径true绝对,false相对
* 比如支持上传jpg,jpeg,gif,png图片,那么此处写成".jpg .jpeg .gif .png",<br>
* 也可以写成".jpg/.jpeg/.gif/.png",类型之间的分隔符是什么都可以,甚至可以不要,<br>
* 直接写成".jpg.jpeg.gif.png",但是类型前边的"."不能丢
* @return
* 例如
* List<String> filePaths = FileUtils.upload(request, "upload/",".xls .xlsx");
* 所有文件则ALLFILES
*/
public static List<String> upload(HttpServletRequest request, String uploadPath, int maxSize,int singleFileSize, int thresholdSize, String fileTypes, boolean flag) {
System.out.println("文件开始上传"+DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
// 设置字符编码
try {
//作用是设置对客户端请求进行重新编码的编码。
request.setCharacterEncoding("UTF-8");
//作用是指定对服务器响应进行重新编码的编码。同时,浏览器也是根据这个参数来对其接收到的数据进行重新编码(或者称为解码)。
//response.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
if(fileTypes == null || fileTypes.equals("")){
System.out.println("必须指定文件的后缀名,例如.docx或者.xlsx等。多个文件后缀名以空格隔开,如果是任意类型,请输入ALLFILES");
return null;
}
List<String> filePaths = new ArrayList<String>();
//保存文件在绝对路径
if(flag){
filePaths = saveFileAbsolutePath(request, uploadPath, maxSize,singleFileSize, thresholdSize, fileTypes);
//保存文件在相对路径
}else{
filePaths = saveFileRelativePath(request, uploadPath, maxSize,singleFileSize, thresholdSize, fileTypes);
}
System.out.println("文件上传结束"+DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
return filePaths;
}

//保存文件在相对路径
private static List<String> saveFileRelativePath(HttpServletRequest request,String relativeUploadPath, int maxSize,int singleFileSize, int thresholdSize, String fileTypes){
String tempPath = relativeUploadPath + "\\" + "temp"; // 临时文件目录
String serverPath = request.getSession().getServletContext().getRealPath("/").replace("\\", "/");
fileTypes = fileTypes.toLowerCase(); // 将后缀全转换为小写
//如果上传文件目录和临时目录不存在则自动创建(相对路径)
if (!new File(serverPath + relativeUploadPath).isDirectory()) {
new File(serverPath + relativeUploadPath).mkdirs();
}
if (!new File(serverPath + tempPath).isDirectory()) {
new File(serverPath + tempPath).mkdirs();
}
System.out.println("serverPath + relativeUploadPath"+serverPath + relativeUploadPath);
System.out.println("serverPath + tempPath"+serverPath + tempPath);
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(thresholdSize); // 最大缓存
factory.setRepository(new File(serverPath + tempPath));// 临时文件目录

ServletFileUpload upload = new ServletFileUpload(factory);
//监听文件上传进度
// upload.setProgressListener(new ProgressListener(){
// public void update(long pBytesRead, long pContentLength, int arg2) {
// System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);
// }
// });
//3、判断提交上来的数据是否是上传表单的数据
// if(!ServletFileUpload.isMultipartContent(request)){
// //按照传统方式获取数据
// System.out.println("传统数据!");
// return null;
// }
upload.setSizeMax(maxSize);// 设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
upload.setHeaderEncoding("UTF-8");//设置防止文件上传中文乱码
// 设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
upload.setFileSizeMax(singleFileSize);

List<String> filePaths = new ArrayList<String>();
//4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
List<FileItem> items;
try {
items = upload.parseRequest(request);
// 获取所有文件列表
for (FileItem item : items) {

// 获得文件名,文件名包括路径
if (!item.isFormField()) { // 如果是文件
// 文件名
String fileName = item.getName().replace("\\", "/");
//文件后缀名
String suffix = null;
if (fileName.lastIndexOf(".") > -1) {
suffix = fileName.substring(fileName.lastIndexOf("."));
} else { //如果文件没有后缀名,不处理,直接跳过本次循环
continue;
}

// 不包含路径的文件名
String SimpleFileName = fileName;
if (fileName.indexOf("/") > -1) {
SimpleFileName = fileName.substring(fileName
.lastIndexOf("/") + 1);
}

// 如果文件类型字符串中包含该后缀名,保存该文件
// 指定能够保存的文件的后缀
if (fileTypes.indexOf(suffix.toLowerCase()) > -1) {
// String uuid = UUID.randomUUID().toString();
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
String relativeFilePath = serverPath
+ relativeUploadPath + "\\" + sf.format(new Date())
// + " " + uuid + " " + SimpleFileName;
+ "-" + SimpleFileName;
item.write(new File(relativeFilePath));
filePaths.add(relativeFilePath);

}else if(fileTypes.indexOf(FileUtils.FILETYPE) > -1){
//任何文件都保存
// String uuid = UUID.randomUUID().toString();
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
String relativeFilePath = serverPath
+ relativeUploadPath + "\\" + sf.format(new Date())
// + " " + uuid + " " + SimpleFileName;
+ "-" + SimpleFileName;
item.write(new File(relativeFilePath));
filePaths.add(relativeFilePath);
}else{
//不指定后缀,任何文件都不保存
System.out.println("不符合任何格式的文件,上传失败");
}

}else{
//如果不是文件
String filename = item.getFieldName();
System.out.println(filename);
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return filePaths;
}

//保存文件在绝对路径
private static List<String> saveFileAbsolutePath(HttpServletRequest request, String absoluteUploadPath, int maxSize,int singleFileSize, int thresholdSize, String fileTypes){
fileTypes = fileTypes.toLowerCase(); // 将后缀全转换为小写
//如果上传文件目录和临时目录不存在则自动创建(绝对路径)
if (!new File(ABSOLUTEPATH).isDirectory()) {
new File(ABSOLUTEPATH).mkdirs();
}
if (!new File(ABSOLUTETEMPPATH).isDirectory()) {
new File(ABSOLUTETEMPPATH).mkdirs();
}
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(thresholdSize); // 最大缓存
factory.setRepository(new File(ABSOLUTETEMPPATH));// 临时文件目录

ServletFileUpload upload = new ServletFileUpload(factory);
//监听文件上传进度
// upload.setProgressListener(new ProgressListener(){
// public void update(long pBytesRead, long pContentLength, int arg2) {
// System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);
// }
// });
//3、判断提交上来的数据是否是上传表单的数据
// if(!ServletFileUpload.isMultipartContent(request)){
// //按照传统方式获取数据
// System.out.println("传统数据!");
// return null;
// }
upload.setSizeMax(maxSize);// 设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
upload.setHeaderEncoding("UTF-8");//设置防止文件上传中文乱码
// 设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
upload.setFileSizeMax(singleFileSize);

List<String> filePaths = new ArrayList<String>();
//4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
List<FileItem> items;
try {
items = upload.parseRequest(request);
// 获取所有文件列表
for (FileItem item : items) {

// 获得文件名,文件名包括路径
if (!item.isFormField()) { // 如果是文件
// 文件名
String fileName = item.getName().replace("\\", "/");
//文件后缀名
String suffix = null;
if (fileName.lastIndexOf(".") > -1) {
suffix = fileName.substring(fileName.lastIndexOf("."));
} else { //如果文件没有后缀名,不处理,直接跳过本次循环
continue;
}

// 不包含路径的文件名
String SimpleFileName = fileName;
if (fileName.indexOf("/") > -1) {
SimpleFileName = fileName.substring(fileName
.lastIndexOf("/") + 1);
}

// 如果文件类型字符串中包含该后缀名,保存该文件
// 指定能够保存的文件的后缀
if (fileTypes.indexOf(suffix.toLowerCase()) > -1) {
// String uuid = UUID.randomUUID().toString();
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
String absoluteFilePath = ABSOLUTEPATH + "\\" + sf.format(new Date())
// + " " + uuid + " " + SimpleFileName;
+ "-" + SimpleFileName;
item.write(new File(absoluteFilePath));
filePaths.add(absoluteFilePath);

}else if(fileTypes.indexOf(FileUtils.FILETYPE) > -1){
//任何文件都保存
// String uuid = UUID.randomUUID().toString();
SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
String absoluteFilePath = ABSOLUTEPATH + "\\" + sf.format(new Date())
// + " " + uuid + " " + SimpleFileName;
+ "-" + SimpleFileName;
item.write(new File(absoluteFilePath));
filePaths.add(absoluteFilePath);
}else{
//不指定后缀,任何文件都不保存
System.out.println("不符合任何格式的文件,上传失败");

}

}else{
//如果不是文件
String filename = item.getFieldName();
System.out.println(filename);
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return filePaths;
}

/**
* 根据字符是否相同来判断
*
* 判断两个文件的内容是否相同,文件名要用绝对路径
* @param fileName1 :文件1的绝对路径
* @param fileName2 :文件2的绝对路径
* @return 相同返回true,不相同返回false
*/
public static boolean isSameFileForChar(String filePath1,String filePath2){
//先判断是否是两个文件
File file1 = new File(filePath1);
File file2 = new File(filePath2);

//判断是否是文件,若有一个不是文件则返回false
if ((!file1.isFile())||(!file2.isFile())) {
System.out.println("至少有一个不是文件");
return false;
}

//判断文件大小
if(file1.length()!=file2.length()){
System.out.println("文件大小不一致");
return false;
}

FileInputStream fis1 = null;
FileInputStream fis2 = null;
try {
fis1 = new FileInputStream(filePath1);
fis2 = new FileInputStream(filePath2);

int len1 = fis1.available();//返回总的字节数
int len2 = fis2.available();//返回总的字节数

if (len1 == len2) {//长度相同,则比较具体内容
//建立两个字节缓冲区
byte[] data1 = new byte[len1];
byte[] data2 = new byte[len2];

//分别将两个文件的内容读入缓冲区
fis1.read(data1);
fis2.read(data2);

//依次比较文件中的每一个字节
for (int i=0; i<len1; i++) {
//只要有一个字节不同,两个文件就不一样
if (data1[i] != data2[i]) {
System.out.println("两个文件有字符不相同");
return false;
}
}
System.out.println("两个文件字符相同");
return true;
} else {
//长度不一样,文件肯定不同
System.out.println("文件大小不一致");
return false;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {//关闭文件流,防止内存泄漏
if (fis1 != null) {
try {
fis1.close();
} catch (IOException e) {
//忽略
e.printStackTrace();
}
}
if (fis2 != null) {
try {
fis2.close();
} catch (IOException e) {
//忽略
e.printStackTrace();
}
}
}
return false;
}

/**
* 计算文件的 MD5 值,用来比较文件是否相等
*
* 2017年11月23日上午10:45:47
* @param file
* @return
* @parameter
* String
*
*/
public static boolean isSameFileForMD5(String filePath1,String filePath2) {
//返回的结果
boolean result = false;
//存储md5的结果
BigInteger b1;
BigInteger b2;
//建立文件
File file1 = new File(filePath1);
File file2 = new File(filePath2);
//判断是否是文件,若有一个不是文件则返回false
if ((!file1.isFile())||(!file2.isFile())) {
System.out.println("至少有一个不是文件");
return result;
}
//判断文件大小
if(file1.length()!=file2.length()){
System.out.println("文件大小不一致");
return result;
}
try {
FileInputStream fis1 = new FileInputStream(file1);
FileInputStream fis2 = new FileInputStream(file2);

int len1 = fis1.available();//返回总的字节数
int len2 = fis2.available();//返回总的字节数

if(len1 != len2){
System.out.println("文件大小不一致");
//关闭流
fis1.close();
fis2.close();
return result;
}

MessageDigest digest1 = null;
MessageDigest digest2 = null;

//创建字节数据,用于将文件中的字符转换成字节
byte buffer1[] = new byte[1024];
byte buffer2[] = new byte[1024];

int length1;
int length2;

//创建MD5加密使用的对象
digest1 =MessageDigest.getInstance("MD5");
digest2 =MessageDigest.getInstance("MD5");
//读取文件
while ((length1 = fis1.read(buffer1)) != -1) {
//使用指定的 byte 数组更新摘要。
//使用指定的 byte 数组,从头开始按照MD5进行编码
digest1.update(buffer1, 0, length1);
}
while ((length2 = fis2.read(buffer2)) != -1) {
//使用指定的 byte 数组更新摘要。
//使用指定的 byte 数组,从头开始按照MD5进行编码
digest2.update(buffer2, 0, length2);
}
b1 = new BigInteger(1,digest1.digest());
b2 = new BigInteger(1,digest2.digest());
System.out.println(b1);
System.out.println(b2);
//关闭流
fis1.close();
fis2.close();
} catch (Exception e) {
e.printStackTrace();
return false;
}

if(b1.compareTo(b2) == 0){
System.out.println("两个文件内容相同");
result = true;
}else{
System.out.println("两个文件内容不相同");
}
return result;
}

/**
* 根据io流来判断文件是否相同
*
* 2017年11月23日下午1:26:52
* @param filePath1
* @param filePath2
* @return
* @parameter
* boolean
*
*/
public static boolean isSameFileForIO(String filePath1,String filePath2){
//返回结果
boolean result = true;
//建立文件
File file1 = new File(filePath1);
File file2 = new File(filePath2);
//判断是否是文件,若有一个不是文件则返回false
if ((!file1.isFile())||(!file2.isFile())) {
System.out.println("至少有一个不是文件");
return false;
}
//判断文件大小
if(file1.length()!=file2.length()){
System.out.println("文件大小不一致");
return false;
}

FileInputStream fis1 = null;
FileInputStream fis2 = null;

try {
fis1 = new FileInputStream(filePath1);
fis2 = new FileInputStream(filePath2);

int c ;
while ((c = fis1.read()) != -1) {
if(fis2.read() != c){
System.out.println("两个文件流不同");
result = false;
break;
}
}
} catch (Exception e) {
e.printStackTrace();
return false;
} finally{
if (fis1 != null) {
try {
fis1.close();
} catch (IOException e) {
//忽略
e.printStackTrace();
}
}
if (fis2 != null) {
try {
fis2.close();
} catch (IOException e) {
//忽略
e.printStackTrace();
}
}
}
if(result == true){
System.out.println("两个文件流相同");
}
return result;
}

/**
* 根据指定目录获取所有文件,包含子目录
*
* 2017年11月22日下午11:42:11
* @param file
* @param fileList
* @parameter
* void
*
*/
public static void fileList(File file, List<File> fileList) {
if(file.isDirectory()) {
//获取子目录文件列表
File[] files = file.listFiles();
for(File f : files) {
fileList(f, fileList);
}
}else {
fileList.add(file);
}
}

/**
* 遍历指定目录下指定后缀名的文件,包括子目录
*
* 2017年11月22日下午11:42:27
* @param file
* @param fileList
* @param suffix
* @parameter
* void
*
*/
public static void fileList(File file, List<File> fileList, String suffix) {
if(file.isDirectory()) {
//获取子目录文件列表
File[] files = file.listFiles();
for(File f : files) {
fileList(f, fileList, suffix);
}
}else {
if(file.getName().endsWith(suffix)) {
fileList.add(file);
}
}
}

/**
* 根据指定目录获取所有文件,包含子目录
*
* 2017年11月22日下午11:42:39
* @param path
* @return
* @parameter
* List<File>
*
*/
public static List<File> fileList(String path) {
File file = new File(path);
List<File> fileList = new ArrayList<File>();
fileList(file, fileList);
return fileList;
}

/**
* 遍历指定目录下指定后缀名的文件,包括子目录
*
* 2017年11月22日下午11:42:50
* @param path
* @param suffix
* @return
* @parameter
* List<File>
*
*/
public static List<File> fileList(String path, String suffix) {
File file = new File(path);
List<File> fileList = new ArrayList<File>();
fileList(file, fileList, suffix);
return fileList;
}

/**
* 复制文件
*
* 2017年11月22日下午11:43:01
* @param srcFile
* @param destFile
* @parameter
* void
*
*/
public static void copyFile(File srcFile, File destFile) {
if(!srcFile.exists()) {
return;
}
if(destFile.exists()) {
destFile.delete();
}
InputStream in = null;
OutputStream out = null;
try {
//根据源文件创建输入流
in = new FileInputStream(srcFile);
//根据目标文件创建输出流
out = new FileOutputStream(destFile);
//创建字节数组,接收文件内容
byte[] data = new byte[1024];
int length = 0;
//边读边写
while((length = in.read(data)) != -1) {
out.write(data, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//关闭
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

/**
* 复制文件夹
*
* 2017年11月22日下午11:43:16
* @param srcFile
* @param destFile
* @parameter
* void
*
*/
public static void copyFolder(File srcFile, File destFile) {
if(srcFile.isDirectory()) {
if(!destFile.exists()) {
destFile.mkdir();
}
File[] files = srcFile.listFiles();
for(File f : files) {
File df = new File(destFile, f.getName());
copyFolder(f, df);
}
}else {
copyFile(srcFile, destFile);
}
}

/**
* 剪切文件
*
* 2017年11月22日下午11:43:28
* @param srcFile
* @param destFile
* @parameter
* void
*
*/
public static void cutFile(File srcFile, File destFile) {
copyFile(srcFile, destFile);
srcFile.delete();
}

/**
* 剪切文件夹
*
* 2017年11月22日下午11:44:09
* @param srcFile
* @param destFile
* @parameter
* void
*
*/
public static void cutFolder(File srcFile, File destFile) {
copyFolder(srcFile, destFile);
delFolder(srcFile);
srcFile.delete();
}

/**
* 删除文件夹
*
* 2017年11月22日下午11:44:17
* @param file
* @parameter
* void
*
*/
public static void delFolder(File file) {
if(file.isDirectory()) {
File[] files = file.listFiles();
for(File f : files) {
delFolder(f);
}
file.delete();
}else {
file.delete();
}
}

/**
* 删除文件
*
* 2017年11月24日下午8:22:57
* @param fileName
* @return
* @parameter
* boolean
*
*/
public static boolean delFile(String fileName){
File file = new File(fileName);
if (!file.exists()) {
System.out.println("删除文件失败:" + fileName + "不存在!");
return false;
} else {
if (file.isFile())
return deleteFile(fileName);
else
return deleteDirectory(fileName);
}
}

/**
* 删除单个文件
*
* @param fileName
* 要删除的文件的文件名
* @return 单个文件删除成功返回true,否则返回false
*/
public static boolean deleteFile(String fileName) {
File file = new File(fileName);
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
if (file.exists() && file.isFile()) {
if (file.delete()) {
System.out.println("删除单个文件" + fileName + "成功!");
return true;
} else {
System.out.println("删除单个文件" + fileName + "失败!");
return false;
}
} else {
System.out.println("删除单个文件失败:" + fileName + "不存在!");
return false;
}
}
/**
* 删除目录及目录下的文件
*
* @param dir
* 要删除的目录的文件路径
* @return 目录删除成功返回true,否则返回false
*/
public static boolean deleteDirectory(String dir) {
// 如果dir不以文件分隔符结尾,自动添加文件分隔符
if (!dir.endsWith(File.separator))
dir = dir + File.separator;
File dirFile = new File(dir);
// 如果dir对应的文件不存在,或者不是一个目录,则退出
if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
System.out.println("删除目录失败:" + dir + "不存在!");
return false;
}
boolean flag = true;
// 删除文件夹中的所有文件包括子目录
File[] files = dirFile.listFiles();
for (int i = 0; i < files.length; i++) {
// 删除子文件
if (files[i].isFile()) {
flag = deleteFile(files[i].getAbsolutePath());
if (!flag)
break;
}
// 删除子目录
else if (files[i].isDirectory()) {
flag = deleteDirectory(files[i]
.getAbsolutePath());
if (!flag)
break;
}
}
if (!flag) {
System.out.println("删除目录失败!");
return false;
}
// 删除当前目录
if (dirFile.delete()) {
System.out.println("删除目录" + dir + "成功!");
return true;
} else {
return false;
}
}

/**
* 写入文本
*
* 2017年11月22日下午11:44:26
* @param file
* @param content
* @parameter
* void
*
*/
public static void writeText(File file, String content) {
Writer writer = null;
try {
writer = new FileWriter(file);
writer.write(content);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

/**
* 写入文本(追加)
*
* 2017年11月22日下午11:44:35
* @param file
* @param content
* @param append
* @parameter
* void
*
*/
public static void writeText(File file, String content, boolean append) {
Writer writer = null;
try {
writer = new FileWriter(file, append);
writer.write(content);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

/**
* 读取文本
*
* 2017年11月22日下午11:44:45
* @param file
* @return
* @parameter
* String
*
*/
public static String readText(File file) {
StringBuffer sb = new StringBuffer();
Reader reader = null;
try {
reader = new FileReader(file);
char[] data = new char[1024];
int length = 0;
while((length = reader.read(data)) != -1) {
String content = new String(data, 0, length);
sb.append(content);
}
}catch (IOException e) {
e.printStackTrace();
} finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}

public static void main(String[] args) {
// deleteDirectory("C:\\Users\\AAS-1389\\Desktop\\TCP-IP详解卷一 - 副本");
File file = new File("C:\\Users\\AAS-1389\\Desktop\\彩信问题-answer.docx");
System.out.println(file.getName());
}
}

=======================================================================================

测试的jsp代码

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>

<!DOCTYPE HTML>
<html>
<head>
<base href="<%=basePath%>">

<title>文件上传</title>
<meta charset="utf-8">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>

<body>

<form action="FileUtilsUpLoad" method="post" enctype="multipart/form-data">
<div>
<input type="file" id="fileUpload" name="fileUpload" style="display: none; " οnchange="fileName.value=this.value"/>
<input id="fileName" readonly style="width: 200px; height: 30px; border: 1px solid #666; border-radius:3px" placeholder="请选择要上传的文件"/>
<input type="button" value="浏览文件..." style="width: 100px; height: 32px; background: green; color: #fff; border: 0; border-radius: 3px" οnclick="fileUpload.click();"/>
</div>
<div>
<input type="submit" value="开始上传" style="margin: 30px 0;width: 200px; height: 30px; background: green; color: #fff; border: 0; border-radius: 33px"/>
</div>
</form>
<form action="FileUtilsDownLoad" method="get" enctype="multipart/form-data">
<div>
<input type="submit" value="开始下载" style="margin: 30px 0;width: 200px; height: 30px; background: green; color: #fff; border: 0; border-radius: 33px"/>
</div>
</form>

</body>
</html>

==================================================================

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

<servlet>
<servlet-name>FileUtilsUpLoad</servlet-name>
<servlet-class>test.FileUtilsTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FileUtilsUpLoad</servlet-name>
<url-pattern>/FileUtilsUpLoad</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>FileUtilsDownLoad</servlet-name>
<servlet-class>test.FileUtilsTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FileUtilsDownLoad</servlet-name>
<url-pattern>/FileUtilsDownLoad</url-pattern>
</servlet-mapping>
</web-app>

=============================================

lib

commons-fileupload-1.3.1.jar

commons-io-2.2.jar

============================================

controller层

package test;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import common.utils.FileUtils;

public class FileUtilsTest extends HttpServlet {

private static final long serialVersionUID = 1L;

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//下载文件
FileUtils.download(request, response, "files/[drcilabo海外]旺旺等级银卡.xlsx");
}

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//上传文件
List<String> filePaths = FileUtils.upload(request, "upload/",".xls .xlsx");
System.out.println(filePaths);
}

}

===============================================================================================

===============================================================================================

以下是ssm中测试

html 测试

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8"/>
<title>My HTML 'upload.jsp' starting page</title>
<script type="text/javascript" src="global/jquery.min.js"></script>
</head>
<body>
<form id="uploadForm" enctype="multipart/form-data" method="post" action="file/fileUpload">
name:<input type="text" name="username"><br/>
upload1:<input type="file" name="file" id="file"><br/>
upload2:<input type="file" name="file" id="file"><br/>
<input type="button" value="上传" οnclick="fileSelected()">
</form>
<form id="downloadForm" method="post" action="file/fileDownload">
<input type="button" value="下载" οnclick="fileDownLoad()">
</form>
</body>
<script>
var iMaxFilesize = 50*2048*1000; //2M
var upLoadUrl = "file/fileUpload";
window.fileSelected = function() {
/* var oFile = document.getElementById('file').files[0]; //读取文件
var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
/* if (!rFilter.test(oFile.type)) {
alert("文件格式必须为图片");
return;
} */
/* if (oFile.size > iMaxFilesize) {
alert("文件大小不能超过2M");
return;
} */
var vFD = new FormData(document.getElementById('uploadForm')), //建立请求和数据
oXHR = new XMLHttpRequest();
oXHR.addEventListener('load', function(resUpload) {
//成功
alert("成功");
}, false);
oXHR.addEventListener('error', function() {
//失败
alert("失败")
}, false);
oXHR.addEventListener('abort', function() {
//上传中断
alert("上传中断")
}, false);
oXHR.open('POST', upLoadUrl);
oXHR.send(vFD);
};

function fileDownLoad(){
/* 由于jQuery的ajax函数、及ajaxSubmit等函数的返回类型(dataType)只有xml、text、json、html等类型,
没有“流”类型,故我们要实现ajax下载时,不能够使用相应的ajax函数进行文件下载。 */
var downLoadUrl = "file/fileDownload";
var form = $("#downloadForm");
form.submit(); //表单提交

//构造一个form表单
/* form.attr('style','display:none'); //下面为在form表单中添加查询参数
form.attr('target','');
form.attr('method','post');
form.attr('action',downLoadUrl);

var input1 = $('<input>');
input1.attr('type','hidden');
input1.attr('name','exportPostTime');

$('body').append(form); //将表单放置在web中
form.append(input1); //将查询参数控件提交到表单上
form.submit(); //表单提交

*/
}

</script>
</html>

-----------------------------------------------------------------

controller层

/**
* 2017年11月22日下午4:46:15
*/
package com.jjmc.server.controller;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import com.jjmc.server.utils.FileUtils;

/**
*
* @author huangtao
* 2017年11月22日下午4:46:15
* business-server
* @parameter
* TODO
*
*/
@Controller
public class TestFile {

@RequestMapping(value = "/file/fileUpload", method = RequestMethod.POST)
public void upload(HttpServletRequest request) throws IllegalStateException, IOException{
System.out.println("进入文件上传");
List<String> list = FileUtils.upload(request,100*1024*1024,50*1024*1024,"allfiles");
System.out.println(list);
System.out.println("结束文件上传");
}

@RequestMapping(value = "/file/fileDownload", method = RequestMethod.POST)
public void download(HttpServletRequest request,HttpServletResponse response) throws IllegalStateException, IOException{
System.out.println("进入文件下载");
List<String> fileNameList = new ArrayList<String>();
fileNameList.add("[drcilabo海外]旺旺等级银卡.xlsx");
fileNameList.add("彩信问题-answer.docx");
fileNameList.add("setting.ini");
fileNameList.add("UC-ZC-01采购管理功能测试用例.xls");
fileNameList.add("JJCC Project Wings II- Test Cases 单元测试- 20171120(吉之岛).xls");
fileNameList.add("音智达Logo.PNG");
fileNameList.add("20171109_members.csv");
fileNameList.add("loading.gif");
fileNameList.add("111.txt");
fileNameList.add("聚星台_-_会员中心系统接口文档V3.7.pdf");
fileNameList.add("ant-1.10.1.jar");
fileNameList.add("短信_1.0.sql");
fileNameList.add("Finance测试.doc");
fileNameList.add("medical CR detail .pptx");
fileNameList.add("conf.properties");
fileNameList.add("rebel.xml");
fileNameList.add("AdminController.java");
FileUtils.download(request, response, "E:\\fileTest",fileNameList,true);
System.out.println("结束文件下载");
}
}

处理文件工具类(批量上传,下载)相关推荐

  1. springboot上传下载文件(4)--上传下载工具类(已封装)

    因为在做毕设,发现之前的搭建ftp文件服务器,通过ftp协议无法操作虚拟机临时文件,又因为ftp文件服务器搭建的比较麻烦:而 hadoop的HDFS虽然可以实现,但我这里用不到那么复杂的:所以我封装了 ...

  2. 淘宝的一键上下架工具怎么批量上传商品的?

    淘宝商家日常的商品管理都需要借用到上货软件,能批量上下架商品的软件,毕竟店铺的商品需要不断更换和上新,才能保持每天都有流量进店,现在也快到秋季,商家也该换新款,批量上传商品和下架商品的时候了. 手动上 ...

  3. ftp工具类:上传与下载文件

    准备工作 服务器已经配置好ftp服务 linux服务器搭建ftp服务: https://program.blog.csdn.net/article/details/88825921 需要用到的jar包 ...

  4. 百度相册批量上传下载类

    Imports System.IO Imports System.Net Imports System.Web Public Delegate Sub BaiduAlbumEventHandler(B ...

  5. 海量上传文件服务器端,bat批量上传ftp文件到服务器

    bat批量上传ftp文件到服务器 内容精选 换一换 服务器上云或云上迁移利用镜像导入功能,将已有的业务服务器制作成镜像后导入到云平台(当前支持vhd.vmdk.qcow2.raw等多种格式),方便企业 ...

  6. linux 传文件夹,linux下上传下载文件夹的方法

    Linux下目录复制:本机->远程服务器 scp -r /home/shaoxiaohu/test1 zhidao@192.168.0.1:/home/test2 test1为源目录,test2 ...

  7. 如何解决上传大文件时(批量上传文件)系统卡死宕机的问题

    最近客户反应开发的一个采购管理系统在上传大的文件时会出现宕机卡死的问题,尤其是在进行多文件批量上传.超大文件(几百MB或上GB)上传时极其容易发生.日志信息显示,引发的异常为致命异常 java.lan ...

  8. java ftp上传文件_jaVA使用FTP上传下载文件的问题

    为了实现 FTP上传下载,大概试了两个方法 sun.net.ftp.FtpClient org.apache.commons.net 一开始使用sun.net.ftp.FtpClient,结果发现唯一 ...

  9. 通过putty取linux文件,putty对Linux上传下载文件或文件夹

    putty是一个开源软件,目前为止最新版本为0.70.对于文件或文件夹的上传下载,在Windows下它提供了pscp和psftp两个命令. (1).pscp pscp在命令提示符中使用,只要putty ...

最新文章

  1. javabean mysql_Mysql 存储 javabean
  2. iOS GCD中级篇 - dispatch_group的理解及使用
  3. 1.2.4 Selecting a defualt database
  4. NLP复习资料(6)-第十章 语义分析
  5. jfinal调用mysql存储过程 封装_jfinal如何调用存储过程?
  6. android 字母索引三方,Android 字母索引动态自定义布局
  7. python中特殊符号怎么输入_python中怎么输入引号
  8. 苹果Mac知识大纲管理神器:OmniOutLiner
  9. frame边框阴影html,CSS阴影效果的比较之drop-Shadow与box-Shadow
  10. MathType|强大的数学公式编辑器
  11. 复旦sakai安装指南
  12. go包管理之vender机制
  13. 云栖社区新版首页上线_开启找bug模式
  14. win7下用VS2008写视频聊天程序,求VFW教程?qzvgK
  15. nextjs+MDX渲染md文件并生成目录
  16. Web前端期末大作业---HTML+CSS+JS实现实现捉虫小游戏
  17. 万字文肝Java基础知识(一)
  18. 怎样快速学习一门计算机编程语言?
  19. 云服务器 网络端口,云服务器的端口号怎么看
  20. oracle 日志 aw,DBMS_AW_EXP: not AW$

热门文章

  1. h2ouve工具使用_‎证照采集星-超好用的证件照批量采集工具 v App Storu
  2. 运用蒙特卡洛法模拟电动汽车常规充电、快速充电、更换电池充电曲线及对日负荷曲线的影响
  3. java 不用中间变量_java异或运算不使用中间变量交换两个数(Java版)详细分解...
  4. SpringBoot中的Bean
  5. 四川玖益科技:新店运营的注意事项
  6. “韭零后”都是这样看基金的!!!
  7. 个人笔记(2016.12.01)
  8. linux SIGCHLD信号
  9. Input输入框调用相机
  10. [附源码]计算机毕业设计JAVA基于javaweb电影购票系统