Spring Thymeleaf Bootstrap CSS [英] Spring Thymeleaf Bootstrap CSS

查看:26
本文介绍了Spring Thymeleaf Bootstrap CSS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

以下是相关文件:

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

<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"><头><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 登录</title><!-- Bootstrap 核心 CSS --><link href="resources/css/bootstrap-3.3.2-dist/bootstrap.min.css" rel="stylesheet"/><!-- 此模板的自定义样式--><link href="resources/css/signin.css" rel="stylesheet"/><!-- 用于 HTML5 元素和媒体查询的 IE8 支持的 HTML5 shim 和 Respond.js --><!--[如果是 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]--><身体><div class="容器"><p th:if="${loginError}">用户名或密码错误</p><form th:action="@{/login}" method="post" class="form-signin"><h2 class="form-signin-heading">请登录</h2><label for="username" class="sr-only">用户名</label><input type="text" id="username" name="username" class="form-control" placeholder="用户名"/><label for="password" class="sr-only">密码</label><input type="password" id="password" name="password" class="form-control" placeholder="密码"/><!-- <button class="btn btn-lg btn-primary btn-block" type="submit">登录</button>--><input type="submit" value="Log in" class="btn btn-lg btn-primary btn-block"/></表单>

<!--/容器--><!-- 针对 Surface/桌面 Windows 8 错误的 IE10 视口破解 --><script src="resources/js/ie10-viewport-bug-workaround.js"></script></html>

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

