这里仅仅介绍JeeCMS中文件上传和下载功能。从前台到后台分析,希望笔者对该功能也能有更多的理解,温故知新。
html代码:
<table id="attachTable" border="0">
<tr>
<td align="center">
</td>
<td align="center">
附件名称
</td>
<td align="center">
上传
</td>
</tr>
<tr id="attachTr${a_index}">
<td align="center">
<a οnclick="$('#attachTr${a_index}').remove();" href="javascript:void(0);" class="pn-opt">删除</a>
</td>
<td align="center">
<input type="text" id="attachmentNames${a_index}" value="${a.name}" name="attachmentNames"/>
<input type="hidden" id="attachmentPaths${a_index}" value="${a.path}" name="attachmentPaths"/>
</td>
<td align="center">
<span id="afc${a_index}" style="position:relative;display:block;width:300px;*width:300px;">
<input type='text' class="text_size" id='attachmentText${a_index}'/>
<input class="browse" type='button' value='浏览'/>
<input οnchange="$('#attachmentText${a_index}').val(this.value)" size="19" type="file" name="attachmentFile" id="attachmentFile${a_index}" style="height:24px;opacity:0;filter:alpha(opacity=0);position:absolute;right:69px;top:2px;"/>
<input type="button" value="上传" οnclick="uploadAttachment(${a_index});" class="upload-button"/>
</span>
<input type="hidden" id="attachmentFilenames${a_index}" name="attachmentFilenames"/>
</td>
</tr>
</table>
这里最主要的有三个字段,attachmentNames,attachmentPath,attachmentFilenames这是三个要存进数据库的字段,在上传的同时要把这三个字段填充完整。以便在提交时可以在后台取到。
上传文件的大致流程:点击浏览选取文件-->点击上传-->js函数触发获得各个参数和File-->后台读取文件上传到指定目录-->返回到前台参数-->提交至数据库。
其中比较重要两个点就是,js函数和后台读取文件的过程。下面将进行重点说明:
function uploadAttachment(n) {
var af = $('#attachmentFile'+n);
//检查是否选择了文件
if(af.val()=='') {
alert('没有选择文件!');
return;
}
//将file移动至上传表单
$('#attachmentContent').empty();
$('#attachmentContent').append(af);
//复制一个file放至原处
//dump_obj(af);
//dump_obj(attachmentContent);
$('#afc'+n).append(af.clone().attr('value',''));
$('#attachmentText'+n).attr('value','');
//修改属性
af.attr('id','');
af.attr('name','attachmentFile');
//其他表单
var attachmentForm = document.getElementById('attachmentForm');
$('#attachmentNum').val(n);
$('#attachmentForm').submit();
}
<form id="attachmentForm" action="o_upload_attachment.jspx" method="post" enctype="multipart/form-data" target="attachment_iframe" style="display:none;width:0px;height:0px;">
<span id="attachmentContent"></span>
<input type="hidden" id="attachmentNum" name="attachmentNum"/>
</form>
<iframe name="attachment_iframe" frameborder="0" border="0" style="display:none;width:0px;height:0px;"></iframe>
这里js函数的几个部分:1,监测是否选取文件;2,将file文件放到表单attachmentForm中;3,获取其他参数(filename,num,file)并提交至后台。
这里需要注意:
enctype="multipart/form-data"
这个属性是必需的,在上传文件的时候需要以字节流的形式上传,这个属性也必须加上。另外iframe是用来存放后台返回的语句代码,目的是把参数放到attachmentNames,attachmentPath,attachmentFilenames中。
后台代码:
public String execute_attachment(
String filename,//文件名
Integer attachmentNum,//文件数量
Boolean mark,//标识
@RequestParam(value = "attachmentFile", required = false) MultipartFile file,//文件
HttpServletRequest request, ModelMap model) {
CmsSite site = CmsUtils.getSite(request);
WebErrors errors = validateUpload(file, request);
if (errors.hasErrors()) {
model.addAttribute("error", errors.getErrors().get(0));
return FrontUtils.getTplPath(request, site.getSolutionPath(),
TPLDIR_MESSAGE, RESULT_PAGE_ATT);
}
String origName = file.getOriginalFilename();//获取文件原始名称
String ext = FilenameUtils.getExtension(origName).toLowerCase(
Locale.ENGLISH);
// TODO 检查允许上传的后缀
try {
String fileUrl;
if (site.getConfig().getUploadToDb()) {
String dbFilePath = site.getConfig().getDbFileUri();
fileUrl = dbFileMng.storeByExt(site.getUploadPath(), ext, file
.getInputStream());
// 加上访问地址
fileUrl = request.getContextPath() + dbFilePath + fileUrl;
} else if (site.getUploadFtp() != null) {
Ftp ftp = site.getUploadFtp();
String ftpUrl = ftp.getUrl();
fileUrl = ftp.storeByExt(site.getUploadPath(), ext, file
.getInputStream());
// 加上url前缀
fileUrl = ftpUrl + fileUrl;
} else {
String ctx = request.getContextPath();
fileUrl = fileRepository.storeByExt(site.getUploadPath(), ext,
file);//此处是上传的核心代码
// 加上部署路径
fileUrl = ctx + fileUrl;
}
model.addAttribute("attachmentPath", fileUrl);
model.addAttribute("attachmentName", origName);
model.addAttribute("attachmentNum", attachmentNum);
} catch (IllegalStateException e) {
model.addAttribute("error", e.getMessage());
log.error("upload file error!", e);
} catch (IOException e) {
model.addAttribute("error", e.getMessage());
log.error("upload file error!", e);
}
return FrontUtils.getTplPath(request, site.getSolutionPath(),
TPLDIR_MESSAGE, RESULT_PAGE_ATT);
}
public String storeByExt(String path, String ext, MultipartFile file)
throws IOException {
String filename = UploadUtils.generateFilename(path, ext);
File dest = new File(ctx.getRealPath(filename));
dest = UploadUtils.getUniqueFile(dest);
store(file, dest);
return filename;
}
private void store(MultipartFile file, File dest) throws IOException {
try {
UploadUtils.checkDirAndCreate(dest.getParentFile());
file.transferTo(dest);
} catch (IOException e) {
log.error("Transfer file error when upload file", e);
throw e;
}
}
这里利用spring的MultipartFile类来上传文件,这样由之前编辑好的路径,文件就实现读取上传了。具体改上传的方法,可以参考某博主的文章:http://blog.sina.com.cn/s/blog_8fb83eec0100wm2r.html。
文件的下载:
[#if message.attachments?size gt 0]
[#list message.attachments as a]
<a id="attach${a_index}">${a.name}</a>
[/#list]
[/#if]
$(function() {
Cms.message_attachment("${base}","${message.id}","${message.attachments?size}","attach");
});
Cms.message_attachment = function(base, messageId, n, prefix) {
//alert(base+","+messageId+","+n+","+prefix);
$.get(base + "/message_attachment_url.jspx", {
"cid" : messageId,
"n" : n
}, function(data) {
var url;
for (var i = 0;i < n; i++) {
url = base + "/message_attachment.jspx?cid=" + messageId + "&i=" + i
+ data[i];
$("#" + prefix + i).attr("href", url);
}
}, "json");
}
取到的参数:根路径base,信息编号messageId,数量n,前缀prefix。提交的url:message_attachment_url.jspx,作用是将附件链接加上href,链接到url上,当点击链接时,message_attachment.jspx链接到后台地址,根据拼接的参数,下载文件,后台代码:
@RequestMapping(value = "/message_attachment_url.jspx", method = RequestMethod.GET)
public void url(Integer cid, Integer n, HttpServletRequest request,
HttpServletResponse response, ModelMap model) {
if (cid == null || n == null) {
return;
}
CmsConfig config = CmsUtils.getSite(request).getConfig();
String code = config.getDownloadCode();//产生下载码,用于后续的下载工作,目的为了掩藏文件的真实路径
long t = System.currentTimeMillis();
JSONArray arr = new JSONArray();
String key;
for (int i = 0; i < n; i++) {
key = pwdEncoder.encodePassword(cid + ";" + i + ";" + t, code);
arr.put("&t=" + t + "&k=" + key);
}
ResponseUtils.renderText(response, arr.toString());
}
@RequestMapping(value = "/message_attachment.jspx", method = RequestMethod.GET)
public void attachment(Integer cid, Integer i, Long t, String k,
HttpServletRequest request, HttpServletResponse response,
ModelMap model) throws IOException {
CmsConfig config = CmsUtils.getSite(request).getConfig();
String code = config.getDownloadCode();//获取之前存入的下载码
int h = config.getDownloadTime() * 60 * 60 * 1000;
if (pwdEncoder.isPasswordValid(k, cid + ";" + i + ";" + t, code)) {//下载码两相比对
long curr = System.currentTimeMillis();
if (t + h > curr) {
CmsMessage cm = messageMng.findById(cid);//得到信息
System.out.println(cm.getTitleHtml()+"title");
if (cm != null) {
List<CmsMessageAttachment> list = cm.getAttachments();//获得所有附件
if (list.size() > i) {
CmsMessageAttachment cma = list.get(i);
response.sendRedirect(cma.getPath());//返回路径
return;
} else {
log.info("download index is out of range: {}", i);
}
} else {
log.info("Message not found: {}", cid);
}
} else {
log.info("download time is expired!");
}
} else {
log.info("download key error!");
}
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
}
至此附件的下载工作基本完成。
本文章恐怕只有笔者自己能够看明白,写的不清楚之处,大家也不用喷了,本来当做笔记用的,未必期望大家都从中受益。