स्थिर सामग्री परोसने के लिए सर्वलेट


145

मैं दो अलग-अलग कंटेनरों (टॉमकैट और जेट्टी) पर एक वेबएप को तैनात करता हूं, लेकिन स्थिर सामग्री की सेवा के लिए उनके डिफ़ॉल्ट सर्वलेट में URL संरचना को संभालने का एक अलग तरीका है जिसका मैं उपयोग करना चाहता हूं ( विवरण )।

इसलिए मैं अपने स्वयं के स्थिर सामग्री (चित्र, सीएसएस, आदि) की सेवा के लिए वेबप में एक छोटा सर्वलेट शामिल करना चाह रहा हूं। सर्वलेट में निम्नलिखित गुण होने चाहिए:

  • कोई बाहरी निर्भरता नहीं
  • सरल और विश्वसनीय
  • If-Modified-Sinceहेडर के लिए समर्थन (यानी कस्टम getLastModifiedविधि)
  • (वैकल्पिक) gzip एन्कोडिंग, etags, के लिए समर्थन ...

क्या ऐसा सर्वलेट कहीं उपलब्ध है? निकटतम मुझे मिल सकती है उदाहरण सर्वलेट बुक से 4-10

अद्यतन: जिस URL संरचना का आप उपयोग करना चाहते हैं - यदि आप सोच रहे हैं - बस:

    <servlet-mapping>
            <servlet-name>main</servlet-name>
            <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
            <servlet-name>default</servlet-name>
            <url-pattern>/static/*</url-pattern>
    </servlet-mapping>

इसलिए सभी अनुरोधों को मुख्य सर्वलेट में पारित किया जाना चाहिए, जब तक कि वे staticमार्ग के लिए न हों। समस्या यह है कि टॉमकैट का डिफ़ॉल्ट सर्वलेट सर्वलेटपथ को ध्यान में नहीं रखता है (इसलिए यह मुख्य फ़ोल्डर में स्थिर फ़ाइलों की तलाश करता है), जबकि जेटी करता है (इसलिए यह staticफ़ोल्डर में दिखता है )।


क्या आप "URL संरचना" का उपयोग करना चाहते हैं? लिंक किए गए उदाहरण 4-10 के आधार पर अपना स्वयं का रोल करना, एक तुच्छ प्रयास की तरह लगता है। मैंने खुद इसे बहुत बार किया है ...
स्टु थॉम्पसन

मैंने URL संरचना को विस्तृत करने के लिए अपना प्रश्न संपादित किया। और हां, मैंने अपना सर्वलेट रोलिंग कर दिया। नीचे मेरा जवाब देखें।
ब्रूनो डी फ़ेने

1
आप स्थिर सामग्री के लिए वेबसर्वर का उपयोग क्यों नहीं करते हैं?
स्टीफन

4
@ स्टेफेन: क्योंकि टॉम्स्क / जेट्टी के सामने हमेशा एक अपाचे नहीं होता है। और एक अलग कॉन्फ़िगरेशन की परेशानी से बचने के लिए। लेकिन आप सही हैं, मैं उस विकल्प पर विचार कर सकता हूं।
ब्रूनो डी फिगेन

मैं बस यह नहीं समझ सकता, आपने इस तरह की मैपिंग का उपयोग क्यों नहीं किया <सर्वलेट-मैपिंग> <सर्वलेट-नाम> डिफ़ॉल्ट </ सर्वलेट-नाम> <url-pattern> / </ url-pattern> </ सर्वलेट-मैपिंग > स्थिर सामग्री परोसने के लिए
Maciek Kreft

जवाबों:


53

मैं थोड़ा अलग समाधान के साथ आया था। यह थोड़ा हैक-ईश है, लेकिन यहां मैपिंग है:

<servlet-mapping>   
    <servlet-name>default</servlet-name>
    <url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
 <servlet-name>default</servlet-name>
    <url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>myAppServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

यह मूल रूप से डिफ़ॉल्ट सर्वलेट के विस्तार से सभी सामग्री फ़ाइलों को मैप करता है, और बाकी सब "myAppServlet" को।

यह Jetty और Tomcat दोनों में काम करता है।


13
वास्तव में आप एक से अधिक url-pattern टैग को सर्वलेट-मैपिंग के अंदर जोड़ सकते हैं;)
Fareed Alnamrouti

5
सर्वलेट-मैपिंग के अंदर सर्वलेट 2.5 और नए समर्थन कई
url-

केवल अनुक्रमणिका फ़ाइलों (index.html) से सावधान रहें क्योंकि वे आपके सर्वलेट पर पूर्वता ले सकते हैं।
एंड्रेस

मुझे लगता है कि यह बुरा विचार है *.sth। अगर किसी को url मिलेगा example.com/index.jsp?g=.sthतो उसे jsp फ़ाइल का स्रोत मिलेगा। या मैं गलत हूँ? (मैं जावा ईई में नया हूं) मैं आमतौर पर यूआरएल पैटर्न /css/*और आदि का उपयोग करता हूं
सेम्परपेरिटस

46

इस मामले में डिफ़ॉल्ट सर्वलेट के पूरी तरह से कस्टम कार्यान्वयन के लिए कोई आवश्यकता नहीं है, आप कंटेनर के स्टोरेज अनुरोध के लिए अनुरोध करने के लिए इस सरल सर्वलेट का उपयोग कर सकते हैं:


package com.example;

import java.io.*;

import javax.servlet.*;
import javax.servlet.http.*;

public class DefaultWrapperServlet extends HttpServlet
{   
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        RequestDispatcher rd = getServletContext().getNamedDispatcher("default");

        HttpServletRequest wrapped = new HttpServletRequestWrapper(req) {
            public String getServletPath() { return ""; }
        };

        rd.forward(wrapped, resp);
    }
}

इस प्रश्न में एक फिल्टर का उपयोग करके नियंत्रक / और स्थैतिक सामग्री के लिए / मैपिंग का एक साफ तरीका है। स्‍वीकार किए गए उत्तर को स्‍वीकार करने के बाद देखें: stackoverflow.com/questions/870150/…
डेविड कार्बनी


30

मैं के साथ अच्छे परिणाम मिला है FileServlet , के रूप में यह काफी सभी HTTP की (etags, बेडौल, आदि) का समर्थन करता है।


धन्यवाद! असफल प्रयासों और बुरे उत्तरों के घंटे, और इसने मेरी समस्या को हल कर दिया
योसी शशो

4
यद्यपि ऐप के बाहर एक फ़ोल्डर से सामग्री की सेवा करने के लिए (मैं इसे डिस्क से एक फ़ोल्डर सर्वर के लिए उपयोग करता हूं, सी: \ संसाधन) मैं इस पंक्ति को संशोधित करता हूं: इस .basePath = getServletContext ()। GetRitPath (getInitParameter ("basePath)। ")); और इसे इसके साथ बदल दिया: this.basePath = getInitParameter ("basePath");
योसी शशो

1
एक अद्यतन संस्करण showcase.omnifaces.org/servlets/FileServlet
koppor

26

एक स्थिर संसाधन सर्वलेट के लिए सार टेम्पलेट

आंशिक रूप से 2007 से इस ब्लॉग पर आधारित , यहाँ एक सर्वलेट के लिए एक आधुनिक और अत्यधिक पुन: प्रयोज्य सार टेम्प्लेट है जो कैशिंग के साथ ठीक से व्यवहार करता है ETag, If-None-Matchऔर If-Modified-Since(लेकिन कोई Gzip और रेंज समर्थन नहीं है; बस इसे सरल रखने के लिए; Gzip को फ़िल्टर के माध्यम से या के माध्यम से किया जा सकता है; कंटेनर विन्यास)।

public abstract class StaticResourceServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;
    private static final long ONE_SECOND_IN_MILLIS = TimeUnit.SECONDS.toMillis(1);
    private static final String ETAG_HEADER = "W/\"%s-%s\"";
    private static final String CONTENT_DISPOSITION_HEADER = "inline;filename=\"%1$s\"; filename*=UTF-8''%1$s";

    public static final long DEFAULT_EXPIRE_TIME_IN_MILLIS = TimeUnit.DAYS.toMillis(30);
    public static final int DEFAULT_STREAM_BUFFER_SIZE = 102400;

    @Override
    protected void doHead(HttpServletRequest request, HttpServletResponse response) throws ServletException ,IOException {
        doRequest(request, response, true);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doRequest(request, response, false);
    }

    private void doRequest(HttpServletRequest request, HttpServletResponse response, boolean head) throws IOException {
        response.reset();
        StaticResource resource;

        try {
            resource = getStaticResource(request);
        }
        catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }

        if (resource == null) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        String fileName = URLEncoder.encode(resource.getFileName(), StandardCharsets.UTF_8.name());
        boolean notModified = setCacheHeaders(request, response, fileName, resource.getLastModified());

        if (notModified) {
            response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
            return;
        }

        setContentHeaders(response, fileName, resource.getContentLength());

        if (head) {
            return;
        }

        writeContent(response, resource);
    }

    /**
     * Returns the static resource associated with the given HTTP servlet request. This returns <code>null</code> when
     * the resource does actually not exist. The servlet will then return a HTTP 404 error.
     * @param request The involved HTTP servlet request.
     * @return The static resource associated with the given HTTP servlet request.
     * @throws IllegalArgumentException When the request is mangled in such way that it's not recognizable as a valid
     * static resource request. The servlet will then return a HTTP 400 error.
     */
    protected abstract StaticResource getStaticResource(HttpServletRequest request) throws IllegalArgumentException;

    private boolean setCacheHeaders(HttpServletRequest request, HttpServletResponse response, String fileName, long lastModified) {
        String eTag = String.format(ETAG_HEADER, fileName, lastModified);
        response.setHeader("ETag", eTag);
        response.setDateHeader("Last-Modified", lastModified);
        response.setDateHeader("Expires", System.currentTimeMillis() + DEFAULT_EXPIRE_TIME_IN_MILLIS);
        return notModified(request, eTag, lastModified);
    }

    private boolean notModified(HttpServletRequest request, String eTag, long lastModified) {
        String ifNoneMatch = request.getHeader("If-None-Match");

        if (ifNoneMatch != null) {
            String[] matches = ifNoneMatch.split("\\s*,\\s*");
            Arrays.sort(matches);
            return (Arrays.binarySearch(matches, eTag) > -1 || Arrays.binarySearch(matches, "*") > -1);
        }
        else {
            long ifModifiedSince = request.getDateHeader("If-Modified-Since");
            return (ifModifiedSince + ONE_SECOND_IN_MILLIS > lastModified); // That second is because the header is in seconds, not millis.
        }
    }

    private void setContentHeaders(HttpServletResponse response, String fileName, long contentLength) {
        response.setHeader("Content-Type", getServletContext().getMimeType(fileName));
        response.setHeader("Content-Disposition", String.format(CONTENT_DISPOSITION_HEADER, fileName));

        if (contentLength != -1) {
            response.setHeader("Content-Length", String.valueOf(contentLength));
        }
    }

    private void writeContent(HttpServletResponse response, StaticResource resource) throws IOException {
        try (
            ReadableByteChannel inputChannel = Channels.newChannel(resource.getInputStream());
            WritableByteChannel outputChannel = Channels.newChannel(response.getOutputStream());
        ) {
            ByteBuffer buffer = ByteBuffer.allocateDirect(DEFAULT_STREAM_BUFFER_SIZE);
            long size = 0;

            while (inputChannel.read(buffer) != -1) {
                buffer.flip();
                size += outputChannel.write(buffer);
                buffer.clear();
            }

            if (resource.getContentLength() == -1 && !response.isCommitted()) {
                response.setHeader("Content-Length", String.valueOf(size));
            }
        }
    }

}

