无法在Spring Boot中找到HTML页面。

4

我正在使用Spring Boot和Angular前端。有时候我想直接从一个服务中重定向。我们只使用.html,.css和脚本文件(没有.jsp)。

这是我尝试重定向到savepassword的代码:

return "static/pages/savepassword.html";

所以第一个问题是如何在这种情况下正确重定向?

接下来,Spring找不到我的html文件。我有这个结构:

enter image description here

我读到Spring应该自动在“static”中找到所有静态文件,但它没有。所以我尝试配置我的ViewControllerRegistry和RessourceControllerRegistry。

@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        super.addResourceHandlers(registry);
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
//      registry.addResourceHandler("/stylesheets/**").addResourceLocations("/stylesheets/");
//      registry.addResourceHandler("/scripts/**").addResourceLocations("/scripts/");
//      registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        super.addViewControllers(registry);
        registry.addViewController("/savePassword").setViewName("static/pages/savePassword.html");
        registry.addViewController("/login").setViewName("static/pages/login.html");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
    }

当我直接调用“static/pages/login.html”时,它可以正常工作。但是当我想要调用“/login”时,系统显示404错误。 第二个问题:我需要配置什么,不需要配置什么?
更新1:Spring Security
http
            .authorizeRequests().antMatchers("/login", "/logout", "/user/**").permitAll()
            .anyRequest().authenticated()
        .and()
            .exceptionHandling()
            .accessDeniedHandler(new CustomAccessDeniedHandler())
            .authenticationEntryPoint(new CustomAuthenticationEntryPoint())
        .and()
            .requiresChannel()
            .anyRequest().requiresSecure()
        .and()
            .csrf()
            .disable()
            //.csrfTokenRepository(csrfTokenRepository())
            .addFilterBefore(new MDCFilter(), ExceptionTranslationFilter.class)
            // .addFilterBefore(new CorsFilter(),// ChannelProcessingFilter.class)
            //.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
            .formLogin()
            .successHandler(new CustomSuccessAuthenticationHandler())
            .failureHandler(new CustomFailureHandler())
            .loginPage("/login").permitAll();
更新-2: 我更新了我的结构,但是仍然无法将/login重定向到自定义登录页面。 enter image description here 更新-3: 我查看了Bob Shields的第二条评论:https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot 我按照以下步骤进行操作:
@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        super.addResourceHandlers(registry);
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        super.addViewControllers(registry);
        registry.addViewController("/savepassword").setViewName("savepassword.html");
        registry.addViewController("/login").setViewName("login.html");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
    }

我将 .html 设置为后缀名,因为否则 /login 将会导致递归问题。有了这个配置,我可以输入 /login,然后调用 /templates/login.html(保存密码同理)。

现在,我想知道如何在 html 中包含我的 css/js

<link rel="stylesheet" type="text/css" href="..resources/stylesheets/bootstrap.min.css" />
    <script src="..resources/scripts/angular.min.js"></script>
    <script src="..resources/scripts/login.js"></script>

这个不起作用......但我可以直接通过/scripts/login.js调用我的脚本。


你能试试/login.html吗? - Darshan Mehta
不行,因为默认的Spring Security页面会出现。通常情况下,我们自定义的login.html(static/pages/login.html)应该显示出来。我更新了我的答案,这样你就可以看到Spring Security配置了。我认为ViewControllerRegistry会将login解析为static/pages/login.html,并采用这个登录页面。 - AndreasGloeckner
我是否需要将静态文件夹放在src/main/resource而不是放在webapp中? - AndreasGloeckner
你可以尝试将一个页面直接放在webapp文件夹下,并使用/login.html进行引用吗? - Darshan Mehta
我已经停用了Spring Security,但是当我直接将HTML文件放在“资源”中时无法访问。 - AndreasGloeckner
2个回答

3
在我看来,最好将*.HTML文件与所有静态CSS FONTS等放在资源文件夹中,就像下面的图片一样。在webapp中,您只能有一个WEB-INF文件夹。
我正在使用这种结构,并且我没有找到任何类css或htmls的问题,我也不会在java中使用结尾的扩展名("static/pages/login.html"之类的)。如果我想访问html,我会像"user/someHtml"这样去访问,如果它在用户文件夹中。
我知道这个答案可能不完全是您要寻找的,但它可能在某些方面对您有所帮助。

enter image description here

编辑: 现在是:

   @Override
   public void addViewControllers(ViewControllerRegistry registry) {
       super.addViewControllers(registry);
       registry.addViewController("/savePassword").setViewName("static/pages/savePassword.html");
       registry.addViewController("/login").setViewName("static/pages/login.html");
       registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}

假设您有一个控制器:
@Controller
@RequestMapping("/myController")
public class MyController{
...


@RequestMapping(value = "/login")
public String login(Model model) {
     // Your code ....

    return "login"; //<- this is your login.html if it is directly in resource/templates folder
}
    @RequestMapping(value = "/savePassword")
public String savePassword(Model model) {
     // Your code ....

    return "savePassword"; //<- this is your savePassword.html if it is directly in resource/templates folder
} 
.....
}

