目录
- SSM整合
- 统一异常处理
- 项目异常处理方案
- 异常解决方案
- 前后端协议联调
- 拦截器
SSM整合
统一异常处理
-
异常的种类及出现异常的原因:
- 框架内部抛出的异常:因使用不合规导致
- 数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)
- 业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等)
- 表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)
- 工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)
-
各个层级均出现异常,异常处理代码写在哪一层
- 所有的异常均抛出到表现层进行处理
-
异常的种类很多,表现层如何将所有的异常都处理到呢?
- 异常分类
-
表现层处理异常,每个方法中单独书写,代码书写量巨大且意义不强,如何解决?
- AOP
- 异常处理器 : 集中统一的处理项目中出现的异常
//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {//除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常@ExceptionHandler(Exception.class)public void doException(Exception ex){System.out.println("嘿嘿,异常你哪里跑!")}
}
项目异常处理方案
- 项目异常分类
-
业务异常(BusinessException)
- 规范的用户行为产生的异常
- 用户在页面输入内容的时候未按照指定格式进行数据填写,如在年龄框输入的是字符串
- 不规范的用户行为产生的异常
- 用户故意传递错误数据
- 规范的用户行为产生的异常
-
系统异常(SystemException)
- 项目运行过程中可预计但无法避免的异常
- 比如数据库或服务器宕机
- 项目运行过程中可预计但无法避免的异常
-
其他异常(Exception)
- 编程人员未预期到的异常,如:用到的文件不存在
-
异常解决方案
- 业务异常(BusinessException)
- 发送对应消息传递给用户,提醒规范操作
- 大家常见的就是提示用户名已存在或密码格式不正确等
- 发送对应消息传递给用户,提醒规范操作
- 系统异常(SystemException)
- 发送固定消息传递给用户,安抚用户
- 系统繁忙,请稍后再试
- 系统正在维护升级,请稍后再试
- 系统出问题,请联系系统管理员等
- 发送特定消息给运维人员,提醒维护
- 可以发送短信、邮箱或者是公司内部通信软件
- 记录日志
- 发消息和记录日志对用户来说是不可见的,属于后台程序
- 发送固定消息传递给用户,安抚用户
- 其他异常(Exception)
- 发送固定消息传递给用户,安抚用户
- 发送特定消息给编程人员,提醒维护(纳入预期范围内)
- 一般是程序没有考虑全,比如未做非空校验等
- 记录日志
前后端协议联调
- 添加了静态资源,SpringMVC会拦截,所有需要在SpringConfig的配置类中将静态资源进行放行。
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");registry.addResourceHandler("/css/**").addResourceLocations("/css/");registry.addResourceHandler("/js/**").addResourceLocations("/js/");registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");}
}
在SpringMvcConfig中扫描SpringMvcSupport
@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"})
@EnableWebMvc
public class SpringMvcConfig {
}
- 异步请求
<script>var vue = new Vue({el: '#app',data:{pagination: {},dataList: [],//当前页要展示的列表数据formData: {},//表单数据dialogFormVisible: false,//控制表单是否可见dialogFormVisible4Edit:false,//编辑表单是否可见rules: {//校验规则type: [{ required: true, message: '图书类别为必填项', trigger: 'blur' }],name: [{ required: true, message: '图书名称为必填项', trigger: 'blur' }]}},//钩子函数,VUE对象初始化完成后自动执行created() {this.getAll();},methods: {//列表getAll() {// 发送 ajax 请求axios.get("/books").then((res) => {this.dataList = res.data.data;});},//弹出添加窗口handleCreate() {this.dialogFormVisible = true;this.resetForm();},//重置表单resetForm() {this.formData = {};},//添加handleAdd () {axios.post("/books",this.formData).then((res)=>{console.log(res.data);// 如果操作成功,关闭弹层,显示数据if (res.data.code == 20011) {this.dialogFormVisible = false;this.$message.success("添加成功");} else if (res.data.code == 20010) {this.$message.error("添加失败");} else {this.$message.error(res.data.msg);}}).finally(()=>{this.getAll();});},//弹出编辑窗口handleUpdate(row) {// console.log(row);// 根据 id 查询数据// 展示弹层,加载数据axios.get("/books/" + row.id).then((res) => {// console.log(res.data.data);if (res.data.code == 20041) {this.formData = res.data.data;this.dialogFormVisible4Edit = true;} else {this.$message.error(res.data.msg);}})},//编辑handleEdit() {axios.put("/books",this.formData).then((res)=>{// 如果操作成功,关闭弹层,显示数据if (res.data.code == 20031) {this.dialogFormVisible4Edit = false;this.$message.success("编辑成功");} else if (res.data.code == 20030) {this.$message.error("编辑失败");} else {this.$message.error(res.data.msg);}}).finally(()=>{this.getAll();});},// 删除handleDelete(row) {// 1. 弹出提示框this.$confirm("此操作永久删除当前数据,是否继续","提示",{type:'info'}).then(()=>{// 2. 做删除业务axios.delete("/books/" + row.id).then((res) => {if (res.data.code == 20021) {this.$message.success("删除成功");} else {this.$message.error("删除失败");}}).finally(()=>{this.getAll();});}).catch(()=>{// 3. 取消删除操作this.$message.info("取消删除操作");});}}})</script>
拦截器
-
拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
-
作用:
- 在指定的方法调用前后执行预先设定的代码
- 阻止原始方法的执行
- 总结:拦截器就是用来做增强
-
拦截器和过滤器的区别
- 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
- 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强
-
让类实现HandlerInterceptor接口,重写接口中的三个方法。
@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {@Override//原始方法调用前执行的内容public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle...");return true;}@Override//原始方法调用后执行的内容public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle...");}@Override//原始方法调用完成后执行的内容public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion...");}
}
注意:拦截器类要被SpringMVC容器扫描到。
- 配置拦截器类
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {@Autowiredprivate ProjectInterceptor projectInterceptor;@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");}@Overrideprotected void addInterceptors(InterceptorRegistry registry) {//配置拦截器registry.addInterceptor(projectInterceptor).addPathPatterns("/books" );}
}
- SpringMVC添加SpringMvcSupport包扫描
@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"})
@EnableWebMvc
public class SpringMvcConfig{}
-
拦截器的访问路径可以通过可变参数设置多个
-
最后说一件事,就是拦截器中的
preHandler
方法,如果返回true,则代表放行,会执行原始Controller类中要请求的方法,如果返回false,则代表拦截,后面的就不会再执行了。 -
使用标准接口 WebMvcConfigurer 简化开发(侵入式较强)
@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {@Autowiredprivate ProjectInterceptor projectInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//配置多拦截器registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");}
}
-
拦截器参数
- handler: 被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装
- modelAndView: 如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整
- ex: 如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理
-
拦截器执行的顺序是和配置顺序有关。就和前面所提到的运维人员进入机房的案例,先进后出。
- 当配置多个拦截器时,形成拦截器链
- 拦截器链的运行顺序参照拦截器添加顺序为准
- 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
- 当拦截器运行中断,仅运行配置在前面的拦截器的 afterCompletion 操作