使用 ExceptionHandler 处理业务流程的异常情况

都在说这是啥,我来告诉你怎么用!

Problem

在业务实现过程中,我们可能会有类似如下的场景,要实现一个下单功能,除了下单正常执行的流程之外,我们还可能需要处理各种的业务异常情况,比如说下单的用户在服务端找不到,下单的商品在服务端找不到等等的业务异常情况(注意是业务异常),这时可能会有如下的伪代码,用户找不到时,给客户端响应 http status 为 500,http body 里的内容为一个 map 对象;如果是正常执行完毕,则给客户端的响应为 http status 200,http body 里的内容为订单的id。

//controller
@RequestMapping
public Object place(HttpServletResponse response,String userId,OrderDTO orderDTO) {
	Map result = new HashMap<>();
	Uzer uzer = orderService.findById(userId);

	if (ObjectUtils.isEmpty(uzer)) {
		result.put("msg", String.format("User %s not be found",userId));
		response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.ordinal());
		return result;
	}
	
	response.setStatus(HttpStatus.OK.ordinal());
	String orderId = orderService.place(userId, orderDTO);
	return orderId;
} 

//service
public String place(String userId, OrderDTO orderDTO) {
	// 正常逻辑
	Uzer uzer = userRepository.findById(userId);
	// 正常逻辑	
	Order order = new Order();
	//assembler form OrderDto
	Order o = orderRepository.save(order);
	return o.id;
}

上面的代码特别丑,比如用了 Spring MVC ,还在方法上传入了 HttpServletResponse 对象;因为不同的情况返回的内容不同,返回值只能是Object,Java的强类型在此一无是处;

Spring MVC Support

如上例所示,一个业务流程的正常情况和异常情况,返回给客户端的响应码,响应体的格式都是不同的;那有没有一种方法可以分开返回业务正常执行成功之后的响应内容和业务的各种异常情况下的响应内容呢?
Spring MVC 的 Exception Handler 机制,完美的解决了这个问题。

//controller
@RequestMapping(value="/place")
@ResponseStatus(code=HttpStatus.CREATED)
public String place(String userId, OrderDTO orderDTO) {
	String orderId = orderService.place(userId, orderDTO);
	return orderId;
}

//service
public String place(String userId, OrderDTO orderDTO) {
	// 正常逻辑
	Uzer uzer = userRepository.findById(userId);

	if (ObjectUtils.isEmpty(uzer)) {
		throw new PlaceOrderException(String.format("User %s is not found", userId));
	}

	// 正常逻辑
	Order order = new Order();
	//assembler form OrderDto
	Order o = orderRepository.save(order);
	return o.id;
}

// exception handler
@ExceptionHandler
@ResponseStatus(value = HttpStatus.OK)
public DRuntimeException dealException(PlaceOrderException e) {
	DRuntimeException exception = new DRuntimeException(e);
	return exception;
}

上述伪代码解耦了下单这个流程的正常业务逻辑和异常业务结果的处理。在 service 层,如果遇到业务异常的情况,只抛出异常,不做其他任何处理。Spring MVC 捕获此异常,并回调 Exception Handler 的方法并将此异常传给此异常处理的逻辑。
解耦之后,在 controller 层,只管构建成功执行的结果,标注的 @ResponseStatus 指定 http 响应的影响码,controller 的返回结果指定响应的内容。
在 ExceptionHandler 中处理异常的情况,可以给此异常,单独指定 ResponseStatus 和 响应内容;
如果业务的异常情况想控制的更精细,可以定义更多的异常类,用于代表不同的异常情况,然后就可以给不同的 ExceptionHandler 写单独的处理逻辑,指定各自的响应码和响应体。

More

@ExceptionHandler 是 Web 应用里使用的,如果输入输出是消息中间件,Spring Messaging 模块还定义了 @MessageExceptionHandler 。

你可能感兴趣的:(Spring)