एक स्थिर संसाधन का प्रतिनिधित्व करते हुए नीचे दिए गए इंटरफेस के साथ इसका उपयोग करें।

interface StaticResource {

    /**
     * Returns the file name of the resource. This must be unique across all static resources. If any, the file
     * extension will be used to determine the content type being set. If the container doesn't recognize the
     * extension, then you can always register it as <code>&lt;mime-type&gt;</code> in <code>web.xml</code>.
     * @return The file name of the resource.
     */
    public String getFileName();

    /**
     * Returns the last modified timestamp of the resource in milliseconds.
     * @return The last modified timestamp of the resource in milliseconds.
     */
    public long getLastModified();

    /**
     * Returns the content length of the resource. This returns <code>-1</code> if the content length is unknown.
     * In that case, the container will automatically switch to chunked encoding if the response is already
     * committed after streaming. The file download progress may be unknown.
     * @return The content length of the resource.
     */
    public long getContentLength();

    /**
     * Returns the input stream with the content of the resource. This method will be called only once by the
     * servlet, and only when the resource actually needs to be streamed, so lazy loading is not necessary.
     * @return The input stream with the content of the resource.
     * @throws IOException When something fails at I/O level.
     */
    public InputStream getInputStream() throws IOException;

}

आपको बस जरूरत है कि दिए गए अमूर्त सर्वलेट से और getStaticResource()जवादोक के अनुसार विधि को लागू करने की ।

