学习视频:B站 狂神说Java – https://www.bilibili.com/video/BV1aE41167Tu?p=1
学习资料:SpringMVC的官方文档 --https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#spring-web
学习文档: 微信公众号 狂神说 --https://mp.weixin.qq.com/mp/homepage?__biz=Mzg2NTAzMTExNg==&hid=3&sn=456dc4d66f0726730757e319ffdaa23e&scene=18&uin=&key=&devicetype=Windows+10+x64&version=63020170&lang=zh_CN&ascene=7&fontgear=2
springMVC 官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc
SpringMVC的重点:SpringMVC的执行流程。
MVC是一种软件设计规范,指的是 Model、View、Controller,分别表示模型、视图、控制器。
我们前面在写代码时的 dao层、service层属于模型,dao层负责对数据的处理,service层进行业务处理;Control 控制层负责 请求转发、重定向,去调用底层业务 以及完成前端的页面渲染,展示给 用户。
Model:数据模型。提供要展示的数据,包括数据和行为,也被认为是 JavaBean组件或领域模型。现在一般就跟为数据Dao 和行为Service。 去提供数据查询和状态更新,还有数据和业务。
而jsp 前端的,那些用户想要看到的,属于视图。View:负责对模型的展示,一般就是我们所见的用户界面,客户想要看到的东西。
servlet层,即控制层 controller,负责转发,重定向;对jsp/html的跳转。 它去接收用户的请求,然后委托给模型进行处理(数据或者状态的改变),然后将处理后的数据返回给 视图 View,由视图展示。 控制器做到就是一个调度员的工作。 接收了一组请求,根据这个请求去调用相应的Model去做数据,业务的处理;然后把结果再给了View,进行展示。
JavaBean 是一种JAVA语言写成的可重用组件。为写成JavaBean,类必须是具体的和公共的,并且具有无参数的构造器。JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,set和get方法获取。众所周知,属性名称符合这种模式,其他Java 类可以通过自省机制(反射机制)发现和操作这些JavaBean 的属性。
最典型的MVC就是JSP + servlet + javabean的模式。[jsp动态web+servlet+java容器 对象实例]
Model1时代:
Model1的优缺点:
Model2时代:
Model2这样不仅提高的代码的复用率与项目的扩展性,且大大降低了项目的维护成本。Model 1模式的实现比较简单,适用于快速开发小规模项目,Model1中JSP页面身兼View和Controller两种角色,将控制逻辑和表现逻辑混杂在一起,从而导致代码的重用性非常低,增加了应用的扩展性和维护的难度。Model2消除了Model1的缺点。
我们建立一个简单的Maven项目, 去理解一下 Model2 时代的一个工作流程。
创建一个Maven项目, 为SpringMVC。删除src文件,使其成为父项目。
1.导入maven依赖:
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.5version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>2.5version>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
dependency>
<dependency>
<groupId>javax.servlet.jsp.jstlgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
dependencies>
2.建立一个Moudle:springmvc-01-servlet , 添加Web app的支持! 在这里,创建一个空的maven项目, 然后选择 addframwork,选择web,并可以选择版本,可以更加方便,减少成本。
3。导入servlet和jsp的 jar依赖
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>2.5version>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
dependency>
dependencies>
4、编写一个Servlet类,用来处理用户的请求。重写 doGet和doPost两种方法。
package com.AL.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1.读取前端参数
String method = req.getParameter("method");
if (method.equals("add")){
req.getSession().setAttribute("msg","执行了add方法");
}
if (method.equals("delete")){
req.getSession().setAttribute("msg","执行了delete方法");
}
// 2.调用业务层
// 3.视图转发或者重定向
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
5、编写test.jsp,在WEB-INF目录下新建一个jsp的文件夹,新建test.jsp。 ${}表示变量占位符,直接替换其中的变量即可。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
${msg}
6、在web.xml中注册Servlet。
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>helloservlet-name>
<servlet-class>com.AL.Servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
web-app>
7、配置Tomcat,并启动测试,这两种方法为:
结果分别为:在浏览器页面显示的结果分别如下所示。
执行了add方法
执行了delete方法
分析这一个maven项目的流程吧:
职责分析:
Controller:控制器,servlet所做的工作:
Model:模型
View:视图
MVC框架要做的事情:
说明:
常见的服务器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;
常见前端MVC框架:vue、angularjs、react、backbone;
由MVC演化出了另外一些模式如:MVP、MVVM 等等…
我们学习的 SpringMVC 所具有的特点:
Spring的web框架围绕着 DispatcherServlet 去进行调度 servlet 设计。**DispatcherServlet**的作用就是将请求分发到不同的处理器。
SpringMVC的工作流程如下图所示:
在用户进行请求时,发送的请求会被前置的控制器拦截,根据拦截到的请求参数生成代理请求, 去找到对应的 实际控制器; 控制器处理请求,此时创建数据库,访问数据库; 然后将处理得到的模型数据返回给控制器; 控制器将利用 模型和视图(ModelAndView) 渲染视图结果;将结果返回给中心控制器,再将结果返回给请求者。
在web.xml配置文件中注册 DispatcherServlet。这个调度员会根据request请求去调度 servlet执行
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servlet.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
在这个 dispatcherServlet中:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
<bean id="/hello" class="com.AL.controller.HelloController"/>
beans>
编写我们的servlet,执行器Controller,并将其交给spring IOC去注册bean
package com.AL.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//注意:这里我们先导入Controller接口
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
System.out.println("我进来了吗?");
//封装对象,放在ModelAndView中。Model
mv.addObject("msg","HelloSpringMVC!");
//封装要跳转的视图,放在ModelAndView中
mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
return mv;
}
}
定义视图。将执行的结果封装在 ModelAndView 中,由其进行渲染。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
${msg}
错误排查:进行测试,发现无法进行跳转。新建lib文件夹,然后将 jar包都导入。
Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。
Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)。
springMVC组件说明:
客户端发送请求-> 前端控制器 DispatcherServlet 接受客户端请求 -> 找到处理器映射 HandlerMapping 解析请求对应的 Handler ->
使用HandlerAdapter 会根据 Handler 来选择处理方式处理请求,并处理相应的业务逻辑 -> 处理器返回一个模型视图 ModelAndView ->
视图解析器进行解析 -> 返回一个视图对象 -> 前端控制器DispatcherServlet 渲染数据(Moder)-> 将得到视图对象返回给用户。
1、前端控制器 DispatcherServlet(不需要工程师开发),由框架提供(重要)作用:Spring MVC 的入口函数。接收请求,响应结果,相当于转发器,中央处理 器。有了 DispatcherServlet 减少了其它组件之间的耦合度。用户请求到达前端控制器,它就相当于 mvc 模式中的 c,
DispatcherServlet 是整个流程控制的中心,由它调用其它 组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。
2、处理器映射器 HandlerMapping(不需要工程师开发),由框架提供
作用:根据请求的 url 查找 Handler。HandlerMapping 负责根据用户请求找到Handler 即处理器(Controller),SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3、处理器适配器 HandlerAdapter
作用:按照特定规则(HandlerAdapter 要求的规则)去执行 Handler。 通过HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
4、处理器 Handler(需要工程师开发)
注意:编写 Handler 时按照 HandlerAdapter 的要求去做,这样适配器才可以去正确执行 Handler。 Handler 是继 DispatcherServlet 前端控制器的后端控制器,在DispatcherServlet 的控制下 Handler 对具体的用户请求进行处理。 由于 Handler 涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发 Handler。
5、视图解析器 View resolver(不需要工程师开发),由框架提供
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)。View Resolver负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。 SpringMVC 框
架提供了很多的 View 视图类型,包括:jstlView、freemarkerView、pdfView 等。 一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。
6、视图 View(需要工程师开发)
View 是一个接口,实现类支持不同的 View 类型(jsp、freemarker、pdf…)
注意:处理器 Handler(也就是我们平常说的 Controller 控制器)以及视图层 View都是需要我们自己手动开发的。其他的一些组件比如:前端控制器 DispatcherServlet、处理器映射器 HandlerMapping、处理器适配器 HandlerAdapter 等等都是框架提供给我们的,不需要自己手动开发。
简要分析执行流程
收到请求,先要去寻找映射器; 返回给 后面找到 url适配器,跳转相应的页面。
我们做的就两个:controller调用业务层,视图层的调用显示。
创建一个HelloSpring项目:Springmvc-02-hellomvc
注册 web.xml文件: 同样是在注册servlet,不过没有像原来一样,直接就自己 注册 映射具体的地址。
在这里 用户的请求,即输入的 url 被 servlet-mapping映射文件 SpringMVC拦截, 拦截到定义的 SpringMVC 配置文件的位置, 即classpath:springmvc-servlet【在 web.xml 配置文件中注册 DispatcherServlet】
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servletparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
/ 和 /* 的区别:< url-pattern > / url-pattern > 不会匹配到.jsp, 只针对我们编写的请求;即:.jsp 不会进入spring的 DispatcherServlet类 。< url-pattern > /* url-pattern > 会匹配 *.jsp,会出现返回 jsp视图 时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.AL.controller"/>
<mvc:default-servlet-handler />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
beans>
在视图解析器中我们把所有的视图都存放在/WEB-INF/目录下,这样可以保证视图安全,因为这个目录下的文件,客户端不能直接访问。
Controller配置文件: 注解开发的方式
package com.AL.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
//真实访问地址 : 项目名/hello
@RequestMapping("/hello")
public String hello(Model model){
//封装数据
model.addAttribute("msg","Hello,SpringMVCAnnotation!");
// web-inf/jsp/hello.jsp
return "hello"; // 会被视图解析器处理
}
}
// 或者可以写成其它的
@Controller
@RequestMapping("/Hello")
public class HelloController {
//真实访问地址 : 项目名/Hello/h1
@RequestMapping("/h1")
public String sayHello(Model model){
//向模型中添加属性msg与值,可以在JSP页面中取出并渲染
model.addAttribute("msg","hello,SpringMVC");
//web-inf/jsp/hello.jsp
return "hello";
}
}
视图层:跳转的页面 hello 和页面的视图信息:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
${msg}
body>
html>
测试:http://localhost:8080/hello
小结
实现步骤其实非常的简单:
使用springMVC必须配置的三大件:处理器映射器、处理器适配器、视图解析器
通常,我们只需要==手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可==,而省去了大段的xml配置
// 注解
@Controller
public class HelloController {
//真实访问地址 : 项目名/hello
@RequestMapping("/hello")
public String hello(Model model){
//封装数据
model.addAttribute("msg","Hello,SpringMVCAnnotation!");
// web-inf/jsp/hello.jsp
return "hello"; // 会被视图解析器处理
}
}
// 原xml配置. 注意:这里我们先导入Controller接口
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
//封装对象,放在ModelAndView中。Model
mv.addObject("msg","HelloSpringMVC!");
//封装要跳转的视图,放在ModelAndView中
mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
return mv;
}
}
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean id="/hello" class="com.AL.controller.HelloController"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
在MVC框架中:处理器 Handler(也就是我们平常说的 Controller 控制器)以及视图层 View都是需要我们自己手动开发的。其他的一些组件比如:前端控制器 DispatcherServlet、处理器映射器 HandlerMapping、处理器适配器 HandlerAdapter 等等都是框架提供给我们的,不需要自己手动开发。【提高开发效率】
控制器Controller
控制器Controller:在xml配置开发的时候,使用了 Controller 接口定义实现,注解开发时使用了 @Controller注解定义实现。
Controller接口:
Controller是一个接口,在org.springframework.web.servlet.mvc包下,接口中只有一个方法;
//实现该接口的类获得控制器功能
public interface Controller {
//处理请求且返回一个模型与视图对象
ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}
创建一个 maven项目, springmvc-04-controller:
配置web.xml文件,注册DispatcherServlet :
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>springmvcservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servlet.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springmvcservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
springmvc-servlet.xml配置文件:定义dispatcherServlet
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.AL.controller"/>
<mvc:default-servlet-handler />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
<bean name="/t1" class="com.AL.controller.ControllerTest1"/>
beans>
实现Controller控制器:
第一种方法:接口定义,实现Controller接口类
编写ControllerTest1 类,实现Controller接口就是一个控制器:
//定义控制器
//注意点:不要导错包,实现Controller接口,重写方法;
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","Test1Controller");
mv.setViewName("test");
return mv;
}
}
定义好控制器 controller后,注册到spring IOC容器bean中:name对应请求路径,class对应处理请求的类
<bean name="/t1" class="com.AL.controller.ControllerTest1"/>
第二种方法:注解定义开发
前端test.jsp界面:注意在WEB-INF/jsp目录下编写,对应我们的视图解析器:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
ALZN
${msg}
说明:
注解:注解的这些关键字,组件有:
注解开发:
注解开发controller控制器:
package com.AL.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
//@Controller注解的类会自动添加到Spring上下文中
@Controller
public class ControllerTest2{
//映射访问路径
@RequestMapping("/t2")
public String index(Model model){
//Spring MVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", "ControllerTest2");
//返回视图位置
return "test";
}
}
指定扫描路径,扫描配置文件:
<context:component-scan base-package="com.AL.controller"/>
支持mvc注解驱动
<mvc:annotation-driven />
测试:重启Tomcat,http://localhost:8080/t2
可以发现,我们的两个请求都可以指向一个视图,但是页面结果的结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱偶合关系。
@RequestMapping:
创建的 ControllerTest3 java类,注解实现controller接口:
@Controller // 被注解的这个类中所有方法,如果返回值是 String,并且有具体页面可以跳转,那么就会被视图解析器解析
@RequestMapping("/c3")
public class ControllerTest3 {
@RequestMapping("/t1")
public String test1(Model model){
model.addAttribute("msg","ControllerTest3");
return "test";
}
}
然后还将 ControllerTest2里面的url映射路径改为 t1:
@Controller
public class ControllerTest2{
//映射访问路径
@RequestMapping("/t1")
public String index(Model model){
//Spring MVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", "ControllerTest2");
//返回视图位置
return "test";
}
}
测试:运行Tomcat,http://localhost:8080/c3/t1
如果 Test3里面只有 /t1这个路径,会发生什么?
发生异常错误。
我们修改想要跳转页面的路径:
修改:
@Controller
@RequestMapping("/c3")
public class ControllerTest3 {
@RequestMapping("/t1")
public String test1(Model model){
model.addAttribute("msg","ControllerTest3");
//return "test";
return "admin/test";
}
}
也可以在注解类上修改:
@Controller
//@RequestMapping("/c3")
@RequestMapping("/c3/admin")
public class ControllerTest3 {
@RequestMapping("/t1")
public String test1(Model model){
model.addAttribute("msg","ControllerTest3");
return "test";
//return "admin/test";
}
}
结果ok。
不过建议 一般在方法上面进行注解。
RestFul 风格
概念
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
功能
资源:互联网所有的事物都可以被抽象为资源
资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
分别对应 添加、 删除、修改、查询。
传统方式操作资源 :通过不同的参数来实现不同的效果!方法单一,post 和 get
http://127.0.0.1/item/queryItem.action?id=1 查询,GET
http://127.0.0.1/item/saveItem.action 新增,POST
http://127.0.0.1/item/updateItem.action 更新,POST
http://127.0.0.1/item/deleteItem.action?id=1 删除,GET或POST
使用RESTful操作资源 :可以通过不同的请求方式来实现不同的效果!如下:请求地址一样,但是功能可以不同!
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 删除,DELETE
例子: Restful只是一种风格, 它是通过不同的请求方式 去实现不同的效果。【在3.2中有看到我们的两个请求都可以指向一个视图,但是页面结果的结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱偶合关系。】
原始的方法:
package com.AL.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RestfulController {
@RequestMapping("/add")
public String test1(int a, int b, Model model){ // 传统的传入参数方法:在url中使用 & 进行连接多个参数 /add?a=1&b=2
int res = a + b;
model.addAttribute("msg","结果为:"+res);
return "test";
}
}
测试:在url路径中手动传参,且用逻辑与符号 & 将多个参数连接。 http://localhost:8080/add?a=1&b=2
采用Restful风格:
在Spring MVC中可以使用 @PathVariable 注解,让方法参数的值对应绑定到一个URI模板变量上。
// Restful风格: http://localhost:8080/add/a/b http://localhost:8080/add/10/20
@RequestMapping("/add/{a}/{b}")
public String test1(@PathVariable int a, @PathVariable int b, Model model){
int res = a + b;
model.addAttribute("msg","结果为:"+res);
return "test";
}
测试:启动Tomcat,在路径中直接写入参数,且会自己去进行比较参数类型。
http://localhost:8080/add/10/20 结果如下:
使用method属性指定请求类型:
上述的默认的这样是以 GET方法进行对a b 的获取, 我们也可以自己去定义获取这个数据的方法, 如以下两种形式:
// Restful风格: http://localhost:8080/add/a/b http://localhost:8080/add/10/20
//@RequestMapping("/add/{a}/{b}")
//@RequestMapping(value = "/add/{a}/{b}", method = RequestMethod.GET),MVC中默认的获取参数方法为 GET, 可以自己去定义获取参数的方法
//@RequestMapping(value = "/add/{a}/{b}", method = RequestMethod.POST) // 会发现执行此方法时 会发生错误。因为映射访问路径,必须是Get请求
@PostMapping("add/{a}/{b}") // value是默认的属性,不用添加也可以. // 这样运行也是错误的?????
public String test1(@PathVariable int a, @PathVariable int b, Model model){
int res = a + b;
model.addAttribute("msg","结果为:"+res);
return "test";
}
这是因为:映射访问路径,必须是Get请求。
解决思路:
我们可以定义一个a.jsp,通过 submit方式进行提交:通过表单的方式去获取:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
ALZN-Restful-Method
结果:http://localhost:8080/add/1/20
改变路径参数类型:
@PostMapping("add/{a}/{b}") // value是默认的属性,不用添加也可以
public String test1(@PathVariable int a, @PathVariable String b, Model model){
String res = a + b;
model.addAttribute("msg","结果为:"+res);
return "test";
}
测试:http://localhost:8080/add/1/9,结果为:可以发现自动转换为 String类型
思考:使用路径变量的好处?
@RequestMapping注解的用法 - 宏愿。 - 博客园 (cnblogs.com)
@RequestMapping的属性:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
设置ModelAndView对象 , 根据view的名称 , 和视图解析器跳到指定的页面 .
页面 : {视图解析器前缀} + viewName +{视图解析器后缀}
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
例子:
创建一个 ModelTest1 控制器controller,进行 使用 request和response测试:
@Controller
public class ModelTest1 {
@RequestMapping("/m1/t1")
public String test1(HttpServletRequest request, HttpServletResponse response){
HttpSession session = request.getSession();
System.out.println(session.getId());
return "test";
}
}
通过设置ServletAPI , 不需要视图解析器 .
1、通过HttpServletResponse进行输出
2、通过HttpServletResponse实现重定向
3、通过HttpServletResponse实现转发
@Controller
public class ResultGo {
@RequestMapping("/result/t1")
public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.getWriter().println("Hello,Spring BY servlet API");
}
@RequestMapping("/result/t2")
public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.sendRedirect("/index.jsp");
}
@RequestMapping("/result/t3")
public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
//转发
req.setAttribute("msg","/result/t3");
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
}
}
通过SpringMVC来实现转发和重定向 - 无需视图解析器;
测试前,需要将视图解析器注释掉【如果不注释掉视图解析器,会发生错误】
@Controller
public class ModelTest1 {
@RequestMapping("/rsm/t1")
public String test1(){
//转发
return "/index.jsp";
}
@RequestMapping("/rsm/t2")
public String test2(){
//转发二
return "forward:/index.jsp";
}
@RequestMapping("/rsm/t3")
public String test3(){
//重定向
return "redirect:/index.jsp";
}
}
通过SpringMVC来实现转发和重定向 - 有视图解析器;
重定向 , 不需要视图解析器 , 本质就是重新请求一个新地方嘛 , 所以注意路径问题.
可以重定向到另外一个请求实现 .
@Controller
public class ResultSpringMVC2 {
@RequestMapping("/rsm2/t1")
public String test1(){
//转发
return "test";
}
@RequestMapping("/rsm2/t2")
public String test2(){
//重定向
return "redirect:/index.jsp";
//return "redirect:hello.do"; //hello.do为另一个请求/
}
}
数据处理
处理提交数据
1、提交的域名称和处理方法的参数名一致
提交数据 : http://localhost:8080/hello?name=alzn
处理方法 :
@Controller
public class DataController {
@RequestMapping("/hello")
public String hello(String name){
System.out.println(name);
return "hello";
}
}
在后台输出的数据为: alzn
2、提交的域名称和处理方法的参数名不一致
提交数据 : http://localhost:8080/hello1?username=alzn
处理方法 : 使用 @RequestParam() 注解来指定提交的url中的参数名称。
//@RequestParam("username") : username提交的域的名称 .
@RequestMapping("/hello1")
public String hello1(@RequestParam("username") String name){
System.out.println(name);
return "hello1";
}
后台输出 : alzn
3、提交的是一个对象
要求提交的表单域和对象的属性名一致 , **参数使用对象**即可。
定义一个 user 类:
package com.AL.ppojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private int age;
}
定义Controller:
@RequestMapping("/user")
public String user(User user){
System.out.println(user);
return "hello";
}
提交数据:http://localhost:8080/user?name=alzn&id=18&age=20
在后台输出的结果为:User(id=18, name=alzn, age=20)
第一种 : 通过Model
控制器 Controller 类的代码:
package com.AL.controller;
import com.AL.ppojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/t1")
public String test1(String name, Model model){
// 1.接收前端参数
System.out.println("前端传过来的参数为:->"+ name);
// 2.将返回的结果给前端 model
model.addAttribute("msg", name);
return "test";
}
// 当前端的参数名和控制器中的方法名参数不一样时, 即域名和方法的参数名不一样时:
@RequestMapping("/t2")
public String test2(@RequestParam("username") String name, Model model){
// 1.接收前端参数
System.out.println("前端传过来的参数为:->"+ name);
// 2.将返回的结果给前端 model
model.addAttribute("msg", name);
return "test";
}
// 当前端给的是一个对象时
@RequestMapping("/t3")
public String test3(User user){
System.out.println(user);
return "test";
}
}
域名和方法的参数名不一样时:使用 @RequestParam()注解去自定义域名中的参数名。
http://localhost:8080/user/t2?username=%E5%B0%BC%E7%8E%9B
http://localhost:8080/user/t3?name=alzn&id=1&age=18
后台的数据为:User(id=1, name=alzn, age=18)
第二种:通过ModelAndView
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest1");
mv.setViewName("test");
return mv;
}
}
第三种 : 通过ModelMap
ModelMap【这种的,对于多个属性如何查看 传递给前端呢?】
@RequestMapping("/t4")
public String test4(User user, ModelMap modelMap){
System.out.println(user);
modelMap.addAttribute("msg", user.getName());
return "test";
}
乱码问题:
package com.AL.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class EncodingController {
@PostMapping("/e/t")
public String test(String name, Model model){
System.out.println(name);
model.addAttribute("msg",name); //获取表单提交的值
return "encodeTest"; //跳转到test页面显示输入的值
}
}
我们可以在首页index.jsp 编写一个提交的表单
@PostMapping(“/e/t”),使用 POST method提交数据
表单中定义了 post方法,进行提交数据。
encodeTest.jsp页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
${msg}
测试:
在首页的表单中输入文本:
DispatchServlet 会调用HandlerMapping 找到Handler,适配器调用servlet程序运行。 http://localhost:8080/e/t 调用url路径对应的方法,执行结果:
假如输入中文: 出现了乱码。
以前乱码问题通过过滤器解决 , 而SpringMVC给我们提供了一个过滤器 , 可以在web.xml中配置 .
修改了xml文件之后重启服务器进行测试,发现结果ok,没有出现乱码。
<filter>
<filter-name>encodingfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
前后端分离时代:
后端部署后端,提供接口,提供数据:
Json
前端独立部署,负责渲染后端的数据
什么是JSON?
在 JavaScript 语言中,一切都是对象。因此,任何JavaScript 支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。看看他的要求和语法格式:
JSON 键值对是用来保存 JavaScript 对象的一种方式,和 JavaScript 对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号 “” 包裹,使用冒号 : 分隔,然后紧接着值:
{"name": "QinJiang"}
{"age": "3"}
{"sex": "男"}
很多人搞不清楚 JSON 和 JavaScript 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:
JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的
var json = '{"a": "Hello", "b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串
JSON 和 JavaScript 对象互转
要实现从JSON字符串转换为JavaScript 对象,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}');
//结果是 {a: 'Hello', b: 'World'}
要实现从JavaScript 对象转换为JSON字符串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'});
//结果是 '{"a": "Hello", "b": "World"}'
例子:
创建一个 springmvc-05-json项目,
1.在web文件下创建jsontest.html文件:在这里面的代码 只能这样写: 不能自闭和。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSON_鑫鑫title>
head>
<body>
<script type="text/javascript">
//编写一个js的对象
var user = {
name:"鑫仔",
age:3,
sex:"男"
};
//将js对象转换成json字符串
var str = JSON.stringify(user);
console.log(str);
//将json字符串转换为js对象
var user2 = JSON.parse(str);
console.log(user2.age,user2.name,user2.sex);
script>
body>
html>
在IDEA中直接打开浏览器观察结果:[直接点击右上角中的浏览器图标,即可查看HTML文件运行结果]
Controller返回JSON数据
Jackson应该是目前比较好的json解析工具了
当然工具不止这一个,比如还有阿里巴巴的 fastjson 等等。
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.8version>
dependency>
dependencies>
配置SpringMVC需要的配置
web.xml中注册 DispatcherServlet 前端控制器:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc-servlet.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>encodingfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingfilter-name>
<url-pattern>/url-pattern>
filter-mapping>
web-app>
定义 DispatcherServlet 的配置文件:springmvc-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.AL.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
beans>
User实体类:使用lombok插件
package com.AL.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String sex;
}
Controller控制器:UserController 。在这里还使用了注解 @ResponseBody。
package com.AL.controller;
import com.AL.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
@RequestMapping("/j1")
@ResponseBody // 它就不会走视图解析器,会直接返回一个字符串。
public String json1(){
User user = new User("鑫仔1号", 18, "男");
return user.toString();
}
}
测试:配置Tomcat启动,运行发现错误。检查发现没有 lib文件,没有将jar包导入。
浏览器输入:http://localhost:8080/j1 结果显示乱码:
解决乱码问题:
我们需要设置一下他的编码格式为utf-8,以及它返回的类型;
通过==@RequestMaping的produces属性==来实现,修改下代码
//produces:指定响应体返回类型和编码
@RequestMapping(value = "/j1",produces = "application/json;charset=utf-8")
再次测试, http://localhost:8080/j1 , 乱码问题OK!
乱码统一解决
上一种方法比较麻烦,如果项目中有许多请求则每一个都要添加,可以通过Spring配置统一指定,这样就不用每次都去处理了!
我们可以在springmvc的配置文件上添加一段消息 StringHttpMessageConverter转换配置!
在 srpingmvc-servlet.xml文件中添加 json转换格式:
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
bean>
property>
bean>
mvc:message-converters>
mvc:annotation-driven>
采用 jackson 进行 json ,数据类型形式的变换:此时需两个东西,一个是@ResponseBody,一个是ObjectMapper对象:
package com.AL.controller;
import com.AL.pojo.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; // jackson中的Mapper对象 映射
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
//@RequestMapping("/j1")
@ResponseBody // 它就不会走视图解析器,会直接返回一个字符串。
@RequestMapping(value = "/j1",produces = "application/json;charset=utf-8") //produces:指定响应体返回类型和编码
public String json1(){
User user = new User("鑫仔1号", 18, "男");
return user.toString();
}
@RequestMapping("/j2")
@ResponseBody
public String json2() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
//创建一个对象
User user = new User("鑫仔1号", 18, "男");
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(user);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return str;
}
}
启动Tomcat进行测试:http://localhost:8080/j2
返回json字符串统一解决
在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody !我们在前后端分离开发中,一般都使用 @RestController ,十分便捷!
在控制器 controller 中,如果想要返回的全部是 json字符串, 那么注解开发时直接使用**@RestController**就可以了。如下所示:
@RestController
public class UserController3 {
@RequestMapping("/t3/j1")
//@ResponseBody // 它就不会走视图解析器,会直接返回一个字符串。
//@RequestMapping(value = "/j1",produces = "application/json;charset=utf-8") //produces:指定响应体返回类型和编码
public String json1(){
User user = new User("鑫仔1号", 18, "男");
return user.toString();
}
@RequestMapping("/t3/j2")
// @ResponseBody //由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
public String json2() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
//创建一个对象
User user = new User("鑫仔1号", 18, "男");
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(user);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return str;
}
}
例子:
@RequestMapping("/t3/j3")
// @ResponseBody //由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
public String json3() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
//创建一个集合对象
List<User> list = new ArrayList<User>();
User user1 = new User("鑫仔1号", 18, "男");
User user2 = new User("鑫仔2号", 19, "男");
User user3 = new User("鑫仔3号", 20, "男");
User user4 = new User("鑫仔4号", 21, "男");
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(list);
return str;
}
启动Tomcat测试的结果:
@RequestMapping("/t3/j4")
// @ResponseBody //由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
public String json4() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
Date date = new Date();
//将我们的对象解析成为json格式. ObjectMapper,时间解析后的默认格式为:Timestamp 时间戳
String str = mapper.writeValueAsString(date);
return str;
}
结果:
@RequestMapping("/t3/j4")
// @ResponseBody //由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
public String json4() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
Date date = new Date();
// 自定义日期的格式
SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
//将我们的对象解析成为json格式. ObjectMapper,时间解析后的默认格式为:Timestamp 时间戳
//String str = mapper.writeValueAsString(date);
String str = mapper.writeValueAsString(sdf.format(date)); //使用 ObjectMapper 来格式化输出
return str;
}
优化:提高代码可复用性:
将时间戳转换格式封装成一个类:
package com.AL.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.text.SimpleDateFormat;
public class JsonUtils {
public static String getJson(Object object) {
return getJson(object,"yyyy-MM-dd HH:mm:ss");
}
public static String getJson(Object object,String dateFormat) {
ObjectMapper mapper = new ObjectMapper();
//不使用时间差的方式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//自定义日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
//指定日期格式
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
控制器controller修改:
@RequestMapping("/t3/j5")
public String json5() throws JsonProcessingException {
Date date = new Date();
String json = JsonUtils.getJson(date);
return json;
}
单独使⽤ @Controller 不加 @ResponseBody 的话⼀般 使⽤在 要返回⼀个视图的情况,这种情况属于⽐较传统的Spring MVC 的应⽤,对应于前后端不分离的情况。
@RestController 只返回对象,对象数据直接以 JSON 或 XML 形式写⼊ HTTP 响应(Response)中,这种情况属于 RESTful Web服务,这也是⽬前⽇常开发所接触的最常⽤的情况(前后端分离)。
@RestController返回JSON或XML形式数据
@ResponseBody 注解的作⽤是将 Controller 的⽅法返回的对象通过适当的转换器转换为指定的格式之后,写⼊到HTTP 响应(Response)对象的 body 中,通常⽤来返回 JSON 或者XML 数据,返回 JSON 数据的情况⽐较多。
@Controller + @ResponseBody = @RestController
Ajax研究
ajax:异步无刷新请求。jquery是一个库,js中的一个函数,方法。
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
Ajax 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术。
在 2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来。Google Suggest能够自动帮你完成搜索单词。
Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当您在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。
就和国内百度的搜索框一样!
传统的网页(即不用ajax技术的网页),想要更新内容或者提交一个表单,都需要重新加载整个网页。
使用ajax技术的网页,通过在后台服务器进行少量的数据交换,就可以实现异步局部更新。
使用Ajax,用户可以创建接近本地桌面应用的直接、高可用、更丰富、更动态的Web用户界面。
伪造Ajax:
我们可以使用前端的一个标签来伪造一个ajax的样子。iframe标签
1、新建一个module :sspringmvc-06-ajax , 导入web支持!
编写 web.xml配置文件,注册dispatcherServlet以及启动顺序和编码等web信息:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicatinContext.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>encodingfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
2、在资源配置文件中进行注解驱动,注解类的包扫描,视图解析器:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.AL.controller"/>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
beans>
3、编写一个控制器 Controller,进行测试 查看环境搭建是否成功:
@RestController
public class AjaxController {
@RequestMapping("/t1")
public String test(){
return "hello";
}
}
4、编写一个 ajax-frame.html 使用 iframe 测试,感受下效果
创建一个 test.html文件,设立一个伪 ajax去进行测试:
DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>iframe测试体验页面无刷新title>
head>
<body>
<script type="text/javascript">
window.onload = function(){
var myDate = new Date();
document.getElementById('currentTime').innerText = myDate.getTime();
};
function LoadPage(){
var targetUrl = document.getElementById('url').value;
console.log(targetUrl);
document.getElementById("iframePosition").src = targetUrl;
}
script>
<div>
<p>请输入要加载的地址:<span id="currentTime">span>p>
<p>
<input id="url" type="text" value="https://www.baidu.com/"/>
<input type="button" value="提交" onclick="LoadPage()">
p>
div>
<div>
<h3>加载页面位置:h3>
<iframe id="iframePosition" style="width: 100%;height: 500px;">iframe>
div>
body>
html>
利用AJAX可以做:
jQuery.ajax
纯JS原生实现Ajax我们不去讲解这里,直接使用jquery提供的,方便学习和使用,避免重复造轮子,有兴趣的同学可以去了解下JS原生XMLHttpRequest !
Ajax的核心是XMLHttpRequest对象(XHR)。XHR为向服务器发送请求和解析服务器响应提供了接口。能够以异步方式从服务器获取新数据。
jQuery 提供多个与 AJAX 有关的方法。
通过 jQuery AJAX 方法,您能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML 或 JSON – 同时您能够把这些外部数据直接载入网页的被选元素中。
jQuery 不是生产者,而是大自然搬运工。
jQuery Ajax本质就是 XMLHttpRequest,对他进行了封装,方便调用!
jQuery.ajax(...)
部分参数:
url:请求地址
type:请求方式,GET、POST(1.9.0之后用method)
headers:请求头
data:要发送的数据
contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
async:是否异步
timeout:设置请求超时时间(毫秒)
beforeSend:发送请求前执行的函数(全局)
complete:完成之后执行的回调函数(全局)
success:成功之后执行的回调函数(全局)
error:失败之后执行的回调函数(全局)
accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型
dataType:将服务器端返回的数据转换成指定类型
"xml": 将服务器端返回的内容转换成xml格式
"text": 将服务器端返回的内容转换成普通文本格式
"html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
"script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
"json": 将服务器端返回的内容转换成相应的JavaScript对象
"jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数
jQuery下载地址:https://jquery.com/download/
选择另存为即可,然后导入文件夹下:
例子:失去焦点的时候,发起一个请求到后台:
需要在 applicationContext中配置静态资源过滤:
<mvc:annotation-driven/>
<mvv:default-servlet-handler/>
在默认界面 index.jsp中编写ajax代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title$
<%----%>
<%--onblur:失去焦点触发事件--%>
用户名:
跳转页面的信息修改, controller的代码:在/a1中时请求发生后调用的 servlet。
@RequestMapping("/a1")
public void ajax1(String name , HttpServletResponse response) throws IOException {
if ("admin".equals(name)){
response.getWriter().print("true");
}else{
response.getWriter().print("false");
}
}
启动tomcat测试!打开浏览器的控制台,当我们鼠标离开输入框的时候,可以看到发出了一个ajax的请求!是后台返回给我们的结果!测试成功!
再次修改前端中 ajax所要展示的状态: status。
ajax所做的事情:
测试: 创建一个实体类 User去进行测试,体会Ajax的 失去焦点,就触发的例子, 导入Lombok:
实体类User:
package com.AL.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String sex;
}
Controller控制器:我们来获取一个集合对象,展示到前端页面
@RequestMapping("/a2")
public List<User> ajax2(){
List<User> list = new ArrayList<User>();
list.add(new User("鑫仔1号",18,"男"));
list.add(new User("鑫仔2号",20,"男"));
list.add(new User("鑫仔3号",3,"男"));
return list; // json
}
启动Tomcat测试,发现 url 为a2时可以获取这些数据。http://localhost:8080/a2
我们如何将这些数据 通过ajax去获取,且不用去页面去变化:test2.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
姓名
年龄
性别
启动,运行测试:
注册提示效果
我们再测试一个小Demo,思考一下我们平时注册时候,输入框后面的实时提示怎么做到的;如何优化。
例子:
@RequestMapping("/a3")
public String ajax3(String name,String pwd){
String msg = "";
//模拟数据库中存在数据
if (name!=null){
if ("admin".equals(name)){
msg = "OK";
}else {
msg = "用户名输入错误";
}
}
if (pwd!=null){
if ("123456".equals(pwd)){
msg = "OK";
}else {
msg = "密码输入有误";
}
}
return msg; //由于@RestController注解,将msg转成json格式返回
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
ajax
用户名:
密码:
启动测试:发现出现了乱码的问题。
解决:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:mvv="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.AL.controller"/>
<mvc:annotation-driven/>
<mvv:default-servlet-handler/>
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
bean>
property>
bean>
mvc:message-converters>
mvc:annotation-driven>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
beans>
拦截器
概述
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:拦截器是AOP思想的具体应用。即横向,面向切面的,不会影响代码。
过滤器
拦截器
实现拦截器有两种方法:
一种是实现 HandlerInterceptor 接口;
另外一种是**继承适配器类[继承实现了WebRequestInterceptor接口]**,接着在接口方法当中,实现处理逻辑,然后在 SpringMVC 的配置文件中配置拦截器即可。
创建一个Maven项目,先测试能否正常启动: 查看Spring是否配置成功了。
控制器 controller:
package com.AL.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@RequestMapping("/t1")
public String test(){
System.out.println("TestController执行了-》test()方法");
return "OK";
}
}
资源配置文件applicationContext.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:mvv="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.AL.controller"/>
<mvv:default-servlet-handler/>
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
bean>
property>
bean>
mvc:message-converters>
mvc:annotation-driven>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
beans>
web.xml核心配置文件, 注册映射servlet,过滤器。绑定DispatcherServlet 配置文件:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicatinContext.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<filter>
<filter-name>encodingfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>encodingfilter-name>
<url-pattern>/url-pattern>
filter-mapping>
web-app>
测试的前端页面:即默认页面,然后请求 url路径。
后台输出:TestController执行了-》test()方法
搭建的 spring项目没有问题。
那如何实现拦截器呢?
想要自定义拦截器,必须实现 HandlerInterceptor 接口。
1、新建一个Moudule , springmvc-07-Interceptor , 添加web支持
2、配置web.xml 和 springmvc-servlet.xml 文件
package com.AL.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
//在请求处理的方法之前执行
//如果返回true执行下一个拦截器
//如果返回false就不执行下一个拦截器
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("------------处理前------------");
return true;
}
//在请求处理方法执行之后执行
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("------------处理后------------");
}
//在dispatcherServlet处理后执行,做清理工作.
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("------------清理------------");
}
}
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.AL.config.MyInterceptor"/>
mvc:interceptor>
mvc:interceptors>
@RequestMapping("/interceptor") // 测试拦截器
public String testFunction() {
System.out.println("控制器中的方法执行了");
return "hello";
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title$
拦截器测试
运行Tomcat进行测试:http://localhost:8080/
且此时后台输出:
------------处理前------------
控制器中的方法执行了
------------处理后------------
------------清理------------
接口HandlerInterceptor中的方法:
验证用户是否登录 (认证用户)
实现思路
1、有一个登陆页面,需要写一个controller访问页面。
2、登陆页面有一提交表单的动作。需要在controller中处理。判断用户名密码是否正确。如果正确,向session中写入用户信息。返回登陆成功。
3、拦截用户请求,判断用户是否登陆。如果用户已经登陆。放行, 如果用户未登陆,跳转到登陆页面
例子:
1.创建一个首页 main.jsp, 登录页面login.jsp
main.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
首页
login.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
登录页面
2.创建一个控制器:LoginController:
一个url 为/mian去跳转到main主界面; 另一个 url=/goLogin跳转到login界面
package com.AL.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/user")
public class LoginController {
@RequestMapping("/main")
public String main(){
return "main";
}
@RequestMapping("/goLogin")
public String login(){
return "login";
}
@RequestMapping("/login")
public String login(HttpSession session, String username, String password){
// 把用户信息存储在 session中
session.setAttribute("userLoginInfo", username);
return "main";
}
}
3.在默认页面进行修改,使其能够跳转到登录页面和首页:index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title$
<%-- 拦截器测试--%>
登录页面
首页
4.创建一个用户登录的拦截器:LoginInterceptor 实现HandlerInterceptor接口
package com.AL.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
// preHandler,在Controller执行前进行的方法
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
// 放行: 判断在什么情况下会登录
// 如果是登录页面 会放行
if (request.getRequestURI().equals("goLogin")){
return true;
}
// 说明我在提交登录
if (request.getRequestURI().equals("login")){
return true;
}
// 第一次登录,也是没有 session的
if (session.getAttribute("userLoginInfo") != null){
return true;
}
// 判断什么情况下没有登录
request.getRequestDispatcher("/WEB/INF/jsp/login.jsp").forward(request,response);
return false;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
5.拦截器配置,定义在/user 下的url路径都会被拦截,在这里,我们写的三个都会被拦截。
<mvc:mapping path="user/**"/>
<bean class="com.AL.config.LoginInterceptor"/>
mvc:interceptor>
启动Tomcat进行测试:观察首页,登录页面,这几个 url 页面是否能够被准确拦截,且不会误拦截
例子:我们想让上述的例子,再登陆后,把信息显示出来,名字:
1.修改 controller中的代码: 并增加了注销这个请求的 servlet:
@RequestMapping("/login")
public String login(HttpSession session, String username, String password, Model model){
System.out.println("login==>"+username);
// 把用户信息存储在 session中
session.setAttribute("userLoginInfo", username);
model.addAttribute("username", username);
return "main";
}
@RequestMapping("/goOut")
public String goOut(HttpSession session){
session.removeAttribute("userLoginInfo");
return "main";
}
2.首页界面, 前端显示: 且增加了注销:main.jsp中定义
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
首页
${username}
这个拦截器是Spring自己的,因为它直接在 applicationContext.xml中就完成配置, 不需要在web.xml中去进行。而且它是 spring mvc的, 因为它注册的时候,拦截配置为如下:
<mvc:interceptor>
<mvc:mapping path="user/**"/>
<bean class="com.AL.config.LoginInterceptor"/>
mvc:interceptor>
其实写拦截器就两个步骤:写一个拦截器的类,关于在什么时候放行,什么时候阻止;然后注册拦截器即可。
springMVC中的 interceptor 拦截器的作用:拦截用户请求并进行响应的处理。例如:权限验证、是否登录…
博客链接:https://www.cnblogs.com/nan993/p/6203328.html
SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的。在SpringMVC 中定义一个Interceptor 非常简单,主要有两种方式,
HandlerInterceptor 接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。
(1 )preHandle (HttpServletRequest request, HttpServletResponse response, Object handle) 方法,顾名思义,该方法将在请求处理之前进行调用。SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
(2 )postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法,由preHandle 方法的解释我们知道这个方法包括后面要说到的afterCompletion 方法都只能是在当前所属的Interceptor 的preHandle 方法的返回值为true 时才能被调用。postHandle 方法,顾名思义就是**在当前请求进行处理之后,也就是Controller 方法调用之后执行**,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行,这和Struts2 里面的Interceptor 的执行过程有点类型。Struts2 里面的Interceptor 的执行过程也是链式的,只是在Struts2 里面需要手动调用ActionInvocation 的invoke 方法来触发对下一个Interceptor 或者是Action 的调用,然后每一个Interceptor 中在invoke 方法调用之前的内容都是按照声明顺序执行的,而invoke 方法之后的内容就是反向的。
(3 )afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法,该方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。
下面是一个简单的代码说明:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class SpringMVCInterceptor implements HandlerInterceptor {
/**
* preHandle方法是进行处理器拦截用的,顾名思义,该方法将在Controller处理之前进行调用,SpringMVC中的Interceptor拦截器是链式的,可以同时存在 多个Interceptor,然后SpringMVC会根据声明的前后顺序一个接一个的执行,而且所有的Interceptor中的preHandle方法都会在 Controller方法调用之前调用。
SpringMVC的这种Interceptor链式结构也是可以进行中断的,这种中断方式是令preHandle的返 回值为false,当preHandle的返回值为false的时候整个请求就结束了。
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generated method stub
return false;
}
/**
* 这个方法只会在当前这个Interceptor的preHandle方法返回值为true的时候才会执行。postHandle是进行处理器拦截用的,它的执行时间是在处理器进行处理之 后,也就是在Controller的方法调用之后执行,
但是它会在DispatcherServlet进行视图的渲染之前执行,也就是说在这个方法中你可以对ModelAndView进行操作。
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
}
/**
* 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。该方法将在整个请求完成之后,也就是DispatcherServlet渲染了视图执行,
* 这个方法的主要作用是用于清理资源的,当然这个方法也只能在当前这个Interceptor的preHandle方法的返回值为true时才会执行。
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}
WebRequestInterceptor 中也定义了三个方法,我们也是通过这三个方法来实现拦截的。这三个方法都传递了同一个参数WebRequest ,那么这个WebRequest 是什么呢?这个WebRequest 是Spring 定义的一个接口,它里面的方法定义都基本跟HttpServletRequest 一样,在WebRequestInterceptor 中对WebRequest 进行的所有操作都将同步到HttpServletRequest 中,然后在当前请求中一直传递。
(1 )preHandle(WebRequest request) 方法。该方法将在请求处理之前进行调用,也就是说会在Controller 方法调用之前被调用。这个方法跟HandlerInterceptor 中的preHandle 是不同的,主要区别在于该方法的返回值是void ,也就是没有返回值,所以我们一般主要用它来进行资源的准备工作,比如我们在使用Hibernate 的时候可以在这个方法中准备一个Hibernate 的Session 对象,然后利用WebRequest 的setAttribute(name, value, scope)把它放到WebRequest 的属性中。这里可以说说这个setAttribute 方法的第三个参数scope ,该参数是一个Integer类型的。在WebRequest 的父层接口RequestAttributes 中对它定义了三个常量:
SCOPE_REQUEST :它的值是0 ,代表只有在request 中可以访问。
SCOPE_SESSION :它的值是1 ,如果环境允许的话它代表的是一个局部的隔离的session,否则就代表普通的session,并且在该session范围内可以访问。
SCOPE_GLOBAL_SESSION :它的值是2 ,如果环境允许的话,它代表的是一个全局共享的session,否则就代表普通的session,并且在该session 范围内可以访问。
(2 )postHandle(WebRequest request, ModelMap model) 方法。该方法将在请求处理之后,也就是在Controller 方法调用之后被调用,但是会在视图返回被渲染之前被调用,所以可以在这个方法里面通过改变数据模型ModelMap 来改变数据的展示。该方法有两个参数,WebRequest 对象是用于传递整个请求数据的,比如在preHandle 中准备的数据都可以通过WebRequest 来传递和访问;ModelMap 就是Controller 处理之后返回的Model 对象,我们可以通过改变它的属性来改变返回的Model 模型。
(3 )afterCompletion(WebRequest request, Exception ex) 方法。该方法会在整个请求处理完成,也就是在视图返回并被渲染之后执行。所以在该方法中可以**进行资源的释放操作**。而WebRequest 参数就可以把我们在preHandle 中准备的资源传递到这里进行释放。Exception 参数表示的是当前请求的异常对象,如果在Controller中抛出的异常已经被Spring 的异常处理器给处理了的话,那么这个异常对象就是是null 。
下面是一个简单的代码说明:
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;
public class AllInterceptor implements WebRequestInterceptor {
/**
* 在请求处理之前执行,该方法主要是用于准备资源数据的,然后可以把它们当做请求属性放到WebRequest中
*/
@Override
public void preHandle(WebRequest request) throws Exception {
// TODO Auto-generated method stub
System.out.println("AllInterceptor...............................");
request.setAttribute("request", "request", WebRequest.SCOPE_REQUEST);//这个是放到request范围内的,所以只能在当前请求中的request中获取到
request.setAttribute("session", "session", WebRequest.SCOPE_SESSION);//这个是放到session范围内的,如果环境允许的话它只能在局部的隔离的会话中访问,否则就是在普通的当前会话中可以访问
request.setAttribute("globalSession", "globalSession", WebRequest.SCOPE_GLOBAL_SESSION);//如果环境允许的话,它能在全局共享的会话中访问,否则就是在普通的当前会话中访问
}
/**
* 该方法将在Controller执行之后,返回视图之前执行,ModelMap表示请求Controller处理之后返回的Model对象,所以可以在这个方法中修改ModelMap的属性,从而达到改变返回的模型的效果。
*/
@Override
public void postHandle(WebRequest request, ModelMap map) throws Exception {
// TODO Auto-generated method stub
for (String key:map.keySet())
System.out.println(key + "-------------------------");;
map.put("name3", "value3");
map.put("name1", "name1");
}
/**
* 该方法将在整个请求完成之后,也就是说在视图渲染之后进行调用,主要用于进行一些资源的释放
*/
@Override
public void afterCompletion(WebRequest request, Exception exception)
throws Exception {
// TODO Auto-generated method stub
System.out.println(exception + "-=-=--=--=-=-=-=-=-=-=-=-==-=--=-=-=-=");
}
}
Xml代码 :
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation=" http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"
下面是我的声明示例:
xml代码 :
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
这样在SpringMVC的配置文件中就可以使用mvc标签了,mvc标签中有一个mvc:interceptors是用于声明SpringMVC的拦截器的。
Xml代码 :
<mvc:interceptors>
<bean class="com.host.app.web.interceptor.AllInterceptor"/>
<mvc:interceptor>
<mvc:mapping path="/test/number.do"/>
<bean class="com.host.app.web.interceptor.LoginInterceptor"/>
mvc:interceptor>
mvc:interceptors>
由上面的示例可以看出可以利用mvc:interceptors标签声明一系列的拦截器,然后它们就可以形成一个拦截器链,拦截器的执行顺序是按声明的先后顺序执行的,先声明的拦截器中的preHandle方法会先执行,然而它的postHandle方法和afterCompletion方法却会后执行。
在mvc:interceptors标签下声明interceptor主要有两种方式:
直接定义一个Interceptor实现类的bean对象。使用这种方式声明的Interceptor拦截器将会对所有的请求进行拦截。
使用mvc:interceptor标签进行声明。使用这种方式进行声明的Interceptor可以通过mvc:mapping子标签来定义需要进行拦截的请求路径。
经过上述两步之后,定义的拦截器就会发生作用对特定的请求进行拦截了。
mvc:interceptor定义需要拦截的请求路径:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.AL.config.MyInterceptor"/>
mvc:interceptor>
mvc:interceptors>
在上传文件的时候,前端的表单 method设置为POST,并且需要对 enctype属性设置文件上传时的数据编码形式。
文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。
前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;
对表单中的 enctype 属性做个详细的说明:
<form action="" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit">
form>
一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。
MultipartResolver实现类去完成文件上传。
1、导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;pom.xml
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.3version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
dependency>
2、配置bean:multipartResolver
【注意!!!这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误】
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"/>
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
bean>
CommonsMultipartFile 的 常用方法:
web.xml配置文件:web开发的支持条件,注册DispatchServlet,启动顺序设置:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
applicationContext.xml配置文件:servlet的配置,其实就是DispatchServlet还有视图解析器、处理器 Bean 容器的注册等:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:mvv="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.AL.controller"/>
<mvv:default-servlet-handler/>
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
bean>
property>
bean>
mvc:message-converters>
mvc:annotation-driven>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"/>
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
bean>
beans>
我们去实际测试一下:
3、编写前端页面
<form action="/upload" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit" value="upload">
form>
4、Controller
创建一个控制器 controller,得到用户请求后,调度servlet:
在这里,将 上传的文件去封装到 CommonsMultipartFile 对象中,CommonsMultipartFile 的 常用方法:
package com.AL.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@Controller
public class FileController {
//@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
//批量上传CommonsMultipartFile则为数组即可
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
//获取文件名 : file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();
//如果文件名为空,直接回到首页!
if ("".equals(uploadFileName)){
return "redirect:/index.jsp";
}
System.out.println("上传文件名 : "+uploadFileName);
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
//如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
System.out.println("上传文件保存地址:"+realPath);
InputStream is = file.getInputStream(); //文件输入流
OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流
//读取写出
int len=0;
byte[] buffer = new byte[1024];
while ((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
os.flush();
}
os.close(); //从后往前进行关闭
is.close();
return "redirect:/index.jsp";
}
}
5、测试上传文件。注意导入 jar包。
后台输出:
上传文件名 : 朴信惠.jpg
上传文件保存地址:E:\Java_work\Learning_code\SpringMVC\out\artifacts\springmvc_08_file_war_exploded\upload
采用file.Transto 来保存上传的文件
1、编写Controller
/*
* 采用file.Transto 来保存上传的文件
*/
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
//上传文件地址
System.out.println("上传文件保存地址:"+realPath);
//通过CommonsMultipartFile的方法直接写文件(注意这个时候)
file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
return "redirect:/index.jsp";
}
2、前端表单提交地址修改
3、访问提交测试,OK!
文件下载步骤:
1、设置 response 响应头
2、读取文件 – InputStream
3、写出文件 – OutputStream
4、执行操作
5、关闭流 (先开后关)
代码实现:
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
//要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "朴信惠.jpg";
//1、设置response 响应头
response.reset(); //设置页面不缓存,清空buffer
response.setCharacterEncoding("UTF-8"); //字符编码
response.setContentType("multipart/form-data"); //二进制传输数据
//设置响应头
response.setHeader("Content-Disposition",
"attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path,fileName);
//2、 读取文件--输入流
InputStream input=new FileInputStream(file);
//3、 写出文件--输出流
OutputStream out = response.getOutputStream();
byte[] buff =new byte[1024];
int index=0;
//4、执行 写出操作
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
前端:
点击下载
测试,下载成功。
web应用程序编写完毕后, 如果想要提供给外界访问:就需要一个服务器来统一管理;
简单来说:web应用程序分为静态和动态的web,还需要URL即网络地址,存放东西的地方;配置文件和jar包用来实现连接的,这些和外部的连接 进行访问,就需要一个服务器:Tomcat。 我们需要把自己开发出来的Web程序放在我们服务器的webapps目录下。
javaWeb:java中用于开发动态web的就称为 javaweb。
完成一个Servlet。Servlet是用来创建动态web的技术。开发一个Servlet程序,需要两个步骤:
Servlet是由Web服务器调用, web服务器在收到了浏览器的请求之后,就会去寻找 请求和响应,即Request和Response,在这里调用的就是 Servlet中的方法(我们做的就是就这个 servlet程序, 它是发布在了 web容器中)。然后去进行响应给客户端东西 数据信息。【Tomcat首次访问Servlet会调用 init()方法 】
Servlet/Tomcat/ Spring 之间的关系: https://www.cnblogs.com/shawshawwan/p/9002126.html
关于 Servlet的知识:
客户端的请求直接打到tomcat,它监听端口,HTTP请求过来后,根据url等信息,确定要将请求交给哪个servlet去处理,然后调用那个servlet的service方法,service方法返回一个response对象,tomcat再把这个response返回给客户端。【init() 方法只会在Tomcat第一次调用Servlet初始化的时候使用;只要访问servlet就会使用 service() 方法;只有在Tomcat关闭的时候才去调用 destory()方法销毁servlet】
Tomcat和jettey是HTTP服务器和Servlet容器,负责给类似Spring这种servlet提供一个运行的环境,其中:Http服务器与Servlet容器的功能界限是:可以把HTTP服务器想象成前台的接待,负责网络通信和解析请求,Servlet容器是业务部门,负责处理业务请求。
Tomcat和Servlet作为Web服务器和Servlet容器的结合,可以接受网络http请求解析为Servlet规范的请求对象和响应对象。比如,HttpServletRequest对象是Tomcat提供的,Servlet是规范,Tomcat是实现规范的Servlet容器,SpringMVC是处理Servlet请求的应用,其中**DispatcherServlet实现了Servlet接口**,Tomcat负责加载和调用DispatcherServlet。同时,DispatcherServlet有自己的容器==(SpringMVC)容器==,这个容器负责管理SpringMVC相关的bean,比如Controler和ViewResolver等。同时,Spring中还有其他的Bean比如Service和DAO等,这些由全局的Spring IOC容器管理,因此,Spring有两个IOC容器。
Spring和Tomcat之间的关系:
如果只是使用spring(不包含springmvc),那么是tomcat容器解析xml文件,通过反射实例化对应的类,根据这些servlet 接口实现类,触发对应的代码处理逻辑,这个时候tomcat负责http报文的解析和servlet调度的工作。
如果使用spring mvc,那么tomcat只是解析http报文,然后将其转发给dispatchsetvlet,然后由springmvc根据其配置,实例对应的类,执行对应的逻辑,然后返回结果给dispatchservlet,最后由它转发给tomcat,由tomcat负责构建http报文数据。
Spring MVC和Tomcat之间的关系:
在servlet初始化(调用init()方法)的时候,Spring MVC会根据配置文件获取配置信息,得到统一资源标识符URI 和处理器Handler之间的映射关系(HandlerMapping)。 所以当一个Request请求时,Tomcat去解析报文,交给DispatchServlet,会根据初始化解析得到的 HandlerMapping配置,找到对应的处理器Handler;而由于处理器运行需要一个对应的环境,所以就有一个处理器的适配器 HandlerAdapter。
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
web-app>
web.xml配置文件中绑定的 applicationContext.xml 文件信息,
里面注册了 适配器、执行器、视图解析器,
MVC框架会存储Servlet和Controller之间的映射关系:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:mvv="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.AL.controller"/>
<mvv:default-servlet-handler/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.AL.config.MyInterceptor"/>
mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="user/**"/>
<bean class="com.AL.config.LoginInterceptor"/>
mvc:interceptor>
mvc:interceptors>
beans>
,可以接受网络http请求解析为Servlet规范的请求对象和响应对象。比如,HttpServletRequest对象是Tomcat提供的,Servlet是规范,Tomcat是实现规范的Servlet容器,SpringMVC是处理Servlet请求的应用,其中**DispatcherServlet实现了Servlet接口**,Tomcat负责加载和调用DispatcherServlet。同时,DispatcherServlet有自己的容器==(SpringMVC)容器==,这个容器负责管理SpringMVC相关的bean,比如Controler和ViewResolver等。同时,Spring中还有其他的Bean比如Service和DAO等,这些由全局的Spring IOC容器管理,因此,Spring有两个IOC容器。
Spring和Tomcat之间的关系:
如果只是使用spring(不包含springmvc),那么是tomcat容器解析xml文件,通过反射实例化对应的类,根据这些servlet 接口实现类,触发对应的代码处理逻辑,这个时候tomcat负责http报文的解析和servlet调度的工作。
如果使用spring mvc,那么tomcat只是解析http报文,然后将其转发给dispatchsetvlet,然后由springmvc根据其配置,实例对应的类,执行对应的逻辑,然后返回结果给dispatchservlet,最后由它转发给tomcat,由tomcat负责构建http报文数据。
Spring MVC和Tomcat之间的关系:
在servlet初始化(调用init()方法)的时候,Spring MVC会根据配置文件获取配置信息,得到统一资源标识符URI 和处理器Handler之间的映射关系(HandlerMapping)。 所以当一个Request请求时,Tomcat去解析报文,交给DispatchServlet,会根据初始化解析得到的 HandlerMapping配置,找到对应的处理器Handler;而由于处理器运行需要一个对应的环境,所以就有一个处理器的适配器 HandlerAdapter。
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
web-app>
web.xml配置文件中绑定的 applicationContext.xml 文件信息,
里面注册了 适配器、执行器、视图解析器,
MVC框架会存储Servlet和Controller之间的映射关系:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:mvv="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.AL.controller"/>
<mvv:default-servlet-handler/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.AL.config.MyInterceptor"/>
mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="user/**"/>
<bean class="com.AL.config.LoginInterceptor"/>
mvc:interceptor>
mvc:interceptors>
beans>