SpringBoot——整合Web开发(二)

SpringBoot——整合Web开发(二)

一、@ControllerAdvice

顾名思义,@ControllerAdvice就是@Controller的增强版。@ControllerAdvice主要用来处理全局数据。一般搭配@Exceptionhadnler、@ModelAttribute以及@InitBinder使用。

1.全局异常处理
@ControllerAdvice最常见的使用场景就是全局异常处理,例如文件上传大小限制的配置,如果用户上传的文件超过了限制大小,就会抛出异常,此时可通过@ControllerAdvice结合@ExceptionHandler定义全局异常捕获机制,代码如下:
当文件超出限制时:
在这里插入图片描述

@ControllerAdvice
public class CustomExceptionHandler {
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public void uploadException(MaxUploadSizeExceededException e, HttpServletResponse response) throws IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter printWriter = response.getWriter();
        printWriter.write("上传文件大小超出限制");
        printWriter.flush();
        printWriter.close();
    }
}

只需在系统中定义CustomExceptionHandler类,然后添加@ControllerAdvice注解即可。当系统启动时,该类就会被扫描到Spring容器中,然后定义uploadException方法,在该方法上添加了@ExceptionHandler注解,其中定义的MaxUploadSizeExceededException.class表名该方法用来处理MaxUploadSizeExceededException 类型的异常。如果想让方法处理所有类型的异常,只需将MaxUploadSizeExceededException 改为Exception即可。方法的参数可以有异常实例、HttpServletResponse以及HttpServletRequest、Model等,返回值可以是一段JSON、一个ModelAndView、一个逻辑视图名等。此时,上传一个超大的文件有错误提示给用户。如下图:
在这里插入图片描述
注意可能出现链接重置问题:

Spring文件上传和连接重置问题
https://blog.csdn.net/cyan20115/article/details/106549410/

  1. 添加全局数据
    @ControllerAdvice是一个全局数据处理组件,因此也可以在@ControllerAdvice中配置全局数据,使用@ModelAttribute注解进行配置,代码如下:
@ControllerAdvice
public class GlobalConfig {
    @ModelAttribute(value = "info")
    public Map<String,String> userinfo() {
        HashMap<String,String> map = new HashMap<>();
        map.put("username", "罗贯中");
        map.put("gender", "男");
        return map;
    }
}

在全局配置中添加userinfo方法,返回一个map,该方法有一个注解@ModelAttribute,其中的value的属性表示这条返回数据的key,而方法的返回值是返回数据的value。
此时在任意请求的Controller中,通过方法参数中的Model可以获取info的数据。

    @GetMapping("/info")
    public void getInfo(Model model) {
        Map<String, Object> mapObj = model.asMap();
        Iterator iterator = mapObj.keySet().iterator();
        while(iterator.hasNext()) {
            Object obj = iterator.next();
            Object value = mapObj.get(obj);
            System.out.println("value = " + value);
        }
    }
  1. 请求参数预处理
    @ControllerAdvice结合@InitBinder还能实现请求参数预处理,即将表单中的数据绑定到实体类上时进行一些额外处理。

在这里插入图片描述

    @GetMapping("/bookAndAuthor")
    public String bookAndbrother(Book book, Author author) {
        return book.toString() + ">>>>>>>>>>>" + author.toString();
//        Book{name='sss', author='null', price=null, publicationData=null}
//        >>>>>>>>>>>Author{name='sss', age=0}
    }

此时参数传递时,两个实体类中的name属性会混淆,@ControllerAdvice结合@InitBinder可以顺利解决该问题。

在这里插入图片描述

    @GetMapping("/bookAndAuthor2")
    public String bookAndbrother2(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) {
        return book.toString() + ">>>>>>>>>>>" + author.toString();
    }

在这里插入图片描述
注意:@InitBinder(“a”) 表示该方法处理@ModelAttribute(“a”)对应的参数的,b同理。
在WebDataBinder对象中,还可以设置允许的字段、禁止的字段,必填字段以及验证器等。

二、自定义错误页

