Spring Web MVC(了解概念;重点学习:配置与注解)
演变
JSP Model1
JSP JavaBean
在一个项目中,如果业务流程比较简单的时候,可以把控制器的功能交给视图,项目架构中只有视图和模型,没有控制器。
Model1模式的基础是JSP,它由JSP和JavaBean组成,JSP从HTTPRequest中获取所需要的数据,并调用JavaBean进行业务逻辑的处理,然后通过HTTPResponse将结果返回给前端浏览器。可见,Model1一定程度上实现了MVC,只不过将控制层和视图层统一定位到JSP页面,JavaBean依然充当模型组件。这种模式下JSP身兼多职,既要负责视图层的数据展示,又要负责业务流程控制,结构较为混乱,也不是我们所希望的松耦合架构,所以在大型项目中或者当业务流程比较复杂的时候不建议这样做。
JSP Model2
JSP Servlet JavaBean
当业务流程比较复杂的时候,就需要把业务流程控制交给专门的控制器,JSP只专注于视图的渲染展现即可。这种模式就是JSP Model2,即JSP Servlet JavaBean,也就是典型的MVC设计模式。
相比于Model1,Model2是将控制层单独划分出来,以Servlet的形式存在于项目架构中,负责业务流程的控制,接收请求,创建所需的JavaBean组件,并将处理后的数据返回给视图(JSP/HTML)进行结果渲染展示。这样的结构比较清晰,效果明显优化很多,并且结合Spring的IoC和AOP,也是一个松耦合的架构模式。所以,除非项目特别简单,一般情况下推荐使用JSP Model2。
MVC的处理过程:
首先视图提供系统与用户交互的界面,并发送用户的输入给控制器;
控制器接收到用户的请求,根据判断,决定调用哪个模型的哪个方法进行处理;
模型被控制器调用,根据控制器的指令进行相应的业务逻辑处理,并返回处理结果(数据);
控制器根据返回的结果,调用相应的视图来渲染、格式化模型返回的数据;
视图响应给客户端浏览器。
MVC处理流程及优缺点
优点:
可以多视图共享多个模型,大大提高了代码的复用性;
MVC的三个模块相互独立,松耦合架构;
控制器提高了应用程序的灵活性和可配置性;
有利于项目的管理和维护。
缺点:
原理较复杂,实现起来固然没有JSP JavaBean的方式来得快;
增加了系统结构和实现的复杂性;
视图对模型数据的访问效率较低。
简介
Spring Web 模型视图控制器(MVC)框架是围绕DispatcherServlet
设计的,该框架将请求分配给处理程序,并具有可配置的处理程序 Map,视图分辨器,语言环境,时区和主题分辨器,以及对文件上传的支持。默认处理程序基于@Controller
和@RequestMapping
注解,提供了多种灵活的处理方法。随着 Spring 3.0 的引入,@Controller
机制还允许您通过@PathVariable
注解和其他功能来创建 RESTful 网站和应用程序。
原则
开放扩展,封闭修改;Spring Web MVC 核心类中的某些方法标记为final
。作为开发人员,您不能覆盖这些方法来提供自己的行为。这不是随意进行的,而是要牢记这一原则。
Spring MVC运行原理
- 客户端发出HTTP请求,Web应用服务器接收此请求。如匹配DispatcherServlet的请求映射路径,则Web容器将该请求转交给DispatcherServlet处理;
- DispatcherServlet拿到请求之后,根据请求的信息(URL、请求参数、HTTP方法等)及HandlerMapping的配置找到处理请求的处理器(Handler);
- 当DispatcherServlet找到相应的Handler之后,通过HandlerAdapter对Handler进行封装,再以统一的适配器接口调用Handler。HandlerAdapter可以理解为真正使用Handler来干活的人。
- 在请求信息真正到达调用Handler的处理方法之前的这段时间,Spring MVC还完成了很多工作,它会将请求信息以一定的方式转换并绑定到请求方法的入参,对于入参的对象会进行数据转换、数据格式化以及数据校验等。这些都做完以后,最后才真正调用Handler的处理方法进行相应的业务逻辑处理。
- 处理器完成业务处理之后,将一个ModelAndView对象返回给DispatcherServlet,其中包含了逻辑视图名和模型数据信息。
- DispatcherServlet通过ViewResolver将逻辑视图名解析为真正的视图对象View,可以是JSP、HTML、XML、PDF、JSON等等,得到真正的视图对象之后,DispatcherServlet会根据ModelAndView对象中的模型数据对View进行视图渲染。最终客户端获得响应消息。
Spring MVC框架的特点
- 角色划分清晰。Model、View、Controller各司其职,耦合度较低。
- 灵活的配置功能。Spring的核心是IoC和AOP,统一可以实现在MVC上,把各种类当作Bean组件配置在Spring容器中。
- 提供了大量的接口和实现类,方便各种场景的开发。
- 真正做到与View层的实现无关。
- 结合Spring的依赖注入,更好地应用了面向接口编程的思想。
- 可以与Spring天衣无缝的整合
DispatcherServlet
DispatcherServlet其实就是个Servlet(它继承自HttpServlet基类),同样也需要在你web应用的web.xml配置文件下声明
DispatcherServlet
依赖的bean
bean的类型 | 作用 |
---|---|
HandlerMapping | 处理器映射。它会根据某些规则将进入容器的请求映射到具体的处理器以及一系列前处理器和后处理器(即处理器拦截器)上。具体的规则视HandlerMapping类的实现不同而有所不同。其最常用的一个实现支持你在控制器上添加注解,配置请求路径。当然,也存在其他的实现。 |
HandlerAdapter | 处理器适配器。拿到请求所对应的处理器后,适配器将负责去调用该处理器,这使得DispatcherServlet无需关心具体的调用细节。比方说,要调用的是一个基于注解配置的控制器,那么调用前还需要从许多注解中解析出一些相应的信息。因此,HandlerAdapter的主要任务就是对DispatcherServlet屏蔽这些具体的细节。 |
HandlerExceptionResolver | 处理器异常解析器。它负责将捕获的异常映射到不同的视图上去,此外还支持更复杂的异常处理代码。 |
ViewResolver | 视图解析器。它负责将一个代表逻辑视图名的字符串(String)映射到实际的视图类型View上。通常你需要配置InternalResourceViewResolver类提供的prefix属性,使其指向视图文件所在的目录。 这里需要理解的一个事情是,一旦你在web应用上下文WebApplicationContext中配置了某个特殊bean以后(比如InternalResourceViewResolver),实际上你也覆写了该bean的默认实现。比方说,如果你配置了InternalResourceViewResolver,那么框架就不会再使用beanViewResolver的默认实现。 |
LocaleResolver& LocaleContextResolver | 地区解析器 和 地区上下文解析器。它们负责解析客户端所在的地区信息甚至时区信息,为国际化的视图定制提供了支持。 |
ThemeResolver | 主题解析器。它负责解析你web应用中可用的主题,比如,提供一些个性化定制的布局等。 |
MultipartResolver | 解析multi-part的传输请求,比如支持通过HTML表单进行的文件上传等。 |
FlashMapManager | FlashMap管理器。它能够存储并取回两次请求之间的FlashMap对象。后者可用于在请求之间传递数据,通常是在请求重定向的情境下使用。 |
逻辑试图和物理视图
逻辑试图:控制器方法返回一个字符串,或者是通过 ModelAndView.setViewName(String viewName) 方法设置一个视图名,此时的视图成为逻辑视图,因为前端控制器需要通过视图解析器来解析逻辑视图名,得到一个视图对象,然后才响应给客户端。
物理视图:在控制器方法中直接通过 ModelAndView.setView(View v)方法设置视图对象,然后返回ModelAndView给前端控制器,这时的视图就是物理视图,因为它前端控制器不需要再使用视图解析器来解析它,直接将视图内容响应给客户端。
定制DispatcherServlet的配置
定制DispatcherServlet的配置,具体的做法,是在web.xml文件中,Servlet的声明元素上添加一些Servlet的初始化参数(通过init-param元素)
可选参数 | 解释 |
---|---|
contextClass | 任意实现了WebApplicationContext接口的类。这个类会初始化该servlet所需要用到的上下文对象。默认情况下,框架会使用一个XmlWebApplicationContext对象。 |
contextConfigLocation | 一个指定了上下文配置文件路径的字符串,该值会被传入给contextClass所指定的上下文实例对象。该字符串内可以包含多个字符串,字符串之间以逗号分隔,以此支持你进行多个上下文的配置。在多个上下文中重复定义的bean,以最后加载的bean定义为准 |
namespace | WebApplicationContext的命名空间。默认是[servlet-name]-servlet |
构建springmvc项目
1.create new project
2.maven---》 create from archetype--》maven-archetype-webapp》起组名 项目名
3.java文件夹 mark directory as sources root
4.test文件夹 mark directory as Test sources root
5.在java包同级建一个文件夹 mark directory as Resource root
6.在resource文件夹下建spring-bean.xml与log4j.properties,dispatcher-servlet.xml
7.在webapp文件夹下面创建static文件夹用于存放静态资源
8.在static文件夹创建css image js
9.在java目录下建班级名文件夹
10 在班级名文件夹下建
controller
mapper
pojo
service
until
引pom
配置web.xml
代码语言:javascript复制<?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_3_1.xsd"
version="3.1">
<display-name>Archetype Created Web Application</display-name>
<!--welcome pages-->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--乱码过滤器-->
<filter>
<filter-name>encodingFilter</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>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-bean.xml</param-value>
<!--classpath是指web项目构建完成后WEB-INF文件夹下的classes目录
classpath:只会到你的class路径中查找找文件;
classpath*:不仅包含class路径,还包括jar文件中(class路径)进行查找. -->
</context-param>
<!--配置springmvc DispatcherServlet-->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--配置dispatcher.xml作为mvc的配置文件-->
<!--必须这样写-->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<!-- <load-on-startup>1</load-on-startup>的作用
1)load-on-startup元素标记容器是否在启动的时候就加载这个servlet(实例化并调用其init()方法)。
2)它的值必须是一个整数,表示servlet应该被载入的顺序
3)当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个servlet;
4)当值小于0或者没有指定时,则表示容器在该servlet被选择时才会去加载。
5)正数的值越小,该servlet的优先级越高,应用启动时就越先加载。
6)当值相同时,容器就会自己选择顺序来加载。
-->
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--把applicationContext.xml加入到配置文件中-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--ContextLoaderListener的作用就是启动Web容器时,读取在contextConfigLocation中定义的xml文件,
自动装配ApplicationContext的配置信息,并产生WebApplicationContext对象,
然后将这个对象放置在ServletContext的属性里,这样我们只要得到Servlet就可以得到WebApplicationContext对象,
并利用这个对象访问spring容器管理的bean。
简单来说,就是上面这段配置为项目提供了spring支持,初始化了Ioc容器-->
</web-app>
配置dispatcher-servlet.xml
代码语言:javascript复制<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--此文件负责整个mvc中的配置-->
<!--启用spring的一些annotation -->
<context:component-scan base-package="kj08.controller"/>
<!-- <context:annotation-config/> -->
<!--<context:component-scan base-package="kj08"/>与上相等的 但是比上面的强大ssm一般用这个-->
<!--会帮我们注册默认处理请求,参数和返回值的类,其中最主要的两个类:DefaultAnnotationHandlerMapping 和 AnnotationMethodHandlerAdapter ,分别为HandlerMapping的实现类和HandlerAdapter的实现类,从3.1.x版本开始对应实现类改为了RequestMappingHandlerMapping和RequestMappingHandlerAdapter。
HandlerMapping的实现类的作用
实现类RequestMappingHandlerMapping,它会处理@RequestMapping 注解,并将其注册到请求映射表中。
HandlerAdapter的实现类的作用
实现类RequestMappingHandlerAdapter,则是处理请求的适配器,确定调用哪个类的哪个方法,并且构造方法参数,返回值。
当配置了mvc:annotation-driven/后,Spring就知道了我们启用注解驱动。然后Spring通过context:component-scan/标签的配置,会自动为我们将扫描到的@Component,@Controller,@Service,@Repository等注解标记的组件注册到工厂中,来处理我们的请求。
表示将所有的文件,包含静态资源文件都交给spring mvc处理。就需要用到<mvc:annotation-driven />了。如果不加,DispatcherServlet则无法区分请求是资源文件还是mvc的注解,而导致controller的请求报404错误。
-->
<mvc:annotation-driven/>
<!--静态资源映射-->
<!--本项目把静态资源放在了webapp的statics目录下,资源映射如下-->
<mvc:resources mapping="/css/**" location="/static/css/"/>
<mvc:resources mapping="/js/**" location="/static/js/"/>
<mvc:resources mapping="/image/**" location="/static/images/"/>
<mvc:default-servlet-handler />
<!--在springMVC-servlet.xml中配置<mvc:default-servlet-handler />后,会在Spring MVC上下文中定义一个o
rg.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它会像一个检查员,对进入
DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,
如果不是静态资源的请求,才由DispatcherServlet继续处理。
一般Web应用服务器默认的Servlet名称是"default",因此DefaultServletHttpRequestHandler可以找到它。
-->
<!-- 对模型视图名称的解析,即在模型视图名称添加前后缀(如果最后一个还是表示文件夹,则最后的斜杠不要漏了) 使用JSP-->
<!-- 默认的视图解析器 在上边的解析错误时使用 (默认使用html)- -->
<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/><!--设置JSP文件的目录位置-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
配置spring-bean.xml
代码语言:javascript复制<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
>
<context:component-scan base-package="kj08"/>
</beans>
配置tomcat
name:服务器名字
after launch 选你有的服务器
url:设置发布路径
deployment 选择 war exploded
(1)war模式这种可以称之为是发布模式,看名字也知道,这是先打成war包,再发布;
(2)war exploded模式是直接把文件夹、jsp页面 、classes等等移到Tomcat 部署文件夹里面,进行加载部署。因此这种方式支持热部署,一般在开发的时候也是用这种方式
再回过头将on update action 改成updateclassesandresources 实现热部署 :改jsp不用重启项目了
log
localhost是运行中的日志,它主要 记录 运行的一些信息,尤其是一些异常 错误 日志信息 。 catelina是 访问 日志信息,它 记录 的 访问 的 时间 , IP , 访问 的 资 料等相 关 信息。
idea运行tomcat是创建副本再运行 副本共享tomcat代码
启动tomcat
弹出浏览器正确访问就是成功
请求
HTTP 的请求报文分为三个部分 请求行、请求头和请求体
Request Line:请求行
请求行(Request Line)分为三个部分:请求方法、请求地址和协议及版本,以CRLF(rn)结束。HTTP/1.1 定义的请求方法有8种:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE,最常的两种GET和POST,如果是RESTful接口的话一般会用到GET、POST、DELETE、PUT。
Request Methods
注意,仅有POST、PUT以及PATCH这三个动词时会包含请求体,而GET、HEAD、DELETE、CONNECT、TRACE、OPTIONS这几个动词时不包含请求体。
Header:请求头
Header | 解释 | 示例 |
---|---|---|
Accept | 指定客户端能够接收的内容类型 | Accept: text/plain, text/html,application/json |
Accept-Charset | 浏览器可以接受的字符编码集。 | Accept-Charset: iso-8859-5 |
Accept-Encoding | 指定浏览器可以支持的web服务器返回内容压缩编码类型。 | Accept-Encoding: compress, gzip |
Accept-Language | 浏览器可接受的语言 | Accept-Language: en,zh |
Accept-Ranges | 可以请求网页实体的一个或者多个子范围字段 | Accept-Ranges: bytes |
Authorization | HTTP授权的授权证书 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Cache-Control | 指定请求和响应遵循的缓存机制 | Cache-Control: no-cache |
Connection | 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) | Connection: close |
Cookie | HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 | Cookie: $Version=1; Skin=new; |
Content-Length | 请求的内容长度 | Content-Length: 348 |
Content-Type | 请求的与实体对应的MIME信息 | Content-Type: application/x-www-form-urlencoded |
Date | 请求发送的日期和时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
Expect | 请求的特定的服务器行为 | Expect: 100-continue |
From | 发出请求的用户的Email | From: user@email.com |
Host | 指定请求的服务器的域名和端口号 | Host: www.zcmhi.com |
If-Match | 只有请求内容与实体相匹配才有效 | If-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Modified-Since | 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 | If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
If-None-Match | 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 | If-None-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Range | 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag | If-Range: “737060cd8c284d8af7ad3082f209582d” |
If-Unmodified-Since | 只在实体在指定时间之后未被修改才请求成功 | If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
Max-Forwards | 限制信息通过代理和网关传送的时间 | Max-Forwards: 10 |
Pragma | 用来包含实现特定的指令 | Pragma: no-cache |
Proxy-Authorization | 连接到代理的授权证书 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Range | 只请求实体的一部分,指定范围 | Range: bytes=500-999 |
Referer | 先前网页的地址,当前请求网页紧随其后,即来路 | Referer: http://www.zcmhi.com/archives... |
TE | 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 | TE: trailers,deflate;q=0.5 |
Upgrade | 向服务器指定某种传输协议以便服务器进行转换(如果支持) | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
User-Agent | User-Agent的内容包含发出请求的用户信息 | User-Agent: Mozilla/5.0 (Linux; X11) |
Via | 通知中间网关或代理服务器地址,通信协议 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 关于消息实体的警告信息 | Warn: 199 Miscellaneous warning |
Request Body:请求体
根据应用场景的不同,HTTP请求的请求体有三种不同的形式。
application/json
application/json 这个 Content-Type 作为响应头大家肯定不陌生。实际上,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。
JSON 格式支持比键值对复杂得多的结构化数据,这一点也很有用。
text/xml
没什么好讲的
Query String:application/x-www-form-urlencoded
这算是最常见的 POST 提交数据的方式了。浏览器的原生 <form> 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。
ModelAndView 类
从名字上看ModelAndView中的Model代表模型,View代表视图,这个名字就很好地解释了该类的作用。业务处理器调用模型层处理完用户请求后,把结果数据存储在该类的model属性中,把要返回的视图信息存储在该类的view属性中,然后让该ModelAndView返回该Spring MVC框架。框架通过调用配置文件中定义的视图解析器,对该对象进行解析,最后把结果数据显示在指定的页面上。
常用构造方法
ModelAndView(String viewName)
最简单的ModelAndView是持有View的名称返回,之后View名称被view resolver,也就是实作org.springframework.web.servlet.View接口的实例解析,例如 InternalResourceView或JstlView等等:
ModelAndView(String viewName, Map model)
如果您要返回Model对象,则可以使用Map来收集这些Model对象,然后设定给ModelAndView,使用下面这个版本的ModelAndView:
ModelAndView()
这个构造方法构造出来的ModelAndView
不能直接使用,应为它没有指定view,也没有绑定对应的model对象。当然,model对象不是必须的,但是view确实必须的。
用这个构造方法构造的实例主要用来在以后往其中加view设置和model对象。
给ModelAndView
实例设置view的方法有两
个:setViewName(String viewName) 和 setView(View view)。前者是使用view
name,后者是使用预先构造好的View对象。其中前者比较常用。事实上View是一个接口,而不是一个可以构造的具体类,我们只能通过其他途径来获取
View的实例。对于view
name,它既可以是jsp的名字,也可以是tiles定义的名字,取决于使用的ViewNameResolver如何理解这个view name。
如何获取View的实例以后再研究。
而对应如何给ModelAndView
实例设置model则比较复杂。有三个方法可以使用:
addObject(Object modelObject)
addObject(String modelName, Object modelObject)
addAllObjects(Map modelMap)
ModelAndView
可以接收Object类型的对象,ModelAndView
将它视为其众多model中的一个。当使用Object类型的对象的时候,必须指定一个名字。ModelAndView
也可以接收没有明显名字的对象,原因在于ModelAndView
将调用spring自己定义的Conventions 类的.getVariableName()方法来为这个model生成一个名字。显然,对model而言,名字是必须的。
Conventions.getVariableName()生成名字的规则是使用对象的类名的小写模式来作model名字。当这个model是集合或数组的时候,使用集合的第一个元素的类名加s来作model的名字。
ModelAndView
也可以接收Map类型的对象,ModelAndView
将这个Map中的元素视为model,而不是把这个Map本身视为model。但是其他的集合类可以用本身作为model对象。
Model 与 ModelMap
首先都是存键值值,只是方法多了点
Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;
ModelMap继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性;
return new ModelAndView("redirect:/404.htm");重定向
学习相关注解(结合postman工具)
@Controller
@Controller 声明该类为SpringMVC中的Controller控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。在SpringMVC 中使用@Controller ,就无需继承特定的类或实现特定的接口,只需使用@Controller 标记一个类是Controller,然后使用@RequestMapping 和@RequestParam 等一些注解用以定义URL 请求和Controller 方法之间的映射,这样的Controller 就能被外界访问到。@Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。
方法的返回值
返回ModelAndView:需要方法结束时,定义ModelAndView,将model和view分别进行设置。
返回void:
在controller方法形参上可以定义request和response,使用request或response指定响应结果:
1、使用request转向页面,如下:
request.getRequestDispatcher("页面路径").forward(request, response);
2、也可以通过response页面重定向:
response.sendRedirect("url")
3、也可以通过response指定响应结果,例如响应json数据如下:
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");
返回字符串:(String)
return "xxxxx";逻辑视图名
return "redirect:/xxxxx"重定向
return "forward:xxxxx"转发
@RequestMapping
@RequestMapping的作用是建立请求URL和处理方法之间的对应关系
@RequestMapping可以作用在方法和类上
作用在类上:第一级的访问目录 作用在方法上:第二级的访问目录
@RequestMapping的属性
path-指定请求路径的URL value属性和path属性是一样的 mthod 指定该方法的请求方式 params 指定限制请求参数的条件 headers 发送的请求中必须包含的请求头
produces:produces = "application/json;charset=utf-8" 等于 response.setContentType("application/json;charset=utf-8");
@ModelAttribute
方法上注释
被@ModelAttribute注释的方法会在此controller每个方法执行前被执行,因此对于一个controller映射多个URL的用法来说,要谨慎使用。
@ModelAttribute注释void返回值的方法
代码语言:javascript复制@Controller
public class HelloWorldController {
@ModelAttribute
public void populateModel(@RequestParam String abc, Model model) {
model.addAttribute("attributeName", abc);
}
@RequestMapping(value = "/helloWorld")
public String helloWorld() {
return "helloWorld";
}
}
//这个例子,在获得请求/helloWorld 后,populateModel方法在helloWorld方法之前先被调用,它把请求参数(/helloWorld?abc=text)加入到一个名为attributeName的model属性中,在它执行后helloWorld被调用,返回视图名helloWorld和model已由@ModelAttribute方法生产好了。
@ModelAttribute注释返回具体类的方法
代码语言:javascript复制@ModelAttribute
public Account addAccount(@RequestParam String number) {
return accountManager.findAccount(number);
}
//model属性的名称没有指定,它由返回类型隐含表示,如这个方法返回Account类型,那么这个model属性的名称是account。这个例子中model属性名称有返回对象类型隐含表示,model属性对象就是方法的返回值。它无须要特定的参数
@ModelAttribute(value="")注释返回具体类的方法
代码语言:javascript复制@Controller
public class HelloWorldController {
@ModelAttribute("attributeName")
public String addAccount(@RequestParam String abc) {
return abc;
}
@RequestMapping(value = "/helloWorld")
public String helloWorld() {
return "helloWorld";
}
}
@ModelAttribute和@RequestMapping同时注释一个方法
代码语言:javascript复制@Controller
public class HelloWorldController {
@RequestMapping(value = "/helloWorld.do")
@ModelAttribute("attributeName")
public String helloWorld() {
return "hi";
}
}
参数上注释
@ModelAttribute注释一个方法的参数
代码语言:javascript复制@Controller
public class HelloWorldController {
@ModelAttribute("user")
public User addAccount() {
return new User("jz","123");
}
@RequestMapping(value = "/helloWorld")
public String helloWorld(@ModelAttribute("user") User user) {
user.setUserName("jizhou");
return "helloWorld";
}
}
//@ModelAttribute("user") User user注释方法参数,参数user的值来源于addAccount()方法中的model属性。此时如果方法体没有标注@SessionAttributes("user"),那么scope为request,如果标注了,那么scope为session
从Form表单或URL参数中获取(实际上,不做此注释也能拿到user对象)
代码语言:javascript复制@Controller
public class HelloWorldController {
@RequestMapping(value = "/helloWorld")
public String helloWorld(@ModelAttribute User user) {
return "helloWorld";
}
}
注意这时候这个User类一定要有没有参数的构造函数
@SessionAttributes
知道是往session作用域中赋值的就行了,但是一般不用,一般都是用原生api去写session的值
提一句:在Controller中得到request 或者session的方式
1.在参数上写HttpServletRequest request
2.定义类属性并自动注入
3.定义一个父类定义属性然后继承
@PathVariable
REST 风格
REST 即 Representational State Transfer
(资源)表现层状态转化,用 URL 定位资源,用 HTTP 描述操作,是目前最流行的一种互联网软件架构,它的结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用,使用POST,DELETE,PUT,GET 分别对应 CRUD,Spring3.0 开始支持 REST 风格的请求。
类似于http://localhost:8080/goods/1
代码语言:javascript复制/**
*
*/
@Controller
public class MyFirstController {
@RequestMapping("/rest/{id}")
public String show(@PathVariable Integer id) {
System.out.println(id);
return "/first";
}
}
使用 @PathVariable 接收 REST 风格参数
@requestParam
锐快死怕mu
与@RequestBody
@requestParam
注解@RequestParam接收的参数是来自requestHeader中,即请求头。通常用于GET请求
@RequestParam有三个配置参数:
required
表示是否必须,默认为true
,必须。defaultValue
可设置请求参数的默认值。value
为接收url的参数名(相当于key值)。
@RequestParam用来处理 Content-Type 为 application/x-www-form-urlencoded 编码的内容
@RequestParam也可用于其它类型的请求,例如:POST、DELETE等请求。
由于@RequestParam是用来处理 Content-Type 为 application/x-www-form-urlencoded 编码的内容的,所以在postman中,要选择body的类型为 x-www-form-urlencoded,这样在headers中就自动变为了 Content-Type : application/x-www-form-urlencoded 编码格式(postman工具)
@RequestBody
注解@RequestBody接收的参数是来自requestBody中,即请求体。一般用于处理非 Content-Type: application/x-www-form-urlencoded编码格式的数据,比如:application/json、application/xml等类型的数据。就application/json类型的数据而言,使用注解@RequestBody可以将body里面所有的json数据传到后端,后端再进行解析。 由于@RequestBody可用来处理 Content-Type 为 application/json 编码的内容,所以在postman中,选择body的类型为row -> JSON(application/json),这样在 Headers 中也会自动变为 Content-Type : application/json 编码格式。 注意:前端使用$.ajax的话,一定要指定 contentType: “application/json;charset=utf-8;” type ="post",默认为 application/x-www-form-urlencoded。data里的对象要变成json字符串用JSON.stringify()方法
form表单ajax提交
代码语言:javascript复制var array=$("#fm").serializeArray();
var data={};
for(var i = 0;i<array.length;i ){
data[array[i].name]=array[i].value;
}
在后端的同一个接收方法里,@RequestBody 与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。
总结
注解@RequestParam接收的参数是来自requestHeader中,即请求头。通常用于GET请求,像POST、DELETE等其它类型的请求也可以使用。
注解@RequestBody接收的参数是来自requestBody中,即请求体。一般用于处理非 Content-Type: application/x-www-form-urlencoded编码格式的数据,比如:application/json、application/xml等类型的数据。通常用于接收POST、DELETE等类型的请求数据,GET类型也可以适用。
重点补充:在使用注解@RequestParam的时候【不加注解的时候效果与@RequestParam类似】,在body data中我们不能传json字符串类型的参数,否则对象中是接收不到传递参数相应的值。相应的在@RequestBody注解标记的形式上传递表格参数则会报错。
@ResponseBody
作用:@ResponseBody注解通常使用在控制层的方法上,用于将Controller的方法返回的对象,通过springmvc提供的HttpMessageConverter接口转换为指定格式的数据如:json,通过Response响应给客户端。假如是字符串则直接将字符串写到客户端;假如是一个对象,此时会将对象转化为json串然后写到客户端。这里需要注意的是,如果返回对象,按utf-8编码。如果返回String,页面可能出现乱码。因此在注解中我们可以手动修改编码格式,例如@RequestMapping(value="xxx",produces="text/html;charset=utf-8"),前面是请求的路径,后面是编码格式。简短截说就是指该类中所有的API接口返回的数据,甭管你对应的方法返回Map或是其他Object,它会以Json字符串的形式返回给客户端
@RestController
@Controller @ResponseBody
@GetMapping @PostMpping @PutMapping @DeleteMapping @PatchMapping
什么是RESTful
RESTful(RESTful Web Services)一种架构风格,表述性状态转移,它不是一个软件,也不是一个标准,而是一种思想,不依赖于任何通信协议,但是开发时要成功映射到某协议时也需要遵循其标准,但不包含对通信协议的更改
特征:
1.通过url地址来标识资源,系统中的每个对象或资源都可以通过其url地址来获取
2.统一接口,显式地使用HTTP方法,来进行crud(create,update,insert,delete)映射
创建资源使用POST
更新资源使用PUT
检索资源使用GET
删除资源使用DELETE
3.资源多重反映.通过url地址访问的每个资源都可以根据客户端的规定进行返回,例:JSON,XML
@GetMapping =@RequestMapping(value = “xxxx”, method = RequestMethod.GET)
其他的以此类推
springMVC拦截器
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。 要使用Spring MVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义。
Filter不管是什么都会拦截
Interceptor 只会拦截访问控制器的方法 并且是依赖aop实现
自定义拦截器实现了HandlerInterceptor接口,并实现了接口中的三个方法
- preHandle() 方法:该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true时,表示继续向下执行; 当其返回值为false时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。
- postHandle()方法:该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。
- afterCompletion()方法:该方法会在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 配置一个全局拦截器,拦截所有请求 -->
<bean class="xxxx" />
<mvc:interceptor>
<!-- 配置拦截器作用的路径 -->
<mvc:mapping path="/**" />
<!-- 配置不需要拦截作用的路径 -->
<mvc:exclude-mapping path="" />
<!-- 定义<mvc:interceptor>元素中,表示匹配指定路径的请求才进行拦截 -->
<bean class="xxxx" />
</mvc:interceptor>
<mvc:interceptor>
<!-- 配置拦截器作用的路径 -->
<mvc:mapping path="/gotoTest" />
<!-- 定义在<mvc: interceptor>元素中,表示匹配指定路径的请求才进行拦截 -->
<bean class="xxxxx" />
</mvc:interceptor>
</mvc:interceptors>
代码语言:javascript复制public class Interceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o)
throws Exception {
System.out.println("CustomInterceptor....preHandle");
//对浏览器的请求进行放行处理
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView)
throws Exception {
System.out.println("CustomInterceptor....postHandle");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e)
throws Exception {
System.out.println("CustomInterceptor....afterCompletion");
}
}
拦截session登录
代码语言:javascript复制public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handle) throws Exception {
//创建session
HttpSession session =request.getSession();
//无需登录,允许访问的地址
String[] allowUrls =new String[]{"/login"};
//获取请求地址
String url =request.getRequestURL().toString();
//获得session中的用户
UserToken user =(UserToken) session.getAttribute("userToken");
for (String strUrl : allowUrls) {
if(url.contains(strUrl)){
return true;
}
}
if(user ==null)
{
throw new UnLoginException("您尚未登录!");
}
//重定向
//response.sendRedirect(request.getContextPath() "/toLogin");
return true;
}
贴士
vmoption加-Dfile.encoding=UTF-8解决日志乱码问题