SpringBoot_第六章(知识点总结)

2023-10-27

目录

目录

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  配置拦截器拦截 那些请求
 */
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    /**
     * controller方法 执行之前
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        log.info("拦截请求{}"+request.getRequestURI());
        User user = (User) request.getSession().getAttribute("loginUser");
        if (user == null) {
            System.out.println("拦截器重定向");
            //如果session不存在登录信息,重定向到登录页面
            request.setAttribute("msg","拦截器拦截未登录");
            request.getRequestDispatcher("/").forward(request,response);
            return false;
        }
        return true;//返回true 程序接着执行
    }


    /**
     * controller方法执行之后,在页面渲染之前
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           @Nullable ModelAndView modelAndView) throws Exception {
        log.info("controller方法执行之后{}",modelAndView);
    }
    /**
     * 页面渲染之后
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                @Nullable Exception ex) throws Exception {
        log.info("页面渲染之后{}",ex);
    }

}

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

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

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

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

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

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

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

Filter代码实现:

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

Servlet代码实现: 

/**
 * 继承HttpServlet类,可以重写各种get post put 等等方法
 *
 * 使用次注解生效
 * @ServletComponentScan(basePackages = "com.example.springboot2_web03")
 *
 * servlet 拦截/s1(精度高 优先匹配)  就不会进入DispatcherServlet拦截/
 */
@WebServlet(urlPatterns = "/s1",name = "MyServlet")
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        System.out.println("执行MyServlet请求get:"+name);
        resp.getWriter().write("get请求MyServlet拦截/s1请求:"+name);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        System.out.println("执行MyServlet请求post:"+name);
        resp.getWriter().write("post请求MyServlet拦截/s1请求:"+name);
    }
}

监听器代码实现:

/**
 * 继承ServletContextListener
 * 容器启动的时候生效
 * 
 * 使用次注解生效
 * @ServletComponentScan(basePackages = "com.example.springboot2_web03")
 */
@WebListener(value = "MyListener")
public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("MyListener监听ServletContext初始化,容器启动的时候输出");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("MyListener监听ServletContext销毁");
    }
}

 

3:文件上传

3.1:文件上传代码实现

第一步:html文件

<!--文件上传必须是post和enctype="multipart/form-data"-->
<form role="form" th:action="@{/fileUpload}" method="post" enctype="multipart/form-data">
    <div class="form-group">
        <label for="exampleInputEmail1">邮箱</label>
        <input type="email" name="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
    </div>
    
    <div class="form-group">
        <label for="exampleInputPassword1">名字</label>
        <input type="text" name="username" class="form-control" id="exampleInputPassword1" placeholder="Password">
    </div>
    <div class="form-group">
        <label for="exampleInputFile">头像</label>
        <!--type="file" 没有multiple代表 单个文件-->
        <input type="file" name="headerImg" id="exampleInputFile">
    </div>
    
    <div class="form-group">
        <label for="exampleInputFile">生活照</label>
        <!--type="file" multiple代表多文件上传 -->
        <input type="file" name="photos" multiple>
    </div>
   
    <button type="submit" class="btn btn-primary">提交</button>
</form>

第二步Java代码实现:

 /**
     * 文件上传
     * @param files
     * @return
     */
    @PostMapping(value = "/fileUpload")
    public String fileUpload(@RequestParam(value = "username") String username,
                             @RequestParam(value = "email")String email,
                             @RequestParam(value = "headerImg") MultipartFile headerImg,
                             @RequestParam(value = "photos") MultipartFile[] photos,
                             Files files) throws IOException {
        if (!headerImg.isEmpty()){
            System.out.println("username:"+username);
            System.out.println("email:"+email);
            System.out.println("files:"+files);
            //headerImg 单文件
            System.out.println("headerImg名字:"+ headerImg.getOriginalFilename());
            System.out.println("headerImg大小:"+ headerImg.getSize());
            System.out.println("headerImg文件类型:"+ headerImg.getContentType());
            String newFileHeaderImg="A"+headerImg.getOriginalFilename();
            headerImg.transferTo(new File("/Users/huyiju/Desktop/upload/"+newFileHeaderImg));
        }

        if (photos.length>0){
            //photos多文件用MultipartFile[]数组
            for (MultipartFile photo : photos) {
                File file=new File("","");
                String newFilePhotos="B"+photo.getOriginalFilename();
                photo.transferTo(new File("/Users/huyiju/Desktop/upload/"+newFilePhotos));

            }
        }

        return "/form/form_layouts";
    }

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

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

