(eblog)2、集成redis、首页数据填充

小助手 1年前 ⋅ 4057 阅读

集成redis

高可用集群

在redis课程中,我们演示过redis的主从、还有哨兵配置,高可用的redis集群中,可以帮我们完成主库下线,从库自动切换的功能。这里我把课程的复习文档贴出来,大家回去照着视频回放和文档搭建起来:

集成到springboot中

第一步、导入redis的pom包

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

第二步、配置redis的连接信息

spring:  
  redis:
    sentinel:
      master: mymaster
      nodes: 47.106.38.101:26379,47.106.38.101:26380

以上的两个redis是我自己的阿里云上配置,大家可以用,也可以自己配置一个。 致此,redis已经集成到我们的springboot项目中了。

以上是哨兵的配置,如果单机redis的话,配置也简单:

spring:
  redis:
    host: localhost
    port: 6379    

第三步、为了让我们的存到redis中的缓存数据能更加容易看懂,这里换一种序列化方式,默认的是jdk的序列化方式,这里选用jackson2JsonRedisSerializer。只需要重写redisTemplate操作模板的生成方式即可。新建一个config包,放在这个包下。

@Configuration
public class RedisConfiguration {
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(new ObjectMapper());
        template.setKeySerializer(jackson2JsonRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        return template;
    }
}

第四步、使用redisTemplate操作数据相对比较麻烦,我们使用一个util封装类,让我们操作redis更加方便。放在utils包下 RedisUtil.java

至此,能操作redis的工具类和配置我们已经集成进来。后面我们需要用到缓存注解的时候我们再单独说明。

集成redis之后可以使用的地方又很多,比如我们的侧边栏热议功能,还有我们的缓存注解Cacheable等。但是使用了redis的缓存注解,你会发现不能给注解设定一个缓存过期时间,为了解决这个问题,我们引入redission。

首先开启一下我们的缓存注解功能,添加一个配置WebMvcConfig 。加上开启注解@EnableCaching。如下:

@EnableCaching
@Configuration
public class WebMvcConfig {
}

接下来,引入redission,其实很简单,首先引入jar包:

<!-- redission -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.10.6</version>
</dependency>

因为redission其实也有引入spring-boot-starter-data-redis包,所以配置redis的属性其实和引入redis是一样的的,因此,引入了jar包之后,我们就可以使用redission功能了,比如做分布式锁、给缓存注解一个过期时间等 ok、关于 redis模块就说到这里,下面我们去填充一下首页的数据先。

首页数据填充

自定义freemarker标签

首先要来弄的是置顶的数据。为了让大家能对freemarker有更多的了解,我们定义一个freemarker标签,然后使用标签去展示我们的数据。

想要自定义freemarker标签需要实现这个接口并且重写excute方法:

public interface TemplateDirectiveModel extends TemplateModel {
  public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException;

}

上面的参数如下:

  • env:系统环境变量,通常用它来输出相关内容,如Writer out = env.getOut()。
  • params:自定义标签传过来的对象,其key=自定义标签的参数名,value值是TemplateModel类型,而TemplateModel是一个接口类型,通常我们都使用TemplateScalarModel接口来替代它获取一个String 值,如TemplateScalarModel.getAsString();当然还有其它常用的替代接口,如TemplateNumberModel获取number,TemplateHashModel等。
  • loopVars  循环替代变量。
  • body 用于处理自定义标签中的内容,如<@myDirective>将要被处理的内容/@myDirective;当标签是<@myDirective />格式时,body=null。

但是直接这些参数来处理我们业务其实还有点麻烦,为了更好使用这个接口,我们需要再封装多一层,这里我引用了mblog项目的对这个接口的封装。

com.example.common.template

  • DirectiveHandler
  • TemplateDirective
  • TemplateModelUtils

上面的3个类我都是在mblog项目中复制过来的,就改了一下包路径

mblog原路径:

https://gitee.com/mtons/mblog/tree/master/src/main/java/com/mtons/mblog/modules/template

有了上面的封装之后,我们要定义个标签模板只需要继承TemplateDirective,重写getName()和excute(DirectiveHandler handler);可以看到excute方法中之后handler了,这个handler我们使用起来就很简便了。

下面我们来定义一个博客列表的标签com.example.templates.PostsTemplate

@Component
public class PostsTemplate extends TemplateDirective {

    @Autowired
    PostService postService;

    @Override
    public String getName() {
        return "posts";
    }

