【问题标题】:Spring Thymeleaf Bootstrap CSSSpring Thymeleaf 引导 CSS
【发布时间】:2018-05-06 12:59:26
【问题描述】:

我正在尝试将 Bootstrap CSS 与我的 Spring + Security + Thymeleaf Web 应用程序一起使用。 CSS 被我的自定义登录屏幕拾取,一切都很好 - 应用了所有样式。但是,当我出于某种原因从登录屏幕进入下一个屏幕时,我的 html 页面没有拾取 CSS 文件并且没有应用样式。有人可以帮忙吗?

以下是相关文件:

登录 html 文件(工作正常):

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="utf-8"></meta>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"></meta>
    <meta name="viewport" content="width=device-width, initial-scale=1"></meta>
    <meta name="description" content=""></meta>
    <meta name="author" content=""></meta>

    <title>motodoc hub Sign in</title>

    <!-- Bootstrap core CSS -->
    <link href="resources/css/bootstrap-3.3.2-dist/bootstrap.min.css" rel="stylesheet" />

    <!-- Custom styles for this template -->
    <link href="resources/css/signin.css" rel="stylesheet" />

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>

  <body>

    <div class="container">

        <p th:if="${loginError}">Wrong username or password</p>
      <form th:action="@{/login}" method="post" class="form-signin">
        <h2 class="form-signin-heading">Please sign in</h2>
        <label for="username" class="sr-only">Username</label>
        <input type="text" id="username" name="username" class="form-control" placeholder="Username" />
        <label for="password" class="sr-only">Password</label>
        <input type="password" id="password" name="password" class="form-control" placeholder="Password" />
        <!-- <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>  -->
        <input type="submit" value="Log in" class="btn btn-lg btn-primary btn-block" />
      </form>

    </div> <!-- /container -->


    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <script src="resources/js/ie10-viewport-bug-workaround.js"></script>
  </body>
</html>

登录控制器(再次 - 一切正常):

package com.motodoc.hub.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController {

    // Login form
    @RequestMapping("/login")
    public String login() {
        System.out.println("in here ....");
        return "login";
    }

    // Login form with error
    @RequestMapping("/login-error")
    public String loginError(Model model) {
        model.addAttribute("loginError", true);
        return "login";
    }
}

主页 html 文件(这是由于某种原因 CSS 未被“选中”的文件):

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>

    <meta charset="utf-8"></meta>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"></meta>
    <meta name="viewport" content="width=device-width, initial-scale=1"></meta>
    <meta name="description" content=""></meta>
    <meta name="author" content=""></meta>

    <!-- Bootstrap core CSSS -->
    <link href="resources/css/bootstrap-3.3.2-dist/bootstrap.min.css" rel="stylesheet" />

    <title>Home</title>
</head>
<body>
    <div th:include="templates/navbar :: navigationBar"></div>
    <br></br>
    <h1>Login success!</h1><br></br>

    <div>
    <table class="table table-striped">
    <caption th:text="#{user.table.caption}">Site Users</caption>
    <thead>
        <tr>
            <th scope="col" th:text="#{user.id.label}">Id</th>
            <th scope="col" th:text="#{user.firstname.label}">First Name</th>
            <th scope="col" th:text="#{user.lastname.label}">Last Name</th>
            <th scope="col" th:text="#{user.username.label}">Username</th>
        </tr>
    </thead>
    <tbody>
        <tr th:each="user : ${currentResults.content}">
            <td th:text="${user.id}">1</td>
            <td th:text="${user.firstName}">George</td>
            <td th:text="${user.lastName}">Washington</td>
            <td th:text="${user.username}">gwash</td>
        </tr>
    </tbody>
</table>
</div>



    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    <script src="resources/js/bootstrap-3.3.2-dist/bootstrap.min.js"></script>

</body>
</html>

家庭控制器类:

@Controller
public class HomeController {

    @Autowired
    private ISecurityUserService securityUserService;

    @RequestMapping("/home")
    public String redirect() {      
        return "redirect:/home/page/1";
    }

    // home
    @RequestMapping(value="/home/page/{pageNumber}", method = RequestMethod.GET)
    public String getUsers(
            @PathVariable("pageNumber") Integer pageNumber, 
            ModelMap model) {

        Page<Person> currentResults = securityUserService.findAll(pageNumber-1);

        model.addAttribute("currentResults", currentResults);

        //Pagination variables
        int startIndex = Math.max(1, pageNumber - 5);
        int endIndex = Math.min(startIndex + 10, currentResults.getTotalPages());

        model.addAttribute("url", "home");
        model.addAttribute("startIndex", startIndex);
        model.addAttribute("endIndex", endIndex);
        model.addAttribute("currentIndex", pageNumber);
        //model.addAttribute("users", users);

        return "home";
    }   
}

