springMVC学习笔记(一)
springMVC笔记
1. springmvc的入门介绍
1.1springmvc在三层架构的位置
1.2mvc模型
MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写, 是一种用于设计创建 Web 应用程序表现层的模式。MVC 中每个部分各司其职:
Model(模型): 通常指的就是我们的数据模型。作用一般情况下用于封装数据。
View(视图): 通常指的就是我们的 jsp 或者 html。作用一般就是展示数据的。 通常视图是依据模型数据创建的。
Controller(控制器): 是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。 它相对于前两个不是很好理解,这里举个例子: 例如: 我们要保存一个用户的信息,该用户信息中包含了姓名,性别,年龄等等。 这时候表单输入要求年龄必须是 1~100 之间的整数。姓名和性别不能为空。并且把数据填充 到模型之中。 此时除了 js 的校验之外,服务器端也应该有数据准确性的校验,那么校验就是控制器的该做 的。 当校验失败后,由控制器负责把错误页面展示给使用者。 如果校验成功,也是控制器负责把数据填充到模型,并且调用业务层实现完整的业务需求。
1.3springmvc概述
SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功 能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring 的 Spring MVC 框架或集成其他 MVC 开发框架,如 Struts1(现在一般不用),Struts2 等。 SpringMVC 已经成为目前最主流的 MVC 框架之一,并且随着 Spring3.0 的发布,全面超越 Struts2,成 为最优秀的 MVC 框架。 它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求。
1.4架构的理解
2.环境的搭建
2.1导包
2.2配置Tomcat
3.入门程序
3.1前端控制器
web.xml配置前端控制器
<!-- 前端控制器--> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 默认找 /WEB-INF/[servlet的名称]-servlet.xml--><!-- 给 org.springframework.web.servlet.DispatcherServlet的 contextConfigLocation属性传入spring容器配置文件值,使其加载该文件--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 表示第一个被创建--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <!-- 1. /* 拦截所有 jsp js png .css 建议别使用 2. *.action *.do 拦截已do action结尾的请求 肯定能使用 ERP 3. / 拦截所有 (不包括jsp .png .css) 强烈建议使用 强烈建议使用 面向前台 面向消费者 //对静态资源放行--> <url-pattern>/</url-pattern> </servlet-mapping>
3.2创建springmvc.xml配置文件
3.2.1springmvc.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.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--开启注解扫描,扫描com.springmvc包下包括子孙包中所有的注解--> <context:component-scan base-package="com.springmvc"/> <!--视图解析器对象--> <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 文件所在的包名+前缀--> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 文件的后缀--> <property name="suffix" value=".jsp"/> </bean><!-- 配置自定义类型转换器--> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters" > <set> <bean class="com.springmvc.utils.StringToDateConverter"></bean> </set> </property> </bean> <!-- 开启springMVC框架注解支持--> <mvc:annotation-driven conversion-service="conversionService"/> </beans>
3.2.2springMVC的组件简单介绍
DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由 它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
HandlerMapping:处理器映射器
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的 映射方式,例如:配置文件方式,实现接口方式,注解方式等。
Handler:处理器
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由 Handler 对具体的用户请求进行处理。
HandlAdapter:处理器适配器
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理 器进行执行。
View Resolver:视图解析器
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名 即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
View:视图
SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView 等。我们最常用的视图就是 jsp。 一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开
发具体的页面。
< mvc:annotation-driven >说明
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。 使用 < mvc:annotation-driven > 自动加载 RequestMappingHandlerMapping (处理映射器)和 RequestMappingHandlerAdapter ( 处 理 适 配 器 ) , 可 用 在 SpringMVC.xml 配 置 文 件 中 使 用 < mvc:annotation-driven >替代注解处理器和适配器的配置。
它就相当于在 xml 中配置了:
<!-- 上面的标签相当于 如下配置--> <!-- Begin --> <!-- HandlerMapping --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerM apping"></bean> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> <!-- HandlerAdapter --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerA dapter"></bean> <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean> <!-- HadnlerExceptionResolvers --> <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExcept ionResolver"></bean> <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolv er"></bean> <bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver" ></bean> <!-- End -->
3.3编写控制器并使用注解配置
流程
1、服务器启动,应用被加载。读取到 web.xml 中的配置创建 spring 容器并且初始化容器中的对象
2、浏览器发送请求,被 DispatherServlet 捕获,该 Servlet 并不处理请求,而是把请求转发出去。转发 的路径是根据请 求 URL,匹配@RequestMapping 中的内容。
3、匹配到了后,执行对应方法。该方法有一个返回值。
4、根据方法的返回值,借助 InternalResourceViewResolver 找到对应的结果视图。
5、渲染结果视图,响应浏览器。
4.注解介绍
4.1RequestMapping注解
源码:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Mapping public @interface RequestMapping { }
作用: 用于建立请求 URL 和处理请求方法之间的对应关系。
出现位置:
类上: 请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。 它出现的目的是为了使我们的 URL 可以按照模块化管理: 例如:
账户模块: /account/add
/account/update
/account/delete ...
订单模块:
/order/add
/order/update
/order/delete
加粗的部分就是把 RequsetMappding 写在类上,使我们的 URL 更加精细。
方法上: 请求 URL 的第二级访问目录。
属性: value:用于指定请求的 URL。它和 path 属性的作用是一样的.(若只用一个属性value或者path,则可以省略 )
method:用于指定请求的方式。
@RequestMapping(value="/saveAccount",method=RequestMethod.POST) public String saveAccount() { System.out.println("保存了账户"); return "success"; }
params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的一模一样。 例如:params = {"accountName"},表示请求参数必须有 accountName params = {"moeny!100"},表示请求参数中 money 不能是 100。
控制器的代码:
@RequestMapping(value="/removeAccount",params= {"accountName","money>100"}) public String removeAccount() { System.out.println("删除了账户"); return "success"; }
jsp 中的代码:
<!-- 请求参数的示例 --> <a href="account/removeAccount?accountName=aaa&money>100">删除账户,金额 100</a> <br/> <a href="account/removeAccount?accountName=aaa&money>150">删除账户,金额 150</a>
注意: 当我们点击第一个超链接时,可以访问成功。 当我们点击第二个超链接时,无法访问
headers:用于指定限制请求消息头的条件。
@RequestMapping(path = "/testRequestMapping",params = {"username"},headers = {"Accept"}) public String testRequestMapping(){ System.out.println("测试RequestMapping注解"); return "success"; }
注意: 以上四个属性只要出现 2 个或以上时,他们的关系是与的关系。
4.2RequestParam注解
作用: 把请求中指定名称的参数给控制器中的形参赋值。
属性: value:请求参数中的名称。 required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
<a href="anno/testRequestParam?name=小明">testRequestParam</a>
@RequestMapping("/testRequestParam") public String testRequestParam(@RequestParam(name="name") String username){ System.out.println("执行了..."); System.out.println(username); return "success"; }
4.3 RequestBody注解
作用: 用于获取请求体内容。直接使用得到是 key=value&key=value...结构的数据。 get 请求方式不适用。
属性: required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值 为 false,get 请求得到是 null。
<form action="anno/testRequestBody" method="post"> 用户姓名:<input type="text" name="username"/><br/> 用户年龄:<input type="text" name="age"/><br/> <input type="submit" value="提交"/> </form>
/** * 获取到请求体的内容 * @param body * @return */ @RequestMapping("/testRequestBody") public String testRequestBody(@RequestBody String body){ System.out.println("执行了..."); System.out.println(body); return "success"; }
4.4 REST风格URL
什么是 rest:
REST(英文:Representational State Transfer,简称 REST)描述了一个架构样式的网络系统, 比如 web 应用程序。它首次出现在 2000 年 Roy Fielding 的博士论文中,他是 HTTP 规范的主要编写者之 一。在目前主流的三种 Web 服务交互方案中,REST 相比于 SOAP(Simple Object Access protocol,简单 对象访问协议)以及 XML-RPC 更加简单明了,无论是对 URL 的处理还是对 Payload 的编码,REST 都倾向于用更 加简单轻量的方法设计和实现。值得注意的是 REST 并没有一个明确的标准,而更像是一种设计的风格。
它本身并没有什么实用性,其核心价值在于如何设计出符合 REST 风格的网络接口。
restful 的优点 :
它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
restful 的特性:
资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。
它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个 URI(统一 资源定位符)指向它,每种资源对应一个特定的 URI 。要 获取这个资源,访问它的 URI 就可以,因此 URI 即为每一个资源的独一无二的识别符。
表现层(Representation):
把资源具体呈现出来的形式,叫做它的表现层 (Representation)。
比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二
进制格式。
状态转化(State Transfer):每 发出一个请求,就代表了客户端和服务器的一次交互过程。
HTTP 协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,
必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以
就是 “表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、
DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来
删除资源。
restful 的示例:
/account/1 HTTP GET : 得到 id = 1 的 account
/account/1 HTTP DELETE: 删除 id = 1 的 account
/account/1 HTTP PUT: 更新 id = 1 的 account
/account HTTP POST: 新增 account
4.5PathVaribale
作用: 用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。
url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
属性: value:用于指定 url 中占位符名称。 required:是否必须提供占位符
<a href="anno/testPathVariable/100">testPathVariable</a> /** * PathVariable注解 * @param id * @return */ @RequestMapping("/testPathVariable/{sid}") public String testPathVariable(@PathVariable(name="sid") String id){ System.out.println("执行了..."); System.out.println(id); return "success"; }
4.6 RequestHeader
作用: 用于获取请求消息头。
属性: value:提供消息头名称
required:是否必须有此消息头
注: 在实际开发中一般不怎么用
<a href="anno/testRequestHeader">testRequestHeader</a> /** * 获取请求头的值 * @param header * @return */ @RequestMapping("/testRequestHeader") public String testRequestHeader(@RequestHeader(value = "Accept") String header){ System.out.println("执行了..."); System.out.println(header); return "success"; }
4.7CookieValue
作用: 用于把指定 cookie 名称的值传入控制器方法参数。
属性: value:指定 cookie 的名称。 required:是否必须有此 cookie。
<a href="anno/testCookieValue">testCookieValue</a> /** * 获取cookie的值 * @param cookieValue * @return */ @RequestMapping("/testCookieValue") public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookieValue){ System.out.println("执行了..."); System.out.println(cookieValue); return "success"; }
4.8ModelAttribute
作用:
该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。
出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
出现在参数上,获取指定的数据给参数赋值。
属性:
value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。 应用场景: 当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
例如: 我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数 据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。
<form action="anno/testModelAttribute" method="post"> 用户姓名:<input type="text" name="u_name"/><br/> 用户年龄:<input type="text" name="age"/><br/> <input type="submit" value="提交"/> </form> /** * ModelAttribute注解 * @return */ @RequestMapping("/testModelAttribute") public String testModelAttribute(@ModelAttribute("abc") User user){ System.out.println("testModelAttribute执行了..."); System.out.println(user); return "success"; } /** * 该方法会先执行 */ @ModelAttribute public void showUser(String u_name, Map<String,User> map){ System.out.println("showUser执行了..."); // 通过用户名查询数据库(模拟) User user = new User(); user.setU_name(u_name); user.setAge("21"); user.setDate(new Date()); map.put("abc",user); } /** * 该方法会先执行 @ModelAttribute public User showUser(String u_name){ System.out.println("showUser执行了..."); // 通过用户名查询数据库(模拟) User user = new User(); user.setU_name(u_name); user.setAge("21"); user.setDate(new Date()); return user; } */
4.9SessionAttribute
作用: 用于多次执行控制器方法间的参数共享。
属性:
value:用于指定存入的属性名称
type:用于指定存入的数据类型
<a href="anno/testSessionAttributes">testSessionAttributes</a> <br/> <a href="anno/getSessionAttributes">getSessionAttributes</a> <br/> <a href="anno/delSessionAttributes">delSessionAttributes</a>
/** * SessionAttritubes注解 * @return */ @RequestMapping("/testSessionAttributes") public String testSessionAttributes(Model model){ System.out.println("testSessionAttributes执行了..."); //底层会存储达到request域对象中 model.addAttribute("msg","小明"); return "success"; } /** * 获取值 * @param modelMap * @return */ @RequestMapping("/getSessionAttributes") public String getSessionAttributes(ModelMap modelMap){ System.out.println("getSessionAttributes执行了..."); //底层会存储达到request域对象中 String msg = (String) modelMap.get("msg"); System.out.println(msg); return "success"; } /** * 清除 * @param status * @return */ @RequestMapping("/delSessionAttributes") public String delSessionAttributes(SessionStatus status){ System.out.println("delSessionAttributes执行了..."); //底层会把存储达到request域对象中清除 status.setComplete(); return "success"; } }
5 请求参数的绑定
5.1 绑定说明
5.1.1绑定的机制
我们都知道,表单中请求参数都是基于 key=value 的。 SpringMVC 绑定请求参数的过程是通过把表单提交请求参数,作为控制器中方法参数进行绑定的。 例如
<a href="account/findAccount?accountId=10">查询账户</a>
中请求参数是: accountId=10
/** * 查询账户 * @return */ @RequestMapping("/findAccount") public String findAccount(Integer accountId) { System.out.println("查询了账户。。。。"+accountId); return "success"; }
5.1.2支持的数据类型
基本类型参数: 包括基本类型和 String 类型
POJO 类型参数: 包括实体类,以及关联的实体类
数组和集合类型参数: 包括 List 结构和 Map 结构的集合(包括数组)
SpringMVC 绑定请求参数是自动实现的,但是要想使用,必须遵循使用要求
5.1.3使用要求
如果是基本类型或者 String类型: 要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
如果是 POJO类型,或者它的关联对象: 要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。
如果是集合类型,有两种方式:
第一种:
要求集合类型的请求参数必须在 POJO 中。
在表单中请求参数名称要和 POJO 中集合属性名称相同。
给 List 集合中的元素赋值,使用下标。
给 Map 集合中的元素赋值,使用键值对。
第二种:
接收的请求参数是 json 格式数据。需要借助一个注解实现。
5.2 使用实例
5.2.1基本类型和 String 类型作为参数
<a href="param/testParam?username=小明&password=123456">请求参数绑定</a> /** * 请求参数绑定 * @return */ @RequestMapping("/testParam") public String testParam(String username,String password){ System.out.println("执行了..."); System.out.println("用户名: " + username); System.out.println("密码: " +password); return "success"; }
5.2.2POJO 类型作为参数
<%-- 自定义类型转换器 --%> <form action="param/saveUser" method="post"> 用户姓名:<input type="text" name="u_name"/><br/> 用户年龄:<input type="text" name="age"/><br/> 用户年龄:<input type="text" name="date"/><br/> <input type="submit" value="提交"/> </form> @RequestMapping("/saveUser") public String saveUser(User user){ System.out.println("执行了..."); System.out.println(user); return "success"; }
<%-- 把数据封装到Account类中,存在User--%> <form action="param/saveAccount" method="post"> 姓名:<input type="text" name="username"/><br/> 密码:<input type="password" name="password"/><br/> 金额:<input type="text" name="money"/><br/> 用户姓名:<input type="text" name="user.u_name"/><br/> 用户年龄:<input type="text" name="user.age"/><br/> <input type="submit" value="提交"/> </form> /** * 请求参数绑定把数据封装到Javabean的类中 * @return */ @RequestMapping("/saveAccount") public String saveAccount(Account account){ System.out.println("执行了..."); System.out.println(account); return "success"; }
5.2.3POJO 类中包含集合类型参数
<%-- 把数据封装到Account类中,类中存在list和map的集合--%> <form action="param/saveAccount" method="post"> 姓名:<input type="text" name="username"/><br/> 密码:<input type="password" name="password"/><br/> 金额:<input type="text" name="money"/><br/> 用户姓名:<input type="text" name="list[0].u_name"/><br/> 用户年龄:<input type="text" name="list[0].age"/><br/> 用户姓名:<input type="text" name="map['one'].u_name"/><br/> 用户年龄:<input type="text" name="map['one'].age"/><br/> <input type="submit" value="提交"/> </form> /** * 请求参数绑定把数据封装到Javabean的类中 * @return */ @RequestMapping("/saveAccount") public String saveAccount(Account account){ System.out.println("执行了..."); System.out.println(account); return "success"; }
5.2.4请求参数乱码问题
post 请求方式:
在 web.xml 中配置一个过滤器
<!-- 配置解决中文乱码的过滤器--> <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> <!-- 启动过滤器 --> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
在 springmvc 的配置文件中可以配置,静态资源不过滤:
<!-- 前端控制器,哪些静态资源不拦截--> <!-- location 表示路径,mapping 表示文件,**表示该目录下的文件以及子目录的文件 --> <mvc:resources mapping="/css/**" location="/css/"/> <mvc:resources mapping="/images/**" location="/images/"/> <mvc:resources mapping="/js/**" location="/js/"/>
get 请求方式:
tomacat 对 GET和 POST 请求处理方式是不同的,GET请求的编码问题,要改 tomcat 的 server.xml 配置文件,如下:
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/> 改为: <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" useBodyEncodingForURI="true"/>
如果遇到 ajax 请求仍然乱码,请把:
useBodyEncodingForURI="true"改为 URIEncoding="UTF-8" 即可