全局异常处理器的基本使用

那使用全局异常处理器可以么?

是的,使用全局异常处理器是一个非常好的选择,因为它可以将异常处理逻辑集中化,避免在 Service 层或 Controller 层中重复编写异常处理代码。以下是使用全局异常处理器来处理添加用户时 username 唯一约束冲突的完整实现方案:


1. 全局异常处理器的优势

  • 集中管理:所有异常处理逻辑集中在一个地方,便于维护和扩展。
  • 代码简洁Service 层和 Controller 层只需关注业务逻辑,不需要处理异常。
  • 统一响应格式:可以确保所有异常返回的响应格式一致,提升 API 的规范性。

2. 实现步骤

步骤 1:定义自定义异常

为了更好地区分业务异常,可以定义一个自定义异常类。

java

换行复制代码

1public class BusinessException extends RuntimeException {
2    public BusinessException(String message) {
3        super(message);
4    }
5}

步骤 2:在 Service 层抛出异常

在 UserService 层中,如果检测到 username 已存在,抛出 BusinessException

java

换行复制代码

1import org.springframework.beans.factory.annotation.Autowired;
2import org.springframework.dao.DuplicateKeyException;
3import org.springframework.stereotype.Service;
4
5@Service
6public class UserServiceImpl implements UserService {
7
8    @Autowired
9    private UserMapper userMapper;
10
11    @Override
12    public void addUser(User user) {
13        try {
14            int affectedRows = userMapper.addOneUser(user);
15            if (affectedRows != 1) {
16                throw new RuntimeException("添加用户失败,影响行数为 " + affectedRows);
17            }
18        } catch (DuplicateKeyException e) {
19            // 捕获唯一约束异常
20            throw new BusinessException("用户名已存在");
21        }
22    }
23}

步骤 3:实现全局异常处理器

使用 @ControllerAdvice 和 @ExceptionHandler 注解,创建一个全局异常处理器,统一处理 BusinessException 和其他异常。

java

换行复制代码

1import org.springframework.http.HttpStatus;
2import org.springframework.http.ResponseEntity;
3import org.springframework.web.bind.annotation.ControllerAdvice;
4import org.springframework.web.bind.annotation.ExceptionHandler;
5import org.springframework.web.bind.annotation.ResponseBody;
6
7@ControllerAdvice
8public class GlobalExceptionHandler {
9
10    // 处理自定义业务异常
11    @ExceptionHandler(BusinessException.class)
12    @ResponseBody
13    public ResponseEntity<Map<String, Object>> handleBusinessException(BusinessException e) {
14        Map<String, Object> response = new HashMap<>();
15        response.put("code", 409); // 409 Conflict
16        response.put("message", e.getMessage());
17        return new ResponseEntity<>(response, HttpStatus.CONFLICT);
18    }
19
20    // 处理其他异常
21    @ExceptionHandler(Exception.class)
22    @ResponseBody
23    public ResponseEntity<Map<String, Object>> handleGenericException(Exception e) {
24        Map<String, Object> response = new HashMap<>();
25        response.put("code", 500); // 500 Internal Server Error
26        response.put("message", "系统错误,请稍后重试");
27        return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
28    }
29}

步骤 4:在 Controller 层调用 Service 层

在 Controller 层中,直接调用 UserService 的方法,无需处理异常。

java

换行复制代码

1import org.springframework.beans.factory.annotation.Autowired;
2import org.springframework.http.ResponseEntity;
3import org.springframework.web.bind.annotation.PostMapping;
4import org.springframework.web.bind.annotation.RequestBody;
5import org.springframework.web.bind.annotation.RequestMapping;
6import org.springframework.web.bind.annotation.RestController;
7
8@RestController
9@RequestMapping("/users")
10public class UserController {
11
12    @Autowired
13    private UserService userService;
14
15    @PostMapping
16    public ResponseEntity<String> addUser(@RequestBody User user) {
17        userService.addUser(user);
18        return ResponseEntity.ok("用户添加成功");
19    }
20}

3. 完整流程

  1. Controller 层 调用 UserService 的 addUser 方法。
  2. UserService 层 执行 INSERT 操作:
    • 如果成功,返回 void
    • 如果因为 username 唯一约束失败,抛出 BusinessException
  3. 全局异常处理器 捕获 BusinessException,返回 409 状态码和错误信息。
  4. Controller 层 根据 UserService 的返回值或全局异常处理器的响应,返回最终的 HTTP 响应。

4. 示例响应

添加成功

json

换行复制代码

1{
2    "code": 200,
3    "message": "用户添加成功"
4}
用户名已存在

json

换行复制代码

1{
2    "code": 409,
3    "message": "用户名已存在"
4}
系统错误

json

换行复制代码

1{
2    "code": 500,
3    "message": "系统错误,请稍后重试"
4}

5. 优点

  • 代码简洁Controller 层和 Service 层只需关注业务逻辑,异常处理由全局异常处理器统一管理。
  • 可扩展性强:如果需要处理更多类型的异常,只需在全局异常处理器中添加新的 @ExceptionHandler 方法。
  • 统一响应格式:所有异常返回的响应格式一致,便于前端处理。

6. 注意事项

  • 异常分类:根据业务需求,可以定义更多的自定义异常类(如 ValidationExceptionNotFoundException 等),并在全局异常处理器中分别处理。
  • 日志记录:在全局异常处理器中记录异常日志,便于排查问题。
  • 国际化:如果需要支持多语言,可以在全局异常处理器中根据请求头或用户偏好返回相应的错误信息。

通过这种方式,可以构建一个健壮且易于维护的异常处理机制。

在Java EE应用程序中,全局异常处理器通常用于捕获并处理在整个应用范围内的未知或未预期的异常。当发生如数学运算异常这运行时异常时,如果没有显式地在方法级别处理,你可以创建一个异常过滤器(Filter)或异常处理器(ExceptionHandler)来统一处理这种场景,并将其重定向到预先定义的错误页面(如error.jsp)。 以下是基本步骤: 1. **创建全局异常过滤器**:在`web.xml`文件中,定义一个`<filter>`标签,指定一个`Filter`实现,比如`GlobalExceptionHandlerFilter`。这个需要实现`javax.servlet.Filter`接口,覆盖`doFilter()`方法来处理请求。 ```xml <filter> <filter-name>GlobalExceptionHandler</filter-name> <filter-class>com.example.GlobalExceptionHandlerFilter</filter-class> </filter> <filter-mapping> <filter-name>GlobalExceptionHandler</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` 2. **捕获异常**:在`GlobalExceptionHandlerFilter`的`doFilter()`方法中,设置一个try-catch块来捕获所有`RuntimeException`及其子,包括数学运算异常。 ```java @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { chain.doFilter(request, response); } catch (RuntimeException e) { handleException(e, (HttpServletResponse) response); } } ``` 3. **处理异常并重定向**:在`handleException()`方法中,将异常信息存储到`HttpServletResponse`,然后使用`sendRedirect()`方法跳转到`error.jsp`。 ```java private void handleException(Exception ex, HttpServletResponse response) { // Log the exception for debugging purposes logger.error("Error caught", ex); // Set the error message and status code response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); PrintWriter writer = response.getWriter(); writer.println("<h1>Error: " + ex.getMessage() + "</h1>"); // Write any additional information you want to display in error.jsp writer.flush(); writer.close(); // Redirect to the error page response.sendRedirect("/error.jsp"); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值