• SpringBoot_第六章(知识点总结)


    目录

    目录

    1:拦截器(Interceptor)

    1.1:拦截器代码实现

    1.2:拦截器源码分析和流程总结

    2:过滤器(Filter)、自定义(Servlet)、监听器(Listener)

    3:文件上传

    3.1:文件上传代码实现

    3.2:文件上传源码分析

    4:整合druid数据源

    4.1:整合德鲁伊

    4.2:德鲁伊监控页面

    5:Spingboot指标监控

    5.1:为什么能实现指标监控

    5.2:怎么能实现指标监控

    6:整合mybatis、mybatis-plus

    6.1:整合mybatis

    6.2:整合mybatis-plus

    7:整合redis集群

    8:错误处理

    8.1:请求不存在的controller

    8.2:请求存在但是代码错误的controller

    8.3:前后端未分离

    8.4: 前后端分析,全局异常

    9:springBoot的run()方法

    9.1:创建application对象

    9.2:执行run()方法


    1:拦截器(Interceptor)

    1.1:拦截器代码实现

    拦截器是Spring容器进行管理的,对请求路径进行动态的拦截,可以进行各种权限日志等等骚操作。

    代码实现第一步:自己实现HandlerInterceptor接口

    1. /**
    2. * 登录检查 拦截器
    3. *
    4. * 1:写拦截器代码逻辑
    5. * 2 配置拦截器拦截 那些请求
    6. */
    7. @Slf4j
    8. public class LoginInterceptor implements HandlerInterceptor {
    9. /**
    10. * controller方法 执行之前
    11. * @return
    12. * @throws Exception
    13. */
    14. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    15. throws Exception {
    16. log.info("拦截请求{}"+request.getRequestURI());
    17. User user = (User) request.getSession().getAttribute("loginUser");
    18. if (user == null) {
    19. System.out.println("拦截器重定向");
    20. //如果session不存在登录信息,重定向到登录页面
    21. request.setAttribute("msg","拦截器拦截未登录");
    22. request.getRequestDispatcher("/").forward(request,response);
    23. return false;
    24. }
    25. return true;//返回true 程序接着执行
    26. }
    27. /**
    28. * controller方法执行之后,在页面渲染之前
    29. */
    30. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    31. @Nullable ModelAndView modelAndView) throws Exception {
    32. log.info("controller方法执行之后{}",modelAndView);
    33. }
    34. /**
    35. * 页面渲染之后
    36. */
    37. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
    38. @Nullable Exception ex) throws Exception {
    39. log.info("页面渲染之后{}",ex);
    40. }
    41. }

    代码实现第二步:自定义拦截器拦截路径和放行路径

    1. /**
    2. * 实现WebMvcConfigurer接口 改变MVC行为
    3. * 使用addInterceptors 接口添加拦截器
    4. */
    5. @Configuration
    6. public class MyMvcConfig implements WebMvcConfigurer {
    7. @Override
    8. public void addInterceptors(InterceptorRegistry registry) {
    9. registry.addInterceptor(new LoginInterceptor())
    10. .addPathPatterns("/*") // /**拦截所有请求,包含静态页面 /*:只拦截后面一级 /**:拦截内容包含多个层级
    11. .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/*","/js/**");//过滤掉登录请求和静态资源
    12. }
    13. }

    1.2:拦截器源码分析和流程总结

    所以真正的执行步骤如下:

    2:过滤器(Filter)、自定义(Servlet)、监听器(Listener)

    Filter、servlet是Servlet规范,拦截的是自定义的请求。因为DispatcherServlet拦截的是/

    但是Filter、servlet可以自定义拦截请求,根据匹配规则,他们会自己处理请求。

    Filter代码实现:

    1. /**
    2. * 继承Filter
    3. * 不会经过拦截器
    4. * 拦截/*所有请求 不管get post
    5. *
    6. * 使用次注解生效
    7. * @ServletComponentScan(basePackages = "com.example.springboot2_web03")
    8. */
    9. @WebFilter(urlPatterns = "/*",filterName = "MyFilter")
    10. public class MyFilter implements Filter {
    11. @Override
    12. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    13. String name = request.getParameter("name");
    14. System.out.println("执行MyFilter无论什么get、post方法:"+name);
    15. chain.doFilter(request,response);//调用链
    16. }
    17. }

    Servlet代码实现: 

    1. /**
    2. * 继承HttpServlet类,可以重写各种get post put 等等方法
    3. *
    4. * 使用次注解生效
    5. * @ServletComponentScan(basePackages = "com.example.springboot2_web03")
    6. *
    7. * servlet 拦截/s1(精度高 优先匹配) 就不会进入DispatcherServlet拦截/
    8. */
    9. @WebServlet(urlPatterns = "/s1",name = "MyServlet")
    10. public class MyServlet extends HttpServlet {
    11. @Override
    12. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    13. String name = req.getParameter("name");
    14. System.out.println("执行MyServlet请求get:"+name);
    15. resp.getWriter().write("get请求MyServlet拦截/s1请求:"+name);
    16. }
    17. @Override
    18. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    19. String name = req.getParameter("name");
    20. System.out.println("执行MyServlet请求post:"+name);
    21. resp.getWriter().write("post请求MyServlet拦截/s1请求:"+name);
    22. }
    23. }

    监听器代码实现:

    1. /**
    2. * 继承ServletContextListener
    3. * 容器启动的时候生效
    4. *
    5. * 使用次注解生效
    6. * @ServletComponentScan(basePackages = "com.example.springboot2_web03")
    7. */
    8. @WebListener(value = "MyListener")
    9. public class MyListener implements ServletContextListener {
    10. @Override
    11. public void contextInitialized(ServletContextEvent sce) {
    12. System.out.println("MyListener监听ServletContext初始化,容器启动的时候输出");
    13. }
    14. @Override
    15. public void contextDestroyed(ServletContextEvent sce) {
    16. System.out.println("MyListener监听ServletContext销毁");
    17. }
    18. }

     
    

    3:文件上传

    3.1:文件上传代码实现

    第一步:html文件

    1. <form role="form" th:action="@{/fileUpload}" method="post" enctype="multipart/form-data">
    2. <div class="form-group">
    3. <label for="exampleInputEmail1">邮箱label>
    4. <input type="email" name="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
    5. div>
    6. <div class="form-group">
    7. <label for="exampleInputPassword1">名字label>
    8. <input type="text" name="username" class="form-control" id="exampleInputPassword1" placeholder="Password">
    9. div>
    10. <div class="form-group">
    11. <label for="exampleInputFile">头像label>
    12. <input type="file" name="headerImg" id="exampleInputFile">
    13. div>
    14. <div class="form-group">
    15. <label for="exampleInputFile">生活照label>
    16. <input type="file" name="photos" multiple>
    17. div>
    18. <button type="submit" class="btn btn-primary">提交button>
    19. form>

    第二步Java代码实现:

    1. /**
    2. * 文件上传
    3. * @param files
    4. * @return
    5. */
    6. @PostMapping(value = "/fileUpload")
    7. public String fileUpload(@RequestParam(value = "username") String username,
    8. @RequestParam(value = "email")String email,
    9. @RequestParam(value = "headerImg") MultipartFile headerImg,
    10. @RequestParam(value = "photos") MultipartFile[] photos,
    11. Files files) throws IOException {
    12. if (!headerImg.isEmpty()){
    13. System.out.println("username:"+username);
    14. System.out.println("email:"+email);
    15. System.out.println("files:"+files);
    16. //headerImg 单文件
    17. System.out.println("headerImg名字:"+ headerImg.getOriginalFilename());
    18. System.out.println("headerImg大小:"+ headerImg.getSize());
    19. System.out.println("headerImg文件类型:"+ headerImg.getContentType());
    20. String newFileHeaderImg="A"+headerImg.getOriginalFilename();
    21. headerImg.transferTo(new File("/Users/huyiju/Desktop/upload/"+newFileHeaderImg));
    22. }
    23. if (photos.length>0){
    24. //photos多文件用MultipartFile[]数组
    25. for (MultipartFile photo : photos) {
    26. File file=new File("","");
    27. String newFilePhotos="B"+photo.getOriginalFilename();
    28. photo.transferTo(new File("/Users/huyiju/Desktop/upload/"+newFilePhotos));
    29. }
    30. }
    31. return "/form/form_layouts";
    32. }

     第三步配置文件设置文件上传大小

    1. #单个文件上限
    2. spring.servlet.multipart.max-file-size=10MB
    3. #多个文件请求上限
    4. spring.servlet.multipart.max-request-size=100MB

    3.2:文件上传源码分析

    首先查看源码MultipartAutoConfiguration的自动装配

    有了文件上传解析器,我们在配置文件中设置上传文件大小配置,默认是1MB(单个文件)和10MB(最大请求)

    然后查看源码

    1. //for循环将controller的参数逐个绑定
    2. args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
    3. //根据请求multipartRequest获取MultipartFile 并将返回值
    4. //赋值给 controller中的MultipartFile 类型的参数
    5. //
    6. List files = multipartRequest.getFiles(name);
    7. return (!files.isEmpty() ? files.toArray(new MultipartFile[0]) : null);

    4:整合druid数据源

    4.1:整合德鲁伊

    1:导入依赖

    1. <dependency>
    2. <groupId>mysqlgroupId>
    3. <artifactId>mysql-connector-javaartifactId>
    4. dependency>
    5. <dependency>
    6. <groupId>com.alibabagroupId>
    7. <artifactId>druid-spring-boot-starterartifactId>
    8. <version>1.2.16version>
    9. dependency>

    2:配置数据库信息和连接池

    1. #德鲁伊数据库连接
    2. spring.datasource.url=jdbc:mysql://localhost:3306/W1?useUnicode=true&characterEncoding=utf-8&useSSL=false
    3. spring.datasource.username=root
    4. spring.datasource.password=123456
    5. #连接池信息
    6. spring.datasource.type= com.alibaba.druid.pool.DruidDataSource
    7. spring.datasource.druid.max-active=20
    8. spring.datasource.druid.min-idle=5
    9. spring.datasource.druid.initial-size=5
    10. spring.datasource.druid.max-wait=60000

    3:代码测试(未使用mybatis,所以这里使用了jdbcTemplate)

    1. @Autowired
    2. JdbcTemplate jdbcTemplate;
    3. /**
    4. * druid测试
    5. */
    6. @Test
    7. void starter_jdbc() {
    8. String sql="select * from t1";
    9. List> maps = jdbcTemplate.queryForList(sql);
    10. maps.forEach(map -> System.out.println(map));
    11. }

    4:结果查看(图片里边初始化的德鲁伊连接池)

    4.2:德鲁伊监控页面

    德鲁伊的依赖包含监控页面功能,只是没有开启我们只需要配置文件开启监控页面就可以

    1:配置监控页面信息

    1. # StatViewServlet配置,说明请参考Druid Wiki,配置_StatViewServlet配置
    2. #是否启用StatViewServlet(监控页面)默认值为false(考虑到安全问题默认并未启动,如需启用建议设置密码或白名单以保障安全)
    3. spring.datasource.druid.stat-view-servlet.enabled=true
    4. spring.datasource.druid.stat-view-servlet.reset-enable=false
    5. spring.datasource.druid.stat-view-servlet.login-username=root
    6. spring.datasource.druid.stat-view-servlet.login-password=123456
    7. ### WebStatFilter配置,说明请参考Druid Wiki,配置_配置WebStatFilter
    8. spring.datasource.druid.web-stat-filter.enabled=true
    9. spring.datasource.druid.web-stat-filter.url-pattern=/*
    10. spring.datasource.druid.web-stat-filter.session-stat-enable=true
    11. spring.datasource.druid.web-stat-filter.session-stat-max-count=1000
    12. spring.datasource.druid.filters=stat,wall
    13. spring.datasource.druid.filter.stat.slow-sql-millis=1000
    14. spring.datasource.druid.filter.stat.log-slow-sql=true
    15. spring.datasource.druid.filter.stat.enabled=true

    2:页面验证

    登录页面,输入账户密码root、123456

    http://localhost:8080/druid/login.html

    5:Spingboot指标监控

    5.1:为什么能实现指标监控

    当我们导入actuator的jar包,打开指标监控的配置文件,访问不同的请求地址,被拦截返回json,就能看到截图中的这些项目信息,不同的指标监控请求能得到项目信息。

    1:导入jar

    1. <dependency>
    2. <groupId>org.springframework.bootgroupId>
    3. <artifactId>spring-boot-starter-actuatorartifactId>
    4. dependency>

    2:打开指标监控 

    1. #开启指标监控 暴露所有 http://localhost:8081/actuator/
    2. management.endpoints.enabled-by-default=true
    3. management.endpoints.web.exposure.include=*
    4. #显示health的详细信息
    5. management.endpoint.health.show-details=ALWAYS
    6. management.info.env.enabled=true
    7. #自定义info信息 http://localhost:8081/actuator/info @project.artifactId@导入maven的pom信息
    8. info.appName=SpringBootWeb04
    9. info.appNameVersion=阿斯顿发生
    10. info.mavenName=@project.artifactId@

     3:访问页面http://localhost:8082/actuator

    5.2:怎么能实现指标监控

    上边的指标监控很详细,但是没有可视化页面。需要我们访问不同的请求得到不同的信息。这个时候就需要一个中控台来同一管理,可视化页面来操作。我们启动一个控制台服务,导入jar,这控制台当我们查询的时候 就会每一秒向两个81和82发送http://localhost:8082/actuator/不同路径

    来发送不同的信息,这个就是原理

    1:控制台服务器8888导入jar,启动服务

    1. <dependency>
    2. <groupId>de.codecentricgroupId>
    3. <artifactId>spring-boot-admin-starter-serverartifactId>
    4. <version>2.7.9version>
    5. dependency>

    启动服务:

    1. @SpringBootApplication
    2. @EnableAdminServer //启动服务管理服务器
    3. public class SpringBoot04AdminServiceApplication {
    4. public static void main(String[] args) {
    5. System.out.println("进入adminUI的管理页面");
    6. SpringApplication.run(SpringBoot04AdminServiceApplication.class, args);
    7. }
    8. }

    2:控制台客户端8081、8082导入jar,启动服务

    1. <dependency>
    2. <groupId>de.codecentricgroupId>
    3. <artifactId>spring-boot-admin-starter-clientartifactId>
    4. <version>2.7.9version>
    5. dependency>

    配置服务暴露和注册控制台

    1. #这里分别是80818082
    2. server.port=8082
    3. #监控服务 将服务注册到8888
    4. spring.boot.admin.client.url=http://localhost:8888
    5. spring.boot.admin.client.instance.prefer-ip=true
    6. #这里是控制台服务名字
    7. spring.application.name=springBoot_client2
    8. #开启指标监控 暴露所有 http://localhost:8081/actuator/
    9. management.endpoints.enabled-by-default=true
    10. management.endpoints.web.exposure.include=*

    启动项目

    1. @SpringBootApplication
    2. @MapperScan(value = {"com.example.springboot04_web_mvc1.mapper"})
    3. public class SpringBoot04WebMvc1Application {
    4. public static void main(String[] args) {
    5. SpringApplication.run(SpringBoot04WebMvc1Application.class, args);
    6. }
    7. }

    查看控制台

    更多详细点击查看 

    6:整合mybatis、mybatis-plus

    6.1:整合mybatis

    1:导入依赖

    1. <dependency>
    2. <groupId>org.mybatis.spring.bootgroupId>
    3. <artifactId>mybatis-spring-boot-starterartifactId>
    4. <version>2.1.3version>
    5. dependency>

    2:配置mapper映射位置

    1. #mybatis配置 config-location配置mybatis文件地址 mapper-locations mapper地址
    2. mybatis.config-location=classpath:mybatis-config.xml
    3. mybatis.mapper-locations=classpath:mapper/*.xml

    3:接口

    1. package com.example.springboot2_web03.mapper;
    2. import com.example.springboot2_web03.entity.T1;
    3. @Mapper
    4. public interface T1Mapper {
    5. List selectAll();
    6. T1 selectById(@Param(value = "id") int id);
    7. @Select("select * from t1 where id=#{id}")
    8. T1 selectById1(@Param(value = "id") int id);
    9. }

    4:mapper配置文件

    1. 1.0" encoding="UTF-8" ?>
    2. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    4. ">

    代码测试:

    1. @Autowired
    2. T1Mapper t1Mapper;
    3. /**
    4. * mybatis测试
    5. */
    6. @Test
    7. void mybatis_test() {
    8. List t1s = t1Mapper.selectAll();
    9. for (T1 t1 : t1s) {
    10. System.out.println("查询数据:"+t1);
    11. }
    12. T1 t1 = t1Mapper.selectById1(1);
    13. System.out.println("根据id查询:"+t1);
    14. }

    6.2:整合mybatis-plus

    1:导入依赖

    1. <dependency>
    2. <groupId>mysqlgroupId>
    3. <artifactId>mysql-connector-javaartifactId>
    4. dependency>
    5. <dependency>
    6. <groupId>com.alibabagroupId>
    7. <artifactId>druid-spring-boot-starterartifactId>
    8. <version>1.2.16version>
    9. dependency>
    10. <dependency>
    11. <groupId>com.baomidougroupId>
    12. <artifactId>mybatis-plus-boot-starterartifactId>
    13. <version>3.5.3.1version>
    14. dependency>
    15. <dependency>
    16. <groupId>com.baomidougroupId>
    17. <artifactId>mybatis-plus-extensionartifactId>
    18. <version>3.5.3.1version>
    19. <scope>compilescope>
    20. dependency>

    2:配置文件

    1. #mybatisPlus配置 config-location配置mybatis文件地址 mapper-locations mapper地址
    2. #mybatis-plus.config-location=classpath:mybatis-config.xml
    3. mybatis-plus.mapper-locations=classpath*:mapper/*.xml
    4. mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

    3:添加分页拦截器

    1. @Configuration
    2. public class MybatisPlusConfig {
    3. /**
    4. * 添加分页插件
    5. */
    6. @Bean
    7. public MybatisPlusInterceptor mybatisPlusInterceptor() {
    8. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    9. PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
    10. paginationInnerInterceptor.setOverflow(true);//最后一页的下一页调回首页
    11. paginationInnerInterceptor.setMaxLimit(500L);//-1不受限制 这里限制500
    12. interceptor.addInnerInterceptor(paginationInnerInterceptor);//如果配置多个插件,切记分页最后添加
    13. //interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
    14. return interceptor;
    15. }

    4:代码测试

    1. //mapper代码
    2. @Mapper
    3. public interface TestMapper extends BaseMapper {
    4. //自定义分页查询
    5. Page selectOrderByAgePage(@Param(value = "page") Page page);
    6. }
    7. //接口和实现类代码
    8. public interface TestService extends IService {
    9. Page selectOrderByAgePage(Page page);
    10. }
    11. @Service
    12. public class TestServiceImpl extends ServiceImpl implements TestService{
    13. @Autowired
    14. TestMapper testMapper;
    15. /**
    16. * 查询数据 分页显示
    17. * @return
    18. */
    19. public Page selectOrderByAgePage(Page page){
    20. return testMapper.selectOrderByAgePage(page);
    21. }
    22. }
    23. //controller 代码
    24. @GetMapping(value = "/dynamic_table")
    25. public String dynamic_table(@RequestParam(name = "pageIndex",defaultValue = "1",required = false)Integer pageIndex,
    26. Model model){
    27. System.out.println("执行dynamic_table方法:默认值是第一页");
    28. //开始页和条数
    29. Page page=new Page<>(pageIndex,3);
    30. Page pages = testService.selectOrderByAgePage(page);
    31. System.out.println("当前页:"+pages.getCurrent());
    32. System.out.println("总页数:"+pages.getPages());
    33. System.out.println("总行数:"+pages.getTotal());
    34. System.out.println("当前页数据:"+pages.getRecords());
    35. model.addAttribute("pages",pages);
    36. return "/table/dynamic_table";
    37. }

    7:整合redis集群

    集群搭建过程见其他文章

    1:导入依赖

    1. org.springframework.boot
    2. spring-boot-starter-data-redis

    2:配置集群信息

    1. #配置redis 集群
    2. #集群密码
    3. spring.redis.password=123456
    4. #集群节点81 - 86
    5. spring.redis.cluster.nodes=127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384,127.0.0.1:6385,127.0.0.1:6386
    6. #最大重定向次数
    7. spring.redis.cluster.max-redirects=5
    8. #连接池最大连接量
    9. spring.redis.lettuce.pool.max-active=8
    10. #连接最大阻塞时间 毫秒
    11. spring.redis.lettuce.pool.max-wait=1s
    12. #空闲的最大数量
    13. spring.redis.lettuce.pool.max-idle=8
    14. #空闲的最小数量
    15. spring.redis.lettuce.pool.min-idle=0

    3:测试代码

    1. //redistemplate配置
    2. @Configuration
    3. public class RedisConfig集群 {
    4. @Bean("redisTemplate")
    5. public RedisTemplate redisTemplateJQ(
    6. @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    7. RedisConnectionFactory factory) {
    8. RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
    9. redisTemplate.setConnectionFactory(factory);
    10. Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
    11. ObjectMapper mapper = new ObjectMapper();
    12. mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    13. mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
    14. serializer.setObjectMapper(mapper);
    15. // 使用StringRedisSerializer来序列化和反序列化redis的key值
    16. redisTemplate.setKeySerializer(new StringRedisSerializer());
    17. redisTemplate.setValueSerializer(serializer);
    18. // Hash的key也采用StringRedisSerializer的序列化方式
    19. redisTemplate.setHashKeySerializer(new StringRedisSerializer());
    20. redisTemplate.setHashValueSerializer(serializer);
    21. redisTemplate.afterPropertiesSet();
    22. return redisTemplate;
    23. }
    24. }
    25. //测试代码
    26. @Autowired
    27. RedisTemplate redisTemplate;
    28. //StringRedisTemplate redisTemplate;
    29. @Test
    30. void t1() {
    31. redisTemplate.opsForValue().set("代", "测试", 10, TimeUnit.MINUTES);
    32. Set keys = redisTemplate.keys("*");
    33. for (String key : keys) {
    34. System.out.println("key:"+key);
    35. }
    36. System.out.println(keys);
    37. System.out.println("返回值a:" + redisTemplate.opsForValue().get(""));
    38. }

    8:错误处理

    8.1:请求不存在的controller

    1:浏览器请求没有服务的controller,返回html

    2:postMan请求没有服务的controller,返回json

    源码分析:

    当请求不存在的时候,找不到处理方法报错

    服务器转发了一个http://localhost:8080/error 请求,该请求会被自动装配的basicErrorController拦截

    1:在ErrorMvcAutoConfiguration声明了一个bean是basicErrorController这个controller会拦截/error请求的错误。

    2:这个controller拦截/error请求,在源码中可以看到这连个拦截错误请求

    ​ 

     3:根据不同的请求方式浏览器和postMan程序来决定返回html和json

    8.2:请求存在但是代码错误的controller

    controller代码

    1. @GetMapping(value = "/basic_table")
    2. public String basic_table(){
    3. //自定义错误 抛出 java.lang.ArithmeticException: / by zero
    4. int a=10/0;
    5. return "/table/basic_table";
    6. }

    源码分析:

    1:执行controller代码报错,DispatcherServlet拦截到异常。

    2:异常处理

    3:系统默认的异常解析器处理异常,结果都处理不了,回到上边用baseErrorController来处理

    8.3:前后端未分离

    当我们配置了4XX和5XX错误的html页面的时候

    我们配置在项目中配置错误页,baseErrorController就会在浏览器请求错误的情况下,跳转到这些错误页面。我们在错误页面中取出异常信息

    html页面

    1. <h3 th:text="${path}">请求路径h3>
    2. <h3 th:text="${status}">状态h3>
    3. <h3 th:text="${message}">错误消息h3>
    4. <h3 th:text="${timestamp}">时间h3>

     浏览器页面显示

    8.4: 前后端分析,全局异常

    首先我们定义两个Controller

    1. @Controller
    2. public class 异常Controller {
    3. /**
    4. * 前后端分离Controller 直接返回json
    5. */
    6. @GetMapping(value = "/basic_table1")
    7. @ResponseBody
    8. public CommonReturnType basic_table1(@RequestParam(value = "a",required = false) int b ){
    9. //1:重点:没有自定义全局异常,默认的异常解析器解析
    10. //这里出现异常没有返回值 会被DispatcherServlet拦截,捕获异常 发送/error
    11. // 会进入baseErrorController 返回html
    12. //2:重点:自定义全局异常,拦截指定异常
    13. // 会根据自定异常返回值 是走ModelAndView 还是直接返回json
    14. // 会进入baseErrorController 返回html
    15. int a=10/0; //报错 后边执行
    16. List users = Arrays.asList(new User("张三1","000"),
    17. new User("张三1","111"),
    18. new User("张三2","222"),
    19. new User("张三3","333"));
    20. return CommonReturnType.crateCommonReturnType(users);
    21. }
    22. /**
    23. * 前后端不分离Controller 返回视图
    24. */
    25. @GetMapping(value = "/basic_table")
    26. public String basic_table(@RequestParam(value = "a") int b ){
    27. //1:重点:没有自定义全局异常,默认的异常解析器解析
    28. //这里出现异常没有返回值 会被DispatcherServlet拦截,捕获异常 发送/error
    29. // 会进入baseErrorController 返回html
    30. //2:重点:自定义全局异常,拦截指定异常
    31. // 会根据自定异常返回值 是走ModelAndView 还是直接返回json
    32. // 会进入baseErrorController 返回html
    33. //自定义错误 抛出 java.lang.ArithmeticException: / by zero
    34. int a=10/0; //报错 后边不执行
    35. // 这个异常ExceptionHandler 直接返回视图 return "login";//返回视图
    36. return "/table/basic_table";
    37. }
    38. }

    自定义全局异常

    1. @Slf4j
    2. @ControllerAdvice //底层Component
    3. public class GlobalExceptionHandler {
    4. //自定义异常CommonReturnType {
    5. // "status": "fail",
    6. // "data": {
    7. // "errCode": "300",
    8. // "errMsg": "参数绑定错误"
    9. // }
    10. //}
    11. //第一个自定义异常
    12. @ExceptionHandler(value = Exception.class)
    13. @ResponseBody
    14. public CommonReturnType GlobalControllerExceptions1(Exception exception){
    15. log.info("异常是{}:",exception);
    16. Map map=new HashMap();
    17. if (exception instanceof ServletRequestBindingException) {
    18. map.put("errCode", "300");
    19. map.put("errMsg", "参数绑定错误");
    20. } else if (exception instanceof NoHandlerFoundException) {
    21. map.put("errCode", "404");
    22. map.put("errMsg", "404错误");
    23. } else {
    24. map.put("errCode", "8888");
    25. map.put("errMsg",exception.getMessage());
    26. }
    27. return CommonReturnType.crateCommonReturnType("fail", map);//返回指定异常
    28. }
    29. //前提:没有配置全局异常解析器 出现异常会被抛出,没有异常解析器处理
    30. //然后发送/error请求 被baseErrorController拦截 返回标准页面
    31. //拦截指定异常,会返回ModelAndView 不加@ResponseBody java.lang.ArithmeticException: / by zero
    32. @ExceptionHandler(value ={NullPointerException.class,ArithmeticException.class})
    33. //@ResponseBody 异常直接返回页面
    34. public String GlobalControllerExceptions(Exception exception) {
    35. log.info("异常是{}:",exception);
    36. return "login";//返回视图
    37. }
    38. }

    9:springBoot的run()方法

    在主方法中启动run

    1. @SpringBootApplication
    2. public class SpringBoot04WebMvc2Application {
    3. public static void main(String[] args) {
    4. String[] strArray={"springboot启动参数"};
    5. ConfigurableApplicationContext run = SpringApplication.run(SpringBoot04WebMvc2Application.class, strArray);
    6. }
    7. }

    9.1:创建application对象

    new SpringBootApplication(主类) 完成初始化,去spring.factories中查找。

    BootstrapRegistryInitializer(引导启动器 0个)

    ApplicationContextInitializer(应用程序上下文初始化器 9个)

    和ApplicationListener(应用程序监听器 11个)

    放到SpringBootAlpplication中完成初始化。

    9.2:执行run()方法

    主要就是

    1:准备引用程序的环境参数

    2:创建applicationContext(里边的refresh是spring的核心源码 里边会执行tomcat)

    3:穿插执行runListenner的各个方法

  • 相关阅读:
    Tensorflow简单CNN实现
    【Javascript】对象中的常规操作(增删改查)
    vue目录树的封装
    国内免费好用 Chat GPT推荐
    11月3日 OpenCV 实战基础学习笔记——图像基本处理
    骰子游戏-第11届蓝桥杯Scratch选拔赛真题精选
    基于php的汇业家具商城
    Pikachu靶场——PHP反序列化漏洞
    嵌入式学习笔记(46) NandFlash的结构
    Luma AI如何注册:文生视频领域的新星
  • 原文地址:https://blog.csdn.net/huyiju/article/details/132630616