SpringBoot 2.x (5):异常处理与部署WAR项目
异常处理:
SpringBoot的异常处理是不友好的,前端只会显示最基本的错误名称
后端控制台会报出具体的错误,那么我们如何告知前端具体的错误信息呢?
1:对全局异常进行处理
一个测试的Controller:
package org.dreamtech.springboot.exception; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ExceptionController { @RequestMapping("/test/exception") private Object test() { int i = 1 / 0; return "test"; } }
自定义一个异常处理类:
package org.dreamtech.springboot.exception; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice //类似的,有@ControllerAdvice public class CustomExceptionHandler { @ExceptionHandler(value = Exception.class) Object handleException(Exception e, HttpServletRequest request) { Map<String, Object> map = new HashMap<String, Object>(); map.put("code", 100); map.put("errMsg", e.toString()); map.put("url", request.getRequestURI()); return map; } }
更进一步,可以加入日志处理:
package org.dreamtech.springboot.exception; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice public class CustomExceptionHandler { private static final Logger LOG = LoggerFactory.getLogger(CustomExceptionHandler.class); @ExceptionHandler(value = Exception.class) Object handleException(Exception e, HttpServletRequest request) { LOG.error("url {},msg {}", request.getRequestURI(), e.toString()); Map<String, Object> map = new HashMap<String, Object>(); map.put("code", 100); map.put("errMsg", e.toString()); map.put("url", request.getRequestURI()); return map; } }
如果前端访问了测试URL,应该显示的内容是:
{"code":100,"errMsg":"java.lang.ArithmeticException: / by zero","url":"/test/exception"}
2.自定义异常处理
导入SpringBoot推荐的thymeleaf模板引擎:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
新建自定义异常类:
package org.dreamtech.springboot.exception; public class MyException extends RuntimeException { private static final long serialVersionUID = -1876094492594770999L; public MyException(String code, String msg) { super(); this.code = code; this.msg = msg; } private String code; private String msg; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
测试Controller:
package org.dreamtech.springboot.exception; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ExceptionController { @RequestMapping("/test/exception") private Object test() { throw new MyException("101", "error"); } }
异常处理类:
package org.dreamtech.springboot.exception; import javax.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.servlet.ModelAndView; @ControllerAdvice public class CustomExceptionHandler { @ExceptionHandler(value = MyException.class) Object handleException(MyException e, HttpServletRequest request) { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("error.html"); modelAndView.addObject("msg", e.toString()); System.out.println(e.toString()); return modelAndView; } }
可以看出,我这里是返回了一个错误页面:error.html,当然也可以返回JSON,类似上面的@RestControllerAdvice
巧合的是,我运行SpringBoot之后发现所有错误页面都跳转到error.html,一开始以为是配置错误了
后来仔细测试后发现,SpringBoot默认将error.html作为同意异常处理页面了,哈哈
部署WAR项目:
通常情况下,我们都会将SpringBoot项目打包成JAR包,然后java -jar启动
然而,有些特殊情况下,我们不得不使用老方式打包成WAR然后部署Tomcat
无论打包成JAR还是WAR都需要MAVEN插件:通常自动生产的项目是自带的
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
如果要打包成WAR,首先需要定义打包方式为WAR:
<packaging>war</packaging>
然后在BUILD中加入项目名称:
<build> <finalName>demo</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
下载Tomcat,针对SpringBoot2.x推荐Tomcat9以上版本
https://tomcat.apache.org/download-90.cgi
修改启动类:
public class DemoApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(DemoApplication.class); } public static void main(String[] args) throws Exception { SpringApplication.run(DemoApplication.class, args); } }
然后打包即可
容器不只有Tomcat,还有Jetty和Undertow等等,只不过最常用的是Tomcat
针对容器的性能,可以采用Jmter进行测试
SpringBoot的启动流程: