SSM整合
一、SSM整合
1. 整合流程
- 创建工程
- SSM整合
- Spring
- SpringConfig
- MyBatis
- MybatisConfig
- JdbcConfig
- jdbc.properties
- SpringMVC
- ServletConfig
- SpringMvcConfig
- Spring
- 功能模块
- 表与实体类
- dao(接口+自动代理)
- service(接口+实现类)
- 业务层接口测试(整合JUnit)
- controller
- 表现层接口测试(PostMan)
二、表现层数据封装
前端接收数据格式
- 创建结果模型类,封装数据到data属性中
- 封装操作结果到code属性中
- 封装特殊消息到message(msg)属性中
案例:
1.定义Result类:
public class Result { private Integer code; private Object data; 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.msg = msg; this.code = code; }; // 省略getter和setter(大部分情况不需要) };
2.定义状态码:
public class Code { public static final Integer SAVE_SUCCESS = 20011; public static final Integer UPDATE_SUCCESS = 20021; public static final Integer DELETE_SUCCESS = 20031; public static final Integer GET_SUCCESS = 20041; public static final Integer SAVE_FAIL = 20010; public static final Integer UPDATE_FAIL = 20020; public static final Integer DELETE_FAIL = 20030; public static final Integer GET_FAIL = 20040; // ...... };
Code类的常量设计不是固定的,可以根据需要自行增减,例如将查询再进行细分为GET_SUCCESS,GET_ALL_SUCCESS,GET_PAGE_SUCCESS
3.表现层代码:
@RestController @RequestMapping("/books") public class BookController { @Autowired private BookService bookService; @PostMapping public Result save(@RequestBody Book book) { boolean flag = bookService.save(book); return new Result(flag ? Code.SAVE_SUCCESS : Code.SAVE_FAIL, flag); }; @PutMapping public Result update(@RequestBody Book book) { boolean flag = bookService.update(book); return new Result(flag ? Code.UPDATE_SUCCESS : Code.UPDATE_FAIL, flag); }; @DeleteMapping("/{id};") public Result delete(@PathVariable Integer id) { boolean flag = bookService.delete(id); return new Result(flag ? Code.DELETE_SUCCESS : Code.DELETE_FAIL, flag); }; @GetMapping("/{id};") public Result getById(@PathVariable Integer id) { Book book = bookService.getById(id); Integer code = book != null ? Code.GET_SUCCESS : Code.GET_FAIL; String msg = book != null ? "" : "查询失败"; return new Result(code, book, msg); }; @GetMapping public Result getAll() { List<Book> books = bookService.getAll(); Integer code = books != null ? Code.GET_SUCCESS : Code.GET_FAIL; String msg = books != null ? "" : "查询失败"; return new Result(code, books, msg); }; };
设置统一数据返回结果类
public class Result { private Object data; private Integer code; private String msg; };
- Result类及其中的字段并不是固定的,可以根据需要自行修改
- 提供若干个构造方法,方便操作
三、异常处理器
出现异常现象的常见位置与常见诱因如下:
- 框架内部抛出的异常:因使用不合规导致
- 数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)
- 业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等)
- 表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)
- 工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)
所有异常均抛出到表现层处理
异常处理
表现层处理异常,每个方法中单独书写,代码书写量大且意义不强,一般采用A0P思想处理异常
异常处理器:
集中的、统一的处理项目中出现的异常e.g.
@RestControllerAdvice public class ProjectExceptionAdvice { @ExceptionHandler(Exception.class) public Result doException(Exception e) { System.out.println(e.getMessage()); return new Result(500, null, "服务器异常"); }; };
名称:
@RestControllerAdvice
类型:类注解
位置:Rest风格开发的控制器增强类定义上方
作用:为Rest风格开发的控制器类做增强
说明:此注解自带
@ResponseBody
注解与@Component
注解,具备对应的功能
- 名称:
@ExceptionHandler
- 类型:方法注解
- 位置:专用于异常处理的控制器方法上方
- 作用:设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行
- 说明:此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常
四、项目异常处理方案
1. 项目异常分类
- 业务异常(BusinessException)
- 规范的用户行为产生的异常
- 不规范的用户行为操作产生的异常
- 系统异常(SystemException)
- 项目运行过程中可预计且无法避免的异常
- 其他异常(Exception)
- 编程人员未预期到的异常
2. 项目异常处理方案:
- 业务异常(BusinessException)
- 发送对应消息传递给用户,提醒规范操作
- 系统异常(SystemException)
- 发送固定消息传递给用户
- 发送特定消息给运维人员,提醒维护
- 记录日志
- 其他异常(Exception)
- 发送固定消息传递给用户
- 发送特定消息给编程人员,提醒维护(纳入预期范围内)
- 记录日志
3. 步骤
自定义项目系统级异常
public class SystemException extends RuntimeException { private Integer code; public Integer getCode() { return 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; }; };
自定义项目业务级异常
public class BusinessException extends RuntimeException { private Integer code; public Integer getCode() { return 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; }; };
自定义异常编码(可选,自定义)
public class ErrorCode { public static final Integer SYSTEM_ERR = 50001; public static final Integer BUSINESS_ERR = 50002; public static final Integer UNKNOW_ERR = 59999; };
触发自定义异常
public Book getById(Integer id) { // 将可能出现的异常进行包装,转换成自定义异常 // 模拟异常 if (id == 1) throw new BusinessException(ErrorCode.BUSINESS_ERR, "id不能为1"); try { int i = 1 / 0; }; catch (Exception e) { throw new SystemException(ErrorCode.SYSTEM_ERR, "访问超时,请稍后再试", e); }; return bookDao.getById(id); };
拦截并处理异常
@RestControllerAdvice public class ProjectExceptionAdvice { @ExceptionHandler(SystemException.class) public Result doSystemException(SystemException e) { return new Result(e.getCode(), null, e.getMessage()); }; @ExceptionHandler(BusinessException.class) public Result doBusinessException(BusinessException e) { return new Result(e.getCode(), null, e.getMessage()); }; @ExceptionHandler(Exception.class) public Result doException(Exception e) { System.out.println(e.getMessage()); return new Result(ErrorCode.UNKNOW_ERR, null, "发生未知异常"); }; };
五、案例
Github仓库:SSM图书管理