Java-SpringMVC

学习视频: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的执行流程

1、回顾MVC

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时代

  • 在web早期的开发中,通常使用的是 Model1
  • Model1中,分为两层:视图层 和 模型层。 它没有控制层去进行调度

Model1的优缺点:

  • 优点:结构简单,适用于小型项目开发
  • 缺点:JSP的职责复杂,不利于维护

Model2时代

  1. 用户发请求
  2. Servlet接收请求数据,并调用对应的业务逻辑方法【DispatcherServlet 调度员进行调度】
  3. 业务处理完毕,返回更新后的数据给servlet
  4. servlet转向到JSP,由JSP来渲染页面
  5. 响应给前端更新后的页面

Model2这样不仅提高的代码的复用率与项目的扩展性,且大大降低了项目的维护成本。Model 1模式的实现比较简单,适用于快速开发小规模项目,Model1中JSP页面身兼View和Controller两种角色,将控制逻辑和表现逻辑混杂在一起,从而导致代码的重用性非常低,增加了应用的扩展性和维护的难度。Model2消除了Model1的缺点。

我们建立一个简单的Maven项目, 去理解一下 Model2 时代的一个工作流程。

创建一个Maven项目, 为SpringMVC。删除src文件,使其成为父项目

1.导入maven依赖:

    <!--maven依赖--><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.5</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version></dependency><dependency><groupId>javax.servlet.jsp.jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency></dependencies>

2.建立一个Moudle:springmvc-01-servlet , 添加Web app的支持! 在这里,创建一个空的maven项目, 然后选择 addframwork,选择web,并可以选择版本,可以更加方便,减少成本。

3。导入servlet和jsp的 jar依赖

    <dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version></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 {@Overrideprotected 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);}@Overrideprotected 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" %>
<html>
<head><title>Title</title>
</head>
<body>${msg}</body>
</html>

6、在web.xml中注册Servlet。

<?xml version="1.0" encoding="UTF-8"?>
<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>hello</servlet-name><servlet-class>com.AL.Servlet.HelloServlet</servlet-class></servlet><servlet-mapping><servlet-name>hello</servlet-name><url-pattern>/hello</url-pattern></servlet-mapping>
</web-app>

7、配置Tomcat,并启动测试,这两种方法为:

  • localhost:8080/hello?method=add【?表示参数占位符】
  • localhost:8080/hello?method=delete

结果分别为:在浏览器页面显示的结果分别如下所示。

执行了add方法
执行了delete方法

分析这一个maven项目的流程吧

  1. 用户去发送请求。即在这个页面输入了方法:localhost:8080/hello?method=add
  2. Servlet接收到了这个请求。对应的在web.xml中的url 路径接收到了用户的请求,即/hello?method=add。在这个Servlet中,它映射的是对应的业务逻辑方法是com.AL.Servlet.HelloServlet;所以会去调用 HelloServlet这个业务。【Tomcat里面注册 然后解析url 寻找servlet】
  3. HelloServlet类被调用了,即去处理用户的请求。 那么就需要获取前端的参数,然后进行调用处理业务层;再把结果 转发或者 重定向。
  4. HelloServlet 这个servlet将 跳转到 JSP,此时是转到 test.jsp,根据这个获取的 msg进行输出
  5. 响应给前端更新的页面,进行 View。

职责分析:

Controller:控制器,servlet所做的工作:

  1. 取得表单数据
  2. 调用业务逻辑
  3. 转向指定的页面

Model:模型

  1. 业务逻辑
  2. 更新保存数据的状态

View:视图

  1. 显示页面

MVC框架要做的事情

  1. 将url映射到 java类 或java类的方法【MVC框架 注解开发配置 url,tomcat服务器注册servlet
  2. 封装用户提交的数据
  3. 处理请求 - 调用相关的业务处理 - 封装响应数据
  4. 将响应的数据进行渲染, jsp/html等表示层的数据

说明:

  • 常见的服务器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;

  • 常见前端MVC框架:vue、angularjs、react、backbone;

  • 由MVC演化出了另外一些模式如:MVP、MVVM 等等…

2、初识SpringMVC

2.1、SpringMVC的原理

我们学习的 SpringMVC 所具有的特点:

  1. 轻量级,简单易学
  2. 高效 , 基于请求响应的MVC框架
  3. 与Spring兼容性好,无缝结合
  4. 约定优于配置
  5. 功能强大:RESTful、数据验证、格式化、本地化、主题等
  6. 简洁灵活

Spring的web框架围绕着 DispatcherServlet 去进行调度 servlet 设计。**DispatcherServlet**的作用就是将请求分发到不同的处理器。

SpringMVC的工作流程如下图所示:

在用户进行请求时,发送的请求会被前置的控制器拦截,根据拦截到的请求参数生成代理请求, 去找到对应的 实际控制器; 控制器处理请求,此时创建数据库,访问数据库; 然后将处理得到的模型数据返回给控制器; 控制器将利用 模型和视图(ModelAndView) 渲染视图结果;将结果返回给中心控制器,再将结果返回给请求者。

