美文网首页
SpringBoot进阶学习下篇

SpringBoot进阶学习下篇

作者: HelloWorld打断点 | 来源:发表于2021-01-07 15:50 被阅读0次

    5、SprinBoot整合Thymeleaf模版引擎
    5.1 SpringBoot对模板的支持
    SpringBoot框架支持很多种模板,(FreeMarker、Thymeleaf、Mustache等),大大方便了前端的开发。

    SpringBoot对Jsp不太支持,并且官方没有提供整合的配置,原因:

    1、SpringBoot使用的是嵌入式Servlet web容器,默认使用jar的打包方式,jar包本身不支持jsp模板。

    2、如果使用Undertow嵌入式容器部署SpringBoot项目的话,不支持Jsp模板。

    3、SpringBoot默认提供了一个处理请求路径"/error"的统一错误处理器,来返回具体的异常信息,如果使用jsp模板的话无法对默认的错误信息进行覆盖,只能在指定的位置指定错误页面。

    5.2 Thymeleaf模板引擎技术
    5.2.1 Thymeleaf介绍
    Thymeleaf是一种基于服务器端的java模板引擎技术,也是一个优秀的面向Java的XML、XHTML、HTML5页面模板,它具有丰富的标签语言、函数和表达式,在使用Spring Boot框架进行页面设计时,一般会选择Thymeleaf模板。

    5.2.2Thymeleaf语法
    在HTML页面上使用Thymeleaf标签,Thymeleaf 标签能够动态地替换掉静态内容,使页面动态展示。

    常用的标签
    th:标签 说明
    th:insert 布局标签,替换内容到引入的文件
    th:replace 页面片段包含(类似JSP中的include标签)
    th:each 元素遍历(类似JSP中的c:forEach标签)
    th:if 条件判断,如果为真
    th:unless 条件判断,如果为假
    th:switch 条件判断,进行选择性匹配
    th:case 条件判断,进行选择性匹配
    th:value 属性值修改,指定标签属性值
    th:href 用于设定链接地址
    th:src 用于设定链接地址
    th:text 用于指定标签显示的文本内容
    标准表达式
    1、变量表达式 ${...}

    来获取到上下文中变量的值。

    Demo:<p th:text="${title}">这是标题</p>

    Thymeleaf内置的上下文对象有:

    ctx 上下文对象
    vars 上下文变量
    locale 上下文区域设置
    request (仅限Web Context)HttpServletRequest对象
    response (仅限Web Context)HttpServletResponse对象
    session (仅限Web Context)HttpSession对象
    servletContext (仅限Web Context)ServletContext对象
    2、选择变量表达式 *{...}

    也是获取到上下问的变量只不过是从业务对象中获取

    Demo:

    <div th:object="${book}"> <p>titile: <span th:text="*{title}">标题</span>.</p></div>

    3、消息表达式 #{...}

    消息表达式#{...}主要用于Thymeleaf模板页面国际化内容的动态替换和展示,使用消息表达式#

    {...}进行国际化设置时,还需要提供一些国际化配置文件。后边会说明

    4、链接表达式 @{...}

    链接表达式@{...}一般用于页面跳转或者资源的引入,在Web开发中占据着非常重要的地位,并且使用

    也非常频繁,Demo:

    <a th:href="@{http://localhost:8080/order/details(orderId={o.id})}">view</a><a th:href="@{/order/details(orderId={o.id})}">view</a>

    5、片段表达式 ~{...}

    片段表达式~{...}用来标记一个片段模板,并根据需要移动或传递给其他模板。其中,最常见的用法是使用th:insert或th:replace属性插入片段。

    <div th:insert="~{thymeleafDemo::title}"></div>

    thymeleaf Demo
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" media="all"
    href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
    <title>Title</title>
    </head>
    <body>
    <p th:text="${hello}">HelloWorld</p>
    </body>
    </html>
    5.2.3Thymeleaf使用Demo
    POM
    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    </dependencies>
    配置

    模板缓存

    spring.thymeleaf.cache = true

    模板编码

    spring.thymeleaf.encoding=utf-8

    应用于模板的模板模式

    spring.thymeleaf.mode = HTML5

    指定模板页面存放路径

    spring.thymeleaf.prefix = classpath:/templates/

    指定模板页面名称的后缀

    spring.thymeleaf.suffix = .html

    配置国际化文件基础名

    spring.messages.basename=i18n.login

    代码
    @Controller
    public class LoginController {
    @RequestMapping("/toLoginPage")
    public String toLoginPage(Model model){
    model.addAttribute("currentYear", Calendar.getInstance().get(Calendar.YEAR));
    return "login";
    }
    }

    HTML
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1,shrink-to-fit=no">
    <title>用户登录界面</title>
    <link th:href="@{/login/css/bootstrap.min.css}" rel="stylesheet">
    <link th:href="@{/login/css/signin.css}" rel="stylesheet">
    </head>
    <body class="text-center">

    <form class="form-signin">
    <img class="mb-4" th:src="@{/login/img/login.jpg}" width="72" height="72">
    <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">请登录</h1>
    <input type="text" class="form-control"
    th:placeholder="#{login.username}" required="" autofocus="">
    <input type="password" class="form-control"
    th:placeholder="#{login.password}" required="">
    <div class="checkbox mb-3">
    <label>
    <input type="checkbox" value="remember-me"> [[#{login.rememberme}]]
    </label>
    </div>
    <button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.button}">登录</button>
    <p class="mt-5 mb-3 text-muted">© <span th:text="{currentYear}">2019</span>-<span th:text="{currentYear}+1">2020</span></p>
    <a class="btn btn-sm" th:href="@{/toLoginPage(l='zh_CN')}">中文</a>
    <a class="btn btn-sm" th:href="@{/toLoginPage(l='en_US')}">English</a>
    </form>
    </body>
    </html>

    5.2.4Thymeleaf设置本地化语言
    首先需要在resources目录下创建一个文件夹来存放默认的和翻译好的语言
    login.properties,login_zh_CN.properties 【默认和中文的都一样】
    login.tip=请登录
    login.username=用户名
    login.password=密码
    login.button=登录
    login.rememberme=记住我

    login_en_US.properties【英文】
    login.tip=please sign in
    login.username=username
    login.password=password
    login.button=login
    login.rememberme=remmeber me

    配置

    配置国际化文件基础名

    spring.messages.basename=language.login

    Html中修改

    <form class="form-signin">
    <img class="mb-4" th:src="@{/login/img/login.jpg}" width="72" height="72">
    <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">请登录</h1>
    <input type="text" class="form-control"
    th:placeholder="#{login.username}" required="" autofocus="">
    <input type="password" class="form-control"
    th:placeholder="#{login.password}" required="">
    <div class="checkbox mb-3">
    <label>
    <input type="checkbox" value="remember-me"> [[#{login.rememberme}]]
    </label>
    </div>
    <button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.button}">登录</button>
    <p class="mt-5 mb-3 text-muted">© <span th:text="{currentYear}">2019</span>-<span th:text="{currentYear}+1">2020</span></p>

    <a class="btn btn-sm" th:href="@{/toLoginPage(setLanguage='zh_CN')}">中文</a>
    <a class="btn btn-sm" th:href="@{/toLoginPage(setLanguage='en_US')}">English</a>
    </form>
    </body>
    </html>

    设置本地化解析器

    public class LanguageLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
    String setLanguage = request.getParameter("setLanguage");
    Locale locale;
    if (!StringUtils.isEmpty(setLanguage)) {
    String[] s = setLanguage.split("_");
    locale = new Locale(s[0],s[1]);
    }else{//为空的情况
    String header = request.getHeader("Accept-Language");
    String[] split = header.split(",");
    String[] split1 = split[0].split("-");
    locale = new Locale(split1[0],split1[1]);
    }
    return locale;
    }

    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
    }
    

    }

    配置到Spring容器中进行覆盖 一定要是localeResolver才行

    @Bean
    public LocaleResolver localeResolver(){
    return new LanguageLocaleResolver();
    }
    总结:在进行本地化配置的时候一定要注意配置文件的命名 文件名语言国家

    5.3SpringBoot缓存
    SpringBoot支持很多缓存组件:

    Generic
    JCache (JSR-107) (EhCache 3、Hazelcast、Infinispan等)
    EhCache 2.x
    Hazelcast
    Infinispan
    Couchbase
    Redis
    Caffeine
    Simple

    添加@EnableCaching之后默认会从这个9个缓存组件中去查找,没有的话默认使用Simple缓存组件。

    5.3.1默认缓存使用
    使用方法:

    在启动类上贴上@EnableCaching,在对应的service查询方法上贴上@Cacheable(cacheNames = "name")来开启缓存。

    @SpringBootApplication
    @EnableCaching
    public class CacheApplication {
    public static void main(String[] args) {
    SpringApplication.run(CacheApplication.class, args);
    }
    }

    //根据id查询person对象爱ing
    @Cacheable(cacheNames = "person")
    public Person findById(Integer id){
    Optional<Person> op = personRepository.findById(id);
    return op.isPresent() ? op.get() : null;
    }

    @Cacheable 注解
    属性名 说明
    value/cacheNames 指定缓存空间的名称,必配属性。这两个属性二选一使用
    key 指定缓存数据的key,默认使用方法参数值,可以使用SpEL表达式SpEL表达式:#root.mathodName ->获取当前方法名#root.mathod ->当前被调用的方法 #root.target ->当前被调用的目标对象#root.targetClass ->当前被调用的目标对象类#root.args[0] 第一个参数, #root.args[1] 第二个参数... ->当前被调用的方法的参数列表#参数名, 也可以使用 #p0 #a0 0是参数的下标索引 ->根据参数名字取出值#result ->当前方法的返回值
    keyGenerator 指定缓存数据的key的生成器,与key属性二选一使用
    cacheManager 指定缓存管理器
    cacheResolver 指定缓存解析器,与cacheManager属性二选一使用
    condition 指定在符合某条件下,进行数据缓存
    unless 指定在符合某条件下,不进行数据缓存
    sync 指定是否使用异步缓存。默认false
    执行原理

    Cacheable通过动态代理的方式进行缓存,方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取,(CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建;

    @Cacheable在不引入任何的依赖的情况下默认使用的是SimpleCacheConfiguration配置的ConcurrentMapCacheManager缓存组件,将缓存结果存储在cacheMap中。使用一个key,默认就是方法的参数,如果多个参数或者没有参数,是按照某种策略生成的,默认是使用KeyGenerator生成的。

    使用SimpleKeyGenerator生成key策略:

    参数个数 key
    没有参数 new SimpleKey()
    有一个参数 参数值
    多个参数 new SimpleKey(params)
    @CachePut注解
    目标方法执行完之后生效, @CachePut被使用于修改操作比较多,哪怕缓存中已经存在目标值了,但是这个

    注解保证这个方法依然会执行,执行之后的结果被保存在缓存中

    @CacheEvict注解
    @CacheEvict注解是由Spring框架提供的,可以作用于类或方法(通常用在数据删除方法上),该注解

    的作用是删除缓存数据。@CacheEvict注解的默认执行顺序是,先进行方法调用,然后将缓存进行清

    除。

    5.3.2Redis缓存
    1、注解方式使用redis缓存
    在使用注解的方式使用redis缓存的时候只需要导入redis的包和配置redis,SpringBoot默认就会走redis缓存,使用方法和默认缓存的使用方法一致。

    POM

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    配置

    Redis配置

    Redis服务地址

    spring.redis.host=127.0.0.1

    Redis服务器连接端口

    spring.redis.port=6379

    Redis服务器连接密码(默认为空)

    spring.redis.password=
    spring.redis.database=1

    对基于注解的Redis缓存数据统一设置有效期为1分钟,单位毫秒

    spring.cache.redis.time-to-live=60000

    原理是在引入redis配置之后,系统直接就会使用RedisCacheConfiguration对缓存进行配置,使用RedisCacheManager来管理缓存,使用方式也是通过@Cacheable等注解来实现的。

    修改默认的序列化方式为json方式

    通过查看RedisCacheConfiguration 类的源码发现默认是jdk的序列化方式

    修改默认的序列化方式

    @Configuration
    public class RedisAnnoConfig {

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换
        RedisSerializer<String> strSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jacksonSeial =
                new Jackson2JsonRedisSerializer(Object.class);
    
        // 解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);
    
        // 定制缓存数据序列化方式及时效
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(1))//缓存时间为1天
                .serializeKeysWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(strSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(jacksonSeial))
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager
                .builder(redisConnectionFactory).cacheDefaults(config).build();
        return cacheManager;
    }
    

    }

    2、使用RedisTemplate进行缓存
    直接注入RedisTemplate进行操作,但是有个问题,注入的redisTemplate在保存数据的时候还是jdk默认的序列化方式因此需要修改序列化方式。RedisAutoConfiguration类来分析。

    修改RedisTemplate序列化方式,思路是直接覆盖自动注册的redisTemplate实例。

    @Configuration
    public class RedisConfig {
    @Bean
    public RedisTemplate<Object,Object> redisTemplate(
    RedisConnectionFactory redisConnectionFactory){
    RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
    redisTemplate.setConnectionFactory(redisConnectionFactory);

        //设置序列化方式
        Jackson2JsonRedisSerializer jackSonSerializer = 
                new Jackson2JsonRedisSerializer(Object.class);
        redisTemplate.setDefaultSerializer(jackSonSerializer);
    
        //解决查询缓存转换异常问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackSonSerializer.setObjectMapper(om);
        // 设置RedisTemplate模板API的序列化方式为JSON
        redisTemplate.setDefaultSerializer(jackSonSerializer);
    
        return redisTemplate;
    }
    

    }

    相关文章

      网友评论

          本文标题:SpringBoot进阶学习下篇

          本文链接:https://www.haomeiwen.com/subject/wcvzoktx.html