【JavaEE进阶】 图书管理系统开发日记——柒

简介: 【JavaEE进阶】 图书管理系统开发日记——柒

🍃前言

前面我们基本实现了图书股管理系统的功能,但是我们依旧存在一个问题。

就是我们不论是否登录,我们直接访问图书列表。也可以进行访问及修改

而我们希望达到的效果是,必须要进行登录后才能进行一系列操作

这里我们使用拦截器来完成着一系列操作

🍀什么是拦截器?

拦截器是Spring框架提供的核⼼功能之⼀,主要⽤来拦截⽤⼾的请求,在指定⽅法前后,根据业务需要执⾏预先设定的代码.

也就是说,允许开发⼈员提前预定义⼀些逻辑,在⽤⼾的请求响应前后执⾏.也可以在⽤⼾请求前阻⽌其执⾏.

在拦截器当中,开发⼈员可以在应⽤程序中做⼀些通⽤性的操作,⽐如通过拦截器来拦截前端发来的请求,判断Session中是否有登录⽤⼾的信息.如果有就可以放⾏,如果没有就进⾏拦截.

就⽐如我们去银⾏办理业务,在办理业务前后,就可以加⼀些拦截操作,办理业务之前,先取号,如果带⾝份证了就取号成功。业务办理结束,给业务办理⼈员的服务进⾏评价.这些就是"拦截器"做的⼯作

🌲拦截器的基本使用

拦截器的使⽤步骤分为两步:

  1. 定义拦截器
  2. 注册配置拦截器

🚩自定义拦截器

我们需要实现HandlerInterceptor接⼝,并重写其所有⽅法

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse
            response, Object handler) throws Exception {
        log.info("LoginInterceptor ⽬标⽅法执⾏前执⾏..");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse
            response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("LoginInterceptor ⽬标⽅法执⾏后执⾏");
    }
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("LoginInterceptor 视图渲染完毕后执⾏,最后执⾏");
    }
}

这里涉及到的三个方法

preHandle()⽅法:⽬标⽅法执⾏前执⾏.返回true:继续执⾏后续操作;返回false:中断后续操作.

postHandle()⽅法:⽬标⽅法执⾏后执⾏

afterCompletion()⽅法:视图渲染完毕后执⾏,最后执⾏(后端开发现在⼏乎不涉及视图,这里博主就不做讲解了)

🚩注册配置拦截器

实现WebMvcConfigurer接⼝,并重写addInterceptors⽅法

@Configuration
public class WebConfig implements WebMvcConfigurer {
    //⾃定义的拦截器对象
    @Autowired
    private LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册⾃定义拦截器对象
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**");//设置拦截器拦截的请求路径( /** 表⽰拦截所有请求)
    }
}

至此简单的拦截器就注册完毕

🚩拦截路径

关于注册配置拦截器的拦截路劲,拦截路径是指我们定义的这个拦截器,对哪些请求⽣效.我们在注册配置拦截器的时候,通过 addPathPatterns() ⽅法指定要拦截哪些请求.也可以通过

excludePathPatterns() 指定不拦截哪些请求.上述代码中,我们配置的是 /** ,表⽰拦截所有的请求.

在拦截器中除了可以设置 /** 拦截所有资源外,还有⼀些常⻅拦截路径设置,比如在该项目中

拦截路径 含义 举例
/* ⼀级路径 能匹配/user,/book,/login,不能匹配/user/login
/** 任意级路径 能匹配/user,/user/login,/user/reg
/book/* /book下的⼀级路径 能匹配/book/addBook,不能匹配/book/addBook/1,/book
/book/** /book下的任意级路径 能匹配/book,/book/addBook,/book/addBook/2,不能匹配/user/login

🚩拦截器执行流程

学会了拦截器的基本使用,那么拦截器的执行流程是什么样的呢?

我们先来看一下正常的执行流程

当我们有了拦截器以后,我们的执行流程为

  1. 添加拦截器后,执⾏Controller的⽅法之前,请求会先被拦截器拦截住.执⾏ preHandle() ⽅法,这个⽅法需要返回⼀个布尔类型的值.如果返回true,就表⽰放⾏本次操作,继续访问controller中的⽅法.如果返回false,则不会放⾏(controller中的⽅法也不会执⾏).
  2. controller当中的⽅法执⾏完毕后,再回过来执⾏ postHandle() 这个⽅法以及afterCompletion() ⽅法,执⾏完毕之后,最终给浏览器响应数据.

🎄项目实现统一拦截

🚩定义拦截器

首先我们定义拦截器如下:

代码实现如下:

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse
            response, Object handler) throws Exception {
        HttpSession session = request.getSession(false);
        if (session != null &&
                session.getAttribute(Constants.SESSION_USER_KEY) != null) {
            return true;
        }
        response.setStatus(401);
        return false;
    }
}

代码解释如下:

  1. 对服务中所存在的session进行判断,如果存在,则返回true,放行
  2. 若不存在,则使用setStatus()方法设置http状态码为401(Unauthorized)
  3. 关于Constants.SESSION_USER_KEY是我自定义的一个常量,表示为所存储的session值
public class Constants {
    public static final String SESSION_USER_KEY = "session_user_key";
}

🚩注册配置拦截器;

@Slf4j
@Configuration
public class WebConfig implements WebMvcConfigurer {
    //⾃定义的拦截器对象
    @Autowired
    private LoginInterceptor loginInterceptor;
    private List<String> excludePaths = Arrays.asList(
            "/user/login",
            "/**/*.js",
            "/**/*.css",
            "/**/*.png",
            "/**/*.html"
    );
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
      //注册⾃定义拦截器对象
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")//设置拦截器拦截的请求路径(/** 表⽰拦截所有请求)
.excludePathPatterns(excludePaths);//设置拦截器排除拦截的路径
    }
}

