Как обслуживать.html файлы с помощью Spring
Я разрабатываю веб-сайт с помощью Spring и пытаюсь обслуживать ресурсы, которые не являются файлами.jsp (например,.html)
сейчас я закомментировал эту часть моей конфигурации сервлета
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
И попытался вернуть с контроллера полный путь к ресурсу.
@Controller
public class LandingPageController {
protected static Logger logger = Logger.getLogger(LandingPageController.class);
@RequestMapping({"/","/home"})
public String showHomePage(Map<String, Object> model) {
return "/WEB-INF/jsp/index.html";
}
}
файл index.html существует в этой папке.
ПРИМЕЧАНИЕ: когда я меняю index.html на index.jsp, мой сервер теперь правильно обслуживает страницу.
Спасибо.
8 ответов
Первоначальная проблема заключается в том, что конфигурация определяет свойство suffix=".jsp"
поэтому реализующий класс ViewResolver добавит .jsp
до конца имя представления возвращается из вашего метода.
Однако, так как вы закомментировали InternalResourceViewResolver
затем, в зависимости от остальной конфигурации вашего приложения, возможно, не будет зарегистрирован ни один другой ViewResolver. Вы можете обнаружить, что сейчас ничего не работает.
поскольку .html
файлы являются статическими и не требуют обработки сервлетом, тогда более эффективно и проще использовать <mvc:resources/>
картирование Это требует Spring 3.0.4+.
Например:
<mvc:resources mapping="/static/**" location="/static/" />
который будет проходить через все запросы, начиная с /static/
к webapp/static/
каталог.
Итак, поставив index.html
в webapp/static/
и используя return "static/index.html";
из вашего метода Spring должен найти представление.
Предыстория проблемы
Первое, что нужно понять, это следующее: это не весна, которая рендерит файлы jsp. Это делает JspServlet (org.apache.jasper.servlet.JspServlet). Этот сервлет поставляется с Tomcat (Jasper Compiler), а не с пружиной. Этот JspServlet знает, как скомпилировать страницу jsp и как вернуть ее в виде HTML-текста клиенту. JspServlet в tomcat по умолчанию обрабатывает только запросы, соответствующие двум шаблонам: *.jsp и *.jspx.
Теперь, когда весна делает вид с InternalResourceView
(или же JstlView
) три вещи действительно имеют место:
- получить все параметры модели из модели (возвращаемой методом вашего контроллера, т.е.
"public ModelAndView doSomething() { return new ModelAndView("home") }"
) - представить эти параметры модели как атрибуты запроса (чтобы он мог быть прочитан JspServlet)
- переслать запрос в JspServlet.
RequestDispatcher
знает, что каждый запрос *.jsp должен быть перенаправлен в JspServlet (потому что это конфигурация tomcat по умолчанию)
Когда вы просто измените имя представления на home.html, tomcat не будет знать, как обрабатывать запрос. Это потому, что нет сервлетов, обрабатывающих запросы *.html.
Решение
Как это решить. Есть три наиболее очевидных решения:
- выставить HTML как файл ресурсов
- поручить JspServlet также обрабатывать *.html запросы
- написать свой собственный сервлет (или передать другой существующий запрос сервлета в *.html).
Для полных примеров кода, как этого добиться, обратитесь к моему ответу в другом посте: Как отобразить запросы в HTML-файл в Spring MVC?
Я бы просто добавил, что вам не нужно реализовывать метод контроллера для этого, так как вы можете использовать тег view-controller (Spring 3) в файле конфигурации сервлета:
<mvc:view-controller path="/" view-name="/WEB-INF/jsp/index.html"/>
Вы по-прежнему можете использовать тот же распознаватель View, но установите суффикс пустым.
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix="" />
Теперь ваш код может вернуть либо index.html, либо index.jsp, как показано в примере ниже -
@RequestMapping(value="jsp", method = RequestMethod.GET )
public String startJsp(){
return "/test.jsp";
}
@RequestMapping(value="html", method = RequestMethod.GET )
public String startHtml(){
return "/test.html";
}
Я столкнулся с той же проблемой и попробовал различные решения для загрузки html-страницы из Spring MVC, следующее решение сработало для меня
Шаг 1 в файле web.xml сервера комментирует эти две строки
<!-- <mime-mapping>
<extension>htm</extension>
<mime-type>text/html</mime-type>
</mime-mapping>-->
<!-- <mime-mapping>
<extension>html</extension>
<mime-type>text/html</mime-type>
</mime-mapping>
-->
Шаг-2 введите следующий код в веб-приложение XML
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
Шаг-3 создайте класс статического контроллера
@Controller
public class FrontController {
@RequestMapping("/landingPage")
public String getIndexPage() {
return "CompanyInfo";
}
}
Шаг 4 в файле конфигурации Spring измените суффикс на.htm .htm
Шаг 5 Переименуйте страницу в файл.htm, сохраните его в WEB-INF и постройте / запустите сервер.
localhost:8080/.../landingPage
Конфигурация Java для html-файлов (в данном случае index.html):
@Configuration
@EnableWebMvc
public class DispatcherConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/index.html").addResourceLocations("/index.html");
}
}
Измените значение p: суффикс =".jsp" соответственно, в противном случае мы можем разработать собственный преобразователь представления
Похоже, вы пытаетесь сделать что-то вроде этого:
- Статические представления HTML
- Пружинные контроллеры, обслуживающие AJAX
В этом случае, как упоминалось ранее, наиболее эффективный способ - позволить веб-серверу (не Spring) обрабатывать запросы HTML как статические ресурсы. Итак, вам нужно следующее:
- Переадресация всех запросов.html, .css, .js, .png и т. Д. В обработчик ресурсов веб-сервера
- Сопоставьте все другие запросы с контроллерами Spring
Вот один из способов сделать это...
web.xml - привязать сервлет к корню (/)
<servlet>
<servlet-name>sprung</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
...
<servlet>
<servlet-mapping>
<servlet-name>sprung</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Spring JavaConfig
public class SpringSprungConfig extends DelegatingWebMvcConfiguration {
// Delegate resource requests to default servlet
@Bean
protected DefaultServletHttpRequestHandler defaultServletHttpRequestHandler() {
DefaultServletHttpRequestHandler dsrh = new DefaultServletHttpRequestHandler();
return dsrh;
}
//map static resources by extension
@Bean
public SimpleUrlHandlerMapping resourceServletMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
//make sure static resources are mapped first since we are using
//a slightly different approach
mapping.setOrder(0);
Properties urlProperties = new Properties();
urlProperties.put("/**/*.css", "defaultServletHttpRequestHandler");
urlProperties.put("/**/*.js", "defaultServletHttpRequestHandler");
urlProperties.put("/**/*.png", "defaultServletHttpRequestHandler");
urlProperties.put("/**/*.html", "defaultServletHttpRequestHandler");
urlProperties.put("/**/*.woff", "defaultServletHttpRequestHandler");
urlProperties.put("/**/*.ico", "defaultServletHttpRequestHandler");
mapping.setMappings(urlProperties);
return mapping;
}
@Override
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
//controller mappings must be evaluated after the static resource requests
handlerMapping.setOrder(1);
handlerMapping.setInterceptors(this.getInterceptors());
handlerMapping.setPathMatcher(this.getPathMatchConfigurer().getPathMatcher());
handlerMapping.setRemoveSemicolonContent(false);
handlerMapping.setUseSuffixPatternMatch(false);
//set other options here
return handlerMapping;
}
}
Дополнительные соображения
- Скрыть расширение.html - это выходит за рамки Spring, если вы делегируете статические запросы ресурсов. Посмотрите в фильтр перезаписи URL.
- Шаблонирование - Вы не хотите дублировать разметку на каждой отдельной HTML-странице для общих элементов. Скорее всего, этого нельзя сделать на сервере, если использовать HTML в качестве статического ресурса. Посмотрите на клиентской стороне *VC Framework. Я фанат YUI, который имеет множество шаблонных механизмов, включая Handlebars.
Если вы используете весеннюю загрузку, вы не должны устанавливать свойства spring.mvc.view.prefix
а также spring.mvc.view.suffix
в вашем файле application.properties вместо этого настройте bean-компонент ViewResolver
из класса конфигурации.
application.properties
# Configured in @Configuration GuestNav
#spring.mvc.view.prefix=/WEB-INF/views/
#spring.mvc.view.suffix=.jsp
# Live reload
spring.devtools.restart.additional-paths=.
# Better logging
server.tomcat.accesslog.directory=logs
server.tomcat.accesslog.file-date-format=yyyy-MM-dd
server.tomcat.accesslog.prefix=access_log
server.tomcat.accesslog.suffix=.log
Основной метод
@SpringBootApplication
public class WebApp extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WebApp.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(WebApp.class, args);
}
}
Класс конфигурации
@Configuration
@EnableWebMvc
public class DispatcherConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/views/**").addResourceLocations("/views/");
}
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/notinuse/");
viewResolver.setSuffix("");
return viewResolver;
}
}
Класс контроллера
@Controller
public class GuestNav {
@GetMapping("/")
public String home() {
return "forward:/views/guest/index.html";
}
}
Вы должны поместить свои файлы в каталог /webapp/views/guest/index.html
, будьте осторожны, каталог webapp находится за пределами каталога ресурсов.
Таким образом, вы можете использовать шаблоны URL-адресов spring-mvc, но использовать статический контекст.