जावा वेब एप्लिकेशन में एप्लिकेशन सर्वर के बाहर से स्थैतिक डेटा की सेवा करने का सबसे सरल तरीका


131

मेरे पास एक जावा वेब एप्लिकेशन है जो टॉमकैट पर चल रहा है। मैं स्थिर छवियों को लोड करना चाहता हूं जो वेब यूआई और एप्लिकेशन द्वारा उत्पन्न पीडीएफ फाइलों में दोनों दिखाए जाएंगे। साथ ही वेब यूआई के माध्यम से अपलोड करके नई छवियां जोड़ी और बचाई जाएंगी।

यह वेब कंटेनर के भीतर स्थिर डेटा संग्रहीत करके ऐसा करने के लिए एक समस्या नहीं है, लेकिन वेब कंटेनर के बाहर से भंडारण और उन्हें लोड करने से मुझे सिरदर्द हो रहा है।

मैं इस बिंदु पर स्थैतिक डेटा की सेवा के लिए अपाचे जैसे एक अलग वेब सर्वर का उपयोग नहीं करना चाहूंगा। मुझे किसी डेटाबेस में छवियों को बाइनरी में संग्रहीत करने का विचार भी पसंद नहीं है।

मैंने कुछ सुझाव देखे हैं जैसे छवि निर्देशिका वेब कंटेनर के बाहर एक निर्देशिका की ओर इशारा करते हुए एक प्रतीकात्मक लिंक होने के नाते, लेकिन क्या यह दृष्टिकोण विंडोज और * निक्स के वातावरण दोनों पर काम करेगा?

कुछ लोगों ने सेवा प्रदान करने वाली छवि को संभालने के लिए एक फ़िल्टर या एक सर्वलेट लिखने का सुझाव दिया है लेकिन उन सुझावों को बहुत अस्पष्ट और उच्च-स्तर पर इंगित किया गया है कि कैसे इसे पूरा करने के बारे में अधिक विस्तृत जानकारी के बिना।

जवाबों:


161

मैंने कुछ सुझाव देखे हैं जैसे छवि निर्देशिका वेब कंटेनर के बाहर एक निर्देशिका की ओर इशारा करते हुए एक प्रतीकात्मक लिंक होने के नाते, लेकिन क्या यह दृष्टिकोण विंडोज और * निक्स के वातावरण दोनों पर काम करेगा?

यदि आप * निक्स फाइलसिस्टम पथ नियमों का पालन करते हैं (यानी आप विशेष रूप से फॉरवर्ड स्लैश का उपयोग करते हैं /path/to/files), तो यह विंडोज पर काम करेगा और साथ ही साथ बदसूरत File.separatorस्ट्रिंग-संघनन के साथ चारों ओर फेल होने की आवश्यकता के बिना । हालाँकि यह केवल उसी कार्यशील डिस्क पर स्कैन किया जाएगा जहाँ से इस कमांड को लागू किया गया है। तो यदि टॉमकैट उदाहरण के लिए स्थापित है, C:तो /path/to/filesवास्तव में इंगित करेगा C:\path\to\files

यदि फ़ाइलें वेबएप के बाहर स्थित हैं, और आप DefaultServletउन्हें संभालने के लिए टॉमकैट रखना चाहते हैं, तो आपको मूल रूप से टॉमकैट में करने की आवश्यकता है, निम्नलिखित कॉन्सेप्ट तत्व को /conf/server.xmlअंदर <Host>टैग में जोड़ना है :

<Context docBase="/path/to/files" path="/files" />

इस तरह से वे सुलभ होंगे http://example.com/files/...। GlassFish / Payara विन्यास उदाहरण यहाँ पाया जा सकता है और WildFly विन्यास उदाहरण यहाँ पाया जा सकता है

आप पढ़ / लिख फ़ाइलें अपने आप पर नियंत्रण करना चाहते हैं, तो आप एक बनाने की जरूरत Servletइस जो मूल रूप से सिर्फ एक हो जाता है के लिए InputStreamउदाहरण के लिए के स्वाद में फ़ाइल की FileInputStreamऔर इसे करने के लिए लिखते हैं OutputStreamकी HttpServletResponse

