依赖
SpringMVC属于Spring框架里的web模块,因此导包时,不仅要导入SpringWeb模块的包,还要导入核心包。
配置文件
web.xml
- 配置DispatcherServlet,给DispatcherServlet配置springmvc配置文件的位置。如果不指定的话,会从/WEB-INF目录下寻找springmvc配置文件的位置。
springmvc.xml
- 开启包扫描
- 配置视图解析器
开始
- 新建一个类,打上@Controller注解,告诉SpringMVC这是一个控制器。
- 新建一个方法,打上@RequestMapping注解,用来处理一个url的请求。
- 通过return一个字符串的方式,可以转发到一个新的页面。
- 通过配置视图解析器,可以实现SpringMVC自动将返回值和前后缀进行拼串。
controller:
@Controller
public class MyFirstController {
@RequestMapping("/hello")
public String helloWorld(){
System.out.println("收到请求,正在处理");
return "success";
}
}
--------------------------------------------------------------------
springmvc.xml:
RequestMapping
可以打在类定义上,也可以打在方法上。当打在类定义上时,表示为类中所有映射路径添加了一个基准路径。例:
@Controller
@RequestMapping("/hello")
public class RequestMappingTestController {
@RequestMapping("/world")
public String helloWorld(){
System.out.println("Hello World");
return "helloworld";
}
}
此时要访问helloWorld方法的路径是应该"/hello/world"
PS:
- 这里的RequestMapping里的路径即使不加上"/",访问路径也是"/hello/world",因为类定义上的RequestMapping添加的是基准路径,而不是字符串拼接。
RequestMapping的其他属性:
- method:规定访问的请求方式(GET、POST等)
- params:规定请求的参数
- params="param"请求参数必须带有param
- params="!param"请求参数不能带有param
- params="param=xxx"请求参数必须带有param,且值必须为xxx
- params="param!=xxx"请求参数不能为xxx,不带param参数,或者param!=xx都可以
- params={"param1=xxx","param2"}多个规则
- headers:规定请求头
@RequestMapping(value = "/world02",headers = "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36")
public String testHeaders(){
return "success";
}
这段代码规定了只接受来自谷歌浏览器的请求
ANT风格的URL
通过"?"、"*"、"**"来实现url的模糊匹配。
?:匹配任意一个字符
*:匹配0或多个字符,亦或是一层路径
**:匹配多层路径
PS:当多个url都匹配时,更加精确的优先
精确匹配 >> ?匹配 >> *匹配 >> **匹配
@PathVariable获取路径上的占位符
通过在路径上使用占位符{变量名},可以在方法的参数上打上@PathVariable来获取到占位符上的变量。
@RequestMapping("/{id}")
public String testPathVariable(@PathVariable("id")String id){
System.out.println(id);
return "success";
}
Rest风格的URL
以往风格的url:
- /getBook?id=1
查询书籍 - /addBook
添加书籍 - /deleteBook?id=1
删除书籍 - /updateBook?id=1&info1=xxx&info2=xxx
更新书籍
REST风格的url:
- /book/1 get方式
查询书籍 - /book post方式
添加书籍 - /book/1 delete方式
删除书籍 - /book/1 put方式
更新书籍
REST风格的特点:
以简洁的url来提交请求,以提交请求的方式来处理资源。
存在的问题:
页面只能发送get和post请求
解决方法:
在post表单中添加"_method"的参数,通过配置HiddenHttpMethodFilter过滤器,
来实现从post方式到指定方式的转化。
Controller配置:
-----------------------------------------------------------------------------
@RequestMapping(value = "/book/{id}",method = RequestMethod.GET)
public String getBook(@PathVariable("id")Integer id){
System.out.println("查询了" + id + "号图书!");
return "success";
}
@RequestMapping(value = "/book",method = RequestMethod.POST)
public String addBook(){
System.out.println("添加了图书!");
return "success";
}
@RequestMapping(value = "/book/{id}",method = RequestMethod.DELETE)
public String deleteBook(@PathVariable("id")Integer id){
System.out.println("删除了" + id + "号图书!");
return "success";
}
@RequestMapping(value = "/book/{id}",method = RequestMethod.PUT)
public String updateBook(@PathVariable("id")Integer id){
System.out.println("更新了" + id + "号图书!");
"success";
}
-----------------------------------------------------------------------------
jsp页面:
-----------------------------------------------------------------------------
查询1号图书
-----------------------------------------------------------------------------
web.xml配置:
-----------------------------------------------------------------------------
HiddenHttpMethodFilter
org.springframework.web.filter.HiddenHttpMethodFilter
HiddenHttpMethodFilter
/*
PS:
高版本tomcat在将PUT或者DELETE请求转发给jsp页面时,会提示PUT和DELETE请求不支持,这时要在jsp声明添加属性isErrorPage="true"。
<%@ page language="java" contentType="text/html; utf-8"
pageEncoding="utf-8" isErrorPage="true" %>
Controller获取参数的方式
1. 直接在方法上定义名字和页面传来参数一样的入参。
public String testParam(String username){
System.out.println("参数为:" + username);
return "success";
}
如上的方法,能接受名为username的参数。
- 当页面带来的参数有值时,username的值即为那个值。
- 当页面传来的参数无值时(username=),username的值为空。
- 当页面传来的参数不包含username时,username为null。
2. 通过@RequestParam来获取指定名字的参数。
@RequestMapping("/paramtest")
public String testParam(@RequestParam("user") String username){
System.out.println("参数为:" + username);
return "success";
}
如上的方法,能接受名为user的参数
@RequestParam有以下参数:
- value:即接受的参数的名字
- name:即value,value和name互为别名,且只能同时指定一个。
- required:是否是必要的,默认为true,即不带指定参数时报错。
- defaultValue:默认值,即不带user时,提供的默认值。
PS:@RequestParam和@PathVariable的区别:
- @RequestParam:是从请求的参数里取的值
- @PathVariable:是从请求地址的占位符里取得值
- 两者都不能从对方的域中取值。
3. 通过@RequestHeader来获取请求头中的参数。
@RequestMapping("/headertest")
public String testHeader(@RequestHeader("User-Agent") String userAgent){
System.out.println("使用的浏览器是" + userAgent);
return "success";
}
如上方法可以获取请求头中User-Agent的信息。
@RequestHeader包含的参数和@RequestParam相同。
- value:报文头中的参数
- name:即value,value和name互为别名,且只能同时指定一个。
- required:是否是必要的,默认为true,即不带指定参数时报错。
- defaultValue:默认值,即不带指定参数时,提供的默认值。
4. 通过@CookieValue来获取请求头中的参数。
@RequestMapping("/cookietest")
public String testCookie(@CookieValue(value = "JSESSIONID", required = false, defaultValue = "123")String jid){
System.out.println("Cookie中的jid为" + jid);
return "success";
}
如上方法可以获取Cookie中JSESSIONID的值
@CookieValue参数和上面的相同。
5. 自动封装传入的参数为POJO
当设置请求的参数为POJO时,SpringMVC会尝试封装POJO的每一个属性,甚至是级联的属性,只要在表单设置好每个参数的名字,SpringMVC就能自动封装为POJO。当传入参数找不到POJO里的属性时,该属性就无法赋值。
Controller:
---------------------------------------------------------------
@RequestMapping(value = "/book",method = RequestMethod.POST)
public String addBook(Book book){
System.out.println(book);
return "success";
}
---------------------------------------------------------------
Book类:
---------------------------------------------------------------
public class Book {
private String bookName;
private String author;
private Double price;
private Address address;
}
---------------------------------------------------------------
Address类:
---------------------------------------------------------------
public class Address {
private String province;
private String city;
}
---------------------------------------------------------------
页面表单:
---------------------------------------------------------------
5. servlet原生API的使用
只要在Controller方法的入参声明了,就可以在方法内直接使用。
@RequestMapping("/originalapi")
public String usingOriginalApi(HttpServletRequest request,
HttpServletResponse response, HttpSession session){
request.setAttribute("message", "this is request");
session.setAttribute("message", "this is session");
return "show";
}
如上,在入参声明了HttpServletRequest、HttpServletResponse、HttpSession就可以直接在方法内使用了。
6. 解决中文乱码问题
- get请求乱码
通过在tomcat的server.xml配置文件中,配置URIEncoding="UTF-8"来解决get请求的乱码。
- post请求乱码
其他请求因为也是从post请求包装来的,因此处理方法与post相同。解决方法如下:
通过配置SpringMVC自带的CharacterEncodingFilter过滤器来解决乱码问题。
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
CharacterEncodingFilter
/*
源码中对这段转换的操作是这样的
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (this.encoding != null && (this.forceEncoding ||
request.getCharacterEncoding() == null)) {
request.setCharacterEncoding(this.encoding);
if (this.forceEncoding) {
response.setCharacterEncoding(this.encoding);
}
}
filterChain.doFilter(request, response);
}
PS:
这里要注意的是,如果同时也配置了HiddenHttpMethodFilter,一定要将CharacterEncodingFilter配置在HiddenHttpMethodFilter前面(先对请求进行编码转换),自己配置的时候就是因为这个问题导致乱码的问题无法解决。
我个人的理解是,在经过HiddenHttpMethodFilter包装后,被转发的不在是原本的request了,而此时对原本的request再进行编码转换是没有用的。
百度到的解释
这是因为(至少在tomcat里)
- request对象的parameter并不是一开始就解析的,它是等你第一次调用“getParameter*等凡是 一切和获得请求参数有关的方法的时候才解析的
- paramter一旦被解析过一次,那就不会再次被解析
- 所以如果在CharacterEncodingFilter之前有另外一个filter,而这个filter调用了getParameter()方法,那么 就有可能使用错误的encoding来解析,从而曹成乱码问题。
http://ju.outofmemory.cn/entry/133399