Spring 安全配置:

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

    @Override
    protected void configure( HttpSecurity http ) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/resources/**").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .permitAll()
            .defaultSuccessUrl("/home")
            .failureUrl("/login-error")
            .and()
        .logout()
            .invalidateHttpSession(true)
            .logoutUrl("/logout")
            .deleteCookies("JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE")
            .logoutSuccessUrl("/")
            .permitAll();
    }

    @Bean
    public CustomAuthenticationProviderImpl authenticationProvider() {
        return new CustomAuthenticationProviderImpl();
    }

    @Bean
    public BCryptPasswordEncoder encoder() {
        return new BCryptPasswordEncoder(10);
    }
}

应用上下文配置类:

@Configuration 
@ComponentScan(basePackages = {"com.motodoc.hub.*"})
@EnableWebMvc
@Import({SpringDataConfig.class, 
    ThymeleafConfig.class, 
    SecurityConfig.class, 
    ServiceBeans.class})
@ImportResource("classpath:trace-context.xml")
@PropertySource("classpath:spring.properties")
public class ApplicationContext extends WebMvcConfigurerAdapter {

    // Maps resources path to webapp/resources
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }

    // Only needed if we are using @Value and ${...} when referencing properties
    @Bean
    public static PropertySourcesPlaceholderConfigurer properties() {
        PropertySourcesPlaceholderConfigurer propertySources = new PropertySourcesPlaceholderConfigurer();
        Resource[] resources = new ClassPathResource[] { 
                new ClassPathResource("spring.properties") };
        propertySources.setLocations(resources);
        propertySources.setIgnoreUnresolvablePlaceholders(true);
        return propertySources;
    }

    // Provides internationalization of messages
    @Bean
    public ResourceBundleMessageSource messageSource() {
        ResourceBundleMessageSource source = new ResourceBundleMessageSource();
        source.setBasename("messages");
        return source;
    }
}

Thymeleaf 配置类:

@Configuration 
public class ThymeleafConfig {

    @Bean 
    public ServletContextTemplateResolver templateResolver() {
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode("HTML5");
        resolver.setOrder(1);
        return resolver;
    }

    @Bean 
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver());

        //add spring security dialect
        Set<IDialect> dialects = new HashSet<IDialect>();
        dialects.add(springSecurityDialect());
        engine.setAdditionalDialects(dialects);

        return engine;
    }

    @Bean 
    public ThymeleafViewResolver thymeleafViewResolver() {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(templateEngine());
        return resolver;
    }

    @Bean
    public SpringSecurityDialect springSecurityDialect() {
        return new SpringSecurityDialect();
    }
}

Webapp 项目目录结构:

【问题讨论】:

    标签: spring-mvc twitter-bootstrap-3 thymeleaf


    【解决方案1】:

    想通了......我的小学生错误......

    我的 home.html 文件中的以下链接没有解析到正确的位置:

    <link href="resources/css/bootstrap-3.3.2-dist/bootstrap.min.css" rel="stylesheet" />
    

    因此,我使用了上下文相关的 URL,如下所示:

    <link th:href="@{/resources/css/bootstrap-3.3.2-dist/bootstrap.min.css}" rel="stylesheet" />
    

    这成功了。

    【讨论】:

    • 谢谢你!我苦苦挣扎了好几个小时,试图找到解决这个导入问题的方法......使用带有 th:href 的链接有帮助,对我有用的路径是 "th:href="@{/css/bootstrap.min.css "。(不要忘记 "css" 之前的 '/')非常感谢!
    【解决方案2】:

    即使没有 Spring 表达式 @{},您的代码也应该可以工作。 只需包含 bootstrap 的 javascript 部分,其中包含下载 zip 文件。

    <link rel="stylesheet" href="/bootstrap-4.0.0/css/bootstrap.min.css" />
    <script src="/bootstrap-4.0.0/js/bootstrap.min.js"></script>
    

    bootstrap-4.0.0 位于 src/main/resources/static/

    【讨论】:

      猜你喜欢
      • 2017-05-26
      • 2019-02-12
      • 2020-08-16
      • 2014-11-17
      • 2020-07-04
      • 2021-07-06
      • 1970-01-01
      • 2019-07-27
      • 2021-01-07
      相关资源
      最近更新 更多