0

我正在使用带有默认注释映射的 Spring 3.2.2 Web MVC。我使用这样的 servlet 映射:

<servlet>
    <servlet-name>profil</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </init-param>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>de.kicktipp.web.config.servlets.ProfilServletConfig</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>profil</servlet-name>
    <url-pattern>/info/profil/*</url-pattern>
</servlet-mapping>

这是我们的 servlet 配置:

@Configuration
@ComponentScan("de.kicktipp.controller")
@EnableWebMvc
public class ProfilServletConfig extends WebMvcConfigurerAdapter
{
    @Override
    public void addInterceptors ( InterceptorRegistry registry )
    {
       // we add a few interceptors here
    }

    @Bean
    public DefaultRequestToViewNameTranslator viewNameTranslator ( )
    {
        DefaultRequestToViewNameTranslator defaultRequestToViewNameTranslator = new DefaultRequestToViewNameTranslator();
        defaultRequestToViewNameTranslator.setStripExtension(false);
        defaultRequestToViewNameTranslator.setAlwaysUseFullPath(false);
        defaultRequestToViewNameTranslator.setPrefix("profil/");
        return defaultRequestToViewNameTranslator;
    }
}

通配符匹配很重要,因为我们想用这种模式匹配许多 url,比如/info/profil/page1/info/profil/page2等等。

当我想匹配/info/profil没有尾部斜杠的“基本”URL 时,它会被 servlet“配置文件”拾取。

现在我尝试了三种控制器方法来匹配/info/profil处理程序方法:

@RequestMapping("/")
protected void get1 () {}

@RequestMapping("")
protected void get2 () {}

@RequestMapping("/info/profil")
protected void get3 () {}

只有最后一个有效。这是因为如果 servlet 中的路径为空字符串,则 UrlPathHelper#getLookupPathForRequest(javax.servlet.http.HttpServletRequest) 返回应用程序中的完整路径:

public String getLookupPathForRequest(HttpServletRequest request) {
    // Always use full path within current servlet context?
    if (this.alwaysUseFullPath) {
        return getPathWithinApplication(request);
    }
    // Else, use path within current servlet mapping if applicable
    String rest = getPathWithinServletMapping(request);
    if (!"".equals(rest)) {
        return rest;
    }
    else {
        return getPathWithinApplication(request);
    }
}

对于对“/info/profil/”的请求,该方法将返回“/”,但对于“/info/profil”(没有尾部斜杠),它将返回“/info/profil”,因为其余变量是空字符串并且在前面该方法返回 pathWithinApplication。

其他路径通常与 servlet 映射中的路径匹配(因为 alwaysUseFullPath 默认为 false)。但是“根”路径与应用程序内部的完整路径匹配(就像它总是在 alwaysUseFullPath 为真时一样)。

为什么会这样?为什么 spring 不尝试匹配空字符串,而是尝试匹配应用程序中的路径?

在此处查看春季问题https://jira.springsource.org/browse/SPR-10491

4

2 回答 2

3

尝试添加

@RequestMapping(method = RequestMethod.GET) public String list() { return "redirect:/strategy/list"; }

结果:

    @RequestMapping(value = "/strategy")
    public class StrategyController {
    static Logger logger = LoggerFactory.getLogger(StrategyController.class);

    @Autowired
    private StrategyService strategyService;

    @Autowired
    private MessageSource messageSource;

    @RequestMapping(method = RequestMethod.GET)
    public String list() {
        return "redirect:/strategy/list";
    }   

    @RequestMapping(value = {"/", "/list"}, method = RequestMethod.GET)
    public String listOfStrategies(Model model) {
        logger.info("IN: Strategy/list-GET");

        List<Strategy> strategies = strategyService.getStrategies();
        model.addAttribute("strategies", strategies);

        // if there was an error in /add, we do not want to overwrite
        // the existing strategy object containing the errors.
        if (!model.containsAttribute("strategy")) {
            logger.info("Adding Strategy object to model");
            Strategy strategy = new Strategy();
            model.addAttribute("strategy", strategy);
        }
        return "strategy-list";
    }  

** 学分:

高级@RequestMapping技巧——控制器根和URI模板

dtr-trading.blogspot.it 的 CRUD 教程

于 2014-05-14T14:10:59.130 回答
0

[EDIT]

As I see you're using annotation mvc config. The default mapping is configured to "/" path in your application. To change these default settings, you can edit your web.xml to this template:

<web-app>
  <!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
       instead of the default XmlWebApplicationContext -->
  <context-param>
      <param-name>contextClass</param-name>
      <param-value>
          org.springframework.web.context.support.AnnotationConfigWebApplicationContext
      </param-value>
  </context-param>

  <!-- Configuration locations must consist of one or more comma- or space-delimited
       fully-qualified @Configuration classes. Fully-qualified packages may also be
       specified for component-scanning -->
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>de.kicktipp.controller.ProfilAppConfig</param-value>
  </context-param>

  <!-- Bootstrap the root application context as usual using ContextLoaderListener -->
  <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- Declare a Spring MVC DispatcherServlet as usual -->
  <servlet>
      <servlet-name>dispatcher</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
           instead of the default XmlWebApplicationContext -->
      <init-param>
          <param-name>contextClass</param-name>
          <param-value>
              org.springframework.web.context.support.AnnotationConfigWebApplicationContext
          </param-value>
      </init-param>
      <!-- Again, config locations must consist of one or more comma- or space-delimited
           and fully-qualified @Configuration classes -->
      <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>de.kicktipp.controller.ProfilServletConfig</param-value>
      </init-param>
  </servlet>

  <!-- map all requests for /info/profil/* to the dispatcher servlet -->
  <servlet-mapping>
      <servlet-name>dispatcher</servlet-name>
      <url-pattern>/info/profil/*</url-pattern>
  </servlet-mapping>
</web-app>

So, you have the de.kicktipp.controller.ProfilServletConfig on your application. Just check if the first code block for de.kicktipp.controller.ProfilAppConfig (contextClass) is really necessary.

Source: Spring Docs

于 2013-04-24T00:05:46.370 回答