Springboot / Angular2 – Как обрабатывать URL-адреса HTML5?

Я считаю, что это простой вопрос, но я не мог найти ответа или хотя бы использовать правильные термины в поиске.

Я настраиваю Angular2 и Springboot вместе. По умолчанию Angular будет использовать пути, такие как localhost:8080\dashboard и localhost:8080\dashboard\detail .

Я бы хотел, чтобы избежать использования пути как hash, если это возможно. Как указано в Угловой документации :

Функция обеспечения маршрутизатора router устанавливает свойство LocationStrategy в PathLocationStrategy, что делает его страtagsей по умолчанию. Мы можем переключиться на HashLocationStrategy с переопределением во время процесса начальной загрузки, если мы этого захотим.

А потом…

Почти все проекты Angular 2 должны использовать стиль HTML по умолчанию. Он создает URL-адреса, которые пользователям легче понять. И он сохраняет возможность выполнения рендеринга на стороне сервера позже.

Проблема в том, что когда я пытаюсь обратиться к localhost:8080\dashboard , Spring будет искать некоторое сопоставление controllerа этому пути, чего у него не будет.

 Whitelabel Error Page There was an unexpected error (type=Not Found, status=404). No message available 

Сначала я думал, что все мои службы будут находиться под localhost:8080\api и все мои статические под localhost:8080\app . Но как я могу сказать Spring игнорировать запросы к этому app ?

Есть ли лучшее решение с Angular2 или Boot?

У меня есть решение для вас, вы можете добавить ViewController для пересылки запросов на Angular от Spring загрузки.

 import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class ViewController { @RequestMapping({ "/bikes", "/milages", "/gallery", "/tracks", "/tracks/{id:\\w+}", "/location", "/about", "/tests","/tests/new","/tests/**","/questions","/answers" }) public String index() { return "forward:/index.html"; } } 

здесь я перенаправил все мои угловые2 («/ bikes», «/ milages», «/ gallery», «/ tracks», «/ tracks / {id: \ w +}», «/ location», «/ about», «/ tests», «/ tests / new», «/ tests / **», «/ questions», «/ answers») к моему SPA. Вы можете сделать то же самое для своего предлога, и вы также можете перенаправить свою страницу ошибок 404 на индексную страницу в качестве следующего шага. Наслаждайтесь!

В моих приложениях Spring Boot (версии 1 и 2) мои статические ресурсы находятся в одном месте:

 src/main/resources/static 

static – папка, распознанная Spring Boot для загрузки статических ресурсов.

Тогда идея состоит в настройке конфигурации Spring MVC.
Более простой способ – использовать конфигурацию Spring Java.

Я WebMvcConfigurer для переопределения addResourceHandlers() . Я добавляю в один ResourceHandler к текущему ResourceHandlerRegistry .
Обработчик сопоставляется с каждым запросом, и я указываю classpath:/static/ как значение местоположения ресурса (вы можете, конечно, добавить другие, если потребуется).
Я добавляю собственный анонимный class PathResourceResolver для переопределения getResource(String resourcePath, Resource location) .
Правило для возврата ресурса следующее: если ресурс существует и доступен для чтения (так что это файл), я возвращаю его. В противном случае по умолчанию я возвращаю страницу index.html . Каково ожидаемое поведение для обработки URL-адресов HTML 5.

Spring Boot 1.X Приложение:

Расширение org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter – путь.
Класс является адаптером интерфейса WebMvcConfigurer с пустыми методами, позволяющими подclassам переопределять только те методы, которые им интересны.

Вот полный код:

 import java.io.IOException; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.resource.PathResourceResolver; @Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**/*") .addResourceLocations("classpath:/static/") .resourceChain(true) .addResolver(new PathResourceResolver() { @Override protected Resource getResource(String resourcePath, Resource location) throws IOException { Resource requestedResource = location.createRelative(resourcePath); return requestedResource.exists() && requestedResource.isReadable() ? requestedResource : new ClassPathResource("/static/index.html"); } }); } } к import java.io.IOException; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.resource.PathResourceResolver; @Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**/*") .addResourceLocations("classpath:/static/") .resourceChain(true) .addResolver(new PathResourceResolver() { @Override protected Resource getResource(String resourcePath, Resource location) throws IOException { Resource requestedResource = location.createRelative(resourcePath); return requestedResource.exists() && requestedResource.isReadable() ? requestedResource : new ClassPathResource("/static/index.html"); } }); } } 

Spring Boot 2.X Приложение:

org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter устарел.
Внедрение непосредственно WebMvcConfigurer – это сейчас, так как он по-прежнему является интерфейсом, но теперь он использует методы по умолчанию (что стало возможным благодаря базовой линии Java 8) и может быть реализовано напрямую без использования адаптера.

Вот полный код:

 import java.io.IOException; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.resource.PathResourceResolver; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**/*") .addResourceLocations("classpath:/static/") .resourceChain(true) .addResolver(new PathResourceResolver() { @Override protected Resource getResource(String resourcePath, Resource location) throws IOException { Resource requestedResource = location.createRelative(resourcePath); return requestedResource.exists() && requestedResource.isReadable() ? requestedResource : new ClassPathResource("/static/index.html"); } }); } } к import java.io.IOException; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.resource.PathResourceResolver; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**/*") .addResourceLocations("classpath:/static/") .resourceChain(true) .addResolver(new PathResourceResolver() { @Override protected Resource getResource(String resourcePath, Resource location) throws IOException { Resource requestedResource = location.createRelative(resourcePath); return requestedResource.exists() && requestedResource.isReadable() ? requestedResource : new ClassPathResource("/static/index.html"); } }); } } 

Вы можете перенаправить все не найденные ресурсы на свою основную страницу, предоставив пользовательский ErrorViewResolver. Все, что вам нужно сделать, это добавить это в свой class @Configuration:

 @Bean ErrorViewResolver supportPathBasedLocationStrategyWithoutHashes() { return new ErrorViewResolver() { @Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map model) { return status == HttpStatus.NOT_FOUND ? new ModelAndView("index.html", Collections.emptyMap(), HttpStatus.OK) : null; } }; } 

Вы можете перенаправить все, что не привязано к Angular, используя что-то вроде этого:

 @Controller public class ForwardController { @RequestMapping(value = "/**/{[path:[^\\.]*}") public String redirect() { // Forward to home page so that route is preserved. return "forward:/"; } } 

Источник: https://stackoverflow.com/a/44850886/3854385

Мой сервер загрузки Spring для углового также является шлюзовым сервером с API-вызовами /api чтобы не иметь страницу входа перед угловыми страницами, вы можете использовать что-то вроде.

 import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; /** * This sets up basic authentication for the microservice, it is here to prevent * massive screwups, many applications will require more secuity, some will require less */ @EnableOAuth2Sso @Configuration public class SecurityConfiguration extends WebSecurityConfigurerAdapter{ @Override public void configure(HttpSecurity http) throws Exception { http .logout().logoutSuccessUrl("/").and() .authorizeRequests() .antMatchers("/api/**").authenticated() .anyRequest().permitAll().and() .csrf() .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); } } 

Чтобы сделать его более простым, вы можете просто реализовать ErrorPageRegistrar напрямую.

 @Component public class ErrorPageConfig implements ErrorPageRegistrar { @Override public void registerErrorPages(ErrorPageRegistry registry) { registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/")); } } 

Это отправит запросы index.html.

 @Controller @RequestMapping("/") public class MainPageController { @ResponseStatus(HttpStatus.OK) @RequestMapping({ "/" }) public String forward() { return "forward:/"; } } 

Это три шага, которые вам нужно выполнить:

  1. Внесите свой собственный компонент TomcatEmbeddedServletContainerFactory и настройте RewriteValve

      import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; ... import org.apache.catalina.valves.rewrite.RewriteValve; ... @Bean TomcatEmbeddedServletContainerFactory servletContainerFactory() { TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory(); factory.setPort(8080); factory.addContextValves(new RewriteValve()); return factory; } 
  2. Добавьте файл rewrite.conf в каталог WEB-INF вашего приложения и укажите правила перезаписи. Вот пример содержимого rewrite.conf, который я использую в угловом приложении, чтобы воспользоваться функцией PathLocationStrategy (в основном я просто перенаправляю все на index.html, поскольку мы просто используем Spring boot для обслуживания статического веб-контента, иначе вам необходимо отфильтровать controllerы в правиле RewriteCond):

      RewriteCond %{REQUEST_URI} !^.*\.(bmp|css|gif|htc|html?|ico|jpe?g|js|pdf|png|swf|txt|xml|svg|eot|woff|woff2|ttf|map)$ RewriteRule ^(.*)$ /index.html [L] 
  3. Из ваших объявлений маршрутизации избавиться от useHash (или установить его в false):

      RouterModule.forRoot(routes) 

или

  RouterModule.forRoot(routes, {useHash: false}) 

пересылайте всю угловую маршрутизацию с помощью index.html. В том числе базовый href.

 import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class ViewController { @RequestMapping({ "jsa/customer","jsa/customer/{id}",}) public String index() { return "forward:/index.html"; } } 

В моем случае jsa является базовым href.

  • Просмотр не обновляется при изменении в Angular2
  • Angular2: 2 услуги в зависимости друг от друга
  • Динамически добавлять слушателя событий в Angular 2
  • Может ли ng-контент использоваться внутри ngFor?
  • Angular2 - как вызвать функцию компонента извне приложения
  • Angular2: как связывать для выбора нескольких
  • Как использовать * ngIf else в Angular?
  • Как получить элемент dom в угловом 2
  • Как заставить Angular2 связывать компонент в innerHTML
  • Местоположение и HashLocationStrategy перестали работать в бета-версии.16.
  • Угловое 2: получение RouteParams из родительского компонента
  • Interesting Posts
    Давайте будем гением компьютера.