फ़ाइल सिस्टम से सेवारत ठोस उदाहरण:

यहां एक ठोस उदाहरण दिया गया है जो इसे /files/foo.extस्थानीय डिस्क फ़ाइल सिस्टम जैसे URL के माध्यम से कार्य करता है:

@WebServlet("/files/*")
public class FileSystemResourceServlet extends StaticResourceServlet {

    private File folder;

    @Override
    public void init() throws ServletException {
        folder = new File("/path/to/the/folder");
    }

    @Override
    protected StaticResource getStaticResource(HttpServletRequest request) throws IllegalArgumentException {
        String pathInfo = request.getPathInfo();

        if (pathInfo == null || pathInfo.isEmpty() || "/".equals(pathInfo)) {
            throw new IllegalArgumentException();
        }

        String name = URLDecoder.decode(pathInfo.substring(1), StandardCharsets.UTF_8.name());
        final File file = new File(folder, Paths.get(name).getFileName().toString());

        return !file.exists() ? null : new StaticResource() {
            @Override
            public long getLastModified() {
                return file.lastModified();
            }
            @Override
            public InputStream getInputStream() throws IOException {
                return new FileInputStream(file);
            }
            @Override
            public String getFileName() {
                return file.getName();
            }
            @Override
            public long getContentLength() {
                return file.length();
            }
        };
    }

}