3.2:文件上传源码分析

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

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

然后查看源码

//for循环将controller的参数逐个绑定
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);


//根据请求multipartRequest获取MultipartFile 并将返回值 
//赋值给 controller中的MultipartFile 类型的参数 
//
List<MultipartFile> files = multipartRequest.getFiles(name);
			return (!files.isEmpty() ? files.toArray(new MultipartFile[0]) : null);

4:整合druid数据源

4.1:整合德鲁伊

1:导入依赖

         <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--德鲁伊操作数据库-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.16</version>
        </dependency>

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

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

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

 @Autowired
    JdbcTemplate jdbcTemplate;
    /**
     * druid测试
     */
    @Test
    void starter_jdbc() {
        String sql="select * from t1";
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
        maps.forEach(map -> System.out.println(map));
    }

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

4.2:德鲁伊监控页面

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

1:配置监控页面信息

# StatViewServlet配置,说明请参考Druid Wiki,配置_StatViewServlet配置
#是否启用StatViewServlet(监控页面)默认值为false(考虑到安全问题默认并未启动,如需启用建议设置密码或白名单以保障安全)
spring.datasource.druid.stat-view-servlet.enabled=true
spring.datasource.druid.stat-view-servlet.reset-enable=false
spring.datasource.druid.stat-view-servlet.login-username=root
spring.datasource.druid.stat-view-servlet.login-password=123456

### WebStatFilter配置,说明请参考Druid Wiki,配置_配置WebStatFilter
spring.datasource.druid.web-stat-filter.enabled=true
spring.datasource.druid.web-stat-filter.url-pattern=/*
spring.datasource.druid.web-stat-filter.session-stat-enable=true
spring.datasource.druid.web-stat-filter.session-stat-max-count=1000
spring.datasource.druid.filters=stat,wall
spring.datasource.druid.filter.stat.slow-sql-millis=1000
spring.datasource.druid.filter.stat.log-slow-sql=true
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

  <!-- springBoot监控  http://localhost:8081/actuator/** -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

2:打开指标监控 

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

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

5.2:怎么能实现指标监控

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

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

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

  <!--服务监控服务器  版本必须一致 否则报错-->
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-server</artifactId>
            <version>2.7.9</version>
        </dependency>

启动服务:

@SpringBootApplication
@EnableAdminServer //启动服务管理服务器
public class SpringBoot04AdminServiceApplication {

    public static void main(String[] args) {
        System.out.println("进入adminUI的管理页面");
        SpringApplication.run(SpringBoot04AdminServiceApplication.class, args);
    }

}

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

    <!-- 服务监控客户端 版本必须一致 否则报错 配置文件服务-->
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
            <version>2.7.9</version>
        </dependency>

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

#这里分别是8081和8082
server.port=8082
#监控服务 将服务注册到8888
spring.boot.admin.client.url=http://localhost:8888
spring.boot.admin.client.instance.prefer-ip=true
#这里是控制台服务名字
spring.application.name=springBoot_client2


#开启指标监控 暴露所有 http://localhost:8081/actuator/
management.endpoints.enabled-by-default=true
management.endpoints.web.exposure.include=*

启动项目

@SpringBootApplication
@MapperScan(value = {"com.example.springboot04_web_mvc1.mapper"})
public class SpringBoot04WebMvc1Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringBoot04WebMvc1Application.class, args);
    }

}

查看控制台

更多详细点击查看 

6:整合mybatis、mybatis-plus

6.1:整合mybatis

1:导入依赖

 <!-- springboot——整合mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

2:配置mapper映射位置

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

3:接口

package com.example.springboot2_web03.mapper;

import com.example.springboot2_web03.entity.T1;

@Mapper
public interface T1Mapper {
     List<T1> selectAll();
     T1 selectById(@Param(value = "id") int id);

     @Select("select * from t1 where id=#{id}")
     T1 selectById1(@Param(value = "id") int id);
}

4:mapper配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.springboot2_web03.mapper.T1Mapper">
    <!--查询全部-->
    <select id="selectAll" resultType="com.example.springboot2_web03.entity.T1">
        select * from t1
    </select>

    <!--根据id查询-->
    <select id="selectById" resultType="com.example.springboot2_web03.entity.T1">
        select * from t1 where id=#{id}
    </select>
</mapper>

代码测试:

 @Autowired
    T1Mapper t1Mapper;
    /**
     * mybatis测试
     */
    @Test
    void mybatis_test() {
        List<T1> t1s = t1Mapper.selectAll();
        for (T1 t1 : t1s) {
            System.out.println("查询数据:"+t1);
        }

        T1 t1 = t1Mapper.selectById1(1);
        System.out.println("根据id查询:"+t1);
    }

