FreeMarker:显示自定义 404 页面而不重定向

FreeMarker : Displaying a custom 404 page without redirection

我有一个静态的 404 页面,里面有花哨的东西。 如果用户输入错误的 url 不存在的页面,我希望他看到那个 404 页面,但也希望保持 url 不变,以便用户看到s/he 输入 url 有什么错误。

进入的页面不存在: http://localhost:10039/my.website/my/halp.html

404页面: http://localhost:10039/my.website/my/notfound.html

简而言之,我不会在这里使用 "sendRedirect",而是 "get content" 的 pageNotFoundUrl 并在 url 仍然是 http://localhost:10039/my.website/my/halp.html

时显示它

我还按照 Kayaman 的建议尝试了 "forward" 而不是重定向,但在这种情况下我得到 " 无法转发。响应已提交。"

TestServlet 在 web.xml 中定义,而这个 class 扩展了 UtilFreemarkerServlet,它扩展了 FreemarkerServlet。

UtilFreemarkerServlet

public abstract class UtilFreemarkerServlet extends FreemarkerServlet {
    private static final long serialVersionUID = 1L;

    public static final String REQUEST_OBJECT_NAME = "RequestObject";

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void init() throws ServletException {
        logger.info("init started");
        super.init();
        Configuration cfg = getConfiguration();
        cfg.setLocalizedLookup(false);

    }

    @Override
    protected ObjectWrapper createObjectWrapper() {
        return ObjectWrapper.BEANS_WRAPPER;
    }

    @Override
    protected HttpRequestParametersHashModel createRequestParametersHashModel(HttpServletRequest request) {
        request.setAttribute(REQUEST_OBJECT_NAME, request);
        return super.createRequestParametersHashModel(request);
    }   

}

TestServlet

public class TestServlet extends UtilFreemarkerServlet{
    private static final long serialVersionUID = 1L;    
    private String website;

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

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {     
        super.service(req, resp);       
        boolean handleResult = handlerForRequest(req, resp);            
    }

    protected boolean handlerForRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        if (resp.getStatus() == 404) {
            String pageNotFoundUrl = "http://localhost:10039/my.website/my/notfound.html";          
            RequestDispatcher rd = req.getRequestDispatcher(url);
            rd.forward(req, resp);
            // resp.sendRedirect(url);
        }

        return true;
    }

}

转发而不是重定向到所需资源,URL 将保持不变。

RequestDispatcher rd = request.getRequestDispatcher("my_404.html");
rd.forward(request, response);

RequestDispatcher 在我的例子中没有用,因为响应一直被提交。这是我最终为 Freemarker Servlet 提供的解决方案;

出于我的目的,我正在覆盖 Freemarker servlet 的几个方法,例如 service() 和 requestUrlToTemplatePath()。通过这种方式,我可以在响应提交之前进行干预。

  1. 首先覆盖服务方法。我的目的是检查请求的 url 页面是否存在。

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {         
        checkIfPageExists(req);
        super.service(req, resp);                       
    }
    
  2. checkIfPageTemplateExists 检查页面模板是否为空。如果为 null,则表示它不可用。在这种情况下,我设置了一个请求属性。否则说明存在

    protected void checkIfPageExists(HttpServletRequest req)
    throws     ServletException {
    
    String relativeUrl = requestUrlToTemplatePath(req);
    try {
            getConfiguration().getTemplate(relativeUrl); //throws exception if the template cannot be accessed
        } catch (TemplateNotFoundException e) {
            logger.debug("TemplateNotFoundException for " + relativeUrl);
            pageNotFound = "/customNotFoundPage.html";
        } catch (IOException e) {
            logger.debug("IOException for " + relativeUrl);
            pageNotFound = "/customNotFoundPage.html";
        } 
      req.setAttribute(NOT_FOUND_PAGE, pageNotFoundPage);
    }
    
  3. 项目符号 1 中的最后一行是针对 super.service() 方法的。这将触发 requestUrlToTemplatePath() 方法,该方法实际上是您可以在不更改 url 的情况下指定要显示的 url 页面的方法。 我只是检查请求是否具有 NOT_FOUND_PAGE 属性。如果是这样,只需覆盖路径本身并继续流程中的下一步。否则,直接使用superclass的路径即可。

    @Override
    protected String requestUrlToTemplatePath(HttpServletRequest request) 
    throws ServletException {
    
        String path = super.requestUrlToTemplatePath(request);
    
        //Check if NOT_FOUND_PAGE is requested
        if(request.getAttribute(NOT_FOUND_PAGE) != null) {
            path =  (String) request.getAttribute(NOT_FOUND_PAGE);      
        }
    
     return path;
     }