├── .gitignore ├── README.md ├── flylib-boot-demo ├── .gitignore ├── flylib-boot-demo.iml ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── flylib │ │ ├── StarterApp.java │ │ └── demo │ │ ├── controller │ │ ├── DemoController.java │ │ └── IndexController.java │ │ └── exception │ │ └── UserException.java │ └── resources │ └── application.properties ├── flylib-boot-starter-web ├── .gitignore ├── flylib-boot-starter-web.iml ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── flylib │ │ └── boot │ │ └── starter │ │ ├── StarterApp.java │ │ ├── controller │ │ ├── BasicErrorController.java │ │ ├── DemoController.java │ │ └── IndexController.java │ │ ├── exception │ │ ├── CustomRuntimeException.java │ │ ├── UnknownResourceException.java │ │ ├── UserException.java │ │ └── ValidationRuntimeException.java │ │ └── handler │ │ └── GlobalExceptionHandler.java │ └── resources │ ├── application-dev.properties │ └── application.properties └── flylib-boot-starter ├── .gitignore ├── flylib-boot-starter.iml ├── pom.xml └── src └── main └── java └── org └── flylib └── boot └── starter ├── config └── MvcConfig.java ├── controller └── DefaultController.java ├── exception ├── CustomRuntimeException.java ├── UnknownResourceException.java └── ValidationRuntimeException.java ├── filter └── LoggingFilter.java ├── handler └── GlobalExceptionHandler.java └── interceptor └── ResponseHandlerInterceptor.java /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.settings/ 3 | /.classpath 4 | /.project 5 | /.idea/ 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## flylib-boot简介 2 | flylib-boot是针对springboot构建的程序的基础框架,专门用于构建程序里的比如统一 3 | 异常处理 4 | 5 | ## 功能 6 | 包含一个Spring Boot的一些常见的基础组件的设置 7 | 1. 针对Handler的全局的异常处理(处理所有Controller里的Handler里抛出的异常) 8 | 2. Filter 9 | 3. Interceptor 10 | 11 | 注意:SpringBoot(SpringMVC)里的Handler特指@Controller注解的类里的每个处理HTTP请求的一个public method. 12 | 13 | ## 使用方法 14 | - Step 1: 进入目录flylib-boot-starter,执行mvn install 15 | - Step 2: 在自己的项目中添加flylib-boot-starter的maven依赖. 并留意自己使用的spring-boot版本,去修改自己的pom.xml文件 16 | ```xml 17 | 18 | org.flylib 19 | flylib-boot-starter 20 | 1.0-SNAPSHOT 21 | 22 | ``` 23 | 并且要注意这里spring-boot版本是1.5.0.RELEASE. 另外需要添加spring-boot-maven-plugin 24 | 实例参考spring-boot-demo项目,它的pom如下: 25 | ```xml 26 | 27 | 29 | 4.0.0 30 | 31 | org.flylib 32 | flylib-boot-demo 33 | 1.0-SNAPSHOT 34 | jar 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-parent 39 | 1.5.0.RELEASE 40 | 41 | 42 | 43 | 44 | UTF-8 45 | UTF-8 46 | 1.8 47 | 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-starter-web 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-starter-test 58 | test 59 | 60 | 61 | org.flylib 62 | flylib-boot-starter 63 | 1.0-SNAPSHOT 64 | 65 | 66 | 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-maven-plugin 71 | 72 | 73 | 74 | 75 | 76 | ``` 77 | 78 | - Step 3: 在自己的程序中new 一个UserException(自定义的异常类)设置捕获异常 79 | ```java 80 | /** 81 | * 用户信息的异常 82 | */ 83 | public class UserException extends RuntimeException{ 84 | 85 | } 86 | 87 | 88 | @RequestMapping("") 89 | public String index() throws RuntimeException { 90 | UserException userException = new UserException(); 91 | CustomRuntimeException cause = new CustomRuntimeException("001", "User not exists"); 92 | userException.initCause(cause); 93 | throw userException; 94 | } 95 | ``` 96 | - Step 4: 运行自己的Spring Boot项目 97 | 输出到浏览器的结果 98 | ```json 99 | { 100 | code:"001", 101 | message:"User not exists", 102 | throwable:{...} 103 | } 104 | ``` 105 | ## 实现原理 106 | 利用了@ControllerAdvice和@ExceptionHandler 107 | 实现代码是 108 | ```java 109 | package org.flylib.boot.starter.handler; 110 | 111 | import org.flylib.boot.starter.exception.CustomRuntimeException; 112 | import org.flylib.boot.starter.exception.UnknownResourceException; 113 | import org.flylib.boot.starter.exception.ValidationRuntimeException; 114 | import org.slf4j.Logger; 115 | import org.slf4j.LoggerFactory; 116 | import org.springframework.beans.TypeMismatchException; 117 | import org.springframework.beans.factory.annotation.Autowired; 118 | import org.springframework.context.MessageSource; 119 | import org.springframework.core.env.Environment; 120 | import org.springframework.http.HttpStatus; 121 | import org.springframework.http.converter.HttpMessageNotReadableException; 122 | import org.springframework.ui.Model; 123 | import org.springframework.web.HttpMediaTypeNotAcceptableException; 124 | import org.springframework.web.HttpMediaTypeNotSupportedException; 125 | import org.springframework.web.HttpRequestMethodNotSupportedException; 126 | import org.springframework.web.bind.MissingServletRequestParameterException; 127 | import org.springframework.web.bind.annotation.ControllerAdvice; 128 | import org.springframework.web.bind.annotation.ExceptionHandler; 129 | import org.springframework.web.bind.annotation.ResponseBody; 130 | import org.springframework.web.context.request.ServletWebRequest; 131 | import org.springframework.web.servlet.LocaleResolver; 132 | import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException; 133 | 134 | import javax.servlet.http.HttpServletRequest; 135 | import javax.servlet.http.HttpServletResponse; 136 | import java.util.HashMap; 137 | import java.util.LinkedHashMap; 138 | import java.util.Locale; 139 | import java.util.Map; 140 | 141 | /** 142 | * 说明: 143 | * 144 | * @ControllerAdvice是controller的一个辅助类,最常用的就是作为全局异常处理的切面类 145 | * @ControllerAdvice可以指定扫描范围 146 | * @ControllerAdvice约定了几种可行的返回值,如果是直接返回model类的话,需要使用@ResponseBody进行json转换 返回String,表示跳到某个view 147 | * 返回modelAndView 148 | * 返回model + @ResponseBody 149 | * 全局异常处理 150 | */ 151 | @ControllerAdvice 152 | public class GlobalExceptionHandler { 153 | 154 | private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); 155 | 156 | @Autowired 157 | private Environment env; 158 | 159 | @Autowired(required = false) 160 | private MessageSource messageSource; 161 | 162 | @Autowired(required = false) 163 | private LocaleResolver localeResolver; 164 | 165 | private static final String defaultMoreInfoUrl = ""; 166 | 167 | private final Map DEFAULT_EXCEPTION_MAPPING_DEFINITIONS; 168 | 169 | public GlobalExceptionHandler() { 170 | DEFAULT_EXCEPTION_MAPPING_DEFINITIONS = createDefaultExceptionMappingDefinitions(); 171 | } 172 | 173 | @ExceptionHandler//处理所有异常 174 | @ResponseBody //在返回自定义相应类的情况下必须有,这是@ControllerAdvice注解的规定 175 | public Map exceptionHandler(Throwable e, HttpServletRequest request, HttpServletResponse response, Model model) { 176 | // 177 | log.error("handle error:",e); 178 | 179 | HttpStatus httpStatus = DEFAULT_EXCEPTION_MAPPING_DEFINITIONS.get(e.getClass().getName()); 180 | if(httpStatus==null){ 181 | httpStatus = HttpStatus.INTERNAL_SERVER_ERROR; 182 | } 183 | //是否是生产环境 184 | boolean isProd = "prod".equals(env.getActiveProfiles()[0]); 185 | Map map = new HashMap(); 186 | if(e.getCause() instanceof CustomRuntimeException){ 187 | CustomRuntimeException exception = (CustomRuntimeException) e.getCause(); 188 | map.put("code",String.valueOf(exception.getCode())); 189 | map.put("message",exception.getMessage()); 190 | }else if(e.getCause() instanceof ValidationRuntimeException){ 191 | ValidationRuntimeException exception = (ValidationRuntimeException) e.getCause(); 192 | map.put("code",String.valueOf(exception.getCode())); 193 | map.put("message",exception.getMessage()); 194 | httpStatus = HttpStatus.BAD_REQUEST; 195 | }else { 196 | map.put("code",String.valueOf(httpStatus.value())); 197 | map.put("message",httpStatus.toString()); 198 | } 199 | 200 | 201 | //不是生产环境,添加调试信息 202 | if(!isProd){ 203 | map.put("throwable",e); 204 | } 205 | response.setStatus(httpStatus.value()); 206 | return map; 207 | } 208 | 209 | protected final Map createDefaultExceptionMappingDefinitions() { 210 | 211 | Map m = new LinkedHashMap(); 212 | 213 | // 400 214 | applyDef(m, HttpMessageNotReadableException.class, HttpStatus.BAD_REQUEST); 215 | applyDef(m, MissingServletRequestParameterException.class, HttpStatus.BAD_REQUEST); 216 | applyDef(m, TypeMismatchException.class, HttpStatus.BAD_REQUEST); 217 | applyDef(m, "javax.validation.ValidationException", HttpStatus.BAD_REQUEST); 218 | 219 | // 404 220 | applyDef(m, NoSuchRequestHandlingMethodException.class, HttpStatus.NOT_FOUND); 221 | applyDef(m, "org.hibernate.ObjectNotFoundException", HttpStatus.NOT_FOUND); 222 | 223 | // 405 224 | applyDef(m, HttpRequestMethodNotSupportedException.class, HttpStatus.METHOD_NOT_ALLOWED); 225 | 226 | // 406 227 | applyDef(m, HttpMediaTypeNotAcceptableException.class, HttpStatus.NOT_ACCEPTABLE); 228 | 229 | // 409 230 | //can't use the class directly here as it may not be an available dependency: 231 | applyDef(m, "org.springframework.dao.DataIntegrityViolationException", HttpStatus.CONFLICT); 232 | 233 | // 415 234 | applyDef(m, HttpMediaTypeNotSupportedException.class, HttpStatus.UNSUPPORTED_MEDIA_TYPE); 235 | applyDef(m, UnknownResourceException.class, HttpStatus.NOT_FOUND); 236 | 237 | return m; 238 | } 239 | private void applyDef(Map m, Class clazz, HttpStatus status) { 240 | applyDef(m, clazz.getName(), status); 241 | } 242 | 243 | private void applyDef(Map m, String key, HttpStatus status) { 244 | m.put(key, status); 245 | } 246 | 247 | 248 | 249 | protected String getMessage(String msg, ServletWebRequest webRequest, Exception ex) { 250 | 251 | if (msg != null) { 252 | if (msg.equalsIgnoreCase("null") || msg.equalsIgnoreCase("off")) { 253 | return null; 254 | } 255 | msg = ex.getMessage(); 256 | if (messageSource != null) { 257 | Locale locale = null; 258 | if (localeResolver != null) { 259 | locale = localeResolver.resolveLocale(webRequest.getRequest()); 260 | } 261 | msg = messageSource.getMessage(msg, null, msg, locale); 262 | } 263 | } 264 | 265 | return msg; 266 | } 267 | } 268 | 269 | ``` 270 | -------------------------------------------------------------------------------- /flylib-boot-demo/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.settings/ 3 | /.classpath 4 | /.project 5 | /.idea/ 6 | -------------------------------------------------------------------------------- /flylib-boot-demo/flylib-boot-demo.iml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /flylib-boot-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.flylib 7 | flylib-boot-demo 8 | 1.0-SNAPSHOT 9 | jar 10 | 11 | 12 | org.springframework.boot 13 | spring-boot-starter-parent 14 | 1.5.0.RELEASE 15 | 16 | 17 | 18 | 19 | UTF-8 20 | UTF-8 21 | 1.8 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-test 33 | test 34 | 35 | 36 | org.flylib 37 | flylib-boot-starter 38 | 1.0-SNAPSHOT 39 | 40 | 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-maven-plugin 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /flylib-boot-demo/src/main/java/org/flylib/StarterApp.java: -------------------------------------------------------------------------------- 1 | package org.flylib; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class StarterApp { 8 | public static void main(String[] args) { 9 | SpringApplication.run(StarterApp.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /flylib-boot-demo/src/main/java/org/flylib/demo/controller/DemoController.java: -------------------------------------------------------------------------------- 1 | package org.flylib.demo.controller; 2 | 3 | import org.flylib.boot.starter.exception.CustomRuntimeException; 4 | import org.flylib.demo.exception.UserException; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | @RequestMapping("demo") 10 | public class DemoController { 11 | 12 | @RequestMapping("") 13 | public String index() throws RuntimeException { 14 | UserException userException = new UserException(); 15 | CustomRuntimeException cause = new CustomRuntimeException("001", "User not exists"); 16 | userException.initCause(cause); 17 | throw userException; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /flylib-boot-demo/src/main/java/org/flylib/demo/controller/IndexController.java: -------------------------------------------------------------------------------- 1 | package org.flylib.demo.controller; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | @RequestMapping("") 8 | public class IndexController { 9 | 10 | @RequestMapping("") 11 | public String index() { 12 | return "hello"; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /flylib-boot-demo/src/main/java/org/flylib/demo/exception/UserException.java: -------------------------------------------------------------------------------- 1 | package org.flylib.demo.exception; 2 | 3 | /** 4 | * 用户信息的异常 5 | */ 6 | public class UserException extends RuntimeException{ 7 | 8 | } 9 | -------------------------------------------------------------------------------- /flylib-boot-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=dev 2 | server.port=3000 3 | #server.error.path=/custom/error -------------------------------------------------------------------------------- /flylib-boot-starter-web/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.settings/ 3 | /.classpath 4 | /.project 5 | /.idea/ 6 | -------------------------------------------------------------------------------- /flylib-boot-starter-web/flylib-boot-starter-web.iml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /flylib-boot-starter-web/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 1.5.8.RELEASE 10 | 11 | 12 | org.flylib 13 | flylib-boot-starter-web 14 | 1.0-SNAPSHOT 15 | jar 16 | 17 | 18 | UTF-8 19 | UTF-8 20 | 1.8 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-test 32 | test 33 | 34 | 35 | 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-maven-plugin 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /flylib-boot-starter-web/src/main/java/org/flylib/boot/starter/StarterApp.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class StarterApp { 8 | public static void main(String[] args) { 9 | SpringApplication.run(StarterApp.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /flylib-boot-starter-web/src/main/java/org/flylib/boot/starter/controller/BasicErrorController.java: -------------------------------------------------------------------------------- 1 | // 2 | // Source code recreated from a .class file by IntelliJ IDEA 3 | // (powered by Fernflower decompiler) 4 | // 5 | 6 | package org.flylib.boot.starter.controller; 7 | 8 | import java.util.Collections; 9 | import java.util.HashMap; 10 | import java.util.Iterator; 11 | import java.util.List; 12 | import java.util.Map; 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.servlet.http.HttpServletResponse; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.boot.autoconfigure.web.ErrorAttributes; 17 | import org.springframework.boot.autoconfigure.web.ErrorController; 18 | import org.springframework.boot.autoconfigure.web.ErrorProperties; 19 | import org.springframework.boot.autoconfigure.web.ErrorViewResolver; 20 | import org.springframework.boot.autoconfigure.web.ServerProperties; 21 | import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeStacktrace; 22 | import org.springframework.core.env.Environment; 23 | import org.springframework.http.HttpStatus; 24 | import org.springframework.http.MediaType; 25 | import org.springframework.http.ResponseEntity; 26 | import org.springframework.stereotype.Controller; 27 | import org.springframework.web.bind.annotation.RequestMapping; 28 | import org.springframework.web.bind.annotation.ResponseBody; 29 | import org.springframework.web.context.request.RequestAttributes; 30 | import org.springframework.web.context.request.ServletRequestAttributes; 31 | import org.springframework.web.servlet.ModelAndView; 32 | 33 | @Controller 34 | @RequestMapping({"${server.error.path:${error.path:/error}}"}) 35 | public class BasicErrorController implements ErrorController { 36 | @Autowired 37 | private ServerProperties serverProperties; 38 | @Autowired 39 | private Environment env; 40 | @Autowired 41 | private ErrorAttributes errorAttributes; 42 | @Autowired( 43 | required = false 44 | ) 45 | private List errorViewResolvers; 46 | 47 | public BasicErrorController() { 48 | } 49 | 50 | public String getErrorPath() { 51 | return this.serverProperties.getError().getPath(); 52 | } 53 | 54 | @RequestMapping( 55 | produces = {"text/html"} 56 | ) 57 | public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { 58 | HttpStatus status = this.getStatus(request); 59 | Map model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML))); 60 | response.setStatus(status.value()); 61 | request.setAttribute("env", this.env.getActiveProfiles()[0]); 62 | ModelAndView modelAndView = this.resolveErrorView(request, response, status, model); 63 | return modelAndView == null ? new ModelAndView("error", model) : modelAndView; 64 | } 65 | 66 | @RequestMapping 67 | @ResponseBody 68 | public ResponseEntity> error(HttpServletRequest request) { 69 | Map body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL)); 70 | HttpStatus status = this.getStatus(request); 71 | boolean isProd = "prod".equals(this.env.getActiveProfiles()[0]); 72 | if (isProd) { 73 | Map body2 = new HashMap(); 74 | body2.put("message", body.get("message")); 75 | body2.put("errors", body.get("errors")); 76 | return new ResponseEntity(body2, status); 77 | } else { 78 | return new ResponseEntity(body, status); 79 | } 80 | } 81 | 82 | protected boolean isIncludeStackTrace(HttpServletRequest request, MediaType produces) { 83 | IncludeStacktrace include = this.getErrorProperties().getIncludeStacktrace(); 84 | if (include == IncludeStacktrace.ALWAYS) { 85 | return true; 86 | } else { 87 | boolean isProd = "prod".equals(this.env.getActiveProfiles()[0]); 88 | if (!isProd) { 89 | return true; 90 | } else { 91 | return include == IncludeStacktrace.ON_TRACE_PARAM ? this.getTraceParameter(request) : false; 92 | } 93 | } 94 | } 95 | 96 | protected ErrorProperties getErrorProperties() { 97 | return this.serverProperties.getError(); 98 | } 99 | 100 | private HttpStatus getStatus(HttpServletRequest request) { 101 | Integer statusCode = (Integer)request.getAttribute("javax.servlet.error.status_code"); 102 | if (statusCode == null) { 103 | return HttpStatus.INTERNAL_SERVER_ERROR; 104 | } else { 105 | try { 106 | return HttpStatus.valueOf(statusCode.intValue()); 107 | } catch (Exception var4) { 108 | return HttpStatus.INTERNAL_SERVER_ERROR; 109 | } 110 | } 111 | } 112 | 113 | protected boolean getTraceParameter(HttpServletRequest request) { 114 | String parameter = request.getParameter("trace"); 115 | if (parameter == null) { 116 | return false; 117 | } else { 118 | return !"false".equals(parameter.toLowerCase()); 119 | } 120 | } 121 | 122 | protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map model) { 123 | Iterator var5 = this.errorViewResolvers.iterator(); 124 | 125 | ModelAndView modelAndView; 126 | do { 127 | if (!var5.hasNext()) { 128 | return null; 129 | } 130 | 131 | ErrorViewResolver resolver = (ErrorViewResolver)var5.next(); 132 | modelAndView = resolver.resolveErrorView(request, status, model); 133 | } while(modelAndView == null); 134 | 135 | return modelAndView; 136 | } 137 | 138 | protected Map getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) { 139 | RequestAttributes requestAttributes = new ServletRequestAttributes(request); 140 | return this.errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /flylib-boot-starter-web/src/main/java/org/flylib/boot/starter/controller/DemoController.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.controller; 2 | 3 | import org.flylib.boot.starter.exception.CustomRuntimeException; 4 | import org.flylib.boot.starter.exception.UserException; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | @RequestMapping("demo") 10 | public class DemoController { 11 | 12 | @RequestMapping("") 13 | public String index() throws RuntimeException { 14 | UserException userException = new UserException(); 15 | CustomRuntimeException cause = new CustomRuntimeException("001", "User not exists"); 16 | userException.initCause(cause); 17 | throw userException; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /flylib-boot-starter-web/src/main/java/org/flylib/boot/starter/controller/IndexController.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.controller; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | @RequestMapping("index") 8 | public class IndexController { 9 | 10 | @RequestMapping("") 11 | public String index() { 12 | return "ssssssssssssss"; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /flylib-boot-starter-web/src/main/java/org/flylib/boot/starter/exception/CustomRuntimeException.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.exception; 2 | 3 | public class CustomRuntimeException extends RuntimeException { 4 | private final String code; 5 | 6 | public CustomRuntimeException(String code, String message) { 7 | super(message); 8 | this.code = code; 9 | } 10 | 11 | public CustomRuntimeException(String code, String message, Throwable cause) { 12 | super(message, cause); 13 | this.code = code; 14 | } 15 | 16 | public String getCode() { 17 | return this.code; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /flylib-boot-starter-web/src/main/java/org/flylib/boot/starter/exception/UnknownResourceException.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.exception; 2 | 3 | public class UnknownResourceException extends RuntimeException { 4 | public UnknownResourceException(String msg) { 5 | super(msg); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /flylib-boot-starter-web/src/main/java/org/flylib/boot/starter/exception/UserException.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.exception; 2 | 3 | /** 4 | * 用户信息的异常 5 | */ 6 | public class UserException extends RuntimeException{ 7 | 8 | } 9 | -------------------------------------------------------------------------------- /flylib-boot-starter-web/src/main/java/org/flylib/boot/starter/exception/ValidationRuntimeException.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.exception; 2 | 3 | public class ValidationRuntimeException extends CustomRuntimeException { 4 | public ValidationRuntimeException(String code, String message) { 5 | super(code, message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /flylib-boot-starter-web/src/main/java/org/flylib/boot/starter/handler/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.handler; 2 | 3 | import org.flylib.boot.starter.exception.CustomRuntimeException; 4 | import org.flylib.boot.starter.exception.UnknownResourceException; 5 | import org.flylib.boot.starter.exception.ValidationRuntimeException; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.TypeMismatchException; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.context.MessageSource; 11 | import org.springframework.core.env.Environment; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.http.converter.HttpMessageNotReadableException; 14 | import org.springframework.ui.Model; 15 | import org.springframework.web.HttpMediaTypeNotAcceptableException; 16 | import org.springframework.web.HttpMediaTypeNotSupportedException; 17 | import org.springframework.web.HttpRequestMethodNotSupportedException; 18 | import org.springframework.web.bind.MissingServletRequestParameterException; 19 | import org.springframework.web.bind.annotation.ControllerAdvice; 20 | import org.springframework.web.bind.annotation.ExceptionHandler; 21 | import org.springframework.web.bind.annotation.ResponseBody; 22 | import org.springframework.web.context.request.ServletWebRequest; 23 | import org.springframework.web.servlet.LocaleResolver; 24 | import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException; 25 | 26 | import javax.servlet.http.HttpServletRequest; 27 | import javax.servlet.http.HttpServletResponse; 28 | import java.util.HashMap; 29 | import java.util.LinkedHashMap; 30 | import java.util.Locale; 31 | import java.util.Map; 32 | 33 | /** 34 | * 说明: 35 | * 36 | * @ControllerAdvice是controller的一个辅助类,最常用的就是作为全局异常处理的切面类 37 | * @ControllerAdvice可以指定扫描范围 38 | * @ControllerAdvice约定了几种可行的返回值,如果是直接返回model类的话,需要使用@ResponseBody进行json转换 返回String,表示跳到某个view 39 | * 返回modelAndView 40 | * 返回model + @ResponseBody 41 | * 全局异常处理 42 | */ 43 | @ControllerAdvice 44 | public class GlobalExceptionHandler { 45 | 46 | private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); 47 | 48 | @Autowired 49 | private Environment env; 50 | 51 | @Autowired(required = false) 52 | private MessageSource messageSource; 53 | 54 | @Autowired(required = false) 55 | private LocaleResolver localeResolver; 56 | 57 | private static final String defaultMoreInfoUrl = ""; 58 | 59 | private final Map DEFAULT_EXCEPTION_MAPPING_DEFINITIONS; 60 | 61 | public GlobalExceptionHandler() { 62 | DEFAULT_EXCEPTION_MAPPING_DEFINITIONS = createDefaultExceptionMappingDefinitions(); 63 | } 64 | 65 | @ExceptionHandler//处理所有异常 66 | @ResponseBody //在返回自定义相应类的情况下必须有,这是@ControllerAdvice注解的规定 67 | public Map exceptionHandler(Throwable e, HttpServletRequest request, HttpServletResponse response, Model model) { 68 | // 69 | log.error("handle error:",e); 70 | 71 | HttpStatus httpStatus = DEFAULT_EXCEPTION_MAPPING_DEFINITIONS.get(e.getClass().getName()); 72 | if(httpStatus==null){ 73 | httpStatus = HttpStatus.INTERNAL_SERVER_ERROR; 74 | } 75 | //是否是生产环境 76 | boolean isProd = "prod".equals(env.getActiveProfiles()[0]); 77 | Map map = new HashMap(); 78 | if(e.getCause() instanceof CustomRuntimeException){ 79 | CustomRuntimeException exception = (CustomRuntimeException) e.getCause(); 80 | map.put("code",String.valueOf(exception.getCode())); 81 | map.put("message",exception.getMessage()); 82 | }else if(e.getCause() instanceof ValidationRuntimeException){ 83 | ValidationRuntimeException exception = (ValidationRuntimeException) e.getCause(); 84 | map.put("code",String.valueOf(exception.getCode())); 85 | map.put("message",exception.getMessage()); 86 | httpStatus = HttpStatus.BAD_REQUEST; 87 | }else { 88 | map.put("code",String.valueOf(httpStatus.value())); 89 | map.put("message",httpStatus.toString()); 90 | } 91 | 92 | 93 | //不是生产环境,添加调试信息 94 | if(!isProd){ 95 | map.put("throwable",e); 96 | } 97 | response.setStatus(httpStatus.value()); 98 | return map; 99 | } 100 | 101 | protected final Map createDefaultExceptionMappingDefinitions() { 102 | 103 | Map m = new LinkedHashMap(); 104 | 105 | // 400 106 | applyDef(m, HttpMessageNotReadableException.class, HttpStatus.BAD_REQUEST); 107 | applyDef(m, MissingServletRequestParameterException.class, HttpStatus.BAD_REQUEST); 108 | applyDef(m, TypeMismatchException.class, HttpStatus.BAD_REQUEST); 109 | applyDef(m, "javax.validation.ValidationException", HttpStatus.BAD_REQUEST); 110 | 111 | // 404 112 | applyDef(m, NoSuchRequestHandlingMethodException.class, HttpStatus.NOT_FOUND); 113 | applyDef(m, "org.hibernate.ObjectNotFoundException", HttpStatus.NOT_FOUND); 114 | 115 | // 405 116 | applyDef(m, HttpRequestMethodNotSupportedException.class, HttpStatus.METHOD_NOT_ALLOWED); 117 | 118 | // 406 119 | applyDef(m, HttpMediaTypeNotAcceptableException.class, HttpStatus.NOT_ACCEPTABLE); 120 | 121 | // 409 122 | //can't use the class directly here as it may not be an available dependency: 123 | applyDef(m, "org.springframework.dao.DataIntegrityViolationException", HttpStatus.CONFLICT); 124 | 125 | // 415 126 | applyDef(m, HttpMediaTypeNotSupportedException.class, HttpStatus.UNSUPPORTED_MEDIA_TYPE); 127 | applyDef(m, UnknownResourceException.class, HttpStatus.NOT_FOUND); 128 | 129 | return m; 130 | } 131 | private void applyDef(Map m, Class clazz, HttpStatus status) { 132 | applyDef(m, clazz.getName(), status); 133 | } 134 | 135 | private void applyDef(Map m, String key, HttpStatus status) { 136 | m.put(key, status); 137 | } 138 | 139 | 140 | 141 | protected String getMessage(String msg, ServletWebRequest webRequest, Exception ex) { 142 | 143 | if (msg != null) { 144 | if (msg.equalsIgnoreCase("null") || msg.equalsIgnoreCase("off")) { 145 | return null; 146 | } 147 | msg = ex.getMessage(); 148 | if (messageSource != null) { 149 | Locale locale = null; 150 | if (localeResolver != null) { 151 | locale = localeResolver.resolveLocale(webRequest.getRequest()); 152 | } 153 | msg = messageSource.getMessage(msg, null, msg, locale); 154 | } 155 | } 156 | 157 | return msg; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /flylib-boot-starter-web/src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bootsrc/flylib-boot/dcafffed30e1a0472f707aff5f11ec3f845d565a/flylib-boot-starter-web/src/main/resources/application-dev.properties -------------------------------------------------------------------------------- /flylib-boot-starter-web/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=dev 2 | server.port=3000 3 | #server.error.path=/custom/error -------------------------------------------------------------------------------- /flylib-boot-starter/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.settings/ 3 | /.classpath 4 | /.project 5 | /.idea/ 6 | -------------------------------------------------------------------------------- /flylib-boot-starter/flylib-boot-starter.iml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /flylib-boot-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 1.5.0.RELEASE 10 | 11 | 12 | org.flylib 13 | flylib-boot-starter 14 | 1.0-SNAPSHOT 15 | jar 16 | 17 | 18 | UTF-8 19 | UTF-8 20 | 1.8 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | provided 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-test 33 | test 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /flylib-boot-starter/src/main/java/org/flylib/boot/starter/config/MvcConfig.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.config; 2 | 3 | import com.fasterxml.jackson.databind.DeserializationFeature; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.fasterxml.jackson.databind.SerializationFeature; 6 | import org.flylib.boot.starter.filter.LoggingFilter; 7 | import org.flylib.boot.starter.interceptor.ResponseHandlerInterceptor; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.autoconfigure.web.HttpMessageConverters; 12 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.annotation.Configuration; 15 | import org.springframework.core.env.Environment; 16 | import org.springframework.http.MediaType; 17 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 18 | import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; 19 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 20 | import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; 21 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 22 | 23 | import java.net.InetAddress; 24 | import java.net.UnknownHostException; 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | /** 29 | * mvc 配置类 30 | * 支持 velocity 和jsp视图解析 31 | * 加载顺序 32 | * 首先用ResourceBundleViewResolver 查找资源 如果差不多再根据velocity 视图解析器查找 如何还差不多就用jsp视图解析器 33 | * 2:ResourceBundleViewResolver 34 | * 3:VelocityViewResolver 35 | * 5:InternalResourceViewResolver 36 | * @author meixinbin 37 | * @2017-1-20 38 | */ 39 | @Configuration 40 | public class MvcConfig extends WebMvcConfigurerAdapter { 41 | 42 | private Logger logger = LoggerFactory.getLogger(getClass()); 43 | 44 | @Autowired 45 | private Environment environment; 46 | 47 | @Bean 48 | public HttpMessageConverters httpMessageConverters() { 49 | MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(); 50 | jsonConverter.setPrefixJson(false); 51 | ObjectMapper objectMapper = new ObjectMapper(); 52 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 53 | objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); 54 | jsonConverter.setObjectMapper(objectMapper); 55 | List ls = new ArrayList(); 56 | ls.add(new MediaType("application","json")); 57 | ls.add(new MediaType("text","json")); 58 | jsonConverter.setSupportedMediaTypes(ls); 59 | return new HttpMessageConverters(jsonConverter); 60 | } 61 | 62 | @Override 63 | public void configurePathMatch(PathMatchConfigurer configurer) { 64 | } 65 | 66 | @Override 67 | public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { 68 | configurer.mediaType(".*", new MediaType("application","json")); 69 | configurer.mediaType(".*", new MediaType("text","json")); 70 | } 71 | 72 | 73 | 74 | @Override 75 | public void addInterceptors(InterceptorRegistry registry) { 76 | registry.addInterceptor(new ResponseHandlerInterceptor()); 77 | super.addInterceptors(registry); 78 | } 79 | 80 | @Bean 81 | public FilterRegistrationBean someFilterRegistration() { 82 | FilterRegistrationBean registration = new FilterRegistrationBean(); 83 | try { 84 | // registration.setFilter(new LoggingFilter(InetAddress.getLocalHost().getHostAddress(),environment.getProperty("app.id"))); 85 | registration.setFilter(new LoggingFilter(InetAddress.getLocalHost().getHostAddress())); 86 | } catch (UnknownHostException e) { 87 | logger.error("get server ip error",e); 88 | } 89 | registration.addUrlPatterns("/*"); 90 | registration.setName("loggingFilter"); 91 | registration.setOrder(Integer.MIN_VALUE); 92 | return registration; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /flylib-boot-starter/src/main/java/org/flylib/boot/starter/controller/DefaultController.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.controller; 2 | 3 | import org.flylib.boot.starter.exception.UnknownResourceException; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | 7 | import javax.servlet.http.HttpServletRequest; 8 | 9 | /** 10 | * Default controller that exists to return a proper REST response for unmapped requests. 11 | */ 12 | @Controller 13 | public class DefaultController { 14 | 15 | @RequestMapping("/**") 16 | public void unmappedRequest(HttpServletRequest request) { 17 | String uri = request.getRequestURI(); 18 | throw new UnknownResourceException("Th|ere is no resource for path " + uri); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /flylib-boot-starter/src/main/java/org/flylib/boot/starter/exception/CustomRuntimeException.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.exception; 2 | 3 | public class CustomRuntimeException extends RuntimeException { 4 | private final String code; 5 | 6 | public CustomRuntimeException(String code, String message) { 7 | super(message); 8 | this.code = code; 9 | } 10 | 11 | public CustomRuntimeException(String code, String message, Throwable cause) { 12 | super(message, cause); 13 | this.code = code; 14 | } 15 | 16 | public String getCode() { 17 | return this.code; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /flylib-boot-starter/src/main/java/org/flylib/boot/starter/exception/UnknownResourceException.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.exception; 2 | 3 | public class UnknownResourceException extends RuntimeException { 4 | public UnknownResourceException(String msg) { 5 | super(msg); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /flylib-boot-starter/src/main/java/org/flylib/boot/starter/exception/ValidationRuntimeException.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.exception; 2 | 3 | public class ValidationRuntimeException extends CustomRuntimeException { 4 | public ValidationRuntimeException(String code, String message) { 5 | super(code, message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /flylib-boot-starter/src/main/java/org/flylib/boot/starter/filter/LoggingFilter.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.filter; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.slf4j.MDC; 6 | import org.springframework.util.StringUtils; 7 | 8 | import javax.servlet.*; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | import java.util.UUID; 13 | 14 | /** 15 | * @author liushaoming 16 | * @create 2017-12-04 11:03 17 | **/ 18 | public class LoggingFilter implements Filter { 19 | private final Logger logger = LoggerFactory.getLogger(this.getClass()); 20 | private final String ip; 21 | // private final String appId; 22 | 23 | // public LoggingFilter(String ip, String appId) { 24 | // this.ip = ip; 25 | // this.appId = appId == null ? "" : appId; 26 | // } 27 | public LoggingFilter(String ip) { 28 | this.ip = ip; 29 | } 30 | 31 | public void init(FilterConfig filterConfig) throws ServletException { 32 | } 33 | 34 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 35 | HttpServletRequest req = (HttpServletRequest)request; 36 | HttpServletResponse res = (HttpServletResponse)response; 37 | // req.setAttribute("_accessTime", System.nanoTime()); 38 | // boolean flag = false; 39 | // String url = req.getRequestURI(); 40 | // String sessionId; 41 | // if (url.lastIndexOf(".") != -1) { 42 | // sessionId = url.substring(url.lastIndexOf(".") + 1, url.length()); 43 | // if ("html".equalsIgnoreCase(sessionId) || "htm".equalsIgnoreCase(sessionId) || "jsp".equalsIgnoreCase(sessionId)) { 44 | // flag = true; 45 | // } 46 | // } else { 47 | // flag = true; 48 | // } 49 | // 50 | // if (flag) { 51 | // RequestIdUtils.setRequestId(); 52 | // MDC.put("requestId", RequestIdUtils.getRequestId()); 53 | // MDC.put("serverIp", this.ip); 54 | // MDC.put("appId", this.appId); 55 | // sessionId = CookieManager.getCookie("sessionId", req); 56 | // if (!StringUtils.hasText(sessionId)) { 57 | // sessionId = UUID.randomUUID().toString(); 58 | // CookieManager.addCookieInMermory("sessionId", sessionId, "/", "", res); 59 | // } 60 | // 61 | // RequestIdUtils.setSessionId(sessionId); 62 | // MDC.put("sessionId", sessionId); 63 | // String referer = req.getHeader("referer"); 64 | // String userAgent = req.getHeader("User-Agent"); 65 | // this.logger.info("access info :{} \"{} {}\" {} \"{}\" \"{}\"", new Object[]{IPUtils.getIpAddr(req), req.getMethod(), req.getRequestURL(), req.getProtocol(), referer == null ? "" : referer, userAgent == null ? "" : userAgent}); 66 | // } 67 | System.out.println("---Filter demo--->"); 68 | chain.doFilter(request, response); 69 | } 70 | 71 | public void destroy() { 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /flylib-boot-starter/src/main/java/org/flylib/boot/starter/handler/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.handler; 2 | 3 | import org.flylib.boot.starter.exception.CustomRuntimeException; 4 | import org.flylib.boot.starter.exception.UnknownResourceException; 5 | import org.flylib.boot.starter.exception.ValidationRuntimeException; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.TypeMismatchException; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.context.MessageSource; 11 | import org.springframework.core.env.Environment; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.http.converter.HttpMessageNotReadableException; 14 | import org.springframework.ui.Model; 15 | import org.springframework.web.HttpMediaTypeNotAcceptableException; 16 | import org.springframework.web.HttpMediaTypeNotSupportedException; 17 | import org.springframework.web.HttpRequestMethodNotSupportedException; 18 | import org.springframework.web.bind.MissingServletRequestParameterException; 19 | import org.springframework.web.bind.annotation.ControllerAdvice; 20 | import org.springframework.web.bind.annotation.ExceptionHandler; 21 | import org.springframework.web.bind.annotation.ResponseBody; 22 | import org.springframework.web.context.request.ServletWebRequest; 23 | import org.springframework.web.servlet.LocaleResolver; 24 | import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException; 25 | 26 | import javax.servlet.http.HttpServletRequest; 27 | import javax.servlet.http.HttpServletResponse; 28 | import java.util.HashMap; 29 | import java.util.LinkedHashMap; 30 | import java.util.Locale; 31 | import java.util.Map; 32 | 33 | /** 34 | * 说明: 35 | * 36 | * @ControllerAdvice是controller的一个辅助类,最常用的就是作为全局异常处理的切面类 37 | * @ControllerAdvice可以指定扫描范围 38 | * @ControllerAdvice约定了几种可行的返回值,如果是直接返回model类的话,需要使用@ResponseBody进行json转换 返回String,表示跳到某个view 39 | * 返回modelAndView 40 | * 返回model + @ResponseBody 41 | * 全局异常处理 42 | */ 43 | @ControllerAdvice 44 | public class GlobalExceptionHandler { 45 | 46 | private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); 47 | 48 | @Autowired 49 | private Environment env; 50 | 51 | @Autowired(required = false) 52 | private MessageSource messageSource; 53 | 54 | @Autowired(required = false) 55 | private LocaleResolver localeResolver; 56 | 57 | private static final String defaultMoreInfoUrl = ""; 58 | 59 | private final Map DEFAULT_EXCEPTION_MAPPING_DEFINITIONS; 60 | 61 | public GlobalExceptionHandler() { 62 | DEFAULT_EXCEPTION_MAPPING_DEFINITIONS = createDefaultExceptionMappingDefinitions(); 63 | } 64 | 65 | @ExceptionHandler//处理所有异常 66 | @ResponseBody //在返回自定义相应类的情况下必须有,这是@ControllerAdvice注解的规定 67 | public Map exceptionHandler(Throwable e, HttpServletRequest request, HttpServletResponse response, Model model) { 68 | // 69 | log.error("handle error:",e); 70 | 71 | HttpStatus httpStatus = DEFAULT_EXCEPTION_MAPPING_DEFINITIONS.get(e.getClass().getName()); 72 | if(httpStatus==null){ 73 | httpStatus = HttpStatus.INTERNAL_SERVER_ERROR; 74 | } 75 | //是否是生产环境 76 | boolean isProd = "prod".equals(env.getActiveProfiles()[0]); 77 | Map map = new HashMap(); 78 | if(e.getCause() instanceof CustomRuntimeException){ 79 | CustomRuntimeException exception = (CustomRuntimeException) e.getCause(); 80 | map.put("code",String.valueOf(exception.getCode())); 81 | map.put("message",exception.getMessage()); 82 | }else if(e.getCause() instanceof ValidationRuntimeException){ 83 | ValidationRuntimeException exception = (ValidationRuntimeException) e.getCause(); 84 | map.put("code",String.valueOf(exception.getCode())); 85 | map.put("message",exception.getMessage()); 86 | httpStatus = HttpStatus.BAD_REQUEST; 87 | }else { 88 | map.put("code",String.valueOf(httpStatus.value())); 89 | map.put("message",httpStatus.toString()); 90 | } 91 | 92 | 93 | //不是生产环境,添加调试信息 94 | if(!isProd){ 95 | map.put("throwable",e); 96 | } 97 | response.setStatus(httpStatus.value()); 98 | return map; 99 | } 100 | 101 | protected final Map createDefaultExceptionMappingDefinitions() { 102 | 103 | Map m = new LinkedHashMap(); 104 | 105 | // 400 106 | applyDef(m, HttpMessageNotReadableException.class, HttpStatus.BAD_REQUEST); 107 | applyDef(m, MissingServletRequestParameterException.class, HttpStatus.BAD_REQUEST); 108 | applyDef(m, TypeMismatchException.class, HttpStatus.BAD_REQUEST); 109 | applyDef(m, "javax.validation.ValidationException", HttpStatus.BAD_REQUEST); 110 | 111 | // 404 112 | applyDef(m, NoSuchRequestHandlingMethodException.class, HttpStatus.NOT_FOUND); 113 | applyDef(m, "org.hibernate.ObjectNotFoundException", HttpStatus.NOT_FOUND); 114 | 115 | // 405 116 | applyDef(m, HttpRequestMethodNotSupportedException.class, HttpStatus.METHOD_NOT_ALLOWED); 117 | 118 | // 406 119 | applyDef(m, HttpMediaTypeNotAcceptableException.class, HttpStatus.NOT_ACCEPTABLE); 120 | 121 | // 409 122 | //can't use the class directly here as it may not be an available dependency: 123 | applyDef(m, "org.springframework.dao.DataIntegrityViolationException", HttpStatus.CONFLICT); 124 | 125 | // 415 126 | applyDef(m, HttpMediaTypeNotSupportedException.class, HttpStatus.UNSUPPORTED_MEDIA_TYPE); 127 | applyDef(m, UnknownResourceException.class, HttpStatus.NOT_FOUND); 128 | 129 | return m; 130 | } 131 | private void applyDef(Map m, Class clazz, HttpStatus status) { 132 | applyDef(m, clazz.getName(), status); 133 | } 134 | 135 | private void applyDef(Map m, String key, HttpStatus status) { 136 | m.put(key, status); 137 | } 138 | 139 | 140 | 141 | protected String getMessage(String msg, ServletWebRequest webRequest, Exception ex) { 142 | 143 | if (msg != null) { 144 | if (msg.equalsIgnoreCase("null") || msg.equalsIgnoreCase("off")) { 145 | return null; 146 | } 147 | msg = ex.getMessage(); 148 | if (messageSource != null) { 149 | Locale locale = null; 150 | if (localeResolver != null) { 151 | locale = localeResolver.resolveLocale(webRequest.getRequest()); 152 | } 153 | msg = messageSource.getMessage(msg, null, msg, locale); 154 | } 155 | } 156 | 157 | return msg; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /flylib-boot-starter/src/main/java/org/flylib/boot/starter/interceptor/ResponseHandlerInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.flylib.boot.starter.interceptor; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.web.method.HandlerMethod; 9 | import org.springframework.web.servlet.HandlerInterceptor; 10 | import org.springframework.web.servlet.ModelAndView; 11 | 12 | /** 13 | * @author liushaoming 14 | * @create 2017-12-04 10:29 15 | **/ 16 | public class ResponseHandlerInterceptor implements HandlerInterceptor { 17 | private static final Logger logger = LoggerFactory.getLogger(ResponseHandlerInterceptor.class); 18 | 19 | public ResponseHandlerInterceptor() { 20 | } 21 | 22 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 23 | request.setAttribute("startTime", System.currentTimeMillis()); 24 | return true; 25 | } 26 | 27 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 28 | String contentType = request.getHeader("Accept"); 29 | if (contentType != null && contentType.indexOf("json") != -1) { 30 | HandlerMethod handlerMethod = (HandlerMethod) handler; 31 | Class clazz = handlerMethod.getReturnType().getMethod().getReturnType(); 32 | if ("void".equals(clazz.toString())) { 33 | response.getWriter().write("{\"code\":\"0\",\"message\":\"ok\"}"); 34 | } 35 | } 36 | 37 | } 38 | 39 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 40 | long startTime = ((Long) request.getAttribute("startTime")).longValue(); 41 | long endTime = System.currentTimeMillis(); 42 | long executeTime = endTime - startTime; 43 | logger.info("[" + handler + "] executeTime :{} ms for request {}", executeTime, request.getRequestURI()); 44 | } 45 | } 46 | --------------------------------------------------------------------------------