प्रतिक्रिया पर, आपको Content-Typeहेडर सेट करना चाहिए ताकि क्लाइंट को पता हो कि कौन सी एप्लिकेशन को प्रदान की गई फ़ाइल के साथ जुड़ना है। और, आपको Content-Lengthहेडर सेट करना चाहिए ताकि क्लाइंट डाउनलोड प्रगति की गणना कर सके, अन्यथा यह अज्ञात होगा। और, आपको Content-Dispositionशीर्षलेख सेट करना चाहिए, attachmentयदि आप एक सेव अस डायलॉग चाहते हैं , अन्यथा क्लाइंट इसे इनलाइन प्रदर्शित करने का प्रयास करेगा। अंत में सिर्फ फाइल कंटेंट को रिस्पॉन्स आउटपुट स्ट्रीम पर लिखें।

यहाँ इस तरह के सर्वलेट का मूल उदाहरण दिया गया है:

@WebServlet("/files/*")
public class FileServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        String filename = URLDecoder.decode(request.getPathInfo().substring(1), "UTF-8");
        File file = new File("/path/to/files", filename);
        response.setHeader("Content-Type", getServletContext().getMimeType(filename));
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
        Files.copy(file.toPath(), response.getOutputStream());
    }

}

जब url-patternउदाहरण के लिए मैप किया जाता है /files/*, तो आप इसे कॉल कर सकते हैं http://example.com/files/image.png। इस तरह से आपके पास अनुरोधों की तुलना में अधिक नियंत्रण हो सकता DefaultServletहै, जैसे कि डिफ़ॉल्ट छवि (यानी if (!file.exists()) file = new File("/path/to/files", "404.gif")या तो) प्रदान करना। इसके अलावा request.getPathInfo()ऊपर का उपयोग करना पसंद किया जाता है request.getParameter()क्योंकि यह अधिक एसईओ के अनुकूल है और अन्यथा IE सेव अस के दौरान सही फ़ाइल नाम नहीं उठाएगा ।

आप डेटाबेस से फ़ाइलों की सेवा के लिए एक ही तर्क का पुन: उपयोग कर सकते हैं। बस new FileInputStream()द्वारा प्रतिस्थापित करें ResultSet#getInputStream()

उम्मीद है की यह मदद करेगा।

यह सभी देखें:


1
@ साल्तोनमोंडो: कम से कम प्रयास के साथ रास्ता।
बालूसी

@ बालसुख, मैंने यह कोशिश की: <Context docBase="/path/to/images" path="/images" />विंडोज में, लेकिन वेबैप फ़ोल्डर के सापेक्ष पथ प्राप्त करना:C:\install\apache-tomcat-8.0.26\webapps\tmp] is not valid
एसीवी

विंडोज पर यह होना चाहिए:<Context docBase="C:\tmp\" path="/images" />
ACV

और HTTP Status 404 - /images/जब कर रहे हो:, काम करता है http://localhost:8080/images/से एक विशिष्ट फ़ाइल लेकिन tmp: http://localhost:8080/images/Tulips.jpgठीक है
ACV

इस तरह यदि मैं फ़ोल्डर के अंदर एक छवि डालता हूं, तो छवि का लिंक 404 प्रतिक्रिया देगा जब तक आप सर्वर को पुनरारंभ नहीं करते हैं, क्या इसका कोई कारण है?
मट्टुस विसकारी

9

आप अपनी छवियों को एक निश्चित पथ पर रख कर ऐसा कर सकते हैं (उदाहरण के लिए: / var / images, या c: \ images), अपनी सेटिंग में सेटिंग जोड़ें (Settings.class द्वारा मेरे उदाहरण में प्रतिनिधित्व), और उन्हें लोड करें उस तरह, HttpServletतुम्हारा में:

String filename = Settings.getValue("images.path") + request.getParameter("imageName")
FileInputStream fis = new FileInputStream(filename);

int b = 0;
while ((b = fis.read()) != -1) {
        response.getOutputStream().write(b);
}

या यदि आप छवि में हेरफेर करना चाहते हैं:

String filename = Settings.getValue("images.path") + request.getParameter("imageName")
File imageFile = new File(filename);
BufferedImage image = ImageIO.read(imageFile);
ImageIO.write(image, "image/png", response.getOutputStream());

तब HTML कोड होगा <img src="imageServlet?imageName=myimage.png" />

बेशक आपको विभिन्न सामग्री प्रकारों की सेवा करने के बारे में सोचना चाहिए - "छवि / जेपीईजी", उदाहरण के लिए फ़ाइल एक्सटेंशन के आधार पर। साथ ही आपको कुछ कैशिंग भी प्रदान करना चाहिए।

इसके अलावा, आप अपने चित्रों की गुणवत्ता में सुधार के लिए इस सर्वलेट का उपयोग कर सकते हैं, तर्क के रूप में चौड़ाई और ऊंचाई पैरामीटर प्रदान करके और उपयोग करके image.getScaledInstance(w, h, Image.SCALE_SMOOTH), प्रदर्शन को देखते हुए, निश्चित रूप से।


2
आपको वास्तव में इसके लिए जावा 2D एपीआई की आवश्यकता नहीं है, यह केवल अनावश्यक रूप से अधिक ओवरहेड जोड़ देगा। बस एक InputStream पढ़ें और OutputStream लिखें।
बालुस सी सी

1
हाँ, मैंने प्रतिक्रिया को फिर से शुरू करने और अन्य हेरफेर के विचार के साथ शुरू किया, लेकिन इसे सरल बना दिया।
बोझाओ

7

Server.xml में जोड़ें:

 <Context docBase="c:/dirtoshare" path="/dir" />

Dir फ़ाइल लिस्टिंग पैरामीटर को web.xml में सक्षम करें:

    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>

Web.xml में परिवर्तन के साथ मैं चुनिंदा बॉक्स में भेजने के लिए फाइलों की एक सूची प्राप्त कर सकता हूं?
टॉमाज़ वास्ज़्ज़ेक

1
यह परिवर्तन tomcat के web.xml में होगा, न कि आपके आवेदन
vsingh

इसके लिए धन्यवाद! क्या web.xml में dir फ़ाइल लिस्टिंग पैरामीटर सक्षम करना आवश्यक है?
दरिरू '’

6

आवश्यकता: WEBROOT निर्देशिका के बाहर या स्थानीय डिस्क से स्थैतिक संसाधन (चित्र / वीडियो आदि) को एक्सेस करना

चरण 1:
टॉमकैट सर्वर के वेबएप के तहत एक फोल्डर बनाएं। हम कहते हैं कि फ़ोल्डर का नाम myproj है

चरण 2:
myproj के तहत एक WEB-INF फ़ोल्डर बनाएँ इसके तहत एक साधारण web.xml बनाएं

web.xml के तहत कोड

<web-app>
</web-app>

उपरोक्त दो चरणों के लिए निर्देशिका संरचना

c:\programfile\apachesoftwarefoundation\tomcat\...\webapps
                                                            |
                                                            |---myproj
                                                            |   |
                                                            |   |---WEB-INF
                                                                |   |
                                                                    |---web.xml

चरण 3:
अब निम्नलिखित स्थान के तहत myproj.xml नाम के साथ एक xml फ़ाइल बनाएँ

c:\programfile\apachesoftwarefoundation\tomcat\conf\catalina\localhost

CODE in myproj.xml:

<Context path="/myproj/images" docBase="e:/myproj/" crossContext="false" debug="0" reloadable="true" privileged="true" /> 

चरण 4:
4 ए) अब अपनी हार्ड डिस्क के ई ड्राइव में myproj नाम से एक फ़ोल्डर बनाएं और एक नया बनाएं

नाम छवियों के साथ फ़ोल्डर और छवियों फ़ोल्डर में कुछ छवियों को जगह (e:myproj\images\)

मान लें कि myfoto.jpg को इसके अंतर्गत रखा गया है e:\myproj\images\myfoto.jpg

4 B) अब WEB-INF नाम से एक फोल्डर e:\myproj\WEB-INFबनाएं और WEB-INF फोल्डर में एक web.xml बनाएं

Web.xml में कोड

<web-app>
</web-app>

चरण 5:
अब नाम। Html और जगह के साथ .html दस्तावेज़ बनाएँ: e: \ myproj

CODE के अंतर्गत CODE। Myproj में आपका स्वागत है

उपरोक्त चरण 4 और चरण 5 के लिए निर्देशिका संरचना निम्नानुसार है

E:\myproj
    |--index.html
    |
    |--images
    |     |----myfoto.jpg
    |
    |--WEB-INF
    |     |--web.xml

चरण 6:
अब Apache tomcat सर्वर शुरू करें

चरण 7:
ब्राउज़र खोलें और निम्नानुसार यूआरएल टाइप करें

http://localhost:8080/myproj    

उसके बाद आप उस सामग्री को प्रदर्शित करें जो index.html में दी गई है

चरण 8:
अपनी स्थानीय हार्ड डिस्क (वेबरोट के बाहर) के तहत छवियों को एक्सेस करने के लिए

http://localhost:8080/myproj/images/myfoto.jpg

क्या आप कृपया मुझे सुझाव दे सकते हैं कि गतिशील मूल्यों के लिए समान कार्य कैसे करें। मेरा मतलब है कि मैं अपने स्थानीय निर्देशिका में (xml) डेटा लिखना चाहता हूं और अपने जेएसपी पृष्ठ में पढ़ना चाहता हूं। क्या सर्वर में लिखने का कोई तरीका निर्देशिका में प्रबंधित किया गया है ताकि मैं उपरोक्त प्रक्रिया का उपयोग करके उन्हें एक्सेस कर सकूं ??
सुदीप 7

हालाँकि मैं index.html फ़ाइल को ठीक से चला सकता हूँ, लेकिन छवियाँ वेब ब्राउज़र में प्रदर्शित नहीं हो रही हैं
rogerwar

मेरी गलती पोस्ट ठीक काम कर रही है मैं ई के अंत में / डाल देना भूल गया: / myproj मैं इसे ई में बदल देता हूं: / myproj / और इसके कामकाजी ठीक धन्यवाद @sbabamca
rogerwar

नमस्ते, पोस्ट के लिए धन्यवाद और यह बहुत उपयोगी है। यहां मैं उस विशिष्ट निर्देशिका के लिए इंटरफ़ेस के माध्यम से फाइलें अपलोड करना चाहता हूं। मैं उसी के लिए POST विधि को सक्षम करना चाहता हूं। क्या कोई कृपया मेरी मदद कर सकता है।
विक्की

6

यह मेरे कार्यस्थल की कहानी है:
- हम स्ट्रेट्स 1 और टॉमकैट 7.x का उपयोग करते हुए बहु चित्र और दस्तावेज़ फ़ाइलों को अपलोड करने का प्रयास करते हैं।
- हम अपलोड की गई फाइल को फाइल सिस्टम, फाइलनाम और डेटाबेस रिकॉर्ड में पूरा रास्ता लिखने की कोशिश करते हैं।
- हम वेब ऐप डायरेक्टरी के बाहर फाइल फोल्डर को अलग करने की कोशिश करते हैं । (*)

नीचे दिए गए समाधान बहुत सरल है, आवश्यकता के लिए प्रभावी (*):

META-INF/context.xmlनिम्नलिखित सामग्री के साथ फ़ाइल फ़ाइल में: (उदाहरण के लिए, मेरा आवेदन http://localhost:8080/ABCमेरे नाम / परियोजना नाम पर चलता है ABC)। (यह फ़ाइल की पूरी सामग्री भी है context.xml)

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ABC" aliases="/images=D:\images,/docs=D:\docs"/>

(टॉमकैट संस्करण 7 या बाद के संस्करण के साथ काम करता है)

परिणाम: हम 2 उर्फ ​​बनाए गए हैं। उदाहरण के लिए, हम छवियों को सहेजते हैं: D:\images\foo.jpg और लिंक से देखें या छवि टैग का उपयोग करें:

<img src="http://localhost:8080/ABC/images/foo.jsp" alt="Foo" height="142" width="142">

या

<img src="/images/foo.jsp" alt="Foo" height="142" width="142">

(मैं Netbeans 7.x का उपयोग करता हूं, Netbeans लगता है कि ऑटो बनाएँ फ़ाइल WEB-INF\context.xml)


2

आप के लिए प्रेषण का फैसला करते हैं FileServletतो आप भी आवश्यकता होगी allowLinking="true"में context.xmlअनुमति देने के लिए आदेश में FileServletसिमलिंक पार करने के लिए।

Http://tomcat.apache.org/tomcat-6.0-doc/config/context.html देखें


0

यदि कोई भी स्वीकार किए गए उत्तर के साथ अपनी समस्या को हल करने में सक्षम नहीं है, तो इन बातों पर ध्यान दें:

  1. विशेषता के localhost:<port>साथ उल्लेख करने की आवश्यकता नहीं है <img> src
  2. सुनिश्चित करें कि आप इस परियोजना को ग्रहण से बाहर चला रहे हैं, क्योंकि ग्रहण context docBaseअपनी स्थानीय server.xmlफ़ाइल के अंदर अपने दम पर प्रवेश बनाता है ।

0

किसी फ़ाइल का InputStream पढ़ें और उसे ServletOutputStreamक्लाइंट को बाइनरी डेटा भेजने के लिए लिखें ।

@WebServlet("/files/URLStream")
public class URLStream extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public URLStream() {
        super();
    }

    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        File source = new File("D:\\SVN_Commit.PNG");
        long start = System.nanoTime();

        InputStream image = new FileInputStream(source);

        /*String fileID = request.getParameter("id");
        System.out.println("Requested File ID : "+fileID);
        // Mongo DB GridFS - https://stackoverflow.com/a/33544285/5081877
        image = outputImageFile.getInputStream();*/

        if( image != null ) {
            BufferedInputStream bin = null;
            BufferedOutputStream bout = null;
            ServletOutputStream sos = response.getOutputStream();
            try {
                bin = new BufferedInputStream( image );
                bout = new BufferedOutputStream( sos );
                int ch =0; ;
                while((ch=bin.read())!=-1) {
                    bout.write(ch);
                }
            } finally {
                bin.close();
                image.close();
                bout.close();
                sos.close();
            }

        } else {
            PrintWriter writer = response.getWriter();
            writer.append("Something went wrong with your request.");
            System.out.println("Image not available.");
        }
        System.out.println("Time taken by Stream Copy = "+(System.nanoTime()-start));
    }
}

