第三十四天 Java基础学习(二十八)

一、@ResponseBody

●自动转换为JSON字符串

@ResponseBody注解可以把控制单元返回值自动转换为JSON字符串。主要完成下面几个事情

•判断返回值是否为JavaBean、JavaBean数组、List<JavaBean类型>、Map等满足键值对的类型。

•如果满足键值对类型,会使用Jackson把对象转换为JSON字符串,设置到响应流中。同时会设置响应内容类型(Content·Type)为application/json;charset=utf-8

Spring MVC默认使用Jackson作为SON转换工具,必须保证项目中存在Jackson的依赖。

●转换为XML文件

XML格式在一些开放平台上用的比较多。

在Spring MVC中支持把返回值转换为XML文件。如果还是使用jackson-databind依赖,默认只能转换返回值为类类型的控制单元,返回值为List是无法转换为XML的,同时还要求实体类上必须有@XmlRootElement,才能转换。

●导入依赖

导入依赖时注意:

•不要导入jackson-databind,只导入jackson-dataformat-xml

• jackson-dataformat-xml版本不要太高,和Tomcat8插件不兼容。2.9.9和Spring 5.3.x可以正确兼容

•因为上面练习导入的是jacksoh-databind,所以需要点击Maven面板> Lifecycle-> Clean清空下缓存

●@RestController注解

对于页面中使用前端框架时的项目。例如页面时通过:EasyUI、BootStrap、Vue等前端框架进行编写时,客户端向服务端发送的请求都是异步Ajax(或类似Ajax的异步请求)。对于这样的项目,控制器中所有的方法都包含@ResponseBody注解。

像这种类中所有的控制单元方法都有@ResponseBody,可以使用@RestController进行简化。当类上使用的是@RestController而不是@Controller时,控制单元方法不再需要写@ResponseBody(也不能写@ResponseBody),Spring MVC在解析控制单元方法时会自动带有@ResponseBody注解。

•注意:

一旦类上使用了@RestController,所有控制单元返回都是XML或JSON数据。而无法实现页面跳转功能了。

只要类中有一个方法是希望实现页面跳转功能,类上就不能使用@RestController。只有类中所有的方法都是返回JSON或XML的情况才能使用@RestController注解。

二、@RequestBody注解

@RequestBody注解底层依赖的依然是Jackson工具包,其作用是把客户端传递过来的请求体中JSON或XML数据转换为Map、类、List<类>、List<Map>等类型。

既然是转换为请求体数据,所以不能是GET类型请求(GET没有请求体),多用在POST类型的请求中。

@RequestBody注解在单体架构项目使用的不是特别多。主要用在分布式项目中多个项目之间传递数据或一些开发平台中(例如微信开发平台接口返回XML数据) 

如果希望在单体架构项目中使用@RequestBody注解,需要在客户端中使用Ajax请求,刻意设置请求的内容类型(Content-Type)为JSON或XML

●请求内容类型详解

在客户端中无论使用的是<form>表单,还是Ajax请求,默认的请求时内容类型都是application/x-www-form-urlencoded,表单普通表单参数。普通表单参数接收方式和上次课讲解的参数接收方式是相同的。因为是默认请求内容类型,所以在谷歌浏览器开发者工具中有时不会特意的显示,有时会显示。

●Ajax请求参数

使用Ajax请求时,默认的参数类型也是普通表单参数(Form Data)

重启项目,访问后会发现谷歌浏览器中现实参数也是普通Form Data

服务端控制器中接收参数还是和正常参数接收相同。但是客户端希望服务端返回JSON数据,所以一定要在类上添加@ResponseBody注解。

•可能出现的错误:

①如果依赖还是使用jackson-dataformat-xml,会发现浏览器开发者工具中响应状态码为406,表示类型无法转换。所以要把依赖换成jackson-databind

②如果控制单元上没有@ResponseBody注解,会发现浏览器开发者工具中响应状态码为404,此时的404不是控制器没有访问到,而是返回值表示页面跳转,没有一个People类型的页面,所以出现404

●修改请求内容类型