package com.motodoc.hub.controller;导入 org.springframework.stereotype.Controller;导入 org.springframework.ui.Model;导入 org.springframework.web.bind.annotation.RequestMapping;@控制器公共类登录控制器{//登录表格@RequestMapping("/登录")公共字符串登录(){System.out.println("在这里......");返回登录";}//登录表单出错@RequestMapping("/登录错误")公共字符串登录错误(模型模型){model.addAttribute("登录错误", true);返回登录";}}

主页 html 文件(这是由于某种原因没有选择"CSS 的文件):

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"><头><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 核心 CSSS --><link href="resources/css/bootstrap-3.3.2-dist/bootstrap.min.css" rel="stylesheet"/><title>首页</title><身体><div th:include="模板/导航栏::导航栏"></div><br></br><h1>登录成功!</h1><br></br><div><table class="table table-striped"><caption th:text="#{user.table.caption}">站点用户</caption><头><tr><th scope="col" th:text="#{user.id.label}">Id</th><th scope="col" th:text="#{user.firstname.label}">名字</th><th scope="col" th:text="#{user.lastname.label}">Last Name</th><th scope="col" th:text="#{user.username.label}">用户名</th></tr></thead><tr th:each="用户:${currentResults.content}"><td th:text="${user.id}">1</td><td th:text="${user.firstName}">乔治<​​/td><td th:text="${user.lastName}">华盛顿</td><td th:text="${user.username}">gwash</td></tr></tbody>

<!-- Bootstrap 核心 JavaScript==================================================--><!-- 放置在文档的末尾,以便页面加载更快--><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></html>

家庭控制器类:

@Controller公共类 HomeController {@自动连线私有 ISecurityUserService securityUserService;@RequestMapping("/home")公共字符串重定向(){返回重定向:/home/page/1";}//家@RequestMapping(value="/home/page/{pageNumber}", method = RequestMethod.GET)公共字符串 getUsers(@PathVariable("pageNumber") 整数 pageNumber,模型映射模型) {页面<人>currentResults = securityUserService.findAll(pageNumber-1);model.addAttribute("currentResults", currentResults);//分页变量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);回家";}}

Spring 安全配置:

@Configuration@EnableWebMvcSecurity@EnableGlobalMethodSecurity(prePostEnabled=true)公共类 SecurityConfig 扩展了 WebSecurityConfigurerAdapter {@自动连线public void configureGlobal(AuthenticationManagerBuilder auth) 抛出异常 {auth.authenticationProvider(authenticationProvider());}@覆盖公共无效配置(WebSecurity web)抛出异常{web.ignoring().antMatchers("/resources/**");}@覆盖protected void configure( HttpSecurity http ) 抛出异常 {http.authorizeRequests().antMatchers("/resources/**").permitAll().anyRequest().authenticated().和().formLogin().loginPage("/登录").permitAll().defaultSuccessUrl("/home").failureUrl("/登录错误").和().登出().invalidateHttpSession(true).logoutUrl("/注销").deleteCookies("JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE").logoutSuccessUrl("/").permitAll();}@豆角,扁豆public CustomAuthenticationProviderImpl authenticationProvider() {返回新的 CustomAuthenticationProviderImpl();}@豆角,扁豆公共 BCryptPasswordEncoder 编码器(){返回新的 BCryptPasswordEncoder(10);}}

应用上下文配置类:

@Configuration@ComponentScan(basePackages = {"com.motodoc.hub.*"})@EnableWebMvc@Import({SpringDataConfig.class,ThymeleafConfig.class,安全配置类,ServiceBeans.class})@ImportResource("classpath:trace-context.xml")@PropertySource("classpath:spring.properties")公共类 ApplicationContext 扩展了 WebMvcConfigurerAdapter {//将资源路径映射到 webapp/resources@覆盖public void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");}//仅当我们在引用属性时使用 @Value 和 ${...} 时才需要@豆角,扁豆公共静态 PropertySourcesPlaceholderConfigurer 属性(){PropertySourcesPlaceholderConfigurer propertySources = new PropertySourcesPlaceholderConfigurer();资源 [] 资源 = 新类路径资源 [] {new ClassPathResource("spring.properties") };propertySources.setLocations(resources);propertySources.setIgnoreUnresolvablePlaceholders(true);返回属性源;}//提供消息的国际化@豆角,扁豆公共 ResourceBundleMessageSource messageSource() {ResourceBundleMessageSource source = new ResourceBundleMessageSource();source.setBasename("消息");返回源;}}

Thymeleaf 配置类:

@Configuration公共类 ThymeleafConfig {@豆角,扁豆公共 ServletContextTemplateResolver templateResolver() {ServletContextTemplateResolver 解析器 = new ServletContextTemplateResolver();resolver.setPrefix("/WEB-INF/views/");resolver.setSuffix(".html");resolver.setTemplateMode("HTML5");resolver.setOrder(1);返回解析器;}@豆角,扁豆公共 SpringTemplateEngine templateEngine() {SpringTemplateEngine engine = new SpringTemplateEngine();engine.setTemplateResolver(templateResolver());//添加spring安全方言设置<ID方言>方言 = new HashSet();方言.add(springSecurityDialect());engine.setAdditionalDialects(方言);返回引擎;}@豆角,扁豆公共 ThymeleafViewResolver thymeleafViewResolver() {ThymeleafViewResolver 解析器 = new ThymeleafViewResolver();resolver.setTemplateEngine(templateEngine());返回解析器;}@豆角,扁豆公共 SpringSecurityDialect springSecurityDialect() {返回新的 SpringSecurityDialect();}}

Webapp 项目目录结构:

解决方案

想通了...小学生的错误是我的部分...

我的 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"/>

这成功了.

I'm trying to use Bootstrap CSS with my Spring + Security + Thymeleaf web application. The CSS gets picked up the by my custom login screen and everything is fine - all styles are applied. However, when I progress from the login screen to the next screen for some reason my html page is not picking up the CSS file and the styles are not being applied. Can someone assist?

Below are the relevant files:

Login html file (which is working fine):

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

Login controller (again - all is working fine with this):

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";
    }
}

Home html file (this is the file where for some reason the CSS is not 'getting picked'):

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

Home controller class:

@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 security config:

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

Application context config class:

@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 config class:

@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 Project Directory structure:

解决方案

Figured it out ... schoolboy error on my part ...

The following link in my home.html file wasn't resolving to the right location:

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

So instead, I used context-relative URL as follows:

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

And this did the trick.

这篇关于Spring Thymeleaf Bootstrap CSS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