SpringMVC 简介
SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring
FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。
SpringMVC 优势:
1、清晰的角色划分: 前端控制器(DispatcherServlet) 请求到处理器映射(HandlerMapping) 处理器适配器(HandlerAdapter) 视图解析器(ViewResolver) 处理器或页面控制器(Controller) 验证器( Validator) 命令对象(Command 请求参数绑定到的对象就叫命令对象) 表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。 2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。 3、由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。 4、和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。 5、可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。 6、可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制。 7、功能强大的数据验证、格式化、绑定机制。 8、利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。 9、本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。 10、强大的 JSP 标签库,使 JSP 编写更容易。 ………………还有比如 RESTful 风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配 置支持等等。
SpringMVC 配置
坐标依赖
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring.version>5.0.2.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</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>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies>
web.xml
<web-app> <display-name>Archetype Created Web Application</display-name> <!-- 配置前端控制器 servlet 跟 mapping--> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置 Servlet 的初始化参数,读取 springmvc 的配置文件,创建 spring 容器 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 配置 servlet 启动时加载对象 而不是请求时候才加载 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <!-- / 表示所有请求都经过它 --> <url-pattern>/</url-pattern> </servlet-mapping>
springmvc.xml 配置文件
该 xml 文件名称可自定义,需要在 web.xml 中指定,详见上方 web.xml 配置
<?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.cheng"></context:component-scan> <!-- 配置视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 配置视图解析器解析的前缀目录 --> <property name="prefix" value="/WEB-INF/pages/"></property> <!-- 配置解析的后缀 下列也就是只解析到 jsp 文件 --> <property name="suffix" value=".jsp"></property> </bean> <!-- 配置 spring 开启注解 mvc 的支持 该注解包含 SpringMVC 中的其他处理器 --> <mvc:annotation-driven></mvc:annotation-driven> </beans>
<mvc:annotation-driven /> 解析
用 自动加载 RequestMappingHandlerMapping(处理映射器)和 RequestMappingHandlerAdapter ( 处理适配器 ),如果不使用这种写法,可以使用下列配置,下载配置其实就是细化,可让你根据适合场景使用适合的处理器,而非全部加载。
<!-- Begin --> <!-- HandlerMapping --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> <!-- HandlerAdapter --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></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.ExceptionHandlerExceptionResolver"></bean> <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"></bean> <bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"></bean> <!-- End -->
小流程
启动 Tomcat-> 加载 web.xml-> 由于配置 load-on-startup 启动即创建前端控制器 -> 加载 springmvc.xml-> 开启注解扫描 -> 扫描 @Controller 注解的类创建对象
前端 jsp 页面发请求 -> 到前端控制器 -> 根据 @RequestMapping 找具体方法执行 -> 根据方法返回结果 -> 根据视图解析器 -> 查找指定的页面 ->Tomcat 渲染页面 -> 响应给页面
常用注解
@RequestMapping
作用:建立请求 URL 与方法之间对应关系。
写法:可以写在类与方法上,value 值为 / 表示根目录
属性:
path/value 指定请求路径的 url 例:@RequestMapping(path ="/hello")、@RequestMapping(value="/hello") 其中如果只有 value 一个属性的话可以省略不写,即 @RequestMapping("/hello")
mthod 指定该方法的请求方式
@RequestMapping(value="/saveAccount",method=RequestMethod.POST) 可以配置多种方式,在 {} 中写
params 指定限制请求参数的条件
RequestMapping(value="/remove",params= {"accountName","money>100"}) // 限制传来参数中必须有 accountName、money 参数,money 还需要 >100
headers 发送的请求中必须包含的请求头
RequestMapping(value="/remove",header= {"Accept"}) // 限制 header 中必须有 Accept
在 jsp 中可以采用绝对与相对 URL 访问 mapping
<a href="${pageContext.request.contextPath}/account/findAccount"> 绝对 </a> <a href="account/findAccount"> 相对 </a> ${pageContext.request.contextPath}取的是虚拟目录的名称
@RequestParam
与前台传递参数不一致,用它进行与形参关联,例如下列前台传的参数 username,但后台必须用 name 时
public String sayHello(@RequestParam(value="username",required=false)String name) {}
@RequestBody
用于获取请求体的内容(注意:get 方法不适用,适用于 post 或 ajax 异步请求)
required:是否必须有请求体,默认值是 true
public String sayHello(@RequestBody String body) {}
@PathVariable
拥有绑定 url 中的占位符的。例如:url 中有 /delete/{id},{id}就是占位符
<a href="user/hello/1"> 入门案例 </a> /** * 接收请求 * @return */ @RequestMapping(path="/hello/{id}") public String sayHello(@PathVariable(value="id") String id) {System.out.println(id); return "success"; }
Restful 风格的 URL
请求路径一样,可以根据不同的请求方式去执行后台的不同方法
restful 风格的 URL 优点
结构清晰
符合标准
易于理解
扩展方便
@RequestHeader
获取指定请求头的值
public String sayHello(@RequestHeader(value="Accept") String header) {}
@CookieValue
获取指定 cookie 的名称的值
@RequestMapping(path="/hello") public String sayHello(@CookieValue(value="JSESSIONID") String cookieValue) {System.out.println(cookieValue); return "success"; }
@ModelAttribute
出现在方法上:表示当前方法会在控制器方法执行前线执行。
出现在参数上:获取指定的数据给参数赋值。
应用场景:当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
/** * 假设 User 对象中有 name 跟 password 字段,前端只传了 name * 要知道 password 第一种在该 Controller 中写读数据库操作 * 第二种在 @ModelAttribute 修饰的方法中写数据库操作 因为它优先执行 */ @RequestMapping(path = "/updateUser") public String updateUser(User user) { System.out.println(user); return "success"; } /** * 作用在方法,先执行 * 通过前端传的 name 查询 password 并返回给 user */ @ModelAttribute public User showUser(String name) { System.out.println("showUser 执行了..."); // 模拟从数据库中查询对象, 此处为演示直接设置对象属性 User user = new User(); user.setName(" 哈哈 "); user.setPassword("123"); return user; }
假设 @ModelAttribute 修饰的先行方法没返回值怎么办?可在方法参数中加合适类型 Map,然后将数据库查询的对象 put 进去,在需要的 Controller 方法的参数上再加 @ModelAttribute 注解把值再赋给 user
@RequestMapping(path = "/updateUser") public String updateUser(@ModelAttribute(value = "abc") User user) { System.out.println(user); return "success"; } @ModelAttribute public void showUser(String name, Map<String, User> map) { System.out.println("showUser 执行了..."); // 模拟从数据库中查询对象 User user = new User(); user.setName(" 哈哈 "); user.setPassword("123"); map.put("abc", user); }
@SessionAttributes
用于多次执行控制器方法间的参数共享。只能写在类上。
@Controller @RequestMapping(path = "/user") @SessionAttributes(value = {"username", "password", "age"}, types = {String.class, Integer.class}) // 把数据存入到 session 域对象中 public class HelloController { /** * 向 session 中存入值 * * @return */ @RequestMapping(path = "/save") public String save(Model model) { System.out.println(" 向 session 域中保存数据 "); // 会向 Request 域中添加数据 // 加 SessionAttributes 注解会再次向 Session 域中 model.addAttribute("username", "root"); model.addAttribute("password", "123"); model.addAttribute("age", 20); return "success"; } /** * 从 session 中获取值 * * @return */ @RequestMapping(path = "/find") public String find(ModelMap modelMap) { // ModelMap 是 Model 的实现类,可以取数据 String username = (String) modelMap.get("username"); String password = (String) modelMap.get("password"); Integer age = (Integer) modelMap.get("age"); System.out.println(username + " : " + password + " : " + age); return "success"; } /** * 清除值 * * @return */ @RequestMapping(path = "/delete") public String delete(SessionStatus status) { // 将 session 状态设置为完成则清除 session status.setComplete(); return "success"; } }
参数绑定
1、传什么接收什么
<a href="account/findAccount?accountId=10"> 查询账户 </a> 后端: public String findAccount(Integer accountId){}
2、实体类
User 实体类中有 name 跟 age 属性,前台传 uname、age,后台用实体类直接接收 后台: public String findAccount(User user){}
3、关联实体类(类中有类), 例如 Account 类中含 User 类:
public class Account implements Serializable{ private String username; private String password; private Double money; private User user; ... }
那它前端就是:
<form action="param/saveAccount" method="post"> 姓名:<input type="text" name="username" /><br/> 密码:<input type="text" name="password" /><br/> 金额:<input type="text" name="money" /><br/> 用户姓名:<input type="text" name="user.uname" /><br/> 用户年龄:<input type="text" name="user.age" /><br/> <input type="submit" value=" 提交 " /> </form>
4、数组和集合类型参数,实体类中包含 List 于 Map
<form action="param/saveAccount" method="post"> 姓名:<input type="text" name="username" /><br/> 密码:<input type="text" name="password" /><br/> 金额:<input type="text" name="money" /><br/> 用户姓名:<input type="text" name="list[0].uname" /><br/> 用户年龄:<input type="text" name="list[0].age" /><br/> 用户姓名:<input type="text" name="map['one'].uname" /><br/> 用户年龄:<input type="text" name="map['one'].age" /><br/> <input type="submit" value=" 提交 " /> </form>
过滤器解决中文乱码
Get 情况下乱码
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.xml 中可以配置静态资源不过滤
<!-- location 表示路径,mapping 表示文件,** 表示该目录下的文件以及子目录的文件 --> <mvc:resources location="/css/" mapping="/css/**"/> <mvc:resources location="/images/" mapping="/images/**"/> <mvc:resources location="/scripts/" mapping="/javascript/**"/>
Post 情况下乱码
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"
HiddentHttpMethodFilter
由于浏览器 form 表单只支持 GET 与 POST 请求,而 DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将浏览器请求改为指定的请求方式,发送给我们的控制器方法,使得支持 GET、POST、PUT 与 DELETE 请求。
使用方法:
第一步:在 web.xml 中配置该过滤器。
第二步:请求方式必须使用 post 请求。
第三步:按照要求提供_method 请求参数,该参数的取值就是我们需要的请求方式。
<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>
此时,前端就要改成如下:
<!-- 保存 --> <form action="springmvc/testRestPOST" method="post"> 用户名称:<input type="text" name="username"><br /> <!-- <input type="hidden" name="_method" value="POST"> --> <input type="submit" value=" 保存 "> </form> <hr /> <!-- 更新 --> <form action="springmvc/testRestPUT/1" method="post"> 用户名称:<input type="text" name="username"><br /> <input type="hidden" name="_method" value="PUT"> <input type="submit" value=" 更新 "> </form>
说白了就是在表单中加入了
<input type="hidden" name="_method" value="PUT">
持续更新中……
- 坐标依赖
- web.xml
- springmvc.xml 配置文件
- <mvc:annotation-driven /> 解析
- 小流程
- @RequestMapping
- @RequestParam
- @RequestBody
- @PathVariable
- Restful 风格的 URL
- @RequestHeader
- @CookieValue
- @ModelAttribute
- @SessionAttributes
- Get 情况下乱码
- Post 情况下乱码
- 坐标依赖
- web.xml
- springmvc.xml 配置文件
- <mvc:annotation-driven /> 解析
- 小流程
- @RequestMapping
- @RequestParam
- @RequestBody
- @PathVariable
- Restful 风格的 URL
- @RequestHeader
- @CookieValue
- @ModelAttribute
- @SessionAttributes
- Get 情况下乱码
- Post 情况下乱码