Skip to content

Commit 54ee201

Browse files
committed
docs: 完善文档 使用指南#处理约束异常
1 parent b507114 commit 54ee201

File tree

2 files changed

+110
-6
lines changed

2 files changed

+110
-6
lines changed

document/web-docs/docs/guide/user-guide.md

+110-6
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
Latest Version:
1414
[![Maven Central](https://img.shields.io/maven-central/v/cn.sticki/spel-validator.svg)](https://central.sonatype.com/search?q=g:cn.sticki%20a:spel-validator)
1515

16-
大多少情况下,你只需要添加以下两个依赖:
16+
大多数情况下,你只需要添加以下两个依赖:
1717

1818
```xml
1919
<dependencys>
@@ -87,7 +87,7 @@ public class SimpleExampleParamVo {
8787

8888
`@SpelValid` 注解包含一个属性 `condition`,支持 SpEL 表达式。
8989

90-
**表达式的算结果为true** 时,表示开启校验,默认情况下开启校验
90+
**表达式的算结果为true** 时,表示开启校验,默认情况下是开启的
9191

9292
```java
9393
@Data
@@ -225,17 +225,121 @@ public class TestParamVo2 {
225225
}
226226
```
227227

228-
## 处理异常
229-
230-
待补充
228+
## 处理约束异常
231229

232230
当校验失败时,本组件会将异常信息上报到 `javax.validation` 的异常体系中。
233231

234-
所以正常情况下,你无需添加额外的异常处理逻辑。
232+
正常情况下,你只需要处理 `org.springframework.web.bind.MethodArgumentNotValidException`
233+
`org.springframework.validation.BindException` 这两个校验异常类就好了 ,而无需额外处理本组件的异常信息。
234+
235+
事实上,`MethodArgumentNotValidException` 继承自 `BindException`,只需要处理 `BindException` 就可以了。
236+
237+
```java
238+
@RestControllerAdvice
239+
public class ControllerExceptionAdvice {
240+
241+
@ExceptionHandler({BindException.class, MethodArgumentNotValidException.class})
242+
public Resp<Void> handleBindException(BindException ex) {
243+
String msg = ex.getFieldErrors().stream()
244+
.map(error -> error.getField() + " " + error.getDefaultMessage())
245+
.reduce((s1, s2) -> s1 + "," + s2)
246+
.orElse("");
247+
return new Resp<>(400, msg);
248+
}
249+
250+
}
251+
```
252+
253+
## 处理业务异常
254+
255+
由于本组件支持 [调用静态方法](spel.md#调用静态方法)[调用Spring Bean方法](spel.md#调用-spring-bean),故在校验过程中可能会抛出除约束异常以外的其他业务异常。
256+
257+
### 举一个不太恰当的例子
258+
259+
以下是一个枚举类,它包含了一个静态方法,用于根据code获取枚举值,如果获取不到则抛出业务异常:
235260

236261
```java
262+
@Getter
263+
public enum ExampleEnum {
264+
265+
XXX(1);
266+
267+
private final Integer code;
268+
269+
ExampleEnum(Integer code) {
270+
this.code = code;
271+
}
272+
273+
/**
274+
* 通过code获取枚举值,如果code不存在则抛出业务异常
275+
*/
276+
public static ExampleEnum getByCode(Integer code) {
277+
for (ExampleEnum value : values()) {
278+
if (value.code.equals(code)) {
279+
return value;
280+
}
281+
}
282+
throw new BusinessException(400, "枚举值不合法");
283+
}
284+
285+
}
237286
```
238287

288+
以下是一个参数类,它包含了一个枚举字段校验,在表达式中引用了上面的枚举类:
289+
290+
```java
291+
@Data
292+
@SpelValid
293+
public class ParamTestBean {
294+
295+
/**
296+
* 枚举值校验
297+
* <p>
298+
* 通过静态方法调用,校验枚举值是否存在
299+
*/
300+
@SpelAssert(assertTrue = "T(cn.sticki.validator.spel.enums.ExampleEnum).getByCode(#this.testEnum)")
301+
private Integer testEnum;
302+
303+
}
304+
```
305+
306+
`ParamTestBean` 校验失败时,我们希望它抛出一个业务异常 `BusinessException`,但实际上会得到一个 `ValidationException`
307+
308+
![img.png](../image/user-g-business-exception.png)
309+
310+
由于本组件的特殊性,所有抛出的异常信息最终都会被我们下层的校验器捕获,然后包一层 `javax.validation.ValidationException` 再抛出。
311+
312+
要从框架层面去解决这个问题,只能够脱离 `javax.validation` 的规范和 `hibernate` 的执行器来进行校验,
313+
目前看来这样做的成本比较大,且会带来一些其他的影响,故暂时不考虑这样做。
314+
315+
### 解决方案
316+
317+
当捕获到 `ValidationException` 时,首先判断下 `e.getCause()` 的类型是不是自己项目中的业务异常基类,如果是业务异常的类型,就丢给对应的方法去处理,像这样:
318+
319+
```java
320+
@RestControllerAdvice
321+
public class ControllerExceptionAdvice {
322+
323+
@ExceptionHandler({BusinessException.class})
324+
public Resp<Void> handleBusinessException(BusinessException ex) {
325+
return new Resp<>(ex.getCode(), ex.getMessage());
326+
}
327+
328+
@ExceptionHandler({ValidationException.class})
329+
public Resp<Void> handleValidationException(ValidationException ex) {
330+
if (ex.getCause() instanceof BusinessException) {
331+
return handleBusinessException((BusinessException) ex.getCause());
332+
}
333+
return new Resp<>(500, "system error");
334+
}
335+
336+
}
337+
```
338+
339+
当然这种方案也有缺点,需要将多种不同的异常类型都进行特殊处理,比较麻烦。
340+
341+
本人不才,目前只能想到这种方案,如果你有更好的解决方案,欢迎到 GitHub 提 [issue](https://github.com/stick-i/spel-validator/issues)
342+
239343
## 开启对 Spring Bean 的支持
240344

241345
默认情况下,解析器无法识别 SpEL 表达式中的 Spring Bean。
Loading

0 commit comments

Comments
 (0)