डेटाबेस से सेवारत ठोस उदाहरण:

यहां एक ठोस उदाहरण दिया गया है जो एक URL के माध्यम से इसे पेश करता है जैसे /files/foo.extकि EJB सेवा कॉल के माध्यम से डेटाबेस जो आपकी इकाई को एक byte[] contentसंपत्ति देता है:

@WebServlet("/files/*")
public class YourEntityResourceServlet extends StaticResourceServlet {

    @EJB
    private YourEntityService yourEntityService;

    @Override
    protected StaticResource getStaticResource(HttpServletRequest request) throws IllegalArgumentException {
        String pathInfo = request.getPathInfo();

        if (pathInfo == null || pathInfo.isEmpty() || "/".equals(pathInfo)) {
            throw new IllegalArgumentException();
        }

        String name = URLDecoder.decode(pathInfo.substring(1), StandardCharsets.UTF_8.name());
        final YourEntity yourEntity = yourEntityService.getByName(name);

        return (yourEntity == null) ? null : new StaticResource() {
            @Override
            public long getLastModified() {
                return yourEntity.getLastModified();
            }
            @Override
            public InputStream getInputStream() throws IOException {
                return new ByteArrayInputStream(yourEntityService.getContentById(yourEntity.getId()));
            }
            @Override
            public String getFileName() {
                return yourEntity.getName();
            }
            @Override
            public long getContentLength() {
                return yourEntity.getContentLength();
            }
        };
    }

}