如果希望修改请求内容类型,可以使用HTML的<form>中enctype属性或使用Ajax中contentType属性进行设置。但是<form>的enctype属性一般只有在文件上传时才会修改,所以希望传递特定类型请求参数内容时,都是通过Ajax进行请求。

注意:

•contentType:必须设置。常见取值“application/json”或"application/xml”。如果没有设置这个属性,取值默认是application/x-www-form-urlencoded,表示普通表单参数。当设置为"application/json”时,会把data取值设置到请求体中,所以服务端接收参数时就不能按照普通表单参数进行接收。

•data:请求参数。必须是字符串类型,不能是JSON格式的对象。因为在JSON中key两次必须有双引号,所以data取值两侧用单引号包含。因为在JavaScript中字符串string类型可以使用单引号包含,也可以使用双引号包含。

•type:请求类型不能是get类型,因为get类型没有请求体。常用就是post类型。

三、视图解析器

●视图和视图解析器

Spring MVC 定义了ViewResolver 和view接口,实现在浏览器中呈现模型,而无需绑定到特定的视图技术。ViewResolver 提供视图名称和实际视图之间的映射。View解决数据在移交给特定视图技术之前的准备工作。由ViewResolver来解析单元方法的处理结果,创建对应的View的对象,然后再调用View的实现对象来完成相关的准备工作。

modelAndView,其中包含了model和View两个部分,model就是用来存储页面中要展示给用户的数据,而View指的是单元方法的返回值,也就是要跳转的页码的逻辑路径。

DispatcherServlet在接收到请求后调用单元方法处理请求,然后接收单元方法的返回值后DispatcherServlet会将model对象和单元方法的返回值封装到modelAndView对象中,然后调用ViewResolver视图解析器的实现类对象的buildView方法来解析ModelAndView对象生成对用的View视图对象,然后再调用View对象的render方法完成物理视图跳转的准备工作并跳转真正的物理视图。

•注意,使用不同的视图技术,需要调用不同的视图解析器来解析modelAndView,ViewResolver视图解析器的实现

●自定义视图解析器

视图解析器支持程序员的自定义,只有在需要简化控制单元返回值的情况下才会自定义视图解析器。

简化控制单元返回值就是让返回值字符串内容少写一点内容。

return后面的内容有两份是重复的:

     前面的/WEB-INF/page/

     后面的jsp

对于这种,项目结构比较固定,页面按照一定规则放在特定位置,且返回值内容比较长时,就可以配置视图解析器。在springmvc.xml配置下面内容。

其中id=“viewResolver”的取值是任意的,也可以省略id属性不写。 

●自定义视图解析器下跳转到其他控制器

当自定义视图解析器后,返回值前面和后面都会固定拼接字符串(在没有使用其他注解情况下)。但是如果控制单元执行完,并不希望跳转到视图,而是跳转到控制器,这时需要在返回值前面明确添加forward:或redirect:,这样就不走视图解析器了。

四、Spring MVC文件上传

文件上传就是把客户端的文件上传到服务端进行保存。在文件上传时文件和其他请求参数是在请求体中进行传递。所以不支持GET类型请求。

默认的表单内容类型application/x-www-form-urlencoded还不支持传递文件流。所以需要在<form>的enctype中设置enctype="multipart/form-data"才表示把文件和其他表单参数设置到请求体中。

Spring MVC的文件上传是通过MultipartResovler组件实现的。提供了两个具体的实现类

其中CommpnsMultipartResovler是实现类。底层是对Apache的Commons-Fileupload的封装,让文件上传代码实现起来更加简单。所以在文件上传时必须在Spring MVC的配置文件中配置CommonsMultipartResovler组件的Bean,同时也得在项目中导入Commons-Fileupload的依赖。谨记:没有MultipartResovler是无法获取到Content-Type="multipart/form-data”类型的数据,无论是表单域数据还是文件域数据。

●Spring MVC文件上传有如下几点要求:

•客户端:

      请求方式必须是POST

       enctype必须为multipart/form-data

