首先说明一下,这里使用的是Springboot2.2.6.RELEASE版本,由于Springboot迭代很快,所以要注意版本问题。
1、SpringBoot中异常处理方式。SpringBoot中对于异常处理提供了五种处理方式。
1.1、第一种方式,自定义错误页面。
SpringBoot默认的处理异常的机制:SpringBoot 默认的已经提供了一套处理异常的机制。一旦程序中出现了异常 SpringBoot 会像/error 的 url 发送请求。在springBoot 中提供了一个叫BasicExceptionController来处理/error请求,然后跳转到默认显示异常的页面来展示异常信息。
上面的界面是Springboot提供的默认错误界面,我们可以自己修改这恶鬼错误的界面。如果我们需要将所有的异常同一跳转到自定义的错误页面,需要再src/main/resources/templates目录下创建error.html页面。注意:错误界面的名称必须叫error。
缺点:自定义错误界面处理异常,异常信息颗粒度比较粗,不符合异常处理的原则。异常处理原则,对关心异常在一个界面进行展示,对不关心的异常可以统一跳转到一个界面进行展示。
1 "-//W3C//DTD HTML 4.01 Transitional//EN" 2 "http://www.w3.org/TR/html4/loose.dtd"> 3 "http://www.w3.org/1999/xhtml"> 4 5错误提示页面 6 7 8 9 出错了,请与管理员联系...... 10 11 12 13
1.2、第二种方式,@ExceptionHandle 注解处理异常。
1 package com.bie.springboothello.controller; 2 3 import org.springframework.stereotype.Controller; 4 import org.springframework.ui.Model; 5 import org.springframework.web.bind.annotation.ExceptionHandler; 6 import org.springframework.web.bind.annotation.RequestMapping; 7 import org.springframework.web.bind.annotation.ResponseBody; 8 import org.springframework.web.servlet.ModelAndView; 9 10 /** 11 * 12 */ 13 @Controller 14 public class DemoController { 15 16 @RequestMapping(value = "/hello") 17 @ResponseBody 18 public String showUser(Model model) { 19 String str = null; 20 str.length(); 21 return "hello"; 22 } 23 24 /** 25 * 该方法需要返回一个ModelAndView,目的是可以让我们封装异常信息以及试图的指定参数Exception e, 26 * 会将产生异常对象注入到方法中。 27 *28 *
29 * 该方法可以处理ArithmeticException算术异常,程序中抛出算术异常,该方法就可以进行捕获。 30 * 根据方法中的定义做什么操作,会将异常对象Exception注入进来,所以需要Exception参数。 31 * 32 * @param e 33 * @return 34 * @ExceptionHandler该注解的value值是可以处理那个异常的异常类型。 35 */ 36 @ExceptionHandler(value = {java.lang.ArithmeticException.class}) 37 public ModelAndView arithmeticExceptionHandler(Exception e) { 38 ModelAndView modelAndView = new ModelAndView(); 39 modelAndView.addObject("error", e.toString()); 40 modelAndView.setViewName("error1"); 41 return modelAndView; 42 } 43 44 45 /** 46 * java.lang.NullPointerException 47 *
48 *
49 * 该方法需要返回一个 ModelAndView,目的是可以让我们封装异常信息以及视图的指定参数Exception e: 50 * 会将产生异常对象注入到方法中 51 * 52 * @param e 53 * @return 54 */ 55 @ExceptionHandler(value = {java.lang.NullPointerException.class}) 56 public ModelAndView nullPointerExceptionHandler(Exception e) { 57 ModelAndView mv = new ModelAndView(); 58 mv.addObject("error", e.toString()); 59 mv.setViewName("error2"); 60 return mv; 61 } 62 63 }
可以根据不同的错误来定义不同的错误提示界面,如下创建了error1.html、error2.html。
1 "-//W3C//DTD HTML 4.01 Transitional//EN" 2 "http://www.w3.org/TR/html4/loose.dtd"> 3 "http://www.w3.org/1999/xhtml"> 4 5错误提示页面 6 7 8 9 java.lang.ArithmeticException出错了,请与管理员联系...... 10 "${error}"> 11 12 13
1 "-//W3C//DTD HTML 4.01 Transitional//EN" 2 "http://www.w3.org/TR/html4/loose.dtd"> 3 "http://www.w3.org/1999/xhtml"> 4 5错误提示页面 6 7 8 9 java.lang.NullPointerException出错了,请与管理员联系...... 10 "${error}"> 11 12 13
缺点,如果该Controller需要处理的异常比较多,就会给代码造成了冗余现象。该方法只能对该Controller的异常进行处理,不可以跨Controller进行异常处理。
1.3、第三种方式,@ControllerAdvice+@ExceptionHandler 注解处理异常。
1 package com.bie.springboothello.controller; 2 3 import org.springframework.web.bind.annotation.ControllerAdvice; 4 import org.springframework.web.bind.annotation.ExceptionHandler; 5 import org.springframework.web.servlet.ModelAndView; 6 7 /** 8 * 全局异常处理类。 9 * 需要创建一个能够处理异常的全局异常类。在该类上需要添加@ControllerAdvice注解 10 */ 11 @ControllerAdvice // 该注解可以实现全局异常处理 12 public class GlobalException { 13 14 15 /** 16 * java.lang.ArithmeticException。 17 *18 * 该方法需要返回一个 ModelAndView,目的是可以让我们封装异常信息以及视图的指定参数 19 * Exception e:会将产生异常对象注入到方法中。 20 * 21 * @param e 22 * @return 23 */ 24 @ExceptionHandler(value = {java.lang.ArithmeticException.class}) 25 public ModelAndView arithmeticExceptionHandler(Exception e) { 26 ModelAndView mv = new ModelAndView(); 27 mv.addObject("error", e.toString()); 28 mv.setViewName("error1"); 29 return mv; 30 } 31 32 33 /** 34 * java.lang.NullPointerException。 35 *
36 * 该方法需要返回一个 ModelAndView:目的是可以让我们封装异常信息以及视图的指定参数 37 * Exception e:会将产生异常对象注入到方法中。 38 * 39 * @param e 40 * @return 41 */ 42 @ExceptionHandler(value = {java.lang.NullPointerException.class}) 43 public ModelAndView nullPointerExceptionHandler(Exception e) { 44 ModelAndView mv = new ModelAndView(); 45 mv.addObject("error", e.toString()); 46 mv.setViewName("error2"); 47 return mv; 48 } 49 50 }
可以根据不同的错误来定义不同的错误提示界面,如下创建了error1.html、error2.html。这里直接使用了上面创建的错误界面error1.htm、error2.html。
1.4、第四种方式,配置 SimpleMappingExceptionResolver 处理异常。该处理方式是对第三种处理异常的简化。
1 package com.bie.springboothello.controller; 2 3 4 import org.springframework.context.annotation.Bean; 5 import org.springframework.context.annotation.Configuration; 6 import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; 7 8 import java.util.Properties; 9 10 /** 11 * 通过SimpleMappingExceptionResolver做全局异常处理 12 */ 13 @Configuration 14 public class GlobalException { 15 16 @Bean 17 public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver() { 18 SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver(); 19 Properties mappings = new Properties(); 20 // 参数一:异常的类型,注意必须是异常类型的全名 21 // 参数二:视图名称 22 mappings.put("java.lang.ArithmeticException", "error1"); 23 mappings.put("java.lang.NullPointerException", "error2"); 24 // 设置异常与视图映射信息的 25 resolver.setExceptionMappings(mappings); 26 return resolver; 27 } 28 29 30 }
可以根据不同的错误来定义不同的错误提示界面,如下创建了error1.html、error2.html。这里直接使用了上面创建的错误界面error1.htm、error2.html。
缺点,和第三种方式对比,无法传递异常对象信息,只是跳转到指定的异常错误界面了。
1.5、第五种方式,自定义 HandlerExceptionResolver 类处理异常。需要在全局异常处理类中实现HandlerExceptionResolver接口。
1 package com.bie.springboothello.controller; 2 3 4 import org.springframework.context.annotation.Configuration; 5 import org.springframework.web.servlet.HandlerExceptionResolver; 6 import org.springframework.web.servlet.ModelAndView; 7 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 /** 12 * 通过实现 HandlerExceptionResolver接口做全局异常处理 13 */ 14 @Configuration 15 public class GlobalException implements HandlerExceptionResolver { 16 17 @Override 18 public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { 19 ModelAndView mv = new ModelAndView(); 20 // 判断不同异常类型,做不同视图跳转 21 if (ex instanceof ArithmeticException) { 22 mv.setViewName("error1"); 23 } 24 if (ex instanceof NullPointerException) { 25 mv.setViewName("error2"); 26 } 27 mv.addObject("error", ex.toString()); 28 return mv; 29 } 30 31 32 }
可以根据不同的错误来定义不同的错误提示界面,如下创建了error1.html、error2.html。这里直接使用了上面创建的错误界面error1.htm、error2.html。
2、Spring Boot整合Junit 单元测试。在pom.xml配置文件中加入junit的启动类依赖包。
1 23 org.springframework.boot 4spring-boot-starter-test 5test 6 12
Spring Boot整合Junit 单元测试,代码如下所示:
1 package com.bie.springboothello; 2 3 import com.bie.springboothello.po.Users; 4 import com.bie.springboothello.service.UsersService; 5 import org.junit.jupiter.api.Test; 6 import org.junit.runner.RunWith; 7 import org.springframework.beans.factory.annotation.Autowired; 8 import org.springframework.boot.test.context.SpringBootTest; 9 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 10 11 /** 12 * Springboot测试类。 13 * 14 * @RunWith:启动器。 SpringJUnit4ClassRunner.class:让junit与spring环境进行整合。 15 * @SpringBootTest(classes={SpringbootHelloApplication.class}) 第一层含义, 当前类为springBoot的测试类。 16 * @SpringBootTest(classes={SpringbootHelloApplication.class}) 第二层含义, 加载SpringBoot启动类。启动springBoot。 17 *18 * junit 与 spring 整合 @Contextconfiguartion("classpath:applicationContext.xml") 19 */ 20 @RunWith(value = SpringJUnit4ClassRunner.class) 21 @SpringBootTest(classes = {SpringbootHelloApplication.class}) 22 class SpringbootHelloApplicationTests { 23 24 @Autowired 25 private UsersService usersService; 26 27 @Test 28 public void testAddUser() { 29 System.out.println("开始---------------------------------------------"); 30 this.usersService.addUser(new Users("别先生", 25)); 31 System.out.println("结束---------------------------------------------"); 32 } 33 34 }
3、Spring Boot热部署。Springboot的热部署,热部署就是在服务不停止的情况下,完成项目的部署处理。意思就是修改完系统就可以立刻看到效果,不用重启项目。
SprigBoot的热部署方式分为两种,第一种是SpringLoader插件、第二种DevTools工具。
在这里吐槽一下eclipse和idea吧,我以eclipse为主,也比较喜欢eclipse吧,因为eclipse免费,哈哈哈,idea收费的,虽然可以买或者找到破解的方法,但是个人还是比较喜欢eclipse的,虽说idea收费版创建springboot是真的爽,eclipse也集成了springboot创建的插件,但是创建成功还需要进行简单的配置,不然pom.xml老是报错,也是十分不爽的。还有一个就是就比如此案例,idea想以maven方式运行项目,可能自己对idea不熟悉吧,嗯,此案例又换成了eclipse创建,练习热部署。
3.1、方式一:以 maven 插件方式使用 SpringLoader。在pom文件中添加插件配置。springloader插件添加到pom.xml配置文件中,将插件的依赖包导入到maven中。
1 23 4 165 15org.springframework.boot 6spring-boot-maven-plugin 78 149 13org.springframework 10springloaded 111.2.5.RELEASE 12
完整的pom.xml配置文件,如下所示:
注意:开始使用的是Springboot2.2.7.RELEASE版本,死活实现不了修改后台,热部署启动,改成了1.5.10.RELEASE版本才实现了效果,我想我大概是不会使用这种方法来实现热部署吧。
1"http://maven.apache.org/POM/4.0.0" 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 4 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 4.0.0 67 12org.springframework.boot 8spring-boot-starter-parent 9 101.5.10.RELEASE 11com.bie.springboot 13springboot-world 140.0.1-SNAPSHOT 15 16 1718 24 251.8 19 203.1.1 213.0.2.RELEASE 222.0.4 2326 38 39 4027 30 31 32org.springframework.boot 28spring-boot-starter-web 2933 36 37org.springframework.boot 34spring-boot-starter-thymeleaf 3541 55 5642 5443 53org.springframework.boot 44spring-boot-maven-plugin 4546 5247 51org.springframework 48springloaded 491.2.5.RELEASE 50
注意:使用 maven 的命令起来启动,如果还是以直接运行main方法启动的话,是没有使用到这个插件的。所以要使用maven的命令运行,才可以做到热部署效果,但是此插件只能做到修改后台不用启动,前端html修改了是无法进行热部署的。
使用 maven 的命令spring-boot:run来启动项目。
SpringLoader插件的缺陷:就是 Java 代码做部署处理,但是对页面无能为力。
效果,如下所示:
注意:这种方式的缺点是 Springloader 热部署程序是在 系统后台以进程的形式来运行,需要手动关闭该进程。嗯,我更不要选择这种方式来做热部署了。
Windows下查看进程及结束进程命令。查看占用8080端口的进程号。
可知,进程号为10968的进程占用了8080端口,可以使用命令 tasklist | findstr “10968”进一步查看10968进程的具体信息。可知10968进程为javaw.exe。
tasklist | findstr "10968"
杀掉进程,tskill 10968。
如果显示'tskill' 不是内部或外部命令,也不是可运行的程序或批处理文件。那么用任务管理器吧,找到pid结束进程。
或者在项目中直接使用jar包的方式,添加springloader的jar包,在项目的lib目录下面添加springloader的jar包。然后在启动的时候使用maven的命令来启动。
启动命令: -javaagent:.\lib\springloaded-1.2.5.RELEASE.jar -noverify
3.1、方式二:使用DevTools 工具,修改项目的 pom.xml配置文件添加 devtools 的依赖。
注意:SpringLoader与DevTools 的区别:
1)、SpringLoader:SpringLoader 在部署项目时使用的是热部署的方式。
2)、DevTools:DevTools 在部署项目时使用的是重新部署的方式。
1 "1.0" encoding="UTF-8"?> 2"http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 4.0.0 56 11org.springframework.boot 7spring-boot-starter-parent 82.2.6.RELEASE 910 com.bie 12springboot-hello 130.0.1-SNAPSHOT 14springboot-hello 15Demo project for Spring Boot 16 1718 20 211.8 1922 73 7423 26 27org.springframework.boot 24spring-boot-starter-web 2528 38 39org.springframework.boot 29spring-boot-starter-test 30test 31 3740 43 44org.springframework.boot 41spring-boot-starter-thymeleaf 4245 49 50org.mybatis.spring.boot 46mybatis-spring-boot-starter 472.1.1 4851 54 55mysql 52mysql-connector-java 5356 60com.alibaba 57druid 581.1.10 5961 65 66junit 62junit 63test 6467 72org.springframework.boot 68spring-boot-devtools 69 70true 7175 91 92 9376 81 82 9077 80org.springframework.boot 78spring-boot-maven-plugin 79
如果Idea如法实现热部署,那么可能是idea和DevTools和Loader的配置问题,Intellij IEDA和Eclipse不同,Eclipse一般设置了自动编译,而IDEA需要自己打开。
在setting->Build,Execution,Deployment->Compiler找到 Build Project Automatically。 这个选项再Eclipse是默认打开的,再IDEA要手动打开。
然后找个地方ctrl+shift+alt+/ 调出Maintenance(维护)控制台,选择Registry(登记)。
勾选运行时自动编译(auto-making when app running)。重启Idea就可以了。
重启之后,此时修改前端还是后台,都可以实现热部署的,如果修改后端的话,Idea控制台会重新部署,如果是修改前端界面,是不会重新部署的,但是也已经刷新了。大大节省了时间和精力。