1
प्रिय @BalusC मुझे लगता है कि आपका दृष्टिकोण एक हैकर के लिए असुरक्षित है, जो निम्नलिखित अनुरोध भेजकर फाइल सिस्टम को ट्रफ कर सकता है files/%2e%2e/mysecretfile.txt:। यह अनुरोध पैदा करता है files/../mysecretfile.txt। मैंने इसका परीक्षण टॉमकैट 7.0.55 पर किया। वे इसे एक निर्देशिका चढ़ाई कहते हैं: owasp.org/index.php/Path_Traversal
क्रिस्टियन

1
@ क्रिश्चियन: हाँ, संभव। मैंने उदाहरण दिया कि इसे कैसे रोका जाए।
बालुसक

इससे उठाव नहीं होना चाहिए। इस तरह सर्वलेट के साथ एक वेबपेज के लिए स्थिर फ़ाइलों की सेवा करना आपदा सुरक्षा वार के लिए एक नुस्खा है। ऐसी सभी समस्याओं को पहले ही हल कर लिया गया है, और बंद होने की संभावना से अधिक अनदेखा सुरक्षा समय बमों के साथ एक नया कस्टम तरीका लागू करने का कोई कारण नहीं है। सही रास्ता टॉमकट / ग्लासफिश / जेट्टी आदि को कंटेंट परोसने के लिए कॉन्फ़िगर करना है, या एनजीआईएनएक्स जैसे समर्पित फाइलर का उपयोग करने के लिए बेहतर है।
लियोनहार्ड Printz

@LeonhardPrintz: सुरक्षा के मुद्दों को इंगित करने के बाद मैं टॉमकैट पर अपने दोस्तों के उत्तर को हटा दूंगा। कोई दिक्कत नहीं है।
बालुस

19

मैंने अपना रोल करना समाप्त कर दिया StaticServlet। यह समर्थन करता है If-Modified-Since, gzip एन्कोडिंग और यह स्थिर फ़ाइलों को युद्ध-फाइलों से भी परोसने में सक्षम होना चाहिए। यह बहुत कठिन कोड नहीं है, लेकिन यह पूरी तरह से तुच्छ भी नहीं है।

कोड उपलब्ध है: StaticServlet.java । टिप्पणी करने के लिए स्वतंत्र महसूस करें।

अद्यतन: खुर्रम उस ServletUtilsकक्षा के बारे में पूछता है जिसे संदर्भित किया गया है StaticServlet। यह केवल सहायक विधियों के साथ एक वर्ग है जो मैंने अपनी परियोजना के लिए उपयोग किया था। एकमात्र तरीका coalesceजो आपको चाहिए वह है (जो SQL फ़ंक्शन के समान है COALESCE)। यह कोड है:

public static <T> T coalesce(T...ts) {
    for(T t: ts)
        if(t != null)
            return t;
    return null;
}

2
अपने आंतरिक वर्ग का नाम न रखें। यह भ्रम पैदा कर सकता है क्योंकि आप इसे java.lang.Error के लिए गलती कर सकते हैं। इसके अलावा, क्या आपका web.xml वही है?
लियोनेल

त्रुटि चेतावनी के लिए धन्यवाद। web.xml एक ही है, "डिफ़ॉल्ट" के साथ StaticServlet के नाम से बदल दिया गया है।
ब्रूनो डी फेन

1
मोटे तौर पर विधि के रूप में, इसे कॉमन-लैंग स्ट्रिंगिंग
यूटिल्स.डेफॉल्टस्ट्रिंग

TransferStream () विधि को Files.copy (, os) से भी बदला जा सकता है;
गेरिट ब्रिंक

यह दृष्टिकोण इतना लोकप्रिय क्यों है? लोग इस तरह से स्थिर फ़ाइल सर्वरों को क्यों लागू कर रहे हैं? इतने सारे सुरक्षा छेद हैं जो बस खोजे जाने की प्रतीक्षा कर रहे हैं, और वास्तविक स्थिर फ़ाइल सर्वरों की इतनी सारी विशेषताएँ जो लागू नहीं होती हैं।
लियोनहार्ड Printz

12

