SpringMVC注解开发
SpringMVC常用注解
1、@Controller
功能:标注控制器类,被标注的类将作为业务控制器被核心控制器搜索。
使用方法:将@Controller添加到类定义前
注意:
@Controller 标记在一个类上还不能真正意义上的说它就是SpringMVC 的一个控制器类,因为这个时候Spring 还不认识它。这个时候就需要我们把这个控制器类交给Spring 来管理。
- 使用注解的配置方法:在springmvc配置文件中添加
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.hcz"/>
<mvc:annotation-driven/>
解释:
com.hcz为控制器所在包,核心控制器会从该包及其子包中查找匹配的控制器。
< mvc:annotation-driven/>:用于注册处理器映射器与处理器适配器两个bean,springMVC通过这2个bean来完成对注解的支持。
2、@RequestMapping定义请求规则
(1)指定模块名称(value属性)
- 一个@Controller 所注解的类中,可以定义多个处理器方法。当然,不同的处理器方法所匹配的 URI 是不同的。这些不同的 URI 被指定在注解于方法之上的@RequestMapping 的 value 属性中。
- @RequestMapping 该注解可以注解在方法上,也可以注解在类上,但意义是不同的。总的来说,要访问处理器的指定方法,必须要在方法指定 URI 之前加上处理器类前定义的模块名称
@RequestMapping:该注解在类的上面使用时
value:所有请求地址的公共部分,叫做模块名称
@RequestMapping:该类的处理器方法上面使用时
value:请求映射
例如:
- 这里可以通过地址http://localhost:8080/springmvc/test/addUser.do可以访问处理器中的addUser方法
- 同理通过地址http://localhost:8080/springmvc/test/removeUser.do可以访问处理器中的removeUser方法
@Controller
@RequestMapping(value = "/test")
public class MyController {
@RequestMapping(value = "/addUser.do")
public ModelAndView addUser(){
ModelAndView mv = new ModelAndView();
mv.addObject("zs","张三");
mv.addObject("lisi","李四");
//当配置了视图解析器
mv.setViewName("show");
//返回视图
return mv;
}
@RequestMapping(value = "/remove.do")
public ModelAndView removeUser(){
ModelAndView mv = new ModelAndView();
mv.addObject("zs","删除张三");
mv.addObject("lisi","删除李四");
mv.setViewName("show");
return mv;
}
}
(2)对请求提交方式的定义(method属性)
- 对于@RequestMapping,其有一个属性 method,用于对被注解方法所处理请求的提交
方式进行限制,即只有满足该 method 属性指定的提交方式的请求,才会执行该被注解方法。 - Method 属性的取值为 RequestMethod 枚举常量。常用的为 RequestMethod.GET 与
RequestMethod.POST,分别表示提交方式的匹配规则为 GET 与 POST 提交 - 客户端浏览器常用的请求方式,及其提交方式有以下几种:
- 也就是说,只要指定了处理器方法匹配的请求提交方式为 POST,则相当于指定了请求发送的方式:要么使用表单请求,要么使用 AJAX 请求。其它请求方式被禁用。
- 当然,若不指定 method 属性,则无论是 GET 还是 POST 提交方式,均可匹配。即对于请求的提交方式无要求。
例如:
修改处理器类如下:
@Controller
@RequestMapping(value = "/test")
public class MyController {
//指定addUser.html使用get请求方式
@RequestMapping(value = "/addUser.do",method = RequestMethod.GET)
public ModelAndView addUser(){
ModelAndView mv = new ModelAndView();
mv.addObject("zs","张三");
mv.addObject("lisi","李四");
//当配置了视图解析器
mv.setViewName("show");
//返回视图
return mv;
}
//指定remove.html使用post请求方式
@RequestMapping(value = "/remove.do",method = RequestMethod.POST)
public ModelAndView removeUser(){
ModelAndView mv = new ModelAndView();
mv.addObject("zs","删除张三");
mv.addObject("lisi","删除李四");
mv.setViewName("show");
return mv;
}
//指定update.html没有限制请求方式
@RequestMapping(value = "/update.do")
public ModelAndView updateUser(){
ModelAndView mv = new ModelAndView();
mv.addObject("zs","更新张三");
mv.addObject("lisi","更新李四");
mv.setViewName("show");
return mv;
}
}
修改index页面如下:
<body>
<a href="test/addUser.do">添加用户(使用get请求方式)</a><br>
<form action="test/remove.do" method="post">
<input type="submit" value="删除用户(使用post请求方式)">
</form>
<a href="test/update.do">更新用户get(没有限制请求方式)</a><br>
<form action="test/update.do" method="post">
<input type="submit" value="更新用户post(使用post请求方式)">
</form>
</body>
3、请求映射方式
1、根据请求方式进行映射
@RequestMapping注解除了可以根据请求的URL进行映射外,还可以根据请求方式进行映射。如果想根据请求方式进行映射,可通过设置method属性来实现。
2、Ant风格的URL路径映射
- Ant风格的URL支持3种通配符:
- ? : 匹配文件名中的一个字符
- * : 匹配文件名中的任意多个字符(至少有一个字符)
- ** : 匹配多层路径(至少有一层)
@RequestMapping支持Ant风格的URL:
@RequestMapping("/user/create??") :匹配/user/createAA、/user/createBB等URL (??匹配任意两个字符)
@RequestMapping("/user/*/createUser"):匹配/user/aaa/createUser、/user/bbb/createUser等URL (*匹配任意字符)
@RequestMapping("/user/**/createUser"):匹配/user/createUser、/user/aaa/bbb/createUser等URL (**匹配任意多层路径)
注意:其 ? 和 * 必须要有,如果为空,则不符合
4、处理器方法的参数
- 处理器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,即程序员可在方法内直接使用。
- HttpServletRequest
- HttpServletResponse
- HttpSession
- 映射URL绑定的占位符到方法入参
- 绑定请求参数到控制器方法参数
- 用户提交的数据 1)逐个接收 2)对象接收
(1) 映射URL绑定的占位符到方法入参
使用 @PathVariable注解可以将URL中的占位符绑定到控制器方法的入参中
- 请求:
<a href="../pathVariable/1">Path Variable</a>
- 注解:
@RequestMapping(value="/pathVariable/{id}")
public String pathVariable(@PathVariable("id") Integer id)
(2)绑定请求参数到控制器方法参数
在URL中通过 ? 传递参数,在控制器方法中通过 @RequestParam注解获取传递的参数,通过 @RequestParam注解的 value 属性指定参数名,required 属性指定参数是否必须,默认为 true,表示请求参数中必须包含对应的参数,如果不存在,则抛出异常。
- 请求:
<a href="../requestParam?loginName=admin&loginPwd=123456">Request Param</a>
- 注解:
@RequestMapping("/requestParam")
public String requestParam(@RequestParam(value="loginName") String loginName,
@RequestParam(value="loginPwd") String loginPwd){
(3)将请求参数绑定到控制器方法的表单对象
1)逐个参数接收(参数名一样)
- 只要保证请求参数名与该请求处理方法的参数名相同即可
例如:
A、修改index页面
<p>提交参数给Controller</p>
<form action="test/submit.do" method="post">
姓名:<input type="text" name="name"><br>
年龄:<input type="text" name="age"><br>
<input type="submit" value="提交参数">
</form>
B、修改处理器类方法
@RequestMapping(value = "/submit.do",method = RequestMethod.POST)
public ModelAndView addUser(String name,Integer age){
System.out.println("name="+name+"age="+age);//name=zs age=null
//可以在方法中直接使用name,age
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
//当配置了视图解析器
mv.setViewName("show");
//返回视图
return mv;
}
注意:
在提交请求参数时,使用POST方式提交请求中文有乱码,需要使用过滤器处理乱码问题
解决方案:
- 在 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>
<!--强制请求对象(HttpServletRequest)使用encoding编码的值-->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!--强制请求对象(HttpServletResponse)使用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>
源码分析:
- 字符集设置核心方法:
2)逐个参数接收(参数名不一样)
- 所谓校正请求参数名,是指若请求 URL 所携带的参数名称与处理方法中指定的参数名不相同时,则需在处理方法参数前,添加一个注解@RequestParam(“请求参数名”),指定请求 URL 所携带参数的名称。
@RequestParam:解决请求中参数名不一样的问题
属性:
1、value 请求中的参数名称
2、required是一个boolean,默认是true,表示请求中必须包含此参数,false 表示可以没有此参数
例如:
A、修改index页面
<p>提交参数名和控制器中的形参名不一样</p>
<form action="test/requestParam.do" method="post">
姓名:<input type="text" name="rname"><br>
年龄:<input type="text" name="rage"><br>
<input type="submit" value="提交参数">
</form>
B、修改处理器类方法
@RequestMapping(value = "/requestParam.do")
public ModelAndView requestParam(@RequestParam(value = "rname",required = false)String name,
@RequestParam(value = "rage",required = false) Integer age){
System.out.println("name="+name+"age="+age);//name=zs age=null
//可以在方法中直接使用name,age
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
//当配置了视图解析器
mv.setViewName("show");
//返回视图
return mv;
}
3)对象参数接收
- 将处理器方法的参数定义为java对象,只要保证请求参数名与这个对象的属性同名即可。
例如:
A、定义Student类
public class Student {
/**
* 属性名和请求中参数名一致
*/
private String name;
private Integer age;
//这里省略set、get方法
}
B、修改index页面
<p>使用Java对象接收请求参数</p>
<form action="test/receiveObject.do" method="post">
姓名:<input type="text" name="name"><br>
年龄:<input type="text" name="age"><br>
<input type="submit" value="提交参数">
</form>
C、修改处理器类方法
/**
* 处理器方法形参是Java对象,这个对象的属性名和请求中参数名不一样
* 请求中参数是name,框架会调用setName()方法给属性赋值
*
*/
@RequestMapping(value = "/receiveObject.do")
public ModelAndView receiveObject(Student student){
System.out.println("name="+student.getName()+",age="+student.getAge());
//可以在方法中直接使用name,age
ModelAndView mv = new ModelAndView();
mv.addObject("myname",student.getName());
mv.addObject("myage",student.getAge());
mv.addObject("mystudent",student);
//当配置了视图解析器
mv.setViewName("show");
//返回视图
return mv;
}
5、处理器方法的返回值
- 使用@Controller 注解的处理器的处理器方法,其返回值常用的有四种类型:
- 第一种:ModelAndView
- 第二种:String
- 第三种:无返回值 void
- 第四种:返回自定义类型对象
(1)返回ModelAndView
- 若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据,此时处理器方法返回 ModelAndView 比较好。
(2)返回String
- 处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址。
/**
* 处理返回结果String:表示逻辑视图名称,需要配置视图解析器
* @param name
* @param age
* @return
*/
@RequestMapping(value = "/returnString-view.html")
public String doReturnView(HttpServletRequest request,String name, Integer age){
System.out.println("name="+name+",age="+age);
request.setAttribute("myname",name);
request.setAttribute("myage",age);
//show:逻辑视图名称,项目中配置了视图解析器
return "show";
}
/**
* 不配置视图解析器的情况
*/
@RequestMapping(value = "/returnString-view2.html")
public String doReturnView2(HttpServletRequest request,String name, Integer age){
System.out.println("name="+name+",age="+age);
request.setAttribute("myname",name);
request.setAttribute("myage",age);
//完整视图路径,项目中不能配置视图解析器,否则会出现404错误
return "/WEB-INF/jsp/show.jsp";
}
6、解读< url-pattern>
(1)*.do
在没有特殊要求的情况下,SpringMVC 的中央调度器 DispatcherServlet 的< url-pattern/ >
常使用后辍匹配方式,如写为*.do 或者 *. action, *. mvc 等。
(2)/
可以写为 /,因为 DispatcherServlet 会将向静态资源的获取请求,例如 . css、. js、. jpg、. png 等资源的获取请求,当作是一个普通的 Controller 请求。中央调度器会调用处理器映射器为其查找相应的处理器。当然也是找不到的,所以在这种情况下,所有的静态资源获取请求也均会报 404 错误
7、静态资源的访问
http://localhost:8080/ch05_url_pattern/index.jsp :tomcat(jsp会转为servlet)
http://localhost:8080/ch05_url_pattern/js/jquery-3.4.1.js : tomcat
http://localhost:8080/ch05_url_pattern/images/p1.jpg : tomcat
http://localhost:8080/ch05_url_pattern/html/test.html: tomcat
http://localhost:8080/ch05_url_pattern/some.do : DispatcherServlet(springmvc框架处理的)
tomcat本身能处理静态资源的访问, 像html, 图片, js文件都是静态资源< url-pattern/ >的值并不是说写为 / 后,静态资源就无法访问了。经过一些配置后,该问题也是可以解决的。
(1)使用< mvc:default-servlet-handler/ >
- 声 明 了 < mvc:default-servlet-handler /> 后 , springmvc 框 架 会 在 容 器 中 创 建DefaultServletHttpRequestHandler 处理器对象。它会像一个检查员,对进入 DispatcherServlet 的 URL 进行筛查,如果发现是静态资源的请求,就将该请求转由 Web 应用服务器默认的Servlet 处理。一般的服务器都有默认的 Servlet。
- 在 Tomcat 中,有一个专门用于处理静态资源访问的 Servlet 名叫 DefaultServlet。在 Tomcat 中,有一个专门用于处理静态资源访问的 Servlet 名叫 DefaultServlet。
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern> 表示静态资源和未映射的请求都这个default处理
</servlet-mapping>
default这个servlet作用:
1、处理静态资源
2、处理未映射到其它servlet的请求
只需在springmvc配置文件中添加< mvc:default-servlet-handler/ >标签即可
<!-- 声明注解驱动-->
<mvc:annotation-driven />
<!--第一种处理静态资源的方式:
需要在springmvc配置文件加入 <mvc:default-servlet-handler>
原理是: 加入这个标签后,框架会创健控制器对象DefaultServletHttpRequestHandler(类似我们自己创建的MyController).
DefaultServletHttpRequestHandler这个对象可以把接收的请求转发给 tomcat的default这个servlet。
-->
<mvc:default-servlet-handler />
注意:
default-servlet-handler 和 @RequestMapping注解有冲突, 需要在springmvc中加入注解驱动 annotation-driven 解决问题
(2)使用< mvc:resources/ >
mvc:resources 加入后框架会创建 ResourceHttpRequestHandler这个处理器对象。让这个对象处理静态资源的访问,不依赖tomcat服务器。
mapping:访问静态资源的uri地址, 使用通配符 **
location:静态资源在你的项目中的目录位置
images / ** :表示
images/p1.jpg , images/user/logo.gif , images/order/history/list.png
配置形式:
<mvc:resources mapping="/images/**" location="/images/" />
<mvc:resources mapping="/html/**" location="/html/" />
<mvc:resources mapping="/js/**" location="/js/" />
<!--mvc:resources和@RequestMapping有一定的冲突-->
<mvc:annotation-driven />
<!--使用一个配置语句,指定多种静态资源的访问-->
<mvc:resources mapping="/static/**" location="/static/" />
目录位置: