Spring 引导 2.6 和 Angular 在静态资源中
Spring Boot 2.6 and Angular in static Resources
我的问题与 问题非常相似,该问题已被提出并回答但不是 100% 最新的。
我们使用 Chris Gaskill 的解决方案有一段时间了,它非常适合我们,因为我们想重定向包含多个路径段(即 /foo/bar
)的请求
从Spring Boot 2.4开始,Boot使用PathPatternParser
代替AntPathMatcher
,其中前者不再支持**
在一个模式的开始(see docs).
是否有其他解决方案可以实现相同的行为?您使用什么将所有与其他任何内容都不匹配的请求重定向到 Angular 应用程序的 index.html
?
这是转发请求的控制器代码。
@Controller
class SpaRoutingController {
@GetMapping("/**/{path:[^\.]*}", headers = "X-Requested-With!=XMLHttpRequest")
fun forward(): String? {
return "forward:/"
}
}
您是否尝试过在 Angular 端实现重定向?在我的应用程序中,我已经解决了这个问题:
const routes: Routes = [
{path: '', redirectTo: '/myProjects', pathMatch: 'full'},
//...
{path: '**', redirectTo: ''}
}
@NgModule({
imports: [
RouterModule.forRoot(routes, {useHash: true})
],
exports: [
RouterModule
],
declarations: []
})
export class MyRoutingModule {
}
PathPatternParser 相当于之前的 AntPathMatcher /**
将是:
@GetMapping("/{*path}")
根据spring documentation:
/resources/{*path} — matches all files underneath the /resources/, as well as /resources, and captures their relative path in a variable named "path"; /resources/image.png will match with "path" → "/image.png", and /resources/css/spring.css will match with "path" → "/css/spring.css"
编辑 - 与循环有关:
在您的情况下,为了避免由于使用 forward:/
而引起的循环,如果您只关心加载 angular 页面,只需将 forward
替换为您的实际内容index.html
如果由于某种原因你需要转发以便在返回响应之前展平uri,你可以通过各种方式解决它
您可以 forward:/index.html
@GetMapping("/index.html") 优先于通配符或使用 @PathVariable
来区分行为并避免永恒的前向循环
@Controller
class SpaRoutingController {
@GetMapping("/{*path}")
fun forward(@PathVariable(value="path", required=false) path: String): String? {
if ("/".equals(path)) { // may need to handle additional cases
return ""; // or your index.html
}
return "forward:/";
}
}
我宁愿选择配置 WebMvcConfigurer
的解决方案。请参阅下面的代码。
Maven 配置
Maven 配置指示 frontend-maven-plugin
构建 angular 并将构建的内容复制到 target/static
目录中,以便它在最终 WAR 和构建的 JAR 中可用。然后我另外配置一个 WebMvcConfigurer
以在 JAR / WAR 的静态目录中查找资源,如果找到 - 将其发送给客户端,否则重定向到 index.html.
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>${maven-clean-plugin.version}</version>
<configuration>
<filesets>
<fileset>
<directory>src/main/webapp</directory>
<includes>
<include>*.js</include>
<include>*.txt</include>
<include>*.html</include>
<include>*.css</include>
<include>*.map</include>
<include>*.json</include>
<include>*.ico</include>
<followSymlinks>false</followSymlinks>
</includes>
</fileset>
<fileset>
<directory>src/main/webapp/assets</directory>
<includes>
<include>**</include>
<followSymlinks>false</followSymlinks>
</includes>
</fileset>
</filesets>
</configuration>
<executions>
<execution>
<id>auto-clean</id>
<phase>initialize</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/classes/static</outputDirectory>
<includeEmptyDirs>true</includeEmptyDirs>
<resources>
<resource>
<directory>${basedir}/src/main/${angular.project.name}/dist/${angular.project.name}</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.8.0</version>
<configuration>
<workingDirectory>src/main/${angular.project.name}</workingDirectory>
</configuration>
<executions>
<execution>
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<nodeVersion>v14.16.1</nodeVersion>
</configuration>
</execution>
<execution>
<id>npm build angular</id>
<goals>
<goal>npm</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<arguments>run build:prod</arguments>
</configuration>
</execution>
</executions>
</plugin>
MVC 配置
这里你尝试查找静态目录中是否存在资源,如果不存在则将其重定向到index.html。
您可能需要根据您的要求更改源位置。
@Configuration
public class ApplicationWebMvcConfiguration 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);
if (requestedResource.exists() && requestedResource.isReadable()) {
return requestedResource;
}
return new ClassPathResource("/static/index.html");
}
});
}
}
在使用Angular时不能谈论index.html
等页面。你有什么路线!
所以当你重定向时,你应该做的是路由而不是页面。
ModelAndView forward() {
return new ModelAndView("redirect:/");
}
PS : 如果 /
是你的默认路由。
您是否尝试过使用 Servlet 过滤器来处理 Spring Boot 未处理的端点?来自 Baeldung 的这篇文章解释了一个解决方案,您可以检查您的用例。
我的问题与
我们使用 Chris Gaskill 的解决方案有一段时间了,它非常适合我们,因为我们想重定向包含多个路径段(即 /foo/bar
)的请求
从Spring Boot 2.4开始,Boot使用PathPatternParser
代替AntPathMatcher
,其中前者不再支持**
在一个模式的开始(see docs).
是否有其他解决方案可以实现相同的行为?您使用什么将所有与其他任何内容都不匹配的请求重定向到 Angular 应用程序的 index.html
?
这是转发请求的控制器代码。
@Controller
class SpaRoutingController {
@GetMapping("/**/{path:[^\.]*}", headers = "X-Requested-With!=XMLHttpRequest")
fun forward(): String? {
return "forward:/"
}
}
您是否尝试过在 Angular 端实现重定向?在我的应用程序中,我已经解决了这个问题:
const routes: Routes = [
{path: '', redirectTo: '/myProjects', pathMatch: 'full'},
//...
{path: '**', redirectTo: ''}
}
@NgModule({
imports: [
RouterModule.forRoot(routes, {useHash: true})
],
exports: [
RouterModule
],
declarations: []
})
export class MyRoutingModule {
}
PathPatternParser 相当于之前的 AntPathMatcher /**
将是:
@GetMapping("/{*path}")
根据spring documentation:
/resources/{*path} — matches all files underneath the /resources/, as well as /resources, and captures their relative path in a variable named "path"; /resources/image.png will match with "path" → "/image.png", and /resources/css/spring.css will match with "path" → "/css/spring.css"
编辑 - 与循环有关:
在您的情况下,为了避免由于使用 forward:/
而引起的循环,如果您只关心加载 angular 页面,只需将 forward
替换为您的实际内容index.html
如果由于某种原因你需要转发以便在返回响应之前展平uri,你可以通过各种方式解决它
您可以 forward:/index.html
@GetMapping("/index.html") 优先于通配符或使用 @PathVariable
来区分行为并避免永恒的前向循环
@Controller
class SpaRoutingController {
@GetMapping("/{*path}")
fun forward(@PathVariable(value="path", required=false) path: String): String? {
if ("/".equals(path)) { // may need to handle additional cases
return ""; // or your index.html
}
return "forward:/";
}
}
我宁愿选择配置 WebMvcConfigurer
的解决方案。请参阅下面的代码。
Maven 配置
Maven 配置指示 frontend-maven-plugin
构建 angular 并将构建的内容复制到 target/static
目录中,以便它在最终 WAR 和构建的 JAR 中可用。然后我另外配置一个 WebMvcConfigurer
以在 JAR / WAR 的静态目录中查找资源,如果找到 - 将其发送给客户端,否则重定向到 index.html.
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>${maven-clean-plugin.version}</version>
<configuration>
<filesets>
<fileset>
<directory>src/main/webapp</directory>
<includes>
<include>*.js</include>
<include>*.txt</include>
<include>*.html</include>
<include>*.css</include>
<include>*.map</include>
<include>*.json</include>
<include>*.ico</include>
<followSymlinks>false</followSymlinks>
</includes>
</fileset>
<fileset>
<directory>src/main/webapp/assets</directory>
<includes>
<include>**</include>
<followSymlinks>false</followSymlinks>
</includes>
</fileset>
</filesets>
</configuration>
<executions>
<execution>
<id>auto-clean</id>
<phase>initialize</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/classes/static</outputDirectory>
<includeEmptyDirs>true</includeEmptyDirs>
<resources>
<resource>
<directory>${basedir}/src/main/${angular.project.name}/dist/${angular.project.name}</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.8.0</version>
<configuration>
<workingDirectory>src/main/${angular.project.name}</workingDirectory>
</configuration>
<executions>
<execution>
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<nodeVersion>v14.16.1</nodeVersion>
</configuration>
</execution>
<execution>
<id>npm build angular</id>
<goals>
<goal>npm</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<arguments>run build:prod</arguments>
</configuration>
</execution>
</executions>
</plugin>
MVC 配置
这里你尝试查找静态目录中是否存在资源,如果不存在则将其重定向到index.html。
您可能需要根据您的要求更改源位置。
@Configuration
public class ApplicationWebMvcConfiguration 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);
if (requestedResource.exists() && requestedResource.isReadable()) {
return requestedResource;
}
return new ClassPathResource("/static/index.html");
}
});
}
}
在使用Angular时不能谈论index.html
等页面。你有什么路线!
所以当你重定向时,你应该做的是路由而不是页面。
ModelAndView forward() {
return new ModelAndView("redirect:/");
}
PS : 如果 /
是你的默认路由。
您是否尝试过使用 Servlet 过滤器来处理 Spring Boot 未处理的端点?来自 Baeldung 的这篇文章解释了一个解决方案,您可以检查您的用例。