ऊपर दी गई जानकारी के उदाहरण से, मुझे लगता है कि यह पूरा लेख टोम्केट 6.0.29 और उससे पहले के व्यवहार पर आधारित है। Https://issues.apache.org/bugzilla/show_bug.cgi?id=50026 देखें । टॉमकैट 6.0.30 पर अपग्रेड करें और (टॉमकैट | जेट्टी) के बीच व्यवहार को विलय करना चाहिए।


1
यही मेरी समझ से भी है svn diff -c1056763 http://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk/। लंबे समय से पहले, इस WONTFIX +3 साल पहले चिह्नित करने के बाद!
ब्रूनो डी फेन

12

इसे इस्तेमाल करे

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
    <url-pattern>*.css</url-pattern>
    <url-pattern>*.ico</url-pattern>
    <url-pattern>*.png</url-pattern>
    <url-pattern>*.jpg</url-pattern>
    <url-pattern>*.htc</url-pattern>
    <url-pattern>*.gif</url-pattern>
</servlet-mapping>    

संपादित करें: यह केवल सर्वलेट 2.5 युक्ति और ऊपर के लिए मान्य है।


ऐसा लगता है कि यह एक मान्य कॉन्फ़िगरेशन नहीं है।
गेद्रोक्स 22'12

10

मुझे भी यही समस्या थी और मैंने टॉमकैट कोडबेस से 'डिफॉल्ट सर्वलेट' के कोड का उपयोग करके इसे हल किया।

https://github.com/apache/tomcat/blob/master/java/org/apache/catalina/servlets/DefaultServlet.java

DefaultServlet सर्वलेट कि बिलाव में निश्चित संसाधनों (jpg, एचटीएमएल, सीएसएस, GIF आदि) कार्य करता है।

यह सर्वलेट बहुत कुशल है और इसमें कुछ गुण हैं जिन्हें आपने ऊपर परिभाषित किया है।

मुझे लगता है कि यह स्रोत कोड, कार्यक्षमता या अवसादों को शुरू करने और दूर करने का एक अच्छा तरीका है जिसकी आपको आवश्यकता नहीं है।

  • Org.apache.naming.resource पैकेज के संदर्भ को java.io.File कोड से हटाया या बदला जा सकता है।
  • Org.apache.catalina.util पैकेज के संदर्भ में संभवतः केवल उपयोगिता विधियाँ / कक्षाएं हैं जिन्हें आपके स्रोत कोड में दोहराया जा सकता है।
  • Org.apache.catalina.Globals वर्ग के संदर्भ अंतर्निर्मित या हटाए जा सकते हैं।

यह बहुत से सामान पर निर्भर करता है org.apache.*। जेट्टी के साथ आप इसका उपयोग कैसे कर सकते हैं?
ब्रूनो डी फ़ेने

