SpringMVC(四)【SSM 整合、统一结果封装、异常处理、前后台协议联调】(1)https://developer.aliyun.com/article/1534216
1.5、接口测试
业务层接口测试(Junit)、表现层接口测试(Postman)
1.5.1、业务层接口测试
这里使用 Spring 整合了 Junit:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class BookServiceTest { @Autowired private BookService bookService; @Test public void testGetById(){ Book book = bookService.getById(1); System.out.println(book); } @Test public void testGetAll(){ for(Book book: bookService.getAll()) System.out.println(book); } }
测试结果:
1.6、表现层数据封装模型
现在当前端发送请求后返回的数据格式并不一致:
所以现在我们需要对前后端数据进行整合,统一格式。我们把前端需要接收的数据统一封装到 data 属性中;为了区分不同的操作,还会将操作类型封装到 code 属性中;对于失败的消息还会把后端希望返回的错误信息封装到一个 message(msg)属性中:
所以,以后我们要把需要所有返回给前端的结果进行统一封装,我们定义一个 Result 类:
- 这个类名和字段可以随便增改
1.6.1、表现层与前端数据传输协议实现
其实也就是把上一节后端返回给前端的结果类型实现一下,我们需要把这些类型写在 controller 包下,毕竟是和表现层相关的:
1.6.2、Result
package com.lyh.controller; 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; } }
1.6.3、Code
状态类(编码结果为0代表失败,结果为1代表成功,越细越好):
package com.lyh.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; }
定义好了返回给前端的类型后,我们当然要把 BookController 中所有控制器方法的返回值改为 Result 类型:
@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_OK:Code.SAVE_ERR,flag); } @PutMapping public Result update(@RequestBody Book book) { boolean flag = bookService.update(book); return new Result(flag ? Code.UPDATE_OK:Code.UPDATE_ERR,flag); } @DeleteMapping("/{id}") public Result delete(@PathVariable Integer id) { boolean flag = bookService.delete(id); return new Result(flag ? Code.DELETE_OK:Code.DELETE_ERR,flag); } @GetMapping("/{id}") public Result getById(@PathVariable Integer id) { Book book = bookService.getById(id); Integer code = book != null ? Code.GET_OK:Code.GET_ERR; 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_OK:Code.GET_ERR; String msg = books != null ? "":"查询失败,请重试!"; return new Result(code,books,msg); } }
测试:
查询所有书籍:
查询 id=10 的书籍:
可以看到,现在不管是查询什么内容,成功或失败,返回的结果都是 json 格式,至于返回的 Result 对象有哪些属性,这是我们后端程序员和前端需要商量的。
1.7、异常处理器
如果我们的后端返回没有问题倒也没事,如果我们后端程序出现了异常,那么将会给前端返回一个 html 页面(404或者500等),所以我们就得处理这种不可避免的异常问题:
1.7.1、常见异常出现的位置及原因
- 框架内部:使用不合规
- 数据层:外部服务器故障(访问超时)
- 业务层:业务逻辑书写错误(下标越界)
- 表现层(和用户交互的层):数据收集、校验规则导致(不匹配的数据类型)
- 工具类:工具类不够严谨不够健壮(连接没有及时释放)
问题1:各个层都可能会出现异常,那异常处理代码写到哪一层?
答:所有的异常均抛出到表现层进行处理。
问题2:让表现层处理异常,每个方法都去 try-catch 代码量太大了,怎么办?
答:用 AOP 思想解决。
事实是 SpringMVC 帮我们提供了异常处理器,而并不需要我们自己实现:
1.7.2、创建异常处理器
在 controller(表现层)下创建一个异常处理器类:
// 这个类必须被 SpringMVC 加载 @RestControllerAdvice public class ProjectExceptionAdvice { @ExceptionHandler(IndexOutOfBoundsException.class) public Result doException(IndexOutOfBoundsException e){ System.out.println("下标越界异常"+e.getMessage()); return new Result(666,null,"报错啦"); } }
- 这里的类注解代表使用 REST 风格开发控制器的话用这种注解来进行异常处理,如果不是 REST 风格的话换成 @ControllerAdvice 即可;这里的方法注解 @ExceptionHandler 相当于声明这个方法会把捕获到的哪种异常类传进去 。
- 这里我们返回的类型同样是 Rsult 类,毕竟是返回给前端的,不然前端得不到返回值会一直等。
测试:
异常处理器添加返回值(Result类型)后:
这样,我们的前端程序媛就可以根据返回值把异常界面做的漂亮一点。
1.7.3、项目异常处理
项目异常分类
- 业务异常:比如程序员故意发一些错误的请求故意折腾我们的系统,或者老实人发一些不规则的数据比如 age=谢永强
- 系统异常:比如数据库服务器宕机、服务器炸了
- 其它异常:文件找不到(未预期到的异常)
项目异常处理方案
- 业务异常:发送消息给用户,让它老实点,别瞎弄
- 系统异常:安抚用户,然后赶紧告诉运维人员,并记录日志
- 其它异常:安抚用户,然后开发人员,并记录日志
SpringMVC(四)【SSM 整合、统一结果封装、异常处理、前后台协议联调】(3)https://developer.aliyun.com/article/1534220