六:Day02_Spring Boot02

一、异常显示页面

1. 设置具体的状态码页面

在templates/下新建error文件夹,在error中新建:状态码.html的页面。例如当出现500时显示的页面为500.html。

2. 使用x进行模糊匹配

当出现5开头状态码的错误时,显示页面可以命名为5xx.html

当出现50开头状态码的错误时,显示页面可以命名为50x.html

3. 统一错误显示页面

在templates下新建error.html。如果项目中不存在具体状态码的页面或没有使用x成功匹配的页面时,显示error.html作为错误显示页面。

二、异常处理机制

常见方式如下:

  1. 在控制器类中添加一个方法,结合@ExceptionHandler。只能对当前控制器中方法出现异常有效。

  2. 新建全局异常类,通过@ControllerAdvice结合@ExceptionHandler。当全局异常处理和局部处理同时存在时,局部生效(就近原则)。

1. 通过@ExceptionHandler注解处理异常

java 复制代码
@Controller
public class UsersController {
    @RequestMapping("showInfo")
    public String showInfo(){
        String str = null;
        str.length();
        return "ok";
    }

    @ExceptionHandler(value = {java.lang.NullPointerException.class} )
    public ModelAndView nullpointExcepitonHandler(Exception e){
        ModelAndView mv = new ModelAndView();
        mv.addObject("err",e.toString());
        mv.setViewName("error1");
        return mv;
    }
}

2. 通过@ControllerAdvice与@ExceptionHandler注解处理异常

java 复制代码
/**
 * 全局异常处理类
 */
@ControllerAdvice
public class GlobalException {
    @ExceptionHandler(value = {java.lang.NullPointerException.class} )
    public ModelAndView nullpointExcepitonHandler(Exception e){
        ModelAndView mv = new ModelAndView();
        mv.addObject("err",e.toString());
        mv.setViewName("error1");
        return mv;
    }

    @ExceptionHandler(value = {java.lang.ArithmeticException.class} )
    public ModelAndView arithmeticExceptionHandler(Exception e){
        ModelAndView mv = new ModelAndView();
        mv.addObject("err",e.toString());
        mv.setViewName("error2");
        return mv;
    }
}

3. 通过SimpleMappingExceptionResolver对象处理异常

java 复制代码
/**
 * 全局异常 
 * SimpleMappingExceptionResolver
 */ 
@Configuration
public class GlobalException2 {

    /**
     * 此方法返回值必须是SimpleMappingExceptionResolver对象
     * @return
     */
    @Bean
    public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
        Properties properties = new Properties();
        /*
         * 参数一:异常类型,并且是全名
         * 参数二:视图名称
         */
        properties.put("java.lang.NullPointerException","error3");
        properties.put("java.lang.ArithmeticException","error4");

        resolver.setExceptionMappings(properties);
        return resolver;
    }

}

4. 通过自定义HandlerExceptionResolver对象处理异常

java 复制代码
/**
 * 自定义HandlerExceptionResolver对象处理异常
 * 必须要实现HandlerExceptionResolver
 */
@Component
public class GlobalException3 implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception e) {
        ModelAndView mv = new ModelAndView();
        //判断不同异常类型,做不同视图的跳转
        if(e instanceof NullPointerException){
            mv.setViewName("error5");
        }
        if(e instanceof ArithmeticException){
            mv.setViewName("error6");
        }
        mv.addObject("error",e.toString());
        return mv;
    }
}

三、文件上传和下载

1. 文件上传

上传文件解析器已经被自动配置,直接只用MultipartFile接收上传的文件。

所以在文件上传时都会生成一个全局唯一的文件名。常见有两种方式:

(1)时间戳+随机数

(2)UUID

java 复制代码
/**
 * 文件上传控制单元方法实现
 * @param photo 名字必须和表单中文件域的name属性值相同
 * @return
 * @throws IOException transferTo抛出的异常,可以使用try...catch处理异常。示例中为了让代码看起来简洁直接抛出了。
 */