आप सही कह रहे हैं, इस संस्करण में टॉमकैट के लिए बहुत अधिक अवसाद हैं (यह भी कई चीजों का समर्थन करता है जो आप नहीं चाहते हैं। मैं अपने उत्तर को संपादित करूंगा।
Panagiotis Korros

5

मुझे कुछ वर्कअराउंड के बारे में वेब पर बढ़िया ट्यूटोरियल मिला। यह सरल और कुशल है, मैंने इसे कई प्रोजेक्ट्स में REST urls स्टाइल दृष्टिकोण के साथ उपयोग किया:

http://www.kuligowski.pl/java/rest-style-urls-and-url-mapping-for-static-content-apache-tomcat,5


4

मैंने tomcat DefaultServlet ( src ) का विस्तार करके और getRelativePath () विधि को ओवरराइड करके किया।

package com.example;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.apache.catalina.servlets.DefaultServlet;

public class StaticServlet extends DefaultServlet
{
   protected String pathPrefix = "/static";

   public void init(ServletConfig config) throws ServletException
   {
      super.init(config);

      if (config.getInitParameter("pathPrefix") != null)
      {
         pathPrefix = config.getInitParameter("pathPrefix");
      }
   }

   protected String getRelativePath(HttpServletRequest req)
   {
      return pathPrefix + super.getRelativePath(req);
   }
}

... और यहाँ मेरे सर्वलेट मैपिंग हैं

<servlet>
    <servlet-name>StaticServlet</servlet-name>
    <servlet-class>com.example.StaticServlet</servlet-class>
    <init-param>
        <param-name>pathPrefix</param-name>
        <param-value>/static</param-value>
    </init-param>       
</servlet>

<servlet-mapping>
    <servlet-name>StaticServlet</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>  

1

स्प्रिंग ऐप के साथ-साथ /favicon.ico और JSP फ़ाइलों से / WEB-INF / jsp / * से सभी अनुरोधों को पूरा करने के लिए कि स्प्रिंग का AbstractUrlBasedView अनुरोध करेगा कि आप बस जेपी सर्वलेट और डिफ़ॉल्ट वॉलेट को फिर से तैयार कर सकते हैं:

  <servlet>
    <servlet-name>springapp</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>/WEB-INF/jsp/*</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/favicon.ico</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>springapp</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

हम jsp सर्वलेट के लिए मानक मैपिंग पर * .jsp यूआरएल-पैटर्न पर भरोसा नहीं कर सकते क्योंकि किसी भी एक्सटेंशन मैपिंग की जाँच करने से पहले पथ पैटर्न '/ *' का मिलान किया जाता है। Jsp सर्वलेट को एक गहरे फ़ोल्डर में मैप करने का मतलब है कि यह पहले से मेल खाता है। मिलान '/favicon.ico' बिल्कुल पथ पैटर्न मिलान से पहले होता है। गहरा पथ मिलान काम करेगा, या सटीक मैच, लेकिन कोई भी एक्सटेंशन मैच इसे '/ *' पथ मैच से आगे नहीं बढ़ा सकता है। डिफ़ॉल्ट सर्वलेट के लिए मैपिंग '/' काम नहीं करता है। आपको लगता है कि सटीक '/' वसंतपथ पर '/ *' पथ पैटर्न को हरा देगा।

उपरोक्त फ़िल्टर समाधान अनुप्रयोग से अग्रेषित / शामिल जेएसपी अनुरोधों के लिए काम नहीं करता है। इसे काम करने के लिए मुझे फ़िल्टर को सीधे स्प्रिंगप्प पर लागू करना था, जिस बिंदु पर url- पैटर्न का मिलान बेकार था क्योंकि सभी अनुरोध जो एप्लिकेशन पर जाते हैं, उसके फ़िल्टर पर भी जाते हैं। इसलिए मैंने फ़िल्टर से मेल खाते हुए पैटर्न को जोड़ा और फिर 'jsp' सर्वलेट के बारे में सीखा और देखा कि यह डिफ़ॉल्ट सर्वलेट की तरह पथ उपसर्ग को नहीं हटाता है। इससे मेरी समस्या हल हो गई, जो बिल्कुल वैसी ही नहीं बल्कि काफी सामान्य थी।


1

टॉमकैट 8.x के लिए जांचा गया: स्थिर संसाधन ठीक काम करते हैं यदि रूट सर्वलेट मैप "" में है। सर्वलेट 3.x के लिए यह किया जा सकता है@WebServlet("")


0

Org.mortbay.jetty.handler.ContextHandler का उपयोग करें। आपको StaticServlet जैसे अतिरिक्त घटकों की आवश्यकता नहीं है।

घाट पर घर,

$ cd संदर्भ

$ cp javadoc.xml static.xml

$ vi static.xml

...

<Configure class="org.mortbay.jetty.handler.ContextHandler">
<Set name="contextPath">/static</Set>
<Set name="resourceBase"><SystemProperty name="jetty.home" default="."/>/static/</Set>
<Set name="handler">
  <New class="org.mortbay.jetty.handler.ResourceHandler">
    <Set name="cacheControl">max-age=3600,public</Set>
  </New>
 </Set>
</Configure>

अपने URL उपसर्ग के साथ ReferencePath का मान सेट करें, और स्थिर सामग्री की फ़ाइल पथ के रूप में संसाधनबेस का मान सेट करें।

इसने मेरे लिए काम किया।


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