在Tomcat中进行URL映射到FrontController servlet

10

我试图遵循 Web应用程序设计模式。除了映射“根”URL之外,一切都正常。

我想将所有请求通过“前端控制器”处理,因此我已经添加了

<servlet-mapping>
    <servlet-name>ControllerServlet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>
web.xml中。通过Netbeans逐步执行可以看到请求进来,Action也能正常工作,但是在此之后就是这一行

request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);

同时,它被控制器捕获后,再次进入Action时会全部失败。

如果不从URL根目录(例如“/”)进入,则可以使其正常工作。

  <servlet-mapping>
        <servlet-name>ControllerServlet</servlet-name>
        <url-pattern>/pages/*</url-pattern>
    </servlet-mapping>

但这不是我想要的。有没有办法让它适用于“根” URL?

4个回答

8
/* URL模式覆盖了所有内容,包括转发的JSP文件和静态资源,例如CSS/JS/images。您不希望将其放在前端控制器servlet上。

将您的控制器servlet保留在更具体的URL模式下,例如/pages/*。您可以通过将静态资源分组到一个常见文件夹中,例如/resources,并创建一个Filter使其映射到/*来实现不使用"/pages"在URL中的功能要求,并在doFilter()方法中执行以下任务:

HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());

if (path.startsWith("/resources/")) {
    // Just let container's default servlet do its job.
    chain.doFilter(request, response);
} else {
    // Delegate to your front controller.
    request.getRequestDispatcher("/pages" + path).forward(request, response);
}

默认情况下,转发的JSP资源不会匹配此过滤器,因此容器自己的JspServlet将正确地接管它。


谢谢回复,看起来有些复杂,所以我需要一段时间才能学习筛选器,在此期间我将把所有内容都留在/pages/目录下。 - Mark
你可以使用 path.match("^.\/[^\.]$") 匹配没有扩展名的请求,并将其转发到前端控制器。 - Ring
1
@user2418306:从URI中删除上下文路径前缀。 - BalusC

3

为什么我们需要映射每个URL。如果您需要映射所有URL,则可能需要在过滤器中跳过URL。

   <filter>
    <display-name>SessionFilter</display-name>
    <filter-name>SessionFilter</filter-name>
    <filter-class>com.colabcom.goshare.app.base.filter.SessionFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>sessionFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

在您的过滤器中,
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        String url = request.getServletPath();
        boolean allowedRequest = Utility.filterURL(url, avoidUrls);
        if(allowedRequest){
            chain.doFilter(request, response);
        }else{
            //Main Filter Code           
        }

一个实用的工具类,用于过滤您的URL:

 public static boolean filterURL(String str, List<String> avoidURLList) {
    boolean exist = false;

    if(avoidURLList == null){
        return exist;
    }
    for (int i = 0; i < avoidURLList.size(); i++) {
        if (str.contains(avoidURLList.get(i))) {
            exist = true;
            break;
        }
    }
    return exist;
}

否则,您可以在web.xml中映射特定的URL,例如:
<filter-mapping>
    <filter-name>sessionFilter</filter-name>
    <url-pattern>*.action</url-pattern>
  </filter-mapping>

谢谢回复,看起来很复杂,所以我需要一段时间才能到达过滤器,现在我会把所有东西都放在/pages/中。 - Mark

0

这个 URL 模式匹配应用程序中所有的 Servlet、JSP 和静态内容。

你需要做的是定义一个 *.jsp 模式,以允许 Tomcat 使用默认的 JSP Servlet:

<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
</servlet-mapping>

0

您可以扩展 Web 服务器的 DefaultServlet。扩展的 Servlet 将成为您的前端控制器。在 doGET 或 doPOST 方法中,将静态页面转发到超类。DefaultServlet 是默认情况下映射到 URL“/”的 Servlet。我已经在 Jetty 服务器上使用过它,但也可以在 Tomcat 上实现。

public class FrontController extends DefaultServlet {

@Override
public void init() throws UnavailableException {
    super.init();
}

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

    String uri = request.getRequestURI();

    /*
     * if request is trying to access inside /static then use the default
     * servlet. YOU CAN USE YOUR OWN BUSINESS LOGIC TO FORWARD REQUESTS 
     * TO DEFAULTSERVLET
     */
    if (uri.startsWith("/static/")) {

        super.doGet(request, response);
        return;
    } else {

        // else use your custom action handlers
    }
}

}

在上面的代码示例中,我将以/static/开头的所有请求转发到默认的servlet进行处理。通过这种方式,您可以将FrontController映射到“/”级别。
<servlet>
<description></description>
<display-name>FrontController</display-name>
<servlet-name>FrontController</servlet-name>
<servlet-class>FrontController</servlet-class>

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


这是否会将您的解决方案绑定到特定容器?换句话说,一旦我将此代码编写到我的应用程序中,我是否会一直使用Tomcat或Jetty或其他容器,直到稍后不得不回来更改此代码? - Ring

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接