DefaultServlet
предназначен для просмотра URI запроса после contextPath
.
В вашем примере кода, когда вы изменили URL-шаблон сервлета из /
в /foo/*
полученный файл разыскиваются на диск теперь включает /foo/
часть.
Другими словами, запрос URI из /css/main.css
результатов в файл (на диске) он ожидает найти в ./src/webapp/foo/css/main.css
Ваш пример имеет несколько недостатков. Не разумно иметь пустую базу ресурсов для вашего ServletContextHandler
, так как самому ServletContext
нужен доступ к этому значению конфигурации.
Вы бы исправить это путем удаления ...
holderPwd.setInitParameter("resourceBase", "./src/webapp/");
и используя ServletContextHandler.setBaseResource(Resource) вместо ...
ctx.setResourceBase(Resource.newResource(new File("./src/webapp")));
Это позволит следующим ServletContext
методам (используются бесчисленными библиотеками сервлет) для работы а также
String getRealPath(String path)
URL getResource(String path)
InputStream getResourceAsStream(String path)
Set<String> getResources(String path)
Наконец, чтобы сделать эту установку вменяемой в ServletContextHandler
, вы добавите имя default
Servlet, на "по умолчанию URL-шаблон", который бывает реализован как DefaultServlet
.
Как это:
// Lastly, the default servlet for root content
// It is important that this is added last.
String defName = "default"; // the important "default" name
ServletHolder holderDef = new ServletHolder(defName, DefaultServlet.class);
holderDef.setInitParameter("dirAllowed","true");
ctx.addServlet(holderDef,"/"); // the servlet spec "default url-pattern"
Теперь, если вы также есть необходимость обслуживания статического контента из запроса URI /foo/*
из каталога, не принадлежащие к веб-приложение, вы можете сделать это. Это потребует установки другого DefaultServlet
, который не участвует в ServletContext
.
Примером этой установки является ...
package jetty;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.resource.PathResource;
import java.io.File;
import java.nio.file.Path;
public class ManyDefaultServlet
{
public static void main(String[] args) throws Exception {
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.addConnector(connector);
// The filesystem paths we will map
Path homePath = new File(System.getProperty("user.home")).toPath().toRealPath();
Path pwdPath = new File(System.getProperty("user.dir")).toPath().toRealPath();
// Setup the basic application "context" for this application at "/"
// This is also known as the handler tree (in jetty speak)
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.setBaseResource(new PathResource(pwdPath));
server.setHandler(context);
// Fist, add special pathspec of "/home/" content mapped to the homePath
ServletHolder holderHome = new ServletHolder("static-home", DefaultServlet.class);
holderHome.setInitParameter("resourceBase",homePath.toUri().toASCIIString());
holderHome.setInitParameter("dirAllowed","true");
// Use request pathInfo, don't calculate from contextPath
holderHome.setInitParameter("pathInfoOnly","true");
context.addServlet(holderHome,"/foo/*"); // must end in "/*" for pathInfo to work
// Lastly, the default servlet for root content
// It is important that this is last.
String defName = "default"; // the important "default" name
ServletHolder holderDef = new ServletHolder(defName, DefaultServlet.class);
holderDef.setInitParameter("dirAllowed","true");
context.addServlet(holderDef,"/"); // the servlet spec "default url-pattern"
server.start();
server.join();
}
}
При этом используется вторым DefaultServlet
, с использованием уникальной ресурсной базы только для этого DefaultServlet
и отображается в URL-шаблон, который заканчивается в /*
.
И наконец, параметру init для этой второй DefaultServlet
предлагается использовать pathInfo URI запроса, а не разделять на contextPath, как обычно.
Для получения дополнительной информации о том, что весь этот Pathinfo, запрос URI, contextPath и URL-модели, заканчивающиеся в /*
все о см в useful answer by @30thh
Это самостоятельные DefaultServlet
декларация не участвует в ServletContext
и библиотеки не смогут видеть или получать доступ к содержимому с этого DefaultServlet
с помощью методов ServletContext
. Однако все входящие запросы HTTP-клиента могут легко запросить контент через этот шаблон url.
К сожалению, я не могу выдвигать более одного раза. Спасибо за подробное объяснение. –