•服务端:

     必须配置MultipartResovler。否则无法解析上传文件的流数据。(<bean>的id值必须叫做multipartResovler)如果没有配置MultipartResovler不仅仅是文件流数据无法解析,连带着其他表单域数据也无法解析。因为文件流数据和表单数据都在请求体中,不解析的话,文件流数据和表单数据都接收不到。

     注意文件域的name取值,文件域必须MultipartFile类型接收。且name的取值必须和MultipartFile对象名相同。

●文件上传实现流程

•导入依赖

在使用CommonsMultipartResovler因为底层是Apache的File-Upload,所以需要导入两个jar包。

        commons-io-2.2.jar       工具包,里面有需要使用的工具类

        commons-fileupload-1.3.1.jar       Apache 文件上传的jar包。

   对应的pom.xml的依赖。commons-fileupload已经依赖了commons-io依赖了。所以根据依赖的传递性只需要添加commons-fileupload依赖就行了。

•在页面中编写文件上传代码

在webapp下新建upload.jsp文件,在文件中填写表单数据。

姓名和地址是随意添加的两个表单域,头像对应的是文件域。

●非Ajax提交数据:

•表单提交方式必须是post 因为get是依附于URL地址传输的并且传输的数据量大小有限制B、enctype:提交表单数据传递类型:

      application/x-www-form-urlencoded普通文本提交 默认

     multipart/form-data 按照二进制流的方式进行数据传递

●Ajax提交数据:

•提交方式必须是post

•将processData属性的值设置为false,告诉浏览器发送对象请求数据

    将contentType属性的值设置为false,设置请求数据的类型为二进制类型。

●配置上传解析器bean

只有配置了MultipartResovler,Spring MVC才会解析上传文件流数据。

同时<beany的id必须叫做multipartResovler,叫其他名字无效。

●编写单元方法处理上传请求

直接在单元方法上声明形参来接收请求数据即可,普通表单数据还是直接使用键名获取即可,上传的时候解析后会被存储到MultipartFile对象中,声明MultipartFile类型的形参接即可,但是形参名必须和file标签的name属性值一致。然后在单元方法中将接收到的上传资源通过流存储到服务器的硬盘中即可。

MultipartFile是一个接口,接口中存在很多方法。其中:getlnputStream()、getOriginalFilename()、transferTo(File)为常用方法。

●注意:

如果客户端就一个文件域使用一个MultipartFile对象接收就可以了。

如果客户端是多个同名的文件域使用MultipartFile数组接收。

如果客户端是多个不同名的文件域使用多个MultipartFile对象接收就可以了。

●图片名称中文会产生文乱码

• 添加字符编码过滤器处理post

•<property name="defaultEncoding" value="UTF-8"></property>

●把文件上传到指定服务器中

•request.getServletContext().getRealPath("/imgs");

●UUID保证文件名称唯一

• 采用时间重新命名文件名称 System.currentTimeMillis();

• UUID!

• 雪花算法

●限制文件大小

•<property name="maxuploadsize”value="10240"></property>

•photo.getsize()

●限制文件类型

五、Spring MVC文件下载

文件下载就是把服务器中的资源下载到本地。需要注意的是浏览器本身作为一款软件,能够打开的文件格式比较多。例如:.html文件、图片文件、.txt文件、.xml文件、.json文件等。当超链接访问的是浏览器本身能打开的资源。浏览器直接打开。这个特点就是响应头参数Content-Disposition控制的,其默认值为inline,表示能打开就打开,不能打开就下载。

●Content-Disposition可取值有两个:

•inline。直接在浏览器中打开(能打开就打开,不能打开就下载)

•attachment。以附件形式下载(恒下载)

●测试inline效果

因为Content-Disposition默认值就是inline。所以不需要特殊设置。

在项目的images中放三个文件。a.png是能打开的、b.json也是能打开的、c.rar在浏览器没有安装插件情况下是无法打开的。

●测试attachment效果

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

因为需要设置响应头,所以就必须编写一个下载的控制器。

●文件下载中包含中文名称解决办法

如果文件下载时包含中文名称,需要保证flename=后面的内容是ISO-8859-1编码。如果filename=后面是UTF-8编码且包含中文会乱码。

六、拦截器

过滤器的作用是保护请求的服务器资源,在请求资源被执行之前,如果请求地址条合拦截范围,则会先执行过滤器。

