一、SpringMVC概况
SpringMVC 也叫 Spring web mvc。是 Spring 框架的一部分,是在 Spring3.0 后发布的。
1、优点
- 基于MVC架构
- 容易理解,上手快,使用简单
- 能够使用spring的IOC和AOP
2、具体实现步骤
1)新建maven web项目
2)导入依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<build>
<plugins>
<!-- 编码和编译和JDK版本 -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
3)注册中央调度器
<servlet>
<servlet-name>myweb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
在tomcat启动后,创建Servlet对象
load-on-startup:表示tomacat启动后创建对象的顺序。它的值是整数,数值越小
tomcat创建的对象越早。
-->
<!--自定义springMVC读取配置文件的位置-->
<init-param>
<!--springMVC配置文件的位置的属性-->
<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可以使用两种值
1.使用扩展名,语法 *.xxx ,xxx是自定义的扩张名。常用的方式 *.do,*.action *.mvc等等
http://localhost:8080/myweb/xxx.do
2.使用斜杠 “/”
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
4)创建SpringMVC配置文件
5)创建处理器
@Controller
public class MyController {
/**
*
* @RequestMapping:请求映射,把指定的请求交给方法处理,一个请求指定一个方法处理
*
* 属性:1. value是一个String,表示请求的URL地址的(some.do)。
* value的值必须是唯一的,不能重复。在使用时,推荐地址以“/ ”
* 位置:1.在方法的上面,常用的
* 2.在类的上面
* 说明:使用RequestMapping修饰的方法叫做处理器方法或者控制器方法。
* 使用@RequestMapping修饰的方法可以处理请求的,类似Servlet中的doGet,doPost
*/
@RequestMapping(value = "/some.do")
public ModelAndView dosome(){ //doGet()
ModelAndView mv = new ModelAndView();
//调用servlet处理请求,把处理结果放入到返回值ModelAndView中
mv.addObject("msg","使用注解的springMVC应用");
mv.addObject("fun","dosome");
mv.setViewName("/show.jsp");
return mv;
}
若有多个请求路径均可匹配该处理器方法的执行,则@RequestMapping 的 value 属性中
可以写上一个数组。
ModelAndView 类中的 addObject()方法用于向其 Model 中添加数据。Model 的底层为一
个 HashMap。
Model 中的数据存储在 request 作用域中,SringMVC 默认采用转发的方式跳转到视图,
本次请求结束,模型中的数据被销毁
6)定义目标页面
在 webapp 目录下新建一个子目录 jsp,在其中新建一个 jsp 页面 show.jsp。
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>show.jsp从request作用域获取数据</h3><br>
<h3>msg数据:${msg}</h3>
<h3>fun数据:${fun}</h3>
</body>
</html>
7)修改视图解析器的注册
<!--声明视图解析器:帮组我们处理视图的路径和扩展名。生成视图对象-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀:表示视图所在的路径-->
<property name="prefix" value="/WEB-INF/jsp"/>
<!--后缀:表示视图文件的扩展名-->
<property name="suffix" value=".jsp"/>
</bean>
3、SpringMVC请求处理流程
上面的过程简化的方式
some.do --> DispatcherServlet --> MyController
1、请求的处理过程
1)执行servlet的service()
protected void service(HttpServletRequest request,HttpServletReponse response)
protected void doService(HttpServletRequest request,HttpServletReponse response)
DispatcherServlet.doDispatch(request,reponse){
调用MyControlller的.doSome()方法
}
二、SpringMVC注解式开发
1、@RequestMapping定义请求规则
1)指定模块名称
通过@RequestMapping 注解可以定义处理器对于请求的映射规则。该注解可以注解在方
法上,也可以注解在类上,但意义是不同的。value 属性值常以“/”开始。
@RequestMapping 的 value 属性用于定义所匹配请求的 URI。但对于注解在方法上与类
上,其 value 属性所指定的 URI,意义是不同的。
2)对请求提交方式的定义
对于@RequestMapping,其有一个属性 method,用于对被注解方法所处理请求的提交
方式进行限制,即只有满足该method属性指定的提交方式的请求,才会执行该被注解方法。
Method 属性的取值为 RequestMethod 枚举常量。常用的为 RequestMethod.GET 与
RequestMethod.POST,分别表示提交方式的匹配规则为 GET 与 POST 提交。
@RequestMapping(value="/some.do",method=RequestMethod.POST)
public ModelAndView some(HttpServletRequest request,HttpServletReponse reponse) throws Exception
客户端浏览器常用的请求方式,及其提交方式
序号 | 请求方式 | 提交方式 |
---|---|---|
1 | 表单请求 | 默认GET,可以指定POST |
2 | Ajax请求 | 默认GET,可以指定POST |
3 | 地址栏请求 | GET请求 |
4 | 超链接请求 | GET请求 |
5 | src资源路径请求 | GET请求 |
- 修改处理器类MyController
@Controller
@RequestMapping("/test")
public class MyController{
@RequestMapping(value="/some.do",method=RequestMethod.POST)
public ModelAndView doSome(HttpServletRequest request,HttpServletReponse reponse) throws Exception{
return new ModelAndView("some");
}
@RequestMapping(value="/other.do",method=RequestMethod.GET)
public ModelAndView doOther(HttpServletRequest request,HttpServletReponse reponse) throws Exception{
return new ModelAndView("other");
}
}
- 修改index页面
<a href="test/some.do">跳转到some页面</a><br>
<a href="test/other.do">跳转到other页面</a><br>
<form action="test/some.do" method="POST">
<input type="submit" value="跳转到some页面"/>
</form>
<br>
<form action="test/other.do" method="POST">
<input type="submit" value="跳转到other页面"/>
</form>
2、处理器方法的参数
- HttpServletRequest
- HttpServletResponse
- HttpSession
- 请求中所携带的请求参数
1)逐个参数接收
- 修改index页面
<form action="test/register.do" method="POST">
姓名:<input type="text" name="name"/>
年龄:<input type="text" name="age"/>
<input type="submit" value="注册"/>
</form>
- 修改处理器类MyController
@Controller
@RequestMapping("/test")
public class MyController{
@RequestMapping(value="/register.do")
public ModelAndView register(String name,int age)
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
mv.setViewName("show");
return mv;
}
- 添加show页面
<body>
name = ${myname}
age = ${age}
</body>
2)解决乱码问题
在 web.xml 中注册字符集过滤器,即可解决 Spring 的请求参数的中文乱码问题。不过,
最好将该过滤器注册在其它过滤器之前。因为过滤器的执行是按照其注册顺序进行的。
<!--注册字符集过滤器:解决post请求乱码问题-->
<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>
<!--强制request使用字符集encoding-->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!--强制使用response使用字符集encoding-->
<init-param>
<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>
3)校正请求参数名@RequestParam
所谓校正请求参数名,是指若请求 URL 所携带的参数名称与处理方法中指定的参数名
不相同时,则需在处理方法参数前,添加一个注解@RequestParam(“请求参数名”),指定请
求 URL 所携带参数的名称。该注解是对处理器方法参数进行修饰的。value 属性指定请求参
数的名称。
- 修改index页面
<form action="test/register.do" method="POST">
姓名:<input type="text" name="rname"/><br>
年龄:<input type="text" name="rage"/><br>
<input type="submit" value="注册"/><br>
</form>
- 修改处理器类MyController
@Controller
public class MyController{
/*
处理器方法的形参前面加入@RequestMapping(value="请求中参数名")
*/
@RequestMapping(value="/some.do")
public ModelAndView doSome(@RequestParam(value="rage") Integer age,@RequestParam(value="rname") String name){
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObjecet("myage",age);
mv.setViewName("show");
return mv;
}
}
- required属性
/*
@RequestParam属性
1.value,请求中参数名
2.required,boolean类型的,默认是true
true:表示请求中必须有参数
false:表示可以没有此参数
*/
@RequestMapping(value="some.do")
public ModelAndView doSome(@RequestParam(value="rage",required=false) Integer age,@RequestParam(value="rname",required=false) String name)
4)对象参数接收
将处理器方法的参数定义为一个对象,只要保证请求参数名与这个对象的属性同名即可。
- 定义类Student
public class Student{
private String name;
private int age;
//getter and setter
//toString
}
- 修改处理器类MyController
@Controller
@RequestMapping("/test")
public class MyController{
@RequestMapping(value="/register.do")
public ModelAndView register(Student student){
ModelAndView mv = new ModelAndView();
mv.addObject("myStudent",student);
mv.setViewName("show");
return mv;
}
}
- 修改shoe页面
<body>
student = ${myStudent}
</body>
3、处理器方法的返回值
使用@Controller 注解的处理器的处理器方法,其返回值常用的有四种类型:
➢ 第一种:ModelAndView
➢ 第二种:String
➢ 第三种:无返回值 void(了解)
➢ 第四种:返回自定义类型对象
1)返回ModelAndView
若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时
处理器方法返回 ModelAndView 比较好。当然,若要返回 ModelAndView,则处理器方法中
需要定义 ModelAndView 对象。
在使用时,若该处理器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何
资源跳转(如对页面的 Ajax 异步响应),此时若返回 ModelAndView,则将总是有一部分多
余:要么 Model 多余,要么 View 多余。即此时返回 ModelAndView 将不合适。
2)返回String
处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址
返回 内部资源逻辑视图名
若要跳转的资源为内部资源,则视图解析器可以使用 InternalResourceViewResolver 内部
资源视图解析器。此时处理器方法返回的字符串就是要跳转页面的文件名去掉文件扩展名后
的部分。这个字符串与视图解析器中的 prefix、suffix 相结合,即可形成要访问的 URI。
-
修改处理器类MyController
@Controller @RequestMapping("/test") public class MyController{ @RequestMapping(value="/register.do") public String register(HttpServletRequest,Student student){ request.setAttribute("myStudent",studnet); return "show"; } }
当然,也可以直接返回资源的物理视图名。不过,此时就不需要再在视图解析器中再配
置前辍与后辍了。@Controller @RequestMapping("/test") public class MyController{ @RequestMapping(value="/register.do") public String register(HttpServletRequest,Student student){ request.setAttribute("myStudent",studnet); return "/WEB-INF/jsp/welcome.jsp"; } }
3)返回void(了解)
对于处理器方法返回 void 的应用场景,AJAX 响应.
若处理器对请求处理后,无需跳转到其它任何资源,此时可以让处理器方法返回 void。
例如,对于 AJAX 的异步请求的响应
- maven加入jackson依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
- 引入jQuery库
使用 jQuery 库文件,需要在使用 ajax()方法的 index 页面中引入。
<meta http-equiv="Content-Type" content="text/html";charset=UTF-8">
<script type="text/javascript" src="js/jquery-1.11.1-min.js"></script>
- 定义index页面
index 页面由两部分内容构成:一个是,用于提交 AJAX 请求;一个是
<script type="text/javascript" src="js/jquery-1.11.1-min.js"></script>
<script type="text/javascript"></script>
$(function(){
$("button").click(function(){
$.ajax({
url:"myajax.do",
data:{
name:"zs",
age:"24",
},
type:"post",
dataType:"json",
success:function(resp){
alert("resp:"+resp.name+" "+resp.age);
}
})
})
})
点击按钮发起请求
<body>
index.jsp
<button>
发起ajax请求
</button>
</body>
-
定义对象Student
public class Student{ //属性名和参数名一样 private String name; private Integer age; //set get }
-
修改处理器类MyController
处理器对于 AJAX 请求中所提交的参数,可以使用逐个接收的方式,也可以以对象的方
式整体接收。只要保证 AJAX 请求参数与接收的对象类型属性同名。 以逐个方式接收参数:
/*
处理器方法方法返回值void,不能表示数据,也没有视图
可以通过使用HttpServletResponse的输出对象,把数据输出到浏览器
*/
@RequestMapping(value="/myajax.do")
public void doSome(Integer age,String name,HttpServletResponse response) throws IOException{
//调用Service处理请求,把处理结果转为一个对象存储
Student student = new Studnet();
student.setName(name);
student.setAge(age);
//使用jackson工具库,把Student专务json
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(student);
System.out.println("json:"+json);
//使用HttpServletResponse输出数据到浏览器
PrintWriter pw = response.getWriter();
pw.print(json);
pw.flush();
pw.close();
}
- 删除视图页面
由于是服务端直接向浏览器发回数据,所以也就无需视图页面了,所以需要删除
WEB-INF 中的 jsp 目录及其中的 show 页面。
4)返回对象Object
处理器方法也可以返回 Object 对象。这个 Object 可以是 Integer,String,自定义对象,
Map,List 等。但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出
现的。
返回对象,需要使用@ResponseBody 注解,将转换后的 JSON 数据放入到响应体中。
- 导入依赖
由于返回 Object 数据,一般都是将数据转化为了 JSON 对象后传递给浏览器页面的。而
这个由 Object 转换为 JSON,是由 Jackson 工具完成的。所以需要导入 Jackson 的相关 Jar 包。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
-
声明注解驱动
将 Object 数据转化为 JSON 数据,需要由消息转换器 HttpMessageConverter 完成。而转
换器的开启,需要由mvc:annotation-driven/来完成。
SpringMVC 使用消息转换器实现请求数据和对象,处理器方法返回对象和响应输出之间
的自动转换
当 Spring 容器进行初始化过程中,在mvc:annotation-driven/处创建注解驱动时,默认
创建了七个 HttpMessageConverter 对象。也就是说,我们注册mvc:annotation-driven/,就
是为了让容器为我们创建 HttpMessageConverter 对象。
<!--注册MVC的注解驱动-->
<mvc:annotation-driven/>
HttpMessageConverter 接口实现类 | 作用 |
---|---|
ByteArrayHttpMessageConverter | 负责读取二进制格式的数据和写出二进制格式的数据 |
StringHttpMessageConverter | 负责读取字符串格式的数据和写出字符串格式的数据 |
ResourceHttpMessageConverter | 负责读取资源文件和写出资源文件数据 |
SourceHttpMessageConverter | 能 够 读 / 写 来 自 HTTP 的 请 求 与 响 应 的javax.xml.transform.Source ,支持 DOMSource,SAXSource, 和 StreamSource 的 XML 格式 |
AllEncompassingFormHttpMessageConverter | 负责处理表单(form)数据 |
Jaxb2RootElementHttpMessageConverter | 使用 JAXB负责读取和写入xml 标签格式的数据 |
MappingJackson2HttpMessageConverter | 负责读取和写入 json 格式的数据。利用Jackson 的 ObjectMapper 读写 json 数据,操作Object 类型数据,可读取 application/json,响应媒体类型为 application/json |
1.返回自定义类型对象
返回自定义类型对象时,不能以对象的形式直接返回给客户端浏览器,而是将对象转换
为 JSON 格式的数据发送给浏览器的。
由于转换器底层使用了Jackson转换方式将对象转换为JSON数据,所以需要导入Jackson
的相关 Jar 包。
- 定义数据类
public class Student{
private String name;
private int age;
//getter and setter
//toString()
}
- 修改处理器类MyController
@Controller
@RequestMapping("/test")
public class MyController{
/*
处理器方法返回一个Student,通过框架爱转为json,响应ajax请求
@ResponseBody:
作用:把处理器方法返回对象转为json后,通过HttpServletResponse输出给浏览器
位置:方法的定义上面,和其他注解没有顺序的关系
返回对象框架的处理流程:
1.框架会把返回Student类型,调用框架中的ArrayList<HttpMessageConverter>中每个类的conWrite()方法检查那个HttpMessageConverter接口的实现类能处理student类型的数据 MappingJackson2HttpMessageConverter
2.框架会调用实现类的write(),MappingJackson2HttpMessageConverter的write()方法把李四的student对象转为json,调用Jackson的ObjectMapper实现转为json
application/json;charset=utf-8
3.框架会调用 @ResponseBody把2的结果数据输出到浏览器,ajax请求处理完成
*/
@RequestMapping(value="/myajax.do")
@ResponseBody
public Student doStudentJson(){
//调用service,获取请求结果数据,Student对象表示结果数据
Student student = new Student();
student.setName("李四")
student.setAge(20);
return student; //会被框架转为json
}
}
- 修改index页面
<script type="text/javascript">
$(function(){
$("button").click(function(){
$.ajax({
url:"test/myajax.do",
success:function(data){
alert(data.name+" "+data.age);
}
});
});
});
</script>
<body>
<button>
提交ajax请求
</button>
</body>
2.返回list集合
- 修改处理器MyController
@Controller
@RequestMapping("/test")
public class MyController{
@RequestMapping(value="/myajax.do")
@ResponseBody
public List<Student> doStudentJson(){
//调用service,获取请求结果数据,Student对象表示结果数据
List<Student> student = new ArraryList<>();
student.add(new Student("张三,22"));
student.add(new Student("李三,22"));
return student; //会被框架转为json
}
}
- 修改index页面
<script type="text/javascript">
$(function(){
$("button").click(function(){
$.ajax({
url:"test/myajax.do",
success:function(data){
$.each(data,function(i,n){
alert(n.name+"===="+n.age)
})
}
});
});
});
</script>
<body>
<button>
提交ajax请求
</button>
</body>
3.返回字符串对象
若要返回非中文字符串,将前面返回数值型数据的返回值直接修改为字符串即可。但若
返 回 的字 符串 中带 有中 文 字符 ,则 接收 方页 面 将会 出现 乱码 。此 时 需要 使用
@RequestMapping 的 produces 属性指定字符集。
produces,产品,结果,即该属性用于设置输出结果类型。
- 修改处理器
/*
处理器方法返回的string,String表示数据的,不是视图。
区分返回值String是数据,还是视图,看有没有@ResponseBody注解,如果有@ResponseBody注解返回
String就是数据,反之就是视图。
默认使用"text/plain;charset=ISO-8859-1"作为contentType,导致中文有乱码
解决方案:给RequestMapping增加一个属性produces,使用这个属性指定新的contentType
*/
@Controller
@RequestMapping("/test")
public class MyController{
@RequestMapping(value="/myajax.do",produces="text/plain;charset=utf-8")
@ResponseBody
public String doText(){
return "HelloSpringMVC使用注解开发";
}
}
- 修改页面
<script type="text/javascript">
$(function{
$("button").click(function(){
$.ajax({
url:"test/myajax.do",
success:function(data){
alert(data)
}
})
})
})
</script>
<body>
<button id="btnAjax">
发起ajax请求
</button>
</body>
4、静态资源访问
的值并不是说写为/后,静态资源就无法访问了。经过一些配置后,该问
题也是可以解决的。
1)使用<mvc:default-servlet-handler/>
声 明 了 <mvc:default-servlet-handler /> 后 , springmvc 框 架 会 在 容 器 中 创 建
DefaultServletHttpRequestHandler 处理器对象。它会像一个检查员,对进入 DispatcherServlet
的 URL 进行筛查,如果发现是静态资源的请求,就将该请求转由 Web 应用服务器默认的
Servlet 处理。一般的服务器都有默认的 Servlet。
在 Tomcat 中,有一个专门用于处理静态资源访问的 Servlet 名叫 DefaultServlet。其
为 default。可以处理各种静态资源访问请求。该 Servlet 注册在 Tomcat 服务
器的 web.xml 中。在 Tomcat 安装目录/conf/web.xml。
只需要在 springmvc.xml 中添加<mvc:default-servlet-handler/>标签即可。
<mvc:default-servlet-handler/>
2) 使用<mvc:resources/> (掌握)
在 Spring3.0 版本后,Spring 定义了专门用于处理静态资源访问请求的处理器
ResourceHttpRequestHandler。并且添加了mvc:resources/标签,专门用于解决静态资源无法访问问题。需要在 springmvc 配置文件中添加如下形式的配置 :
<mvc:resources location="/images/" mapping="/images/**" />
<!--
location:表示静态资源所在的目录。当然,目录不要使用/WEB-INF/及其子目录
mapping:表示对资源的请求(以 /images/开始的请求,如 /images/beauty.jpg,/images/car.png 等)。注意后面是两个星号**
-->
3)声明注解驱动
解决动态资源和静态资源冲突的问题,在 springmvc 配置文件加入:
<!--声明注解驱动-->
<mvc:annotation-driven/>
4)一条配置语句,指定多种静态资源的访问
在webapp下建一个static文件夹并将所有静态资源放在下面,然后在springmvc.xml中配置如下:
<mvc:resource mapping="/static/**" location="/static/" />
5、绝对路径与相对路径
1)在jsp , html中使用的地址,都是在前端页面中的地址,都是相对地址
地址分类:
1.绝对地址,带有协议名称的是绝对地址,http://www.baidu.com,ftp://202.122.23.1
2.相对地址,没有协议开头的,…例如user/some.do.,/user/some .do…
相对地址不能独立使用,必须有一个参考地址。通过参考地址+相对地址本身才能指定资源。
张三同学,1班有张三,2班也有张三
3.参考地址
在你的页面中的,访问地址不加" "
访问的是:http://localhost:8080/ch06 path/index.jsp
路径:http://localhost:8080/ch06 path/
资源:index.jsp
在index.jsp发起user/some .do请求,访问地址变为http://localhost:8080/ch06 path/user/some.do
当你的地址没有斜杠开头,例如user/some.do,当你点击链接时,访问地址是当前页面的地址
加上链接的地址。
http:l/localhost:8080/ch06_path/+ user/some . do
在index.jsp在user/some.do,就变为http://localhost:8080/ch06 path/user/user/some .do
解决方案:
1.加入$ {pageContext.request.contextPath}
2.加入一个base标签,是html语言中的标签。表示当前页面中访问地址的基地址。
你的页面中所有没有w/w开头的地址,都是以base标签中的地址为参考地址
使用base中的地址+ user/some .do组成访问地址
base标签使用:
指定路径:
<%
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/";
%>
指定base标签
<head>
<base href="<%=basePath%>">
<title>title</title>
</head>
2)2)在你的页面中的,访问地址加"/"
访问的是:http://localhost:8080/ch06_path/index.jsp
路径:http://localhost:8080/ch06 path/
资源:index.jsp
点击/user/some.do访问地址变为http://localhost:8080/user/some.do
参考地址是你的服务器地址,也就是http://localhost:8080
如果你的资源不能,加入
p
a
g
e
C
o
n
t
e
x
t
.
r
e
q
u
e
s
t
.
c
o
n
t
e
x
t
P
a
t
h
<
a
h
r
e
f
=
"
{pageContext.request.contextPath} <a href="
pageContext.request.contextPath<ahref="ipageContext.request.contextPath}/user/some.do">发起user/some.do的get请求
三、SSM整合开发
1、概念及其整合流程
SpringMVC:视图层,界面层,负责接收请求,显示处理结果的。
Spring:业务层,管理service,dao,工具类对象的。
MyBatis:持久层, 访问数据库的
用户发起请求–SpringMVC接收–Spring中的Service对象–MyBatis处理数据
SSM整合也叫做SSI (IBatis也就是mybatis的前身), 整合中有容器。
1.第一个容器SpringMVC容器, 管理Controller控制器对象的。
2.第二个容器Spring容器,管理Service,Dao,工具类对象的
我们要做的把使用的对象交给合适的容器创建,管理。 把Controller还有web开发的相关对象
交给springmvc容器, 这些web用的对象写在springmvc配置文件中
service,dao对象定义在spring的配置文件中,让spring管理这些对象。
springmvc容器和spring容器是有关系的,关系已经确定好了
springmvc容器是spring容器的子容器, 类似java中的继承。 子可以访问父的内容
在子容器中的Controller可以访问父容器中的Service对象, 就可以实现controller使用service对象
实现步骤:
0.使用springdb的mysql库, 表使用student(id auto_increment, name, age)
1.新建maven web项目
2.加入依赖
springmvc,spring,mybatis三个框架的依赖,jackson依赖,mysql驱动,druid连接池
jsp,servlet依赖
3.写web.xml
1)注册DispatcherServlet ,目的:1.创建springmvc容器对象,才能创建Controller类对象。
2.创建的是Servlet,才能接受用户的请求。
2)注册spring的监听器:ContextLoaderListener,目的: 创建spring的容器对象,才能创建service,dao等对象。
3)注册字符集过滤器,解决post请求乱码的问题
4.创建包, Controller包, service ,dao,实体类包名创建好
5.写springmvc,spring,mybatis的配置文件
1)springmvc配置文件
2)spring配置文件
3)mybatis主配置文件
4)数据库的属性配置文件
6.写代码, dao接口和mapper文件, service和实现类,controller, 实体类。
7.写jsp页面
2、搭建SSM开发环境
1)导入依赖
<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>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jsp依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2.1-b03</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
2)配置web.xml
<!--注册中央调度器-->
<servlet>
<servlet-name>myweb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--springMVC配置文件的位置的属性-->
<param-name>contextConfigLocation</param-name>
<!--指定自定义文件的位置-->
<param-value>classpath:conf/dispatcherServlet.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>
<!--注册spring的监听器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--注册字符集过滤器-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encodind</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3、SSM整合注解开发
1)建Student表
属性int,name,age
2)导依赖
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jsp 依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2.1-b03</version>
<scope>provided</scope>
</dependency>
<!--springmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!-- 事务的-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--aspectj 依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<!--mybatis 和 和 spring 整合的-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!--mysql 驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
</dependencies>
插件:
<build>
<resources>
<resource>
<directory>src/main/java</directory><!-- 所在的目录-->
<includes><!-- 包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
3)定义包,组织程序的结构
jsp文件
4)编写配置文件
1.jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/springdb
jdbc.name=root
jdbc.password=123456
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--spring配置文件-->
<!--引入配置文件-->
<context:property-placeholder location="classpath:conf/jdbc.properties"/>
<!--配置Druid数据库连接池-->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource"
init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.name}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--注册SqlSessionFactoryBean-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:conf/mybatis.xml"/>
</bean>
<!--声明mybatis的扫描器,创建dao对象-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.hxc.dao"/>
</bean>
<!--声明service的注解@Service所在的包名位置-->
<context:component-scan base-package="com.hxc.service"/>
</beans>
3.springmvc.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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--springMVC配置文件-->
<context:component-scan base-package="com.hxc.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--注意是以mvc结尾的-->
<mvc:annotation-driven/>
<!--
1.响应ajax请求,返回json
2.解决静态资源访问问题
-->
</beans>
4.mybatis.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--设置别名-->
<typeAliases>
<package name="com.hxc.pojo"></package>
</typeAliases>
<!--sql mapper(sql映射文件)的位置-->
<mappers>
<!--
name:是包名,这个包中的所有mapper.xml一次都能加载
使用package的要求
1.mapper文件名和dao接口名必须完全一样,包括大小写
2.mapper文件和dao接口必须在同一目录
-->
<package name="com.hxc.dao"></package>
</mappers>
</configuration>
5)定义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">
<!--注册中央调度器-->
<servlet>
<servlet-name>myweb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!--springMVC配置文件的位置的属性-->
<param-name>contextConfigLocation</param-name>
<!--指定自定义文件的位置-->
<param-value>classpath:conf/dispatcherServlet.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>
<!--注册spring的监听器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--注册字符集过滤器-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encodind</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
6)定义实体类
package com.hxc.pojo;
public class Student {
private int id;
private String name;
private int age;
public Student() {
}
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
7)Dao接口和sql映射文件
public interface StudentDao {
int addStudent(Student student);
List<Student> selectAll();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hxc.dao.StudentDao">
<insert id="addStudent">
insert into springdb.student(name, age) VALUES (#{name},#{age});
</insert>
<select id="selectAll" resultType="Student">
select id,name,age from springdb.student order by id desc ;
</select>
</mapper>
7)Service接口和实现类
public interface StudentService {
int addStudent(Student student);
List<Student> selectAll();
}
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentDao studentDao;
@Override
public int addStudent(Student student) {
return studentDao.addStudent(student);
}
@Override
public List<Student> selectAll() {
return studentDao.selectAll();
}
8)处理器定义
@Controller
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;
@RequestMapping("/addStudent.do")
public ModelAndView addStudent(Student student){
ModelAndView mv = new ModelAndView();
String tips = "注册失败";
//调用service处理student
int nums = studentService.addStudent(student);
if (nums>0){
//注册成功
tips = "学生:"+student.getName()+"注册成功";
}
//添加数据
mv.addObject("tips",tips);
//指定结果页面
mv.setViewName("result");
return mv;
}
//处理查询,响应ajax
@RequestMapping("/listStudent.do")
@ResponseBody
public List<Student> queryStudent(){
List<Student> studentList = studentService.selectAll();
return studentList;
}
9)定义视图-首页文件-index.jsp
//指定路径
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/";
%>
<html>
<head>
<title>首页</title>
<base href="<%=basePath%>"> //指定base标签
</head>
<body>
<div align="center">
<p>SSM整合开发--实现student表的操作</p>
<img src="images/ssm.jpg">
<table>
<tr>
<td><a href="addStudent.jsp">注册学生</a></td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td><a href="listStudent.jsp">查询学生</a></td>
</tr>
</table>
</div>
</body>
</html>
10)注册学生页面–addStudent.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/";
%>
<html>
<head>
<title>addStudent</title>
<base href="<%=basePath%>">
</head>
<body>
<div align="center">
<p>学生注册页面</p>
<form action="student/addStudent.do" method="post">
<table>
<tr>
<td>姓名:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>年龄</td>
<td><input type="text" name="age"></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" value="注册"></td>
</tr>
</table>
</form>
</div>
</body>
</html>
10)浏览学生页面-listStudent.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/";
%>
<html>
<head>
<title>显示页面</title>
<base href="<%=basePath%>">
<script type="text/javascript" src="js/jquery-3.4.1.js"></script>
<script type="text/javascript">
$(function () {
loadStudentData()
$("#btnLoader").click(function () {
loadStudentData()
})
})
function loadStudentData() {
$.ajax({
url:"student/listStudent.do",
type:"get",
dataType:"json",
success:function (data) {
//清除旧数据
$("#info").html("");
//增加新的数据
$.each(data,function (i,n) {
$("#info").append("<tr>")
.append("<td>"+n.id+"</td>")
.append("<td>"+n.name+"</td>")
.append("<td>"+n.age+"</td>")
.append("</tr>")
})
}
})
}
</script>
</head>
<body>
<div align="center">
<table>
<thead>
<tr>
<td>学号</td>
<td>姓名</td>
<td>年龄</td>
</tr>
</thead>
<tbody id="info">
</tbody>
</table>
<input type="button" id="btnLoader" value="查询数据">
</div>
</body>
</html>
四、SpringMVC核心技术
1、请求转发和重定向
1)请求转发
处理器方法返回 ModelAndView 时,需在 setViewName()指定的视图前添加 forward:,且
此时的视图不再与视图解析器一同工作,这样可以在配置了解析器时指定不同位置的视图。
视图页面必须写出相对于项目根的路径。forward 操作不需要视图解析器。
处理器方法返回 String,在视图路径前面加入 forward: 视图完整路径。
/*
处理器方法返回ModelAndView:实现转发到其他的视图页面
语法:setViewName("forward:视图的完整路径")
forward关键字的特点:不和视图解析器一同工作,就当项目中没有视图解析器
*/
@RequestMapping(value="/some.do")
public ModelAndView doSome(Integer age,String name){
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
//forward,显式指定转发操作,forward:视图完整路劲
//mv.setViewName("forword/WEB-INF/view/show.jsp");
mv.setViewName("forward:/other.jsp");
return mv;
}
2)请求重定向
在处理器方法返回的视图字符串的前面添加 redirect:,则可实现重定向跳转
处理器方法的定义:
@RequestMapping(value="/doredirect.do")
public ModelAndView doSome(Integer age,String name){
ModelAndView mv = new ModelAndView();
//指定视图
mv.setViewName("forward:/other.jsp");
//mv.setViewName("forword/WEB-INF/view/show.jsp");
//重定向不能访问受保护的WEB-INF下面的资源
return mv;
}
2、异常处理
异常处理:
springmvc框架采用的是统一,全局的异常处理。
把controller中的所有异常处理都集中到一个地方。采用的是aop的思想。把业务逻辑和异常处理代码分开。解耦合。
1)@ExceptionHandler 注解
使用注解@ExceptionHandler 可以将一个方法指定为异常处理方法。该注解只有一个可
选属性 value,为一个 Class<?>数组,用于指定该注解的方法所要处理的异常类,即所要匹
配的异常。
而被注解的方法,其返回值可以是 ModelAndView、String,或 void,方法名随意,方法
参数可以是 Exception 及其子类对象、HttpServletRequest、HttpServletResponse 等。系统会
自动为这些方法参数赋值。
对于异常处理注解的用法,也可以直接将异常处理方法注解于 Controller 之中。
1.自定义异常类
定义三个异常类:NameException、AgeException、MyUserException。其中 MyUserException
是另外两个异常的父类
public class MyUserException extends Exception{
public MyUserException(){
super();
}
public MyUserException(String message){
super(message);
}
}
public class NameException extends Exception{
public NameException(){
super();
}
public NameException(String message){
super(message);
}
}
public class AgeException extends Exception{
public AgeException(){
super();
}
public AgeException(String message){
super(message);
}
}
2.修改Controller抛出异常
@Controller
public class MyController{
@RequestMapping(value="/some.do")
public ModelAndView doSome(Integer age,String name) throws MyUserException{
ModelAndView mv = new ModelAndView();
if(!"zs".equals(name)){
throw new NameException("姓名不正确!!!");
}
mv.addObject("myname",name);
mv.addObject("myage",age);
mv.setViewName("show");
return mv;
}
}
3.创建全局异常处理类
/*
@ControllerAdvice:控制器增强(也就是说给控制器类增加功能--异常处理功能)
位置:在类的上面
特点:必须让框架知道这个注解所在的包名,需要在sprignmvc配置文件声明组件扫描器
*/
@ControllerAdvice
public calss GlobalExceptionHandler{
/*
处理异常的方法和控制器方法的定义一样,可以有多个参数,可以有ModelAndView,String,void对象类型的返回值
定义方法处理异常,在处理类中定义处理异常的方法
方法的上面加入@ExceptionHanlder
形参:Exception,表示Controller中抛出的异常
通过形参可以获取发送的异常信息
@ExceptionHanlder(异常的class):表示异常的类型,当发生类型异常时由当前方法处理
*/
@ExceptionHanlder(value=NameException.class)
public ModelAndView doNameException(Exception ex){
ModelAndView mv = new ModelAndView();
mv.addObject("tips","处理NameException");
mv.addObject("ex",ex);
mv.setViewName("nameError");
return mv;
}
@ExceptionHanlder(value=AgeException.class)
public ModelAndView doAgeException(Exception ex){
ModelAndView mv = new ModelAndView();
mv.addObject("tips","处理AgeException");
mv.addObject("ex",ex);
mv.setViewName("ageError");
return mv;
}
//处理其他异常,NameException AgeException以外,不知类型的异常
@ExceptionHanlder()
public ModelAndView doOtherException(Exception ex){
//处理其他异常
ModelAndView mv = new ModelAndView();
mv.addObject("tips","处理Exception");
mv.addObject("ex",ex);
mv.setViewName("defautError");
return mv;
}
}
4.定义异常响应页面
<body>
nameError page<br>
${ex.message}
</body>
<body>
ageError page<br>
${ex.message}
</body>
<body>
defaultError page<br>
${ex.message}
</body>
5.定义Spring配置文件
<!--注册组件扫描器
base-package:指定Controller注解所在的包名
-->
<context:component-scan base-package="com.hxc.controller"/>
<!--注册组件扫描器
base-package:指定@ControllerAdvice注解所在的包名
-->
<context:component-scan base-package="com.hxc.handler"/>
<!--注册注解驱动-->
<mvc:annotation-driven/>
3、拦截器
拦截器:
1)拦截器是springmvc中的一种,需要实现HandlerInterceptor接口。
2)拦截器和过滤器类似,功能方向侧重点不同。过滤器是用来过滤器请求参数,设置编码字符集等工作。
拦截器是拦截用户的请求,做请求做判断处理的。
3)拦截器是全局的,可以对多个controller做拦截。
二个项自中可以有o个或多个拦截器,他们在一起拦截用户的请求。
拦截器常用在:用户登录处理,权限检查,记录日志。
拦截器的使用步骤:
1.定义类实现HandlerInterceptor接口.
2.在springmvc配置文件中,声明拦截器,让框架知道拦截器的存在。
拦截器的执行时间:
1)在请求处理之前,也就是controller类中的方法执行之前先被拦截。
2)在控制器方法执行之后也会执行拦截器。
3)在请求处理完成后也会执行拦截器。
1)一个拦截器的执行
//拦截器类:拦截用户的请求。
public class MyInterceptor implements HandlerInterceptor {
private long btime = 0;
/*
* preHandle叫做预处理方法。
* 重要:是整个项目的入口,门户。 当preHandle返回true 请求可以被处理。
* preHandle返回false,请求到此方法就截止。
*
* 参数:
* Object handler : 被拦截的控制器对象
* 返回值boolean
* true:请求是通过了拦截器的验证,可以执行处理器方法。
* 拦截器的MyInterceptor的preHandle()
=====执行MyController中的doSome方法=====
拦截器的MyInterceptor的postHandle()
拦截器的MyInterceptor的afterCompletion()
*
* false:请求没有通过拦截器的验证,请求到达拦截器就截止了。 请求没有被处理
* 拦截器的MyInterceptor的preHandle()
*
*
* 特点:
* 1.方法在控制器方法(MyController的doSome)之前先执行的。
* 用户的请求首先到达此方法
*
* 2.在这个 方法中可以获取请求的信息, 验证请求是否符合要求。
* 可以验证用户是否登录, 验证用户是否有权限访问某个连接地址(url)。
* 如果验证失败,可以截断请求,请求不能被处理。
* 如果验证成功,可以放行请求,此时控制器方法才能执行。
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
btime = System.currentTimeMillis();
System.out.println("拦截器的MyInterceptor的preHandle()");
//计算的业务逻辑,根据计算结果,返回true或者false
//给浏览器一个返回结果
//request.getRequestDispatcher("/tips.jsp").forward(request,response);
return true;
}
/*
postHandle:后处理方法。
参数:
Object handler:被拦截的处理器对象MyController
ModelAndView mv:处理器方法的返回值
特点:
1.在处理器方法之后执行的(MyController.doSome())
2.能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的
数据和视图,可以影响到最后的执行结果。
3.主要是对原来的执行结果做二次修正,
ModelAndView mv = MyController.doSome();
postHandle(request,response,handler,mv);
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler, ModelAndView mv) throws Exception {
System.out.println("拦截器的MyInterceptor的postHandle()");
//对原来的doSome执行结果,需要调整。
if( mv != null){
//修改数据
mv.addObject("mydate",new Date());
//修改视图
mv.setViewName("other");
}
}
/*
afterCompletion:最后执行的方法
参数
Object handler:被拦截器的处理器对象
Exception ex:程序中发生的异常
特点:
1.在请求处理完成后执行的。框架中规定是当你的视图处理完成后,对视图执行了forward。就认为请求处理完成。
2.一般做资源回收工作的, 程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收。
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("拦截器的MyInterceptor的afterCompletion()");
long etime = System.currentTimeMillis();
System.out.println("计算从preHandle到请求处理完成的时间:"+(etime - btime ));
}
1.注册拦截器
<!--注册组件扫描器-->
<context:component-scan base-package="com.hxc.controller"/>
<!--注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.hxc.interceptors.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<mvc:mapping/>用于指定当前所注册的拦截器可以拦截的请求路径,而/**表示拦截所
有请求。
2.修改index页面
<body>
index page
</body>
3.修改处理器
@Controller
@RequestMapping("/test")
public class MyController{
@RequestMapping(value="/some.do")
public ModelAndView doSome(){
System.out.println("执行了处理器方法");
return new ModelAndView("/WEN-INF/jsp/show.jsp");
}
}
4.修改show页面
<body>
show page
</body>
5.控制台输出结果
执行MyInterceptor ----- preHandle()--
执行处理器方法
执行MyInterceptor ----- postHandle()--
执行MyInterceptor ----- afterCompletion()--
2)多个拦截器的执行
1.在定义一个拦截器
public class MyInterceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行MyInterceptor222 ------ preHandle() ---");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("执行MyInterceptor222 ------ postHandle() ---");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("执行MyInterceptor222 ------ afterCompletion() ---");
}
}
2.多个拦截器的注册与执行
<!--注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.hxc.interceptors.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.hxc.interceptors.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
3.控制台输出结果
执行MyInterceptor ----- preHandle()--
执行MyInterceptor222 ----- preHandle()--
执行处理器方法
执行MyInterceptor222 ----- postHandle()--
执行MyInterceptor ----- postHandle()--
执行MyInterceptor222 ----- afterCompletion()--
执行MyInterceptor ----- afterCompletion()--
当有多个拦截器时,形成拦截器链。拦截器链的执行顺序,与其注册顺序一致。需要再
次强调一点的是,当某一个拦截器的 preHandle()方法返回 true 并被执行到时,会向一个专
门的方法栈中放入该拦截器的 afterCompletion()方法。
多个拦截器中方法与处理器方法的执行顺序如下图:
从图中可以看出,只要有一个 preHandle()方法返回 false,则上部的执行链将被断开,
其后续的处理器方法与 postHandle()方法将无法执行。但,无论执行链执行情况怎样,只要
方法栈中有方法,即执行链中只要有 preHandle()方法返回 true,就会执行方法栈中的
afterCompletion()方法。最终都会给出响应。
3)权限拦截器举例
1.修改index页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/";
%>
<html>
<head>
<title>Title</title>
<base href="<%=basePath%>">
</head>
<body>
<p>拦截器</p>
<form action="some.do" method="post">
姓名:<input type="text" name="name"><br>
年龄:<input type="text" name="age"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
2.定义Controller
@Controller
public class MyController {
@RequestMapping(value = "/some.do")
public ModelAndView dosome(String name,Integer age){
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
mv.setViewName("show");
return mv;
}
}
3.定义show页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<body>
<p>我的名字:${myname}</p>
<p>我的年龄:${myage}</p>
</body>
</html>
4.定义权限拦截器
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object attr = request.getSession().getAttribute("name");
String loginName = "";
if (attr != null){
loginName = (String)attr;
}
//判断登陆的账户,是否符合要求
if (!"zs".equals(loginName)){
//不能访问系统
//给用户提示
request.getRequestDispatcher("/tips.jsp").forward(request,response);
}
//zs登陆
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
5.注册权限拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.hxc.handler.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
6.定义login页面
<body>
模拟登陆,zs登录系统
<%
session.setAttribute("name","zs");
%>
</body>
7.定义logout页面
<body>
退出系统,从session中删除数据
<%
session.removeAttribute("name");
%>
</body>
4)拦截器与过滤器的区别
区别 | 过滤器 | 拦截器 |
---|---|---|
对象 | servlet中的对象 | 框架中的对象 |
实现的接口 | 实现Filter接口 | 实现HandlerInterceptor接口 |
作用 | 用来设置request,response的参数、属性。侧重对数据过滤的 | 用来验证请求的,能截断请求 |
谁创建的对象 | tomcat服务器创建的对象 | springmvc容器中创建的对象 |
执行点 | 一个 | 三个 |
处理对象 | jsp js html等 | 侧重拦截Controller的对象,如果你的请求不能被DispatcherServlet接收,这个请求不会被执行拦截器内容 |
执行对象 | 普通方法执行 | 过滤servlet请求响应 |
}
//判断登陆的账户,是否符合要求
if (!"zs".equals(loginName)){
//不能访问系统
//给用户提示
request.getRequestDispatcher("/tips.jsp").forward(request,response);
}
//zs登陆
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
###### 5.注册权限拦截器
```xml
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.hxc.handler.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
6.定义login页面
<body>
模拟登陆,zs登录系统
<%
session.setAttribute("name","zs");
%>
</body>
7.定义logout页面
<body>
退出系统,从session中删除数据
<%
session.removeAttribute("name");
%>
</body>
4)拦截器与过滤器的区别
区别 | 过滤器 | 拦截器 |
---|---|---|
对象 | servlet中的对象 | 框架中的对象 |
实现的接口 | 实现Filter接口 | 实现HandlerInterceptor接口 |
作用 | 用来设置request,response的参数、属性。侧重对数据过滤的 | 用来验证请求的,能截断请求 |
谁创建的对象 | tomcat服务器创建的对象 | springmvc容器中创建的对象 |
执行点 | 一个 | 三个 |
处理对象 | jsp js html等 | 侧重拦截Controller的对象,如果你的请求不能被DispatcherServlet接收,这个请求不会被执行拦截器内容 |
执行对象 | 普通方法执行 | 过滤servlet请求响应 |