6.2:整合mybatis-plus

1:导入依赖

  <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--德鲁伊操作数据库-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.16</version>
        </dependency>

        <!-- springboot——整合mybatis-->
        <!--        <dependency>-->
        <!--            <groupId>org.mybatis.spring.boot</groupId>-->
        <!--            <artifactId>mybatis-spring-boot-starter</artifactId>-->
        <!--            <version>2.1.3</version>-->
        <!--        </dependency>-->

        <!--mybatisPlus依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>

        <!-- MybatisPlus分页插件注解-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-extension</artifactId>
            <version>3.5.3.1</version>
            <scope>compile</scope>
        </dependency>

2:配置文件

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

3:添加分页拦截器

@Configuration
public class MybatisPlusConfig {

    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        paginationInnerInterceptor.setOverflow(true);//最后一页的下一页调回首页
        paginationInnerInterceptor.setMaxLimit(500L);//-1不受限制 这里限制500条
        interceptor.addInnerInterceptor(paginationInnerInterceptor);//如果配置多个插件,切记分页最后添加

        //interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
        return interceptor;
    }

4:代码测试

//mapper代码
@Mapper
public interface TestMapper extends BaseMapper<Test> {
    //自定义分页查询
    Page<Test> selectOrderByAgePage(@Param(value = "page") Page<Test> page);

}


//接口和实现类代码
public interface TestService extends IService<Test> {
     Page<Test> selectOrderByAgePage(Page<Test> page);
}

@Service
public class TestServiceImpl extends ServiceImpl<TestMapper, Test> implements TestService{

    @Autowired
    TestMapper testMapper;

    /**
     * 查询数据 分页显示
     * @return
     */
    public Page<Test> selectOrderByAgePage(Page<Test> page){
       return testMapper.selectOrderByAgePage(page);
    }
}


//controller 代码
 @GetMapping(value = "/dynamic_table")
    public String dynamic_table(@RequestParam(name = "pageIndex",defaultValue = "1",required = false)Integer pageIndex,
                                            Model model){

        System.out.println("执行dynamic_table方法:默认值是第一页");

        //开始页和条数
        Page<Test> page=new Page<>(pageIndex,3);
        Page<Test> pages = testService.selectOrderByAgePage(page);
        System.out.println("当前页:"+pages.getCurrent());
        System.out.println("总页数:"+pages.getPages());
        System.out.println("总行数:"+pages.getTotal());
        System.out.println("当前页数据:"+pages.getRecords());

        model.addAttribute("pages",pages);
        return "/table/dynamic_table";
    }

