生产级别的通用异常处理

所有的异常都抛出,统一在表现层处理,其余直接抛出就好。

1580218612292-5dac3d0a-8202-482f-8454-1f16f7cd15ee.png

spring定义的错误响应方式如图所示。

使用Java提供的异常类抛出的时候只可以传递string,所以需要自定义一个异常类,继承RuntimeException,抛出的时候同时包含信息和状态码

1580257288867-682fa387-dcbd-44b5-a2bc-e2618f3b59a1.png

新建通用异常处理类

相当于aop里面的通知,起到拦截的作用,要做到通用,状态码不可以写死,这里的设计不对,后面会改进

src/main/java/com/deltaqin/common/advice/CommonExceptionHandler.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.deltaqin.common.advice;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

// aop拦截,相当于aop的通知
@ControllerAdvice
// 此拦截是针对controller的,默认拦截有controller注解的类
public class CommonExceptionHandler {

// 只是拦截处理特定的异常
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<String> handleException(RuntimeException e){
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());

}
}

common模块引入springMVC的依赖

需要controller注解

不需要启动器,只需要spring-webmvc里面的MVC

1
2
3
4
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>

自定义异常类

抛出的时候只抛出自定义的异常

src/main/java/com/deltaqin/common/exception/mallException.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.deltaqin.common.exception;

import com.deltaqin.common.enums.ExceptionEnums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Getter
public class mallException extends RuntimeException {

private ExceptionEnums exceptionEnums;
}

异常枚举类

具有固定实例个数的类,不像正常类无限制,类的对象是提前创建好的

src/main/java/com/deltaqin/common/enums/ExceptionEnums.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.deltaqin.common.enums;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum ExceptionEnums {

PRICE_CANNOT_BE_NALL(400, "价格不能为空"),
PRICE_CANNOT_BE(400, "价格不能为空")
;
private int code;
private String msg;
}

item-service模块引入自定义通用异常的依赖

1
2
3
4
5
<dependency>
<groupId>com.deltaqin.common</groupId>
<artifactId>common</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>

修改item-service抛出的异常

抛出异常的时候,不仅仅是传递信息还要传递状态码

src/main/java/com/deltaqin/item/web/ItemController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.deltaqin.item.web;

import com.deltaqin.common.enums.ExceptionEnums;
import com.deltaqin.common.exception.mallException;
import com.deltaqin.item.service.ItemService;
import com.deltaqin.item.pojo.Item;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("item")
public class ItemController {

@Autowired
private ItemService itemService;

@PostMapping
public ResponseEntity<Item> saveItem(Item item){
if (item.getPrice() == null) {
// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
// throw new RuntimeException("价格不能为空");
throw new mallException(ExceptionEnums.PRICE_CANNOT_BE_NALL);
}
item = itemService.saveItem(item);
return ResponseEntity.status(HttpStatus.CREATED).body(item);
}
}

修改通用异常处理类

src/main/java/com/deltaqin/common/advice/CommonExceptionHandler.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.deltaqin.common.advice;

import com.deltaqin.common.exception.mallException;
import com.deltaqin.common.vo.ExceptionResult;
//import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

// aop拦截,相当于aop的通知
@ControllerAdvice
// 此拦截是针对controller的,默认拦截有controller注解的类
public class CommonExceptionHandler {

// 只是拦截处理特定的异常
// @ExceptionHandler(mallException.class)
// public ResponseEntity<String> handleException(mallException e){
// ExceptionEnums em = e.getExceptionEnums();
// return ResponseEntity.status(em.getCode()).body(em.getMsg());
//
// }
@ExceptionHandler(mallException.class)
public ResponseEntity<ExceptionResult> handleException(mallException e){
return ResponseEntity.status(e.getExceptionEnums().getCode())
.body(new ExceptionResult(e.getExceptionEnums()));

}
}

自定义异常结果集

src/main/java/com/deltaqin/common/vo/ExceptionResult.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.deltaqin.common.vo;

import com.deltaqin.common.enums.ExceptionEnums;
import lombok.Data;

@Data
public class ExceptionResult {
private int status;
private String message;
private Long timestamp;

public ExceptionResult(ExceptionEnums em){
this.status = em.getCode();
this.message = em.getMsg();
this.timestamp = System.currentTimeMillis();
}
}

1580257315394-7d210355-bc47-42cf-83c4-1c6cbade5ca2.png

注意

  • 写代码报了一个小时错吗,老是让我定义一个service,我都懵逼了。。。居然是启动类的类名和service的类名一样了
  • 注意启动类的位置决定了可以扫描的包的位置。要放在com.deltaqin里面,不要再往里面放,不然导入common的时候扫不到com.deltaqin.common里面的内容