前面一篇文章,我们讲了SpringMVC如何接收数据,即在springMVC中,如何把数据从前台传递到后台。这篇文章,我们将详细的讲一下springMVC如何响应,即在接收处理数据后,如何对前台进行响应,如何返回画面,如何把后台处理的数据返回到前台。
下面,我们来说一说SpringMVC的数据处理及跳转的方式,即结果跳转的方式
1. ModelAndView,利用视图解析器
1.1 说在之前
首先,我们再看一下前面的那张SpringMVC的原理图:
我们的处理器处理好了之后,将其返回,然后再经过视图解析器(这个我们不用管)解析完成后,就呈现给前台。
了解了是什么之后,我们再来看一下我们之前是怎么写的:
这是一种简化版的写法,然后,我们再来看一下实现这个功能的配置文件:
1.2 具体实现
了解了是什么,以及我们之前是怎么用的了,下面,我们再来看一下,如何使用ModelAndView来实现。
第一步:做相关配置(代码如下):
<!-- templateEngine -->
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver"/>
</bean>
<bean id="templateResolver" class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/html/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5"/>
</bean>
截图如下:
当然,如果是跟着前面的文章创建并配置的,这东西都有,所以就不用管了。
第二步:写Controller中的方法
不说不会,一说就会,很简单的东西。创建对象,调用方法,传递值,返回页面。
多说一句:java中没有key value形式的数据类型(python中有),但是,这种形式在java中很常用,比如xml配置文件,前端书写,某些类方法参数的书写,url中值的传递,都会用到。其实它的底层逻辑还是一种映射匹配的逻辑(猜的),至于如何实现映射匹配,那这方法就有很多了。
第三步:看一下返回后的页面书写(很简单):
这个是刚开始的页面,就多加了一个按钮,没啥
第四步:运行测试:
ModelAndView的整体流程大致就是这样,其中的一些逻辑上的问题,在这上面也提到了。至于一些实操时细节上的错误,具体情况具体分析,不多说。
2.利用servletAPI
2.1 ServletAPI的简单实现
servlet是一个很强大的东西,不需要使用视图解析器,前面我们利用servlet实现了对数据的接收,这里还可以利用servlet来说实现页面和数据的返回。下面,我们一起来看是怎么写的。
第一步:看Controller中的方法
其实这个,啊,也不太好说啥
第二步:看前台:
就多了一个触发器,没啥
第三步:运行测试:
注意,利用了servlet,就没有使用视图解析器,也就不用进行页面返回
2.2 请求转发
请求转发 :是一种服务器行为,指收到客户端发出的请求后,服务器进行转发,转发不会执行转发后的代码,此时将会对请求对象进行保存,地址栏中的URL地址不会改变,得到响应后,服务端再将响应发送给客户端,整个过程只有一个请求,一个响应。
什么意思呢?下面我们来具体解释一下。
首先,我们来看一下流程图:
说明:我们知道,一个服务器可以部署多个项目,一个项目可能有多个servlet。请求转发就是发生在不同的servlet之间的,是靠服务器完成的。首先,我们客户端发出请求,注意,请求分为两部分:请求地址,即url;请求对象(内容),即Request;我们的请求对象会根据我们的请求地址到达我们的服务器,此即R时我们的请求对象equest中的内容会被打到我们服务器中的HttpRequest里面,完成第一次的数据传送。之后,服务器会根据相应的地址(url)将HttpRequest中的内容传递给相应的servlet。但是servlet有个特点,它只能处理HttpServletRequest。所以服务器又将HttpRequest中的内容打到HttpServletRequest中,完成第二次的数据传送。之后servlet会处理HttpServletRequest中的内容。但是,此时,如果servletA因为某些原因不能处理这个请求,同时另一个servletB可以并且想处理这个请求,那么服务器就会将servletA中HttpServletRequest中的内容重新打到HttpRequest中,然后服务器再将HttpRequest中的内容打到servletB中的HttpServletRequest中,由servletB对这个请求进行处理,并且最终由servletB完成对客户端的响应,servletA不进行响应。请求由servletA打到servletB的这个过程,我们称之为请求转发,它是有服务器完成的,整个过程只有一个请求,一个响应。
下面这张图是客户端发出请求的一些信息,包括请求类型,url,Request等等其他的一些内容。
2.3 重定向
重定向(Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置(如:网页重定向、域名的重定向、路由选择的变化也是对数据报文经由路径的一种重定向)
看不懂?下面,我们来具体解释一下。
有了上面请求转发的讲解,我们知道,浏览器发生请求Request到服务器,并将请求Request打到服务器的HttpRequest上,然后服务器再将HttpRequest中的内容打到servlet中的HttpServletRequest上,由servlet进行处理,如果servletA处理不了,会将HttpServletRequest中的内容重新打到服务器的HttpRequest上,然后服务器寻找想要处理并且能够处理的servletB,将HttpRequest中的内容打到servletB中的HttpServletRequest上,由servletB进行处理。
那我们能不能换个途径呢?不用请求转发也可以让servletB来处理相应的请求呢?答案是可以的。
当servletA处理不了时,servletA会将HttpServletRequest中的内容和servletB的地址打到HttpServletResponse中(servlet内部的),然后再由HttpServletResponse将内容打到服务器的HttpResponse上,然后,由服务器将HttpResponse中的内容打到Response中,最后由Response将内容返回给浏览器,然后浏览器会根据servletB的地址,将请求经过一系列的传递,最终打到servletB上,最后由servletB对请求进行处理,然后返回内容。这个过程就是重定向。是服务器指导,客户端行为。
大致流程可以归结为下面的这张图:
注意:请求转发和重定向中的servletB不仅仅指的是servlet,这里只是为了说明简便,用servletB来代替,我们将其范围扩大一下,它可以是客户端也可以是服务端。
区别:请求转发是一个请求,一个响应;重定向是两个请求,两个响应。
2.4 重定向的简单实现
首先,我们来看一下Controller中的方法:
第41-44行,test2方法是重定向的内容
然后,我们在开始页面添加一个触发按钮:
然后,点击运行,我们看一下
解释:当我们点击触发test2的按钮时,test2是被触发了,然后test2通过servletAPI的方法,给客户端返回来了一个mv1的地址,这个过程是一个请求,一个响应,请求是客户端触发的(那个按钮),响应是test2给的(mv1的地址),然后客户端根据test2的响应就是mv1的地址访问mv1,得到了第二个图,这个第二个请求,和第二个响应。整个过程有2个请求2个响应,这就是重定向。
2.5 请求转发的简单实现
下面,我们来看一下请求转发的简单实现
首先,我们看一下Controller中的方法:
然后,我们在index页面中,写一个form表单,进行数据的传递:
然后,我们运行一下,看下结果:
解释:首先,我们根据打印,可以确定test3运行了,然后,由于test3中的servletAPI的方法,我们把请求传递给了test1,然后test1也运行了,内容也打印了,并且最终的响应是test1的响应。纵观整个过程,请求只有一个,就是我们点击“提交”按钮时的请求,响应也只有一个,就是test1的最终给客户端的响应,并且url始终不变,是test3的url,一个请求,一个响应,url不变,这就是请求转发。
3. 利用SpringMVC来实现重定向和请求转发
既然servlet可以实现请求转发和重定向,那么作为一个更高级的框架spring可不可以实现呢?当然是可以的啦,下面,我们一起来看一下mvc如何实现重定向和请求转发。
首先,说明一点,mvc实现这些东西时,不需要视图解析器,所以我们需要将springmvc.xml中的视图解析器的配置注释掉。
注释掉这个之后,我们的suc界面会出现下面的情况,很正常
3.1 mvc实现页面跳转
利用mvc来实现页面跳转是很简单的一件事
首先,我们看一下Controller中的方法:
很简单
然后,在起始页面加一个触发按钮(图略)
然后,看一下运行结果
没有什么问题
3.2 mvc实现请求转发
这个也十分简单,只需要在上面的基础上改一下返回值,再加一个单词即可。下面,我们一起来看一下。
首先,看一下Controller中的方法:
然后,在起始页面加一个触发按钮(图略)
然后,看一下运行结果:
3.3 mvc实现重定向
这个也十分简单,只需要在上面的基础上改一下返回值,再加一个单词即可。下面,我们一起来看一下。
首先,看一下Controller中的方法:
然后,在起始页面加一个触发按钮(图略)
然后,看一下运行结果:
3.4 最常用的方式
就是文章开篇写的,利用视图解析器的那种传统方式,这里就不多说了。这会通常用于跳转页面和对页面赋值。
4. 对json数据的响应
在之前,我们用的是ajax来实现后台的响应的,并且响应的是json类型的数据。那么SpringMVC能不能实现对json类型的数据的响应呢?答案是可以的。下面,我们一起来看一下。
4.1 返回json字符串
之前,我们只用@RequestMapping后,如果要返回,那么返回的是一个页面,现在,我们要返回json类型的数据,具体怎么做,我们一起来看一看
首先,看我们Controller中的方法
解释:重点就是这个ResponseBody注解,因为它的存在,实现了这一规划,具体作用,图片中有。
然后,前台加一个触发按钮(图略)
然后,点击运行一下:
返回的是字符串,乱码问题,后面会解决。
4.2 利用ajax完成数据的传递
下面,我们来看一下,如何利用ajax来完成数据的传递。注意:ajax实现不了页面的跳转。
第一步:导入相关的依赖,代码如下:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
看下截图:
第二步:去写Controller中的方法(截图如下):
第三步:去前台写ajax(代码如下):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<input type="button" value="传值" onclick="get1()">
</body>
<script>
function get1(){
$.ajax ({
type:"get",
url:"/New_SpringMVCDemo_02/mav/test8",
data:{"username":"张三","age":18},
success:function (data){
console.log(data);
},
error:function (XMLHttpRequest,textStatus,errorThrown){
alert(typeof (errorThrown));
}
});
}
</script>
</html>
第四步:运行测试(结果如下图):
其实ajax这块我不是太懂,后面有机会了会认真学一下,然后写几篇博客的。
4.3 对其他资源的放行
我们知道,DIspatcherServlet是一个拦截器,他会拦截转发所有的资源,这就导致一个问题,那就是静态资源(img、css、js)也会被拦截到,从而不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置(代码如下):
<!--设置静态资源不过滤-->
<mvc:resources mapping="/css/**" location="/css/"/> <!--样式-->
<mvc:resources mapping="/images/**" location="/images/"/> <!--图片-->
<mvc:resources mapping="/js/**" location="/js/"/> <!--javascript-->
然后,我们在webapp下创建相应的目录即可
解释:
- 这是用标签配置的方式完成不过滤功能
- location元素表示webapp目录下的包下的所有文件
- mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b