SpringBoot中的全局异常处理。在处理异常时,可以根据实际情况返回不同的页面,但是这种异常处理方式一般用来处理应用级别的异常,有一些容器级别的错误就处理不了,例如Filter中抛出异常,使用@ControllerAdvice定义就无法处理,因此SpringBoot处理异常还有其他方式。
事实上,SpringBoot在返回错误信息时不一定返回HTML页面,而是根据实际情况返回HTML页面或者一段JSON(若开发者发起Ajax请求,则错误信息是一段JSON)。这一段HTML或JSON都能够自由定制。
SpringBoot中错误默认是由BasicErrorController类来处理的,该类中的核心方法主要有两个:
·
其中,errorHtml方法用来返回错误HTML页面,error用来返回错误JSON,具体返回的是HTML还是JSON,则要看请求头的Accept参数。返回JSON的逻辑很简单,返回HTML的逻辑稍微有些复杂,在errorHtml方法中,通过调用resolveErrorView方法来获取一个错误视图的ModelAndView。而resolveErrorView方法的调用最终会来到DefaultErrorViewResolver类中。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
从这一段源码中可以看到,SpringBoot默认是在error目录下查找4xx、5xx的文件作为错误视图,当找不到时会回到errorHtml方法中,然后使用error作为默认的错误页面视图名,如果名为error视图也找不到,用户就会看到默认展示的两个错误页面,整个错误处理流程大致就是这样的。

  • 简单配置
    要自定义错误页面其实很简单,提供4xx和5xx页面即可。不需要向用户展示详细的错误信息,那么可以把错误信息定义成静态页面,直接在resources/static目录下创建error目录,然后在error目录中创建错误展示页面。错误展示页面的命令规则有两种:一种是4xx.html、5xx.html;另一种直接使用响应码命名文件,例如404.html、500.html。第二种命令方式划分得更细,当出错时,不同的错误会展示不同的错误页面。 在这里插入图片描述
    在这里插入图片描述

若用户定义了多个错误页面,则响应码.html页面的优先级高于4xx.html、5xx.html页面的优先级,即若当前是一个404错误,则优先展示404.html而不是4xx.html;动态页面的优先级高于静态页面,即若resources/templates和resources/static下同时定义了4xx.html,则优先展示resources/templates/4xx.html。

  • 复杂配置
    上面这种配置还是不够灵活,只能定义HTML页面,无法处理JSON的定制。Spring Boot中支持Error信息的深度定制,接下来将从三个方面介绍深度定制:自定义Error数据、自定义Error视图以及完全自定义。
  1. 自定义Error数据
    自定义数据Error数据就是对返回的数据进行自定义。SpringBoot返回的Error信息分别是timestamp、error、message以及path。在BasicErrorController的errorHtml方法和error方法中,都是通过getErrorAttributes方法获取Error信息的。该方法最终会调用到DefaultErrorAttributes类的getErrorAttributes方法,而DefaultErrorAttributes类是在ErrorMvcAutoConfiguration中默认提供的。ErrorMvcAutoConfiguration类的errorAttributes方法源码如下:

    然后找到其实现方法:
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    从这段源码中可以看出,当系统中没有提供ErrorAttributes时才会采用DefaultErrorAttributes。因此自定义错误提示时,只需要自己提供一个ErrorAttributes即可,而DefaultErrorAttributes是ErrorAttributes的子类,因此只需要继承DefaultErrorAttributes即可。在这里插入图片描述
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
        Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, options);
        errorAttributes.remove("error");
        errorAttributes.put("errorMsg", "对不起,您访问的页面不存在!!!");
        return errorAttributes;
    }
}

在这里插入图片描述

下面的内容我看其他人都是可以显示内容,但我需要配置上自定义Error信息和自定义的Error视图才显示
在这里插入图片描述
如果不显示错误信息,可以添加如下配置:
在这里插入图片描述
2. 自定义视图
Error视图时展示给用户的页面,在BasicErrorController的errorHtml方法中调用resolveErrorView方法获取一个 ModelAndView实例。resolveErrorView方法是由ErrorViewResolver提供的,通过ErrorMvcAutoConfiguration类的源码可以看到SpringBoot默认采用的ErrorViewResolver是DefaultErrorViewResolver。在这里插入图片描述在这里插入图片描述
在这里插入图片描述
根据上述实现自定义的Error视图:

