SpringMVC学习笔记
1.1SpringMVC基本说明
SpringMVC是基于spring的,是spring中的一个模块,做web开发使用的,SpringMVC又叫做spring web mvc 说明他是spring的核心技术,做web开发,SpringMVC内部使用的是mvc架构模式。
SpringMVC是一个容器,管理对象的,使用IoC核心技术。SpringMVC管理界面层中的控制器对象。
SpringMVC底层也是Servlet。以Servlet为核心,接受请求,处理请求,显示处理结果给用户。
处理用户的请求:
用户发起请求-----SpringMVC-----Spring----MyBatis----mysql数据库
什么是MVC
1.2SpringMVC中的核心Servlet---DispatchServlet
DispatcherServlet是框架的一个Servlet对象,负责接收请求,响应处理结果
DispatcherServlet的父类是HttpServlet
DispatcherServlet也叫作前端控制器(front controller)
SpringMVC是管理控制器对象,原来没有SpringMVC之前使用Servlet作为控制器对象使用,现在通过SpringMVC容器创建一种叫做控制器的对象,代替Servlet行使控制器的角色,功能。
1.3第一个SpringMVC
步骤:
1.maven中新建web应用
2.加入web依赖
spring-webmvc依赖(springmvc框架依赖),servlet依赖。
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.12</version>
</dependency>
3.声明SpringMVC核心对象DispatcherServlet
1)DispatcherServlet是一个Servlet对象
2)DispatcherServlet叫做前端控制器(front controller)
3)DispatcherServlet作用:
1.在servlet的init()方法中,创建SpringMVC中的容器对象。
2.作为servlet,接受请求。
<!--在web.xml中声明-->
<servlet>
<servlet-name>myweb</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>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myweb</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<load-on-startup>标签的作用:标记是否在web服务器(这里用的是Tomcat)启动时是否创建这个Servlet实例,即是否在Web服务器启动时调用执行该Servlet的init()方法,而不是在真正访问时才创建。
其中它里面的数值必须是一个整数
当其中的值大于0时,表示容器在启动时就加载并初始化这个servlet,数值越小,该Servlet的优先级越高,其被创建的也就越早
当值小于0时或者没有被指定时,则表示该Servlet在真正被使用的时候才会被创建。
当两个值相同时,容器会自己选择创建顺序
4.创建一个jsp,发起请求
<%
5.创建一个普通的类,作为控制器使用(代替之前的Servlet)
1)在类的上面加入@Controller注解
@Controller:创建控制器(处理器)对象
控制器:叫做后端控制器(back controller),自定义的类处理请求的。
使用位置:在类的上面,表示创建此类的对象,对象放在SpringMVC容器中
2)在类中定义方法,方法的上面加入@RequestMapping注解
方法处理请求的,相当于servlet的doGet,doPost
@RequestMapping:(当在类上面使用时)
属性value:表示所欲请求地址的公共前缀,相当于是模块名称。
使用位置:在类的上面。
@RequestMapping:(当在方法上面使用时)
属性value:表示把指定的请求交给方法处理。
@RequestMapping:表示当前方法为处理器方法。该方法要对 value 属性所指定的 URI 进行处理与响应。被注解的方法的方法名可以随意。
若有多个请求路径均可匹配该处理器方法的执行,则@RequestMapping 的 value 属性中 可以写上一个数组。
ModelAndView 类中的 addObject()方法用于向其 Model 中添加数据。Model 的底层为一 个 HashMap。
Model 中的数据存储在 request 作用域中,SringMVC 默认采用转发的方式跳转到视图, 本次请求结束,模型中的数据被销毁。
6.创建作为结果的jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
7.创建SpringMVC的配置文件(和spring的配置文件一样)
1)声明组件扫描器,指定@Controller注解所在的包名
2)声明视图解析器对象。
8.使用逻辑视图名称。
1.4web开发中配置文件的说明
1.web.xml部署描述文件,给服务器(tomcat)
作用:服务器在启动的时候,读取web.xml,根据文件中的声明创建各种对象,根据文件中的声明,知道请求和servlet等对象的关系。
2.框架的配置文件,SpringMVC的配置文件
作用:声明框架创建项目中的各种对象,主要是创建Controller对象的,
配置文件的加载顺序和功能:
1.tomcat服务器启动,读取web.xml,根据web.xml文件中的说明,创建对象。
<servlet>
<servlet-name>myweb</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>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myweb</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
创建DispatcherServlet对象,会执行init()方法,在init()方法中会执行SpringMVC容器对象创建WebApplicationContext ctx=new ClassPathXMLApplicationContext(“classpath:springmvc.xml”)
2.springmvc框架,new ClassPathXMLApplicationContext()读取SpringMVC的配置文件。
<context:component-scan base-package="com.hao"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
使用组件扫描器base-package="com.hao.controller",遍历Controller包中的所有类,找到相关类中的@Controller,@RequestMapping注解,就能创建其对象。并执行相关方法。
1,2两步都是项目启动的过程,没有执行任何的用户请求
3.用户发起请求some.do----DispatcherServlet
DispatcherServlet里面有WebApplicationContext,WebApplicationContext里面有MyController对象,请求相关方法,DispatcherServlet就知道是MyController处理的。
其中MyController是自己创建的类,里面有@controller,@RequestMapping注解。
SpringMVC注解式开发
2.1RequestMapping注解的使用
属性:value 请求的uri地址
属性:1)在方法上面,必须的。2)在类的上面作为模板名称
属性method请求的方式,使用RequestMethod类的枚举,表示请求方式。
2.2接收请求中的参数
对于HttpServletRequest,HttpServletResponse,HttpSession只需要在控制器方法的形参列表中定义就可以了,框架会给参数赋值,在控制器方法内部可以直接使用request,response,session参数。
接收请求中的参数:逐个接收,对象接收
2.2.1 逐个接收
逐个接收:请求中的参数名和控制器方法的形参名一样,按照名称对象接收参数。
参数接收:
1.框架使用request对象,接收参数
String name=request.getParameter(“name”);
2.在中央调度器的内部调用相关方法时候,按名称对象传递参数。
<form action="/some.do" method="post">
姓名:<input type="text" name="name"/><br>
年龄:<input type="text" name="age"/><br>
<input type="submit" value="提交"/>
</form>
但是当请求中参数名和形参名不一样时,则得不到自己想要的值
这时候要加注解:@RequestParam,
属性值:value 请求中的参数名称
requierd:boolean类型的,
默认是true,请求中必须由此参数,否则会报错。
当时false时,表示请求中可以没有参数。
位置:在形参定义的前面
2.2.2请求参数中文乱码问题
如果获取参数的方法为post的话,如果参数中有中文,则会出现中文乱码问题,Spring对于请求参数中的中文乱码问题,给出了专门的字符集过滤器。
解决方案:
在web.xml中注册字符集过滤器,即可解决Spring的请求参数的中文乱码问题,不过,最好将该过滤器注册在其他过滤器之前,因为过滤器的执行是按照其注册顺序进行的。
相关代码:
<filter>
<filter-name>characterEncodingFilter</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>
<init-param>
<!--强制请求(request)对象使用encoding的编码方式-->
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<!--强制应答(response)对象使用的encoding的编码方式-->
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
接收参数的问题:
1.参数最好使用包装类型,例如Integer,能接收空值情况,接收的是null
2.框架可以使用String到int,long,float,double等类型装换
3.post请求中有乱码的问题,使用字符集过滤器。
2.2.3对象接收
对象接收:在控制器方法的形参是java对象,使用java对象的属性接收请求中的参数值
要求:java对象的属性名和请求中参数名一样。
框架的处理步骤:
1.调用Student的无参数构造方法,创建对象
2.调用对象set方法,同名的参数,调用对应的set方法,参数是name,则调用setName(参数值)。
例子:
//实体类
package com.hao.entity;
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//Controller
<!--首页-->
<form action="/some2.do" method="post">
姓名:<input type="text" name="name"/><br>
年龄:<input type="text" name="age"/><br>
<input type="submit" value="提交"/>
</form>
2.3控制器方法的返回值
控制器方法的返回值表示本次请求的处理结果,返回值有ModelAndView,String,void,Object
请求的处理结果包含:数据和视图
2.3.1ModelAndView数据和视图
请求的结果有数据和视图,使用ModelAndView最方便
数据:存放request作用域
视图:执行forward转发操作。
2.3.2 String视图
框架的返回值是String,执行的是forward转发操作,视图可以表示为完整试图路径,或者视图的逻辑名称。
视图解析器:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
2.3.3void 没有数据和视图
void:没有数据和视图,可以使用HttpServletResponse对象输出数据,响应ajax请求
<script type="text/javascript" src="js/jquery-3.4.1.js"></script>
<script type="text/javascript">
$(function (){
$("#btnAjax").on("click",function(){
$.ajax({
url:"return-void-ajax.do",
data:{
name:"张三",
age:11
},
dataType:"json",
success:function (resp){
alert("rest===="+resp.name+resp.age);
}
})
})
})
</script>
2.3.4Object
控制器方法返回对象Object,用来响应ajax请求。返回对象Object,可以使List,Student,Map,String,Integer....这些都是数据,而ajax请求需要的就是数据,在ajax请求中,一般需要从服务器返回的是json格式的数据,经常要处理java对象到json的转换,而且还需要输出数据响应ajax请求,框架提供了处理java对象到json转换,和数据输出工作。
2.3.4.1HttpMessageConverter消息转换器
HttpMessageConverter接口,
作用
1)实现请求的数据转为java对象,
2)把控制器方法返回的对象转为json,xml,text,二进制等不同格式的数据。
2.3.4.2@ResponseBody
@ResponseBody注解的作用,就是把student转换后的json通过HttpServletResponse对象输出给浏览器
//输出json,响应ajax
response.setContentType("application/json;charset=utf-8");
PrintWriter pw=response.getWriter();
pw.println(json);
pw.flush();
pw.close();
2.3.4.3控制器方法返回对象转为json的步骤
1)pom.xml加入jackson依赖,springmvc框架,默认处理json就是使用jackson
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.0</version>
</dependency>
2)在springmvc的配置文件中,加入注解驱动的标签mvc:annotation-driven
<mvc:annotation-driven/>
<!--注意此注解属于: xmlns:mvc="http://www.springframework.org/schema/mvc"-->
3)在控制器方法的上面加入@ResponseBody注解,表示返回值数据,输出到浏览器。
4)首页
<script type="text/javascript" src="js/jquery-3.4.1.js"></script>
<script type="text/javascript">
$(function (){
$("#btnAjax").on("click",function(){
$.ajax({
//url:"return-void-ajax.do",
url:"doStudentJson.do",
data:{
name:"张三",
age:11
},
dataType:"json",
success:function (resp){
alert("rest===="+resp.name+resp.age);
}
})
})
})
</script>
<button id="btnAjax">发起Ajax请求</button>
框架的处理模式:
1.框架根据控制其方法的返回值类型,找到HttpMessageConverter接口的实现类,最后找到的是MappingJackson2HttpMessageConverter,
2.使用实现类MappingJackson2HttpMessageConverter,执行他的write()方法,把student对象转为了json格式的数据
3.框架使用@ResponseBody注解,把2中的json输出给浏览器。
2.3.4.4控制器方法返回list对象转为json的步骤
1)pom.xml加入jackson依赖,springmvc框架,默认处理json就是使用jackson
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.0</version>
</dependency>
2)在springmvc的配置文件中,加入注解驱动的标签mvc:annotation-driven
<mvc:annotation-driven/>
<!--注意此注解属于: xmlns:mvc="http://www.springframework.org/schema/mvc"-->
3)在控制器方法的上面加入@ResponseBody注解,表示返回值数据,输出到浏览器。
4)首页
<script type="text/javascript" src="js/jquery-3.4.1.js"></script>
<script type="text/javascript">
$(function (){
$("#btnAjax").on("click",function(){
$.ajax({
//url:"return-void-ajax.do",
//url:"doStudentJson.do",
url:"doStudentArray.do",
data:{
name:"张三",
age:11
},
dataType:"json",
/* success:function (resp){
alert("rest===="+resp.name+resp.age);
}*/
success:function (resp){
$.each(resp,function (i,n){
alert("n name:"+n.name+"age:"+n.age);
})
}
})
})
})
</script>
<button id="btnAjax">发起Ajax请求</button>
2.3.4.3控制器方法返回对象为string文本数据解决乱码
在@RequestMapping中加入produces属性即可解决乱码问题:
第三章
相对路径
在页面中,有路径的问题,访问路径有“/"开头的,还有没有”/“开头的。
<a href="test/some.do">没有斜杠开头的</a>
<a href="/test/some.do">有斜杠开头的</a>
<a href="http://www.baidu.com">有协议开头的地址</a>
地址的区别:
1)有协议开头的例如http://www.baidu.com,称为绝对地址,地址是唯一的,可以直接访问的
2)没有协议开头的,例如test/some.do , /test/some.do称为相对地址,相对地址单独使用不能表示某个资源,不能访问。相对地址必须和参考地址在一起,才能表示一个资源的完整地址,才可以访问。
没有“/”开头的,多次点击可能出现页面未找到的现象,解决方法为在路径前面加上${pageContext.request.contextPath}/
<a href="test/some.do">没有斜杠开头的</a>
解决方式:
第一种:<a href="${pageContext.request.contextPath}/test/some.do">没有斜杠开头的</a>
优点:好理解
缺点:每个链接地址,都需要加el表达式
第二种:固定当前页面中没有“/”开头地址的参考地址,使用html中的base标签。
<%
String basePath=request.getScheme()+"://" + request.getServerName()+":" +request.getServerPort()+request.getContextPath()+"/";
%>
<head>
<base href="<%=basePath%>"/>
</head>
有“/”开头的地址,参考地址是服务器地址,也就是从协议开始到端口号的位置,地址缺少访问路径。
解决方式:在路径的前面加el表达式${pageContext.request.contextPath}
SpringMVC核心技术
请求重定向和转发
转发(forward)
控制器方法返回时ModelAndView实现转发forward
语法:mv.setViewName("forward:视图完整路径")
forward特点:不和视图解析器一同工作,就当项目中没有视图解析器
forward语句可以用在需要访问视图解析器以外的前端页面时。
重定向redirect
控制器方法返回时ModelAndView实现重定向redirect
语法:modelAanView.setViewName("redirect:视图完整路径")
redirect特点:不和视图解析器一同工作,就当项目中没有视图解析器。
框架提供的重定向的功能:
1.框架可以事项两次请求之间的数据传递,把第一个请求中的Model里面简单类型的数据,转为字符串,附加到目标页面的后面,做get参数传递,可以在目标页面中获取参数值的使用。
2.在目标页面中,可以使用${param.参数名},获取参数的值。
重定向redirect不能访问受保护的目录(即/WEB-INF),而forward可以。
异常处理
框架使用的是集中地异常处理,把各个Controller中抛出的异常集中到一个地方处理,处理异常的叫做异常处理器
框架中使用两个注解完成异常的集中处理,这样每个Controller就不用单独处理异常了,这两个注解分别是:
1)@ExceptionHandler:放在方法的上面,表示此方法可以处理某个类型的异常,当异常发生时,执行这个方法。
2)@ControllerAdvice:放在类的上面,表示这个类中有异常的处理方法,相当于aop中的@Aspect。@ControllerAdvice看作是控制器增强,就是给Conroller类增加异常(切面)的处理功能。
拦截器
拦截器:是SpringMVC框架中的一种对象,需要实现接口HandlerInterceptor,拦截用户的请求,拦截到controller的请求。
作用:拦截用户的请求,可以预先对请求做处理,根据处理结果,决定是否执行controller,也可以把多个controller中共用的功能定义到拦截器
特点:
1.拦截器可以分为系统拦截器和自定义拦截器
2.一个项目可以有多个拦截器,0个或者多个自定义拦截器
3.拦截器侧重拦截用户的请求
4.拦截器是在请求处理之前先执行的。
一个拦截器
拦截器的定义:
1)创建类实现拦截器接口HandlerInterceptor,实现接口中的方法(3个)
public class MyInterceptor implements HandlerInterceptor {
/*
preHandle:预先处理请求的方法。
参数:Object handler:被拦截的控制器对象(MyController)
返回值:Boolean
true:表示请求是正确的,可以被controller处理
false:请求不能被处理,控制器方法不会执行。只执行preHandle方法,请求到此截止。
特点:
1.执行时间:在控制器方法之前先执行的
2.可以对请求做处理,可以做登录的检查,权限的判断,统计数据等等。
3.决定请求是否执行。
*/
2)在SpringMVC配置文件中,声明拦截器对象,并指定拦截的url地址。
<!--声明拦截器-->
<mvc:interceptors>
<!--声明第一个拦截器-->
<mvc:interceptor>
<!--指定拦截器的拦截地址
/**代表拦截所有地址
-->
<mvc:mapping path="/**"/>
<!--指定要使用的拦截器-->
<bean class="com.hao.handler.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
控制器相关的代码为:
当preHandle的返回值为true时候,其执行结果为:
preHandle执行了 执行了MyController中的doSome方法 postHandle执行了 afterCompletion执行了
请求的执行顺序为:用户发起请求---preHandle---控制器中的方法---postHandle---afterCompletion
当preHandle的返回值为false时候,其执行结果为:
preHandle执行了
多个拦截器
使用两个拦截器,主要看拦截器的执行顺序,以及哪个方法控制请求的执行。
使用多个拦截器的作用:
1.把验证功能分散到独立的拦截器,每个拦截器做单一的验证处理
2.组合多个拦截器
总结:多个拦截器,串在一个链条上,多个拦截器和一个控制对象在一个链条上,框架中使用HandlerExecutionChain(处理器执行链)表示这个执行链条。
当有多个拦截器时,形成拦截器链。拦截器链的执行顺序,与其注册顺序一致。需要再 次强调一点的是,当某一个拦截器的 preHandle()方法返回 true 并被执行到时,会向一个专 门的方法栈中放入该拦截器的 afterCompletion()方法。即无论执行链执行情况怎样,只要 方法栈中有方法,即执行链中只要有 preHandle()方法返回 true,并被执行到时候,就会执行方法栈中的 afterCompletion()方法。最终都会给出响应。
拦截器和过滤器的对比
-
拦截器是SpringMVC框架中的对象,过滤器是servlet中的对象
-
拦截器对象是框架容器创建的,过滤器对象是tomcat创建的对象
-
拦截器是侧重对请求做判断的,处理的,可以截断请求,过滤器是侧重对request,response对象的属性,参数设置值的,例如request.setCharacterEncoding(“utf-8”)
-
拦截器的执行时间有三个,分别是控制器方法之前,之后,请求完成后,过滤器的执行时间都是在请求之前。
-
拦截器是拦截对controller,动态资源请求的,过滤器可以过滤所有请求,包括动态的和静态的
-