1.SSM整合
代码参考Springmvc_08_ssm
流程分析
- 添加依赖:pom.xml
- 编写配置类:
Spring
的配置类SpringConfig.javaSpringMVC
的配置类SpringMvcConfig.javaWeb
项目的入口配置类ServletConfig.javaMyBatis
的配置类MyBatisConfig.java- 第三方数据源的配置类JdbcConfig.java
- 创建数据库表:tbl_book.sql
- 根据数据库表创建对应的模型类:Book.java
- 通过
Dao
层完成数据库表的增删改查:BookDao.java- 编写
Service
层:BookServiceImpl.java和BookService.javabookDao
在Service
中注入的会提示一个红线提示,因为BookDao
是一个接口,没有实现类,最终注入的是代理对象,该代理对象需要等Web
服务器启动并完成IOC
容器的创建才会生成,但是可以正常运行- 编写
Controller
层:BookController.java
测试
- 对
Service
层进行测试:BookServiceTest.java- 使用
PostMan
对Controller
中接口进行测试
2.统一结果封装
在
Controller
层中会返回不同类型数据给前端(有boolean
值、单个对象的Json
或集合对象的Json
等),如果后台能够返回统一的数据结果,前端在解析时就可按照一种方式进行解析,简化开发。主要思想如下(即创建Result
类):
- 为了封装返回的结果数据:创建结果模型类,封装数据到
data
属性中(定义为Object
类型就可以接收所有类型的数据)- 为了封装返回的数据是何种操作及是否操作成功:封装操作结果到
code
属性中- 操作失败后为了封装返回的错误信息:封装特殊消息到
msg
属性中代码参考Springmvc_09_result
表现层与前端数据传输协议实现
和前端的传输协议其实就是定义数据以什么形式返回给前端,前端根据返回的结果,先从中获取
code
,根据code
判断,如果成功则取data
属性的值,如果失败则取msg
中的值做提示。具体流程如下:
- 环境准备:和之前类似,不再赘述
- 结果封装:
- 创建Result.java
- 定义返回码Code.java
- 修改
Controller
类的返回值为Result
类- 使用
PostMan
测试:看返回的Json
数据中三个属性是否符合预期
3.统一异常处理
假设在
Service
层某个方法执行过程中出现异常,此时返回给前端是500错误页面,前端开发人员无法处理。其实在开发的任何一个位置都有可能出现异常,需要思考以下问题:
- 各个层级均出现异常,异常处理代码书写在哪一层?不管是
Dao
层还是啥层,所有的异常全往上抛(即均抛出到表现层进行处理)- 异常的种类很多,表现层如何将所有的异常都处理到呢?对异常分类
- 表现层处理异常,每个方法中单独书写,代码书写量巨大且意义不强,如何解决?AOP
代码参考Springmvc_10_exception
异常处理器的使用
- 环境准备:和之前类似,不再赘述
- 创建异常处理器类ProjectExceptionAdvice.java
- 放置在
controller
包下确保SpringMvcConfig
能够扫描到该类,并且其中的方法可以视为和控制器方法具有一样的处理流程- 每个处理异常的方法返回的是
Result
类型的对象,因为需要返回给前端去解析
项目异常处理方案
为异常的种类有很多,如果每一个异常都对应一个
@ExceptionHandler
,那需要写许多方法来处理各自的异常,所以在处理异常之前需对异常进行分类:
- 业务异常(
BusinessException
):
- 规范的用户行为产生的异常,如在年龄框输入字符串
- 不规范的用户行为操作产生的异常,如用户故意传递错误数据
- 系统异常(
SystemException
):
- 项目运行过程中可预计但无法避免的异常,比如数据库或服务器宕机
- 其他异常(
Exception
):
- 编程人员未预期到的异常,如用到的文件不存在
对于上述三种异常,有以下解决流程:
- 业务异常:
- 发送对应消息传递给用户,提醒规范操作
- 系统异常:
- 发送固定消息传递给用户,比如系统繁忙,请稍后再试
- 发送特定消息给运维人员,提醒维护
- 记录日志
- 其他异常:
- 发送固定消息传递给用户
- 发送特定消息给编程人员,提醒维护(比如未做非空校验等)
- 记录日志
编码思路:
- 先通过自定义异常,完成BusinessException和SystemException的定义
- 让自定义异常类继承
RuntimeException
是为了后期在抛出这两个异常的时候,就不用在try-catch
或throws
- 自定义异常类中添加
code
属性是为了更好的区分异常是来自哪个业务- 将其他异常包装成自定义异常类型:使用
try-catch
或throws
皆可public Book getById(Integer id) { // 模拟业务异常,包装成自定义异常 if (id == 1) { throw new BusinessException(Code.BUSINESS_ERR, "请输入正确id!"); } // 模拟系统异常,将可能出现的异常进行包装,转换成自定义异常 try { int i = 1 / 0; } catch (Exception e) { throw new SystemException(Code.SYSTEM_TIMEOUT_ERR, "服务器访问超时,请重试!", e); } return bookDao.getById(id); }
- 在异常处理器类ProjectExceptionAdvice.java中对不同的异常进行处理
4.前后台协议联调
主要是前端代码的编写
代码参考Springmvc_11_page
5.拦截器
代码参考Springmvc_12_interceptor
拦截器概念
在介绍拦截器(
Interceptor
)前先大致了解下浏览器发送请求后整个流程:
- 浏览器发送一个请求会先到
Web
服务器(即Tomcat
)Tomcat
服务器接收到请求以后,会去判断请求的是静态资源还是动态资源- 静态资源会直接到
Tomcat
的项目部署目录下去直接访问- 动态资源需要交给项目的后台代码进行处理
- 在找到具体的方法前,可配置一/多个过滤器,按照顺序进行执行
- 然后进入到到中央处理器(
SpringMVC
中的内容),SpringMVC
会根据配置的规则进行拦截- 满足规则则进行处理,找到其对应的
Controller
类中的方法进行执行,完成后返回结果- 不满足规则则不进行处理
如果此时需要在每个
Controller
中的方法执行的前后添加业务,该如何实现?使用拦截器即可,它是一种动态拦截方法调用的机制,在SpringMVC
中动态拦截控制器方法的执行(可以理解为增强方法),主要作用如下:
- 在指定的方法调用前后执行预先设定的代码
- 阻止原始方法的执行
拦截器和过滤器之间的区别是什么?
- 归属不同:
Filter
属于Servlet
技术,Interceptor
属于SpringMVC
技术- 拦截内容不同:
Filter
对所有访问进行增强,Interceptor
仅针对SpringMVC
的访问进行增强
入门案例
环境准备:和之前类似,不再赘述
拦截器开发:
- 创建拦截器类ProjectInterceptor.java(因为是给表示层使用,所以放在
controller
包下)- 配置拦截器类:
- 未简化版则需要创建SpringMvcSupport.java,并且
SpringMVC
对SpringMvcSupport.java
所在包进行扫描- 简化版就不需要创建SpringMvcSupport.java(也就不需要额外扫描包),可直接在
SpringMvcSupport.java
中进行配置
拦截器参数
- 前置处理方法
preHandle
:该方法中可通过返回值来决定是否要进行放行,所以使用率较高// request:请求对象,可以获取请求数据中的内容 // response:响应对象 // handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装,意味着可获取方法的相关信息 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String contentType = request.getHeader("Content-Type"); HandlerMethod hm = (HandlerMethod) handler; String name = hm.getMethod().getName(); System.out.println("preHandle..." + contentType); System.out.println("preHandle..." + name); return true; }
- 后置处理方法
postHandle
:// modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息并进行调整(现在都返回json数据,该参数使用率不高) public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle..."); }
- 完成处理方法
afterCompletion
:// ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理(现在已有全局异常处理器类,该参数的使用率不高) public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion..."); }
拦截器链配置
在项目中如果有多个拦截器,它们的执行顺序是什么?拦截器执行的顺序和配置顺序有关
- 当配置多个拦截器时,形成拦截器链
- 拦截器链的运行顺序参照拦截器添加顺序为准
- 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
- 当拦截器运行中断,仅运行配置在前面的拦截器的
afterCompletion
操作
参考
https://www.bilibili.com/video/BV1Fi4y1S7ix?p=59-74