@Component
public class ErrorView implements ErrorViewResolver {
    @Override
    public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
        ModelAndView mnv = new ModelAndView("errorpage1");
        mnv.addAllObjects(model);
        return mnv;
    }
}

在这里插入图片描述

在这里插入图片描述

  1. 完全自定义
    前面提供的两种自定义方式都是对BasicErrorControlle类中的某个环节进行修补。查看Error自动化配置类ErrorMvcAutoConfiguration,可以发现BasicErrorController本身只是一个默认的配置,相关源码如下:

在这里插入图片描述
从这段源码中可以看到,若开发者没有提供自己的ErrorController,则SpringBoot提供BasicErrorController作为默认的ErrorController。因此,如果开发者需要更加灵活地对Error视图和数据进行处理,那么只需要提供自己的ErrorContrller即可。提供自己的ErrorController有两种方法:一种是实现只提供一个待实现的方法,而BasicErrorController已经实现了很多功能,因此这里选择第二种方式,即通过继承BasicErrorController来实现自己的ErrorController。具体实现如下:


package com.example.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Component
public class myErrorController extends BasicErrorController {


/*
  public myErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
        super(errorAttributes, errorProperties);
    }
*/



/*
 public myErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) {
        super(errorAttributes, errorProperties, errorViewResolvers);
    }*/

@Autowired
    public myErrorController(ErrorAttributes errorAttributes, ServerProperties serverProperties, List<ErrorViewResolver> errorViewResolvers) {
        super(errorAttributes, serverProperties.getError(), errorViewResolvers);
    }


public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = this.getStatus(request);
        // 文件上传异常 java.lang.UnsupportedOperationException
      //  Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
        Map<String, Object> model = this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.ALL));
        response.setStatus(status.value());
        ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
        model.put("haha", "哈哈哈 你找不到吧!!!!");
      //  return modelAndView != null ? modelAndView : new ModelAndView("error", model);
        modelAndView.setViewName("error");
        modelAndView.addAllObjects(model);
        if (modelAndView != null) {
            return modelAndView ;
        } else {
            return new ModelAndView("error", model);
        }
    }



    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        HttpStatus status = this.getStatus(request);
        if (status == HttpStatus.NO_CONTENT) {
            return new ResponseEntity(status);
        } else {
            Map<String, Object> body = this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.ALL));
            body.put("haha1", "哈哈哈 你找不到吧!!!!");
            request.setAttribute("haha1", "哈哈哈,你找不到吧!!!");
            return new ResponseEntity(body, status);
        }
    }
}

在这里插入图片描述

三、CORS支持

CORS(Cross-Origin Resource Sharing)是由W3C制定的一种跨域资源共享技术标准,其目的就是为了解决前端的跨域请求。在JAVAEE开发中,最常见的前端跨域请求解决方案是JSONP,但是JSONP支持GET请求,这是一个很大的缺陷,而CORS则支持多种HTTP请求方法。
JSONP教程
Jsonp(JSON with Padding)是json的一种“使用模式”,可以让网页从别的域名(网站)那获取资料,即跨域读取数据。为什么我们从不同的域(网站)访问数据需要一个特殊的技术(JSONP)呢?这是因为同源策略。同源策略,它是由Netscape提出的一个著名的安全策略,现在所有支持JavaScript的浏览器都会使用这个策略。

  • 全局配置
