本笔记是根据颜群老师的课程所学习的springMVC,用于个人回忆。
Servlet发展史:Pure Servlet->Structs->SpringMVC
要做servlet:除了导入5个关键jar外,还需要一个spring-mvc.jar
第一个SpringMVC程序
本demo通过jsp作为前台演示,
a.导包,创建springmvc.xml 勾选常用的命名空间
普通Servlet流程: 请求->url-pattern->交给对应的servlet去处理
如果现在想用springMVC 而不是普通的Servlet 如何告知程序
?
答案就是配置一个SpringMVC-web自带的一个Servlet 这个Servlet就是大名鼎鼎的DispatcherServlet
b.编写web.xml中的拦截器【配置DispatcherServlet】
<!-- 通过以下配置,拦截所有请求,交给SpringMVC处理 -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定mvc文件位置 -->
<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>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--默认xml可以放在Web-Context中,命名方式为xxx-servlet.xml-->
c. 编写SpringMVC’s servlet : org.taroballs.handler.SpringMVCHandler.java
package org.taroballs.handler;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/*
* 之前讲过,一个普通的类要变成一个特定功能的类,有4种办法:1.实现接口 2.继承类 3.通过注解 4.通过配置
* SpringMVC中可以通过后面两种方法【注解/配置】实现
*/
@Controller //注释,表明该类不是普通类,而是个控制器
//【此时有注解->需要在springmvc.xml中将当前所在包放入扫描器中】
public class SpringMVCHandler {
@RequestMapping("/welcome") //拦截welcome请求
public String welcome() {
return "success"; //由于添加了前缀和后缀解析器 所以会返回到/view/success.jsp中
}
}
又因为此时是通过注解@Controller,所以需要在springmvc.xml中将当前所在包放入扫描器中
编写springmvc.xml
<!-- 因为有注解,所以配置一个扫描器,扫描有注解的包 -->
<context:component-scan base-package="org.taroballs.handler"></context:component-scan>
再配置一个视图解析器
<!-- 配置视图解析器() InternalResourceViewResolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
d.编写index.jsp 以及 view/success.jsp
<!-- index.jsp -->
<a href="welcome">click here!</a>
<!-- view/success.jsp -->
<body>
Welcome to SpringMVC.
</body>
demo完成,有几个【小细节】提一下
a.web.xml中的servlet-mapping如何区分是普通Servlet还是MVCServlet
(了解即可)
对于 | SpringMVC | 普通Servlet |
---|---|---|
url-pattern区分 | ".action"交由其处理 | 无".action"交由其处理 |
识别区分后,找谁? | 找@RequestMapping()映射 | 找@WebServlet() |
b.默认约定SpringMVC配置文件 存放在WebContent,名为springDispatcherServlet-servlet.xml或者xxx-servlet.xml中
,也可以显示使用<init-param>
指定xml文件位置
c. 注解@RequestMapping
可以写在方法上面,也可以写在类上面 - 写在类上面表示先通过RequestMapping找到该类,再通过@RequestMapping找到该类对应的方法
即:响应的MVCServelet是通过请求路径匹配RequestMapping中的地址 所找到的
@Controller
@RequestMapping("SpringMVCHandler")
public class SpringMVCHandler {
@RequestMapping("/welcome")
public String welcome() {
return "success";
} //写在方法和类上面
}
//访问地址为: /SpringMVCHandler/welcome
映射是 去匹配@RequestMapping注解
,可以和方法名、类名 不一致
f.return "success"跳转默认采用“请求转发”的方式进行页面跳转
,如何手动设置这一模块:【指定请求方式】
请求转发 | 重定向 |
---|---|
return “forward:/view/success.jsp” | redirect:/view/success.jsp |
注意此种手动配置方式,不会被视图解析器加上前缀/view和后缀.jsp
e.ant风格路径通配符的请求路径
ant风格的请求路径 如@RequestMapping(“welcome/**/test”) | |
---|---|
? | 单字符 |
* | 任意个字符(0或多个) |
** | 任意目录 |
基于ant的@PathVariable获取动态参数
/*ant风格的请求路径
* ? 单字符 * 任意多个或一个 **任意目录
*/
@RequestMapping(value = "welcome/*/testRestful")
public String welcomeRestful() {
return "success";
}
<!-- index.jsp -->
测试Restful请求风格
<a href="handler/welcome/restfultesttestasssss/testRestful">点击测试Restful请求风格</a>
使用HiddenHttpMethodFilter过滤器:实现put|delete请求方式
原本请求方式只有get/post,我们设置
- 通过过滤器之后,包含四种请求方式
- 即其他两种请求方式通过过滤器实现
我们约定一个隐藏域来进行拦截:
- 对于一般的请求我过滤器并不拦截
- 如果这个请求满足以下条件–>进行拦截
<input type="hidden" name="_method" value="delete/put">
- 请求方式为post
- type=“hidden”
- name="_method"
- 这个过滤器SpringMVC已经写过了HiddenHttpMethodFilter
a.增加过滤器
<!-- web.xml -->
<!-- 配置HiddenHttpMethodFilter过滤器:目的是给普通浏览器增加put|delete请求方式 -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
b.编写表单
测试带Rest风格的增删改查
<!-- 当请求方式为post 且
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_method" value="PUT">
包含隐藏域
即可通过过滤器器使用DELTE/PUT请求方法
-->
<form action="handler/testRestful/1234" method="post" >
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="增">
</form>
<form action="handler/testRestful/1234" method="post" >
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="删">
</form>
<form action="handler/testRestful/1234" method="post" >
<input type="submit" value="改">
</form>
<form action="handler/testRestful/1234" method="get" >
<input type="submit" value="查">
</form>
c.编写Handler:匹配具体的请求方式
//测试:通过过滤器器使用DELTE/PUT请求方法
@RequestMapping(value = "testRestful/{id}",method = RequestMethod.PUT)
@ResponseBody
public String testP(@PathVariable("id") Integer id) {
System.out.println("PUT:增"+id); //调用Service层 实现真正的Dao
return "restful";
}
@RequestMapping(value = "testRestful/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String testDelete(@PathVariable("id") Integer id) {
System.out.println("DELETE:删"+id); //调用Service层 实现真正的Dao
return "restful";
}
@RequestMapping(value = "testRestful/{id}",method = RequestMethod.POST)
public String testPost(@PathVariable("id") Integer id) {
System.out.println("POST:改"+id); //调用Service层 实现真正的Dao
return "restful";
}
@RequestMapping(value = "testRestful/{id}",method = RequestMethod.GET)
public String testGet(@PathVariable("id") Integer id) {
System.out.println("GET:查"+id); //调用Service层 实现真正的Dao
return "restful";
}
此外,可以发现,当映射名相同时 @RequestMapping(value = "testRestful/{id}",method = RequestMethod.POST)
,可以通过不同的method参数 接收处理不同的请求方式。
从过滤器处理put|delete请求的部分源码和打断点续步的方式我们也可以看出这个一过程
通过@RequestParam接收前台传递的值
<!-- 前台index.jsp -->
通过@RequestParam前台传值给SpingMVC
<form action="handler/testParams" method="post" >
name:<input type="text" name="name" ></br>
age:<input type="text" name="age" ></br>
<input type="submit" value="传值">
</form>
控制器中
//测试:接受前台传递的值
@RequestMapping(value = "testParams")
public String testParam(@RequestParam("name")String name,@RequestParam(value = "age",required = false,defaultValue ="24") Integer age) {
// 以前用原生Servlet的获取参数值得方法:String name = request.getParameters("name");
System.out.println("当前改学生的姓名为:"+name+",年龄为:"+age);
return "ParamResult";
}
获取请求头信息@RequestHeader
<a href="handler/getRequestHeader">@RequestHeader获取请求头信息</a>
//测试:获取请求头信息
@RequestMapping(value = "getRequestHeader")
public String getRequestHeader(@RequestHeader("Accept-Language") String AL,@RequestHeader("Accept") String AC) {
System.out.println(AL+","+AC);
return "success";
}
获取请求的JESSIONCookie@CookieValue
<a href="handler/getJESSIONCookie">@CookieValue获取请求Cookie</a>
//测试:获取请求的JESSIONCookie
@RequestMapping(value = "getJESSIONCookie")
public String getJESSIONCookie(@CookieValue("JSESSIONID") String JSESSIONID) {
System.out.printl