7:整合redis集群

集群搭建过程见其他文章

1:导入依赖

  <!--    =======================   -->
        <!--    这里是Redis的集群测试案例    -->
        <!--    =======================   -->

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

2:配置集群信息

#配置redis 集群
#集群密码
spring.redis.password=123456
#集群节点81 - 86
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
#最大重定向次数
spring.redis.cluster.max-redirects=5
#连接池最大连接量
spring.redis.lettuce.pool.max-active=8
#连接最大阻塞时间 毫秒
spring.redis.lettuce.pool.max-wait=1s
#空闲的最大数量
spring.redis.lettuce.pool.max-idle=8
#空闲的最小数量
spring.redis.lettuce.pool.min-idle=0

3:测试代码


//redistemplate配置
@Configuration
public class RedisConfig集群 {

    @Bean("redisTemplate")
    public RedisTemplate<Object, Object> redisTemplateJQ(
            @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
                    RedisConnectionFactory factory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);

        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        serializer.setObjectMapper(mapper);

        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(serializer);

        // Hash的key也采用StringRedisSerializer的序列化方式
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(serializer);

        redisTemplate.afterPropertiesSet();
        return redisTemplate;

    }

}


//测试代码
 @Autowired
   RedisTemplate redisTemplate;
    //StringRedisTemplate redisTemplate;

    @Test
    void t1() {
        redisTemplate.opsForValue().set("代", "测试", 10, TimeUnit.MINUTES);
        Set<String> keys = redisTemplate.keys("*");
        for (String key : keys) {
            System.out.println("key:"+key);
        }
        System.out.println(keys);
        System.out.println("返回值a:" + redisTemplate.opsForValue().get("代"));
    }

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代码

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

源码分析:

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

2:异常处理

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

8.3:前后端未分离

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

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

html页面

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

 浏览器页面显示

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

首先我们定义两个Controller

@Controller
public class 异常Controller {


    /**
     * 前后端分离Controller 直接返回json
     */
    @GetMapping(value = "/basic_table1")
    @ResponseBody
    public CommonReturnType basic_table1(@RequestParam(value = "a",required = false) int b ){

        //1:重点:没有自定义全局异常,默认的异常解析器解析
        //这里出现异常没有返回值 会被DispatcherServlet拦截,捕获异常 发送/error
        // 会进入baseErrorController 返回html

        //2:重点:自定义全局异常,拦截指定异常
        // 会根据自定异常返回值 是走ModelAndView 还是直接返回json
        // 会进入baseErrorController 返回html

        int a=10/0; //报错 后边执行
        List<User> users = Arrays.asList(new User("张三1","000"),
                new User("张三1","111"),
                new User("张三2","222"),
                new User("张三3","333"));
        return CommonReturnType.crateCommonReturnType(users);
    }

    /**
     * 前后端不分离Controller 返回视图
     */
    @GetMapping(value = "/basic_table")
    public String basic_table(@RequestParam(value = "a") int b ){
        //1:重点:没有自定义全局异常,默认的异常解析器解析
        //这里出现异常没有返回值 会被DispatcherServlet拦截,捕获异常 发送/error
        // 会进入baseErrorController 返回html

        //2:重点:自定义全局异常,拦截指定异常
        // 会根据自定异常返回值 是走ModelAndView 还是直接返回json
        // 会进入baseErrorController 返回html
        
        //自定义错误 抛出 java.lang.ArithmeticException: / by zero
        int a=10/0; //报错 后边不执行
        // 这个异常ExceptionHandler 直接返回视图  return "login";//返回视图
        return "/table/basic_table";
    }
}

自定义全局异常

@Slf4j
@ControllerAdvice //底层Component
public class GlobalExceptionHandler {

    //自定义异常CommonReturnType {
    //    "status": "fail",
    //    "data": {
    //        "errCode": "300",
    //        "errMsg": "参数绑定错误"
    //    }
    //}