@Configuration
public class crossOrginConfig implements WebMvcConfigurer {
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/book1/**")//允许请求路径(本地)
                .allowedHeaders("*")
                .allowedMethods("*")
                .maxAge(1800)
                .allowedOrigins("http://localhost:8082");//表示支持的域(访问本地的那个域)
    }
}

解释:

  • 全局配置需要自定义实现WebMvcConfigurer接口,然后实现接口中的addCorsMappings方法。
  • 在addCorsMappings方法中,addMapping表示对哪种格式的请求路径进行跨域处理,allowedHeaders表示允许的请求头,默认允许所有的请求头信息;allowedMethods表示允许的请求方法,默认是GET、POST和HEAD;*表示支持所有的请求方法;maxAge表示探测请求的有效期;allowedOrigins表示支持的域。
  • 局部配置
    8080:
    @RequestMapping("/book2")
    @ResponseBody
    @CrossOrigin(value = "http://localhost:8082",maxAge = 1800, allowedHeaders = "*")
    public String getBookInfo2(String name) {
        return "receview:" + name;
    }

页面统一:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.staticfile.org/jquery/2.0.0/jquery.min.js"></script>
</head>

<body>
<div id="contentDiv"></div>
<input type="button" value="提交数据" onclick="getData()"/>
</body>
<script>
    function getData() {
        alert("getData");
        $.ajax({
            url:'http://localhost:8080/book2'
            ,data: {name:'三国演义'}
            ,contentType: 'application/json;charset=utf-8'
            ,dataType:'json'
            ,success: function(msg) {
                console.log("msg==================" + msg);
                $("#contentDiv").html(msg);
            },error: function (msg) {
                console.log(msg);
                console.log("errro==================" + msg);
            }
        });
    }
</script>
</html>

问题总结如下:

  1. 如果返回json,需要配置json转换器
  2. java.lang.IllegalArgumentException: Content-Type cannot contain wildcard type ‘*’
    参考链接:https://blog.csdn.net/mjlfto/article/details/103888497
  3. 关于请求出现 Status Code: 406 Not Acceptable
    状态码406:HTTP协议状态码的一种,表示无法使用请求的内容特性来响应请求的网页。说白了就是后台的返回结果前台无法解析就报406错误。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【2021年,将Spring全家桶的课程进行Review,确保不再有课程的顺序错乱,从而导致学员看不懂。进入2022年,将Spring的课程进行整理,整理为案例精讲的系列课程,并开始加入高阶Spring Security等内容,一步步手把手教你从零开始学会应用Spring,课件将逐步进行上传,敬请期待!】 本课程是Spring全家桶系列课程的第三部分Spring BootSpring案例精讲课程以真实场景、项目实战为导向,循序渐进,深入浅出的讲解Java网络编程,助力您在技术工作中更进一步。 本课程聚焦Spring Boot核心知识点:整合Web(如:JSP、Thymeleaf、freemarker等的整合)的开发、全局异常处理、配置文件的配置访问、多环境的配置文件设置、日志Logback及slf4j的使用、国际化设置及使用, 并在最后以一个贯穿前后台的Spring Boot整合Mybatis的案例为终奖,使大家快速掌握Spring的核心知识,快速上手,为面试、工作都做好充足的准备。 由于本课程聚焦于案例,即直接上手操作,对于Spring的原理等不会做过多介绍,希望了解原理等内容的需要通过其他视频或者书籍去了解,建议按照该案例课程一步步做下来,之后再去进一步回顾原理,这样能够促进大家对原理有更好的理解。 【通过Spring全家桶,我们保证你能收获到以下几点】 1、掌握Spring全家桶主要部分的开发、实现2、可以使用Spring MVC、Spring BootSpring Cloud及Spring Data进行大部分的Spring开发3、初步了解使用微服务、了解使用Spring进行微服务的设计实现4、奠定扎实的Spring技术,具备了一定的独立开发的能力  【实力讲师】 毕业于清华大学软件学院软件工程专业,曾在Accenture、IBM等知名外企任管理及架构职位,近15年的JavaEE经验,近8年的Spring经验,一直致力于架构、设计、开发及管理工作,在电商、零售、制造业等有丰富的项目实施经验  【本课程适用人群】如果你是一定不要错过!  适合于有JavaEE基础的,如:JSP、JSTL、Java基础等的学习者没有基础的学习者跟着课程可以学习,但是需要补充相关基础知识后,才能很好的参与到相关的工作中。 【Spring全家桶课程共包含如下几门】 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值