2.2、创建一个HelloSpring MVC程序

  1. 在web.xml配置文件中注册 DispatcherServlet。这个调度员会根据request请求去调度 servlet执行

    <?xml version="1.0" encoding="UTF-8"?>
    <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"><!--1.注册servlet--><servlet><servlet-name>springMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--通过初始化参数指定SpringMVC配置文件的位置,进行关联--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><!--启动顺序,数字越小,启动越早   1表示和服务器一起启动--><load-on-startup>1</load-on-startup></servlet><!--所有的请求都会被SpringMVC拦截--><servlet-mapping><servlet-name>springMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
    </web-app>
    
  2. 在这个 dispatcherServlet中:

    • 注册我们的 controller容器bean即执行器 handler;
    • 处理映射器HandlerMapping。将不同的servlet程序进行类似于map 散列表存储,dispatcherServlet会根据request在mapping中选择正确的 servlet程序
    • 处理器适配器HandlerAdapter:在mvc中会有各种各样的执行器 controller。针对不同的Controller选择合适的处理器执行器。
    • 视图解析器,进行页面渲染 返回给客户端
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--添加处理映射器。 这个是将 servlet存储为散列表,便于 dispatcherServlet对servlet请求进行寻找controller--><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    <!--    &lt;!&ndash;添加处理器适配器。 针对不用的controller 采用不同方式解决,适配器模式&ndash;&gt;--><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><!--Handler。 还需要将自己的类交给 SpringIOC客户端,注册bean, 就是注册 controller--><bean id="/hello" class="com.AL.controller.HelloController"/>
    </beans>
    
  3. 编写我们的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中。Modelmv.addObject("msg","HelloSpringMVC!");//封装要跳转的视图,放在ModelAndView中mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jspreturn mv;}
    }
    
  4. 定义视图。将执行的结果封装在 ModelAndView 中,由其进行渲染。

    • 由前面的控制器 Controller可以发现执行结果会封装在 ModelAndView中,
    • 然后去由ViewResolver 会根据逻辑 View 查找实际的 View视图
    • 再将Model 对象传递给 View。完成视图渲染,将view返回给浏览器
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head><title>Title</title>
    </head>
    <body>
    ${msg}
    </body>
    </html>
    
  5. 测试:更改Tomcat配置,http://localhost:8080/hello

  6. 错误排查:进行测试,发现无法进行跳转。新建lib文件夹,然后将 jar包都导入。

    1. 查看控制台输出,看一下是不是缺少了什么jar包。
    2. 如果jar包存在,显示无法输出,就在IDEA的项目发布中,添加lib依赖!
    3. 重启Tomcat 即可解决!

2.3、SpringMVC执行原理

Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。

Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)

SpringMVC执行原理

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 等等都是框架提供给我们的,不需要自己手动开发。

简要分析执行流程

  1. DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
    我们假设请求的url为 : http://localhost:8080/SpringMVC/hello
    如上url拆分成三部分: http://localhost:8080服务器域名
    SpringMVC部署在服务器上的web站点
    hello表示控制器
    通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。
  2. HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
  3. HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。
  4. HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
  5. HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
  6. Handler让具体的Controller执行。
  7. Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView
  8. HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
  9. DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
  10. 视图解析器将解析的逻辑视图名传给DispatcherServlet。
  11. DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。

收到请求,先要去寻找映射器; 返回给 后面找到 url适配器,跳转相应的页面。

我们做的就两个:controller调用业务层,视图层的调用显示

2.4、使用注解开发

创建一个HelloSpring项目:Springmvc-02-hellomvc

  • 注册 web.xml文件: 同样是在注册servlet,不过没有像原来一样,直接就自己 注册 映射具体的地址。

    在这里 用户的请求,即输入的 url 被 servlet-mapping映射文件 SpringMVC拦截, 拦截到定义的 SpringMVC 配置文件的位置, 即classpath:springmvc-servlet【 web.xml 配置文件中注册 DispatcherServlet】

