代码之家  ›  专栏  ›  技术社区  ›  bezmax

带xml混合问题的Spring注释

  •  2
  • bezmax  · 技术社区  · 16 年前

    我正在试图找到一个最佳的方法来使用最新的spring3.0。我真的很喜欢@RequestMapping注释及其所有特性。但是,我不喜欢的是,绑定到动作的URL应该在java文件中完全指定。

    最好是以某种方式将整个url绑定配置发送到上下文xml文件。不过,如果url绑定至少可以部分地移动到xml,也可以。

    这就是我的意思:

    当前代码:

    @Controller
    @RequestMapping("myController")
    class MyController {
        @RequestMapping("**/someMethod")
        String someMethod(...) {
        }
    }
    

    此代码将myController/somethod绑定到myController::somethod。我不喜欢的是“myController”部分绑定也在这个java文件中。我想让它尽可能的模块化,而这个部分对我来说非常糟糕。

    上下文.xml

    <mapping>
        <url>myController</url>
        <controller>MyController</controller>
    </mapping>    
    

    @Controller
    //-- No request mapping here --// @RequestMapping("myController")
    class MyController {
        @RequestMapping("**/someMethod")
        String someMethod(...) {
        }
    }
    

    在Spring3中的带注释的控制器上有这样的功能吗?

    3 回复  |  直到 16 年前
        1
  •  4
  •   Arthur Ronald    16 年前

    按要求。你想吗 创建自己的URL模式,而不使用Spring控制器注释 .

    首先,创建CustomController注释以避免被@Controller检测到 HandlerMapping

    package br.com.ar.web.stereotype;
    
    @Target(value=TYPE)
    @Retention(value=RUNTIME)
    @Component
    public @interface CustomController {}
    

    @CustomController
    public class AccountController {
    
        public void form(Long id) {
            // do something
        }
    
    }
    

    我们的handleAdapter—它负责调用我们的控制器—类似于Spring验证程序接口方法

    package br.com.ar.web.support;
    
    public class CustomHandlerAdapter implements HandlerAdapter {
    
        public boolean supports(Object handler) {
            Annotation [] annotationArray = handler.getClass().getAnnotations();
    
            for(Annotation annotation: annotationArray) {
               /**
                 * Make sure your annotation contains @SomeController
                 */
            }
        }
    
        /**
          * Third parameter is our CustomController
          */
        public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            Method[] methods = handler.getClass().getMethods();
    
            /**
              * Logic To verify whether Target method fullfil request goes here
              */            
    
            /**
              * It can be useful To see MultiActionController.invokeNamedMethod and MultiActionController.isHandlerMethod              
              */
            method.invoke(// parameters goes here);
        }
    
        public long getLastModified(HttpServletRequest request, Object handler) {
            return -1;
        }
    }
    

    getApplicationContext().getBean(beanName);
    
    package br.com.ar.web.servlet.handler;
    
    public class CustomeHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
    
        private static final String CUSTOM_HANDLER_ADAPTER_NAME = "CUSTOM_HANDLER_ADAPTER_NAME";
    
        /**
          * Bind each URL path-CustomController bean name
          */
        private final Map handlerMap = new LinkedHashMap();
    
        /**
          * Ordered interface will make sure your HandlerMapping should be intercepted BEFORE or AFTER DefaultAnnotationHandlerMapping
          */
        public final void setOrder(int order) {
            this.order = order;
        }
    
        public final int getOrder() {
            return this.order;
        }
    
        /**
          * HandlerMapping interface method
          */
        public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            String url = extractUrl(request);
    
            if(handlerMap.get(url) == null) {
                /**
                  * Because Spring 3.0 controller is stateful
                  * Let's just store CustomController class (Not an instance) in ApplicationContext
                  *
                  * Or use a FactoryBean to retrieve your CustomController
                  */
                handlerMap.put(url, getApplicationContext().getBean(beanName));
            }
    
            /**
              * instantiateClass needs no-arg constructor
              */
            Object handler = BeanUtils.instantiateClass(handlerMap.get(url));
    
            return new HandlerExecutionChain(handler);
        }
    
        private String extractUrl(HttpServletRequest request) {
            /**
              * Here goes code needed To retrieve URL path from request
              *
              * Take a look at AntPathMatcher, UrlPathHelper and PathMatcher
              *
              * It can be useful To see AbstractUrlHandlerMapping.getHandlerInternal method
              */ 
        }
    
    }
    

    <bean id="br.com.ar.web.servlet.handler.CustomHandlerMapping"/>
    <bean id="br.com.ar.web.support.CustomHandlerAdapter"/>
    <!--To allow Spring 3.0 controller-->
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
    

    我希望它能给你一个好的开始

    幕后

    /**
      * Our HandlerMapping goes here
      */
    HandlerMapping handlerMapping = getHandler(request);
    
    HandlerExecutionChain handlerExecutionChain = handlerMapping.getHandler(request);
    
    for(HandlerInterceptor interceptor: handlerExecutionChain.getInterceptors) {
        interceptor.preHandle(request, response, handlerExecutionChain.getHandler());
    }
    
    /**
      * Our CustomController goes here
      */
    Object handler = handlerExecutionChain.getHandler();
    
    /**
      * Our CustomHandlerAdapter goes here
      */
    HandlerAdapter handlerAdapter = getHandlerAdapter(handler);
    
    ModelAndView mav = handlerAdapter.handle(request, response, handler);
    
    for(HandlerInterceptor interceptor: handlerExecutionChain.getInterceptors) {
        interceptor.postHandle(request, response, handlerExecutionChain.getHandler());
    }
    
        2
  •  0
  •   skaffman    16 年前

    您可以以相当大的灵活性将XML和注释样式映射结合起来。两者都可以使用Ant风格的通配符匹配,所以您可以这样做(没有经过测试,但给出了一般的想法):

    <bean class="SimpleUrlHandlerMapping">
       <property name="mappings">
          <map>
             <entry key="myController/**" value-ref="myController"/>
          </map>
       </property>
    </bean>
    
    <bean id="myController" class="MyController"/>
    

    然后

    @Controller
    class MyController {
        @RequestMapping("**/someMethod")
        String someMethod(...) {
        }
    }
    

    URL /myController/someMethod

    你可能需要玩一点让它工作,但这是它的要点。

        3
  •  0
  •   Arthur Ronald    16 年前

    绑定到操作的URL应完全指定 在java文件中

    所以依靠 ControllerClassNameHandlerMapping

    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
    

    记住ControllerNameHandlerMapping 控制器后缀 如果存在的话 如果只希望第一个字母的大小写较低,请将区分大小写的属性设置为true

    package br.com.ar.view.resources;
    
    @Controller
    public class UserController {
    
        /**
          * mapped To /user/form
          */
        @RequestMapping(method=RequesMethod.GET)
        public void form(Model model) {
            model.add(categoryRepository().getCategoryList());
        }
    
        /**
          * mapped To user/form
          */
        @RequestMapping(method=RequesMethod.POST)
        public void form(User user) {
            userRepository.add(user);
        }
    
    }
    

    还有更多: 如果您使用模块化的应用程序,则可以依赖basePackage属性

    br.com.ar.view.financial.AccountController;
    br.com.ar.view.resources.ManagementController;
    

    定义基本包

    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
        <property name="basePackage" value="br.com.ar.view"/>
    </bean>
    

    你可以打电话给你的账户管理员

    /financial/account/form
    

    你可以打电话给你的管理员 形式 方法as

    /resources/management/form
    

    因为我很确定您在配置上使用默认TranslateToViewName约定,所以您的目录结构应该如下所示

    /WEB-INF
        /view
            /financial
                /user
                    form.jsp
    
            /resources
                /management
                    form.jsp
    

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/view/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    

    最后,如果你的要求 . 没问题,请定义defaultHandler属性

    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
        <property name="basePackage" value="br.com.ar.view"/>
        <property name="caseSensitive" value="true"/>
        <property name="defaultHandler">
            <bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
        </property>
    </bean>
    

    现在,如果您调用/index.htm(我假设您的DispatcherServlet截获了htm扩展),并且您没有任何IndexController,Spring将查找

    /WEB-INF/view/index.jsp