※ 基于注解的SpringMVC
1)用于支持注解的配置
使用基于注解的配置可以省略很多操作,更方便。我们之前所看到的所有的xml配置,如果替换成基于注解只需要在spring的xml文件中做如下配置:
<mvc:annotation-driven/>
在Spring中,
处理器列可以使用 @Controller注解
业务逻辑层可以使用 @Service注解
数据持久层可以使用 @Repository注解
如果在处理器上使用 @Controller注解,那么还需要在配置文件中指定哪个包下面的类使用了该注解:
<context:component-scan base-package="com.briup.web.controller"></context:component-scan>
2)基于注解的Controller
使用注解后,就不需要再实现特定的接口,任意一个javaBean对象都可以当做处理器对象,对象中任意一个方法都可以作为处理器方法。
只需
在类上加上 @Controller注解
方法上加上 @RequestMapping注解
即可
例如:
web.xml中:
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-web-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
src下面的spring-web-mvc.xml中:
<mvc:annotation-driven/>
<context:component-scan base-package="com.briup.web.controller"></context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
自定义的Controller中:
@Controller
public class HomeController {
@RequestMapping("/home")
public ModelAndView home(){
ModelAndView mv = new ModelAndView("index");
return mv;
}
}
如上代码,使用 @Controller表明HomeController类是一个处理器类,
通过 @RequestMapping("/home")表明当url请求名为/home时,调用home方法执行处理,
当处理完成之后返回ModelAndView对象。因为在spring-web-mvc.xml中配置了视图解析器的前缀和后缀,所以最后视图home.jsp被返回
3)基于注解的Controller的返回值
1.返回ModelAndView,和之前一样
2.返回String,表示跳转的逻辑视图名字,模型可以通过参数传过来
@Controller
public class HomeController {
@RequestMapping("/home")
public String home(Model model){
model.addAttribute("msg", "hello world");
return "index";
}
}
3.声明返回类型为void
可以通过参数获取request和response,分别使用服务器内部跳转和重定向,自己来决定要跳转的位置。
@Controller
public class HomeController {
@RequestMapping("/home")
public void home(HttpServletRequest request,HttpServletResponse response){
String username = request.getParameter("username");
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("hello world! "+username);
//或者使用servlet的方式进行跳转/重定向
}
}
配置文件:
<?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:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 对springMVC中注解的支持
识别注解 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 扫描注解的类有哪些 -->
<context:component-scan
base-package="com.briup.web.annotation"></context:component-scan>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 返回页面(视图)
path指的是项目名字后面的资源名称
view-name 逻辑视图名,前提:当前配置了
视图解析器
没有视图解析器,物理视图的路径名字
-->
<mvc:view-controller path="/login" view-name="login"/>
<!-- 对静态资源的处理
SpringMVC处理xx.js,xxx.css,xxx.png等资源不做
二次拦截
-->
<mvc:default-servlet-handler/>
</beans>
注解Controller:
package com.briup.web.annotation;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/*
* @Controller表示控制器
*/
@Controller
public class HomeController {
//http://localhost:8888/jd1812_MVC/home
/*@RequestMapping对应的
* 就是资源名称
*/
@RequestMapping("/home")
public ModelAndView test(){
ModelAndView mv=
new ModelAndView();
System.out.println("home.......");
mv.setViewName("hello");
return mv;
}
@RequestMapping("/home1")
public ModelAndView test1(HttpServletRequest req,HttpServletResponse res){
try {
PrintWriter pw=res.getWriter();
pw.println("test...");
pw.flush();
pw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/*
* 方法的返回值是String类型
* 返回值表示视图
* spring文件配置视图解析器
* 返回视图是逻辑视图名子
* spring文件没有配置视图解析器
* 返回视图是物理视图名子
*/
@RequestMapping("/home2")
public String test2(){
return "hello";
}
@RequestMapping("/home3")
public String test3(Model model){
model.addAttribute("name", "jake...ok");
return "hello";
}
@RequestMapping("/home4")
public void test4(HttpServletResponse res){
try {
PrintWriter pw=
res.getWriter();
pw.println("tom...ok");
pw.flush();
pw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
※ .Spring2.5中引入注解对处理器(headler)支持
@Controller
用于标识是处理器类;
@RequestMapping
请求到处理器功能方法的映射规则;
@RequestParam
请求参数到处理器功能处理方法的方法参数上的绑定;
@ModelAttribute
请求参数到命令对象的绑定;
@SessionAttributes
用于声明session 级别存储的属性,放置在处理器类上,通常列出模型属性(如@ModelAttribute)对应的名称,则这些属性会透明的保存到session 中
@InitBinder
自定义数据绑定注册支持,用于将请求参数转换到命令对象属性的对应类型;
※.Spring3引入了更多的注解,其中包含了对RESTful架构风格的支持
@CookieValue
cookie数据到处理器功能处理方法的方法参数上的绑定;
@RequestHeader
请求头数据到处理器功能处理方法的方法参数上的绑定;
@RequestBody
请求的body体的绑定
@ResponseBody
处理器功能处理方法的返回值作为响应体
@ResponseStatus
定义处理器功能处理方法/异常处理器返回的状态码和原因;
@ExceptionHandler
注解式声明异常处理器;
@PathVariable
请求URI 中的模板变量部分到处理器功能处理方法的方法参数上的绑定,从而支持RESTful架构风格的URI;
※ .Spring3中引入的mvc命名空间
mvc这个命名空间是在Spring3中引入的,其作用是用来支持mvc的配置
需要在<bean>中声明出这个命名空间及其对应的schemaLocation中的值
<mvc:annotation-driven>
自动注册基于注解风格的处理器和适配器:
在spring2.5中是DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter
在spring3中是RequestMappingHandlerMapping和RequestMappingHandlerAdapter.
同时还支持各种数据的转换器.
<mvc:interceptors>
配置自定义的处理器拦截器,例如:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<ref bean="handlerInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
<mvc:view-controller>
收到相应请求后直接选择相应的视图,例如:
<mvc:view-controller path="/hello" view-name="test"></mvc:view-controller>
<mvc:resources>
逻辑静态资源路径到物理静态资源路径的对应.例如:
<mvc:resources mapping="/images/**" location="/images/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:default-servlet-handler>
当在web.xml中DispatcherServlet使用<url-pattern>/</url-pattern> 映射的时候,
会静态资源也映射了,如果配置了这个mvc标签,那么再访问静态资源的时候就转交给默认的Servlet来响应静态文件,否则报404 找不到静态资源错误。
spring配置:
<?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:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 对springMVC中注解的支持
识别注解 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 扫描注解的类有哪些 -->
<context:component-scan
base-package="com.briup.web.annotation"></context:component-scan>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 返回页面(视图)
path指的是项目名字后面的资源名称
view-name 逻辑视图名,前提:当前配置了
视图解析器
没有视图解析器,物理视图的路径名字
-->
<mvc:view-controller path="/login" view-name="login"/>
<!-- 对静态资源的处理
SpringMVC处理xx.js,xxx.css,xxx.png等资源不做
二次拦截
-->
<mvc:default-servlet-handler/>
</beans>
※ .@Controller和@RequestMapping注解
1) 声明处理器
@Controller
public class HelloWorldController {
}
2) 映射处理器中的【功能处理方法】
@Controller
public class HelloWorldController {
@RequestMapping("/home")
public ModelAndView home(){
ModelAndView mv = new ModelAndView("index");
return mv;
}
}
表明该方法映射的url路径为/home
3) @RequestMapping也可以写在处理器类上
@RequestMapping("/test")
@Controller
public class HomeController {
@RequestMapping("/home")
public ModelAndView home(){
ModelAndView mv = new ModelAndView("index");
return mv;
}
}
表明该方法映射的url路径为/test/home
注意:功能处理方法的方法可以是String类型,表示逻辑视图的名字,可以不用返回ModelAndView对象(见上面测试)
例如:
@Controller
public class HelloWorldController {
@RequestMapping("/home")
public String home(){
return "index";
}
}
※ .请求映射
假设浏览器发送了一个请求如下:
-------------------------------
POST /login HTTP1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,en;q=0.8,zh;q=0.5,en-US;q=0.3
Connection: keep-alive
Cookie: JSESSIONID=DBC6367DEB1C024A836F3EA35FCFD5A2
Host: 127.0.0.1:8989
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
username=tom&password=123
--------------------------------
http协议的请求格式如下:
---------------------------------
请求方法 URL 协议版本号
请求头信息
请求头信息
请求头信息
..
回车换行
请求正文
---------------------------------
从格式中我们可以看到【请求方法、URL、请求头信息、请求正文】这四部分一般是可变的,
因此我们可以把请求中的这些信息在处理器的【功能处理方法】中进行的映射,因此请求的映射分为如下几种:
URL路径映射
使用URL映射到处理器的功能处理方法;
请求方式映射限定
例如限定功能处理方法只处理GET请求;
请求参数映射限定
例如限定只处理包含username参数的请求;
请求头映射限定
例如限定只处理"Accept=application/json"的请求。
※ .URL路径映射
1) 普通URL路径映射
@RequestMapping(value="/test")
@RequestMapping("/hello")
注解中只出现一个参数且参数名为value的话,可以将参数名去掉
@RequestMapping(value={"/test", "/user/hello"})
多个URL路径可以映射到同一个处理器的功能处理方法。
2) URI模板模式映射
@RequestMapping(value="/users/{userId}")
{XXX}占位符, 请求的URL可以是"/users/123456"或"/users/abcd",之后可以通过@PathVariable可以提取URI模板模式中的{XXX}中的值
@RequestMapping(value="/users/{userId}/create")
这样也是可以的,请求的URL可以是"/users/123/create"
@RequestMapping(value="/users/{userId}/topics/{topicId}")
这样也是可以的,请求的URL可以是"/users/123/topics/123"
3) Ant风格的URL路径映射
@RequestMapping(value="/users/**")
可以匹配"/users/abc/abc",但"/users/123"将会被【URI模板模式映射中的"/users/{userId}"模式优先映射到】
@RequestMapping(value="/product/?")
可匹配"/product/1"或"/product/a",但不匹配"/product"或"/product/aa";
?代表有且只有一个字符
@RequestMapping(value="/product*")
可匹配"/productabc"或"/product",但不匹配"/productabc/abc";
*代表0~n个字符
@RequestMapping(value="/product/*")
可匹配"/product/abc",但不匹配"/productabc";
@RequestMapping(value="/products/**/{productId}")
可匹配"/products/abc/abc/123"或"/products/123",也就是Ant风格和URI模板变量风格可混用;
**代表所有的子路径
4) 正则表达式风格的URL路径映射(具体参考正则类java.util.regex.Pattern;)
从Spring3.0 开始支持正则表达式风格的URL路径映射,格式为{变量名:正则表达式},之后通过@PathVariable可以提取{XXX:正则表达式匹配的值}中的XXX这个变量的值。
@RequestMapping(value="/products/{categoryCode:\\d+}-{pageNumber:\\d+}")
可以匹配"/products/123-1",但不能匹配"/products/abc-1",这样可以设计更加严格的规则。
@RequestMapping(value="/user/{userId:^\\d{4}-[a-z]{2}$}")
可以匹配"/user/1234-ab"
注意:\d表示数字,但是\在java的字符串中是特殊字符,所以需要再加一个\进行转义即可
括号:
[abc] 查找方括号之间的任何字符。
[^abc] 查找任何不在方括号之间的字符。
[0-9] 查找任何从 0 至 9 的数字。
[a-z] 查找任何从小写 a 到小写 z 的字符。
[A-Z] 查找任何从大写 A 到大写 Z 的字符。
[A-z] 查找任何从大写 A 到小写 z 的字符。
元字符:
. 查找单个任意字符,除了换行和行结束符.如果要表示.这个字符,需要转义
\w 查找单词字符。 字母 数字 _
\W 查找非单词字符。非 字母 数字 _
\d 查找数字。
\D 查找非数字字符。
量词:
n+ 匹配任何包含至少一个 n 的字符串。
n* 匹配任何包含零个或多个 n 的字符串。
n? 匹配任何包含零个或一个 n 的字符串。
n{X} 匹配包含 X 个 n 的序列的字符串。
n{X,Y} 匹配包含 X 到 Y 个 n 的序列的字符串。
n{X,} 匹配包含至少 X 个 n 的序列的字符串。
n$ 匹配任何结尾为 n 的字符串。
^n 匹配任何开头为 n 的字符串。
正则表达式风格的URL路径映射是一种特殊的URI模板模式映射
URI模板模式映射不能指定模板变量的数据类型,如是数字还是字符串;
正则表达式风格的URL路径映射,可以指定模板变量的数据类型,可以将规则写的相当复杂。
匹配的内容包含一个数字
@RequestMapping("/regex/{userid:\\d}")
匹配的内容包含至少一个数字
@RequestMapping("/regex/{userid:\\d+}”)
匹配的内容包含3个数字
@RequestMapping("/regex/{userid:\\d{3}}")
匹配的内容是开始是3个数字,中间随意的字符,最后结尾1-9中的任意两个数字
@RequestMapping("/regex/{userid:^\\d{3}.*[1-9]{2}$}")
匹配内容是3~5个数字
@RequestMapping("/regex/{userid:\\d{3,5}}")
注:userid可以看做占位,冒号后面为以后填写值的格式。
注解Controller类:
package com.briup.web.annotation;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/*
* http://localhost:8888/jd1811_MVC/user/act
* @RequestMapping基于功能区分用的
*/
@Controller
@RequestMapping("/user")
public class ActionController {
// @RequestMapping("/act")
// @RequestMapping(value="/act")
/*
* 多个资源请求名字对应一个处理方法
*/
@RequestMapping(value={"/act","test1","test2"})
public String test(){
return "hello";
}
//http://127.0.0.1:8888/jd1812_MVC/user/user/tom
@RequestMapping("/user/{userid}")
public String restful( String userid){
System.out.println(userid+"------");
return "hello";
}
/*@PathVariable 将restful风格中的{}占位
* 中的变量代表的值赋给参数
* 默认,restful风格中的{}占位中的变量
* 和参数中表示的值的变量相同
* 如果restful风格中的{}占位中的变量
* 和参数中表示的值的变量不相同
* 在@PathVariable指定名字(restful风格中的{}占位中的变量名)
*
*/
@RequestMapping("/user1/{userid}")
public String restful1(@PathVariable("userid") String username){
System.out.println(username+"------");
return "hello";
}
@RequestMapping("/user2/{userid}")
public String restful2(@PathVariable("userid") long username){
System.out.println(username+"------");
return "hello";
}
@RequestMapping("/user3/{userid}/{passwd}")
public String restful4(@PathVariable("userid") long username,@PathVariable String passwd){
System.out.println(username+"------"+passwd);
return "hello";
}
//http://127.0.0.1:8888/jd1812_MVC/user/user3/1222/passwd
//http://127.0.0.1:8888/jd1812_MVC/user/user3/1222/passwd
@RequestMapping("/user3/{userid}/passwd")
public String restful3(@PathVariable("userid") long username){
System.out.println(username+"------");
return "hello";
}
/*
* http://localhost:8888/jd1812_MVC/product/
*
* /product/*只能统配斜杠后面没有斜杆的
* 资源名称
* /product/test
* /product/hello
* /product/test/hello
* *统配0到多个字符
* ** 统配内容中可以出现多个斜杆
* http://localhost:8888/jd1812_MVC/
* user/product/test/hello
*/
// @RequestMapping("/product/*")
// @RequestMapping("/product/**")
/*
* ?位置只能出现一个字符
*/
// @RequestMapping("/product/?")
//http://localhost:8888/jd1812_MVC/user/productyyyyyyy
/*
* 统配以product开头的资源
* 当时统配内容不能有斜杆
*/
// @RequestMapping("/product*")
//两个*也是表示统配内容,不能出现斜杠
// @RequestMapping("/product**")
// public String ant(){
// System.out.println("ant.......");
// return "hello";
// }
//http://localhost:8888/jd1812_MVC
///user/productyyyyyyy/test
@RequestMapping("/product**/{userid}")
public String ant(@PathVariable String userid){
System.out.println("ant......."+userid);
return "hello";
}
//http://localhost:8888/jd1812_MVC/user/regex/
// @RequestMapping("/regex/{userid:\\d+}")
// public String regex(@PathVariable String userid){
// System.out.println("regex...."+userid);
// return "hello";
// }
// @RequestMapping("/regex/{userid:\\d{3}}")
// public String regex(@PathVariable String userid){
// System.out.println("regex...."+userid);
// return "hello";
// }
// @RequestMapping("/regex/{userid:\\d{3,5}}")
// public String regex(@PathVariable String userid){
// System.out.println("regex...."+userid);
// return "hello";
// }
//regex/123test19
//@RequestMapping("/regex/{userid:^\\d{3}.*[1-9]{2}$}")
// public String regex(@PathVariable String userid){
// System.out.println("regex...."+userid);
// return "hello";
// }
// 3232-az
// @RequestMapping(value="/regex/{userid:^\\d{4}-[a-z]{2}$}")
// public String regex(@PathVariable String userid){
// System.out.println("regex...."+userid);
// return "hello";
// }
@RequestMapping("/regex/{userid:[A-z]*}")
public String regex(@PathVariable String userid){
System.out.println("regex...."+userid);
return "hello";
}
// @RequestMapping("/test/{userid}")
/*
* method属性指定提交方式
*/
// @RequestMapping(value="/test/{userid}"
// ,method=RequestMethod.GET)
// @RequestMapping(value="/test/{userid}"
// ,method=RequestMethod.POST)
// @RequestMapping(value="/test/{userid}"
// ,method={RequestMethod.POST,RequestMethod.GET})
// public String method(@PathVariable String userid,String username){
// System.out.println(username+"&&&"+userid);
// return "hello";
// }
@RequestMapping(value="/test1"
,method=RequestMethod.POST)
public String method(@PathVariable String userid,String username){
System.out.println(username+"&&&"+userid);
return "hello";
}
@RequestMapping(value="/test1"
,method=RequestMethod.GET)
public String method1(@PathVariable String userid,String username){
System.out.println(username+"&&&"+userid);
return "hello";
}
}