除此之外,博主还对之前的代码进行了一个改变,对返回的数据进行了一个封装,我希望在进行返回数据的时候我们只需要调用相应的方法就会返回我们所需要的相应结果

🚩代码的修改

首先我们准备一个枚举类为ResultStatus,里面有相应的业务状态显示以及相应的状态码设置

public enum ResultStatus {
    SUCCESS(200),
    UNLOGIN(-1),
    FAIL(-2);
    private Integer code;
    ResultStatus(int code) {
        this.code = code;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
}

然后我们再创建一个类Result,用来包装我们的返回结果。

并创建三个方法,进行返回结果的使用

代码实现如下:

@Data
public class Result {
    private ResultStatus status;
    private String errorMessage;
    private Object data;
    /**
     * 业务执⾏成功时返回的⽅法
     *
     * @param data
     * @return
     */
    public static Result success(Object data) {
        Result result = new Result();
        result.setStatus(ResultStatus.SUCCESS);
        result.setErrorMessage("");
        result.setData(data);
        return result;
    }
    /**
     * 业务执⾏失败时返回的⽅法
     *
     * @param
     * @return
     */
    public static Result fail(String msg) {
        Result result = new Result();
        result.setStatus(ResultStatus.FAIL);
        result.setErrorMessage(msg);
        result.setData("");
        return result;
    }
    /**
     * 业务执⾏失败时返回的⽅法
     *
     * @param
     * @return
     */
    public static Result unlogin() {
        Result result = new Result();
        result.setStatus(ResultStatus.UNLOGIN);
        result.setErrorMessage("⽤⼾未登录");
        result.setData(null);
        return result;
    }
}

🚩重写图书列表接口

由于我们返回的结果格式进行了改变,我们需要对相应的代码进行改变

@RequestMapping("/queryBookById")
public Result queryBookById(Integer bookId){
    if (bookId==null || bookId<=0){
        return Result.unlogin();
    }
    BookInfo bookInfo = bookService.queryBookById(bookId);
    return Result.success(bookInfo);
}

🌳前端代码的实现

前端相应代码实现如下:

function getBookList() {
    $.ajax({
        type: "get",
        url: "/book/getListByPage"+location.search,
        success: function (result) {
            console.log(result);
            if (result == null || result.data == null) {
                location.href = "login.html";
                return;
            }
            if (result != null) {
                var finalHtml = "";
                var data = result.data;
                for (var book of data.records) {
                    finalHtml += '<tr>';
                    finalHtml += '<td><input type="checkbox" name="selectBook" value="'+book.id+'" id="selectBook" class="book-select"></td>'
                    finalHtml += '<td>' + book.id + '</td>';
                    finalHtml += '<td>' + book.bookName + '</td>';
                    finalHtml += '<td>' + book.author + '</td>';
                    finalHtml += '<td>' + book.count + '</td>';
                    finalHtml += '<td>' + book.price + '</td>';
                    finalHtml += '<td>' + book.publish + '</td>';
                    finalHtml += '<td>' + book.statusCN + '</td>';
                    finalHtml += '<td><div class="op">';
                    finalHtml += '<a href="book_update.html?bookId=' + book.id + '">修改</a>'
                    finalHtml += '<a href="javascript:void(0)" onclick="deleteBook(' + book.id + ')">删除</a>'
                    finalHtml += '</div></td>';
                    finalHtml += "</tr>";
                }
                $("tbody").html(finalHtml);
                //翻页信息
                $("#pageContainer").jqPaginator({
                    totalCounts: data.total, //总记录数
                    pageSize: 10,    //每页的个数
                    visiblePages: 5, //可视页数
                    currentPage: data.pageRequest.currentPage,  //当前页码
                    first: '<li class="page-item"><a class="page-link">首页</a></li>',
                    prev: '<li class="page-item"><a class="page-link" href="javascript:void(0);">上一页<\/a><\/li>',
                    next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下一页<\/a><\/li>',
                    last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后一页<\/a><\/li>',
                    page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{{page}}<\/a><\/li>',
                    //页面初始化和页码点击时都会执行
                    onPageChange: function (page, type) {
                        console.log("第" + page + "⻚, 类型:" + type);
                        if (type != 'init') {
                            location.href = "book_list.html?currentPage=" + page;
                        }
                    }
                });
            }
        },
        error(error) {
            if(error.status == 401) {
                location.href = "login.html";
            }
        }
    });
}

⭕总结

关于《【JavaEE进阶】 图书管理系统开发日记——柒》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

相关文章
|
5月前
|
SQL 监控 关系型数据库
一键开启百倍加速!RDS DuckDB 黑科技让SQL查询速度最高提升200倍
RDS MySQL DuckDB分析实例结合事务处理与实时分析能力,显著提升SQL查询性能,最高可达200倍,兼容MySQL语法,无需额外学习成本。
|
运维 安全 网络安全
网络安全规划实践
网络安全规划实践
530 0
|
Java Unix Linux
Fastqc用腻了,来试下这个R包吧
平时拿到数据后首先要进行质控环节,其中FastaQC软件的使用最为广泛,它可以为每一个样品生成一个html报告和一个‘zip’ 文件,zip解压之后生成fastqc_data.txt和summary.txt的文件,里面包含了测序样品的质量信息,但是如果有几十个甚至上百个数据时候,我们总不可能一一的打开每个html文件查看,因此Multiqc软件成为了解决这一问题的首选方案,可以基于结果zip文件进行多样品的整合分析,信息生成在一张报告上。然而哪里有问题,哪里就有R包,对于R语言爱好者,这里再提供一种可替代的方法--fastqcr包,好处就是不管有没有linux环境时候,都可以快速对数据进行质检
572 0
|
前端开发 easyexcel API
前后端分离项目知识汇总(整合课程分类)
前后端分离项目知识汇总(整合课程分类)
212 0
|
8天前
|
人工智能 自然语言处理 Shell
🦞 如何在 OpenClaw (Clawdbot/Moltbot) 配置阿里云百炼 API
本教程指导用户在开源AI助手Clawdbot中集成阿里云百炼API,涵盖安装Clawdbot、获取百炼API Key、配置环境变量与模型参数、验证调用等完整流程,支持Qwen3-max thinking (Qwen3-Max-2026-01-23)/Qwen - Plus等主流模型,助力本地化智能自动化。
🦞 如何在 OpenClaw (Clawdbot/Moltbot) 配置阿里云百炼 API
|
6天前
|
人工智能 JavaScript 应用服务中间件
零门槛部署本地AI助手:Windows系统Moltbot(Clawdbot)保姆级教程
Moltbot(原Clawdbot)是一款功能全面的智能体AI助手,不仅能通过聊天互动响应需求,还具备“动手”和“跑腿”能力——“手”可读写本地文件、执行代码、操控命令行,“脚”能联网搜索、访问网页并分析内容,“大脑”则可接入Qwen、OpenAI等云端API,或利用本地GPU运行模型。本教程专为Windows系统用户打造,从环境搭建到问题排查,详细拆解全流程,即使无技术基础也能顺利部署本地AI助理。
6493 13
|
4天前
|
人工智能 机器人 Linux
保姆级 OpenClaw (原 Clawdbot)飞书对接教程 手把手教你搭建 AI 助手
OpenClaw(原Clawdbot)是一款开源本地AI智能体,支持飞书等多平台对接。本教程手把手教你Linux下部署,实现数据私有、系统控制、网页浏览与代码编写,全程保姆级操作,240字内搞定专属AI助手搭建!
3734 11
保姆级 OpenClaw (原 Clawdbot)飞书对接教程 手把手教你搭建 AI 助手
|
4天前
|
存储 人工智能 机器人
OpenClaw是什么?阿里云OpenClaw(原Clawdbot/Moltbot)一键部署官方教程参考
OpenClaw是什么?OpenClaw(原Clawdbot/Moltbot)是一款实用的个人AI助理,能够24小时响应指令并执行任务,如处理文件、查询信息、自动化协同等。阿里云推出的OpenClaw一键部署方案,简化了复杂配置流程,用户无需专业技术储备,即可快速在轻量应用服务器上启用该服务,打造专属AI助理。本文将详细拆解部署全流程、进阶功能配置及常见问题解决方案,确保不改变原意且无营销表述。
4039 5
|
6天前
|
人工智能 JavaScript API
零门槛部署本地 AI 助手:Clawdbot/Meltbot 部署深度保姆级教程
Clawdbot(Moltbot)是一款智能体AI助手,具备“手”(读写文件、执行代码)、“脚”(联网搜索、分析网页)和“脑”(接入Qwen/OpenAI等API或本地GPU模型)。本指南详解Windows下从Node.js环境搭建、一键安装到Token配置的全流程,助你快速部署本地AI助理。(239字)
4165 21