包含文本(用于显示)以及文件下载的 Servlet-Response
Servlet-Response containing text (for display) as well as file download
我正在尝试通过 Java Servlet 从我的服务器下载文件。
我遇到的问题是,当我直接输入 servlet url (https://localhost:8443/SSP/settings?type=db_backup) 时,我让 servlet 执行它的代码并提示我下载对话框。
但我想通过 Javascript 调用 servlets doGet 方法,用某种进度条包装它。
这里的问题:执行了 servlet 中的代码,但我没有收到文件的下载提示。
到目前为止我的代码:
HTML:
<!-- Solution #1 -->
<button class="btn_do_db_backup" type="button">DB-Backup #1</button>
<!-- Solution #2 -->
<form action="/SSP/settings?type=db_backup" method="GET">
<button type="submit">DB-Backup #2</button></br>
</form>
JS:
// Solution #1
$(".btn_do_db_backup").click(function(e){
e.preventDefault();
$.get("settings?type=db_backup", function(data){
if(data != ""){
//further coding
}
});
// Having the code below works but doesnt
// give me the chance to wrap the call with a loading animation
//document.location = "/SSP/settings?type=db_backup";
});
Servlet:
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
// PART 1
// execute srcipt to generate file to download later on
StringBuffer output = new StringBuffer();
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "D:\TEMP\sql_dump.cmd");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
String filename = "";
int tmp = 0;
while (true) {
line = r.readLine();
if (line == null) { break; }
output.append(line + "\n");
// code for finding filename not optimal but works for now -> redo later on
if(tmp == 1){
filename = line.substring(line.indexOf("db_backup_"), line.indexOf('"', line.indexOf("db_backup_")) );
}
tmp++;
}
// PART 2
// download the file generated above
OutputStream out = response.getOutputStream();
String filepath = "D:\TEMP\sql_dump\";
response.setContentType("APPLICATION/OCTET-STREAM");
response.setHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
FileInputStream fileInputStream = new FileInputStream(filepath + filename);
int i;
while ((i = fileInputStream.read()) != -1) {
out.write(i);
}
out.close();
fileInputStream.close();
}
解决方案 #2 效果很好,我收到了一个下载文件的弹出窗口。
解决方案 #1 调用 servlet doGet 方法(通过上面的 JS 代码,我的 servlet 中的代码被正确执行)但我没有得到下载弹出窗口
我想使用解决方案 #1,因为这让我有机会用加载动画包装 $.post
调用。
我在解决方案 #1 中缺少什么来获取下载弹出窗口?
编辑 1:
我发现$.get()
函数中的data
填充的是想要的文件的内容。例如,我现在可以在 div 中显示 .txt 文件的内容,但我想改为下载所述 .txt 文件。
编辑 2:
已解决,详情请参阅下面的回答 & comment/ansewer 如果您认为可以用更好的方式完成
经过相当长的一段时间尝试让它工作后,我找到了一个可行的解决方案。可能有更好的,但那是我想出的。
希望这对其他人也有帮助。
我在这里所做的基本解释:
- 让表单对 java servlet
执行 GET 请求(通过 JS)
- servlet 执行命令行脚本(在我的例子中是我的 postgreSQL 数据库的 sql- 转储)
- servlet 收集命令行的输出和生成文件的内容(sql_dump)并将它们放入响应中
- 客户端获取响应并将其分成 3 部分(命令行输出、sql_dump-文件的文件名和内容)
- 然后(通过 JS)命令行输出显示在文本区域中,以便更好地了解脚本实际执行的操作
- sql_dump 文件的内容由 JS 代码处理以生成要下载的文件(通过按钮手动或自动)
因此,不用多说,这里我们使用 flow ... 代码 :)
解决方案:
HTML:
<form id="form_download_db_backup">
<input type="submit" value="Create & Download DB-Backup"></br>
<a download="" id="downloadlink" style="display: none">download</a>
</form>
<div class="db_backup_result" id="db_backup_result" style="display: none;">
</br>Commandline-Output</br>
<textarea id ="txta_db_backup_result" rows="4" cols="50"></textarea>
</div>
JS:
$("#form_download_db_backup").submit(function(e){
e.preventDefault();
var spinner = new Spinner().spin();
var target = document.getElementById('content');
target.appendChild(spinner.el);
$.ajax({
url:'settings?type=db_backup',
type:'get',
success:function(data){
spinner.stop();
if(data != ""){
var str_data = "" + data;
// Cut commanline output from data
var commandline_output = str_data.substring( 0, str_data.indexOf("--End") );
//show commanline output in textarea
$("#txta_db_backup_result").html(commandline_output);
// Cut content of db_backup file from data
var sql_dump_content = str_data.substring( str_data.indexOf("--sql_d_s--") + 13,str_data.indexOf("--sql_d_e--") );//|
// Cut filename from data
var filename = str_data.substring( str_data.indexOf("--sql_d_fns--") + 15,str_data.indexOf("--sql_d_fne--") - 2 );
//-------------------------------------------------------------
// Prepare download of backupfile
var link = document.getElementById('downloadlink');
var textFile = null;
var blob_data = new Blob([sql_dump_content], {type: 'text/plain'});
// FOR IE10+ Compatibility
if(window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob_data, filename);
}
// If we are replacing a previously generated file we need to
// manually revoke the object URL to avoid memory leaks.
if (textFile !== null) {
window.URL.revokeObjectURL(textFile);
}
textFile = window.URL.createObjectURL(blob_data);
link.href = textFile;
link.download = filename;
//link.style.display = 'block'; // Use this to make download link visible for manual download
link.click(); // Use this to start download automalically
//-------------------------------------------------------------
// show div containing commandline output & (optional) downloadlink
document.getElementById("db_backup_result").style.display = 'block';
}
}
});
});
Java-Servlet:
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String type = request.getParameter("type");
if(null != type)switch (type) {
case "db_backup":
ServletOutputStream out = response.getOutputStream();
// Prepare multipart response
response.setContentType("multipart/x-mixed-replace;boundary=End");
// Start: First part of response ////////////////////////////////////////////////////////////////////////
// execute commandline script to backup the database
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "D:\TEMP\sql_dump.cmd");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
String filename = "";
int tmp = 0;
while (true) {
line = r.readLine();
if (line == null) { break; }
// code for finding filename not optimal but works for now -> redo later on
if(tmp == 1){
filename = line.substring(line.indexOf("db_backup_"), line.indexOf('"', line.indexOf("db_backup_")) );
}
else{
line = line.replace("\u201E", "\'"); // replaces the lowercase " (DOUBLE LOW-9 QUOTATION MARK)
line = line.replace("\u201C", "\'"); // replaces the uppercase " (LEFT DOUBLE QUOTATION MARK)
}
out.println(line);
tmp++;
}
// End: First part of response ////////////////////////////////////////////////////////////////////////
// Separator of firt & second part
out.println("--End");
out.flush();
// Add filename in response (name of download file)
out.println("--sql_d_fns--"); // separator for filename (used to extract filename from response data)
out.println(filename);
out.println("--sql_d_fne--"); // separator for filename (used to extract filename from response data)
// Start: Second part of response ////////////////////////////////////////////////////////////////////////
out.println("--sql_d_s--"); // separator for content of db-dump (this is the text thats going to be downloaded later on)
String filepath = "D:\TEMP\sql_dump\";
FileInputStream fileInputStream = new FileInputStream(filepath + filename);
int i;
while ((i = fileInputStream.read()) != -1) {
out.write(i);
}
out.println("--sql_d_e--"); // separator for content of db-dump (this is the text thats going to be downloaded later on)
// End: Second part of response ////////////////////////////////////////////////////////////////////////
// End the multipart response
out.println("--End--");
out.flush();
break;
default:
break;
}
}
postgreSQL 转储包含 "lowercase" & "uppercase" 我必须替换的引号。我在这里给每个人都放了一个 link 以防有人也与他们斗争。他们对那里列出的那些字符有多种编码。
我正在尝试通过 Java Servlet 从我的服务器下载文件。 我遇到的问题是,当我直接输入 servlet url (https://localhost:8443/SSP/settings?type=db_backup) 时,我让 servlet 执行它的代码并提示我下载对话框。
但我想通过 Javascript 调用 servlets doGet 方法,用某种进度条包装它。
这里的问题:执行了 servlet 中的代码,但我没有收到文件的下载提示。
到目前为止我的代码:
HTML:
<!-- Solution #1 -->
<button class="btn_do_db_backup" type="button">DB-Backup #1</button>
<!-- Solution #2 -->
<form action="/SSP/settings?type=db_backup" method="GET">
<button type="submit">DB-Backup #2</button></br>
</form>
JS:
// Solution #1
$(".btn_do_db_backup").click(function(e){
e.preventDefault();
$.get("settings?type=db_backup", function(data){
if(data != ""){
//further coding
}
});
// Having the code below works but doesnt
// give me the chance to wrap the call with a loading animation
//document.location = "/SSP/settings?type=db_backup";
});
Servlet:
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
// PART 1
// execute srcipt to generate file to download later on
StringBuffer output = new StringBuffer();
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "D:\TEMP\sql_dump.cmd");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
String filename = "";
int tmp = 0;
while (true) {
line = r.readLine();
if (line == null) { break; }
output.append(line + "\n");
// code for finding filename not optimal but works for now -> redo later on
if(tmp == 1){
filename = line.substring(line.indexOf("db_backup_"), line.indexOf('"', line.indexOf("db_backup_")) );
}
tmp++;
}
// PART 2
// download the file generated above
OutputStream out = response.getOutputStream();
String filepath = "D:\TEMP\sql_dump\";
response.setContentType("APPLICATION/OCTET-STREAM");
response.setHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
FileInputStream fileInputStream = new FileInputStream(filepath + filename);
int i;
while ((i = fileInputStream.read()) != -1) {
out.write(i);
}
out.close();
fileInputStream.close();
}
解决方案 #2 效果很好,我收到了一个下载文件的弹出窗口。
解决方案 #1 调用 servlet doGet 方法(通过上面的 JS 代码,我的 servlet 中的代码被正确执行)但我没有得到下载弹出窗口
我想使用解决方案 #1,因为这让我有机会用加载动画包装 $.post
调用。
我在解决方案 #1 中缺少什么来获取下载弹出窗口?
编辑 1:
我发现$.get()
函数中的data
填充的是想要的文件的内容。例如,我现在可以在 div 中显示 .txt 文件的内容,但我想改为下载所述 .txt 文件。
编辑 2:
已解决,详情请参阅下面的回答 & comment/ansewer 如果您认为可以用更好的方式完成
经过相当长的一段时间尝试让它工作后,我找到了一个可行的解决方案。可能有更好的,但那是我想出的。
希望这对其他人也有帮助。
我在这里所做的基本解释:
- 让表单对 java servlet 执行 GET 请求(通过 JS)
- servlet 执行命令行脚本(在我的例子中是我的 postgreSQL 数据库的 sql- 转储)
- servlet 收集命令行的输出和生成文件的内容(sql_dump)并将它们放入响应中
- 客户端获取响应并将其分成 3 部分(命令行输出、sql_dump-文件的文件名和内容)
- 然后(通过 JS)命令行输出显示在文本区域中,以便更好地了解脚本实际执行的操作
- sql_dump 文件的内容由 JS 代码处理以生成要下载的文件(通过按钮手动或自动)
因此,不用多说,这里我们使用 flow ... 代码 :)
解决方案:
HTML:
<form id="form_download_db_backup">
<input type="submit" value="Create & Download DB-Backup"></br>
<a download="" id="downloadlink" style="display: none">download</a>
</form>
<div class="db_backup_result" id="db_backup_result" style="display: none;">
</br>Commandline-Output</br>
<textarea id ="txta_db_backup_result" rows="4" cols="50"></textarea>
</div>
JS:
$("#form_download_db_backup").submit(function(e){
e.preventDefault();
var spinner = new Spinner().spin();
var target = document.getElementById('content');
target.appendChild(spinner.el);
$.ajax({
url:'settings?type=db_backup',
type:'get',
success:function(data){
spinner.stop();
if(data != ""){
var str_data = "" + data;
// Cut commanline output from data
var commandline_output = str_data.substring( 0, str_data.indexOf("--End") );
//show commanline output in textarea
$("#txta_db_backup_result").html(commandline_output);
// Cut content of db_backup file from data
var sql_dump_content = str_data.substring( str_data.indexOf("--sql_d_s--") + 13,str_data.indexOf("--sql_d_e--") );//|
// Cut filename from data
var filename = str_data.substring( str_data.indexOf("--sql_d_fns--") + 15,str_data.indexOf("--sql_d_fne--") - 2 );
//-------------------------------------------------------------
// Prepare download of backupfile
var link = document.getElementById('downloadlink');
var textFile = null;
var blob_data = new Blob([sql_dump_content], {type: 'text/plain'});
// FOR IE10+ Compatibility
if(window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob_data, filename);
}
// If we are replacing a previously generated file we need to
// manually revoke the object URL to avoid memory leaks.
if (textFile !== null) {
window.URL.revokeObjectURL(textFile);
}
textFile = window.URL.createObjectURL(blob_data);
link.href = textFile;
link.download = filename;
//link.style.display = 'block'; // Use this to make download link visible for manual download
link.click(); // Use this to start download automalically
//-------------------------------------------------------------
// show div containing commandline output & (optional) downloadlink
document.getElementById("db_backup_result").style.display = 'block';
}
}
});
});
Java-Servlet:
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String type = request.getParameter("type");
if(null != type)switch (type) {
case "db_backup":
ServletOutputStream out = response.getOutputStream();
// Prepare multipart response
response.setContentType("multipart/x-mixed-replace;boundary=End");
// Start: First part of response ////////////////////////////////////////////////////////////////////////
// execute commandline script to backup the database
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "D:\TEMP\sql_dump.cmd");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
String filename = "";
int tmp = 0;
while (true) {
line = r.readLine();
if (line == null) { break; }
// code for finding filename not optimal but works for now -> redo later on
if(tmp == 1){
filename = line.substring(line.indexOf("db_backup_"), line.indexOf('"', line.indexOf("db_backup_")) );
}
else{
line = line.replace("\u201E", "\'"); // replaces the lowercase " (DOUBLE LOW-9 QUOTATION MARK)
line = line.replace("\u201C", "\'"); // replaces the uppercase " (LEFT DOUBLE QUOTATION MARK)
}
out.println(line);
tmp++;
}
// End: First part of response ////////////////////////////////////////////////////////////////////////
// Separator of firt & second part
out.println("--End");
out.flush();
// Add filename in response (name of download file)
out.println("--sql_d_fns--"); // separator for filename (used to extract filename from response data)
out.println(filename);
out.println("--sql_d_fne--"); // separator for filename (used to extract filename from response data)
// Start: Second part of response ////////////////////////////////////////////////////////////////////////
out.println("--sql_d_s--"); // separator for content of db-dump (this is the text thats going to be downloaded later on)
String filepath = "D:\TEMP\sql_dump\";
FileInputStream fileInputStream = new FileInputStream(filepath + filename);
int i;
while ((i = fileInputStream.read()) != -1) {
out.write(i);
}
out.println("--sql_d_e--"); // separator for content of db-dump (this is the text thats going to be downloaded later on)
// End: Second part of response ////////////////////////////////////////////////////////////////////////
// End the multipart response
out.println("--End--");
out.flush();
break;
default:
break;
}
}
postgreSQL 转储包含 "lowercase" & "uppercase" 我必须替换的引号。我在这里给每个人都放了一个 link 以防有人也与他们斗争。他们对那里列出的那些字符有多种编码。