现在您的addViewController应该是这样的:
   @Override
      public void addViewControllers(ViewControllerRegistry registry) {
          super.addViewControllers(registry);
          registry.addViewController("/savePassword").setViewName("forward:/myController/savePassword");
       registry.addViewController("/login").setViewName("forward:/myController/login");
       registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}

在你的addViewController中,你试图访问一个控制器而不是HTML,你将通过从方法addViewControllers访问的CONTROLLER来访问你的HTML。
更新:
如果你将CSS放入资源的静态文件夹中,例如:

enter image description here

您可以这样简单地访问它们:
<link rel="stylesheet" th:href="@{/css/bootstrap-datetimepicker.min.css}" />

希望这可以帮到你!

首先,谢谢你 ;) 是的,我像这样改变了我的结构,现在(+1),但是还有两个问题:如何重定向和设置ViewController。 - AndreasGloeckner
我想你需要扩展WebMvcConfigurerAdapter。例如,当您尝试在浏览器中访问应用程序时,如http://localhost:8080/,您将被重定向到“user/showSomething”。 @Override public void addViewControllers( ViewControllerRegistry registry ) { registry.addViewController( "/" ).setViewName("forward:/user/showSomething" ); registry.setOrder( Ordered.HIGHEST_PRECEDENCE ); super.addViewControllers( registry ); }PS:您可能会遗漏“forward”,就像我的例子一样。希望这可以帮助您。 - Lazar Lazarov
它就是不起作用...无法访问任何HTML...即使没有Spring安全性,也没有ViewControllerRegistry/ ResourceHandlerRegistry。 - AndreasGloeckner
谢谢,我用的方法跟你有点不一样。现在我在包含CSS和JS方面遇到了问题...(见更新3) - AndreasGloeckner
你试过JHipster了吗?看看它,它可能是你所需要的一切。 - Sanjay Rawat
显示剩余2条评论

3

好的,现在我完全理解了。我会尽可能详细地说明。

我的最终结构

structure

1. 静态资源

Spring有一些默认配置,可以让您将静态资源放置在其中,而无需进行配置。您需要在src/main/resources中创建这些文件夹

  • /META-INF/resources/
  • resources(是的,src/main/resources中有一个额外的resources文件夹)
  • static
  • public

请参阅Spring文档。有关示例,请查看Bob Shields的第二条评论:

在创建了一堆“findme.txt”文件之后,每个文件都有不同的“source-relative”路径字符串,我发现可以使用“http://host/findme.txt”获取以下位置:

src/main/resources/public/findme.txt

src/main/resources/static/findme.txt

src/main/resources/resources/findme.txt-(是的,resources ^ 2!)

src/main/resources/findme.txt-未找到!

我将我的文件夹“scripts”和“stylesheets”放在静态文件夹中。当我想要在html中包含这些文件夹中的文件时,源代码看起来像src="scripts/file.js",因为在static中的文件和文件夹是直接根据host/scripts/file.js找到的。

对我来说不需要ResourceHandlerRegistry!

2. 视图控制器

我想将我的login.html路由到/login,savepassword.html到/savepassword,将我的index.html路由到/。这是我所做的:

registry.addViewController("/savepassword").setViewName("savepassword.html");
registry.addViewController("/login").setViewName("login.html");
registry.addViewController("/").setViewName("loggedin/index.html");

我将 *.html 设置为了文件后缀,否则会出现问题,Spring 无法区分/login 和login(.html)。 你可以看到,我将 index.html 放在了一个名为 “loggedin” 的不同文件夹中。这个文件夹位于我的 public 文件夹下(由 Spring 发现,见第一点)。为什么这样做呢?请参考第三点。 3. Spring 安全
.authorizeRequests().antMatchers("/stylesheets/**", "/scripts/**","/login", "/user/**").permitAll()
...omitted further configuration...
.loginPage("/login").permitAll();

首先,我希望用户在访问其他网站之前必须始终登录。因此,登录页面的所有资源都必须可用。

以下代码使stylesheets和scripts中的每个文件都可以访问。请记住,stylesheets和scripts文件夹位于static中。由于自定义登录页面,我必须设置“/login”。老实说,我以为.loginPage("/login").permitAll();将授予访问权限,但实际上并没有。如果没有它,Spring会尝试访问“/login”,但由于没有权限而无法访问,然后自动重定向到登录=> ERR_TOO_MANDY_REDIRECTS。“/user/**”仅供一些服务使用,所有用户均可使用。

正如您所看到的,我不允许访问"loggedin"文件夹,因此只有已登录的访问者才能进入其中的文件 ;)

4.重定向

我只是标记了整个控制器@RequestController,它实现了@ResponseBody。当我返回一个字符串,例如return "redirect:/savepassword";时,Spring会将其设置为ResponseBody,并将其解释为字符串/JSON(?)。

我必须将控制器标记为@Controller,并将@ResponseBody设置为每个必须返回JSON或类似内容的服务。我的服务只被标记为@RequestMapping和method = RequestMethod.GET,最后我返回类似return "redirect:/savepassword";的字符串。这将使Spring重定向到/savepassword,它实际上位于src/main/resources/public/savepassword.html中。

最后,它可以工作了,但找出Spring如何提供文件确实很难。我希望它能帮助其他人 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接