SSM开发基本规范
- 表现层数据的封装
- 异常处理类
- 项目异常处理方案
idea中自动装配的时候对bean类型做检测系统会爆红但是我们只要修改就可以了
1. 表现层数据封装(统一返回结果)
前端已经疯了 格式不统一
- 前端接收数据格式统一创建结果模型类,封装数据到data属性中
public class Result {
private Object data;
private Integer code;
private String msg;
public Result() {
}
public Result(Integer code,Object data) {
this.data = data;
this.code = code;
}
public Result(Integer code, Object data, String msg) {
this.data = data;
this.code = code;
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
前端接收数据格式统一创建结果模型类,封装数据到data属性中
约定好code
public class Code {
public static final Integer SAVE_OK = 20011;
public static final Integer DELETE_OK = 20021;
public static final Integer UPDATE_OK = 20031;
public static final Integer GET_OK = 20041;
public static final Integer SAVE_ERR = 20010;
public static final Integer DELETE_ERR = 20020;
public static final Integer UPDATE_ERR = 20030;
public static final Integer GET_ERR = 20040;
public static final Integer SYSTEM_ERR = 50001;
public static final Integer SYSTEM_TIMEOUT_ERR = 50002;
public static final Integer SYSTEM_UNKNOW_ERR = 59999;
public static final Integer BUSINESS_ERR = 60002;
}
他妈的还是会有问题
查询的数据不存在 又要一起约定修改
就是数据不存在还要告诉用户一声,不能一句话不说
还要封装message
- 设置统一数据返回结果类
- 自己定义格式不固定 还可以提供构造方法
设置code 异常代码(常量)
package com.itheima.controller;
//状态码 (常量)
public class Code {
public static final Integer SAVE_OK = 20011;
public static final Integer DELETE_OK = 20021;
public static final Integer UPDATE_OK = 20031;
public static final Integer GET_OK = 20041;
public static final Integer SAVE_ERR = 20010;
public static final Integer DELETE_ERR = 20020;
public static final Integer UPDATE_ERR = 20030;
public static final Integer GET_ERR = 20040;
}
result 表现层数据封装
package com.itheima.controller;
public class Result {
//描述统一格式中的数据
private Object data; //必须是Object
//描述统一格式中的编码,用于区分操作,可以简化配置0或1表示成功失败
private Integer code;
//描述统一格式中的消息,可选属性
private String msg;
//空参
public Result() {
}
// code data 构造方法
public Result(Integer code,Object data) {
this.data = data;
this.code = code;
}
// code data msg 构造方法
public Result(Integer code, Object data, String msg) {
this.data = data;
this.code = code;
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
AOP思想的运用:
有这么多的异常我们该怎么处理?
解决方案:
全部抛到 表现层 来处理异常
所有的异常均抛出到表现层进行处理
集中的统一处理项目中出现的异常
之前存在的问题:
- 把异常均抛出到表现层处理:代码书写量大且意义不强
- 我们不可能每个异常处理都一样 所以我们要分类处理,但是还是会存在问题 不能用try catch写
解决方案:AOP
AOP的思想但是我们不用写AOP
2. 异常处理器
按照他的格式来进行编写
@RestControllerAdvice 声明做异常处理的
声明做异常处理的
为Rest风格开发的控制器类做增强
@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器
@ExceptionHandler用于设置当前处理器类对应的异常类型
//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {
//@ExceptionHandler用于设置当前处理器类对应的异常类型
//1. 处理系统异常
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(ex.getCode(),null,ex.getMessage());
}
//2. 处理业务异常
@ExceptionHandler(BusinessException.class)
public Result doBusinessException(BusinessException ex){
return new Result(ex.getCode(),null,ex.getMessage());
}
//3. 除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
@ExceptionHandler(Exception.class)
public Result doOtherException(Exception ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");
}
}
@ExceptionHandler 声明处理异常的种类
专门用来拦截异常的 声明处理异常的种类
之前存在的问题:不规范的用户行为操作产生的异常
( )定义用来处理哪一种类型的异常
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(ex.getCode(),null,ex.getMessage());
}
@ExceptionHandler(BusinessException.class)
public Result doBusinessException(BusinessException ex){
return new Result(ex.getCode(),null,ex.getMessage());
}
@ExceptionHandler(Exception.class)
public Result doOtherException(Exception ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");
}
}
3. 项目异常处理方案
- 异常处理器
- 自定义异常
- 异常编码
- 自定义消息
- 业务异常
- 系统异常
- 其他异常
怎么做?
项目异常处理
1)自定义项目系统级异常
//先继承 运行时异常(他会把异常自动向上抛出)
public class SystemException extends RuntimeException{
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public SystemException(Integer code, String message) {
super(message);
this.code = code;
}
public SystemException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
2)自定义项目业务级异常
public class BusinessException extends RuntimeException{
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public BusinessException(Integer code, String message) {
super(message);
this.code = code;
}
public BusinessException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
3)自定义异常编码
4)模拟业务异常
5)拦截并处理异常
用构造方法把code data 传过去的值 会被异常处理类去接收
//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {
//@ExceptionHandler用于设置当前处理器类对应的异常类型
//1. 处理系统异常
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(ex.getCode(),null,ex.getMessage());
}
//2. 处理业务异常
@ExceptionHandler(BusinessException.class)
public Result doBusinessException(BusinessException ex){
return new Result(ex.getCode(),null,ex.getMessage());
}
//3. 除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
@ExceptionHandler(Exception.class)
public Result doOtherException(Exception ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");
}
}
6)异常处理效果对比
4. 全局异常处理器(瑞吉)
@ControllerAdvice
package com.itheima.reggie.common;
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.sql.SQLIntegrityConstraintViolationException;
/**
* 全局异常处理
*/
@ControllerAdvice(annotations = {RestController.class, ControllerAdvice.class})
@ResponseBody//方法返回的是JSON数据最终 封装成JSON数据并且返回
@Slf4j
public class GlobalExceptionHandler {
/**
* 异常处理方法 处理的是关于这个的异常SQLIntegrityConstraintViolationException
* @return
*/
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex) {
log.error(ex.getMessage());
if (ex.getMessage().contains("Duplicate entry")){
String[] split = ex.getMessage().split(" ");
String msg = split[2]+"已存在";
return R.error(msg);
}
return R.error("未知错误");
}
/**
* 自定义异常处理
* @param ex
* @return
*/
//TODO 在全局异常处理器中去处理自己的异常
@ExceptionHandler(CustomException.class)
public R<String> exceptionHandler(CustomException ex) {
log.error(ex.getMessage());
return R.error(ex.getMessage());
}
}
这里是设置了自定义异常处理
在项目中自定义一个全局异常处理器,在异常处理器上加上注解 @ControllerAdvice,可以通过属性annotations指定拦截哪一类的Controller方法。 并在异常处理器的方法上加上注解 @ExceptionHandler 来指定拦截的是那一类型的异常。
WebMvcConfigurationSupport
@Configuration //
public class SpringMvcSupport extends WebMvcConfigurationSupport {
/* @Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}
前端
SSM整合标准开发(了解)
5. 拦截器(Interceptor)
- 概念:是一种动态拦截的方法机制,在SpringMVC中动态拦截控制器方法的执行 拦截方法的调用
- 作用:
- 在指定的方法调用前后执行预先设定的代码(功能)
- 阻止原始方法的执行
简单的说:
拦截器只能对SpringMVC的访问进行增强
可以在控制器之前 或者之后执行
拦截器与过滤器区别
- 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC的激素和
- 拦截内容不同:拦截器Interceptor仅针对SpringMVC的访问进行增强,Filter对所有访问进行增强
制作拦截器
- 制作拦截器的功能类
- 配置拦截器的执行位置
创建一个interceptor包书写类 一般设置在controller中
实现HandlerInterceptor接口 然后覆盖三个方法 alt+insert override Methods
类:ProjectInterceptor
HandlerInterceptor
先去实现HandlerInterceptor接口
再去重写这三个方法
@Component: 因为拦截器是为SpringMVC服务的,SpringMVC的环境需要加载到它 受SpringMVC的管理
@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
@Override
//原始方法调用前执行的内容
//返回值类型可以拦截控制的执行,true放行,false终止
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String contentType = request.getHeader("Content-Type");
HandlerMethod hm = (HandlerMethod)handler;
System.out.println("preHandle...111"+contentType);
return true;
}
@Override
//原始方法调用后执行的内容
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...111");
}
@Override
//原始方法调用完成后执行的内容
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...111");
}
}
WebMvcConfigurationSupport 过滤访问资源
在继承WebMvcConfigurationSupport的类中 注入拦截器
addResourceHandlers
**addResourceHandlers (拦截器对象) 这里需要@Autowired注入拦截器 过滤访问的静态资源 **
如果return false;表示终止原始操作的运行
@Configuration //配置成为一个bean
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
//注入拦截器 projectInterceptor
private ProjectInterceptor projectInterceptor;
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}
@Override
protected void addInterceptors(InterceptorRegistry registry) {
//配置拦截器 访问books的时候拦截
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
}
}
步骤:
- 声明bena实现HandlerInterceptor接口
- 定义配置类,继承WebMvcConifgurationSupport实现addInterceptor方法(扫描加载配置)
- **添加具体的拦截器并设定拦截器的访问路径,路径可以通过可变参数设置多个 ** 设置哪个具体的拦截器 拦截什么请求
- 使用标准接口WebMvcConfigurer简化开发
1.声明bena实现HandlerInterceptor接口
2.定义配置类,继承WebMvcConifgurationSupport实现addInterceptor方法(扫描加载配置)
3.添加拦截器并设定拦截器的访问路径,路径可以通过可变参数设置多个
**4.使用标准接口WebMvcConfigurer简化开发 **
拦截器执行流程
拦截器参数
前置处理
后置处理