SpringMVC

SpringMVC

一. SpringMVC 是什么

SpringMVC是Spring家族中的一个 web 成员,它是一种基于 Java实现了Web MVC 设计思想的请求驱动类型的 轻量级 web 框架, 即使用了 MVC架构,模式的思想,将 Web 层进行职责解耦,基于请求驱动指的就是使用请求-响应
模型.

二. Spring MVC 能做什么

  1. 让我们能非常简单的设计出干净的Web层;
  2. 进行更简洁的Web层的开发;
  3. 天生与Spring框架集成(如IoC容器、AOP等);
  4. 提供强大的约定大于配置的契约式编程支持;
  5. 能简单的进行Web层的单元测试;
  6. 支持灵活的URL到页面控制器的映射;
  7. 非常容易与其他视图技术集成,如Velocity、FreeMarker等等,因为模型 数据不放在特定的 API 里,而是放在一个 Model 里(Map 数据结构实现,因此很容易被其他框架使用);
  8. 非常灵活的数据验证、格式化和数据绑定机制,能使用任何对象进行数据绑定,不必实现特定框架的 API;
  9. 支持灵活的本地化等解析;
  10. 更加简单的异常处理;
  11. 对静态资源的支持;
  12. 支持 Resultdul 风格;

三. Spring MVC架构

3.1 Spring MVC请求处理流程

image-20190103092520973

Spring MVC 框架是基于请求驱动的Web框架, 且使用了前端控制器模式(是用来提供一个集中的请求处理机制,所有的请求都将由一个单一的处理程序处理来进行设计,再根据请求映射规则分发给相应的页面控制器(动作/处理器)

进行处理, 我们看一下 Spring MVC 处理请求的流程:

  1. 用户发送请求, 请求被前端控制器(DispatherServlet)捕获
  2. DispatcherServlet收到请求调用处理器映射器HandlerMapping
  3. DispatcherServlet获得返回的HandlerExecutionChain(包括 Handler 对象以及Handler对象对应的拦截器)
  4. DispatcherServlet根据获得的 HandlerExecutionChain, 选择一个合适的HandlerAdapter(如果成功获得HandlerAdapter, 此时执行拦截器的preHandler(...)方法);
  5. HandlerAdapter 根据请求的 Handler 适配并执行对应的 Handler;
  6. handler 执行完毕, 返回ModelAndView(模型和视图)给HandlerAdapter;
  7. HandlerAdapter将执行结果ModelAndView返回给前端控制器
  8. 前端控制器接收到对应的 ModelAndView 后, 请求对应的视图解析器;
  9. 视图解析器解析 ModelAndView 后返回对应的 view
  10. 渲染视图并返回渲染后的视图给前端控制器;
  11. 最后前端控制器将渲染后的页面响应给用户或者客户端;

3.2 Spring MVC 核心架构图

image-20190103095134380

四. Spring MVC 环境搭建

  1. 开发环境

idea + jdk8 + maven + jetty

  1. 新建 maven 工程
image-20190103100237154

然后 next, 输入包名 一路 next, 直到出现这个

image-20190103100453913
  1. 添加 pom 文件里的 jar 包依赖
<!-- spring web -->
<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>
  1. web.xml(前端控制器配置)
<?xml version="1.0" encoding="UTF-8"?>
<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>

  1. servlet-context.xml 配置
<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. 页面控制器的编写
/**
* 采用注解扫描形式 */
@Controller
public class HelloController {
/**
* 请求映射地址 hello
* @return */
@RequestMapping("hello") 
public ModelAndView hello(){
ModelAndView mv = new ModelAndView();
mv.addObject("hello", "hello spring mvc"); 
mv.setViewName("hello");
return mv;
} 
  1. 视图
<%@ 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

image-20190103102204806

五. 注解

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 和类的方法绑定

 @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);
    }

六. 重定向与请求转发

/**
* 重定向到 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 对象

<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 接口

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

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 文件,增加以下内容

<!-- 出错页面定义 --> <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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容