一. SpringMVC 是什么
SpringMVC是Spring家族中的一个 web 成员,它是一种基于 Java实现了Web MVC 设计思想的请求驱动类型的 轻量级 Web 框架, 即使用了 MVC架构,模式的思想,将 Web 层进行职责解耦,基于请求驱动指的就是使用请求-响应模型.
二. Spring MVC 能做什么
- 让我们能非常简单的设计出干净的Web层;
- 进行更简洁的Web层的开发;
- 天生与Spring框架集成(如IoC容器、AOP等);
- 提供强大的约定大于配置的契约式编程支持;
- 能简单的进行Web层的单元测试;
- 支持灵活的URL到页面控制器的映射;
- 非常容易与其他视图技术集成,如Velocity、FreeMarker等等,因为模型 数据不放在特定的 API 里,而是放在一个 Model 里(Map 数据结构实现,因此很容易被其他框架使用);
- 非常灵活的数据验证、格式化和数据绑定机制,能使用任何对象进行数据绑定,不必实现特定框架的 API;
- 支持灵活的本地化等解析;
- 更加简单的异常处理;
- 对静态资源的支持;
- 支持 Resultdul 风格;
三. Spring MVC架构
3.1 Spring MVC请求处理流程
Spring MVC 框架是基于请求驱动的Web框架, 且使用了前端控制器模式(是用来提供一个集中的请求处理机制,所有的请求都将由一个单一的处理程序处理来进行设计,再根据请求映射规则分发给相应的页面控制器(动作/处理器)
进行处理, 我们看一下 Spring MVC 处理请求的流程:
- 用户发送请求, 请求被前端控制器(DispatherServlet)捕获
- DispatcherServlet收到请求调用处理器映射器HandlerMapping
- DispatcherServlet获得返回的HandlerExecutionChain(包括 Handler 对象以及Handler对象对应的拦截器)
- DispatcherServlet根据获得的 HandlerExecutionChain, 选择一个合适的HandlerAdapter(如果成功获得HandlerAdapter, 此时执行拦截器的preHandler(…)方法);
- HandlerAdapter 根据请求的 Handler 适配并执行对应的 Handler;
- handler 执行完毕, 返回ModelAndView(模型和视图)给HandlerAdapter;
- HandlerAdapter将执行结果ModelAndView返回给前端控制器
- 前端控制器接收到对应的 ModelAndView 后, 请求对应的视图解析器;
- 视图解析器解析 ModelAndView 后返回对应的 view
- 渲染视图并返回渲染后的视图给前端控制器;
- 最后前端控制器将渲染后的页面响应给用户或者客户端;
3.2 Spring MVC 核心架构图
四. Spring MVC 环境搭建
- 开发环境
idea + jdk8 + maven + jetty
- 新建 maven 工程
然后 next, 输入包名 一路 next, 直到出现这个
- 添加 pom 文件里的 jar 包依赖
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 27 28 29 30 31 32 33 34 35
|
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!-- spring mvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!-- web servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> </dependency> <!-- jetty 插件 --> <build> <finalName>springmvc01</finalName> <resources> <resource> <directory>src/main/resources</directory> </resource> </resources> <plugins> <!-- 编译环境插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>6.1.25</version> <configuration> <scanIntervalSeconds>10</scanIntervalSeconds> <contextPath>/springmvc01</contextPath> </configuration> </plugin> </plugins> </build>
|
- web.xml(前端控制器配置)
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
<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_3_0.xsd" id="WebApp_ID" version="3.0"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml</param-value> </context-param> <!-- 启用 spring 容器环境上下文监听 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 编码过滤 utf-8 --> <filter> <description>char encoding filter</description> <filter-name>encodingFilter</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>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- servlet 请求分发器 --> <servlet> <servlet-name>springMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:servlet-context.xml</param-value> </init-param> <!-- 表示启动容器时初始化该 Servlet --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMvc</servlet-name> <!-- 这是拦截请求, /代表拦截所有请求 --> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
|
- servlet-context.xml 配置
1 2 3 4 5 6 7 8
|
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd 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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 扫描 com.shsxt.controller 下包 --> <context:component-scan base-package="com.shsxt.controller" /> <!-- mvc 请求映射 处理器与适配器配置--> <mvc:annotation-driven/> <!--配置视图解析器 默认的视图解析器- --> <bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="contentType" value="text/html" /> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> </beans>
|
- 页面控制器的编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
/** * 采用注解扫描形式 */ @Controller public class { /** * 请求映射地址 hello * @return */ @RequestMapping("hello") public ModelAndView hello(){ ModelAndView mv = new ModelAndView(); mv.addObject("hello", "hello spring mvc"); mv.setViewName("hello"); return mv; }
|
- 视图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort( )+path+"/";%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'hello.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <!-- el 表达式接收参数值 --> ${hello} </body> </html>
|
启动 jetty 服务器, 在浏览器打开localhost:8080/springmvc01/index
五. 注解
5.1 @Controller
在 spring 3.0 中,通过@controller 标注即可将 class 定义为一个 controller 类。为使 spring 能找到定义为 controller 的 bean,需要在 spring-context 配置文件中增加如下定义
<context:component-scan base-package="com.shsxt.controller"/>
5.2 @RequestMapping
在类前面定义,则将 url 和类绑定。
在方法前面定义,则将 url 和类的方法绑定
1 2 3 4 5 6 7
|
@RequestMapping("saveOrUpdateCustomerServe") @ResponseBody public ResultInfo saveOrUpdateCustomerServe(CustomerServe customerServe, HttpServletRequest request){ Integer id = LoginUserUtil.releaseUserIdFromCookie(request); customerServeService.saveOrUpdateCustomerServe(customerServe, id); return success(CrmConstant.OPS_SUCCESS_MSG); }
|
六. 重定向与请求转发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
/** * 重定向到 jsp ModelAndView1 */ @RequestMapping("queryView4") public ModelAndView queryView4(RedirectAttributes attr){ ModelAndView mv=new ModelAndView(); attr.addAttribute("a", "sxt"); attr.addAttribute("b", "尚学堂"); mv.setViewName("redirect:v1.jsp"); return mv; }
/** 请求转发 */ @RequestMapping("index") public String index(){ return "customer_loss"; }
|
七. Spring MVC 全局异常处理
在 JavaEE 项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的代码耦合度高,工作量大且 不好统一,维护的工作量也很大。
SpringMvc 对于异常处理这块提供了支持,通过 SpringMvc 提供的全局异 常处理机制,能够将所有类型的异常处理从各处理过程解耦出来,这样既保证了 相关处理过程的功能较单一,也实现了异常信息的统一处理和维护.
1.使用 Spring MVC 提供的简单异常处理器 SimpleMappingExceptionResolver;
2.实现 Spring 的异常处理接口 HandlerExceptionResolver 自定义自己的异常处理器;
3.使用@ExceptionHandler 注解实现异常处理;
one
配置 SimpleMappingExceptionResolver 对象
1 2 3 4 5 6 7 8 9
|
<bean class="org.springframework.web.servlet.handler.SimpleMappingExcepti onResolver"> <property name="defaultErrorView" value="error"></property> <property name="exceptionAttribute" value="ex"></property> <property name="exceptionMappings"> <props> <prop key="com.shsxt.exception.BusinessException">error</prop> <prop key="com.shsxt.exception.ParamsException">error</prop> </props> </property> </bean>
|
使用 SimpleMappingExceptionResolver 进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,但该方法仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适用.
two
实现 HandlerExceptionResolver 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public class MyExceptionHandler implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { Map<String,Object> map = new HashMap<String, Object>(); map.put("ex", ex); ModelAndView mv=null; if(ex instanceof ParamsException){ return new ModelAndView("error_param", map); } if(ex instanceof BusinessException){ return new ModelAndView("error_business", map); } return new ModelAndView("error", map); } }
|
使用实现 HandlerExceptionResolver 接口的异常处理器进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,同时,在异常处理时能获取导致出现异常的对象,有利于提供更详细的异常处理信息。
three
页面处理器继承 BaseController
1 2 3 4 5 6 7 8 9
|
public class BaseController { @ExceptionHandler public String exc(HttpServletRequest request,HttpServletResponse response,Exception ex){ request.setAttribute("ex", ex); if(ex instanceof ParamsException){ return "error_param"; } if(ex instanceof BusinessException){ return "error_business"; } return "error"; } }
|
使用@ExceptionHandler 注解实现异常处理,具有集成简单、有扩展性好(只需要将要异常处理的 Controller 类继承于 BaseController 即可)、不需要附加Spring 配置等优点,但该方法对已有代码存在入侵性(需要修改已有代码,使相关类继承于 BaseController),在异常处理时不能获取除异常以外的数据.
未捕获异常处理
对于 Unchecked Exception 而言,由于代码不强制捕获,往往被忽略,如果运行期产生了Unchecked Exception,而代码中又没有进ñ行相应的捕获和处理,则我们可能不得不面对尴尬的 404、 500……等服务器内部错误提示页面。
我们需要一个全面而有效的异常处理机制。目前大多数服务器也都支持在 Web.xml 中通过<error-page>
(Websphere/Weblogic)或者<error-code>
(Tomcat)节点配置特定异常情况的显示页面。修改 web.xml 文件,增加以下内容
1 2 3 4 5 6 7 8 9 10 11 12
|
<!-- 出错页面定义 --> <error-page> <exception-type>java.lang.Throwable</exception-type> <location>/500.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/500.jsp</location> </error-page> <error-page> <error-code>404</error-code> <location>/404.jsp</location> </error-page>
|
原文:大专栏 SpringMVC