1、SpringMVC的概述
2、SpringMVC的核心DispatcherServlet程序
3、SpringMVC的示例程序
4、视图解析器
5、@RequestMapping注解详解标注在方法上
6、Controller中如何接收请求参数
1、SpringMVC的概述
Spring MVC框架是一个开源的Java平台,为开发强大的基于JavaWeb应用程序提供全面的基础架构支持非常容易和非常快速。
Spring web MVC框架提供了MVC(模型 - 视图 - 控制器)架构和用于开发灵活和松散耦合的Web应用程序的组件。 MVC模式导致应用程序的不同方面(输入逻辑,业务逻辑和UI逻辑)分离,同时提供这些元素之间的松散耦合。
· 模型(Model)封装了应用程序数据,通常它们将由POJO类组成。
· 视图(View)负责渲染模型数据,一般来说它生成客户端浏览器可以解释HTML输出。
· 控制器(Controller)负责处理用户请求并构建适当的模型,并将其传递给视图进行渲染。
这里的控制器和servlet功能是一样的 ,
Servlet:接收请求参数→封装成JavaBean对象模型,只不过这里spring帮我们封装好了
2、SpringMVC的核心DispatcherServlet程序
官方给的一个图:
说明:图片的下方可以看出:Servlet引擎是在tomcat里面,所有配置dispatcherServlet不是在spring容器中进行配置,而是在web.xml中进行配置
1、所有的请求进来都是进入到前端控制器FrontController(也就是dispatcherServlet帮我们接收所有的请求)。
2、然后再把这些请求转给(delegate request 委托请求)不同的Controller控制器(handler request),并创建模型(create model)(delegate rendering of response 委托渲染响应模型),重新返回给前端控制器.
3、前端控制器将模型交给视图(view template ) 进行渲染响应,渲染完之后返回给前端控制器( return control) ,并由前端控制器返回给客户端
注意:Servlet 不需要加@controller注解,加@controller注解是在黄色的这个位置
在springmvc中所有的请求都是经过dispatcherservlet的,并响应回去
3、SpringMVC的第一个Hello示例程序
3.1、SpringMVC——Hello world程序的步骤:
1、创建一个动态的web工程
2、导入SpringMVC的包
commons-logging-1.1.3.jar
log4j-1.2.17.jar
spring-aop-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar
2、创建工程需要的配置文件:
(1) log4j.properties
# Global logging configuration log4j.rootLogger=INFO, stdout # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
(2) 创建SpringMVC的配置文件
<?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 http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="com.tcent"></context:component-scan> </beans>
(3) 配置web.xml
<servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <!-- 给Spring的核心组件,告诉它,springMVC的配置文件在哪 --> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- load-on-startup表示当前这个Servlet程序,当Web服务器一启动的时候,就创建和初始化 --> <load-on-startup>1</load-on-startup> </servlet> <!-- Map all requests to the DispatcherServlet for handling --> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <!-- / 拦截全部请求。/支持restful风格 --> <url-pattern>/</url-pattern> </servlet-mapping>
这里 有两点很重要:
(1)原来的servlet程序是在第一次访问的时候进行创建并且初始化,后面的每次访问只调用service()方法,但是,你只要一加上这个配置load-on-startup ,就会在web工程已启动就给你创建出来并进行初始化,好处就是我们做好初始化之后,你后面的访问速度就会比较快,就跟数据库连接池一样,我先把连接都准备好,你一进来我就直接给你,就不会产生等你每次访问,我就给你创建这么慢,就提升了访问速度。
(2)url-pattern用/拦截所有请求,而且支持restful风格。这里不要写成/*了,/*的权限太高了,而且也不支持restful风格
2、创建jsp页面
4.1、WebContent/index.jsp
<body>
<a href="${ pageContext.request.contextPath }/hello">hello(访问服务器。转发到WebContent/jsp/target.jsp页面)</a>
</body>
4.2、在WebContent/jsp/target.jsp
<body>
请求转发进来 了
</body>
5、编写一个类HelloController(当然也可以叫HelloHandler这都是习惯命名)
/** * @Controller 表示当前类是一个控制器 */ @Controller public class HelloController { /** * @RequestMapping("/hello") <br/> * 表示在SpringMVC中注册一个控制器,请求地址是http://ip:port/工程名/hello * @return */ @RequestMapping("/hello") public String hello() { System.out.println("这是SpringMVC的hello程序"); // "/jsp/target.jsp" 返回值表示要跳转的地址 // /打头,表示绝对路径:到http://ip:port/工程名/ 映射到WebContent目录 // "/jsp/target.jsp" 整个表示http://ip:port/工程名/jsp/target.jsp页面 // SpringMVC默认跳转使用的是转发 return "/jsp/target.jsp"; } }
SpringMVC默认跳转使用的是转发
注意:@RequestMapping(“/hello”)表示请求映射,相当于我们之前的servlet中
<servlet-mapping> <servlet-name>xxx</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
的作用一样,也是表示到工程名后面跟的hello,就能访问塔hello
表示在SpringMVC中注册一个控制器,请求地址是http://ip:port/工程名/hello
3.2、SpringMVC.xml配置文件的另一种存放方式
原来的方案一:
1、编写一个SpringMVC配置文件,
2、通过dispatcherServlet的初始化参数告诉SpringMVC它的配置文件在哪里。
<!-- The front controller of this Spring Web application, responsible for handling all application requests --> <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <!-- 给Spring的核心组件,告诉它,springMVC的配置文件在哪 --> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- load-on-startup表示当前这个Servlet程序,当Web服务器一启动的时候,就创建和初始化 --> <load-on-startup>1</load-on-startup> </servlet> <!-- Map all requests to the DispatcherServlet for handling --> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <!-- / 拦截全部请求。/支持restful风格 --> <url-pattern>/</url-pattern> </servlet-mapping>
另一种方案是二:
1、在web.xml配置文件所在的目录下创建一个SpringMVC配置文件。
2、这个配置文件名的命名规则是你springMVC前端控制器的servlet-name的值-servlet.xml
servlet-name(<servlet-name>springDispatcherServlet</servlet-name>
取代如下一段代码:
<init-param> <!-- 给Spring的核心组件,告诉它,springMVC的配置文件在哪 --> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param>
原先的和现在的对比:
4、视图解析器
配置SpringMVC提交的视图解析器:
<!-- 配置Spring的视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- prefix配置返回的视图的前缀 --> <property name="prefix" value="/jsp/"/> <!-- suffix配置返回的视图的后缀 --> <property name="suffix" value=".jsp"/> </bean>
视图解析器工作原理 :
5、@RequestMapping注解详解标注在方法上
@RequestMapping是给个方法配置一个访问地址。就比如web学习的Servlet程序,在web.xml中配置了访问地址之后,它们之间就有一个访问映射关系。
5.1、value属性(**重点**)
@RequestMapping(value="/hello")
表示映射到 当前这个请求方法 的访问地址。
/ 表示到http://ip:port/工程名/ 映射到代码的WebContent目录
/hello 就表示到http://ip:port/工程名/hello
此处的value单个属性可以省略
5.2、params属性
params是要求此请求的参数匹配
params="username"表示请求地址必须带有username参数
params="username=abc"表示请求参数中必须要有username,而且值还必须是abc
params="username!=abc"表示1、请求参数中不能有username参数。2、有username参数,但值不能等于abc
params="!username"表示请求地址不能带有username参数
params= {"username!=abc","!password"}params可以有多个值,每个值之间是&&关系
以上条件表示要求:
(请求地址中不能有username参数 || username参数值不能等于 abc && 不能有password参数)
/** * params="username"表示当前请求地址必须要有username参数。<br/> * params = "username=wzg168"表示当前请求地址必须要有username参数。而且值必须是wzg168<br/> * params = "username!=wzg168"表示当前请求地址不能包含username参数,或有了username参数的话,值必须不等于wzg168 * params = "!username"表示当前请求地址不能包含请求参数username。 * @return */ @RequestMapping(value = "/param", params = {"abc","xxx=ccc"}) public String param() { System.out.println("这是param方法"); return "param"; }
5.3、headers属性
可以限定请求头中的内容:
/** * headers = "User-Agent=Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" * 表示限定浏览器必须是谷歌浏览器,而且版本还是Chrome/58.0.3029.110 * @return */ @RequestMapping(value = "/header", headers = "User-Agent=Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36") public String header() { System.out.println("这是header方法"); return "param"; }
多个参数时,value不可省略
5.4、method属性(*次重点*)
form标签页面内容:
<form action="${ pageContext.request.contextPath }/method" method="post"> <input type="submit" /> </form>
代码:
/** * method=RequestMethod.GET 表示当前请求必须是GET请求才允许访问<br/> * method=RequestMethod.POST 表示当前请求必须是POST请求才允许访问<br/> */ @RequestMapping(value="/method",method=RequestMethod.POST) public String method() { System.out.println("这是method方法"); return "param"; }
5.5、@RequestMapping标注在Controller类上
@RequestMapping(value = "/hello")
public String hello()
它原来的请求访问地址是:http://ip:port/工程名/hello
当我们在Controller控制器上添加一个@RequestMapping注解,并赋于value属性值的时候。
比如:
@RequestMapping(value="/person")
@Controller
public class HelloController {
这个时候,HelloController中的所有方法必须都在原有请求地址路径前面加上/person。
比如:
@RequestMapping(value = "/hello")
public String hello()
它原来的访问地址是:http://ip:port/工程名/hello
在Controller控制器上加了@RequestMapping(value="/person")之后,那么访问地址是:
http://ip:port/工程名/Controller地址/方法上的地址
http://ip:port/工程名/person/hello
5.6、通配符在@RequestMapping中的使用(不常用)
1、绝对匹配
@RequestMapping(value = "/fun") public String fun() { System.out.println("这是绝对匹配"); return "target"; }
/fun 表示http://ip:port/工程名/fun
2、? 问号 匹配资源路径
? 问号表示一个任意字符
@RequestMapping(value = "/fu?") public String fun1() { System.out.println("这是fun1方法 ,fu?"); return "target"; }
表示请求地址是:http://ip:port/工程名/fu[a-Z0-9_]
3、* 星号 匹配资源路径
* 星号 可以匹配多个任意字符
@RequestMapping(value = "/fu*") public String fun2() { System.out.println("这是fun2方法 ,fu*"); return "target"; }
注:当一个路径同时匹配多个规则的时候,调用方法的优先顺序是:
绝对匹配--->>>>?问号匹配---->>>>*星号匹配
匹配的精度越高,越优先
4、? 问号 匹配一层目录
? 问号表示一个任意字符
@RequestMapping(value = "/?/fun") public String fun3() { System.out.println("这是fun3方法 ,/?/fun"); return "target"; }
5、* 星号 匹配一层目录
* 星号 可以匹配多个任意字符
@RequestMapping(value = "/*/fun") public String fun4() { System.out.println("这是fun4方法 ,/*/fun"); return "target"; }
6、** 星星号 匹配多层目录
@RequestMapping(value = "/**/fun") public String fun5() { System.out.println("这是fun5方法 ,/**/fun"); return "target"; }
6、Controller中如何接收请求参数
6.1、原生API参数类型
6.1.1、HttpServletRequest类
@RequestMapping(value = "/param1") public String param1(HttpServletRequest request) { System.out.println("这是param1方法"); System.out.println(request); return "param"; }
6.1.2、HttpSession类
@RequestMapping(value = "/param2") public String param2(HttpServletRequest request, HttpSession session) { System.out.println("这是param2方法"); System.out.println(request); System.out.println(session); return "param"; }
6.1.3、HttpServletResponse类
@RequestMapping(value = "/param3") public String param3(HttpServletRequest request, HttpSession session, HttpServletResponse response) { System.out.println("这是param3方法"); System.out.println(response); System.out.println(request); System.out.println(session); return "param"; }
6.2、普通类型传入参数(注入)
通过request对象获取(不推荐):
@RequestMapping(value="/param4") public String param4(HttpServletRequest request) { System.out.println("这是param4方法"); System.out.println(request.getParameter("username")); return "param"; }
我们在Controller的目标方法上直接设置方法的参数。就可以直接传入请求参数的值。
@RequestMapping(value="/param5") public String param5(String username) { System.out.println("这是param5方法"); System.out.println(username); return "param"; }
通过方法传入参数可以结合@RequestMapping注解params属性传值使用,并进行接受。
要求:参数名必须和方法的参数名相匹配。
6.3、普通类型数组的参数
@RequestMapping(value = "/param6") public String param6(String[] hobbies) { System.out.println("这是param6方法"); if (hobbies != null) { for (String string : hobbies) { System.out.println(string); } } return "param"; }
注:当然也可以使用String hobbies直接接收一个字符串,中间它会用逗号隔开,但自己使用的时候还要解析,有点自找麻烦的感觉,推荐还是使用String[] hobbies这种形式
6.4、普通类型使用@RequestParam入参
@RequestMapping(value = "/param7") public String param7(@RequestParam(value = "username") String user) { System.out.println("这是param7方法"); System.out.println(user); return "param"; }
注意:请求参数名username和方法参数名的区别user,这里也就相当于起别名
@RequestParam(value = "username") String user 表示SpringMVC会自动将请求过来的参数username的值。注入到方法参数user中。
默认情况下。@RequestParam(value = "username")中要求的username参数必须要有值(即required=true)。否则就会报如下错误:
required:属性设置当前要求的username参数是否客户端必须传递。默认值是true表示必须传递。
如果没有传递就报错。
也可以手动修改为false。允许不传递值。则默认值是null
defaultValue:属性设置当客户端没有传递值的时候。设置的默认值。
6.5、@RequestHeader获取请求头入参
@RequestMapping(value = "/param8") public String param8(@RequestHeader(value = "User-Agent") String userAgent, @RequestHeader(value = "Host") String host) { System.out.println("这是param8方法"); System.out.println(userAgent); System.out.println(host); return "param"; }
6.6、@CookieValue获取Cookie值入参
@CookieValue注解获取cookie的值注入。
value中填写的是cookie的key
@RequestMapping(value = "/param9") public String param9(@CookieValue(value = "JSESSIONID") String jsessionid) { System.out.println("这是param9方法"); System.out.println(jsessionid); return "param"; }
6.7、一个Pojo对象类型的参数
创建Person对象:
public class Person { private Integer id; private String name; private String phone; private Integer age;
创建一个表单:
<form action="${ pageContext.request.contextPath }/param10"> id:<input type="text" name="id" /><br/> name:<input type="text" name="name" /><br/> phone:<input type="text" name="phone" /><br/> age:<input type="text" name="age" /><br/> <input type="submit" /> </form>
这里的name值必须和pojo属性一致,才能通过表单注入值到对象
Controller中的方法代码:
@RequestMapping(value="/param10") public String param10(Person person) { System.out.println("这是param10方法"); System.out.println(person); return "param"; }
要求:pojo对象自动入参的要求是客户端传递的参数名必须跟pojo对象的属性名对应上。
6.8、对象中套对象(级联属性)
比如Person对象中套有book对象。只需要传递参数。子对象名.属性名就可以自动的注入到Person对象的book对象的属性中。
public class Book { private String name; private BigDecimal price;
public class Person { private Integer id; private String name; private String phone; private Integer age; private Book book;
表单:
<form action="${ pageContext.request.contextPath }/param10"> id:<input type="text" name="id" /><br/> name:<input type="text" name="name" /><br/> phone:<input type="text" name="phone" /><br/> age:<input type="text" name="age" /><br/> book.name:<input type="text" name="book.name" /><br/> book.price:<input type="text" name="book.price" /><br/> <input type="submit" /> </form>
常用spring开发jar包即额外包下载