1、SpringMVC简介
SpringMVC是web前端最主流的MVC框架之一;SpringMVC3.0后全面超越struts2,成为最优秀的MVC框架。SpringMVC通过一套MVC注解,让POJO成为处理请求的控制器,而无需实现任何接口。SpringMVC支持REST风格的URL请求;采用了松散耦合可插拔组件结构,比其他MVC框架更具扩展性和灵活性。
2、SpringMVC入门程序HelloWorld
步骤:
1、创建普通的动态web工程;
2、导入jar包
3、web.xml文件配置DispatcherServlet
4、创建springmvc.xml配置文件,配置包扫描和视图解析器
5、创建控制器类,类上添加注解@Controller
6、创建处理器方法,方法上添加@RequestMapping,指定请求的路径
7、页面上面创建<a>标签,配置href的值未@RequestMapping配置的值。
2.1 IDEA创建动态web(普通web工程,非maven)工程
1、File——》new——》project——》Java Enterprise——》Web Application;
2、点击下一步,选择项目存放位置,定义好项目名,一直finish即可。
3、在WEB-INF下面,创建classes和lib文件夹,名字不可改
4、在File中找到Project Structure,点击Modules ,选择Paths,选中Use module compile output path,把路径改成刚刚创建的classes文件夹;
apply后再点旁边的Dependencies,点击"+"号,选择1 JARs or directories ,选择你刚刚创建的lib文件夹,OK——》选中jar Directory。
5、回到主界面后,点击Run ,选择Edit Configurations,看tomcat已经有啦,这是java Enterprise的好处啦,点击Deployment
6、点击下面的图标就可以运行了
然后自动就会在浏览器上面打开首页,看到效果了。
2.2 加入jar到刚才创建的lib中
添加jar包到lib之后,要执行下面的操作:
2.2 修改web.xml,添加DispatcherServlet配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置 DispatcherServlet -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置 DispatcherServlet 的一个初始化参数: 配置 SpringMVC 配置文件的位置和名称 -->
<!--
实际上也可以不通过 contextConfigLocation 来配置 SpringMVC 的配置文件, 而使用默认的.
默认的配置文件为: /WEB-INF/<servlet-name>-servlet.xml
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--在web服务器启动的时候就加载这个servlet,否则会在第一次请求的时候再加载,效率慢-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!--拦截路径,拦截所有路径-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.3 创建配置文件springmvc.xml
在类路径下,创建springmvc.xml文件,内容如下:
<?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"
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-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- 配置扫描的包 -->
<context:component-scan base-package="com.springmvc"></context:component-scan>
<!-- 配置视图解析器: 如何把 handler 方法返回值解析为实际的物理视图 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
2.4 创建包,创建类HelloWorld
package com.springmvc;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloWorld {
@RequestMapping("helloworld")
public String hello(){
System.out.println("Hello World...");
return "success";
}
}
注意:类上添加了@Controller注解,方法hello上面添加了@RequestMapping注解,并且配置了请求路径:helloworld。
2.5 修改首页index.jsp,创建success.jsp页面
index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<a href="helloworld">点击跳转到success页面</a>
</body>
</html>
在WEB-INF下面创建jsp目录,然后创建success.jsp页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>成功页面</title>
</head>
<body>
success page
</body>
</html>
2.6 启动,访问,点击查看效果
3、请求映射和参数封装
3.1 @RequestMapping注解
该注解可以使用到类上和方法上,DispatcherServlet拦截请求之后,就会通过控制器的@RequestMapping提供的信息确定请求的处理方法。如果类上定义了该注解,那么类中所有的方法的请求路径上都要加上类上的路径:比如类上配置了@RequestMapping("demo"),处理器方法上配置了@RequestMapping("/hello")(这个 hello 前面的 斜杠/ 可有可无),那么请求路径就是:demo/hello。
我们上面配置的是@RequestMapping注解的value属性,其实他还有其他几个属性:method、params,headers。
method可以指定该方法接受的请求方式,比如GET和POST,如果指定了method属性,那么在前台页面就只能使用对应的请求方式了。但是如果没有指定method,那么GET和POST请求都是可以的。method的属性值在枚举类RequestMethod中定义。
params和headers指定了前端必须要传的参数和请求头,可以更加精确的确定请求;
params的例子:params = {"username","age!=100"}表示前台一定要包含参数username和age,但是age不能等于100,否则请求失败(404)。
headers的例子:headers = {"Accept-Language=zh-CN,zh;q=0.9"},表示请求头中一定要包含Content-Language并且值只能是zh-CN。
@RequestMapping的请求路径还支持Ant风格的URL,Ant风格的地址支持下面三种匹配符:?:匹配文件名中的一个字符;*:匹配文件名中的任意字符;**:匹配多层路径。
3.2 @PathVariable注解
@PathVariable用来绑定URL中的占位符。带占位符的URL是Spring3.0新增的功能,通过注解@PathVariable可以将URL中的占位符绑定到处理器方法的参数中,但是URL路径中占位符的值一定要和@PathVariable的value属性名称是一样的,例如:
@RequestMapping(value = "testPathVariable/{name}")
public String testMethod(@PathVariable("name") String myName){
System.out.println("我是。。。。"+myName);
return SUCCESS;
}
两个都是name,这样的话String myName的名称可以随便取。
3.3 SpringMVC如何支持PUT和DELETE请求
浏览器form表单只支持GET和POST请求,而PUT和DELETE请求并不支持。Spring3.0添加了一个过滤器(org.springframework.web.filter.HiddenHttpMethodFilter),可以将这些请求转换为标准的Http方法,使得可以支持GET、POST、PUT和DELETE请求。
步骤如下:
1、配置HiddenHttpMethodFilter
<!--配置org.springframework.web.filter.HiddenHttpMethodFilter
作用:可以将POST请求转换为 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>
2、发送的是POST请求
3、需要在发送post请求时,携带一个 name="_method" value="PUT"("DELETE")的隐藏域。
3.4 @RequestParam注解绑定请求参数
@RequestParam(value = "name"):可以把url路径中 ? 后面的参数绑定到方法的参数中,name和url路径中?后面的参数名名称要一致。这样的话,方法的形参名称就可以随便命名了。如果不@RequestParam或者说@RequestParam不知道value,那么只要方法的形参名和url的?后面的参数名相同,也可以把请求参数的值绑定到形参中。
如果请求路径是:<a href="springmvc/testMethod?name=111&pwd=110&qq=100">testMethod</a>
那么后台方法可以是:
@RequestMapping(value = "testRequestParam")
public String testMethod(@RequestParam(value = "name") String name,@RequestParam(value = "pwd") String pwd){
System.out.println("name:"+name+",pwd:"+pwd);
return SUCCESS;
}
也可以是:
public String testMethod(String name,String pwd){
System.out.println("name:"+name+",pwd:"+pwd);
return SUCCESS;
}
@RequestParam还可以设置属性:@RequestParam(value = "name",required = true,defaultValue = "qqqq") ,即设置该参数是否必须传,是否设定默认值。
3.5 @RequestHeader注解
@RequestHeader可以用来获取请求头的值,例如:
@RequestMapping(value = "testRequestHeader")
public String testRequestHeader(@RequestHeader(value = "Accept-Language") String head){
System.out.println("请求头 :"+head);
return SUCCESS;
}
他和@RequestParam一样还有required和defaultValue属性。
3.6 @CookieValue注解
可以用在方法形参前面,映射一个Cookie值:还有required和defaultValue属性。
@RequestMapping(value = "testCookieValue")
public String testCookieValue(@CookieValue(value = "JSESSIONID") String sessionId){
System.out.println("CookieValue :"+sessionId);
return SUCCESS;
}
3.7、POJO对象绑定请求参数的值
上面第三点,都是讲的单个参数的传递和接收,在开发中,很多时候需要提交表单或者传递很多的参数,如果每个参数都需要在方法中指定一个形参的话,那么就会显得方法很臃肿了。所以,可以使用POJO对象来绑定请求参数,只要保证请求的参数名和POJO的属性名是一一对应的就行了,并且,还支持级联属性的绑定。
3.7.1 创建两个POJO
public class Department {
private Integer id;
private String deptName;
//get/set方法以及toString方法
}
public class User {
private Integer id;
private String name;
private Integer age;
private Department department;
//get/set方法以及toString方法
}
3.7.2 场景处理器方法
@RequestMapping(value = "testPojo")
public String testPojo( User user){
System.out.println("pojo :"+user);
return SUCCESS;
}
3.7.3 前端代码
<a href="springmvc/testPojo?id=1&name=tom&age=12&department.deptName=jishu&department.id=1001">testPojo</a>
后台打印:
pojo :User{id=1, name='tom', age='12', department=Department{id=1001, deptName='jishu'}}
当然,实际开发中,如果是POJO接收的话,一般情况下是form表单进行提交的,不会是一个<a>标签。
3.8、使用Servlet原生的API作为形参
MVC 的 Handler 方法可以接受以下ServletAPI 类型的参数:HttpServletRequest、HttpServletResponse 、HttpSession 、java.security.Principal 、Locale、InputStream、OutputStream 、Reader、Writer(HttpServletResponse.getWriter()) 这些可以直接在处理器的方法形参上引入即可。
@RequestMapping(value = "testServletApi")
public void testServletApi(HttpServletRequest request, HttpServletResponse response, Writer writer) throws IOException {
System.out.println(request+"===="+response);
writer.write("servlet api test");
}
4、处理模型数据
Spring MVC 提供了以下几种途径输出模型数据:
ModelAndView:处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据;
Map 及 Model:入参为org.springframework.ui.Model、org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。
@SessionAttributes:将模型中的某个属性暂存到HttpSession 中,以便多个请求之间可以共享这个属性;
@ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中。
4.1 ModelAndView
控制器处理方法的返回值如果为 ModelAndView,则其既包含视图信息,也包含模型数据信息。
添加模型数据的方法:
MoelAndView addObject(String attributeName, Object attributeValue)
ModelAndView addAllObject(Map<String, ?> modelMap)
设置视图的方法:
void setView(View view)
void setViewName(String viewName)
@RequestMapping(value = "testModelAndView")
public ModelAndView testModelAndView() throws IOException {
//创建 ModelAndView 对象并设置视图名称
ModelAndView modelAndView = new ModelAndView(SUCCESS);
//添加模型数据
modelAndView.addObject("time",new Date());
modelAndView.addObject("usernames", Arrays.asList("tom","jack","bob"));
return modelAndView;
}
前台页面的请求和取值:
<a href="springmvc/testModelAndView">testModelAndView</a>
times:${requestScope.time}
<br/>
usernames:${requestScope.usernames}
4.2 Map及Model
Spring MVC 在内部使用了一个org.springframework.ui.Model 接口存储模型数据;
具体步骤:
Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
如果方法的入参为 Map 或 Model类型,Spring MVC 会将隐含模型的引用传递给这些入参。在方法体内,开发者可以
通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据。
@RequestMapping(value = "testMapAndModel")
public String testMapAndModel(Map<String,Object> map, Model model) throws IOException {
//添加模型数据
map.put("time",new Date());
model.addAttribute("usernames", Arrays.asList("tom","jack","bob"));
return SUCCESS;
}
4.3 @SessionAttributes
若希望在多个请求之间共用某个模型属性数据,则可以在控制器类(该注解只能在类上使用)上标注一个 @SessionAttributes,Spring MVC 就会将在模型中对应的属性暂存到 HttpSession 中。
@SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中;
@SessionAttributes(types=User.class): 会将隐含模型中所有类型为 User.class 的属性添加到会话中。
@SessionAttributes(value={“user1”, “user2”}) :会将模型中属性名为 user1和user2 的属性方法HttpSession中;
@SessionAttributes(types={User.class, Dept.class})
@SessionAttributes(value={“user1”, “user2”}, types={Dept.class})
@SessionAttributes(value = {"department"},types = {String.class,Date.class})
@RequestMapping("springmvc")
@Controller
public class SpringMvcTest {
private static final String SUCCESS = "success";
@RequestMapping(value = "testSessionAttribute")
public String testSessionAttribute(Map<String,Object> map, Model model) throws IOException {
Department department = new Department();
department.setId(1001);
department.setDeptName("jishubu");
//添加模型数据
map.put("department",department);
map.put("time",new Date());
model.addAttribute("password", "123456");
return SUCCESS;
}
}
页面取值:
request times:${requestScope.time}
<br/>
request usernames:${requestScope.password}
<br/>
request department:${requestScope.department}
<br/>
下面的数据是从session域中获取:
<br/>
session times:${sessionScope.time}
<br/>
session usernames:${sessionScope.password}
<br/>
session department:${sessionScope.department}
<br/>
页面效果:
request times:Fri Feb 28 09:47:00 CST 2020
request usernames:123456
request department:Department{id=1001, deptName='jishubu'}
下面的数据是从session域中获取:
session times:Fri Feb 28 09:47:00 CST 2020
session usernames:123456
session department:Department{id=1001, deptName='jishubu'}
4.4 @ModelAttribute
在方法定义上使用 @ModelAttribute 注解:Spring MVC 在调用目标处理方法前,会先逐个调用在方法级上标注了@ModelAttribute 的方法。
在方法的入参前使用 @ModelAttribute 注解:可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数绑定到对象中,再传入入参,将方法入参对象添加到模型中;
后台代码:
@ModelAttribute
public void getUser(@RequestParam(value="id",required=false) Integer id,
Map<String, Object> map) throws IOException {
if(id!=null){
//模拟从数据库,根据id获取一个对象
User user = new User();
user.setId(1000);
user.setAge(12);
user.setName("jack");
System.out.println("从数据库根据id查询到的User:"+user);
//map.put("user",user);
//对应 testModelAttribute的@ModelAttribute("myuser")
map.put("myuser",user);
}
}
@RequestMapping(value = "testModelAttribute")
//public String testModelAttribute(User user) {
public String testModelAttribute(@ModelAttribute("myuser") User user) {
System.out.println("修改User:"+user);
return SUCCESS;
}
前台表单:因为不能修改年龄,所以前台表单没有age
<form action="springmvc/testModelAttribute" method="post">
id:<input type="text" name="id" value="1000">
name:<input type="text" name="name" value="jack">
<input type="submit" value="提交"/>
</form>
执行流程:
* 1. 执行 @ModelAttribute 注解修饰的方法,从数据库中取出对象,把对象放入到了 Map 中,键为:user
* 2. SpringMVC 从 Map 中取出 User 对象,并把表单的请求参数赋给该 User 对象的对应属性.
* 3. SpringMVC 把上述对象传入目标方法的参数(testModelAttribute(User user))
* 1. 有 @ModelAttribute 标记的方法, 会在每个目标方法执行之前被 SpringMVC 调用!
* 2. @ModelAttribute 注解也可以来修饰目标方法 POJO 类型的入参, 其 value 属性值有如下的作用:
* 1). SpringMVC 会使用 value 属性值在 implicitModel 中查找对应的对象, 若存在则会直接传入到目标方法的入参中。
* 2). SpringMVC 会一 value 为 key,POJO 类型的对象为 value,存入到 request 中。
注意:由@SessionAttributes引发的异常
org.springframework.web.HttpSessionRequiredException:
Session attribute 'user' required - not found in session
如果在处理类定义处标注了@SessionAttributes(“xxx”),则尝试从会话中获取该属性,并将其赋给该入参,然后再用
请求消息填充该入参对象。如果在会话中找不到对应的属性,则抛出 HttpSessionRequiredException 异常