Статичні ресурси - це елементи веб-програми, які є статичними. Ось так просто. Тобто, це файли, які не змінюються протягом виконання програми, такі як CSS-стилі, HTML-сторінки, скрипти JavaScript, зображення і т.п. Все б нічого, але, виявляється, Spring MVC не вміє їх обробляти, якщо йому в цьому не допомогти.
Справа в тому, що по-замовчуванню, статичні запити обробляє так званий DefaultServlet, який створюється самим сервером і який привязаний до адреси /, тобто до кореневої папки веб-програми (web application root). Якщо програма отримала запит (request) і для нього зареєстровано відповідний сервлет в файлі web.xml, то цей сервлет буде викликано для обробки запиту. А коли відповідного сервлету не зареєстровано, запит буде оброблено згаданим "сервлетом по-замовчуванню" (java-allandsundry.com). Це він знає, як обробляти запити до статичних ресурсів.
Але згідно концепції Spring MVC феймворку, коренева папка веб-програми закріплена за так званим фронт-контролером, який називається DispatcherServlet (див. метод getServletMappings()):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class MusicBoxDispatcherServlet extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { RootConfig.class }; } /* * DispatcherServlet loads beans containing web components * such as controllers, view resolvers, and handler mappings * that are defined in the SpringAppConfig configuration * class (using Java configuration). */ @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { SpringAppConfig.class }; } } |
Таким чином, DispatcherServlet від Spring MVC перехоплює всі запити і дезактивує роботу серверного default-сервлету. Але обробляти статичні запити він не вміє. Щоб налаштувати таку обробку є два шляхи:
- підключити заново default-сервлет (docs.spring.io);
- налаштувати ResourceHandlerRegistry (docs.spring.io).
Перший метод в мене не запрацював, проте реалізація його виглядає доволі простою (метод має знаходитись в класі, що створить Spring-контекст, його ім'я задане в методі getServletConfigClasses() ):
1 2 3 4 | @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } |
Для другого методу потрібно всі статичні ресурси покласти в одну кореневу папку, яку можна назвати, наприклад resources. Всередині цієї папки для зручності можна створити дерево каталогів, яке буде відображати ресурси, які там знаходяться:
--- resources
--- images
--- style
--- html
--- js
Потім в методі addResourceHandlers(ResourceHandlerRegistry registry) підвязуємо цю директорію до шаблону веб-адреси:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | package com.musicbox.springmvcproject.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.InternalResourceViewResolver; @Configuration // Class is expected to contain details on beans // that are to be created in the spring application context. @EnableWebMvc // in web.xml: <mvc:annotation-driven> @ComponentScan(basePackages="com.musicbox") // Enable automatic component scanning public class SpringAppConfig extends WebMvcConfigurerAdapter { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true); return resolver; } // Handle static requests @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**") .addResourceLocations("/resources/") .setCachePeriod(31556926); } } |
Тоді звертатися, наприклад, до зображення, можна буде наступним чином (див. малюнок - файл index.jsp):
1 2 3 4 5 6 7 8 | <!DOCTYPE html> <html> <body background="resources/images/background-gramophone.jpg"> <h1>Hello world!</h1> </body> </html> |
Останнім прикладом я аж ніяк не закликаю вас використовувати css інтегровані в html код. Ні.
В даному випадку, дерево каталогів має такий вигляд:
Зверніть увагу, що на відміну від випадку, коли програмуєте без використання фреймворку Spring, то шлях в:
<body background="resources/images/background-gramophone.jpg">
вказується відносний - відносно файлу, з якого проводиться виклик, тобто відносно index.jsp. І цей фрагмент мав би вигляд:
<body background="../../resources/images/background-gramophone.jpg">
Також зверніть увагу на наявність та відсутність слешів на початку шляху (в методі
addResourceHandlers(ResourceHandlerRegistry registry) та в файлі index.jsp) - це може бути джерелом помилок.
Також наостанок зауважу, що для додавання до поточного jsp іншого jsp/html в мене запрацював варіант з директивою include (include directive):
1 | <%@ include file="/resources/html/header_menu.html" %>
|
І не запрацював варіант із подією include (include action):
1 | <jsp:include page="/resources/html/header_menu.html" flush="true" /> |
Можна почитати:
fruzenshtein.com
docs.spring.io
docs.spring.io
mkyong.com
mytechnotes.biz
baeldung.com
kielczewski.eu
spring.io/blog
java-tips.org
Немає коментарів:
Дописати коментар