拦截请求并在内部转发给控制器?

时间:2015-08-25 14:13:42

标签: java spring

我有一个分为不同模块的项目,例如一个网站和一个论坛。

论坛可在以下网址找到:

http://example.com/[forum]/

例如可以是:

http://example.com/support/
http://example.com/helpme/
http://example.com/aforum/

该网站位于:

http://example.com/[site]/

例如可以是:

http://example.com/site1/
http://example.com/nice/
http://example.com/something/

[论坛]和[网站]部分是可变的。在我的数据库中,我查找了#34; nice"是一个网站," helpme"是一个论坛。

我的ForumController有一个Spring RequestMapping:

@RequestMapping(value = { "/{simpleTitle:[0-9a-z-]+}" }, method = RequestMethod.GET, produces = "text/html")
    public void list(@PathVariable String simpleTitle, Model model, HttpServletRequest req, HttpServletResponse resp) {

我对网站有同样的东西,所以一个SiteController:

@RequestMapping(value = { "/{simpleTitle:[0-9a-z-]+}" }, method = RequestMethod.GET, produces = "text/html")
    public void list(@PathVariable String simpleTitle, Model model, HttpServletRequest req, HttpServletResponse resp) {

这当然很糟糕,因为2个具有相同请求映射的控制器并不好。

我可以创建一个FrontController,它具有上面的请求映射,查找simpleTitle(论坛或网站)和调用函数来显示论坛或网站。这很有效。

但它并非如此"春天"喜欢和结构化。

是否有可能"拦截"请求并在控制器上内部转发(或调用函数)?

这样我就可以拥有看起来像一个简单标题的拦截器,决定它是一个论坛还是一个网站,并且"转发" /"调用"正确的控制者。

2 个答案:

答案 0 :(得分:2)

坦率地说,我喜欢@Luiggi Mendoza解决方案,但如果您想要替代方案,请使用以下内容:

            package eu.europa.acer.aris.ceremp.filter;

        import java.io.IOException;

        import javax.servlet.FilterChain;
        import javax.servlet.ServletException;
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;

        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.beans.factory.annotation.Value;
        import org.springframework.security.core.authority.SimpleGrantedAuthority;
        import org.springframework.security.core.context.SecurityContextHolder;
        import org.springframework.stereotype.Component;
        import org.springframework.web.filter.OncePerRequestFilter;


        @Component(value = "yourCustomFilter")
        public class YourCustomFilter extends OncePerRequestFilter{

            private static final Logger logger = LoggerFactory.getLogger(YourCustomFilter.class);

            @Override
            protected void doFilterInternal(HttpServletRequest request,
                    HttpServletResponse response, FilterChain filterChain)
                            throws ServletException, IOException {
                //String[] path = request.getRequestURL().toString().split("/");

                            if (letPagePass(request.getRequestURL().toString()) == false)
                            {   
                                // if request is bound to static resource like js//img do nothing, the filter chain will activate
                                if (letResourcePass(request.getRequestURL().toString()))
                                {

                                }
                                else 
                                {
                                    String[] urlInfos = obtainUrlAndParametersLast(request.getRequestURL().toString());
                                    // last element will always give back  last part including any parameter
                                    // first element will always be a controller modifier
                                    response.sendRedirect(request.getContextPath()+rebuildControllerPath(urlInfos));
                                    return;
                                }
                            }
                filterChain.doFilter(request, response);

            }

            private String rebuildControllerPath(String[] pathElement )
            {
                //do your thing here
                if ("forum".equals(pathElement[0]))
                {
                String addenda = "/forumController/";
                for (String singlePart: pathElement)
                {
                    addenda = addenda+singlePart+"/";
                }
                return addenda;
                }

            }

            // bind forceful redirect
            public boolean letPagePass(String url)
            {
                // if you have some page that are naturally unique among controllers that you want always to process natively
                String[] path = url.split("/");
                if (path[path.length-2].startsWith("yourCertainUrlIgnoringParameters"))
                {
                    return true;
                }
                // directcall
                else if (path[path.length-2].startsWith("yourCertainUrlIgnoringParameters2"))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

            public boolean letResourcePass(String url)
            {
                String[] path = url.split("/");

                /*
                this assumes you have always a strict structure so your image//js//reource will always be in
                https://domainname/a/lot/of/folder/img/actuaresource.png
                or
                https://domainname/a/lot/of/folder/js/actuaresource.js
                etc
                */
                //image pass
                if (path[path.length-2].equals("img") || url.contains("/img/"))
                {
                    return true;
                }
                //css pass
                else if (path[path.length-2].equals("css")  || url.contains("/css/"))
                {
                    return true;
                }
                //js pass
                else if (path[path.length-2].equals("js")  || url.contains("/js/"))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

            @Override
            public void destroy() {
            }

        }

并在web.xml文件中添加以下xml代码段

        <!--  your fi Filter -->
            <filter>
                <filter-name>yourCustomFilter</filter-name>
                <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            </filter>
            <filter-mapping>
                <filter-name>yourCustomFilter</filter-name>
                <url-pattern>/*</url-pattern>
            </filter-mapping>

答案 1 :(得分:0)

干杯Luiggi Mendoza和witchedwiz为伟大的想法!

在我吃饭的时候,我提出了一个非常简单的解决方案:使用servlet过滤器。在doFilter中添加一个带有HttpServletRequestWrapper(类型:forum或type:site)的请求头。

在@RequestMapping中添加header属性,例如headers =“type = forum”。

现在@RequestMapping可以有相同的网址,它们在请求标头中有所不同。并且所有弹簧功能都有效,尽管到目前为止我只做了一个简单的测试用例。

WebApplicationContextUtils帮助在servlet过滤器中获取了spring bean。