无关风月
2025-02-14 11ec1c23a9f47ed70b124e413e33e3696897390f
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
package com.jilongda.common.exception;
 
 
import com.jilongda.common.basic.ApiResult;
import com.jilongda.common.swagger.GlobalResultEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.NoHandlerFoundException;
 
import javax.naming.SizeLimitExceededException;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.xml.bind.ValidationException;
import java.nio.file.AccessDeniedException;
import java.text.DecimalFormat;
import java.util.Set;
 
/**
 * @author madman
 * @version 1.0
 * @date 2019/7/30 16:13
 * 全局的异常处理
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 请求参数错误
     */
    private final static String BASE_PARAM_ERR_MSG = "参数校验不通过";
    @Value("${spring.servlet.multipart.max-file-size:10MB}")
    private String maxFileSize;
    @Value("${spring.servlet.multipart.max-request-size:10MB}")
    private String maxRequestSize;
 
    /**
     * 文件大小转换
     *
     * @param size
     * @return
     */
    private static String asReadableFileSize(long size) {
        if (size <= 0) {
            return "0";
        }
        final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
        return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + "" + units[digitGroups];
    }
 
    /**
     * 顶级的异常处理
     * 处理所有不可知异常
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(Exception.class)
    public ApiResult handleException(Exception e) {
        // 打印异常堆栈信息
        log.error("顶级异常->:" + e.getMessage(), e);
        if (e instanceof TokenException) {
            TokenException e1 = (TokenException) e;
            return ApiResult.failed(e1.getCode(), e.getMessage());
        }
        return ApiResult.failed(e.getMessage());
    }
 
 
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({MultipartException.class})
    public ApiResult fileUpLoad2(MaxUploadSizeExceededException e) {
        log.error("上传文件异常 => : {}", e.getMessage());
        if (e.getCause().getCause() instanceof FileSizeLimitExceededException) {
            return ApiResult.failed("文件大小超出限制,允许的大小在" + maxFileSize);
        } else if (e.getCause().getCause() instanceof SizeLimitExceededException) {
            return ApiResult.failed("文件单次上传总大小超过限制,允许的大小在" + maxRequestSize);
        } else {
            return ApiResult.failed("文件上传失败");
        }
    }
 
    /**
     * 自定义的异常处理
     * 业务异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ServerException.class)
    @ResponseStatus(HttpStatus.OK)
    public ApiResult handleBusinessException(ServerException e) {
        // 打印异常堆栈信息
        log.error(" ---> 业务处理异常: {}", e.getMessage());
        return ApiResult.failed(e.getCode(), e.getMessage(), e.getData());
    }
 
    /**
     * 请求参数类型不匹配异常
     * 例如本应传递int,却传递了String
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({MethodArgumentTypeMismatchException.class})
    public ApiResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
        log.warn("方法参数类型不匹配异常: {}", e);
        return ApiResult.failed("方法请求参数类型不匹配异常");
    }
 
    /**
     * 缺少servlet请求参数抛出的异常
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public ApiResult handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        log.warn(" 参数错误: {}", e.getParameterName());
        return ApiResult.failed(BASE_PARAM_ERR_MSG + ":请求参数");
    }
 
    /**
     * 请求参数不能正确读取解析时,抛出的异常,比如传入和接受的参数类型不一致
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public ApiResult handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        log.error("参数解析失败:", e);
        return ApiResult.failed("传入和接受的参数类型不一致");
    }
 
    /**
     * 请求参数无效抛出的异常
     * 校验参数抛出的异常
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ApiResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult result = e.getBindingResult();
        String message = getBindResultMessage(result);
        log.error("参数验证失败:" + message);
        return ApiResult.failed(message.split(":")[1]);
    }
 
    /**
     * 构造参数校验错误信息
     *
     * @param result
     * @return
     */
    private String getBindResultMessage(BindingResult result) {
        // 多个错误随机取值的
        FieldError error = result.getFieldError();
        String field = error != null ? error.getField() : "空";
        String code = error != null ? error.getDefaultMessage() : "空";
        return String.format("%s:%s", field, code);
    }
 
 
    /**
     * 请求参数绑定到controller请求参数时的异常
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({BindException.class})
    public ApiResult handleHttpMessageNotReadableException(BindException e) {
        BindingResult result = e.getBindingResult();
        String message = getBindResultMessage(result);
        log.error("参数绑定失败:{}", message);
        return ApiResult.failed("请求参数绑定失败");
    }
 
    /**
     * javax.validation:validation-api 校验参数抛出的异常
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({ConstraintViolationException.class})
    public ApiResult handleServiceException(ConstraintViolationException e) {
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        ConstraintViolation<?> violation = violations.iterator().next();
        String message = violation.getMessage();
        log.warn("参数验证失败:{}", message);
        return ApiResult.failed("参数验证失败:" + message);
    }
 
    /**
     * javax.validation 下校验参数时抛出的异常
     * 400 - Bad Request
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({ValidationException.class})
    public ApiResult<String> handleValidationException(ValidationException e) {
        log.warn("参数验证失败:{}", e);
        return ApiResult.failed("参数验证失败:" + e.getMessage());
    }
 
    /**
     * 不支持该请求方法时抛出的异常
     * 例如本应GET,结果却是POST
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public ApiResult<String> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        log.warn("不支持当前请求方法: {}", e);
        return ApiResult.failed("Request Method 不正确");
    }
 
 
    /**
     * 不支持当前媒体类型抛出的异常
     *
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({HttpMediaTypeNotSupportedException.class})
    public ApiResult<String> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
        log.warn("不支持当前媒体类型:{} ", e);
        return ApiResult.failed("不支持当前媒体类型");
    }
 
    /**
     * 操作数据库出现异常:名称重复,外键关联
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(DataIntegrityViolationException.class)
    public ApiResult<String> handleException(DataIntegrityViolationException e) {
        log.error("操作数据库出现异常:{}", e);
        return ApiResult.failed("操作数据库出现异常:" + e.getMessage());
    }
 
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(NoHandlerFoundException.class)
    public ApiResult<String> handlerNoFoundException(Exception e) {
        log.error("请求路径匹配异常:" + e.getMessage(), e);
        return ApiResult.failed(GlobalResultEnum.NOT_FOUND.getCode(), "路径不存在,请检查路径是否正确");
    }
 
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(AccessDeniedException.class)
    public ApiResult<String> handleAuthorizationException(AccessDeniedException e) {
        log.warn(e.getMessage());
        return ApiResult.failed(GlobalResultEnum.FORBIDDEN.getCode(), "没有权限,请联系管理员授权");
    }
}