この記事では、主に次の 3 つの側面から Web ワーク ファイルのアップロードとダウンロードに関する知識を紹介します。
1. 梱包リクエストリクエスト
2. ファイルアップロード用の解析クラスを取得します
3. 実際のプロジェクト構成と使い方
Web アップロードとダウンロードは、小規模な Web サイトであっても、大量の同時アクセスがある取引 Web サイトであっても、非常に一般的な要件です。もちろん、WebWork はファイルのアップロードを実装するための非常に使いやすいインターセプターも提供するため、アップロードとダウンロードを実装する際には、フレームワークのアップロードとダウンロードの実装にも注意を払うことができます。
1. 梱包リクエストリクエスト
•クライアントがActionをリクエストするたびに、WebWorkディスパッチクラスのServletDispatcher.service()メソッドが呼び出されます。
具体的な処理については、Webwork での Action 呼び出し方法の詳しい説明
をご参照ください。public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException { try { if (encoding != null) { try { request.setCharacterEncoding(encoding); } catch (Exception localException) { } } if (locale != null) { response.setLocale(locale); } if (this.paramsWorkaroundEnabled) { request.getParameter("foo"); } request = wrapRequest(request); //封装 request请求 serviceAction(request, response, getNameSpace(request), getActionName(request), getRequestMap(request), getParameterMap(request), getSessionMap(request), getApplicationMap()); } catch (IOException e) { String message = "Could not wrap servlet request with MultipartRequestWrapper!"; log.error(message, e); sendError(request, response, 500, new ServletException(message, e)); } }
まず、wrapRequest メソッドの動作を見てみましょう:
protected HttpServletRequest wrapRequest(HttpServletRequest request) throws IOException { if ((request instanceof MultiPartRequestWrapper)) { return request; } if (MultiPartRequest.isMultiPart(request)) { request = new MultiPartRequestWrapper(request, getSaveDir(), getMaxSize()); } return request; }
• まず、受信リクエストが MultiPartRequestWrapper によってカプセル化されているかどうかを判断します。カプセル化されている場合は、直接戻ります。
• それ以外の場合、リクエストのヘッダー情報の ContentType がマルチタイプ パラメータ (multipart/formdata) リクエストであるかどうかを確認します。そうである場合は、HttpServletRequestWrapper を継承する WebWork 独自の MultiPartRequestWrapper タイプにリクエストをラップします。
MultiPartRequest.isMultiPart() メソッドは次のように実装されます:
public static boolean isMultiPart(HttpServletRequest request){ String content_type = request.getHeader("Content-Type"); return content_type != null && content_type.startsWith("multipart/form-data"); }
•ファイルの一時保存ディレクトリの構成と、webwork.properties での最大アップロード サイズは、この時点で実際に影響します。
•MultiPartRequestWrapper オブジェクトの作成時に渡されるパラメータは、getSaveDir() メソッドと getMaxSize() メソッドによって取得されます。
• このメソッドでは、設定内の webwork.multipart.saveDir および webwork.multipart.maxSize 属性が検索され、見つからない場合は、属性で指定された一時ディレクトリが使用されます。環境のディレクトリが使用されます。
具体的な実装は次のとおりです:
protected String getSaveDir() { String saveDir = Configuration.getString("webwork.multipart.saveDir").trim(); if (saveDir.equals("")) { File tempdir = (File) getServletConfig().getServletContext().getAttribute("javax.servlet.context.tempdir"); log.info("Unable to find 'webwork.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir"); if (tempdir != null) { saveDir = tempdir.toString(); } } else { File multipartSaveDir = new File(saveDir); if (!multipartSaveDir.exists()) { multipartSaveDir.mkdir(); } } if (log.isDebugEnabled()) { log.debug("saveDir=" + saveDir); } return saveDir; }
2. ファイルアップロード用の解析クラスを取得します
MultiPartRequestWrapper のコンストラクターがリクエストをどのようにラップするかを見てみましょう:
public MultiPartRequestWrapper(HttpServletRequest request, String saveDir, int maxSize) throws IOException { super(request); if ((request instanceof MultiPartRequest)) { this.multi = ((MultiPartRequest) request); } else { String parser = ""; parser = Configuration.getString("webwork.multipart.parser"); if (parser.equals("")) { log.warn("Property webwork.multipart.parser not set. Using com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest"); parser = "com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest"; } else if (parser.equals("pell")) { parser = "com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest"; } else if (parser.equals("cos")) { parser = "com.opensymphony.webwork.dispatcher.multipart.CosMultiPartRequest"; } else if (parser.equals("jakarta")) { parser = "com.opensymphony.webwork.dispatcher.multipart.JakartaMultiPartRequest"; } try { Class baseClazz = MultiPartRequest.class; Class clazz = Class.forName(parser); if (!baseClazz.isAssignableFrom(clazz)) { addError("Class '" + parser + "' does not extend MultiPartRequest"); return; } Constructor ctor = clazz.getDeclaredConstructor(new Class[] { Class.forName("javax.servlet.http.HttpServletRequest"), String.class, Integer.TYPE }); Object[] parms = { request, saveDir, new Integer(maxSize) }; this.multi = ((MultiPartRequest) ctor.newInstance(parms)); } catch (ClassNotFoundException e) { addError("Class: " + parser + " not found."); } catch (NoSuchMethodException e) { addError("Constructor error for " + parser + ": " + e); } catch (InstantiationException e) { addError("Error instantiating " + parser + ": " + e); } catch (IllegalAccessException e) { addError("Access errror for " + parser + ": " + e); } catch (InvocationTargetException e) { addError(e.getTargetException().toString()); } } }
• まず、受信したリクエストが MultiPartRequest 抽象クラスのサブクラスであるかどうかを判断し、そうである場合は、独自の MultiPartRequest 型変数によってリクエストを直接参照します。
• それ以外の場合は、WebWork 構成の webwork.multipart.parser プロパティを読み取ります。これにより、ファイル アップロードを実装するために Webwork が内部的に使用するものが決まります。 指定しない場合、デフォルトで PellMultiPartRequest の実装が使用されます。
•設定されたクラスを見つけた後、WebWork は Java リフレクションを介してそのクラスのインスタンスを作成します。サポートされているすべてのクラスは、インスタンスの作成後、MultiPartRequestWrapper のメンバー multi に割り当てられます。
• WebWork のファイル アップロードは、いくつかの一般的な FileUpload ライブラリをカプセル化しており、単独では実装されません。
•これには、pell、cos、および apache common の 3 つの実装が含まれています。WebWork は、これら 3 つのパッケージをカプセル化し、共通のアクセス インターフェイス MultiPartRequest を提供します。詳細な実装は、PellMultiPartRequest、CosMultiPartRequest、および JakartaMultiPartRequest です。
• jakarta は、同じ HTTP パラメーター名を使用する複数のファイルをサポートします。 WebWork の FileUpload インターセプターを直接使用する場合は、pell を使用することをお勧めします。中国語のファイル名を持つファイルをアップロードすると、pell パッケージのみが中国語のファイル名を正しく取得し、Apache common がファイル名をファイルに変更するためです。 xxx.tmp 名のように、cos が文字化けしてしまうため、唯一の選択肢は pell です。
• cos の機能は比較的強力ですが、WebWork のカプセル化により、cos はリクエストの文字エンコーディングを設定する必要がある多くの機能を失います。 WebWork のカプセル化が設定されていないため、cos の文字化けの問題が発生します。もちろん、cos を単独で使用すれば、そのような問題は回避されます。
3. 実際のプロジェクト構成と使用方法
• 設定ファイル
アクション構成:
<action name="uploadAttach" class=".....attach.action.uploadAttach" caption="上传附件"> <result name="success" type="dispatcher"> <param name="location">/result.jsp</param> </result> <result name="error" type="dispatcher"> <param name="location">/result.jsp</param> </result> <interceptor-ref name="defaultStack" /> <interceptor-ref name="fileUploadStack" /> //webwok 上传所需要的拦截栈 </action> //拦截栈的定义 <interceptor-stack name="fileUploadStack"> <interceptor-ref name="fileUpload"/> <interceptor-ref name="params"/> </interceptor-stack> //拦截栈对应的拦截器 <interceptor name="fileUpload" class="com.opensymphony.webwork.interceptor.FileUploadInterceptor"/> <interceptor name="params" class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/>
•フロントエンドは比較的安定していて強力な Ajaxupload を使用します。ここでは詳しく説明しません。jQuery AjaxUpload 画像アップロード コード
。•Webwork アップロード リクエストをカプセル化し、解析クラスを取得することにより、アップロード インターセプターの具体的な実装は次のように準備されています。
public String intercept(ActionInvocation invocation) throws Exception {if (!(ServletActionContext.getRequest() instanceof MultiPartRequestWrapper)) { if (log.isDebugEnabled()) { log.debug("bypass " + invocation.getProxy().getNamespace() + "/" + invocation.getProxy().getActionName()); } return invocation.invoke(); } Action action = invocation.getAction(); ValidationAware validation = null; if ((action instanceof ValidationAware)) { validation = (ValidationAware) action; } MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) ServletActionContext.getRequest(); if (multiWrapper.hasErrors()) { Collection errors = multiWrapper.getErrors(); Iterator i = errors.iterator(); while (i.hasNext()) { String error = (String) i.next(); if (validation != null) { validation.addActionError(error); } log.error(error); } } Enumeration e = multiWrapper.getFileParameterNames(); while ((e != null) && (e.hasMoreElements())) { String inputName = (String) e.nextElement(); String[] contentType = multiWrapper.getContentTypes(inputName); String[] fileName = multiWrapper.getFileNames(inputName); File[] file = multiWrapper.getFiles(inputName); if (file != null) { for (int i = 0; i < file.length; i++) { log.info("file " + inputName + " " + contentType[i] + " " + fileName[i] + " " + file[i]); } } if (file == null) { if (validation != null) { validation.addFieldError(inputName, "Could not upload file(s). Perhaps it is too large?"); } log.error("Error uploading: " + fileName); } else { invocation.getInvocationContext().getParameters().put(inputName, file); invocation.getInvocationContext().getParameters().put(inputName + "ContentType", contentType); invocation.getInvocationContext().getParameters().put(inputName + "FileName", fileName); } } String result = invocation.invoke(); for (Enumeration e1 = multiWrapper.getFileParameterNames(); e1 != null && e1.hasMoreElements();) { String inputValue = (String) e1.nextElement(); File file[] = multiWrapper.getFiles(inputValue); for (int i = 0; i < file.length; i++) { File f = file[i]; log.info("removing file " + inputValue + " " + f); if (f != null && f.isFile()) f.delete(); } } return result; }
•First determine whether the current request contains a multimedia request, if so, record the log and execute the action.
•Then determine whether the MultiPartRequestWrapper contains errors during the file upload process, return the error information to the client, and do not continue to call Action.
•If none of the above judgment conditions are met, start traversing the parameters of the uploaded file in MultiPartRequestWrapper, and put the file name and file content type into the Action parameter map for subsequent business classes to operate.
•In the fileupload interceptor function of WebWork, the File it provides is only a temporary file, which will be automatically deleted after the Action is executed. You must handle the storage of the file yourself in the Action, or write it to a directory on the server, or Save to database. If you plan to write to a directory on the server, you must face the problem of dealing with the same name of the file yourself, but in fact the cos package already provides automatic renaming rules for file renames.
The above code introduces you to the relevant knowledge of Webwork for file upload and download. I hope it will be helpful to you.