【问题标题】:Spring Boot with AngularJS html5ModeSpring Boot 与 AngularJS html5Mode
【发布时间】:2014-09-10 08:12:34
【问题描述】:

我使用 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);

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

【问题讨论】:

  • 我认为那里没有足够的信息来了解您做了什么,以及为什么它不起作用。

标签: html angularjs angular spring spring-boot


【解决方案1】:

使用此控制器将 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 仅转发未在任何其他 Controller 或 RestController 中定义的路径。这意味着如果您已经拥有:

@RestController
public class OffersController {

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

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

【讨论】:

  • 值“说”中的正则表达式是什么?
  • 匹配所有没有后缀的东西(所以不是静态资源)
  • 与其他选项相比,此选项的优点在于此选项保留了来自安全控制器的 /login 等路由。
  • 这个解决方案对我有帮助。
  • 为什么正则表达式有 2 个左大括号但只有 1 个右大括号?
【解决方案2】:

1-首先你创建一个新的控制器然后复制粘贴下面的代码

@Controller
public class viewController {

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

}

3- 从 Angular 应用程序中删除以下 2 个项目

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

2- 在 Angular 应用程序中,您必须将 $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>

对我来说很好用

【讨论】:

    【解决方案3】:

    我终于让我的 Angular 5 应用程序在带有或不带有 spring-boot-starter-tomcat 和 provided(嵌入式)的 Spring Boot 中运行!

    /**
     * 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");
        }
    }
    

    【讨论】:

    • 你确定这行得通,@RestController 如何返回视图?
    【解决方案4】:

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

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

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

    Spring boot and custom 404 error page

    【讨论】:

    • 它可以工作,但响应状态码将是 404,这不太好。我将使用它作为旁路。谢谢
    【解决方案5】:

    您可以通过提供自定义 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;
            }
        };
    }
    

    【讨论】:

      【解决方案6】:

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

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

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

      【讨论】:

        【解决方案7】:

        对以前的代码进行小幅调整,对我有用。

        // 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;
                        }
                    });
        }
        

        }

        【讨论】:

          【解决方案8】:

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

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

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

          【讨论】:

          • 您能详细说明这是如何工作的吗?对我来说,它只返回字符串“index”!我的 index.html 在资源/静态/应用下
          • html5mode 的目的是避免使用# 前缀。您将其替换为 app 前缀,那么值是多少。最好只使用基于哈希的路由策略。
          【解决方案9】:

          我有同样的问题。据我所知,在html5模式下,angularjs不解析hash而是输入url或者url添加throughpushState。

          问题是 PathResourceResolver 映射目录而不是文件。因为它打算从目录中提供请求的文件,而不是重写 url。对于应用程序,这意味着,如果您刷新浏览器窗口或输入像http://example.com/mystate 这样的网址,它会从服务器查询“/mystate”。如果 spring 不知道 url,它们会返回 404。其中一种解决方案是将每个可能的状态映射到 index.html,例如 here(source,顺便说一句,看看 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;
                              }
                          });
              }
          }
          

          【讨论】:

          • 我无法让它与 index.html 中包含的其他静态资源(即 JS 和 CSS 资源)一起使用。例如,我的静态文件夹中有另一个 css 文件,我在 index.html 文件的 head 部分中链接到它。当我在 Chrome 开发工具中查看该文件时,它的内容是 index.html。
          • 我最终手动将角度路由映射到特定控制器,该控制器根据您的链接源转发到 index.html。它工作正常,清晰易懂:)
          • @SébastienTromp 如何手动将路由映射到特定控制器?我是弹簧靴的新手。我的要求是,当我在浏览器中点击 URL 时,它应该在浏览器中加载特定的角度组件。
          猜你喜欢
          • 2015-08-21
          • 2015-02-16
          • 2017-01-12
          • 1970-01-01
          • 2013-11-06
          • 2014-12-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多