我正在开发一个web应用程序(Java/JSP),其中一部分是允许用户只"一次"下载所请求的文件。问题是,当他们点击"下载"按钮时,他们将被要求保存/打开或取消文件,无论他们回应什么,文件将被标记为已下载,用户将无法再次下载。我正试图找出一种方法,不计算文件下载时,用户响应"取消",并检查是否真的用户下载文件完全。
下面是Java部分:
@WebServlet("/download")
public class download extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final int DEFAULT_BUFFER_SIZE = 10240;
/**
* @see HttpServlet#HttpServlet()
*/
public download() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Class.forName("org.sqlite.JDBC");
Connection c = DriverManager.getConnection("jdbc:sqlite:C:\sqlite\mascapp.db");
c.setAutoCommit(false);
Cookie[] cookies = request.getCookies();
if(request.getSession().getAttribute("aeid") == null || request.getSession().getAttribute("uid") == null)
{
response.sendRedirect("/index.jsp");
}
int ae_num = Integer.parseInt(request.getSession().getAttribute("aeid").toString());
String sql = "SELECT file, filename FROM reports INNER JOIN download USING(tipid) WHERE reports.tipid = ?"+
"AND download.ts_" + ae_num+ " = 0;";
PreparedStatement stmt = c.prepareStatement(sql);
String tipNum = request.getParameter("tipid");
if (tipNum != null) {
stmt.setString(1, tipNum);
//stmt.setString(2, tipNum);
ResultSet res = stmt.executeQuery();
BufferedInputStream fileBlob = null;
String filename = "";
while (res.next()) {
fileBlob = new BufferedInputStream(res.getBinaryStream("file"), DEFAULT_BUFFER_SIZE);
filename = res.getString("filename");
}
if (fileBlob != null) {
System.out.println(filename);
response.setContentType("APPLICATION/OCTET-STREAM");
response.setHeader("Content-Disposition", "attachment; filename="" + filename + """);
BufferedOutputStream output = new BufferedOutputStream(response.getOutputStream(),
DEFAULT_BUFFER_SIZE);
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = fileBlob.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
output.close();
fileBlob.close();
Date now = new Date();
sql = "UPDATE download SET ts_" + ae_num + " = " + now.getTime() + " WHERE tipid = ?;";
System.out.println(sql);
stmt = c.prepareStatement(sql);
stmt.setString(1, tipNum);
stmt.executeUpdate();
stmt.close();
c.commit();
c.close();
}
else
{
c.close();
response.sendRedirect("/MASC/formdownloaded.jsp");
}
}
else
{
response.getWriter().append("<html><body><h1>Error: no param</h1></body></html>");
c.close();
}
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
有什么解决方案或建议吗?
检查这个页面:http://johnculviner.com/jquery-file-download-plugin-for-ajax-like-feature-rich-file-downloads/(这个链接有时不工作,如果你有一些问题,这里有一个链接到github: https://github.com/johnculviner/jquery.fileDownload)
看起来你在这里能做的最好的事情就是通过检查客户端从服务器发回的带有下载文件流的特殊cookie来确保下载已经开始。为此,您必须将Cookie添加到servlet响应中,如以下线程:
文件下载完成后才能设置cookie。那么在servlet doGet方法的末尾你应该有这样的内容:
Cookie fileDwnld = new Cookie("fileDownload", "true");
fileDwnld.setPath("/");
response.addCookie(fileDwnld);
客户端代码:
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="jquery.fileDownload.js"></script>
<script>
$(document).ready(function() {
$("#btnSubmit").click(function(){
$.fileDownload('path/to/servlet')
.done(function () { alert('File download a success!'); })
.fail(function () { alert('File download failed!'); });
});
});
答案是不要那样做。这些对话框的存在是有充分理由的,其中一些涉及安全性。
你想做什么取决于为什么你只希望用户下载文件一次。下载可能会因为各种原因而失败,所以如果用户在下载过程中失去连接,你该怎么办?
我没有一个合适的答案,但我知道标题中的"attachment;"强制浏览器"下载"文件,而不是"打开它",如果你明白我的意思的话。试着删除标题,看看你是否得到想要的效果。