一方、AJAX XmlHttpRequestを介してサーブレットを呼び出してエラーメッセージを表示できますが、ファイルを返す方法はありますか? XHRオブジェクトのコールバック関数は、サーバーから受信したバイナリデータでは機能せず、標準の「ファイルの保存/読み込み」ブラウザダイアログを表示できません。
私たちはこの方法から抜け出しました。 クライアントはサーブレットを2回呼び出します。 ステップ1で、彼はサーバーストレージからファイルをダウンロードするように要求し(これに必要なすべてのパラメーターを渡すAJAXテクノロジーを使用)、サーブレットはファイルを読み取り、そのコンテンツ、名前、MIMEタイプ、およびその他の属性をセッションに入れ、クライアントに応答します( JSON応答形式 )特定の
session_id
(ドキュメントが正常に受信され、クライアントを待機している)、またはJavaScriptが
window.alert()
介してクライアントに簡単に表示できるエラー文字列のいずれか。 ステップ1でsession_idを受信すると、クライアントは2番目の移動を行います。フォームの通常の転送を使用します
example.com/servletname?session_id=123456
example.com/servletname?session_id=123456
は、このパラメーターを使用して同じサーブレットにすぐに次のリクエストを行い、
Content-Type: application/octet-stream
を受信します。応答として
Content-Type: application/octet-stream
同志。これにより、最終的にブラウザーに標準ダイアログが表示されます。 その後、ドキュメントはセッションから削除され、スペースが解放されます。
いくつかの短いメモ:
- AJAXキッチン全体では、 MochiKitの古いバージョン1.3.1を使用します。
- ファイル名に非ASCII文字を含むドキュメントを発行する場合、この名前はすべてのブラウザーで正しく表示されません。
- JSON回答の形成には、既製のライブラリ、たとえば一般的なjson-libを使用できますが、このような小さなタスクでは、プロジェクトに新しい依存関係を追加したくありませんでした。
作業の追加の説明は、提示されたコードで取得できます。
AbstractGetFileAJAXWay.java
作業の大部分を行う抽象Javaクラス。 特定の継承クラスは、各ケースに固有の2つのメソッドを実装する必要があります。
package unchqua.getfileajaxway;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Random;
/**
* .
*
* <p> :</p>
* <dl>
* <dt>populateIdentity(HttpServletRequest)</dt>
* <dd> ,
* .</dd>
* <dt>getDocument(HttpServletRequest, Object)</dt>
* <dd> .</dd>
* </dl>
*
* <p>
* : EJB (
* ),
* AbstractGetFileAJAXWay#DSID (,
* ) .
* </p>
*
* <p> JSON- :</p>
* <ul>
* <li> EJB:<br/>
* <pre>{"result":"success","dsid":"362547383846347775"}</pre>
* </li>
* <li> EJB:<br/>
* <pre>{"result":"failure","reason":" !"}</pre>
* </li>
* </ul>
*/
public abstract class AbstractGetFileAJAXWay extends HttpServlet {
public static final String DSID = "dsid";
public class GetFileAJAXWayException extends Exception {
public GetFileAJAXWayException() { super(); }
public GetFileAJAXWayException(String msg) { super(msg); }
public GetFileAJAXWayException(Throwable thw) { super(thw); }
public GetFileAJAXWayException(String msg, Throwable thw) { super(msg, thw); }
}
public interface IFileContainer extends Serializable {
public String getFileName();
public String getContentType();
public long getFileLength();
public byte[] getFileContent();
}
/**
* .
*
* @param req HTTP-.
* @param resp HTTP-.
* @throws ServletException
* @throws IOException
*/
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// .
String dsid = req.getParameter(DSID);
// .
if (dsid != null && dsid.length() > 0) {
try {
deliverDocument(dsid, req, resp);
} catch (GetFileAJAXWayException e) {
e.printStackTrace();
throw new ServletException(e);
}
}
// .
else if (req.getParameterMap().size() > 0) {
try {
Object identity = populateIdentity(req);
retrieveDocument(identity, req, resp);
} catch (GetFileAJAXWayException e) {
e.printStackTrace();
throw new ServletException(e);
}
}
// .
else {
final String err = " !";
log(err);
sendFailureReply(err, resp);
return;
}
}
/**
* .
* @param identity , . * @param req HTTP-.
* @param resp HTTP-.
* @throws ServletException
* @throws IOException
*/
private void retrieveDocument
(Object identity, HttpServletRequest req, HttpServletResponse resp)
throws IOException {
// .
HttpSession session = req.getSession(false);
// , .
IFileContainer cont;
try {
cont = getDocument(req, identity);
} catch (Exception e) {
final String err = " : "
+ e.getMessage() + "!";
log(err);
sendFailureReply(err, resp);
return;
}
// .
final String dsid = dsid(
new long[]{ cont.hashCode(),
cont.getFileLength(),
session.hashCode() });
// .
session.setAttribute(dsid, cont);
// .
sendSuccessReply(dsid, resp);
}
/**
* .
* @param dsid .
* @param req HTTP-.
* @param resp HTTP-.
* @throws ServletException
* @throws IOException
*/
private void deliverDocument
(String dsid, HttpServletRequest req, HttpServletResponse resp)
throws GetFileAJAXWayException, IOException {
// .
HttpSession session = req.getSession(false);
// ?
Object sessobj = session.getAttribute(dsid);
if (sessobj == null) {
throw new GetFileAJAXWayException(" \"" + DSID + "\" !");
} else if (!(sessobj instanceof IFileContainer)) {
throw new GetFileAJAXWayException(" \"" + DSID + "\" !");
}
// .
session.removeAttribute(dsid);
// .
IFileContainer document = (IFileContainer) sessobj;
// .
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentLength((int) document.getFileLength());
resp.setContentType(document.getContentType());
resp.setHeader("Content-Transfer-Encoding", "binary");
/* // -- IE
String filename = "=?windows-1251?Q?" + new org.apache.commons.codec.net.QuotedPrintableCodec().encode(document.getFileName(), "Cp1251") + "?=";
resp.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
*/
/* // IE --
String filename = java.net.URLEncoder.encode(document.getFileName(), "Cp1251").replaceAll("\\+", " ");
resp.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
*/
/**/ // -
String filename = document.getFileName();
int dotpos = filename.lastIndexOf('.');
if (dotpos > -1)
filename = "file." + filename.substring(dotpos + 1);
else
filename = "file.dat";
resp.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
/**/
OutputStream out = resp.getOutputStream();
out.write(document.getFileContent());
out.flush();
out.close();
}
/**
* , .
*
* @param trashheap .
* <tt>null</tt>, .
* @return .
*/
private String dsid(long[] trashheap) {
long dsid = System.currentTimeMillis();
if (trashheap != null && trashheap.length > 0)
for (int i = 0; i < trashheap.length; i++)
dsid ^= trashheap[i];
return Long.toString(Math.abs(new Random(dsid).nextLong()), 10);
}
/**
* JSON.
* @param subject .
* @return .
*/
private String escapeJSON(String subject) {
if (subject == null || subject.length() == 0)
return "";
return subject.replaceAll("\"", "\\\"")
.replaceAll("\\\\", "\\\\")
.replaceAll("[\n\r]", "\\\\n");
}
/**
* JSON- .
* @param dsid , () .
* @param resp HTTP-.
* @throws ServletException
* @throws IOException
*/
private void sendSuccessReply(String dsid, HttpServletResponse resp)
throws IOException {
String dsidJSON = "{\"result\":\"success\",\"dsid\":\""
+ escapeJSON(dsid) + "\"}";
sendAnyReply(dsidJSON, resp);
}
/**
* JSON- .
* @param reason .
* @param resp HTTP-.
* @throws ServletException
* @throws IOException
*/
private void sendFailureReply(String reason, HttpServletResponse resp)
throws IOException {
String reasonJSON = "{\"result\":\"failure\",\"reason\":\""
+ escapeJSON(reason) + "\"}";
sendAnyReply(reasonJSON, resp);
}
/**
* .
* @param json .
* @param resp HTTP-.
* @throws IOException
*/
private void sendAnyReply(String json, HttpServletResponse resp)
throws IOException {
final byte[] result_bytes = json.getBytes("UTF-8");
final int CHUNK = 1024;
final BufferedOutputStream output = new BufferedOutputStream(
resp.getOutputStream(), CHUNK);
resp.setStatus(HttpServletResponse.SC_OK);
resp.setHeader("Content-Encoding", "UTF-8");
resp.setContentType("text/plain; charset=UTF-8");
resp.setContentLength(result_bytes.length);
int bytes_pos = 0, bytes_chunk = 0;
do {
bytes_chunk = bytes_pos + CHUNK <= result_bytes.length
? CHUNK
: result_bytes.length - bytes_pos;
output.write(result_bytes, bytes_pos, bytes_chunk);
bytes_pos += bytes_chunk;
} while (bytes_pos < result_bytes.length);
output.flush();
output.close();
}
/**
* .
* @param req HTTP-.
* @return , {@link #getDocument(Object)}
* .
* @throws GetFileAJAXWayException
* .
*/
protected abstract Object populateIdentity(HttpServletRequest req)
throws GetFileAJAXWayException;
/**
* ,
* .
* @param req HTTP-.
* @param identity .
* @return .
* @throws GetFileAJAXWayException .
*/
protected abstract IFileContainer getDocument(HttpServletRequest req,
Object identity) throws GetFileAJAXWayException;
}
ConcreteDocumentRetrievalServlet.java
特定のケースに必要なロジックを実装する継承クラス。
package unchqua.getfileajaxway;
public class ConcreteDocumentRetrievalServlet extends AbstractGetFileAJAXWay {
public ConcreteDocumentRetrievalServlet() {
super();
}
public Object populateIdentity(HttpServletRequest req)
throws GetFileAJAXWayException {
// .
return null;
}
public IFileContainer getDocument(HttpServletRequest req, Object identity)
throws GetFileAJAXWayException {
// .
return null;
}
}
GetFileAJAXWay.jsp
サーブレットと対話するJSPファイルの例。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>
<meta http-equiv="Expires" content="Tue, Feb 07 1978 15:30:00 GMT"/>
<meta http-equiv="Content-Style-Type" content="text/css"/>
<meta http-equiv="Content-Script-Type" content="text/javascript"/>
<title>GetFileAJAXWay example</title>
<!-- MochiKit. -->
<script type="text/javascript" src="/MochiKit-1.3.1/Base.js"></script>
<script type="text/javascript" src="/MochiKit-1.3.1/Iter.js"></script>
<script type="text/javascript" src="/MochiKit-1.3.1/DOM.js"></script>
<script type="text/javascript" src="/MochiKit-1.3.1/Async.js"></script>
<script type="text/javascript">
<!--
// .
var SERVLET_PATH = "/servletname"; // unchqua.ConcreteDocumentRetrievalServlet .
// URL .
var SERVLET_URL = document.location.protocol + '//'
+ document.location.hostname
+ (document.location.port > 0 ? ':' + document.location.port : '')
+ SERVLET_PATH;
/**
* AJAX-.
*/
function JS_AJAX_GetElFAFile(reqid) {
// .
var parameters = {};
parameters["reqid"] = reqid; // reqid – .
parameters["rand"] = new Date().getTime(); // .
// .
loadJSONDoc(SERVLET_URL, parameters)
.addCallbacks(
JS_AJAX_GetElFAFile_Success,
JS_AJAX_GetElFAFile_Failure);
}
/**
* AJAX- .
*/
function JS_AJAX_GetElFAFile_Success(jsondata) {
// ?
if (JS_AJAX_GetElFAFile_Is_response_error(jsondata)) {
JS_AJAX_GetElFAFile_Failure(jsondata);
return;
}
else if (typeof(jsondata.dsid) == "undefined") {
JS_AJAX_GetElFAFile_Failure("Document is not received!");
return;
}
// .
window.location.href = SERVLET_URL + "?dsid=" + jsondata.dsid;
}
/**
* AJAX- .
*/
function JS_AJAX_GetElFAFile_Failure(jsondata) {
var error_text =
(typeof(jsondata.result) != "undefined"
&& jsondata.result == "failure"
&& typeof(jsondata.reason) != "undefined"
&& jsondata.reason.length > 0)
? jsondata.reason
: jsondata.message + " (" + jsondata.number + ")";
window.alert(error_text);
}
/**
* Is response error?
*
* jsonadata: JSON object just received.
*
* Returns flag (true/false).
*/
function JS_AJAX_GetElFAFile_Is_response_error(jsondata) {
// ( ).
var artifical_error = typeof(jsondata.result) != "undefined"
&& jsondata.result == "failure";
// Internal server error.
var hard_error = typeof(jsondata.number) != "undefined"
&& typeof(jsondata.message) != "undefined"
&& jsondata.number == 500;
return artifical_error || hard_error;
}
//-->
</script>
</head>
<body>
<a href="javascript:JS_AJAX_GetElFAFile(/*docid=*/123);"> !</a>
</body>
</html>