SSM学习第二天
学习springMvc的初步学习
一、Spring集成web环境 1.1、ApplicationContext应用上下文获取方式 应用上下文对象是通过new ClasspathXmlApplicationContext (spring配置文件)方式获取的,但是每次从容器中获得Bean时都要编写new ClasspathXmlApplicationContext (spring配置文件) ,这样的弊端是配置文件加载多次,应用上下文对象创建多次。
在Web项目中,可以使用ServletContextListener 监听Web应用的启动,我们可以在Web应用启动时,就加载Spring的配置文件,创建应用上下文对象ApplicationContext ,在将其存储到最大的域servletContext 域中,这样就可以在任意位置从域中获得应用上下文ApplicationContext 对象了。
1.2 、Spring提供获取应用上下文的工具 上面的分析不用手动实现,Spring提供了一个监听器ContextLoaderListener 就是对上述功能的封装,该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext 域中,提供了一个客户端工具WebApplicationContextUtils 供使用者获得应用上下文对象。
所以我们需要做的只有两件事:
①在web.xml 中配置ContextLoaderListener 监听器(导入spring-web坐标)
②使用WebApplicationContextUtils 获得应用上下文对象ApplicationContext
1.3 、导入Spring集成web的坐标1 2 3 4 5 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.0 .5 .RELEASE</version> </dependency>
1.4 、配置ContextLoaderListener监听器1 2 3 4 5 6 7 8 9 10 11 <!--全局参数--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!--Spring的监听器--> <listener> <listener-class > org .springframework .web .context .ContextLoaderListener </listener -class > </listener >
1.5 、通过工具获得应用上下文对象1 2 3 4 5 6 7 8 9 10 public class WebApplicationContextUtils { public static ApplicationContext getWebApplicationContext (ServletContext servletContext) { return (ApplicationContext) servletContext.getAttribute("app" ); } } ServletContext servletContext = this .getServletContext(); ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
二、SpringMVC 简介 2.1 、SpringMVC概述SpringMVC 是一种基于 Java 的实现 MVC 设计模型 的请求驱动类型的轻量级 Web 框架 ,属于SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 中。
SpringMVC 已经成为目前最主流的MVC框架之一,并且随着Spring3.0 的发布,全面超越 Struts2,成为最优秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求。
2.2、 SpringMVC快速入门 需求:客户端发起请求,服务器端接收请求,执行逻辑并进行视图跳转。
开发步骤:
①导入SpringMVC相关坐标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <!--Spring坐标--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0 .5 .RELEASE</version> </dependency> <!--SpringMVC坐标--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0 .5 .RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0 .1 </version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.2 .1 </version> <scope>provided</scope> </dependency>
②配置SpringMVC核心控制器DispathcerServlet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <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 :spring -mvc .xml </param -value > </init -param > <load -on -startup >1</load -on -startup > </servlet > <servlet -mapping > <servlet -name >DispatcherServlet </servlet -name > <url -pattern >/</url -pattern > </servlet -mapping >
③创建Controller类和视图页面
1 2 3 4 5 6 7 public class QuickController { public String quickMethod () { System.out.println("quickMethod running....." ); return "index" ; } }
④使用注解配置Controller类中业务方法的映射地址
1 2 3 4 5 6 7 8 9 @Controller public class QuickController { @RequestMapping("/quick") public String quickMethod () { System.out.println("quickMethod running....." ); return "index" ; } }
⑤配置SpringMVC核心文件 spring-mvc.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 <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" /> </beans>
⑥客户端发起请求测试
三、SpringMVC 组件解析 3.1 、SpringMVC的执行流程
①用户发送请求至前端控制器DispatcherServlet。
②DispatcherServlet收到请求调用HandlerMapping处理器映射器。
③处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
④DispatcherServlet调用HandlerAdapter处理器适配器。
⑤HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
⑥Controller执行完成返回ModelAndView。
⑦HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
⑧DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
⑨ViewReslover解析后返回具体View。
⑩DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。DispatcherServlet响应用户。
3.2 、SpringMVC组件解析1. 前端控制器: DispatcherServlet
用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的中心,由
它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。
2. 处理器映射器: HandlerMapping
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的
映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3. 处理器适配器: HandlerAdapter
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理
器进行执行。
4. 处理器: Handler
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由
Handler 对具体的用户请求进行处理。
5 .视图解析器: View Resolver
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
6. 视图: View
SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面
3.4 SpringMVC的XML配置解析1. 视图解析器
我们可以通过属性注入的方式修改视图的的前后缀
1 2 3 4 5 <!--配置内部资源视图解析器--> <bean class ="org.springframework.web.servlet.view.InternalResourceViewResolver" > <property name="prefix" value="/WEB-INF/views/" ></property> <property name="suffix" value=".jsp" ></property> </bean>
四、SpringMVC的数据响应 4.1 、SpringMVC的数据响应方式1) 页面跳转
直接返回字符串
通过ModelAndView对象返回
2) 回写数据
4.2 、页面跳转1. 返回字符串形式
直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转。
2. 返回ModelAndView对象
1 2 3 4 5 6 7 8 9 10 11 12 @RequestMapping("/quick2") public ModelAndView quickMethod2 () { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("redirect:index.jsp" ); return modelAndView; } @RequestMapping("/quick3") public ModelAndView quickMethod3 () { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("forward:/WEB-INF/views/index.jsp" ); return modelAndView; }
3. 向request域存储数据
在进行转发时,往往要向request域中存储数据,在jsp页面中显示,那么Controller中怎样向request域中存储数据呢?
①通过SpringMVC框架注入的request对象setAttribute()方法设置
1 2 3 4 5 @RequestMapping("/quick") public String quickMethod (HttpServletRequest request) { request.setAttribute("name" ,"zhangsan" ); return "index" ; }
②通过ModelAndView的addObject()方法设置
1 2 3 4 5 6 7 @RequestMapping("/quick3") public ModelAndView quickMethod3 () { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("forward:/WEB-INF/views/index.jsp" ); modelAndView.addObject("name" ,"lisi" ); return modelAndView; }
4.3 回写数据 1. 直接返回字符串
Web基础阶段,客户端访问服务器端,如果想直接回写字符串作为响应体返回的话,只需要使用
response.getWriter().print(“hello world”) 即可,那么在Controller中想直接回写字符串该怎样呢?
①通过SpringMVC框架注入的response对象,使用response.getWriter().print(“hello world”) 回写数据,此时不需要视图跳转,业务方法返回值为void。
1 2 3 4 @RequestMapping("/quick4") public void quickMethod4 (HttpServletResponse response) throws IOException { response.getWriter().print("hello world" ); }
②将需要回写的字符串直接返回,但此时需要通过**@ResponseBody**注解告知SpringMVC框架,方法返回的字符串不是跳转是直接在http响应体中返回。
1 2 3 4 5 @RequestMapping("/quick5") @ResponseBody public String quickMethod5 () throws IOException { return "hello springMVC!!!" ; }
在异步项目中,客户端与服务器端往往要进行json格式字符串交互,此时我们可以手动拼接json字符串返回。
开发中往往要将复杂的java对象转换成json格式的字符串,我们可以使用web阶段学习过的json转换工具jackson进行转换,导入jackson坐标。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <!--jackson--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9 .0 </version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9 .0 </version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9 .0 </version> </dependency>
通过jackson转换json格式字符串,回写字符串。
1 2 3 4 5 6 7 8 9 10 @RequestMapping("/quick7") @ResponseBody public String quickMethod7 () throws IOException { User user = new User(); user.setUsername("zhangsan" ); user.setAge(18 ); ObjectMapper objectMapper = new ObjectMapper(); String s = objectMapper.writeValueAsString(user); return s; }
2. 返回对象或集合
通过SpringMVC帮助我们对对象或集合进行json字符串的转换并回写,为处理器适配器配置消息转换参数,指定使用jackson进行对象或集合的转换,在方法上添加**@ResponseBody**就可以返回json格式的字符串,因此,我们可以使用mvc的注解驱动代替上述配置。
1 2 3 4 5 6 7 8 <!--mvc的注解驱动--> <mvc:annotation-driven/>
1 2 3 4 5 6 7 8 9 10 @RequestMapping(value="/quick10") @ResponseBody public User save10 () throws IOException { User user = new User(); user.setUsername("lisi2" ); user.setAge(32 ); return user; }
五、 SpringMVC 获得请求数据 2.1 获得请求参数 客户端请求参数的格式是:name=value&name=value
服务器端要获得请求的参数,有时还需要进行数据的封装,SpringMVC可以接收如下类型的参数:
基本类型参数
POJO类型参数
数组类型参数
集合类型参数
2.2、 获得基本类型参数 Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。
2.3 、获得POJO类型参数Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配。
2.4、获得数组类型参数 Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配。
2.5 获得集合类型参数 获得集合参数时,要将集合参数包装到一个POJO中才可以。
1 2 3 4 5 6 7 8 <form action="${pageContext.request.contextPath}/quick12" method="post" > <input type="text" name="userList[0].username" ><br> <input type="text" name="userList[0].age" ><br> <input type="text" name="userList[1].username" ><br> <input type="text" name="userList[1].age" ><br> <input type="submit" value="提交" ><br> </form>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class VO { private List<User> userList; public List<User> getUserList () { return userList; } public void setUserList (List<User> userList) { this .userList = userList; } @Override public String toString () { return "VO{" + "userList=" + userList + '}' ; } } @RequestMapping("/quick12") @ResponseBody public void quickMethod12 (Vo vo) throws IOException { System.out.println(vo.getUserList()); }
当使用ajax提交时,可以指定contentType为json形式,那么在方法参数位置使用@RequestBody可以直接接收集合数据而无需使用POJO进行包装。
2.5 获得集合类型参数 注意:通过谷歌开发者工具抓包发现,没有加载到jquery文件,原因是SpringMVC的前端控制器DispatcherServlet的url-pattern配置的是/,代表对所有的资源都进行过滤操作,我们可以通过以下两种方式指定放行静态资源:
•在spring-mvc.xml配置文件中指定放行的资源
<mvc:resources mapping=”/js/**” location=”/js/“/>
•使用mvc:default-servlet-handler/ 标签
2.6 请求数据乱码问题 当post请求时,数据会出现乱码,我们可以设置一个过滤器来进行编码的过滤。
1 2 3 4 5 6 7 8 9 10 11 12 <filter> <filter-name>CharacterEncodingFilter</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 >CharacterEncodingFilter </filter -name > <url -pattern >/*</url -pattern > </filter -mapping >
2.7、文件上传 1. 文件上传客户端三要素
1 2 3 4 5 6 7 <form action="${pageContext.request.contextPath}/quick20" method="post" enctype="multipart/form-data" > 名称:<input type="text" name="name" ><br> 文件:<input type="file" name="file" ><br> <input type="submit" value="提交" ><br> </form>
2. 文件上传原理
当form表单修改为多部分表单时,request.getParameter()将失效。
enctype=“application/x-www-form-urlencoded”时,form表单的正文内容格式是:key=value&key =value&key =value
当form表单的enctype取值为Mutilpart/form-data时,请求正文内容就变成多部分形式:
2.7.1、单文件上传步骤 ①导入fileupload和io坐标
1 2 3 4 5 6 7 8 9 10 <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2 .2 </version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4 </version> </dependency>
②配置文件上传解析器
1 2 3 4 5 6 7 8 <bean id="multipartResolver" class ="org.springframework.web.multipart.commons.CommonsMultipartResolver" > <!--上传文件总大小--> <property name="maxUploadSize" value="5242800" /> <!--上传单个文件的大小--> <property name="maxUploadSizePerFile" value="5242800" /> <!--上传文件的编码类型--> <property name="defaultEncoding" value="UTF-8" /> </bean>
③编写文件上传代码
1 2 3 4 5 6 7 8 9 @RequestMapping("/quick20") @ResponseBody public void quickMethod20 (String name,MultipartFile uploadFile) throws IOException { String originalFilename = uploadFile.getOriginalFilename(); uploadFile.transferTo(new File("C:\\upload\\" +originalFilename)); }
2.7.2、多文件上传实现 多文件上传,只需要将页面修改为多个文件上传项,将方法参数MultipartFile类型修改为MultipartFile[]即可
1 2 3 4 5 6 7 8 @RequestMapping("/quick21") @ResponseBody public void quickMethod21 (String name,MultipartFile[] uploadFiles) throws IOException { for (MultipartFile uploadFile : uploadFiles){ String originalFilename = uploadFile.getOriginalFilename(); uploadFile.transferTo(new File("C:\\upload\\" +originalFilename)); } }