    @Override
    public void execute(DirectiveHandler handler) throws Exception {
        Long categoryId = handler.getLong("categoryId", 0);
        int pn = handler.getInteger("pn", 1);
        int size = handler.getInteger("size", 10);
        String order = handler.getString("order", "created");

        Page page = new Page(pn, size);
        IPage results = postService.paging(page, categoryId, order);
        handler.put(RESULTS, results).render();
    }
}

上面的代码可以知道,我们标签有几个参数:categoryId、pn、size、order。 然后封装成了两个类:Page、QueryWrapper,都是mybatis-plus里面的封装类,用于分页和参数查询。

为了可以做缓存,这里我们没有直接传QueryWrapper过去,而是直接传参数过去,这样我们可以用参数作为缓存的key。

下面我们去具体看看postService.paging(Page page, Long categoryId, String order);方法。

@Override
@Cacheable(cacheNames = "cache_post", key = "'page_' + #page.current + '_' + #page.size " +
        "+ '_query_' +#categoryId + '_' + #order")
public IPage paging(Page page, Long categoryId, String order) {

    QueryWrapper wrapper = new QueryWrapper<Post>()
            .eq(categoryId != 0, "category_id", categoryId)
            .orderByDesc(order);
    IPage<PostVo> pageData = postMapper.selectPosts(page, wrapper);

    return pageData;
}

上面接口又调用了mapper的接口,并且使用了缓存注解@Cacheable表示缓存结果,key是page的pn、size、还有categoryId、order的参数。 好了,上面我定义了一个模板标签,需要在页面中使用还需要把这个标签配置到freemarker中,因此我们定义一个FreemarkerConfig。

  • com.example.config.FreemarkerConfig
@Configuration
public class FreemarkerConfig {

    @Autowired
    private freemarker.template.Configuration configuration;

    @Autowired
    private ApplicationContext applicationContext;

    @PostConstruct
    public void setUp() {
        configuration.setSharedVariable("posts", applicationContext.getBean(PostsTemplate.class));
    }
}

页面使用标签

好了,freemarker标签就是这样生成了,下面我们在页面中使用。我们定义的标签名称是posts,结果是results。所以置顶模块,我们这样写:

  • templates/index.ftl

图片

得到的结果如下:

图片

首页侧边栏-本周热议(续)

在上一次作业中,我们完成了本周热议的数据接口:

图片

但是还没在页面中展示我们的数据,一般按照逻辑,我们应该页面中写个ajax,然后调用这接口展示数据,现在我们学会了自定义freemarker,我觉得定义一个标签更方便点,因此,这里我们修改一下接口,把接口改成模板标签。

ok,我们安装刚才的流程,梳理一下:

  • 首先定义一个模板HotsTemplate,继承TemplateDirective
  • 重写getName和execute方法
  • 然后在FreemarkerConfig中配置注入标签
  • 页面中使用标签
/**
 * 本周热议
 */
@Component
public class HotsTemplate extends TemplateDirective {

    @Autowired
    RedisUtil redisUtil;

    @Override
    public String getName() {
        return "hots";
    }

    @Override
    public void execute(DirectiveHandler handler) throws Exception {
        Set<ZSetOperations.TypedTuple> lastWeekRank = redisUtil.getZSetRank("last_week_rank", 0, 6);

        List<Map<String, Object>> hotPosts = new ArrayList<>();
        for (ZSetOperations.TypedTuple typedTuple : lastWeekRank) {

            Map<String, Object> map = new HashMap<>();
            map.put("comment_count", typedTuple.getScore());
            map.put("id", redisUtil.hget("rank_post_" + typedTuple.getValue(), "post:id"));
            map.put("title", redisUtil.hget("rank_post_" + typedTuple.getValue(), "post:title"));

            hotPosts.add(map);
        }
        handler.put(RESULTS, hotPosts).render();
    }
}

上面execute的内容是把之前的本周热议的接口搬过来的。 然后是freemarkerConfig.setUp

configuration.setSharedVariable("hots", applicationContext.getBean(HotsTemplate.class));

有了这行代码,页面中就可以使用了。

  • templates/inc/right.ftl
<dl class="fly-panel fly-list-one">
    <dt class="fly-panel-title">本周热议</dt>
    <@hots>
        <#list results as post>
            <dd>
                <a href="jie/detail.html">${post.title}</a>
                <span><i class="iconfont icon-pinglun1"></i> ${post.comment_count}</span>
            </dd>
        </#list>
    </@hots>
</dl>

好了,这一次的作业的内容了。我们要学会快速自定义freemarker标签。freemarker模板引擎还是比较主流的页面引擎。


全部评论: 0

    我有话说: