Objective
In a Web application, exceptions are very common when request processing occurs. Therefore, when the application of various types of anomalies, the exception of the capture or two processing (such as SQL Anomaly can not be thrown out) is very necessary, such as in the development of external API services, agreed to the parameters of the response format, such as, the respCode
respMsg
caller based on the error code to carry out their own business logic. This chapter focuses on the unification of exceptions and data validation processing.
springboot
, by default, when sending an exception, the Jump value /error
request is displayed incorrectly, depending on the different Content-Type
error results, such as JSON request, the JSON format parameters are returned directly.
When a browser accesses an exception:
postman
When using Access:
- Unified exception Handling
- Creating a global uniform exception handling class
- Data validation
- Summarize
- At last
Cliché
Unified exception Handling
Obviously, the default exception page is not friendly to the user or the caller, so we generally do the exception tip information to implement our own business.
Creating a global uniform exception handling class
Use @ControllerAdvice
and @ExceptionHandler
define a unified exception handling class
@ControllerAdvice: Controller enhancements that enable the @exceptionhandler, @InitBinder, @ModelAttribute annotation methods to be applied to all @RequestMapping annotations.
@ExceptionHandler: Exception handler, which is used to process a defined exception when it appears
Create Exception class: Commonexceptionhandler
@ControllerAdvicepublic class CommonExceptionHandler { /** * 拦截Exception类的异常 * @param e * @return */ @ExceptionHandler(Exception.class) @ResponseBody public Map<String,Object> exceptionHandler(Exception e){ Map<String,Object> result = new HashMap<String,Object>(); result.put("respCode", "9999"); result.put("respMsg", e.getMessage()); //正常开发中,可创建一个统一响应实体,如CommonResp return result; }}
Extra different exceptions (such as custom exceptions), when different exception handling is required, you can write multiple exceptionhandler methods, annotations ExceptionHandler
Specify the exception classes to be handled, such as
/** * 拦截 CommonException 的异常 * @param ex * @return */ @ExceptionHandler(CommonException.class) @ResponseBody public Map<String,Object> exceptionHandler(CommonException ex){ log.info("CommonException:{}({})",ex.getMsg(), ex.getCode()); Map<String,Object> result = new HashMap<String,Object>(); result.put("respCode", ex.getCode()); result.put("respMsg", ex.getMsg()); return result; }
due to the addition @ResponseBody
, the returned json
format is
Indicates that the exception has been intercepted.
can intercept different anomalies, to carry out different abnormal hints, such as,, and NoHandlerFoundException
HttpMediaTypeNotSupportedException
AsyncRequestTimeoutException
so on , here is not listed, the reader can join their own after the actual operation.
Returns when the page is returned ModelAndView
, as
@ExceptionHandler(value = Exception.class) public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception { ModelAndView mav = new ModelAndView(); mav.addObject("exception", e); mav.addObject("url", req.getRequestURL()); mav.setViewName(DEFAULT_ERROR_VIEW); return mav; }
Since the work is only a front-end separation of development mode, so generally there is no direct return to the requirements of the resource page, generally return a fixed response format, such as,, respCode
respMsg
data
The front end through respCode
the value of the judgment of business judgment, is the pop window or jump page.
Data validation
In the Web development, for the request parameters, the general need to verify the validity of the parameters, the original method of writing a field by one to judge, this way is not universal, so Java JSR 303: Bean Validation
specification is to solve the problem.
JSR 303
Just a specification, and there is no specific implementation, the current is usually only hibernate-validator
to carry out uniform parameter verification.
JSR303 the type of validation defined
Constraint |
More Information |
@Null |
The annotated element must be anull |
@NotNull |
The annotated element must not be anull |
@AssertTrue |
The annotated element must be atrue |
@AssertFalse |
The annotated element must be afalse |
@Min(value) |
The annotated element must be a number whose value must be greater than or equal to the specified minimum value |
@Max(value) |
The annotated element must be a number whose value must be less than or equal to the specified maximum value |
@DecimalMin(value) |
The annotated element must be a number whose value must be greater than or equal to the specified minimum value |
@DecimalMax(value) |
The annotated element must be a number whose value must be less than or equal to the specified maximum value |
@Size(max, min) |
The size of the annotated element must be within the specified range |
@Digits (integer, fraction) |
The annotated element must be a number whose value must be within an acceptable range |
@Past |
The annotated element must be a past date |
@Future |
The annotated element must be a future date |
@Pattern(value) |
The annotated element must conform to the specified regular expression |
Hibernate Validator Additional constraint
Constraint |
More Information |
@Email |
The annotated element must be an e-mail address |
@Length |
The size of the annotated string must be within the specified range |
@NotEmpty |
The annotated string must be non-empty |
@Range |
The annotated element must be within the appropriate range |
Create an entity class
@Data@NoArgsConstructor@AllArgsConstructorpublic class DemoReq { @NotBlank(message="code不能为空") String code; @Length(max=10,message="name长度不能超过10") String name;}
Then in the control layer method, you can add @Valid
, so that before the visit, the request parameters will be tested.
@GetMapping("/demo/valid") public String demoValid(@Valid DemoReq req) { return req.getCode() + "," + req.getName(); }
startup, after accesshttp://127.0.0.1:8080/demo/valid
When the correct parameters are added,http://127.0.0.1:8080/demo/valid?code=3&name=s
So the unified calibration of the data is completed, for the use of other annotations, we can Google, basically all very simple, for the existing annotations can not meet the verification needs, but also for the development of custom annotations, a brief explanation, the compilation of custom annotations
If you do not use @valid, you can also write a tool class programmatically to verify the entity parameters.
public class ValidatorUtil { private static Validator validator = ((HibernateValidatorConfiguration) Validation .byProvider(HibernateValidator.class).configure()).failFast(true).buildValidatorFactory().getValidator(); /** * 实体校验 * * @param obj * @throws CommonException */ public static <T> void validate(T obj) throws CommonException { Set<ConstraintViolation<T>> constraintViolations = validator.validate(obj, new Class[0]); if (constraintViolations.size() > 0) { ConstraintViolation<T> validateInfo = (ConstraintViolation<T>) constraintViolations.iterator().next(); // validateInfo.getMessage() 校验不通过时的信息,即message对应的值 throw new CommonException("0001", validateInfo.getMessage()); } }}
Use
@GetMapping("/demo/valid") public String demoValid(@Valid DemoReq req) { //手动校验 ValidatorUtil.validate(req); return req.getCode() + "," + req.getName(); }
Custom Check Annotations
Custom annotations, the primary implementation ConstraintValidator
of the processing class can be, here has written a checksum constant annotation as an example: The parameter value can only be a specific value.
Custom annotations
@Documented//指定注解的处理类@Constraint(validatedBy = {ConstantValidatorHandler.class })@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })@Retention(RUNTIME)public @interface Constant { String message() default "{constraint.default.const.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String value();}
Annotation processing Classes
public class ConstantValidatorHandler implements ConstraintValidator<Constant, String> { private String constant; @Override public void initialize(Constant constraintAnnotation) { //获取设置的字段值 this.constant = constraintAnnotation.value(); } @Override public boolean isValid(String value, ConstraintValidatorContext context) { //判断参数是否等于设置的字段值,返回结果 return constant.equals(value); }}
Use
@Constant(message = "verson只能为1.0",value="1.0") String version;
Run:
At this point, the custom annotations are in effect. You can develop according to the actual needs.
You can see that when the checksum is not passed, the return of the exception information is not friendly, at this time, the use of unified exception processing, check exceptions to special processing, in particular, for the exception handling class
There are several situations (request entities annotated by @requestbody and @requestparam, check exception classes are different)
@ExceptionHandler (methodargumentnotvalidexception.class) public map<string,object> handlebindexception ( Methodargumentnotvalidexception ex) {Fielderror fielderror = Ex.getbindingresult (). Getfielderror (); Log.info ("parameter check exception: {} ({})", Fielderror.getdefaultmessage (), Fielderror.getfield ()); map<string,object> result = new hashmap<string,object> (); Result.put ("Respcode", "01002"); Result.put ("Respmsg", Fielderror.getdefaultmessage ()); return result; } @ExceptionHandler (Bindexception.class) public map<string,object> handlebindexception (Bindexception ex) { Verify that the parameter check except for the requestbody annotation corresponds to the bindingresult of beanpropertybindingresult fielderror fielderror = Ex.getbindi Ngresult (). Getfielderror (); Log.info ("Required check exception: {} ({})", Fielderror.getdefaultmessage (), Fielderror.getfield ()); map<string,object> result = new hashmap<string,object> (); Result.put ("Respcode", "01002"); ResULt.put ("Respmsg", Fielderror.getdefaultmessage ()); return result; }
After launch, the prompt is friendly.
So it is necessary to unify the anomaly.
Summarize
This chapter is mainly to explain the uniform exception handling and the validity of the data verification, while a simple implementation of a custom annotation class, when you meet the existing annotations can not be resolved by the form of a custom, of course, for general purpose, the use @Pattern(正则表达式)
is basically achievable.
At last
At present, many big guys on the internet have a springboot
series of tutorials, if there is a similar, please forgive me. This article is the author in front of the computer word knocking, each step is practice. If there is something wrong in the text, also hope to put forward, thank you.
Cliché
- Personal QQ:
499452441
- Public Number:
lqdevOps
Personal blog: https://blog.lqdev.cn
Complete Example: chapter-8
Original address: http://blog.lqdev.cn/2018/07/20/springboot/chapter-eight/
Springboot | The eighth chapter: Unification anomaly, data check processing