    //第一个自定义异常
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public CommonReturnType GlobalControllerExceptions1(Exception exception){
        log.info("异常是{}:",exception);
        Map<String,Object> map=new HashMap();
        if (exception instanceof ServletRequestBindingException) {
            map.put("errCode", "300");
            map.put("errMsg", "参数绑定错误");
        } else if (exception instanceof NoHandlerFoundException) {
            map.put("errCode", "404");
            map.put("errMsg", "404错误");
        } else {
            map.put("errCode", "8888");
            map.put("errMsg",exception.getMessage());
        }
        return CommonReturnType.crateCommonReturnType("fail", map);//返回指定异常
    }


    //前提:没有配置全局异常解析器 出现异常会被抛出,没有异常解析器处理
    //然后发送/error请求 被baseErrorController拦截 返回标准页面

    //拦截指定异常,会返回ModelAndView 不加@ResponseBody java.lang.ArithmeticException: / by zero
    @ExceptionHandler(value ={NullPointerException.class,ArithmeticException.class})
    //@ResponseBody 异常直接返回页面
    public String GlobalControllerExceptions(Exception exception) {
        log.info("异常是{}:",exception);
        return "login";//返回视图
    }


}

9:springBoot的run()方法

在主方法中启动run

@SpringBootApplication
public class SpringBoot04WebMvc2Application {

    public static void main(String[] args) {
        String[] strArray={"springboot启动参数"};
        ConfigurableApplicationContext run = SpringApplication.run(SpringBoot04WebMvc2Application.class, strArray);


    }

}

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的各个方法

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringBoot_第六章(知识点总结) 的相关文章

随机推荐

  • hisi3521叠加OSD水印

    freetype下载安装 下载 https download savannah gnu org releases freetype 解压 tar xvf freetype 2 4 10 tar gz 进入freetype文件目录 cd fr
  • 编译原理三大经典书籍(龙书 虎书 鲸书)

    1 龙书 Dragon book 英文名 Compilers Principles Techniques and Tools 作者 Alfred V Aho Ravi Sethi Jeffrey D Ullman 中文名 编译原理技术和工具
  • 谐振电路 - 01 介绍

    1 定义 对于包含电容和电感及电阻元件的无源一端口网络 其端口可能呈现容性 感性及电阻性 当电路端口的电压U和电流I 出现同相位 电路呈电阻性时 称之为谐振现象 这样的电路 称之为谐振电路 缩写是 LLC 谐振电路的本质是电容中的电场能与电
  • panosim引入新python库提示——SyntaxError: future feature annotations is not defined

    标题错误原因 根本原因是python的版本冲突 高版本python的下载的库给低版本用 背景 panosim自带python为3 6 引入新库的方式为 将其他python版本下载的库放到 Lib site packages下 我用cmd终端
  • 自学黑客(网络安全),一般人我劝你还是算了吧

    一 自学网络安全学习的误区和陷阱 1 不要试图先成为一名程序员 以编程为基础的学习 再开始学习 我在之前的回答中 我都一再强调不要以编程为基础再开始学习网络安全 一般来说 学习编程不但学习周期长 而且实际向安全过渡后可用到的关键知识并不多
  • 解决 WebStorm 很卡的问题

    1 打开安装WebStorm的位置 找到WebStorm exe vmoptions文件 我的文件位置 2 设置 一般最大的设置为1G已经够了 我原来的设置是7百多 Xmx1024m Xms526m 3 如果还不行 再忽略项目中的node
  • Twins:重新思考视觉Transformer中的空间注意力机制

    点击下方卡片 关注 CVer 公众号 AI CV重磅干货 第一时间送达 Twins Revisiting the Design of Spatial Attention inVision Transformers 单位 美团 阿德莱德大学
  • lora人物训练

    准备好训练的图片 尺寸根据你显卡显存的大小 默认的图片尺寸大小为512 512 显卡显存小于8G的 建议使默认尺寸 如果你的显卡显存可以满足12g或12g以上 推荐使用768 768的图片来训练我们的模型 用大尺寸训练后的模型可以适当减少生
  • MySQL基础之DDL指令

    MySQL基础之DDL指令 数据库 数据表的操作 一 数据库的操作 前言 数据库的命名规则 1 数据库的创建 2 数据库的使用 3 数据库的修改 二 数据表的操作 1 表的创建 2 表的修改 2 1 表中列的修改 2 2 表的修改 一 数据
  • ROS MoveIT1(Noetic)安装总结

    前言 由于MoveIT2的Humble的教程好多用的还是moveit1的环境 所以又装了Ubutun20 04和ROS1 Noetic 2022年12月6日 环境 系统 Ubutun20 04LTS Ros Noetic 虚拟机 VMwar
  • SQL server 实现触发器备份表数据

    在项目里 一个表被增加 需要同步插入的数据 写了一个触发器 需要一个备份表 一个触发器 创建备份表 SELECT INTO PATIENT backup FROM PATIENT 触发器 CREATE TRIGGER dbo Insert
  • 三维图形变换:三维几何变换,投影变换(平行/ 透视 投影)

    通过三维图形变换 可由简单图形得到复杂图形 三维图形变化则分为三维几何变换和投影变换 6 1 三维图形几何变换 三维物体的几何变换是在二维方法基础上增加了对 z 坐标的考虑得到的 有关二维图形几何变换的讨论 基本上都适合三维空间 从应用角度
  • 2023-9-14 数字三角形

    题目链接 数字三角形 include
  • 【AIGC】斯坦福小镇升级版——AI-Town源码解读

    写在前面的话 接上一篇斯坦福小镇升级版 AI Town搭建指南 本本篇将解读 AI Town 使用的技术栈 代码架构 与LLM的交互 以及与斯坦福AI小镇的对比结果 如想直接看结论可跳到文章最后 整体架构 技术栈 AI Town 使用 Ty
  • MATLAB实现列主元高斯消去法

    列主元高斯消去法 function x gauss column A b 输入矩阵A和列向量b 返回解向量x ni nj size b if rank A rank A b 若系数矩阵秩和增广矩阵秩不相等 则无解 fprintf 无解 n
  • 点火开关分为4个档位,分别是off,acc,IG-on,和ST

    off全车除了常火 如应急灯 时钟等的记忆功能 外 均不供电 acc 是附件档 部分车载附属设备供电 如视听系统 仪表灯 灯光等 也就是说 车停在哪里 发动机不转 除了空调不能用外 车内的设备基本都可以用 IG on是汽车点火档 在保证AC
  • 如何用VB实现Modbus串行通讯

    如何用 VB 实现 Modbus 串行通讯 在一些应用中可能需要使用诸如 VB 来进行上位机监控程序的开发 而 Modbus 协议是这类应用中首选的通讯协议 Modbus 协议以其简单易用 在工业领域里已广泛的为其他第三方设备所支持 这里对
  • Warning: JAVA_HOME is not set! Error: Unable to find java executable. Is it in your PATH?

    报错 Warning JAVA HOME is not set Error Unable to find java executable Is it in your PATH 问题描述 启动flume的时候报错 解决方案 1 修改linux
  • PCL系列笔记——(滤波)Filter

    目录 直通滤波 PassThrough filter 体素滤波 VoxelGrid filter 离群点滤波器 StatisticalOutlierRemoval filter 直通滤波 PassThrough filter 这个滤波很直接
  • SpringBoot_第六章(知识点总结)

    目录 目录 1 拦截器 Interceptor 1 1 拦截器代码实现 1 2 拦截器源码分析和流程总结 2 过滤器 Filter 自定义 Servlet 监听器 Listener 3 文件上传 3 1 文件上传代码实现 3 2 文件上传源