What we usually do is upload files. The upload folder is similar to the upload file, but there are some differences. This time we made the upload folder and record it for later use.
The first thing we need to understand is the three elements of uploading files:
1. Form submission method: post (get method submission has a size limit, post does not)
2. The enctype attribute of the form: must be set to multipart/form-data.
3. The form must have a file upload item: file, and the file item needs to be given a name value
The upload folder needs to add an attribute webkitdirectory, like this:
<input id="fileFolder" name="fileFolder" type="file" webkitdirectory>
However, there is a problem with the webkitdirectory attribute. It can only support high versions of chrome, and cannot support low versions of IE, such as ie6, ie7, and ie8. It cannot be adapted to all browsers and the operating environment is relatively single.
In js, you can judge whether the number of files in the folder and the size of the folder meet the requirements, and you cannot submit to the background if they do not meet the requirements:
Front HTML template
this.GetHtmlFiles = function()
{
var acx = "";
acx += '<div class="file-item" id="tmpFile" name="fileItem">\
<div class="img-box"><img name="file" src="js/file.png"/></div>\
<div class="area-l">\
<div class="file-head">\
<div name="fileName" class="name">HttpUploader程序开发.pdf</div>\
<div name="percent" class="percent">(35%)</div>\
<div name="fileSize" class="size" child="1">1000.23MB</div>\
</div>\
<div class="process-border"><div name="process" class="process"></div></div>\
<div name="msg" class="msg top-space">15.3MB 20KB/S 10:02:00</div>\
</div>\
<div class="area-r">\
<span class="btn-box" name="cancel" title="取消"><img name="stop" src="js/stop.png"/><div>取消</div></span>\
<span class="btn-box hide" name="post" title="继续"><img name="post" src="js/post.png"/><div>继续</div></span>\
<span class="btn-box hide" name="stop" title="停止"><img name="stop" src="js/stop.png"/><div>停止</div></span>\
<span class="btn-box hide" name="del" title="删除"><img name="del" src="js/del.png"/><div>删除</div></span>\
</div>';
acx += '</div>';
//Folder template
acx += '<div class="file-item" name="folderItem">\
<div class="img-box"><img name="folder" src="js/folder.png"/></div>\
<div class="area-l">\
<div class="file-head">\
<div name="fileName" class="name">HttpUploader程序开发.pdf</div>\
<div name="percent" class="percent">(35%)</div>\
<div name="fileSize" class="size" child="1">1000.23MB</div>\
</div>\
<div class="process-border top-space"><div name="process" class="process"></div></div>\
<div name="msg" class="msg top-space">15.3MB 20KB/S 10:02:00</div>\
</div>\
<div class="area-r">\
<span class="btn-box" name="cancel" title="取消"><img name="stop" src="js/stop.png"/><div>取消</div></span>\
<span class="btn-box hide" name="post" title="继续"><img name="post" src="js/post.png"/><div>继续</div></span>\
<span class="btn-box hide" name="stop" title="停止"><img name="stop" src="js/stop.png"/><div>停止</div></span>\
<span class="btn-box hide" name="del" title="删除"><img name="del" src="js/del.png"/><div>删除</div></span>\
</div>';
acx += '</div>';
//Upload list
acx += '<div class="files-panel" name="post_panel">\
<div name="post_head" class="toolbar">\
<span class="btn" name="btnAddFiles">Select multiple files</span>\
<span class="btn" name="btnAddFolder">Select a folder</span>\
<span class="btn" name="btnPasteFile">Paste files and directories</span>\
<span class="btn" name="btnSetup">安装控件</span>\
</div>\
<div class="content" name="post_content">\
<div name="post_body" class="file-post-view"></div>\
</div>\
<div class="footer" name="post_footer">\
<span class="btn-footer" name="btnClear">Clear completed files</span>\
</div>\
</div>';
return acx;
};
The logic of selecting files, selecting folders, pasting files and folders
this.open_files = function (json)
{
for (var i = 0, l = json.files.length; i < l; ++i)
{
this.addFileLoc(json.files[i]);
}
setTimeout(function () { _this.PostFirst(); },500);
};
this.open_folders = function (json)
{
for (var i = 0, l = json.folders.length; i < l; ++i) {
this.addFolderLoc(json.folders[i]);
}
setTimeout(function () { _this.PostFirst(); }, 500);
};
this.paste_files = function (json)
{
for (var i = 0, l = json.files.length; i < l; ++i)
{
this.addFileLoc(json.files[i]);
}
};
The difference when receiving folders in the background is that MultipartHttpServletRequest is needed
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List files = null;
try
{
files = upload.parseRequest(request);
}
catch (FileUploadException e)
{// Parsing file data error
out.println("read file data error:" + e.toString());
return;
}
FileItem rangeFile = null;
// Get all uploaded files
Iterator fileItr = files.iterator();
// Loop through all files
while (fileItr.hasNext())
{
// Get the current file
rangeFile = (FileItem) fileItr.next();
if(StringUtils.equals( rangeFile.getFieldName(),"pathSvr"))
{
pathSvr = rangeFile.getString();
pathSvr = PathTool.url_decode(pathSvr);
}
}
Packages and classes on the server side
Page at the file block, verify the code part
boolean verify = false;
String msg = "";
String md5Svr = "";
long blockSizeSvr = rangeFile.getSize();
if(!StringUtils.isBlank(blockMd5))
{
md5Svr = Md5Tool.fileToMD5(rangeFile.getInputStream());
}
verify = Integer.parseInt(blockSize) == blockSizeSvr;
if(!verify)
{
msg = "block size error sizeSvr:" + blockSizeSvr + "sizeLoc:" + blockSize;
}
if(verify && !StringUtils.isBlank(blockMd5))
{
verify = md5Svr.equals(blockMd5);
if(!verify) msg = "block md5 error";
}
if(verify)
{
//Save file block data
FileBlockWriter res = new FileBlockWriter();
//Create only the first block
if( Integer.parseInt(blockIndex)==1) res.CreateFile(pathSvr,Long.parseLong(lenLoc));
res.write( Long.parseLong(blockOffset),pathSvr,rangeFile);
up6_biz_event.file_post_block(id,Integer.parseInt(blockIndex));
JSONObject o = new JSONObject();
o.put("msg", "ok");
o.put("md5", md5Svr);
o.put("offset", blockOffset);//file-based block offset position
msg = o.toString();
}
rangeFile.delete();
out.write(msg);
The logic of generating file names
public String genFile(int uid, String md5,String nameLoc) throws IOException
{
SimpleDateFormat fmtDD = new SimpleDateFormat("dd");
SimpleDateFormat fmtMM = new SimpleDateFormat("MM");
SimpleDateFormat fmtYY = new SimpleDateFormat("yyyy");
Date date = new Date();
String strDD = fmtDD.format(date);
String strMM = fmtMM.format (date);
String strYY = fmtYY.format (date);
String path = this.getRoot() + "/";
path = path.concat(strYY);
path = path.concat("/");
path = path.concat(strMM);
path = path.concat("/");
path = path.concat(strDD);
path = path.concat("/");
path = path.concat(md5);
path = path.concat(".");
path = path.concat(PathTool.getExtention(nameLoc));
File fl = new File(path);
return fl.getCanonicalPath();//
}
The following is the processing done by the service layer:
The overall module is divided as follows:
The data type entity logic is processed as follows
public class FileInf {
public FileInf(){}
public String id="";
public String pid="";
public String pidRoot="";
/** * Indicates whether the current item is a folder item. */
public boolean fdTask=false;
// /// Is it a sub-file in the folder /// </summary>
public boolean fdChild=false;
/** * User ID. Integrated with third-party systems. */
public int uid=0;
/** * The name of the file on the local computer */
public String nameLoc="";
/** * The name of the file on the server. */
public String nameSvr="";
/** * The full path of the file on the local computer. Example: D:\Soft\QQ2012.exe */
public String pathLoc="";
/** * The full path of the file on the server. Example: F:\\ftp\\uer\\md5.exe */
public String pathSvr="";
/** * The relative path of the file on the server. Example: /www/web/upload/md5.exe */
public String pathRel="";
/** * File MD5 */
public String md5="";
/** * The length of the digitized file. In bytes, for example: 120125 */
public long lenLoc=0;
/** * Formatted file size. Example: 10.03MB */
public String sizeLoc="";
/** * File resume location. */
public long offset=0;
/** * The size has been uploaded. In bytes */
public long lenSvr=0;
/** * Percentage uploaded. Example: 10% */
public String perSvr="0%";
public boolean complete=false;
public Date PostedTime = new Date();
public boolean deleted=false;
/** * Whether the scan has been completed, and it is provided to large folders. Scanning will start after the large folders are uploaded. */
public boolean scaned=false;
}
The logic in the backend database basically uses the above entity classes
The file data table operation class is as follows
Load a list of all outstanding files
public String GetAllUnComplete(int f_uid)
{
StringBuilder sb = new StringBuilder();
sb.append("select ");
sb.append(" f_id");
sb.append(",f_fdTask");
sb.append(",f_nameLoc");
sb.append(",f_pathLoc");
sb.append(",f_md5");
sb.append(",f_lenLoc");
sb.append(",f_sizeLoc");
sb.append(",f_pos");
sb.append(",f_lenSvr");
sb.append(",f_perSvr");
sb.append(",f_complete");
sb.append(",f_pathSvr");//fix(2015-03-16): Fix the problem that the file cannot be resumed.
sb.append(" from up6_files ");//change(2015-03-18): joint query folder data
sb.append(" where f_uid=? and f_deleted=0 and f_fdChild=0 and f_complete=0 and f_scan=0");//fix(2015-03-18): load only the unfinished list
ArrayList<FileInf> files = new ArrayList<FileInf>();
DbHelper db = new DbHelper();
PreparedStatement cmd = db.GetCommand(sb.toString());
try {
cmd.setInt(1, f_uid);
ResultSet r = db.ExecuteDataSet(cmd);
while(r.next())
{
FileInf f = new FileInf();
f.uid = f_uid;
f.id = r.getString(1);
f.fdTask = r.getBoolean(2);
f.nameLoc = r.getString(3);
f.pathLoc = r.getString(4);
f.md5 = r.getString(5);
f.lenLoc = r.getLong(6);
f.sizeLoc = r.getString(7);
f.offset = r.getLong(8);
f.lenSvr = r.getLong(9);
f.perSvr = r.getString(10);
f.complete = r.getBoolean(11);
f.pathSvr = r.getString(12);//fix(2015-03-19): Fix the problem that the file cannot be resumed.
files.add(f);
}
r.close();
cmd.getConnection().close();
cmd.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace ();
}
if(files.size() < 1) return null;
Gson g = new Gson ();
return g.toJson( files);//bug: When arrFiles is empty, this line of code is abnormal
}
The overall effect after implementation is as follows
Effect after uploading the folder
The folder data saved by the server, and the hierarchical structure is consistent with that of the local client. This is very useful when used in an OA system or a network disk system
Most of the back-end code logic is the same, and it currently supports MySQL, Oracle, and SQL. You need to configure the database before use, you can refer to this article I wrote: http://blog.ncmem.com/wordpress/2019/08/12/java-http%E5%A4%A7%E6%96%87 %E4%BB%B6%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0%E4%B8%8A%E4%BC%A0/
Welcome to join the group to discuss "374992201"