17

I start my web application with spring boot. It use a simple main class to start an embedded tomcat server:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

I want to configure the server in the way that he can handle angularjs html5mode that will be activated with

$locationProvider.html5Mode(true);

Relevant postings from other users shows that you need to redirect to the root. the html5 mode remove the hashbag from the url. If you refresh the page the server doesnt find the page cause he do not handle the hash. see: AngularJS - Why when changing url address $routeProvider doesn't seem to work and I get a 404 error

4

9 回答 9

26

使用此控制器将 URI 转发到 index.html 以保留 AngularJS 路由。来源https://spring.io/blog/2015/05/13/modularizing-the-client-angular-js-and-spring-security-part-vii

@Controller
public class ForwardController {

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

Controller在此解决方案中,ForwardController 仅转发未在任何其他nor中定义的路径RestController。这意味着如果您已经拥有:

@RestController
public class OffersController {

    @RequestMapping(value = "api/offers")
    public Page<OfferDTO> getOffers(@RequestParam("page") int page) {
        return offerService.findPaginated(page, 10);
    }
} 

两个控制器都将正常工作 -@RequestMapping(value = "api/offers")之前检查过@RequestMapping(value = "/**/{[path:[^\\.]*}")

于 2017-06-30T16:15:43.987 回答
22

我有同样的问题。据我所知,在 html5 模式下,angularjs 不解析哈希,而是输入 url 或通过 pushState添加的 url 。

问题是 PathResourceResolver 映射目录而不是文件。因为它打算从目录中提供请求的文件,而不是重写 url。对于应用程序,这意味着,如果您刷新浏览器窗口或键入http://example.com/mystate之类的 url ,它会从服务器查询“/mystate”。如果 spring 不知道 url,它们会返回 404。其中一种解决方案是将每个可能的状态映射到 index.html,就像这里一样(来源,顺便说一句,看看 webjars - 太棒了!)。但在我的情况下,我可以安全地将“/**”映射到 index.html,因此我的解决方案是覆盖 PathResourceResolver#getResource:

@Configuration
@EnableConfigurationProperties({ ResourceProperties.class })
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private ResourceProperties resourceProperties = new ResourceProperties();

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        Integer cachePeriod = resourceProperties.getCachePeriod();

        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/")
                .setCachePeriod(cachePeriod);

        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/static/index.html")
                .setCachePeriod(cachePeriod).resourceChain(true)
                .addResolver(new PathResourceResolver() {
                    @Override
                    protected Resource getResource(String resourcePath,
                            Resource location) throws IOException {
                        return location.exists() && location.isReadable() ? location
                                : null;
                    }
                });
    }
}
于 2014-09-27T10:03:45.083 回答
11

我找到了一个我可以忍受的解决方案。

@Controller
public class ViewController {

    @RequestMapping("/")
    public String index() {
        return "index";
    }

    @RequestMapping("/app/**")
    public String app() {
        return "index";
    }
}

angularjs 应用程序必须在子域应用程序下。如果您不希望这样,您可以创建一个像 app.subdomain.com 这样的子域来映射到您的子域应用程序。使用此构造,您不会与 webjars、statis 内容等发生冲突。

于 2014-09-29T12:43:54.747 回答
4

对对我有用的先前代码的小调整。

// Running with Spring Boot v1.3.0.RELEASE, Spring v4.2.3.RELEASE
@Configuration
@EnableConfigurationProperties({ ResourceProperties.class })
public class WebMvcConfig extends WebMvcConfigurerAdapter {

@Autowired
private ResourceProperties resourceProperties = new ResourceProperties();

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    Integer cachePeriod = resourceProperties.getCachePeriod();

    final String[] staticLocations = resourceProperties.getStaticLocations();
    final String[] indexLocations  = new String[staticLocations.length];
    for (int i = 0; i < staticLocations.length; i++) {
        indexLocations[i] = staticLocations[i] + "index.html";
    }
    registry.addResourceHandler(
            "/**/*.css",
            "/**/*.html",
            "/**/*.js",
            "/**/*.json",
            "/**/*.bmp",
            "/**/*.jpeg",
            "/**/*.jpg",
            "/**/*.png",
            "/**/*.ttf",
            "/**/*.eot",
            "/**/*.svg",
            "/**/*.woff",
            "/**/*.woff2"
            )
            .addResourceLocations(staticLocations)
            .setCachePeriod(cachePeriod);

    registry.addResourceHandler("/**")
            .addResourceLocations(indexLocations)
            .setCachePeriod(cachePeriod)
            .resourceChain(true)
            .addResolver(new PathResourceResolver() {
                @Override
                protected Resource getResource(String resourcePath,
                        Resource location) throws IOException {
                    return location.exists() && location.isReadable() ? location
                            : null;
                }
            });
}

}

于 2016-04-06T09:32:02.687 回答
4

您可以通过提供自定义 ErrorViewResolver 将所有未找到的资源转发到您的主页。您需要做的就是将其添加到您的 @Configuration 类中:

@Bean
ErrorViewResolver supportPathBasedLocationStrategyWithoutHashes() {
    return new ErrorViewResolver() {
        @Override
        public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
            return status == HttpStatus.NOT_FOUND
                    ? new ModelAndView("index.html", Collections.<String, Object>emptyMap(), HttpStatus.OK)
                    : null;
        }
    };
}
于 2016-10-27T09:45:03.483 回答
3

我终于让我的 Angular 5 应用程序与 Spring Boot 一起工作,无论是否(嵌入)或不spring-boot-starter-tomcat使用!provided

/**
 * Needed for html5mode (PathLocationStrategy in Angular). Every path except api/* and resources (css, html, js, woff, etc..)
 * should be redirect to index.html and then should angular managed routes (which could be correct or non existing).
 */
@RestController
@RequestMapping
public class ForwardController {

    @GetMapping(value = "/**/{[path:[^\\.]*}")
    public ModelAndView forward() {
        return new ModelAndView("/index.html");
    }
}
于 2018-01-19T10:15:01.403 回答
0

我刚刚遇到了类似的问题,我想配置资源,同时我想启用 AngularJS Html5 模式。

在我的情况下,我的静态文件是从/public路由提供的,因此我在索引操作上使用了以下请求映射,并且一切正常。

@RequestMapping(value = {"", "/", "/{[path:(?!public).*}/**"}, method = GET)
public String indexAction() {
    return "index";
}
于 2016-08-07T09:03:06.203 回答
0

1-首先创建新控制器,然后复制并粘贴下面的简单代码

@Controller
public class viewController {

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

}

3-从角度应用程序中删除下面的 2 个项目

$locationProvider.hashPrefix('!');
$urlRouterProvider.otherwise("/");

2-在角度应用程序中,您必须添加$locationProvider.html5Mode(true);到应用程序路线

3- 不要忘记在 index.html 文件中的任何 http 请求之前放置基本标记

<head>
<base href="/"> /* Or whatever your base path is */

//call every http request for style and other 
...
</head>

这对我来说很好

于 2018-04-23T10:26:07.930 回答
0

我在使用角度 Html5Mode 时遇到了同样的问题。对我有用的解决方案是在 web.xml 中为 404 配置错误页面,在我的情况下为我的索引视图分配路径“/”。

<error-page>
    <error-code>404</error-code>
    <location>/</location>
</error-page>

同样,您可以尝试在spring boot中配置错误页面。作为参考,您可以查看此链接。

Spring Boot 和自定义 404 错误页面

于 2017-02-18T18:55:22.803 回答