URL को सीधे srcएटिब्यूट में रिजल्ट करें ।

<img src='http://172.0.0.1:8080/ServletApp/files/URLStream?id=5a575be200c117cc2500003b' alt="mongodb File"/>
<img src='http://172.0.0.1:8080/ServletApp/files/URLStream' alt="local file"/>

<video controls="controls" src="http://172.0.0.1:8080/ServletApp/files/URLStream"></video>

0

यदि आप JAX-RS (जैसे RESTEasy) के साथ काम करना चाहते हैं, तो यह कोशिश करें:

@Path("/pic")
public Response get(@QueryParam("url") final String url) {
    String picUrl = URLDecoder.decode(url, "UTF-8");

    return Response.ok(sendPicAsStream(picUrl))
            .header(HttpHeaders.CONTENT_TYPE, "image/jpg")
            .build();
}

private StreamingOutput sendPicAsStream(String picUrl) {
    return output -> {
        try (InputStream is = (new URL(picUrl)).openStream()) {
            ByteStreams.copy(is, output);
        }
    };
}

का उपयोग कर javax.ws.rs.core.Responseऔरcom.google.common.io.ByteStreams


-1

मैंने इसे और भी सरल किया। समस्या: एक CSS फ़ाइल में img फ़ोल्डर के लिए url लिंक थे। 404 हो जाता है।

मैंने url, http: // tomcatfolder: port / img / blablah.png को देखा, जो मौजूद नहीं है। लेकिन, यह वास्तव में टॉमकैट में रूट ऐप की ओर इशारा कर रहा है।

तो मैंने बस अपने वेब ऐप से img फ़ोल्डर को उस ROOT ऐप में कॉपी किया। काम करता है!

उत्पादन के लिए अनुशंसित नहीं है, बेशक, लेकिन यह एक आंतरिक उपकरण देव ऐप के लिए है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.