परिचय
अपलोड करने के लिए फ़ाइल को ब्राउज़ करने और चुनने के लिए आपको <input type="file">
प्रपत्र में एक HTML फ़ील्ड की आवश्यकता होती है । जैसा कि HTML विनिर्देश में कहा गया है कि आपको POST
विधि का उपयोग करना होगा और enctype
प्रपत्र की विशेषता को सेट करना होगा "multipart/form-data"
।
<form action="upload" method="post" enctype="multipart/form-data">
<input type="text" name="description" />
<input type="file" name="file" />
<input type="submit" />
</form>
इस तरह के फॉर्म को जमा करने के बाद, बाइनरी मल्टीपार्ट फॉर्म डेटा अनुरोध निकाय में एक अलग प्रारूप में उपलब्ध होता है जब वह enctype
सेट नहीं होता है।
सर्वलेट 3.0 से पहले, सर्वलेट एपीआई ने मूल रूप से समर्थन नहीं किया multipart/form-data
। यह केवल डिफ़ॉल्ट रूप का समर्थन करता है application/x-www-form-urlencoded
। request.getParameter()
और पत्नी के सभी वापसी करेंगे null
जब बहुखण्डीय प्रपत्र डेटा का उपयोग कर। यह वह जगह है जहाँ प्रसिद्ध अपाचे कॉमन्स FileUpload तस्वीर में आया था।
इसे मैन्युअल रूप से पार्स न करें!
आप सिद्धांत रूप में अनुरोध निकाय को स्वयं के आधार पर पार्स कर सकते हैं ServletRequest#getInputStream()
। हालांकि, यह एक सटीक और थकाऊ काम है जिसके लिए RFC2388 के सटीक ज्ञान की आवश्यकता होती है । आपको अपने स्वयं के या कुछ होमग्रोन लाइब्रेरी-कम-कोड को इंटरनेट पर कहीं और पाए जाने के लिए ऐसा करने का प्रयास नहीं करना चाहिए। बहुत से ऑनलाइन स्रोत इसमें असफल रहे हैं, जैसे कि roseindia.net। पीडीएफ फाइल को अपलोड करना भी देखें । आपको बरसों तक लाखों उपयोगकर्ताओं द्वारा उपयोग की जाने वाली एक वास्तविक लाइब्रेरी का उपयोग किया जाना चाहिए (और अंतर्निहित परीक्षण!)। इस तरह की लाइब्रेरी ने अपनी मजबूती साबित की है।
जब आप पहले से ही सर्वलेट 3.0 या नए पर हों, तो देशी एपीआई का उपयोग करें
यदि आप कम से कम सर्वलेट 3.0 (टॉमकैट 7, जेटी 9, जेबॉस 6, ग्लासफिश 3, आदि) का उपयोग कर रहे हैं, तो आप केवल मानक एपीआई का उपयोग HttpServletRequest#getPart()
करके व्यक्तिगत मल्टीपार्ट फॉर्म डेटा आइटम (सबसे सर्वलेट 3.0 कार्यान्वयन) वास्तव में अपाचे का उपयोग कर सकते हैं। इसके लिए कवर के तहत कॉमन्स फाइलअपलोड!)। साथ ही, सामान्य फॉर्म फ़ील्ड getParameter()
सामान्य तरीके से उपलब्ध हैं ।
पहले अपने सर्वलेट को एनोटेट करें @MultipartConfig
ताकि वह उसे पहचान सके और multipart/form-data
अनुरोधों का समर्थन कर सके और इस तरह getPart()
काम कर सके:
@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
// ...
}
फिर, doPost()
इस प्रकार लागू करें :
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String description = request.getParameter("description"); // Retrieves <input type="text" name="description">
Part filePart = request.getPart("file"); // Retrieves <input type="file" name="file">
String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
InputStream fileContent = filePart.getInputStream();
// ... (do your job here)
}
ध्यान दें Path#getFileName()
। यह फ़ाइल नाम प्राप्त करने के लिए एक MSIE फिक्स है। यह ब्राउज़र गलत फ़ाइल नाम के बजाय केवल फ़ाइल नाम के साथ पूर्ण फ़ाइल पथ भेजता है।
यदि आपके पास <input type="file" name="file" multiple="true" />
बहु-फ़ाइल अपलोड के लिए है, तो उन्हें नीचे के रूप में इकट्ठा करें (दुर्भाग्य से ऐसी कोई विधि नहीं है request.getParts("file")
):
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ...
List<Part> fileParts = request.getParts().stream().filter(part -> "file".equals(part.getName()) && part.getSize() > 0).collect(Collectors.toList()); // Retrieves <input type="file" name="file" multiple="true">
for (Part filePart : fileParts) {
String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
InputStream fileContent = filePart.getInputStream();
// ... (do your job here)
}
}
जब आप सर्वलेट 3.1 पर नहीं होते हैं, तो मैन्युअल रूप से सबमिट किया गया फ़ाइल नाम प्राप्त करें
ध्यान दें कि Part#getSubmittedFileName()
सर्वलेट 3.1 (टॉमकैट 8, जेट्टी 9, वाइल्डली 8, ग्लासफिश 4, आदि) में पेश किया गया था। यदि आप अभी तक सर्वलेट 3.1 पर नहीं हैं, तो आपको प्रस्तुत फ़ाइल नाम प्राप्त करने के लिए एक अतिरिक्त उपयोगिता विधि की आवश्यकता है।
private static String getSubmittedFileName(Part part) {
for (String cd : part.getHeader("content-disposition").split(";")) {
if (cd.trim().startsWith("filename")) {
String fileName = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
return fileName.substring(fileName.lastIndexOf('/') + 1).substring(fileName.lastIndexOf('\\') + 1); // MSIE fix.
}
}
return null;
}
String fileName = getSubmittedFileName(filePart);
फ़ाइल का नाम प्राप्त करने के लिए MSIE फिक्स पर ध्यान दें। यह ब्राउज़र गलत फ़ाइल नाम के बजाय केवल फ़ाइल नाम के साथ पूर्ण फ़ाइल पथ भेजता है।
जब आप सर्वलेट 3.0 पर नहीं होते हैं, तो Apache Commons FileUpload का उपयोग करें
यदि आप अभी तक सर्वलेट 3.0 पर नहीं हैं (यह अपग्रेड करने के लिए समय के बारे में नहीं है?), मल्टीपार्ट फॉर्म डेटा अनुरोधों को पार्स करने के लिए आम अभ्यास अपाचे कॉमन्स फाइलअपलोड का उपयोग करना है। इसमें एक उत्कृष्ट उपयोगकर्ता मार्गदर्शिका और अक्सर पूछे जाने वाले प्रश्न (ध्यान से दोनों के माध्यम से जाना) है। ओ'रेली (" कॉस ") भी है MultipartRequest
, लेकिन इसमें कुछ (मामूली) कीड़े हैं और सक्रिय रूप से वर्षों तक बनाए नहीं रखा गया है। मैं इसे इस्तेमाल करने की सलाह नहीं दूंगा। Apache Commons FileUpload अभी भी सक्रिय रूप से बनाए रखा गया है और वर्तमान में बहुत परिपक्व है।
Apache Commons FileUpload का उपयोग करने के लिए, आपको अपने वेबपृष्ठ में कम से कम निम्न फ़ाइलें होनी चाहिए /WEB-INF/lib
:
आपका प्रारंभिक प्रयास सबसे अधिक संभावना में विफल रहा क्योंकि आप कॉमन्स IO को भूल गए।
अपाचे कॉमन्स FileUpload का उपयोग करते समय doPost()
आपके UploadServlet
दिखने में कैसा हो सकता है, इसका एक किकऑफ़ उदाहरण है :
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
for (FileItem item : items) {
if (item.isFormField()) {
// Process regular form field (input type="text|radio|checkbox|etc", select, etc).
String fieldName = item.getFieldName();
String fieldValue = item.getString();
// ... (do your job here)
} else {
// Process form file field (input type="file").
String fieldName = item.getFieldName();
String fileName = FilenameUtils.getName(item.getName());
InputStream fileContent = item.getInputStream();
// ... (do your job here)
}
}
} catch (FileUploadException e) {
throw new ServletException("Cannot parse multipart request.", e);
}
// ...
}
यह बहुत महत्वपूर्ण है कि आप कॉल नहीं करते है getParameter()
, getParameterMap()
, getParameterValues()
, getInputStream()
, getReader()
एक ही अनुरोध पहले से पर आदि,। अन्यथा सर्वलेट कंटेनर अनुरोध निकाय को पढ़ेगा और पार्स करेगा और इस प्रकार Apache Commons FileUpload को एक खाली अनुरोध निकाय मिलेगा। Ao ServletFileUpload # parseRequest (अनुरोध) एक खाली सूची भी देखें ।
ध्यान दें FilenameUtils#getName()
। यह फ़ाइल नाम प्राप्त करने के लिए एक MSIE फिक्स है। यह ब्राउज़र गलत फ़ाइल नाम के बजाय केवल फ़ाइल नाम के साथ पूर्ण फ़ाइल पथ भेजता है।
वैकल्पिक रूप से आप यह सब लपेट भी सकते हैं, Filter
जिसमें यह सब स्वचालित रूप से हो जाता है और सामान को अनुरोध के समरूप में वापस डाल दिया जाता है ताकि आप request.getParameter()
सामान्य तरीके से उपयोग जारी रख सकें और अपलोड की गई फ़ाइल को पुनः प्राप्त कर सकें request.getAttribute()
। आप इस ब्लॉग लेख में एक उदाहरण पा सकते हैं ।
GlassFish3 बग के लिए getParameter()
अभी भी वापसी का समाधानnull
ध्यान दें कि 3.1.2 से अधिक पुराने ग्लासफिश संस्करणों में एक बग था जिसमें getParameter()
अभी भी रिटर्न है null
। यदि आप ऐसे कंटेनर को लक्षित कर रहे हैं और इसे अपग्रेड नहीं कर सकते हैं, तो आपको getPart()
इस उपयोगिता विधि की मदद से मूल्य निकालने की आवश्यकता है :
private static String getValue(Part part) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(part.getInputStream(), "UTF-8"));
StringBuilder value = new StringBuilder();
char[] buffer = new char[1024];
for (int length = 0; (length = reader.read(buffer)) > 0;) {
value.append(buffer, 0, length);
}
return value.toString();
}
String description = getValue(request.getPart("description")); // Retrieves <input type="text" name="description">
अपलोड की गई फ़ाइल सहेज रहा है (न getRealPath()
ही उपयोग करें part.write()
!)
डिस्क या डेटाबेस में प्राप्त किए गए InputStream
( fileContent
जैसा कि उपरोक्त कोड स्निपेट में दिखाया गया चर) को ठीक से सहेजने पर विस्तार से निम्नलिखित उत्तरों पर जाएं :
अपलोड की गई फ़ाइल सेवित करना
डिस्क या डेटाबेस से सहेजे गए फ़ाइल को ठीक से ग्राहक को वापस भेजने पर विस्तार से निम्नलिखित उत्तरों के लिए:
अजाक्सिंग फॉर्म
निम्नलिखित उत्तरों की ओर जाएं कि कैसे अजाक्स (और jQuery) का उपयोग करके अपलोड किया जाए। ध्यान दें कि प्रपत्र डेटा एकत्र करने के लिए सर्वलेट कोड को इसके लिए बदलने की आवश्यकता नहीं है! केवल जिस तरह से आप प्रतिक्रिया करते हैं उसे बदला जा सकता है, लेकिन यह बल्कि तुच्छ है (यानी जेएसपी को अग्रेषित करने के बजाय, केवल कुछ JSON या XML या यहां तक कि सादे पाठ को प्रिंट करें जो अजाक्स कॉल के लिए जिम्मेदार स्क्रिप्ट के आधार पर उम्मीद कर रहा है)।
आशा है कि यह सब मदद करता है :)