<?xml version="1.0" encoding="UTF-8"?>
<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"><!--1.注册servlet--><servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--通过初始化参数指定SpringMVC配置文件的位置,进行关联--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet</param-value></init-param><!--启动顺序,数字越小,启动越早   1表示和服务器一起启动--><load-on-startup>1</load-on-startup></servlet><!--所有的请求都会被SpringMVC拦截--><servlet-mapping><servlet-name>SpringMVC</servlet-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错。

    • 注意web.xml版本问题,要最新版!
    • 注册DispatcherServlet
    • 关联SpringMVC的配置文件
    • 启动级别为1
    • 映射路径为 / 【不要用/*,会404】
  • 注册 springmvc-servlet.xml配置文件。在这里面,由web.xml中的springmvc跳转到这个 springmvc的配置文件中, 且由这个配置文件去调用 包里面的 bean,即com.AL.controller 对应的代码。从这个代码返回的信息,即跳转的页面,由视图解析器 自动拼接成一个完成的 .jsp 地址,完成跳转。
<?xml version="1.0" encoding="UTF-8"?>
<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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 --><context:component-scan base-package="com.AL.controller"/><!-- 让Spring MVC不处理静态资源 --><mvc:default-servlet-handler /><!--支持mvc注解驱动在spring中一般采用@RequestMapping注解来完成映射关系要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例这两个实例分别在类级别和方法级别处理。而annotation-driven配置帮助我们自动完成上述两个实例的注入。--><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>
  1. 在视图解析器中我们把所有的视图都存放在/WEB-INF/目录下,这样可以保证视图安全,因为这个目录下的文件,客户端不能直接访问。

    • 让IOC的注解生效
    • 静态资源过滤 :HTML . JS . CSS . 图片 , 视频 …
    • MVC的注解驱动
    • 配置视图解析器

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.jspreturn "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.jspreturn "hello";}
}
  • @Controller是为了让Spring IOC容器初始化时自动扫描到;【注册bean容器,处理器Controller】
  • @RequestMapping是为了映射请求路径,这里因为类与方法上都有映射所以访问时应该是/HelloController/hello;【映射器功能】
  • 方法中声明Model类型的参数是为了把Action中的数据带到视图中;
  • 方法返回的结果是视图的名称hello,加上配置文件中的前后缀变成WEB-INF/jsp/hello.jsp。【xml配置中的视图解析器去做这件事】

视图层:跳转的页面 hello 和页面的视图信息:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body>
${msg}
</body>
</html>

测试:http://localhost:8080/hello

小结

实现步骤其实非常的简单:

  1. 新建一个web项目
  2. 导入相关jar包
  3. 编写web.xml, 注册DispatcherServlet
  4. 编写springmvc配置文件
  5. 接下来就是去创建对应的控制类, controller
  6. 最后完善前端视图和controller之间的对应
  7. 测试运行调试.

使用springMVC必须配置的三大件:处理器映射器、处理器适配器、视图解析器

通常,我们只需要==手动配置视图解析器,而处理器映射器处理器适配器只需要开启注解驱动即可==,而省去了大段的xml配置

  • 注解开发和 原来xml配置之间的 Controller 之间的区别:
// 注解
@Controller
public class HelloController {//真实访问地址 : 项目名/hello@RequestMapping("/hello")public String hello(Model model){//封装数据model.addAttribute("msg","Hello,SpringMVCAnnotation!");// web-inf/jsp/hello.jspreturn "hello"; // 会被视图解析器处理}
}// 原xml配置.    注意:这里我们先导入Controller接口
public class HelloController implements Controller {public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {//ModelAndView 模型和视图ModelAndView mv = new ModelAndView();//封装对象,放在ModelAndView中。Modelmv.addObject("msg","HelloSpringMVC!");//封装要跳转的视图,放在ModelAndView中mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jspreturn mv;}
}
  • 对应的dispatcherServlet配置文件 springmvc-servlet.xml中的配置区别: 注解开发时只需定义视图解析器
    <!--添加处理映射器。 这个是将 servlet存储为散列表,便于 dispatcherServlet对servlet请求进行寻找controller--><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--    &lt;!&ndash;添加处理器适配器。 针对不用的controller 采用不同方式解决,适配器模式&ndash;&gt;--><bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/><!--Handler。 还需要将自己的类交给 SpringIOC客户端,注册bean, 就是注册 controller--><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 等等都是框架提供给我们的,不需要自己手动开发。【提高开发效率】

3、Controller配置总结

控制器Controller

  • 控制器复杂提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。
  • 控制器负责解析用户的请求并将其转换为一个模型。
  • 在Spring MVC中一个控制器类可以包含多个方法
  • 在Spring MVC中,对于Controller的配置方式有很多种

控制器Controller:在xml配置开发的时候,使用了 Controller 接口定义实现,注解开发时使用了 @Controller注解定义实现。

Controller接口:

Controller是一个接口,在org.springframework.web.servlet.mvc包下,接口中只有一个方法;

//实现该接口的类获得控制器功能
public interface Controller {//处理请求且返回一个模型与视图对象ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}

3.1、Controller接口定义实现类

创建一个 maven项目, springmvc-04-controller:

  1. 配置web.xml文件,注册DispatcherServlet :

    <?xml version="1.0" encoding="UTF-8"?>
    <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"><!--1.注册servlet--><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--通过初始化参数指定SpringMVC配置文件的位置,进行关联--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><!--所有的请求都会被SpringMVC拦截--><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
    </web-app>
    
  2. springmvc-servlet.xml配置文件:定义dispatcherServlet

<?xml version="1.0" encoding="UTF-8"?>
<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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 --><context:component-scan base-package="com.AL.controller"/><!-- 让Spring MVC不处理静态资源 --><mvc:default-servlet-handler /><!--支持mvc注解驱动在spring中一般采用@RequestMapping注解来完成映射关系要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例这两个实例分别在类级别和方法级别处理。而annotation-driven配置帮助我们自动完成上述两个实例的注入。--><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>
  1. 实现Controller控制器:

    1. 第一种方法:接口定义,实现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"/>
      
    2. 第二种方法:注解定义开发

  2. 前端test.jsp界面:注意在WEB-INF/jsp目录下编写,对应我们的视图解析器:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head><title>ALZN</title>
    </head>
    <body>
    ${msg}
    </body>
    </html>
    
  3. 测试:配置Tomcat运行测试,http://localhost:8080/t1

说明:

  • 实现接口Controller定义控制器是较老的办法
  • 缺点是:一个控制器中只有一个方法,如果要多个方法则需要定义多个Controller;定义的方式比较麻烦;

3.2、使用Controller注解开发

注解:注解的这些关键字,组件有:

  • @Component 组件
  • @Service service层
  • @Controller controller层
  • @Repository dao层

注解开发:

  • @Controller注解类型用于声明Spring类的实例是一个控制器
  • Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。

注解开发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";}
}

指定扫描路径,扫描配置文件:

    <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 --><context:component-scan base-package="com.AL.controller"/>
支持mvc注解驱动
<mvc:annotation-driven />

测试:重启Tomcat,http://localhost:8080/t2

可以发现,我们的两个请求都可以指向一个视图,但是页面结果的结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱偶合关系

3.3、RequestMapping说明

@RequestMapping

  • @RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

创建的 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这个路径,会发生什么?

发生异常错误。

我们修改想要跳转页面的路径

  • 在WEB-INF下的JSP,创建一个admin 文件夹, 原来拼接的是 jsp下面的文件, 这时我们在controller下 添加或者重新修改跳转名称即可。

修改:

@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。

不过建议 一般在方法上面进行注解

4、Resful风格

4.1、Restful风格

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=2int 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";}

这里的测试显示错误405:

这是因为:映射访问路径,必须是Get请求

解决思路:

我们可以定义一个a.jsp,通过 submit方式进行提交:通过表单的方式去获取

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>ALZN-Restful-Method</title>
</head>
<body><form action="/add/10/30" method="post"><input type="submit"></form>
</body>
</html>

结果: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类型

4.2、restful风格的优势

思考:使用路径变量的好处

  • 使路径变得更加简洁;
  • 获得参数更加方便,框架会自动进行类型转换
  • 通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法,如这里访问是的路径是/commit/1/a,则路径与方法不匹配,而不会是参数转换失败。

4.3、@RequestMapping 注解介绍

@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 {};
}

4.4、重定向和转发

ModelAndView

设置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的方法进行重定向、转发

通过设置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

通过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为另一个请求/}}

4.4、数据处理

数据处理

处理提交数据

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.将返回的结果给前端 modelmodel.addAttribute("msg", name);return "test";}// 当前端的参数名和控制器中的方法名参数不一样时, 即域名和方法的参数名不一样时:@RequestMapping("/t2")public String test2(@RequestParam("username") String name, Model model){// 1.接收前端参数System.out.println("前端传过来的参数为:->"+ name);// 2.将返回的结果给前端 modelmodel.addAttribute("msg", name);return "test";}// 当前端给的是一个对象时@RequestMapping("/t3")public String test3(User user){System.out.println(user);return "test";}
}
  • 接收前端的参数并返回给前端这个数据:http://localhost:8080/user/t1?name=pipi

  • 域名和方法的参数名不一样时:使用 @RequestParam()注解去自定义域名中的参数名。

http://localhost:8080/user/t2?username=%E5%B0%BC%E7%8E%9B

  • 当传递的是一个对象时:在java中将多个参数定义为一个对象中的属性,去获取这多个数据。

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";}

4.5、过滤器

乱码问题:

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方法,进行提交数据。

<form action="/e/t" method="POST"><input type="text" name="name"><input type="submit">
</form>

encodeTest.jsp页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body>
${msg}
</body>
</html>

测试:

在首页的表单中输入文本:

DispatchServlet 会调用HandlerMapping 找到Handler,适配器调用servlet程序运行。 http://localhost:8080/e/t 调用url路径对应的方法,执行结果:

假如输入中文: 出现了乱码。

以前乱码问题通过过滤器解决 , 而SpringMVC给我们提供了一个过滤器 , 可以在web.xml中配置 .

修改了xml文件之后重启服务器进行测试,发现结果ok,没有出现乱码。

<filter><filter-name>encoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param>
</filter>
<filter-mapping><filter-name>encoding</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

5、Json

5.1、Json简介

前后端分离时代:

  • 后端部署后端,提供接口,提供数据:

    Json

  • 前端独立部署,负责渲染后端的数据

什么是JSON?

  • JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别广泛。
  • 采用完全独立于编程语言的文本格式来存储和表示数据。
  • 简洁和清晰的层次结构使得 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文件运行结果]

5.2、Jackson使用

Controller返回JSON数据

Jackson应该是目前比较好的json解析工具了

当然工具不止这一个,比如还有阿里巴巴的 fastjson 等等。

  • 我们这里使用Jackson,使用它需要导入它的jar包:pom.xml配置文件导入依赖
    <dependencies><!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.8</version></dependency></dependencies>
  • 配置SpringMVC需要的配置

    web.xml中注册 DispatcherServlet 前端控制器:

    <?xml version="1.0" encoding="UTF-8"?>
    <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"><!--1.注册servlet--><servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--通过初始化参数指定SpringMVC配置文件的位置,进行关联--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><!-- 启动顺序,数字越小,启动越早 --><load-on-startup>1</load-on-startup></servlet><!--所有请求都会被springmvc拦截 --><servlet-mapping><servlet-name>SpringMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping><filter><filter-name>encoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encoding</filter-name><url-pattern>/</url-pattern></filter-mapping></web-app>
    
  • 定义 DispatcherServlet 的配置文件:springmvc-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --><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的实体类,然后我们去编写我们的测试Controller:

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;
}

@Controlller + @ResponseBody

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转换格式:

<!--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:@ResponseBody 和 ObjectMapper对象

采用 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")@ResponseBodypublic 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测试的结果:

  • 前端输出一个 时间对象: 结果默认显示的是时间戳,即1976年到现在的毫秒数
    @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;}

结果:

  • 默认日期格式会变成一个数字,是1970年1月1日到当前日期的毫秒数!

  • Jackson 默认是会把时间转成timestamps形式

  • 取消Timestamps格式,自定义时间转换

    @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、@RestController之间的关系:

  • 单独使⽤ @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

6、Ajax

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信息:

<?xml version="1.0" encoding="UTF-8"?>
<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"><!--1.注册servlet--><servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--通过初始化参数指定SpringMVC配置文件的位置,进行关联--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicatinContext.xml</param-value></init-param><!-- 启动顺序,数字越小,启动越早 --><load-on-startup>1</load-on-startup></servlet><!--所有请求都会被springmvc拦截 --><servlet-mapping><servlet-name>SpringMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping><filter><filter-name>encoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encoding</filter-name><url-pattern>/*</url-pattern></filter-mapping>
</web-app>

2、在资源配置文件中进行注解驱动,注解类的包扫描,视图解析器:

<?xml version="1.0" encoding="UTF-8"?>
<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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --><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可以做:

  • 注册时,输入用户名自动检测用户是否已经存在。
  • 登陆时,提示用户名密码错误
  • 删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行也删除。
  • …等等

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:请求方式,GETPOST1.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" %>
    <html>
    <head><title>$Title$</title><%--<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>--%><script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script><script>function a1(){$.post({url:"${pageContext.request.contextPath}/a1",data:{'name':$("#txtName").val()},success:function (data,status) {alert(data);alert(status);}});}</script>
    </head>
    <body><%--onblur:失去焦点触发事件--%>
    用户名:<input type="text" id="txtName" οnblur="a1()"/></body>
    </html>
    
  • 跳转页面的信息修改, 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所做的事情:

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" %>
<html>
<head><title>Title</title>
</head>
<body>
<input type="button" id="btn" value="获取数据"/>
<table width="80%" align="center"><tr><td>姓名</td><td>年龄</td><td>性别</td></tr><tbody id="content"></tbody>
</table><script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script>
<script>$(function () {$("#btn").click(function () {$.post("${pageContext.request.contextPath}/a2",function (data) {console.log(data)var html="";for (var i = 0; i <data.length ; i++) {html+= "<tr>" +"<td>" + data[i].name + "</td>" +"<td>" + data[i].age + "</td>" +"<td>" + data[i].sex + "</td>" +"</tr>"}$("#content").html(html);});})})
</script>
</body>
</html>

启动,运行测试:

Ajax验证用户名体验

注册提示效果

我们再测试一个小Demo,思考一下我们平时注册时候,输入框后面的实时提示怎么做到的;如何优化。

例子:

  • 我们写一个Controller:
    @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格式返回}
  • 前端页面 login.jsp:利用Ajax去获取请求
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>ajax</title><script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script><script>function a1(){$.post({url:"${pageContext.request.contextPath}/a3",data:{'name':$("#name").val()},success:function (data) {if (data.toString()=='OK'){$("#userInfo").css("color","green");}else {$("#userInfo").css("color","red");}$("#userInfo").html(data);}});}function a2(){$.post({url:"${pageContext.request.contextPath}/a3",data:{'pwd':$("#pwd").val()},success:function (data) {if (data.toString()=='OK'){$("#pwdInfo").css("color","green");}else {$("#pwdInfo").css("color","red");}$("#pwdInfo").html(data);}});}</script>
</head>
<body>
<p>用户名:<input type="text" id="name" οnblur="a1()"/><span id="userInfo"></span>
</p>
<p>密码:<input type="text" id="pwd" οnblur="a2()"/><span id="pwdInfo"></span>
</p>
</body>
</html>

启动测试:发现出现了乱码的问题。

解决:

  • 在applicationContext.xml配置文件中加入解决 json 乱码配置问题:
<?xml version="1.0" encoding="UTF-8"?>
<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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --><context:component-scan base-package="com.AL.controller"/><!--注解驱动--><mvc:annotation-driven/><!--静态资源过滤--><mvv:default-servlet-handler/><!--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><!-- 视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"id="internalResourceViewResolver"><!-- 前缀 --><property name="prefix" value="/WEB-INF/jsp/" /><!-- 后缀 --><property name="suffix" value=".jsp" /></bean></beans>

7、拦截器

拦截器

概述

SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。

过滤器与拦截器的区别:拦截器是AOP思想的具体应用。即横向,面向切面的,不会影响代码。

过滤器

  • servlet规范中的一部分,任何java web工程都可以使用
  • 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截

拦截器

  • 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
  • 拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的

实现拦截器有两种方法:

  • 一种是实现 HandlerInterceptor 接口;

  • 另外一种是**继承适配器类[继承实现了WebRequestInterceptor接口]**,接着在接口方法当中,实现处理逻辑,然后在 SpringMVC 的配置文件中配置拦截器即可。

创建一个Maven项目,先测试能否正常启动: 查看Spring是否配置成功了。

  • 资源配置文件 applicationContext.xml、控制器controller、web.xml核心配置文件
  1. 控制器 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";}
    }
    
  2. 资源配置文件applicationContext.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --><context:component-scan base-package="com.AL.controller"/><!--静态资源过滤--><mvv:default-servlet-handler/><!--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><!-- 视图解析器 --><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. web.xml核心配置文件, 注册映射servlet,过滤器。绑定DispatcherServlet 配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <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"><!--1.注册servlet--><servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--通过初始化参数指定SpringMVC配置文件的位置,进行关联--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicatinContext.xml</param-value></init-param><!-- 启动顺序,数字越小,启动越早 --><load-on-startup>1</load-on-startup></servlet><!--所有请求都会被springmvc拦截 --><servlet-mapping><servlet-name>SpringMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping><filter><filter-name>encoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encoding</filter-name><url-pattern>/</url-pattern></filter-mapping>
    </web-app>
    
  4. 测试的前端页面:即默认页面,然后请求 url路径。

后台输出:TestController执行了-》test()方法

搭建的 spring项目没有问题。

7.1、自定义拦截器

那如何实现拦截器呢?

想要自定义拦截器,必须实现 HandlerInterceptor 接口

1、新建一个Moudule , springmvc-07-Interceptor , 添加web支持

2、配置web.xml 和 springmvc-servlet.xml 文件

3、编写一个拦截器

  • 这里创建的 config 拦截器的部分, 选择重写方法:
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("------------清理------------");}
}
  • 创建拦截器配置:注册拦截器配置文件信息,在application.xml配置文件中绑定
    <!--关于拦截器的配置--><mvc:interceptors><mvc:interceptor><!--/** 包括路径及其子路径--><!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截--><!--/admin/** 拦截的是/admin/下的所有--><mvc:mapping path="/**"/><!--bean配置的就是拦截器--><bean class="com.AL.config.MyInterceptor"/></mvc:interceptor></mvc:interceptors>
  • 编写一个Controller,接收请求
    @RequestMapping("/interceptor") // 测试拦截器public String testFunction() {System.out.println("控制器中的方法执行了");return "hello";}
  • 前端界面 index.jsp中去定义:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html><head><title>$Title$</title></head><body><a href="${pageContext.request.contextPath}/interceptor">拦截器测试</a></body>
</html>

运行Tomcat进行测试:http://localhost:8080/

  • 拦截器测试绑定了 /interceptor 这个路径

  • 点击后,跳转请求

且此时后台输出:

------------处理前------------
控制器中的方法执行了
------------处理后------------
------------清理------------

接口HandlerInterceptor中的方法:

  • preHandle:在请求处理的方法之前执行;如果返回true执行下一个拦截器,如果返回false就不执行下一个拦截器
  • postHandle:在请求处理方法执行之后执行
  • afterCompletion:在dispatcherServlet处理后执行,做清理工作.

7.2、登录判断认证

验证用户是否登录 (认证用户)

实现思路

1、有一个登陆页面,需要写一个controller访问页面。

2、登陆页面有一提交表单的动作。需要在controller中处理。判断用户名密码是否正确。如果正确,向session中写入用户信息。返回登陆成功。

3、拦截用户请求,判断用户是否登陆。如果用户已经登陆。放行, 如果用户未登陆,跳转到登陆页面

例子:

1.创建一个首页 main.jsp, 登录页面login.jsp

main.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body>
<h1>首页</h1>
</body>
</html>

login.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head><h1>登录页面</h1>
<hr><body><form action="${pageContext.request.contextPath}/user/login" method="post">用户名:<input type="text" name="username"> <br>密码:<input type="text" name="password"> <br><input type="submit" value="提交">
</form></body>
</html>

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" %>
<html><head><title>$Title$</title></head><body>
<%--  <a href="${pageContext.request.contextPath}/interceptor">拦截器测试</a>--%><h1><a href="${pageContext.request.contextPath}/user/goLogin">登录页面</a></h1><h1><a href="${pageContext.request.contextPath}/user/main">首页</a></h1></body>
</html>

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" %>
<html>
<head><title>Title</title>
</head>
<body>
<h1>首页</h1><span>${username}</span><p><a href="${pageContext.request.contextPath}/user/goOut">注销</a>
</p>
</body>
</html>

这个拦截器是Spring自己的,因为它直接在 applicationContext.xml中就完成配置, 不需要在web.xml中去进行。而且它是 spring mvc的, 因为它注册的时候,拦截配置为如下:

        <mvc:interceptor><!-- 包括这个路径下面的所有的请求--><mvc:mapping path="user/**"/><bean class="com.AL.config.LoginInterceptor"/></mvc:interceptor>

其实写拦截器就两个步骤:写一个拦截器的类,关于在什么时候放行,什么时候阻止;然后注册拦截器即可。

7.3、Spring中拦截器的使用

springMVC中的 interceptor 拦截器的作用:拦截用户请求并进行响应的处理。例如:权限验证、是否登录…

博客链接:https://www.cnblogs.com/nan993/p/6203328.html

一、定义Interceptor实现类

SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的。在SpringMVC 中定义一个Interceptor 非常简单,主要有两种方式,

  1. 第一种方式是要定义的Interceptor类要实现了Spring 的HandlerInterceptor 接口,或者是这个类继承实现了HandlerInterceptor 接口的类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter ;
  2. 第二种方式是实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类。

(一)实现HandlerInterceptor接口

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 stubreturn 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 接口

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 stubSystem.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 stubfor (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 stubSystem.out.println(exception + "-=-=--=--=-=-=-=-=-=-=-=-==-=--=-=-=-=");  }  }

二、把定义的拦截器类加到SpringMVC的拦截体系中

1.在SpringMVC的配置文件中加上支持MVC的schema

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的拦截器的

(二)使用mvc:interceptors标签来声明需要加入到SpringMVC拦截器链中的拦截器

Xml代码 :

<mvc:interceptors>  <!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->  <bean class="com.host.app.web.interceptor.AllInterceptor"/>  <mvc:interceptor>  <mvc:mapping path="/test/number.do"/>  <!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->  <bean class="com.host.app.web.interceptor.LoginInterceptor"/>  </mvc:interceptor>
</mvc:interceptors>

​ 由上面的示例可以看出可以利用mvc:interceptors标签声明一系列的拦截器,然后它们就可以形成一个拦截器链,拦截器的执行顺序是按声明的先后顺序执行的,先声明的拦截器中的preHandle方法会先执行,然而它的postHandle方法和afterCompletion方法却会后执行。

​ 在mvc:interceptors标签下声明interceptor主要有两种方式:

  1. 直接定义一个Interceptor实现类的bean对象。使用这种方式声明的Interceptor拦截器将会对所有的请求进行拦截。

  2. 使用mvc:interceptor标签进行声明。使用这种方式进行声明的Interceptor可以通过mvc:mapping子标签来定义需要进行拦截的请求路径

​ 经过上述两步之后,定义的拦截器就会发生作用对特定的请求进行拦截了。

mvc:interceptor定义需要拦截的请求路径

<!--关于拦截器的配置-->
<mvc:interceptors><mvc:interceptor><!--/** 包括路径及其子路径--><!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截--><!--/admin/** 拦截的是/admin/下的所有--><mvc:mapping path="/**"/><!--bean配置的就是拦截器--><bean class="com.AL.config.MyInterceptor"/></mvc:interceptor>
</mvc:interceptors>

8、文件上传和下载

在上传文件的时候,前端的表单 method设置为POST,并且需要对 enctype属性设置文件上传时的数据编码形式

文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver

前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;

对表单中的 enctype 属性做个详细的说明:

  • application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
  • multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
  • text/plain:除了把空格转换为 “+” 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
<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程序员上传文件的最佳选择。

  • Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。
  • 而Spring MVC则提供了更简单的封装。
  • Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。
  • Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类
  • CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。

MultipartResolver实现类去完成文件上传。

8.1、文件上传

1、导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;pom.xml

<!--文件上传-->
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version>
</dependency>

2、配置bean:multipartResolver

注意!!!这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误

<!--文件上传配置-->
<bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 --><property name="defaultEncoding" value="utf-8"/><!-- 上传文件大小上限,单位为字节(10485760=10M) --><property name="maxUploadSize" value="10485760"/><property name="maxInMemorySize" value="40960"/>
</bean>

CommonsMultipartFile 的 常用方法:

  • String getOriginalFilename():获取上传文件的原名
  • InputStream getInputStream():获取文件流
  • void transferTo(File dest):将上传文件保存到一个目录文件中

web.xml配置文件:web开发的支持条件,注册DispatchServlet,启动顺序设置:

<?xml version="1.0" encoding="UTF-8"?>
<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"><!--1.注册servlet--><servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--通过初始化参数指定SpringMVC配置文件的位置,进行关联--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></init-param><!-- 启动顺序,数字越小,启动越早 --><load-on-startup>1</load-on-startup></servlet><!--所有请求都会被springmvc拦截 --><servlet-mapping><servlet-name>SpringMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>

applicationContext.xml配置文件:servlet的配置,其实就是DispatchServlet还有视图解析器、处理器 Bean 容器的注册等:

<?xml version="1.0" encoding="UTF-8"?>
<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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --><context:component-scan base-package="com.AL.controller"/><!--静态资源过滤--><mvv:default-servlet-handler/><!--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><!-- 视图解析器 --><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"><!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 --><property name="defaultEncoding" value="utf-8"/><!-- 上传文件大小上限,单位为字节(10485760=10M) --><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 的 常用方法:

  • String getOriginalFilename():获取上传文件的原名
  • InputStream getInputStream():获取文件流
  • void transferTo(File dest):将上传文件保存到一个目录文件中
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

8.2、file.Transto 文件上传

采用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、前端表单提交地址修改

<form action="/upload2" enctype="multipart/form-data" method="post"><input type="file" name="file"/><input type="submit" value="upload">
</form>

3、访问提交测试,OK!

8.3、文件下载

文件下载步骤:

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(); //设置页面不缓存,清空bufferresponse.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;
}

前端:

<a href="/download">点击下载</a>

测试,下载成功。

9、Spring、Spring MVC、Spring Boot 如何与 Tomcat进行交互

web应用程序编写完毕后, 如果想要提供给外界访问:就需要一个服务器来统一管理;

简单来说:web应用程序分为静态和动态的web,还需要URL即网络地址,存放东西的地方;配置文件和jar包用来实现连接的,这些和外部的连接 进行访问,就需要一个服务器:Tomcat。 我们需要把自己开发出来的Web程序放在我们服务器的webapps目录下。

javaWeb:java中用于开发动态web的就称为 javaweb。

完成一个Servlet。Servlet是用来创建动态web的技术。开发一个Servlet程序,需要两个步骤:

  • 编写一个类,实现Servlet接口。 sun公司默认有两个类:HttpServlet,GenericServlet。HttpServlet继承了Servlet接口的功能, 所以我们直接继承HttpServlet,编写一个类 就能去实现servlet接口。
  • 把开发好的java类添加到web服务器中。即在web.xml配置文件中,完成servlet注册和servlet请求的路径映射。
    在这里,我们就将实现了Servlet接口的java程序叫做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。

  • SpringMVC中的web.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<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"><!--1.注册servlet--><servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--通过初始化参数指定SpringMVC配置文件的位置,进行关联--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></init-param><!-- 启动顺序,数字越小,启动越早 --><load-on-startup>1</load-on-startup></servlet></web-app>
  • web.xml配置文件中绑定的 applicationContext.xml 文件信息,

    • 里面注册了 适配器、执行器、视图解析器,

    • MVC框架会存储Servlet和Controller之间的映射关系:

<?xml version="1.0" encoding="UTF-8"?>
<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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --><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><!--/** 包括路径及其子路径--><!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截--><!--/admin/** 拦截的是/admin/下的所有--><mvc:mapping path="/**"/><!--bean配置的就是拦截器--><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。

  • SpringMVC中的web.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<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"><!--1.注册servlet--><servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--通过初始化参数指定SpringMVC配置文件的位置,进行关联--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></init-param><!-- 启动顺序,数字越小,启动越早 --><load-on-startup>1</load-on-startup></servlet></web-app>
  • web.xml配置文件中绑定的 applicationContext.xml 文件信息,

    • 里面注册了 适配器、执行器、视图解析器,

    • MVC框架会存储Servlet和Controller之间的映射关系:

<?xml version="1.0" encoding="UTF-8"?>
<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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --><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><!--/** 包括路径及其子路径--><!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截--><!--/admin/** 拦截的是/admin/下的所有--><mvc:mapping path="/**"/><!--bean配置的就是拦截器--><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>

Java-Spring MVC学习笔记相关推荐

  1. Spring MVC 学习笔记一 HelloWorld

    Spring MVC 学习笔记一 HelloWorld Spring MVC 的使用可以按照以下步骤进行(使用Eclipse): 加入JAR包 在web.xml中配置DispatcherServlet ...

  2. Spring MVC 学习笔记 对locale和theme的支持

    Spring MVC 学习笔记 对locale和theme的支持 Locale Spring MVC缺省使用AcceptHeaderLocaleResolver来根据request header中的 ...

  3. Spring MVC 学习笔记(整理)

    SpringMVC学习 1.概述 Spring MVC是一种基于Java实现MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行解耦,基于请求-响应模型帮助我们 ...

  4. 狂神说java spring篇 学习笔记

    前言 笔记整合自 未名湖畔种千玺:跟着狂神学Spring(官方资料+自己整合+细节补充+整合MyBatis) 黑心白莲:[狂神说]Spring学习笔记(全) 酷狗蛋儿的:Spring c命名和p命名空 ...

  5. Spring MVC学习笔记——SiteMesh的使用(转)

    转自 SiteMesh的使用 SiteMesh的介绍就不多说了,主要是用来统一页面风格,减少重复编码的. 它定义了一个过滤器,然后把页面都加上统一的头部和底部. 需要先在WEB-INF/lib下引入s ...

  6. Spring MVC学习笔记

    文章目录 创建一个servlet项目 导入依赖 添加Web框架 编写Servlet 注册这个servlet 编写跳转页面 配置Tomcat 第一个Spring MVC程序 1. web.xml的配置 ...

  7. 【Spring MVC学习笔记 六】SpringMVC框架整合AJAX完成局部刷新

    本篇Blog介绍另一个常用的技术Ajax.虽然Ajax可以脱离SpringMVC去使用,但是SpringMVC对AJax有更好的支持 AJAX概念概述 AJAX即Asynchronous Javasc ...

  8. Spring MVC 学习笔记 json格式的输入和输出

    Spring mvc处理json需要使用jackson的类库,因此为支持json格式的输入输出需要先修改pom.xml增加jackson包的引用 <!-- json --><depe ...

  9. Spring MVC学习笔记(七)

    2019独角兽企业重金招聘Python工程师标准>>> 配置Spring MVC <?xml version="1.0" encoding="UT ...

  10. Spring MVC学习笔记——POJO和DispatcherServlet

    POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称. 使用POJO名称是为了避免和EJB(Enter ...

最新文章

  1. java uiautomation_Java UiAutomation類代碼示例
  2. 《AngularJS实战》——3.1 模板中的过滤器
  3. vmx转换ofv模板,导入esxi
  4. C++ 计算并输出三角形的面积
  5. Reactive Extensions简介一
  6. Spring+Hibernate+c3p0连接池配置-连接无法释放的问题解决方案
  7. Mysql分页加pagebean_Spring+MyBatis+SpringMvc+Mysql+Druid+PageHelper分页实现
  8. AddStaticMeshComponent
  9. MyBatis之快速入门
  10. python中添加路径_python中添加模块导入路径的方法
  11. (笔记)涉及到的WinAPI函数
  12. SQLServer 数据库之锁
  13. 2022款华硕灵耀pro16和华硕proart创16区别哪个好哪个更值得入手
  14. DTcms 上传图片BUG补丁,解决方案
  15. PD快充协议JD6606S资料
  16. Upgraded Edition
  17. Linux下利用ssh远程文件传输 传输命令 scp
  18. NB IoT LWM2M Object or/and Resource Identifier: (Object ID) or (ResourceID)
  19. 大学四年,我因为使用这几个学习方法,成为了同学眼中的“大神”、BUG克星!
  20. 想拿互联网大厂的前端offer, 除了技术,你还差什么?

热门文章

  1. win10 uwp 使用 AppCenter 自动构建
  2. 关闭新版360浏览器广告流氓行为
  3. 大数据培训学习效果好吗
  4. 《斯坦福高效睡眠法》书中的精髓:如何用好黄金90分钟睡眠法则,利用生理特征让我们晚上快速入睡,并在白天的时候保持清醒。
  5. 发布WordPress支持列表显示的音乐播放器插件
  6. Pytroch nn.Unfold() 与 nn.Fold()图码详解
  7. JAVA银杏湖景区旅游管理信息平台计算机毕业设计Mybatis+系统+数据库+调试部署
  8. 中科蓝讯-库文件的选择
  9. 2018年度托福考情分析——口语篇
  10. 自考计算机网络应用,自考计算机网络原理总复习.doc