Как сопоставить Spring контроллер MVC с uri с завершающей косой чертой и без нее?

У меня есть контроллер Spring с несколькими RequestMappings для разных URI. Мой сервлет - "ui". URI базы сервлета работает только с завершающей косой чертой. Я бы хотел, чтобы мои пользователи не вводили конечную косую черту.

Этот URI работает:

http://localhost/myapp/ui/

Этого нет:

http://localhost/myapp/ui

Он дает мне сообщение HTTP статуса 404.

Сервлет и отображение из моего web.xml:

<servlet>
    <servlet-name>ui</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>ui</servlet-name>
    <url-pattern>/ui/*</url-pattern>
</servlet-mapping>    

Мой контроллер:

@Controller
public class UiRootController {

    @RequestMapping(value={"","/"})
    public ModelAndView mainPage() { 
        DataModel model = initModel();
        model.setView("intro");     
        return new ModelAndView("main", "model", model);
    }

    @RequestMapping(value={"/other"})
    public ModelAndView otherPage() { 
        DataModel model = initModel();
        model.setView("otherPage");     
        return new ModelAndView("other", "model", model);
    }

}

Ответ 1

Если ваше веб-приложение существует в каталоге webapps веб-сервера, например webapps/myapp/, то к корню этого контекста приложения можно получить доступ в http://localhost:8080/myapp/, предполагая порт Tomcat по умолчанию. Это должно работать с конечной косой чертой или без нее, я думаю, по умолчанию - конечно, это верно в Jetty v8.1.5

Как только вы нажмете /myapp, Spring DispatcherServlet возьмет на себя запросы маршрутизации на <servlet-name>, как указано в web.xml, который в ваш случай /ui/*.

Затем DispatcherServlet направляет все запросы от http://localhost/myapp/ui/ к @Controller s.

В самом контроллере вы можете использовать @RequestMapping(value = "/*") для метода mainPage(), который приведет к тому, что оба http://localhost/myapp/ui/ и http://localhost/myapp/ui будут перенаправлены на mainPage().

Примечание: вы также должны использовать Spring >= v3.0.3 из-за SPR-7064

Для полноты, вот файлы, которые я тестировал с помощью:

SRC/основные/Java/контроллеры/UIRootController.java

package controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class UiRootController {
  @RequestMapping(value = "/*")
  public ModelAndView mainPage() {
    return new ModelAndView("index");
  }

  @RequestMapping(value={"/other"})
  public ModelAndView otherPage() {
    return new ModelAndView("other");
  }
}

WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0" metadata-complete="false">
  <servlet>
    <servlet-name>ui</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <!-- spring automatically discovers /WEB-INF/<servlet-name>-servlet.xml -->
  </servlet>

  <servlet-mapping>
    <servlet-name>ui</servlet-name>
    <url-pattern>/ui/*</url-pattern>
  </servlet-mapping>
</web-app>

WEB-INF/щ-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:component-scan base-package="controllers" />

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
  p:order="2"
  p:viewClass="org.springframework.web.servlet.view.JstlView"
  p:prefix="/WEB-INF/views/"
  p:suffix=".jsp"/>
</beans>

А также 2 файла JSP в WEB-INF/views/index.jsp и WEB-INF/views/other.jsp.

Результат:

  • http://localhost/myapp/ → список каталогов
  • http://localhost/myapp/ui и http://localhost/myapp/ui/ → index.jsp
  • http://localhost/myapp/ui/other и http://localhost/myapp/ui/other/ → other.jsp

Надеюсь, это поможет!

Ответ 2

Используя Springboot, мое приложение могло ответить как с завершающим косой чертой, так и без нее, установив параметр @RequestMapping "значение" в пустую строку:

@RestController
@RequestMapping("/some")
public class SomeController {
//                  value = "/" (default) ,
//                  would limit valid url to that with trailing slash.
    @RequestMapping(value = "", method = RequestMethod.GET)
    public Collection<Student> getAllStudents() {
        String msg = "getting all Students";
        out.println(msg);
        return StudentService.getAllStudents();
    }
}

Ответ 3

В конце концов я добавил новую RequestMapping для перенаправления запросов /ui в/ui/. Также удалено отображение пустой строки из mainPage RequestMapping. Для web.xml не требуется редактирования.

В моем контроллере закончилось что-то вроде этого:

    @RequestMapping(value="/ui")
    public ModelAndView redirectToMainPage() {
        return new ModelAndView("redirect:/ui/");
    }

    @RequestMapping(value="/")
    public ModelAndView mainPage() { 
        DataModel model = initModel();
        model.setView("intro");     
        return new ModelAndView("main", "model", model);
    }

    @RequestMapping(value={"/other"})
    public ModelAndView otherPage() { 
        DataModel model = initModel();
        model.setView("otherPage");     
        return new ModelAndView("other", "model", model);
    }

Теперь URL http://myhost/myapp/ui перенаправляется на http://myhost/myapp/ui/, а затем мой контроллер отображает вводную страницу.

Ответ 4

Другим решением, которое я нашел, является не предоставление сопоставления запросов для mainPage() значение:

@RequestMapping
public ModelAndView mainPage() { 
    DataModel model = initModel();
    model.setView("intro");     
    return new ModelAndView("main", "model", model);
}

Ответ 5

PathMatchConfigurer api позволяет вам настроить различные настройки связанных с сопоставлением URL-адресов и сопоставлением путей. В соответствии с последней версией spring по умолчанию используется путь по пути. Для настройки выберите пример ниже.

Для конфигурации на основе Java

@Configuration
@EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.setUseTrailingSlashMatch(true);
    }
}

Для конфигурации на основе XML

<mvc:annotation-driven>
    <mvc:path-matching trailing-slash="true"/>
</mvc:annotation-driven>

Для @RequestMapping ( "/foo" ), если конечное слэш-совпадение установлено на false, example.com/foo/!= example.com/foo, и если оно установлено на true (по умолчанию), example.com/foo/== example.com/foo

Ура!

Ответ 6

попробуйте добавить

@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