(eblog)2、整合Redis,以及项目优雅的异常处理与返回结果封装

5,145 阅读5分钟

公众号:MarkerHub(关注获取更多项目资源)

eblog 代码仓库:github.com/markerhub/e…

eblog 项目视频: www.bilibili.com/video/BV1ri…


开发文档目录:

(eblog)1、项目架构搭建、首页页面初始化

(eblog)2、整合Redis,以及项目优雅的异常处理与返回结果封装

(eblog)3、用Redis的zset有序集合实现一个本周热议功能

(eblog)4、自定义 Freemaker 标签实现博客首页数据填充

(eblog)5、博客分类填充、登录注册逻辑

(eblog)6、博客发布收藏、用户中心的设置

(eblog)7、消息异步通知、细节调整

(eblog)8、博客搜索引擎开发、后台精选

(eblog)9、即时群聊开发,聊天记录等


前后端分离项目vueblog请点击这里:超详细!4小时开发一个SpringBoot+vue前后端分离博客项目!!


1. 优雅的异常处理

有时候不可避免服务器报错的情况,如果不配置异常处理机制,就会默认返回 tomcat 或者 nginx 的 5XX 页面,对普通用户来说,不太友好,用户也不懂什么情况。这时候需要我们程序员设计返回一个友好简单的页面给用户。

处理办法如下:通过使用 @ControllerAdvice 来进行统一异常处理,@ExceptionHandler(value = Exception.class) 来指定捕获的 Exception 各个类型异常 ,这个异常的处理,是全局的,所有类似的异常,都会跑到这个地方处理。

  • com.example.common.exception.GlobalExceptionHandler

  • com.example.common.exception.HwException

步骤一、首先我们自定义一个异常 HwException,需要继承 RuntimeException,这样涉及到事务时候才会有回滚。HwException 将作为我们系统 catch 到错误时候报出来的异常。

public class HwException extends RuntimeException {
    private int code;
    public HwException() {}
    public HwException(int code) {
        this.code = code;
    }
    public HwException(String message) {
        super(message);
    }
    public HwException(int code, String message) {
        super(message);
        this.code = code;
    }
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
}

步骤二、定义全局异常处理,@ControllerAdvice 表示定义全局控制器异常处理,@ExceptionHandler 表示针对性异常处理,可对每种异常针对性处理。

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) {
        log.error("------------------>捕捉到全局异常", e);
        if(e instanceof HwException) {
            //...
        }
        ModelAndView mav = new ModelAndView();
        mav.addObject("exception", e);
        mav.addObject("message", e.getMessage());
        mav.addObject("url", req.getRequestURL());
        mav.setViewName("error");
        return mav;
    }
    @ExceptionHandler(value = HwException.class)
    @ResponseBody
    public Result jsonErrorHandler(HttpServletRequest req, HwException e) {
        return Result.fail(e.getMessage(), "some error data");
    }
}

步骤三、定义异常 error 页面。打开 layui 页面,有个 tips.ftl 的页面比较符合我们的异常页面。可用于展示异常。

  • templates/error.ftl
<#include "/inc/layout.ftl"/>
<@layout "首页">
    <#include "/inc/header-panel.ftl" />
    <div class="layui-container fly-marginTop">
        <div class="fly-panel">
            <div class="fly-none">
                <h2><i class="iconfont icon-tishilian"></i></h2>
                <p>${message}</p>
            </div>
        </div>
    </div>
</@layout>

2. 统一的结果返回封装(异步返回)

上面我们用到了一个 Result 的类,这个用于我们的异步统一返回的结果封装。一般来说,结果里面有几个要素必要的

  • 是否成功,可用 code 表示(如 0 表示成功,-1 表示异常)

  • 结果消息

  • 结果数据

所以可得到封装如下:

  • com.example.common.lang.Result
@Data
public class Result implements Serializable {
    private String code;
    private String msg;
    private Object data;
    public static Result succ(Object data) {
        Result m = new Result();
        m.setCode("0");
        m.setData(data);
        m.setMsg("操作成功");
        return m;
    }
    public static Result succ(String mess, Object data) {
        Result m = new Result();
        m.setCode("0");
        m.setData(data);
        m.setMsg(mess);
        return m;
    }
    public static Result fail(String mess) {
        Result m = new Result();
        m.setCode("-1");
        m.setData(null);
        m.setMsg(mess);
        return m;
    }
    public static Result fail(String mess, Object data) {
        Result m = new Result();
        m.setCode("-1");
        m.setData(data);
        m.setMsg(mess);
        return m;
    }
}

3、集成 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(uploader.shimo.im/f/HTgtITdNf…

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

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

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

@EnableCaching
@Configuration
publicclassWebMvcConfig{
}

接下来,引入 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 模块就说到这里,下面我们去填充一下首页的数据先。

(完)

MarkerHub 文章索引:

github.com/MarkerHub/J…