@RequestMapping("/upload")
@ResponseBody
public String upload(MultipartFile photo, HttpServletRequest request) throws IOException {
    // 判断上传文件流是否为空。如果不为空继续执行
    if(!photo.isEmpty()) {
        // 使用UUID生成文件名称
        // String fileName = UUID.randomUUID().toString();
        // 使用时间戳+随机数生成文件名
        long timeMillis = System.currentTimeMillis();
        Random random = new Random();
        String fileName = timeMillis + "" + random.nextInt(1000);
        // 获取上传时文件名
        String oldName = photo.getOriginalFilename();
        // 获取上传时文件的扩展名
        String suffix = oldName.substring(oldName.lastIndexOf("."));
        // 获取到当前项目images目录,发布到Tomcat后的绝对路径。
        String realPath = request.getServletContext().getRealPath("/images");

        //重要部分
        photo.transferTo(new File(realPath,fileName + suffix));
        return "ok";
    }
    return "err";
}

2. 文件下载

如果希望所有的文件都是下载,而不是能打开则打开。可以在响应头中设置Content-Disposition参数为attachment。attachment结合filename可以设置下载文件的名称。

java 复制代码
@RequestMapping("/download")
public void download(HttpServletRequest req, HttpServletResponse response, String filename) {
    try {
        // filename=的值就是客户端看到的下载文件名称
         String newFilename = new String(filename.getBytes("utf-8"),"iso-8859-1");
        response.setHeader("Content-Disposition", "attachment;filename=" + newFilename);
        File file = new File(req.getServletContext().getRealPath("/images"), filename);
        FileInputStream fis = new FileInputStream(file);
        ServletOutputStream os = response.getOutputStream();
       //重要部分
        IOUtils.copy(fis, os);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

四、内容协商

根据客户端接收能力不同,返回不同媒体类型的数据。示例:浏览器发送两次请求,访问资源相同,第一次请求要求返回json数据,第二次请求要求返回xml数据。

1. 导入依赖

XML 复制代码
<dependency>
   <groupId>com.fasterxml.jackson.dataformat</groupId>
   <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

2. 编写页面发送请求

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>数据协商访问</title>
    <script src="https://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<button onclick="getJson()">json格式</button>
<button onclick="getXml()">Xml格式</button>
<script>
    function getJson(){
        $.ajax({
            url:"show",
            type:"get",
            dataType:"json",
            success:function(data){
                console.log(data);
            }
        });
    }
    function getXml(){
        $.ajax({
            url:"show",
            type:"get",
            dataType:"xml",
            success:function(data){
                console.log(data);
            }
        });
    }
</script>
</body>
</html>

3. 编写controller

java 复制代码
@RequestMapping("/show")
public Map<String,Object> map(){
    Map<String,Object> map = new HashMap<>();
    map.put("id",1);
    map.put("name","张三");
    return map;
}

五、更换内置的服务器

1. 添加依赖

XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. 更换服务器

根据SpringBoot的⼯作机制,⽤什么技术,加⼊什么依赖就⾏了。SpringBoot提供了3款内置的服务器:

  • tomcat(默认):apache出品,粉丝多,应⽤⾯⼴,负载了若⼲较重的组件

  • jetty:更轻量级,负载性能远不及tomcat

  • undertow:负载性能勉强跑赢tomcat

想⽤哪个,加个坐标就OK。前提是把tomcat排除掉,因为tomcat是默认加载的。

XML 复制代码
<dependencies>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
         <exclusions>
             <exclusion>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-tomcat</artifactId>
             </exclusion>
         </exclusions>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-undertow</artifactId>
     </dependency>
</dependencies>

六、Spring Boot多环境配置文件

Spring Boot应用支持多环境配置文件,在开发、测试、上线等不同的环境中,可以激活不同的环境配置,解决切换环境时修改配置文件的麻烦。

1. 环境配置文件定义要求

  1. 必须定义在application配置文件所在目录中,即只能是 classpath、classpath/config、 root、 root/config 等四个目录之一。

  2. 配置文件命名是application-xxx。其中xxx即环境名称,如: application-dev、application-test、application-prod等。

  3. application配置文件中需要激活相应的环境配置,使用 spring.profiles.active=环境名称 来激活。或者在启动时,增加启动参数 -Dspring.profiles.active=环境名称

  4. 配置文件类型: yaml、yml、properties。

  5. 可以一次性激活若干环境配置,按照激活顺序依次读取环境配置,后读取的覆盖先读取的同名配置。不同名的配置使用保留|追加方式处理。

2. 环境配置文件使用方式

在application配置文件激活
  • 配置公共的配置

  • 激活指定的配置文件

XML 复制代码
# 选择使用的环境
spring:
  profiles:
    active: dev

application-dev.yml配置如下:

XML 复制代码
server:
  port: 81

七、SpringBoot整合拦截器

1. 新建拦截器类

java 复制代码
//不要忘记类上注解@Component
@Component
public class DemoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("执行拦截器");
        return false;
    }
}

