使用AngularJS html5Mode进行Spring Boot

时间:2014-07-19 07:05:45

标签: html5 spring angularjs spring-boot

我使用spring boot启动我的Web应用程序。它使用一个简单的主类来启动嵌入式tomcat服务器:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {

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

}

我想以他能够处理将被激活的angularjs html5mode的方式配置服务器

$locationProvider.html5Mode(true);

其他用户的相关帖子显示您需要重定向到根目录。 html5模式从url中删除hashbag。如果刷新页面,服务器找不到页面导致他不处理哈希。见:AngularJS - Why when changing url address $routeProvider doesn't seem to work and I get a 404 error

9 个答案:

答案 0 :(得分:22)

我有同样的问题。据我所知,在html5模式下,angularjs不会解析哈希,但输入的网址或网址已添加through pushState

问题在于PathResourceResolver映射目录而不是文件。因为它打算从目录提供所请求的文件,但不是为了重写URL。对于应用程序,这意味着,如果您刷新浏览器窗口或输入http://example.com/mystate之类的网址,则会查询" / mystate"从服务器。如果spring不知道url,他们会返回404.其中一个解决方案是将每个可能的状态映射到index.html,例如heresource,顺便看看webjars - 它是' s大!)。但在我的情况下,我可以安全地映射" / **"到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;
                    }
                });
    }
}

答案 1 :(得分:21)

使用此控制器将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:/";
    }
} 

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

@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:[^\\.]*}")

答案 2 :(得分:10)

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

@Controller
public class ViewController {

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

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

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

答案 3 :(得分: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;
                }
            });
}

}

答案 4 :(得分: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;
        }
    };
}

答案 5 :(得分:3)

我终于让我的Angular 5应用程序使用或不使用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");
    }
}

答案 6 :(得分:0)

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

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

@RequestMapping(value = {"", "/", "/{[path:(?!public).*}/**"}, method = GET)
public String indexAction() {
    return "index";
}

答案 7 :(得分:0)

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

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

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

Spring boot and custom 404 error page

答案 8 :(得分:0)

1-首先你创建新的Controller然后复制并粘贴简单的代码

@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>

这对我来说很好用