目录
3、web.xml中配置核心控制器DispatcherServlet
(1)Get请求的编码问题,要改tomcat的server.xml配置文件
(2)POST请求的编码问题,要在web.xml文件中配置编码过滤器
1、下载地址:https://www.postman.com/downloads/
一、SpringMVC的基本概念
(一)三层架构和MVC
1、三层架构概述
开发架构一般都是基于两种形式:
- C/S架构:客户端/服务器
- B/S架构:浏览器/服务器
在javaEE开发中,几乎都是基于B/S架构的开发。那么在B/S架构中,系统标准的三层架构包括:表现层、业务层、持久层。
- 表现层:也就是我们常说的web层。他负责接受客户端请求,向客户端响应结果,通常客户端使用http协议请求web层,web需要接受http请求,完成http响应。
- 业务层:也就是我们常说的service层。他负责业务逻辑处理。
- 持久层:dao层。负责数据持久化,和数据库做交互。
2、model1模式介绍
这个模式十分简单,页面显示,控制分发,业务逻辑,数据访问全部通过JSP去实现。
优点:架构简单,比较适合小型项目开发
缺点:JSP职责不单一,职责过重,不便于维护
3、model2模式介绍
这个模式通过两部分去实现,即JSP与Servlet。JSP负责控制分发,业务逻辑以及数据访问。
优点:职责清晰,较适合于大型项目架构
缺点: 不适合小型项目开发
4、MVC模式介绍
MVC模式则分为三大块,即视图(View),控制器(Control),模型(Model)。视图是JSP负责的页面显示,控制器则是Servlet负责的控制分发,模型包括Service和Dao两个部分,分别负责业务逻辑和数据访问。
优点:分工明确,各司其职,互不干扰。适用于大型项目架构,有利于组件的重构
缺点:增加了系统开发的复杂度
(二)SpringMVC概述
1、SpringMVC是什么?
SpringMVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分。简化开发,减少出错,方便组内开发人员之间的配合。
他通过一套注解,让一个简单的Java类成为处理请求的控制器,而无需实现任何接口。同时它还支持Restful编程风格的请求。
2、SpringMVC在三层架构中的位置
SpringMVC位于三层架构中的表现层,作用是接收请求响应数据,响应的数据通过视图、模版展示给用户。
3、SpringMVC主要组件
- 前端控制器(DispatcherServlet):接收请求、响应结果,相当于转发器,有了DispatcherServlet就减少了其他组件之间的耦合度。
- 处理器映射器(HandlerMapping):根据请求的URL来查找Handler
- 处理器适配器(HandlerAdapter):负责执行Handler
- 处理器(Handler):处理业务逻辑的Java类
- 视图解析器(ViewResolver):进行视图的解析,根据视图逻辑名将ModelAndView解析成真正的视图。
- 视图(View):View是一个接口,他的实现类支持不同的视图类型,如jsp,freemarker等等。
二、SpringMVC入门
(一)SpringMVC的入门案例
1、入门案例需求分析
构建页面index.jsp发起请求,在服务器端处理请求,控制台打印处理请求成功,跳转main.jsp成功页面。
2、构建maven项目并添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
3、web.xml中配置核心控制器DispatcherServlet
<servlet>
<servlet-name>springmvc01</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc01</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
4、配置SpringMVC
<!--扫描注解包-->
<context:component-scan base-package="com.offcn.controller">
</context:component-scan>
<!--处理器映射器:根据请求路径匹配映射路径找到对应的执行器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<!--处理器适配器:根据处理器映射器返回的执行器对象,去执行执行器对象-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<!--视图解析器:解析视图-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
5、构建页面发起请求
<a href="/hello/test1">hello</a>
6、编写控制器并注解配置
@Controller
@RequestMapping("hello")
public class HelloController {
@RequestMapping("test1")
public String test1(){
System.out.println("正在处理请求");
return "main";
}
}
7、启动服务器测试
pom.xml文件中服务器插件配置:
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!--指定编码格式-->
<uriEncoding>utf-8</uriEncoding>
<!--指定项目启动后的访问路径-->
<path>/</path>
<!--指定访问端口号-->
<port>8888</port>
</configuration>
</plugin>
</plugins>
</build>
(二)SpringMVC执行过程及原理分析
1、案例的执行过程
浏览器客户端发起请求,请求到达服务器tomcat,tomcat将请求相关信息参数封装到对象request和response中,再将request和response对象交给Service方法处理,在Service方法中会根据请求路径将请求交给对应的Controller执行器处理。
2、SpringMVC的请求响应流程
浏览器发送请求,被DispatcherServlet捕获,DispatcherServlet没有直接处理请求,而是将请求交给HandlerMapping处理器映射器,处理器映射器根据请求路径去Controller控制层中匹配对应的执行器,并将匹配结果返回给DispatcherServlet,由DispatcherServlet调用HandlerAdapter处理器适配器来执行控制层执行器方法;
执行器方法执行后的返回结果,由DispatcherServlet交给视图解析器ViewResolver来处理,找到对应的结果视图,渲染视图,并将结果响应给浏览器。
(三)SpringMVC常用组件介绍
1、DispatcherServlet:前端控制器
用户请求到达前端控制器,他就相当于mvc模式中的C,DispatcherServlet是整个流程控制的中心,由它调用其他组件处理用户的请求,DispatcherServlet的存在降低了组件之间的耦合性。
2、HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求找到Handler,即处理器,SpringMVC提供了不同的映射器实现不同的映射方式。例如:配置文件方式,实现接口方式,注解方式。
3、Handler:处理器
它就是我们开发中要编写的具体业务控制器。由DispatcherServlet把用户请求转发到Handler。由Handler对具体的用户请求进行处理。
4、HandlerAdapter:处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
5、View Resolver:视图解析器
ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
6、View:视图
SpringMVC框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。
7、mvc:annotation-driven标签说明
在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。
使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping(处理器映射器)和RequestMappingHandlerAdapter(处理器适配器),可用在SpringMVC.xml配置文件中使用<mvc:annotation-driven>替代处理器映射器和适配器的配置。
<mvc:annotation-driven>标签相当于以下配置:
<!-- HandlerMapping处理器映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
</bean>
<!-- HandlerAdapter处理器适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
erAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter">
</bean>
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter">
</bean>
<!-- HadnlerExceptionResolvers异常处理器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolv
er"></bean>
<bean
class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"></bean>
(四)RequestMapping注解
用于定义映射路径,建立请求url和控制层方法之间的对应关系
1、RequestMapping注解源码解读
@Target({ElementType.METHOD, ElementType.TYPE})
@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 {};
}
2、RequestMapping注解的描述
(1)注解位置
- 类上:定义一级映射路径
- 方法上:定义二级映射路径
(2)注解属性
- value:用于指定映射路径url。他和path属性的作用是一样的。
- method:用于指定请求的方式。
- params:用于指定限制请求参数的条件。它支持简单的表达式。
要求请求参数的 key 和 value 必须和配置的一模一样
- headers:用于指定限制请求消息头的条件。
三、SpringMVC中的请求参数绑定
(一)绑定说明
1、绑定的机制
表单中请求参数都是基于key=value的。SpringMVC绑定请求参数的过程是通过把表单提交请求参数,作为控制器中方法参数进行绑定的。
2、支持的数据类型
基本类型参数:包括基本类型和String
POJO类型参数:包括实体类,以及关联的实体类
数组和集合类型参数:包括List结构和Map结构的集合。
3、使用要求
基本类型或者String类型:要求我们的参数名称必须和控制器中方法的形参名称保持一致。
POJO类型:要求表单中参数名称和POJO类的属性名称保持一致。并且控制器方法的参数类型是POJO类型。
集合类型:
第一种:要求集合类型的请求参数必须在POJO中。在表单中请求参数名称要和POJO中集合属性名称相同。给List集合中的元素赋值,使用下标。给Map集合中的元素赋值,使用键值对。
第二种:接收的请求参数是json格式数据。需要借助一个注解实现。
(二)参数绑定示例
1、基本类型和string作为参数
(1)页面定义请求
<form action="/hello/test2" method="post">
用户名:<input name="userName" type="text">
年龄:<input name="age" type="text">
<input type="submit" value="提交">
</form>
(2)执行器方法绑定参数
@RequestMapping("test2")
public String test2(String userName,int age){
System.out.println("用户名:"+userName);
System.out.println("年龄:"+age);
return "main";
}
2、POJO类型作为参数
(1)页面定义请求
<form action="/hello/test3" >
用户名:<input name="pname" type="text">
年龄:<input name="age" type="text">
车名称:<input name="car.cname" type="text">
车价格:<input name="car.cprice" type="text">
<input type="submit" value="提交">
</form>
(2)执行器方法绑定参数
@RequestMapping("test3")
public String test3(Person person){
System.out.println(person);
return "main";
}
3、POJO类中包含集合类型参数
(1)页面定义请求
<form action="/hello/test4" >
用户名:<input name="pname" type="text">
年龄:<input name="age" type="text">
车名称:<input name="car.cname" type="text">
车价格:<input name="car.cprice" type="text">
list集合车1:车名称<input name="carList[0].cname" type="text">
list集合车1:车价格<input name="carList[0].cprice" type="text">
list集合车2:车名称<input name="carList[1].cname" type="text">
list集合车2:车价格<input name="carList[1].cprice" type="text">
set集合车1:车名称<input name="carSet[0].cname" type="text">
set集合车1:车价格<input name="carSet[0].cprice" type="text">
set集合车2:车名称<input name="carSet[1].cname" type="text">
set集合车2:车价格<input name="carSet[1].cprice" type="text">
map集合车1:车名称<input name="map['x']" type="text">
map集合车1:车价格<input name="map['y']" type="text">
map集合车2:车名称<input name="map['x2]" type="text">
map集合车2:车价格<input name="map['y2']" type="text">
<input type="submit" value="提交">
</form>
(2)执行器方法绑定参数
@RequestMapping("test4")
public String test4(Person person){
System.out.println(person);
return "main";
}
4、数组类型参数
(1)页面定义请求
<form action="/hello/test5" >
爱好1:<input name="hobbies" type="text">
爱好2:<input name="hobbies" type="text">
爱好3:<input name="hobbies" type="text">
<input type="submit" value="提交">
</form>
(2)执行器方法绑定参数
@RequestMapping("test5")
public String test5(String[] hobbies){
for(String hobby:hobbies){
System.out.println(hobby);
}
return "main";
}
5、使用ServletAPI对象作为方法参数
(1)引用ServletAPI的依赖jar包
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
(2)执行器方法绑定参数
@RequestMapping("test6")
public void test6(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("我在请求转发");
request.getRequestDispatcher("/hello/test1").forward(request,response);
}
6、请求参数乱码问题
(1)Get请求的编码问题,要改tomcat的server.xml配置文件
<Connector connectionTimeout="20000" port="8080"protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
(2)POST请求的编码问题,要在web.xml文件中配置编码过滤器
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filterclass>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>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
7、静态资源访问
(1)将静态资源交给默认的DefaultServlet处理
<mvc:default-servlet-handler></mvc:default-servlet-handler>
(2)指定静态资源的访问路径
在springMVC.xml配置文件中加如下配置:
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
(三)自定义参数处理
1、使用场景
SpringMVC不能自动识别参数转换为我们需要的数据类型,浏览器报400错误,类型转换异常。
2、使用步骤
(1)定义类型转换器
public class MyDateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date=simpleDateFormat.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
(2)配置类型转换器
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<bean class="com.offcn.util.MyDateConverter"></bean>
</property>
</bean>
<mvc:annotation-driven conversion-service="conversionService"/>
(3)引用类型转换器
<form action="/hello/test7" >
入职日期:<input name="hireDate" type="date">
<input type="submit" value="提交">
</form>
@RequestMapping("test7")
public String test7(Date hireDate){
System.out.println(hireDate);
return "main";
}
四、SpringMVC的注解详解
(一)RequestParam
1、注解介绍
使用在方法入参位置,用于指定请求参数名称,将该请求参数绑定到注解参数位置
属性:name:指定要绑定的请求参数名称
required:指定请求参数是否必传
defaultValue:指定当没有传入请求参数时的默认取值
2、注解使用案例
@RequestMapping("test1")
public String test1(@RequestParam(name = "pname",required = true,defaultValue = "李四")String name){
System.out.println(name);
return "main";
}
(二)RequestHeader
1、注解介绍
注解在方法入参位置,用于获取请求头信息
2、注解使用案例
@RequestMapping("test2")
public String test2(@RequestHeader("Upgrade-Insecure-Requests")String data){
System.out.println(data);
return "main";
}
(三)RequestBody
1、注解介绍
用于方法入参位置,获取请求体内容。直接使用得到是key=value&key=value...结构的数据。get请求方式不适用。通常用于将json格式字符串绑定到bean对象中。
2、注解使用案例
(1)直接获取请求体内容
<form action="/annotation/test3" method="post">
用户名:<input name="userName" type="text">
年龄:<input name="age" type="text">
<input type="submit" value="提交">
</form>
@RequestMapping("test3")
public String test3(@RequestBody String data){
System.out.println(data);
return "main";
}
(2)将json格式请求参数绑定到指定对象bean中
添加json转换配置:
添加一个json的转换依赖:(fastjson)
pom.xml:
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
</dependencies>
springMVC.xml,配置fastjson:
<!--开启springmvc注解-->
<mvc:annotation-driven>
<mvc:message-converters>
<!-- 配置Fastjson支持 -->
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<button onclick="sendCar()">发起ajax请求</button>
<script>
function sendCar() {
$.ajax({
type: "POST",
url: "/annotation/test4",
data: '{"cname":"宝马","cprice":"20"}',
contentType:"application/json",
success: function(msg){
alert( "Data Saved: " + msg );
}
});
}
</script>
@RequestMapping("test4")
public String test4(@RequestBody Car car){
System.out.println(car);
return "main";
}
(四)CookieValue
1、注解介绍
用于方法入参位置,把指定cookie名称的值传入控制器方法参数
2、注解使用案例
@RequestMapping("test5")
public String test5(@CookieValue("JSESSIONID") String data){
System.out.println(data);
return "main";
}
(五)ModelAttribute
1、注解介绍
该注解是SpringMVC4.3版本以后新加入的。它可以用于修饰方法和参数。
- 出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
- 出现在参数上,获取指定的数据给参数赋值。
2、注解使用案例
(1)注解在方法上
@ModelAttribute("shareParam")
public String test6(){
System.out.println("我是公共方法");
return "公共参数";
}
(2)注解在参数位置
@RequestMapping("test7")
public String test7(@ModelAttribute("shareParam")String data){
System.out.println(data);
return "main";
}
五、Rest风格编程
(一)Rest风格URL规范介绍
1、什么是restful
Restful架构,就是目前最流行的一种互联网软件架构风格。REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的。Fielding将他对互联网软件的架构原则,定名为REST,即Representational State Transfer的缩写。即"表现层状态转化"。如果一个架构符合REST原则,就称它为Restful架构。值得注意的是 REST并没有一个明确的标准,而更像是一种设计的格式。
2、restful的优点
它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用
3、restful的特性
(1)资源(Resource)
网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个 URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的 URI 就可以,因此 URI 即为每一个资源的独一无二 的识别符。
(2)表现层(Representation)
把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
(3)状态转化(State Transfer)
每发出一个请求,就代表了客户端和服务器的一次交互过程。
HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是“表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET 、POST 、PUT、 DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
(4)传统请求URL
新增:http://localhost:8888/annotation/addPerson POST
修改:http://localhost:8888/annotation/updatePerson POST
删除:http://localhost:8888/annotation/deletePerson?id=1 GET
(5)REST风格请求
新增:http://localhost:8888/annotation/person POST
修改:http://localhost:8888/annotation/person PUT
删除:http://localhost:8888/annotation/person/1 DELETE
(二)PathVariable注解详解
该注解用于绑定 url 中的占位符。例如:请求 url 中/annotation/test9/{id},这个{id}就是url占位符。url 支持占位符是 spring3.0 之后加入的。是springmvc 支持 rest 风格 URL 的一个重要标志。
属性:
value:用于指定url中占位符名称
required:是否必须提供占位符
(三)PathVariable案例
1、构建页面发起请求
REST风格编程:
新增:
<form action="/annotation/person" method="post">
用户名:<input name="userName" type="text">
年龄:<input name="age" type="text">
<input type="submit" value="提交">
</form>
修改:
<form action="/annotation/person" method="post">
<input type="hidden" name="_method" value="PUT">
用户名:<input name="userName" type="text">
年龄:<input name="age" type="text">
<input type="submit" value="提交">
</form>
删除:
<form action="/annotation/person/1" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="提交">
</form>
查询:
<a href="/annotation/person/1">查询用户</a>
2、定义控制层执行器处理请求
@RequestMapping(value = "person",method = RequestMethod.POST)
public String addPerson(String userName,int age){
System.out.println("新增用户:"+userName);
return "main";
}
@RequestMapping(value = "person",method = RequestMethod.PUT)
public String updatePerson(String userName,int age){
System.out.println("修改用户:"+userName);
return "main";
}
@RequestMapping(value = "person/{id}",method = RequestMethod.DELETE)
public String deletePerson(@PathVariable(value = "id")int id){
System.out.println("删除用户:id"+id);
return "main";
}
@RequestMapping(value = "person/{id}",method = RequestMethod.GET)
public String findPerson(@PathVariable(value = "id")int id){
System.out.println("查询用户信息:id"+id);
return "main";
}
3、引入请求方式转换过滤器
<filter>
<filter-name>hiddenMethodFilter</filter-name>
<filterclass>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
六、响应数据和结果视图
(一)返回值分类
1、返回值为字符串
用于指定返回的逻辑视图名称
@RequestMapping("test1")
public String test1(String pname){
System.out.println(pname);
System.out.println("返回string类型测试");
return "main";
}
2、void类型
通常使用原始servlet处理请求时,返回该类型
@RequestMapping("test2")
public void test2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("返回void类型测试");
request.getRequestDispatcher("/response/test1").forward(request,response);
}
3、ModelAndView
用于绑定参数和指定返回视图名称
@RequestMapping("test3")
public ModelAndView test3(ModelAndView modelAndView){
modelAndView.addObject("aa","aa1");
modelAndView.setViewName("main");
return modelAndView;
}
(二)转发和重定向
1、forward请求转发
@RequestMapping("test4")
public String test4(){
System.out.println("我是请求转发");
return "forward:/response/test1";
}
2、redirect重定向
@RequestMapping("test5")
public String test5(RedirectAttributes redirectAttributes,String pname){
System.out.println("我是重定向");
// redirectAttributes.addAttribute("pname",pname);
redirectAttributes.addFlashAttribute("pname",pname);
return "redirect:/response/test1";
}
注意:重定向携带参数,需要使用对象RedirectAttributes,该对象提供两个方法封装参数 addAttribute()和addFlashAttribute()。
第一个方法参数会明文显示在浏览器地址栏。
第二个方法参数会隐藏,使用第二种方法传参时,获取参数时需要加注解@ModelAttribute;
七、Postman工具使用
(一)介绍
用户在开发或者调试网络程序或者是网页B/S模式的程序的时候是需要一些方法来跟踪网页请求的,用户可以使用一些网络的监视工具比如著名的Firebug等网页调试工具。今天给大家介绍的这款网页调试工具不仅可以调试简单的css、html、脚本等简单的网页基本信息,它还可以发送几乎所有类型的HTTP请求!Postman在发送网络HTTP请求方面可以说是Chrome插件类产品中的代表产品之一。
(二)下载安装
1、下载地址:https://www.postman.com/downloads/
(三)工具的使用
八、SpringMVC中的父子容器解析
Spring和SpringMVC的容器具有父子关系,Spring容器为父容器,SpringMVC为子容器,子容器可以引用父容器中的bean,二父容器不可以引用子容器中的Bean。
- 配置Spring的配置文件时,排除扫描控制层注解:
<context:component-scan base-package="com.offcn">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
- 配置SpringMVC的配置文件时,扫描控制层注解:
<context:component-scan base-package="com.offcn.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
九、SpringMVC中的文件上传
(一)文件上传的必要前提
- form表单的enctype取值必须是:multipart/form-data(默认值是:application/x-www-form-urlencoded)enctype:是表单请求正文的类型。
- method属性取值必须是Post
- 提供一个文件选择域<input type="file"/>
(二)原理分析
当form表单的enctype取值不是默认值后,request。getParameter()将失效。
enctype="application/x-www-form-urlencoded"时,form表单的正文内容是:
key=value&key=value&key=value;
当form表单的enctype取值为Mutilpart/form-data时,请求正文内容就变成:每一部分都是MIME类型描述的正文。
(三)SpringMVC的文件上传
1、构建工程添加相关依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
2、编写jsp页面
<form enctype="multipart/form-data" method="post" action="/file/fileUpload">
<input type="file" name="file">
<input type="submit" value="上传">
</form>
3、编写控制器
@RequestMapping("fileUpload")
public String fileUpload(MultipartFile file){
File dest = new File("C:\\Users\\mwx\\Pictures\\"+file.getOriginalFilename());
//文件上传
try {
file.transferTo(dest);
} catch (IOException e) {
e.printStackTrace();
}
return "main";
}
4、配置文件解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>
十、SpringMVC中的异常处理
(一)异常处理的方式介绍
系统中异常包括两类:预期异常和运行时异常RuntimeException。
前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。
(二)异常处理的设计思路
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理。
(三)异常处理的步骤
1、编写异常类和错误页面
@RequestMapping("test2")
public String test2(){
System.out.println("模拟出现异常");
int i = 10/0;
return "main";
}
2、自定义异常处理器
public class MyExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ex.printStackTrace();
System.out.println("自定义异常处理");
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
return modelAndView;
}
}
3、配置异常处理器
<bean class="com.offcn.util.MyExceptionHandler"></bean>
十一、SpringMVC中的拦截器使用
(一)拦截器的介绍和作用
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理后处理。用户可以自己定义一些拦截器来实现特定的功能。
拦截器链:就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
(二)拦截器与过滤器的区别
过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。拦截器是 SpringMVC 框架自己的,只有使用了SpringMVC框架的工程才能用。过滤器在web.xml中的 url-pattern 标签中配置了/*之后,可以对所有要访问的资源拦截。
(三)自定义拦截器的步骤
1、实现HandlerInterceptor接口
public class MyIntercepter implements HandlerInterceptor {
/**
* 控制层执行器方法前的拦截器
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("我是控制层执行器方法前的拦截器");
//校验用户是否登录
HttpSession session = request.getSession();
String pname=(String)session.getAttribute("pname");
if(pname!=null){
//当前用户已经登录,放行
return true;
}else{
//当前用户未登录,拦截跳转到登录页面
request.getRequestDispatcher("/login.jsp").forward(request,response);
return false;
}
//返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法
}
/**
* 控制层方法返回时拦截器
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {
System.out.println("我是控制层执行器方法返回时拦截器");
}
/**
* 控制层方法结束后的拦截器
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception {
System.out.println("我是控制层执行器方法结束后的拦截器");
}
}
2、配置拦截器
<!--springMVC配置文件中注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/file/login"/>
<bean class="com.offcn.util.MyIntercepter"></bean>
</mvc:interceptor>
</mvc:interceptors>
(四)拦截器的注意事项
1、拦截器的放行
拦截器中的放行指的是:如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
2、拦截器中方法的说明
定义拦截器需要实现HandlerInterceptor接口,该接口中有三个方法:
-
preHandle()方法:
控制层执行器方法前的拦截器(该方法时在控制层执行器方法前调用,当该方法返回结果为true则继续调用下一个拦截器,如果已经是最后一个拦截器,则调用控制层中的执行器方法;当该方法返回结果为false,则不会继续执行控制层执行器中的方法)
-
postHandle()方法
控制层方法返回时拦截器(该方法是控制层执行器方法执行之后,由DispatcherServlet在将结果响应给浏览器前调用的方法)
-
afterCompletion()方法
控制层方法结束后的拦截器(该方法在请求业务处理执行完全结束之后由DispatcherServlet调用执行)
public class MyInterceptor2 implements HandlerInterceptor {
/**
* 控制层执行器方法前的拦截器(该方法时在控制层执行器方法前调用,当该方法返回结果为true则继续调用下一个拦截器,如果已经时最后
* 一个拦截器,则调用控制层中的执行器方法;当该方法返回结果为false,则不会继续执行控制层执行器中的方法)
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("我是控制器方法前拦截器2");
return true;
}
/**
* 控制层方法返回时拦截器(该方法是控制层执行器方法执行之后,由DispatcherServlet在将结果响应给浏览器前调用的方法)
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception{
System.out.println("我是控制层执行器方法返回时拦截器2");
}
/**
* 控制层方法结束后的拦截器(该方法在请求业务处理执行完全结束之后由DispatcherServlet调用执行)
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception {
System.out.println("我是控制层执行器方法结束后的拦截器2");
}
}
3、拦截器的作用路径
<!--拦截器注册-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/><!--用于指定拦截的 url-->
<mvc:exclude-mapping path="/file/login"/><!--用于指定排除的 url-->
<bean class="com.offcn.util.MyIntercepter"></bean>
</mvc:interceptor>
</mvc:interceptors>
4、多个拦截器的执行顺序
(1) 先来顺序执行 所有拦截器的 preHandle方法
(2)如果任何一个拦截器返回false。直接跳出不执行目标方法
- 如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle
- 如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion;
(3)所有拦截器都返回True。执行目标方法
(4)倒序执行所有拦截器的postHandle方法。
(5)前面的步骤有任何异常都会直接倒序触发 afterCompletion
(6)页面成功渲染完成以后,也会倒序触发 afterCompletion
十二、拦截器的简单案例
(一)实现思路分析
1、定义登录页面,并定义请求映射。
2、判断用户名密码是否正确
3、如果正确 向 session 中写入用户信息
4、返回登录成功。
5、拦截用户请求,判断用户是否登录
6、如果用户已经登录。放行
7、如果用户未登录,跳转到登录页面
(二)案例代码
1、登录页面login.jsp定义
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/file/login" method="post">
用户名:<input type="text" name="pname">
密码:<input type="text" name="password">
<input type="submit" value="登录">
</form>
</body>
</html>
2、控制器实现
@RequestMapping("login")
public String login(String pname, String password, HttpSession session){
System.out.println("登录校验成功");
//将登录成功的用户名存放到session中
session.setAttribute("pname",pname);
return "main";
}
3、拦截器实现
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("我是控制层执行器方法前的拦截器");
//校验用户是否登录
HttpSession session = request.getSession();
String pname=(String)session.getAttribute("pname");
if(pname!=null){
//当前用户已经登录,放行
return true;
}else{
//当前用户未登录,拦截跳转到登录页面
request.getRequestDispatcher("/login.jsp").forward(request,response);
return false;
}
//返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法
}
4、注册拦截器
<mvc:interceptor>
<mvc:mapping path="/**"/><!--用于指定拦截的 url-->
<mvc:exclude-mapping path="/file/login"/><!--用于指定排除的 url-->
<bean class="com.offcn.util.MyIntercepter"></bean>
</mvc:interceptor>