2. 配置拦截器

java 复制代码
//类上有注解@Configuration。此类相当于SpringMVC配置文件。
@Configuration
public class MyConfig implements WebMvcConfigurer {
    @Autowired
    private DemoInterceptor demoInterceptor;
    //配置拦截器的映射
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

//addPathPattern(): 拦截哪些URL。 /* 拦截全部
​//excludePathPatterns(): 不拦截哪些URL。
//当和addPathPattern()冲突时,excludePathPatterns()生效。    

    registry.addInterceptor(demoInterceptor)
        .addPathPatterns("/*")
        .excludePathPatterns("/login");
    }
}

八、原生组件注入

注入Servlet的过滤器,拦截器。

1. 启动器配置

java 复制代码
@SpringBootApplication
//扫描Servlet原生组件
@ServletComponentScan({"com.xxx.filter", "com.xxx.listener"})
public class Springboot02Application {

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

2. 自定义过滤器,拦截器

九、SpringBoot项目打jar包

XML 复制代码
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <fork>true</fork>
            </configuration>
        </plugin>
    </plugins>
</build>

十、Spring Boot中的常见注解

1. @Configuration

通常使用在配置类(组件)上 。声明该类为配置类

2. @Bean

通常用在方法上 ,方法的返回值交由IOC管理,IOC中的默认id为方法名.

3. @Import

通常用在配置类上,导入其它的类,被导入的类交由IOC管理,类中的方法有@Bean注解。

4. @Conditional

提交注解,符合条件才会进行。

注解 例如 解释
@ConditionalOnBean @ConditionalOnBean(User.class) Spring容器中存在对应的bean生效
@ConditionalOnMissingBean @ConditionalOnMissingBean(name = "user") Spring容器中不存在对应的bean生效
@ConditionalOnClass @ConditionalOnClass(Menu.class) 类加载器可以加载到对应的类生效
@ConditionalOnMissingClass @ConditionalOnMissingClass(Menu.class) 类加载器加载不到对应的类生效
@ConditionalOnProperty @ConditionalOnProperty(prefix = "spring.aop") 应用环境中的属性满足条件生效
@ConditionalOnSingleCandidate @ConditionalOnMissingClass(Menu.class) 表示当指定Bean在容器中只有一个,或者虽然有多个但是指定首选Bean
@ConditionalOnWebApplication 当前应用是Web应用生效
@ConditionalOnNotWebApplication 当前应用不是Web应用生效

5. @ConfigurationProperties

读取Springboot配置文件中的数据,自动注入到属性中。

1.Springboot配置文件application.yml中添加

XML 复制代码
menu:
    id: 1
    name: Good
    url: menu/show

2.创建类Menu

3.测试

java 复制代码
@SpringBootTest
class Springboot02ApplicationTests {
    @Autowired
    Menu menu;
    
    @Test
    void contextLoads() {
    	//Menu(id=1, name=Good, url=menu/show)
        System.out.println(menu);
    }
}

6. @EnableConfigurationProperties

  • 我们注入的是第三方提供的类(组件)上不能添加@Component注解,通过@EnableConfigurationProperties注解注册第三方组件。

十一、Spring Boot 启动流程和自动配置原理

相关推荐
加班是不可能的,除非双倍日工资1 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi2 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip2 小时前
vite和webpack打包结构控制
前端·javascript
excel2 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国3 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼3 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy3 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT3 小时前
promise & async await总结
前端
Jerry说前后端3 小时前
RecyclerView 性能优化:从原理到实践的深度优化方案
android·前端·性能优化
画个太阳作晴天3 小时前
A12预装app
linux·服务器·前端