目录
4.1.1.HttpServletRequest、HttpServletResponse、HttpSession
4.1.2.ModelAndView、Model、ModelMap
1.SpringMVC入门
1.1.Springmvc是什么?
Spring Web MVC(简称SpringMVC) 和 Struts2 都属于表现层的框架,SpringMVC是Spring框架的一部分,我们可以从Spring的整体结构中看得出来:
1.2.Springmvc处理流程
注:Handler是指controller,action
1.3.入门程序
1.使用idea创建web项目 MySpringMvc
2.pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itcast</groupId>
<artifactId>MySpringMvc</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>MySpringMvc Maven Webapp</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<spring.version>4.1.1.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
<build>
<finalName>HelloSpringMVC</finalName>
</build>
</project>
3.SpringMVC框架的核心配置文件:springmvc.xml
在resources目录下创建 springmvc.xml。SpringMVC本身就是Spring的子项目,对Spring兼容性很好,不需要做很多配置。这里只配置一个Controller扫描就可以了,让Spring对页面控制层Controller进行管理。
<?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:p="http://www.springframework.org/schema/p"
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-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 使用注解方式开发:配置controller扫描包-->
<context:component-scan base-package="com.itcast.controller" />
</beans>
4.SpringMVC的前端控制器
在web.xml中,配置SpringMVC的前端控制器DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>springmvc-first</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- 配置SpringMVC前端控制器 --> <servlet> <servlet-name>springmvc-first</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 指定SpringMVC核心配置文件位置 --> <!-- SpringMVC的配置文件的默认路径是/WEB-INF/${servlet-name}-servlet.xml --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc-first</servlet-name> <!-- 设置所有以action结尾的请求进入SpringMVC --> <!-- 1: /* 拦截所有请求 包含(.js.css .png .jpg .jsp) 2: *.action *.do 拦截以.action或.do结尾的请求 不拦截(.js.css .png .jpg) 3: / 拦截所有请求 不包含.jsp --> <url-pattern>*.action</url-pattern> </servlet-mapping> </web-app>
5.在WEB-INF目录下创建 jsp/login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>SpringMvc首页</title>
</head>
<body>
<p>用户名:${username}</p>
<p>密码:${password}</p>
</body>
</html>
6.创建controller
package com.itcast.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class IndexController { @RequestMapping("/login.action") public ModelAndView login(){ //创建ModelAndView(类似模型对象),用来存放数据和视图 ModelAndView modelAndView = new ModelAndView(); //设置数据到模型对象中 //相当于放到request域中,可以从页面获取数据 modelAndView.addObject("username", "张飞"); modelAndView.addObject("password", "123"); //设置视图,需要设置视图的位置,跳转到指定页面 modelAndView.setViewName("/WEB-INF/jsp/login.jsp"); //返回ModelAndView return modelAndView; } }
- 使用注解方式开发,所以需要在类上添加@Controller注解,把Controller交由Spring管理;
- 在方法上面添加@RequestMapping注解,表示请求路径。
- springmvc中的controller不是单例模式,后面会说
7.启动项目,浏览器访问
2.Springmvc架构
2.1.框架结构
2.2.架构流程
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求调用HandlerMapping处理器映射器。
- 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回DispatcherServlet。
- DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
- 执行处理器(Controller,也叫后端控制器)。
- Controller执行完成返回ModelAndView
- HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器
- ViewReslover解析后返回具体View
- DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
- DispatcherServlet响应用户
2.3.组件说明
以下组件通常使用框架提供实现:
1)DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
2)HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,
例如:配置文件方式,实现接口方式,注解方式等。
3)Handler:处理器
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。
4)HandlAdapter:处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
下图是许多不同的适配器,最终都可以使用usb接口连接
5)ViewResolver:视图解析器
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,
再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
6)View:视图
springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
Springmvc三大组件:
在springmvc的各个组件中,处理器映射器、处理器适配器、视图解析器称为springmvc的三大组件。
需要程序员开发的组件有handler、view
2.4.默认加载的组件
我们没有做任何配置,就可以使用这些组件,框架已经默认加载这些组件了,配置文件位置如下图:
2.5.组件扫描器
使用组件扫描器省去在spring容器配置每个Controller类的繁琐。使用<context:component-scan>自动扫描标记@Controller的控制器类,在springmvc.xml配置文件中配置如下:
<!-- 配置controller扫描包,多个包之间用,分隔 -->
<context:component-scan base-package="cn.itcast.controller" />
2.6.注解映射器和适配器
2.6.1.配置处理器映射器
注解式处理器映射器,对类中标记了@ResquestMapping的方法进行映射,根据@ResquestMapping定义的url匹配@ResquestMapping标记的方法,匹配成功返回HandlerMethod对象给前端控制器。HandlerMethod对象中封装url对应的方法Method。
从spring3.1版本开始,废除了DefaultAnnotationHandlerMapping的使用,推荐使用RequestMappingHandlerMapping完成注解式处理器映射。
在springmvc.xml配置文件中配置如下:
<!-- 配置处理器映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
2.6.2.配置处理器适配器
注解式处理器适配器,对标记@ResquestMapping的方法进行适配。
从spring3.1版本开始,废除了AnnotationMethodHandlerAdapter的使用,推荐使用RequestMappingHandlerAdapter完成注解式处理器适配。
在springmvc.xml配置文件中配置如下:
<!-- 配置处理器适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />
2.6.3.注解驱动(简化注解处理映射器和适配器)
直接配置处理器映射器和处理器适配器比较麻烦,可以使用注解驱动来取代注解映射器和适配器。
SpringMVC使用 <mvc:annotation-driven> 自动加载 RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter
可以在springmvc.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置:
<!-- 注解驱动 -->
<mvc:annotation-driven />
2.7.视图解析器
视图解析器使用SpringMVC框架默认的InternalResourceViewResolver,这个视图解析器支持JSP视图解析
在springmvc.xml配置文件中配置如下:
<!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 配置逻辑视图的前缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 配置逻辑视图的后缀 --> <property name="suffix" value=".jsp" /> </bean>
注:逻辑视图名需要在controller中返回ModelAndView指定。
比如逻辑视图名为login,则最终返回的jsp视图地址:“WEB-INF/jsp/login.jsp”
最终jsp物理地址:前缀+逻辑视图名+后缀
我们可以修改之前controller中的试图地址,浏览器访问依然成功。
package com.itcast.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class IndexController {
@RequestMapping("/login.action")
public ModelAndView login(){
//创建ModelAndView(类似模型对象),用来存放数据和视图
ModelAndView modelAndView = new ModelAndView();
//设置数据到模型对象中
//相当于放到request域中,可以从页面获取数据
modelAndView.addObject("username", "张飞");
modelAndView.addObject("password", "123");
// 方式一:设置视图,需要设置视图的物理位置
// modelAndView.setViewName("/WEB-INF/jsp/login.jsp");
// 方式二:配置了视图解析器前缀和后缀之后,这里只需要设置逻辑视图即可。
// 视图解析器根据前缀+逻辑视图名+后缀,拼接出来物理路径
modelAndView.setViewName("login");
//返回ModelAndView
return modelAndView;
}
}
3.整合Springmvc、Spring、Mybatis
整合目标:控制层采用springmvc、持久层使用mybatis实现。
注意:spring和mybatis需要整合,但springmvc本来就是spring的子框架,所以不需要整合。
参考文档:整合SSM案例
4.参数绑定
4.1.默认支持的参数类型
4.1.1.HttpServletRequest、HttpServletResponse、HttpSession
处理器形参中添加如下类型的参数,处理适配器会默认识别并进行赋值。
- HttpServletRequest:通过request对象获取请求信息
- HttpServletResponse:通过response处理响应信息
- HttpSession:通过session对象得到session中存放的对象
发送请求:http://localhost:8081/queryUserById?id=1
发送请求时,后台需要从请求的参数中把请求的id取出来,id包含在Request对象中,可以从Request对象中取id。
想获得Request对象只需要在Controller方法的形参中添加一个参数即可,Springmvc框架会自动把Request对象传递给方法。
1)新增 user.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
</head>
<body>
<p>ID:${id}</p>
<p>姓名:${name}</p>
<p>性别:${sex}</p>
<p>地址:${address}</p>
<p>生日:${birthday}</p>
</body>
</html>
2)Controller:
package com.itcast.controller;
import com.itcast.entity.UserEntity;
import com.itcast.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/queryUserById")
public ModelAndView queryUserById(HttpServletRequest request){
// 从request中获取请求参数
String strId = request.getParameter("id");
Integer id = Integer.valueOf(strId);
// 根据id查询商品数据
UserEntity userEntity = userService.queryUserById(id);
// 把结果传递给页面
ModelAndView modelAndView = new ModelAndView();
// 把商品数据放在模型中
modelAndView.addObject("id", userEntity.getId());
modelAndView.addObject("name", userEntity.getName());
modelAndView.addObject("sex", userEntity.getSex());
modelAndView.addObject("address", userEntity.getAddress());
modelAndView.addObject("birthday", userEntity.getBirthday());
// 设置逻辑视图
modelAndView.setViewName("user");
return modelAndView;
}
}
3)浏览器访问:
4.1.2.ModelAndView、Model、ModelMap
- 除了 ModelAndView 以外,还可以使用 Model、ModelMap 来向页面传递数据,不管是 Model、ModelMap 还是 ModelAndView,其本质都是使用Request对象向jsp传递数据。
- Model是一个接口,ModelMap是Model接口的实现类,如果直接使用Model,springmvc会实例化成ModelMap。所以使用Model和ModelMap的用法和效果是一样的,在参数里直接声明即可,只是参数类型不一致而已。
- 如果使用Model则可以不使用ModelAndView对象,Model对象可以向页面传递数据,View对象则可以使用String返回值替代。
ModelAndView我们就不演示了,Model和ModelAndMap用法是一样的。
@RequestMapping("/queryUserById2")
public String queryUserById2(HttpServletRequest request, Model model){
// 从request中获取请求参数
String strId = request.getParameter("id");
Integer id = Integer.valueOf(strId);
// 根据id查询商品数据
UserEntity userEntity = userService.queryUserById(id);
// 把结果传递给页面
model.addAttribute("id", userEntity.getId());
model.addAttribute("name", userEntity.getName());
model.addAttribute("sex", userEntity.getSex());
model.addAttribute("address", userEntity.getAddress());
model.addAttribute("birthday", userEntity.getBirthday());
return "user";
}
4.2.简单类型
当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定。
这样,从Request取参数的方法就可以进一步简化。
@RequestMapping("/queryUserById3")
public String queryUserById3(int id, Model model){
// 根据id查询商品数据
UserEntity userEntity = userService.queryUserById(id);
// 把结果传递给页面
model.addAttribute("id", userEntity.getId());
model.addAttribute("name", userEntity.getName());
model.addAttribute("sex", userEntity.getSex());
model.addAttribute("address", userEntity.getAddress());
model.addAttribute("birthday", userEntity.getBirthday());
return "user";
}
4.2.1.支持的数据类型
参数类型推荐使用包装数据类型,因为基础数据类型的值不可以为null
整形:Integer、int
字符串:String
单精度:Float、float
双精度:Double、double
布尔型:Boolean、boolean
比如:
请求url:
http://localhost:8080/xxx.action?id=2&status=false
方法参数:
public String editItem(Model model,Integer id,Boolean status)
4.2.2.@RequestParam
使用@RequestParam常用于处理简单类型的绑定。
@RequestParam属性:
- value:请求参数名称
- required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报错
- defaultValue:默认值,表示如果请求中没有同名参数时的默认值
@RequestMapping("/queryUserById4")
public String queryUserById4(@RequestParam(value = "id",
required = true,
defaultValue = "2")
Integer itemId, Model model){
// 根据id查询商品数据
UserEntity userEntity = userService.queryUserById(itemId);
// 把结果传递给页面
model.addAttribute("id", userEntity.getId());
model.addAttribute("name", userEntity.getName());
model.addAttribute("sex", userEntity.getSex());
model.addAttribute("address", userEntity.getAddress());
model.addAttribute("birthday", userEntity.getBirthday());
return "user";
}
浏览器访问:
注意:请求参数中的id,与@RequestParam中的value值对应,与参数itemId无关。
4.3.Pojo类型
可以使用对象类型接收参数,要求对象属性名与参数名要一致。
1)Controller
@RequestMapping("/updateUserById")
public String updateUserById(UserEntity userEntity){
// 根据id修改数据
boolean flag = userService.updateUserById(userEntity);
if(flag){
return "success";
}else {
return "faliure";
}
}
2)新增success.jsp、failure.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
</head>
<body>
操作成功!!!
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
</head>
<body>
操作失败!!!
</body>
</html>
3)使用postman模拟请求:
4)发送请求,操作成功
4.4.解决乱码问题
解决post请求乱码问题,在web.xml中:
<!-- 解决post乱码问题 -->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 设置编码参是UTF8 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
解决get请求乱码问题,方案有两种:
1)修改tomcat配置文件添加编码与工程编码一致,如下:
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
2)对参数进行重新编码:
String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码
4.5.包装Pojo类型
包装类:
public class QueryVo {
private UserEntity userEntity;
}
Controller:
@RequestMapping("/queryUserById")
public String queryItem(QueryVo queryVo) {
System.out.println(queryVo.getUserEntity().getId());
System.out.println(queryVo.getUserEntity().getName());
return "success";
}
4.6.自定义参数
- 由于日期数据有很多种格式,springmvc没办法把字符串转换成日期类型。所以需要自定义参数绑定。
- 前端控制器接收到请求后,找到注解形式的处理器适配器,对RequestMapping标记的方法进行适配,并对方法中的形参进行参数绑定。可以在springmvc处理器适配器上自定义转换器Converter进行参数绑定。
- 一般使用<mvc:annotation-driven/>注解驱动加载处理器适配器,可以在此标签上进行配置。
4.6.1.自定义Converter
//Converter<S, T>
//S:source,需要转换的源的类型
//T:target,需要转换的目标类型
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
try {
// 把字符串转换为日期类型
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse(source);
return date;
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 如果转换异常则返回空
return null;
}
}
4.6.2.配置Converter
我们同时可以配置多个的转换器,类似下图的usb设备,可以接入多个usb设备。
在springmvc.xml文件中配置:
方式一:
<!-- 配置注解驱动 -->
<!-- 如果配置此标签,可以不用配置... -->
<mvc:annotation-driven conversion-service="conversionService" />
<!-- 转换器配置 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.itcast.springmvc.converter.DateConverter" />
</set>
</property>
</bean>
方式二:(了解)
<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer" ref="customBinder"></property>
</bean>
<!-- 自定义webBinder -->
<bean id="customBinder" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService" />
</bean>
<!-- 转换器配置 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.itcast.springmvc.convert.DateConverter" />
</set>
</property>
</bean>
注意:此方法需要独立配置处理器映射器、适配器,不再使用<mvc:annotation-driven/>
4.7.数组类型
Controller方法中可以用String[]接收,或者pojo的String[]属性接收。两种方式任选其一即可。
包装类:
public class QueryVo {
private String[] ids;
}
Controller:
@RequestMapping("/queryUserById")
public String queryItem(QueryVo queryVo, Integer[] ids) {
System.out.println(queryVo.getItem().getId());
System.out.println(queryVo.getItem().getName());
System.out.println(queryVo.getIds().length);
System.out.println(ids.length);
return "success";
}
4.8.集合类型
包装类:
public class QueryVo {
private List<UserEntity> entityList;
}
Controller:
@RequestMapping("/queryUserById")
public String queryItem(QueryVo queryVo) {
System.out.println(queryVo.getItem().getId());
System.out.println(queryVo.getItem().getName());
return "success";
}
注意:接收List类型的数据必须是pojo的属性,如果方法的形参为ArrayList类型无法正确接收到数据。
绑定集合与绑定数组的区别:都可以在封装pojo的类中添加数组属性,但绑定数组还可以直接在方法中用数组参数表示,而集合不可以
5.@RequestMapping
通过@RequestMapping注解可以定义不同的处理器映射规则。
5.1.URL路径映射
@RequestMapping(value="item") 或 @RequestMapping("/item"), / 可省略
value的值是数组,可以将多个url映射到同一个方法
@RequestMapping(value = {"/queryUserById","queryById"})
public ModelAndView queryUserById(int id){
// 根据id查询商品数据
UserEntity userEntity = userService.queryUserById(id);
// 设置逻辑视图
ModelAndView modelAndView = new ModelAndView("user");
modelAndView.addObject("userEntity", userEntity);
return modelAndView;
}
5.2.添加在类上面
在class上添加@RequestMapping(url)指定通用请求前缀, 限制此类下的所有方法请求url必须以请求前缀开头.
@Controller
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = {"/queryUserById","queryById"})
public ModelAndView queryUserById(int id){
// 根据id查询商品数据
UserEntity userEntity = userService.queryUserById(id);
// 设置逻辑视图
ModelAndView modelAndView = new ModelAndView("user");
modelAndView.addObject("userEntity", userEntity);
return modelAndView;
}
}
此时需要进入queryItemList()方法的请求url为:
http://127.0.0.1:8080/user/queryUserById
或者 http://127.0.0.1:8080/user/queryById
5.3.请求方法限定
除了可以对url进行设置,还可以限定请求进来的方法
1)限定GET方法
@RequestMapping(method = RequestMethod.GET)
如果通过POST访问则报错:
HTTP Status 405 - Request method 'POST' not supported
例如:
@RequestMapping(value = "itemList",method = RequestMethod.POST)
2)限定POST方法
@RequestMapping(method = RequestMethod.POST)
如果通过GET访问则报错:
HTTP Status 405 - Request method 'GET' not supported
3)GET和POST都可以
@RequestMapping(method = {RequestMethod.GET,RequestMethod.POST})
注:如果不配置请求方式,默认任何请求方式都可以。
6.方法返回值
6.1.返回 ModelAndView
controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view,此处不再演示。
6.2.返回void
在Controller方法形参上可以定义request和response,使用request或response指定响应结果:
1)使用request转发页面,如下:
request.getRequestDispatcher("页面路径").forward(request, response);
request.getRequestDispatcher("/WEB-INF/jsp/success.jsp").forward(request, response);
2)可以通过response页面重定向:
response.sendRedirect("url")
response.sendRedirect("/springmvc-web2/itemEdit.action");
3)可以通过response指定响应结果,例如响应json数据如下:
response.getWriter().print("{\"abc\":123}");
6.3.返回字符串
6.3.1.逻辑视图名
controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
比较返回ModelAndView和String的区别:
两者都可以携带数据和跳转视图,但ModelAndView不解耦,跳转视图和携带数据是同一个对象,而String是解耦的,视图和数据分离,所以建议使用返回String的方式
@RequestMapping(value="/queryItemList")
public ModelAndView queryItemList(){
//调用service查询数据
List<Items> list = itemsService.queryItemsList();
//创建ModelAndView(类似模型对象),用来存放数据和视图
ModelAndView modelAndView = new ModelAndView();
//设置数据到模型对象中
modelAndView.addObject("itemList", list);
//设置视图,需要设置视图的位置
modelAndView.setViewName("itemList");
return modelAndView;
}
@RequestMapping(value="/queryItemList")
public String queryItemList2(Model model){
//调用service查询数据
List<Items> list = itemsService.queryItemsList();
//直接使用参数model放置数据
model.addAttribute("itemList", list);
//跳转视图
return "itemList";
}
6.3.2.Redirect重定向
Contrller方法返回字符串可以重定向到一个url地址
@RequestMapping("updateItem")
public String updateItemById(Item item) {
// 更新商品
itemService.updateItemById(item);
// 修改商品成功后,重定向到商品编辑页面
// 重定向后浏览器地址栏变更为重定向的地址,
// 重定向相当于执行了新的request和response,所以之前的请求参数都会丢失
// 如果要指定请求参数,需要在重定向的url后面添加 ?itemId=1 这样的请求参数
return "redirect:/itemEdit?itemId=" + item.getId();
}
6.3.3.forward转发
Controller方法执行后继续执行另一个Controller方法
@RequestMapping("updateItem")
public String updateItemById(Item item) {
// 更新商品
itemService.updateItemById(item);
// 修改商品成功后,重定向到商品编辑页面
// return "redirect:/itemEdit.action?itemId=" + item.getId();
// 修改商品成功后,继续执行另一个方法
// 使用转发的方式实现。转发后浏览器地址栏还是原来的请求地址,
// 转发并没有执行新的request和response,所以之前的请求参数都存在
return "forward:/itemEdit";
}
7.springmvc与struts2的区别
- springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过滤器。
- springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
- Struts采用值栈存储请求和响应的数据,通过OGNL存取数据, springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过request域传输到页面。Jsp视图解析器默认使用jstl。
8.异常处理器
springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。
8.1.异常处理思路
系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:
8.2.自定义异常类
为了区别不同的异常,通常根据异常类型进行区分,这里我们创建一个自定义系统异常。
如果controller、service、dao抛出此类异常说明是系统预期处理的异常信息。
public class MyException extends Exception {
// 异常信息
private String message;
public MyException() {
super();
}
public MyException(String message) {
super();
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
8.3.自定义异常处理器
public class CustomHandleException implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object obj,
Exception exception) {
// 参数obj: 发生异常的包名+类名+方法名 定位某个方法
// 参数exception: 抛出的是什么异常
// 定义异常信息
String msg;
// 判断异常类型
if (exception instanceof MyException) {
// 如果是自定义异常,读取异常信息
msg = exception.getMessage();
} else {
// 如果是运行时异常,则取错误堆栈,从堆栈中获取异常信息
Writer out = new StringWriter();
PrintWriter s = new PrintWriter(out);
exception.printStackTrace(s);
msg = out.toString();
}
// 把错误信息发给相关人员,邮件,短信等方式
// TODO
// 返回错误页面,给用户友好页面显示错误信息
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", msg);
modelAndView.setViewName("error");
return modelAndView;
}
}
8.4.异常处理器配置
在springmvc.xml中添加:
<!-- 配置自定义全局异常处理器 -->
<bean id="customHandleException" class="com.itcast.exception.CustomHandleException"/>
9.@ResponseBody
作用:
@ResponseBody注解用于将Controller的方法返回的对象,通过springmvc提供的HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端
本例子应用:@ResponseBody注解实现将Controller方法返回java对象转换为json响应给客户端。
配置json转换器:
方式一:(建议)
在springmvc.xml配置文件中,使用注解驱动
方式二:
如果不使用注解驱动<mvc:annotation-driven />,就需要给处理器适配器配置json转换器,参考之前学习的自定义参数绑定。
在springmvc.xml配置文件中,给处理器适配器加入json转换器:
<!--处理器适配器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean> </list> </property> </bean>
10.RESTful支持
10.1.什么是restful?
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
资源:互联网所有的事物都可以被抽象为资源
资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。分别对应 添加、 删除、修改、查询。
传统方式操作资源
http://127.0.0.1/item/queryItem.action?id=1 查询,GET
http://127.0.0.1/item/saveItem.action 新增,POST
http://127.0.0.1/item/updateItem.action 更新,POST
http://127.0.0.1/item/deleteItem.action?id=1 删除,GET或POST
使用RESTful操作资源
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 删除,DELETE
10.2.从URL上获取参数
使用RESTful风格开发的接口,根据id查询商品,接口地址是:http://127.0.0.1/item/1
我们需要从url上获取商品id,步骤如下:
1)使用注解@RequestMapping("item/{id}")声明请求的url
{xxx}叫做占位符,请求的URL可以是“item/1”或“item/2”
2)使用(@PathVariable() Integer id)获取url上的数据
/**
* 使用RESTful风格开发接口,实现根据id查询商品
*/
@RequestMapping("item/{id}")
@ResponseBody
public Item queryItemById(@PathVariable() Integer id) {
Item item = this.itemService.queryItemById(id);
return item;
}
如果@RequestMapping中表示为"item/{id}",id和形参名称一致,@PathVariable不用指定名称。
如果不一致,例如"item/{ItemId}"则需要指定名称@PathVariable("itemId")。
注意两个区别
1)@PathVariable是获取url上数据的。@RequestParam获取请求参数的(包括post表单提交)
2)如果加上@ResponseBody注解,就不会走视图解析器,不会返回页面,目前返回的json数据。如果不加,就走视图解析器,返回页面
11.拦截器
11.1.定义
Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。
11.2.拦截器定义
实现HandlerInterceptor接口,如下:
public class HandlerInterceptor1 implements HandlerInterceptor {
// controller执行后且视图返回后调用此方法
// 这里可得到执行controller时的异常信息
// 这里可记录操作日志
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("HandlerInterceptor1....afterCompletion");
}
// controller执行后但未返回视图前调用此方法
// 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
System.out.println("HandlerInterceptor1....postHandle");
}
// Controller执行前调用此方法
// 返回true表示继续执行,返回false中止执行
// 这里可以加入登录校验、权限拦截等
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("HandlerInterceptor1....preHandle");
// 设置为true,测试使用
return true;
}
}
10.3.拦截器配置
在springmvc.xml中配置拦截器
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 所有的请求都进入拦截器 -->
<mvc:mapping path="/**" />
<!-- 配置自定义拦截器 -->
<bean class="cn.itcast.ssm.interceptor.HandlerInterceptor1" />
</mvc:interceptor>
<mvc:interceptor>
<!-- 所有的请求都进入拦截器 -->
<mvc:mapping path="/**" />
<!-- 配置自定义拦截器 -->
<bean class="cn.itcast.ssm.interceptor.HandlerInterceptor2" />
</mvc:interceptor>
</mvc:interceptors>
总结:
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用
postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有preHandle返回true才调用