过滤器的执行时机,是在Servlet之前执行的。但是在使用了SpringMVC后,Servlet只有一个了,也就是DisptcherServlet。

如果仍然使用过滤器来完成请求的拦截,因为过滤器是在Servlet之前执行的,就会造成,过滤器会拦截DispatcherServlet所有的请求。

SpringMVC给出了拦截器来实现单元方法的拦截,拦截器的执行是在DispatcherServlet之后和单元方法之前的,这样就可以在单元方法被之前之前对请求进行自定义的拦截处理了。

注意:只有URL匹配到了控制单元,拦截器才能生效

●使用拦截器

•创建拦截器类

     通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。

     通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。

•两者不同点是:

1.WebRequestInterceptor的入参WebRequest是包装了HttpServletRequest 和HttpServletResponse的,通过WebRequest获取Request中的信息更简便。

2.WebRequestInterceptor的preHandle是没有返回值的,说明该方法中的逻辑并不影响后续的方法执行,所以这个接口实现就是为了获取Request中的信息,或者预设一些参数供后续流程使用。

●postHandle方法

作用:

对单元方法转发的资源进行拦截拦截,可以对model中的数据进行校验等。

执行时机: 

单元方法之后,转发的视图资源之前。

参数:

HttpServletRequestrequest:此次拦截的请求的request对象。

HttpServletResponse response:此次拦截的请求的response对象。

Object handler:HandlerMethod类型,存储了拦截的单元方法的method对象。ModelAndView:存储了model和view信息的对象。

●afterCompletion方法

作用:

对整个拦截流程中的异常信息进行捕捉处理。

执行时机:

处理完视图和模型数据,渲染视图完毕之后执行。

参数:

HttpServletRequest request:此次拦截的请求的request对象。

HttpServletResponse response:此次拦截的请求的response对象。

Object handler:HandlerMethod类型,存储了拦截的单元方法的method对象。

Exception:存储异常信息的对象,如果没有异常信息则默认为null。

●AOP通知执行

配置:前置--->环绕前置--->切点--->环绕后置--->后置

注解:环绕前置--->前置--->切点---->后置---->环绕后置

●过滤器和拦截器区别

•来源不同

拦截器是springvc中的技术,过滤器是Java EE中的技术

•生效位置不同

拦截器是进入Dispatcherservlet后才能执行,过滤器是进入到Dispatcherservlet容器前就可以触发。

•目标不同

拦截器拦截的目标是HandlerMethod(控制单元,控制器方法),过滤器可以过滤所有的URL。

•运行机制不同

拦截器是在HandlerMethod之前前后和视图处理完成后执行,分为三部分。过滤器只能在目标资源前后执行。

•接口中方法类型不同

拦截器中的方法都是default方法,可以重写也可以不重写。过滤器中的方法都是abstract方法,如果当前类不是抽象类,必须重写。

•上下文不同

拦截器可以获取到Spring容器中内容,但是Filter因为是被Tomcat管理,所以无法获取Spring容器内容。

七、跨域

项目和项目之前访问的网址或ip:port称为域(domain)

跨域:当前项目的协议、ip、端口和访问的URL的协议、IP、端口中有一个不同,这种访问就叫跨域。

例如:当前项目http://localhost:8080访问了http:/localhost:8081就是跨域访问。

●什么时候有跨域

跨域只发生在Ajax请求中。

Ajax研发之初为了保证安全性,设置默认情况下不允许跨域访问。

●跨域的支持

浏览器为了保证Ajax默认不允许跨域实现,浏览器中都有一个同源策略。

同源策略:当使用ajax请求时,不允许跨域访问。只能访问当前域的资源。

●解决跨域的方式

解决跨域的方法有很多,常见的解决方案:

• jsonp:Spring 4的支持。

•设置响应头:Spring5支持。只需要在允许被跨域访问的方法上面添加@CrossOrigin注解即可。

●@CrossOrigin解释说明

只要在控制单元方法上添加了@CrossOrigin注解后,会在响应头中添加Access-Control-Allow-Origin:*

Access-Control-Allow-Origin是HTTP协议中允许哪些IP的项目跨域访问,*表示所有IP

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值