SpringMVC简介
MVC模型
MVC全称Model View Controller,是一种设计创建Web应用程序的 模式。这三个单词分别代表Web应用程序的三个部分:
Model(模型):指数据模型。用于存储数据以及处理用户请求 的业务逻辑。在Web应用中,JavaBean对象,业务模型等都属 于Model。
View(视图):用于展示模型中的数据的,一般为jsp或html文 件。
Controller(控制器):是应用程序中处理用户交互的部分。接 受视图提出的请求,将数据交给模型处理,并将处理后的结果交 给视图显示。
SpringMVC
SpringMVC是一个基于MVC模式的轻量级Web框架,是Spring框架 的一个模块,和Spring可以直接整合使用。SpringMVC代替了 Servlet技术,它通过一套注解,让一个简单的Java类成为处理请求 的控制器,而无须实现任何接口。
SpringMVC入门案例
接下来我们编写一个SpringMVC的入门案例
1、使用maven创建web项目,补齐包结构。
2、引入相关依赖和tomcat插件
<dependencies> <!-- Spring核心模块 --> <dependency> <groupId>org.springframework</groupId> <artifactId>springcontext</artifactId> <version>5.2.12.RELEASE</version> </dependency> <!-- SpringWeb模块 --> <dependency> <groupId>org.springframework</groupId> <artifactId>springweb</artifactId> <version>5.2.12.RELEASE</version> </dependency> <!-- SpringMVC模块 --> <dependency> <groupId>org.springframework</groupId> <artifactId>springwebmvc</artifactId> <version>5.2.12.RELEASE</version> </dependency> <!-- Servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servletapi</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <!-- JSP --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <!-- tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.1</version> <configuration> <port>8080</port> <path>/</path> <uriEncoding>UTF8</uriEncoding> <server>tomcat7</server> <systemProperties> <java.util.logging.SimpleFormatter.format>%1$tH:%1$tM:%1$tS %2$s%n%4$s: %5$s%6$s%n </java.util.logging.SimpleFormatter.format> </systemProperties> </configuration> </plugin> </plugins> </build>
3、在web.xml中配置前端控制器DispatcherServlet。
<web-app> <display-name>Archetype Created Web Application</display-name> <!--SpringMVC前端控制器,本质是一个 Servlet,接收所有请求,在容器启动时就会加载--> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</paramvalue> </init-param> <load-on-startup>1</load-onstartup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
4 编写SpringMVC核心配置文件springmvc.xml,该文件和Spring 配置文件写法一样。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> <!-- 扫描包 --> <context:component-scan base-package="com.itbaizhan"/> <!-- 开启SpringMVC注解的支持 --> <mvc:annotation-driven/> </beans>
5、编写控制器
@Controller public class MyController1 { // 该方法的访问路径是/c1/hello1 @RequestMapping("/c1/hello1") public void helloMVC(){ System.out.println("hello SpringMVC!"); } }
6 使用tomcat插件启动项目,访问 http://localhost:8080/c1/hello1
SpringMVC执行流程
SpringMVC的组件
DispatcherServlet:前端控制器,接受所有请求,调用其他组件。
HandlerMapping:处理器映射器,根据配置找到方法的执行链。
HandlerAdapter:处理器适配器,根据方法类型找到对应的处理器。
ViewResolver:视图解析器,找到指定视图。
组件的工作流程
1、客户端将请求发送给前端控制器。
2、前端控制器将请求发送给处理器映射器,处理器映射器根据路径找到方法的执行链,返回给前端控 制器。
3、前端控制器将方法的执行链发送给处理器适配器,处理器适配器根据方法类型找到对应的处理器。
4、处理器执行方法,将结果返回给前端控制器。
5、前端控制器将结果发送给视图解析器,视图解析器找到视图文件位置。
6、视图渲染数据并将结果显示到客户端。
SpringMVC参数获取_封装为简单数据类型
在Servlet中我们通过 request.getParameter(name) 获取请求参数。该方式存 在两个问题:
1、请求参数较多时会出现代码冗余。
2、与容器紧耦合。
而SpringMVC支持参数注入的方式用于获取请求数据,即将请求参 数直接封装到方法的参数当中。用法如下:
1、编写控制器方法
// 获取简单类型参数 @RequestMapping("/c1/param1") public void simpleParam(String username,int age){ System.out.println(username); System.out.println(age); }
2、访问该方法时,请求参数名和方法参数名相同,即可完成自动封装。
SpringMVC参数获取_封装为对象类型
SpringMVC支持将参数直接封装为对象,写法如下:
封装单个对象
1、编写实体类
public class Student { private int id; private String name; private String sex; // 省略getter/setter/tostring }
2、编写控制器方法
// 获取对象类型参数 @RequestMapping("/c1/param2") public void objParam(Student student){ System.out.println(student); }
3、访问该方法时,请求参数名和方法参数的属性名相同,即可完成自动封装。
封装关联对象
1、编写实体类
public class Address { private String info; //地址信息 private String postcode; //邮编 // 省略getter/setter/tostring } public class Student { private int id; private String name; private String sex; private Address address; // 地址对象 // 省略getter/setter/tostring }
2、编写控制器方法
// 获取关联对象类型参数 @RequestMapping("/c1/param3") public void objParam2(Student student){ System.out.println(student); }
3、访问该方法时,请求参数名和方法参数的属性名相同,即可完成自动封装。
我们也可以使用表单发送带有参数的请求:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>表单提交</title> </head> <body> <form action="/c1/param3" method="post"> id:<input name="id"> 姓名:<input name="name"> 性别:<input name="sex"> 住址:<input name="address.info"> 邮编:<input name="address.postcode"> <input type="submit"> </form> </body> </html>
SpringMVC参数获取_封装为集合类型
SpringMVC支持将参数封装为List或Map集合,写法如下:
封装为List集合
封装为简单数据类型集合
1、编写控制器方法
// 绑定简单数据类型List参数,参数前必须添加 @RequestParam注解 @RequestMapping("/c1/param4") public void listParam(@RequestParamList<String> users){ System.out.println(users); }
该方式也可以绑定数组类型:
@RequestMapping("/c1/param5") public void listParam2(@RequestParam String[] users){ System.out.println(users[0]); System.out.println(users[1]); }
2、请求的参数写法
封装为对象类型集合
SpringMVC不支持将参数封装为对象类型的List集合,但可以封装 到有List属性的对象中。
1、编写实体类
public class Student { private int id; private String name; private String sex; private List<Address> address; // 地址集合 // 省略getter/setter/tostring }
2、编写控制器方法
// 对象中包含集合属性 @RequestMapping("/c1/param6") public void listParam3(Student student){ System.out.println(student); }
3、请求的参数写法
封装为Map集合
同样,SpringMVC要封装Map集合,需要封装到有Map属性的对象中。
1、编写实体类
public class Student { private int id; private String name; private String sex; private Map<String,Address> address; // 地址集合 // 省略getter/setter/tostring }
2、编写控制器方法
// 对象中包含Map属性 @RequestMapping("/c1/param7") public void mapParam(Student student){ System.out.println(student); }
3、请求的参数写法
SpringMVC参数获取_使用Servlet原生对象获取参数
SpringMVC也支持使用Servlet原生对象,在方法参数中定义 HttpServletRequest 、 HttpServletResponse 、 HttpSession 等类型的参数即可直接在 方法中使用。
// 使用Servlet原生对象 @RequestMapping("/c1/param8") public void servletParam(HttpServletRequest request, HttpServletResponse response, HttpSession session){ // 原生对象获取参数 System.out.println(request.getParameter("name")); System.out.println(response.getCharacterEncoding()); System.out.println(session.getId()); }
访问该方法即可:http://localhost:8080/c1/param8?name=bjwan
一般情况下,在SpringMVC中都有对Servlet原生对象的方法的 替代,推荐使用SpringMVC的方式代替Servlet原生对象。
SpringMVC参数获取_自定义参数类型转换器
前端传来的参数全部为字符串类型,SpringMVC使用自带的转换器 将字符串参数转为需要的类型。如:
// 获取简单类型参数 @RequestMapping("/c1/param1") public void simpleParam(String username,int age){ System.out.println(username); System.out.println(age); }
请求路径:http://localhost:8080/c1/param1?username=bz&age =10
但在某些情况下,无法将字符串转为需要的类型,如:
@RequestMapping("/c1/param9") public void dateParam(Date birthday){ System.out.println(birthday); }
由于日期数据有很多种格式,SpringMVC没办法把所有格式的字符 串转换成日期类型。比如参数格式为 birthday=2025-01-01 时,SpringMVC 就无法解析参数。此时需要自定义参数类型转换器。
1、定义类型转换器类,实现Converter接口
// 类型转换器必须实现Converter接口,两个泛型代表转换前的类型,转换后的类型 public class DateConverter implements Converter<String, Date> { /** * 转换方法 * @param source 转换前的数据 * @return 转换后的数据 */ @Override public Date convert(String source) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date date = null; try { date = sdf.parse(source); } catch (ParseException e) { e.printStackTrace(); } return date; } }
2、注册类型转换器对象
<!-- 配置转换器工厂 --> <bean id="dateConverter" class="org.springframework.context.support.ConversionServiceFactoryBean"> <!-- 转换器集合 --> <property name="converters"> <set> <!-- 自定义转换器 --> <bean class="com.itbaizhan.converter.DateConverter"></bean> </set> </property> </bean <!-- 使用转换器工厂 --> <mvc:annotation-driven conversionservice="converterFactory"> </mvc:annotation-driven>
3、此时再访问http://localhost:8080/c1/param9?birthday=2025- 01-01时,SpringMVC即可将请求参数封装为Date类型的参数。
SpringMVC参数获取_编码过滤器
在传递参数时,tomcat8以上能处理get请求的中文乱码,但不能处 理post请求的中文乱码
1、编写jsp表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>编码过滤器</title> </head> <body> <form action="/cn/code" method="post"> 姓名:<input name="username"> <input type="submit"> </form> </body> </html>
2、编写控制器方法
@RequestMapping("/cn/code") public void code(String username){ System.out.println(username); }
SpringMVC提供了处理中文乱码的过滤器,在web.xml中配置该过 滤器即可解决中文乱码问题:
<!--SpringMVC中提供的字符编码过滤器,放在所有过滤器的最上方--> <filter> <filter-name>encFilter</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> </filter> <filter-mapping> <filter-name>encFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
SpringMVC处理响应_配置视图解析器
SpringMVC默认情况下会在控制器执行完成后跳转到视图页面,视 图解析器能找到相应的视图,之前的404异常就是由于没有配置视 图解析器导致找不到视图。
在SpringMVC中提供了13个视图解析器,用于支持不同的视图技术。InternalResourceViewResolver是SpringMVC的默认视图解析 器,用来解析JSP视图。
<!-- 视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 视图前缀 --> <property name="prefix" value="/" /> <!-- 视图后缀 --> <property name="suffix" value=".jsp" /> </bean>
SpringMVC处理响应_控制器方法的返回值
我们可以通过控制器方法的返回值设置跳转的视图,控制器方法支 持以下返回值类型:
返回值为void
此时会跳转到名字是 前缀+方法路径名+后缀 的jsp页面
1、编写控制器方法
// 路径是helloMVC,方法执行完后会跳转到/helloMVC.jsp @RequestMapping("/helloMVC") public void helloMVC(){ System.out.println("hello SpringMVC!"); }
2、编写helloMVC.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>MVC</title> </head> <body> <h1>欢迎来到SpringMVC</h1> </body> </html>
返回值为String
此时会跳转到名字是 前缀+返回值+后缀 的jsp页面
编写控制器方法
// 返回值为String @RequestMapping("/c2/hello1") public String helloMVC1(){ System.out.println("hello SpringMVC!"); // 方法执行完后会跳转到/helloMVC.jsp return "helloMVC"; }
返回值为ModelAndView
这是SpringMVC提供的对象,该对象可以向request域设置数据并 指定跳转的页面。该对象中包含Model对象和View对象。
1、Model:向request域中设置数据。
2、View:指定跳转的页面。
1、编写控制器方法
// 返回值为ModelAndView @RequestMapping("/c2/hello2") public ModelAndView useMAV(){ System.out.println("返回值类型为ModelAndView"); // 1.创建ModelAndView对象 ModelAndView modelAndView = new ModelAndView(); // 2.获取Model对象,本质是一个Map Map<String, Object> model = modelAndView.getModel(); // 3.使用Model对象向request域设置数据 model.put("name","程序员"); // 4.使用View对象设置跳转的路径为/baizhan.jsp modelAndView.setViewName("baizhan"); return modelAndView; }
2、编写jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java"%> <html> <head> <title>百千万</title> </head> <body> <h1>你好!${requestScope.name}</h1> </body> </html>
3、修改web.xml命名空间,让jsp页面默认支持el表达式
<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/webapp_3_1.xsd" version="3.1"> </web-app>
SpringMVC处理响应_request域设置数据
当控制器返回值为ModelAndView时我们可以向request域设置数 据,我们还有以下方法可以向request域设置数据:
使用原生的HttpServletRequest
@RequestMapping("/c2/hello3") public String setRequestModel(HttpServletRequest request){ request.setAttribute("username","面涂学堂"); return "baizhan"; }
使用Model、ModelMap
SpringMVC提供了Model接口和ModelMap类,控制器方法添加这 两个类型的参数,使用该参数设置数据,该数据就会存到request域中。
@RequestMapping("/c2/hello4") public String setRequestModel2(Model model, ModelMap modelMap){ // 使用Model将数据存入request域 // model.addAttribute("username","辛苦学堂"); // 使用ModelMap将数据存入request域 modelMap.addAttribute("username","辛苦学堂"); return "baizhan"; }
使用Map集合
Model接口底层就是一个Map集合,我们可以给控制器方法设置 Map类型的参数,向Map中添加键值对,数据也会存到request域 中。
@RequestMapping("/c2/hello5") public String setRequestModel3(Map map){ map.put("username","辛苦学堂"); return "baizhan"; }
SpringMVC处理响应_session域设置数据
Session作用域表示在当前会话中有效。在SpringMVC中对于
Session作用域传值,只能使用HttpSession对象来实现。
1、编写控制器方法
@RequestMapping("/c2/hello6") public String setSeesionModel(HttpSession session){ session.setAttribute("address","北京"); return "baizhan"; }
2、编写jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java"%> <html> <head> <title>百战不败</title> </head> <body> <h1>你好!${requestScope.name}</h1> <h1>地址是!${sessionScope.address}</h1> </body> </html>
SpringMVC处理响应_context域设置数据
context作用域表示在整个应用范围都有效。在SpringMVC中对 context作用域传值,只能使用ServletContext对象来实现。但是该 对象不能直接注入到方法参数中,需要通过HttpSession对象获取。
1、编写控制器方法
@RequestMapping("/c2/hello7") public String setContextModel(HttpSession session){ ServletContext servletContext = session.getServletContext(); servletContext.setAttribute("age",10); return "baizhan"; }
2、编写jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java"%> <html> <head> <title>百战不败</title> </head> <body> <h1>你好!${requestScope.name}</h1> <h1>地址是!${sessionScope.address}</h1> <h1>年纪是!${applicationScope.age}</h1> </body> </html>
SpringMVC处理响应_请求转发&重定向
之前的案例,我们发现request域中的值可以传到jsp页面中,也就 是通过视图解析器跳转到视图的底层是请求转发。
如果我们跳转时不想使用视图解析器,可以使用原生 HttpServletRequest进行请求转发或HttpServletResponse进行重定向:
@RequestMapping("/c2/hello8") public void myForward1(HttpServletRequest request, HttpServletResponse response) throws Exception{ request.setAttribute("name","辛苦学堂"); // 请求转发 // request.getRequestDispatcher("/c2/hello9").forward(request,response); // 原生重定向 response.sendRedirect("/c2/hello9"); } @RequestMapping("/c2/hello9") public void myForward2(HttpServletRequest request){ System.out.println("hello"); System.out.println(request.getAttribute("name")); }
SpringMVC还提供了一种更简单的请求转发和重定向的写法:
@RequestMapping("/c2/hello10") public String myForward3(HttpServletRequest request){ request.setAttribute("name","辛苦学堂"); // 请求转发 return "forward:/c2/hello9"; // 重定向 // return "redirect:/c2/hello9"; }
SpringMVC通过注解来实现控制器的功能,接下来我们详细学习 SpringMVC的常用注解:
SpringMVC的常用注解:
SpringMVC注解_@Controller
作用:标记控制器,将控制器交给Spring容器管理。
位置:类上方
SpringMVC注解_@RequestMapping
作用:给控制器方法设置请求路径
位置:方法或类上方。用于类上,表示类中的所有控制器方法都是 以该地址作为父路径。
属性:
1、value/path:请求路径
2、method:指定请求方式
3、params:规定必须发送的请求参数
4、headers:规定请求必须包含的请求头
@Controller @RequestMapping("/c3") public class MyController3 { /* 访问路径为 /c3/annotation1 支持post和get请求 请求时必须带有age参数 请求时必须带有User-agent请求头 */ @RequestMapping(path = "/annotation1",method = {RequestMethod.GET,RequestMethod.POST},params = {"age"},headers = {"User-agent"}) public String annotation1(String username){ System.out.println(username); return "baizhan"; } }
SpringMVC注解_@RequestParam
作用:在控制器方法中获取请求参数
位置:方法参数前
属性:
1、name:指定请求参数名称
2、defaultValue: 为参数设置默认值
3、required:设置是否是必须要传入的参数
/* 定义请求的参数名为username,默认值为sxt,不是必须的参数 */ @RequestMapping("/annotation2") public String annotation2(@RequestParam(name = "username",defaultValue = "sxt",required = false) String name){ System.out.println(name); return "baizhan"; }
SpringMVC注解_@RequestHeader、@CookieValue
@RequestHeader
作用:在控制器方法中获取请求头数据
位置:方法参数前
@CookieValue
作用:在控制器方法中获取Cookie数据
位置:方法参数前
/* 获取User-Agent请求头 获取JSESSIONID的Cookie值 */ @RequestMapping("/annotation3") public String annotation3(@RequestHeader("User-Agent") String userAgent, @CookieValue("JSESSIONID") String jSessionId){ System.out.println(userAgent); System.out.println(jSessionId); return "baizhan"; }