SpringMVC框架知识点详解

官方的下载网址是:http://www.springsource.org/download

一、Spring MVC简介

1.1Spring MVC工作流程

映射器:主要是根据浏览器上输入的url来映射所有满足要求的Handle(控制器类)

适配器:主要是决定调用哪个Handler来实现具体的业务逻辑

1.2Spring MVC VS Struts2

1)springmvc的入口是一个servlet,即前端控制器;

     struts2入口是一个filter过虑器,即前端过滤器,

2)springmvc是基于方法开发(控制器类是单例的,不可能维护实体变量),传递参数是通过方法形参,可以设计为单例;

     struts2是基于类开发(维护一个实体变量),传递参数是通过类的属性,只能设计为多例

3)springmvc通过参数解析器是将request对象内容进行解析成方法形参,将响应数据和页面封装成ModelAndView对象,最后又将模型数据通过request对象传输到页面;

     struts采用值栈存储请求和响应的数据,通过OGNL存取数据

4)springmvc开发运行速度快于struts2

二、Spring MVC工程搭建(xml)

2.1导入springioc,springweb , springmvc相关的jar包

2.2在/WEB-INF/ web.xml文件配置SpringMVC的前端控制器DispatcherServlet(前端控制器)

<!-- 注册springmvc核心控制器 -->
    <servlet>
    <!-- servlet-name名字随便写 -->
       <servlet-name>DispatcherServlet</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <!-- 通知DispatcherServlet去指定的目录下加载springmvc.xml配置文件
           classpath:是在工程的src路径下寻找
        如果不配置init-param的话,控制器会自动寻找/WEB-INF/<servlet-name>-servlet.xml文件-->
       <init-param>
       <!-- 值是固定的,相当于键值对 -->
           <param-name>contextConfigLocation</param-name>
           <param-value>classpath:springmvc.xml</param-value>
       </init-param>
    </servlet>
    <servlet-mapping>
       <servlet-name>DispatcherServlet</servlet-name>
       <url-pattern>*.action</url-pattern>//拦截请求
    </servlet-mapping>

注:在默认情况下:springmvc框架的配置文件必须叫<servlet-name>-servlet.xml

且必须放在/WEB-INF/目录下,我们可以在web.xml文件中,为DispatcherServlet配置一个初始化参数,

让它去我们指定的目录下加载springmvc.xml配置文件

2.3配置springmvc.xml

    注:该配置文件的命名规则遵循web.xml文件中核心控制器配置。

<!-- 控制器(程序员) -->
    <bean name="/hello.action" class="cn.itcast.javaee.springmvc.base.HelloAction"></bean> 
   
   
    <!-- 映射器(框架) 如果不写,默认是将bean标签的name属性当做URL--> 
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> 
     
    <!-- 适配器(框架),如果不写,默认是用于寻找实现了Controller接口的类 --> 
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean> 
 
    <!-- 视图解析器(框架),默认是通过ModelAndView对象中封装的视图名称(真实路径)找到真正的页面--> 
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean> 
     
</beans>

2.4创建HelloAction.java控制器类

/**
 * 控制器
 * @author AdminTC
 */
public class HelloAction implements Controller{
    /**
     * 业务方法,controller接口中的方法handleRequest,必须实现
     */
    public ModelAndView handleRequest(HttpServletRequest requqest,HttpServletResponse response) throws Exception {
       // ModelAndView现在不用了
       ModelAndView modelAndView = new ModelAndView();
       modelAndView.addObject("message","这是我的第一个springmvc应用程序");
       modelAndView.setViewName("/jsp/success.jsp");
       return modelAndView;
    }
}

2.5写jsp

在/WebRoot/下创建jsp/success.jsp

<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>这是我的第一个springmvc应用程序</title>
  </head>
  <body>
    success.jsp<br/>
    ${message}
  </body>
</html>

部署web应用到tomcat中,通过浏览器访问如下URL:

       http://localhost:8080/springmvc-day01/hello.action

三、springmcv组件讲解(在springmvc中配置)

3.1概念讲解

1)DispatcherServlet:前端控制器

用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。

2)HandlerMapping:处理器映射器

HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口(controller)方式,注解方式等。

3)HandlAdapter:处理器适配器

通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

4)Handler:处理器

Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。

由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。

5)ViewResolver:视图解析器

View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。

6)View:视图

springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。

一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

说明:

在springmvc的各个组件中,处理器映射器、处理器适配器、视图解析器称为springmvc的三大组件。

需要用户开发的组件有handler(控制器)、view(视图)

3.2组件用法注意事项

1)视图解析器InternalResourceViewResolver【解析视图逻辑名对应的真实路径】

      ModelAndView对象中即可以封装真实视图路径名,也可以封装视图路径的逻辑名。在springmvc中,如果是真实名称,可以不配置,如果不是,要配置前缀和后缀。逻辑视图名需要在controller中返回ModelAndView指定,比如逻辑视图名为success,则最终返回的jsp视图地址为::

“/jsp/itemList.jsp”

最终jsp物理地址:前缀+逻辑视图名+后缀

代码如下:

 <!-- 视图解析器(框架) --> 
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

Action类代码如下:

modelAndView.setViewName("success");

2)映射器BeanNameUrlHandlerMapping

    该映射器适合一个请求访问一个控制器

   将程序员定义的Action所对应的<bean>标签的name属性作为请求路径

 <!-- 注册控制器(程序员) -->
      <bean name="/add.action" class="cn.itcast.javaee.springmvc.mapping.UserAction"></bean>
 
      <!-- 注册映射器(handler包)(框架) -->
      <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

http://localhost:8080/springmvc-day01/add.action,访问到UserAction类

3)映射器SimpleUrlHandlerMapping

多个路径对应同一个Action

/delete.action和/update.action和/find.action请求路径都交由<bean>标签为id的Action,

 <!-- 注册控制器(程序员) -->
      <bean id="userActionID" class="cn.itcast.javaee.springmvc.mapping.UserAction"></bean>
      
      <!-- 注册映射器(handler包)(框架) -->
      <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
           <property name="mappings">
               <props>
                  <prop key="/delete.action">userActionID</prop>
                  <prop key="/update.action">userActionID</prop>
                  <prop key="/find.action">userActionID</prop>
               </props>
           </property>
      </bean>

http://localhost:8080/springmvc-day01/delete.action,

http://localhost:8080/springmvc-day01/update.action,

http://localhost:8080/springmvc-day01/find.action,三个地址都访问到UserAction类

4)适配器SimpleControllerHandlerAdapter

适配器 :帮你找到实现controler接口的类-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

5)控制器ParameterizableViewController

直接将请求跳转到jsp页面,不经过程序员写的控制器

<!-- /index.action请求,直接转发到WEB-INF/index.jsp页面 -->
      <bean name="/index.action" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
           <property name="viewName" value="/index.jsp"/>
      </bean>

3.3自定义日期转换器和编码过滤器

1)在默认情况下,springmvc不能将String类型转成Date类型,必须自定义类型转换器

public class AdminAction extends Controller{
    @Override
    protected void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {
       binder.registerCustomEditor(Date.class,new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
    }

2)spring提供的,专用于解决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>
    </filter>
    <filter-mapping>
       <filter-name>CharacterEncodingFilter</filter-name>
       <url-pattern>/*</url-pattern>
    </filter-mapping>

四、Spring MVC工程搭建(注解)

4.1创建工程导入jar包

  导入springioc,springweb和springmvc相关的jar包

4.2在/WEB-INF/下创建web.xml文件

<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.xml</param-value>  <配置路径名称>
       </init-param>
    </servlet>
    <servlet-mapping>
       <servlet-name>DispatcherServlet</servlet-name>
       <url-pattern>*.action</url-pattern>   <!--拦截.action请求-->
    </servlet-mapping>

4.3配置springmvc.xml

    SpringMVC本身就是Spring的子项目,对Spring兼容性很好,不需要做很多配置。配置一个Controller扫描就可以了,让Spring对页面控制层Controller进行管理。

    1)组件扫描器

          省去在spring容器配置每个Controller类的繁琐。使用<context:component-scan>自动扫描标记@Controller的控制器类,

    2)注解式映射器

          对类中标记了@ResquestMapping的方法进行映射。根据@ResquestMapping定义的url匹配@ResquestMapping标记的方法,匹配成功返回HandlerMethod对象给前端控制器。

          HandlerMethod(处理器方法)对象中封装url对应的方法Method。 从spring3.1版本开始,废除了DefaultAnnotationHandlerMapping的使用,推荐使用RequestMappingHandlerMapping完成注解式处理器映射。

   3)注解式适配器

         对标记@ResquestMapping的方法进行适配。从spring3.1版本开始,废除了AnnotationMethodHandlerAdapter的使用,推荐使用RequestMappingHandlerAdapter完成注解式处理器适配。

   4)注解驱动

        为了省事,直接受用注解驱动因为直接配置处理器映射器和处理器适配器比较麻烦。 SpringMVC使用<mvc:annotation-driven>自动加载                                                  RequestMappingHandlerMapping和RequestMappingHandlerAdapter

       可以在springmvc.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置。

<!-- 注解驱动 -->
<mvc:annotation-driven />

springmvc配置如下:

<!-- Action控制器 -->
      <context:component-scan base-package="cn.itcast.javaee.springmvc.helloannotation"/> //controller类所在的包
     
      <!-- 基于注解的映射器(可选) -->
      <bean class=" org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping "/>
     
      <!-- 基于注解的适配器(可选) -->
      <bean class=" org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter "/>
     
     <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
       <property name="prefix" value="/jsp/"/>
       <property name="suffix" value=".jsp"/>
    </bean>       
</beans>

4.4创建HelloAction.java控制器类

    1)HelloAction是一个普通的java类,不需要实现任何接口。

    2)需要在类上添加@Controller注解,把Controller交由Spring管理

    3)在方法上面添加@RequestMapping注解,里面指定请求的url。其中“.action”可以加也可以不加。

/**
 * 单例
 * 控制器(程序员)
*/
//加上这个@Controller,相当于是控制器类
@Controller
public class HelloAction{
    public HelloAction(){//单例,第一次访问创建
       System.out.println("HelloAction()::" + this.hashCode());
    }
   
    /**
     * 业务方法
     * 只要是/hello.action的请求,都交由HelloAction对象中的hello()方法去处理
     * 之前是在xml中配置bean的。
     */
    //value值是可以写多个的。
    @RequestMapping(value="/hello.action")  
    //hello带参数用Model类,这个类是
    public String hello(Model model) throws Exception{
       System.out.println("HelloAction::hello()");
       model.addAttribute("message","你好");
       return "success";
    }
   
    /**
     * 业务方法
     * 只要是/bye.action的请求,都交由HelloAction对象中的bye()方法去处理
     */
    @RequestMapping(value="/bye.action")  
    public String bye(Model model) throws Exception{
       System.out.println("HelloAction::hello()");
       model.addAttribute("message","再见");
       return "success";
    }
}

4.5在/WebRoot/下创建success.jsp

<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>这是我的第二个springmvc应用程序</title>
  </head>
  <body>
    success.jsp<br/>
    ${message}
  </body>
</html>

部署到tomcat中,http://127.0.0.1:8080/springmvc-day02/hello.action

五、springmvc项目开发小功能

5.1参数绑定

1)默认支持的形参类型

HttpServletRequest:通过request对象获取请求信息,一般get方式提交的可以用request对象获取。

HttpServletResponse:通过response处理响应信息

HttpSession:通过session对象得到session中存放的对象

Model/ModelMap:用于向页面传递数据。ModelMap是Model接口的实现类,也可以通过ModelMap向页面传递数据。如果使用Model/ModelMap则在方法中可以不使用ModelAndView对象,Model对象可以向页面传递数据,View对象则可以使用String返回值替代。

2)简单基本类型

   当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定。这样,从Request取参数的方法就可以进一步简化。参数类型推荐使用包装数据类型,因为基础数据类型不可以为null

整型:Integer、int

字符串:String

单精度:Float、float

双精度:Double、double

布尔型:Boolean、boolean

说明:对于布尔类型的参数,请求的参数值为true或false。或者1或0

请求url:

http://localhost:8080/xxx.action?id=2&status=false

处理器方法:

    public String editItem(Model model,Integer id,Boolean status)

 

   使用@RequestParam对简单参数的约定

   常用于处理简单类型的绑定。

  value:参数名字,即入参的请求参数名字,如value=“itemId”表示请求的参数 区中的名字为itemId的参数的值将传入

  required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报错

                    HTTP Status 400 - Required Integer parameter 'XXXX' is not present

  defaultValue:默认值,表示如果请求中没有同名参数时的默认值

@RequestMapping("/itemEdit"),页面中参数名itemId的参数(默认为1,必须要传)传过来给形参id。
public String queryItemById(@RequestParam(value = "itemId", required = true, defaultValue = "1") Integer id,
                   ModelMap modelMap) {}

3)pojo对象类型数据

       pojo: 普通的Java对象,对于属性一般实现了JavaBean的标准,另外还可以包含一些简单的业务逻辑(方法)

       如果提交的参数很多,或者提交的表单中的内容很多的时候,可以使用简单类型接受数据,也可以使用pojo类接收数据。

要求:pojo对象中的属性名和表单中input的name属性一致

public String updateItem(Item item) {
         // 返回逻辑视图
         return "success";
}

4)自定义参数

    比如:由于日期数据有很多种格式,springmvc没办法把字符串转换成日期类型。所以需要自定义参数绑定。

    前端控制器接收到请求后,找到注解形式的处理器适配器,对RequestMapping标记的方法进行适配,并对方法中的形参进行参数绑定。可以在springmvc处理器适配器上自定义转换器Converter进行参数绑定。

//Converter<S, T>
//S:source,需要转换的源的类型
//T:target,需要转换的目标类型
public class DateConverter implements Converter<String, Date> {
 
         @Override
         public Date convert(String source) {
                   try {
                            // 把字符串转换为日期类型
                            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
                            Date date = simpleDateFormat.parse(source);
 
                            return date;
                   } catch (ParseException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                   }
                   // 如果转换异常则返回空
                   return null;
         }
}
在springmvc中:
<!-- 转换器配置 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
         <property name="converters">
                   <set>
                            <bean class="cn.itcast.springmvc.converter.DateConverter" />//自定义类名
                   </set>
         </property>
</bean>

5)数组参数

针对需求:在商品列表页面选中多个商品,然后删除。

注意:数组名要和表单中的name名称一样。

方法:

 //数组的名字要和页面03_emp中name的属性值保持一样
    public String deleteAll(Model model,int[] ids) throws Exception{
       System.out.println("需要删除的员工编号分别是:");
       for(int id : ids){
           System.out.print(id+" ");
       }
       model.addAttribute("message","批量删除员工成功");
       return "/jsp/ok.jsp";
    }

jsp页面:

 <th>编号</th>
           <th>姓名</th>
        </tr>
        <tr>
           <td><input type="checkbox" name="ids" value="1"/></td>
           <td>哈哈</td>
        </tr>
        <tr>
           <td><input type="checkbox" name="ids" value="2"/></td>
           <td>呵呵</td>
          省略
        </tr>

6)将表单的数据绑定到List

需求:表单中的每一条记录对应一个user类,

注意:list类名要和jspname属性名一样。

批量注册用户

UserAction.java

@Controller
@RequestMapping(value="/user")
public class UserAction {
    @RequestMapping(value="/addAll")
    public String addAll(Bean bean,Model model) throws Exception{
       for(User user : bean.getUserList()){
           System.out.println(user.getName()+":"+user.getGender());
       }
       model.addAttribute("message","批量增加用户成功");
       return "/success.jsp";
    }
}

Bean.java

public class Bean {
//list类名要和jsp中name属性名一样。
    private List<User> userList = new ArrayList<User>();
    public Bean(){}
    public List<User> getUserList() {
       return userList;
    }
    public void setUserList(List<User> userList) {
       this.userList = userList;
    }
}

 registerAll.jsp

 <form action="${pageContext.request.contextPath}/user/addAll.action" method="POST">
        
       姓名:<input type="text" name="userList[0].name" value="哈哈"/>
       性别:<input type="text" name="userList[0].gender" value="男"/>
       <hr/>
      
       姓名:<input type="text" name="userList[1].name" value="呵呵"/>
       性别:<input type="text" name="userList[1].gender" value="男"/>
       <hr/>
 
       姓名:<input type="text" name="userList[2].name" value="嘻嘻"/>
       性别:<input type="text" name="userList[2].gender" value="女"/>
       <hr/>
      
       <input type="submit" value="批量注册"/>
      
    </form>

5.2解决项目中的编码问题

解决post乱码问题

提交发现,保存成功,但是保存的是乱码

在web.xml中加入:

 <!-- 解决post乱码问题 -->
         <filter>
                   <filter-name>encoding</filter-name>
                   <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
                   <!-- 设置编码参是UTF8 -->
                   <init-param>
                            <param-name>encoding</param-name>
                            <param-value>UTF-8</param-value>
                   </init-param>
         </filter>
         <filter-mapping>
                   <filter-name>encoding</filter-name>
                   <url-pattern>/*</url-pattern>
         </filter-mapping>

以上可以解决post请求乱码问题。

 对于get请求中文参数出现乱码解决方法有两个:

修改tomcat配置文件添加编码与工程编码一致,如下:

<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

另外一种方法对参数进行重新编码:

String userName =new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")

ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码

5.3@RequestMapping注解使用

1)url路径的映射

@RequestMapping(value="item")或@RequestMapping("/item"),value的值是数组,可以将多个url映射到同一个方法

@RequestMapping(value = { "itemList", "itemListAll" })
public ModelAndView queryItemList() {

2)可以添加到类上

在class上添加@RequestMapping(url)指定通用请求前缀, 限制此类下的所有方法请求url必须以请求前缀开头

3)请求方法限定

//限定GET方法
@RequestMapping(method = RequestMethod.GET)
//如果通过POST访问则报错:
//HTTP Status 405 - Request method 'POST' not supported
//限定POST方法
@RequestMapping(method = RequestMethod.POST)
//如果通过GET访问则报错:
//HTTP Status 405 - Request method 'GET' not supported
//GET和POST都可以(默认)
@RequestMapping(method = {RequestMethod.GET,RequestMethod.POST})

5.4controller控制器方法的返回值

1)返回ModelAndView

controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。

控制器方法:

public ModelAndView handleRequest(HttpServletRequest requqest,HttpServletResponse response) throws Exception {
       // ModelAndView现在不用了
       ModelAndView modelAndView = new ModelAndView();
       modelAndView.addObject("message","这是我的第一个springmvc应用程序");
       modelAndView.setViewName("/jsp/success.jsp");
       return modelAndView;
    }

2)返回void,利用request和response指定响应结果

在Controller方法形参上可以定义request和response,使用request或response指定响应结果:

①使用request转发页面,如下:

request.getRequestDispatcher("页面路径").forward(request, response);

②可以通过response页面重定向:

response.sendRedirect("url")

response.sendRedirect("/springmvc-web2/itemEdit.action");

3)返回字符串(项目中一般都用这种)

①controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。

public String hello(Model model) throws Exception{
       System.out.println("HelloAction::hello()");
       model.addAttribute("message","你好");
       return "success";
    }

②转发和重定向

在转发情况下,共享request域对象,会将参数从第一个业务控制方法传入第二个业务控制方法,

反之,重定向则不行

public String findEmpById(int id,Model model) throws Exception{
       System.out.println("查询"+id+"号员工信息");
       //转发到EmpAction的另一个方法中去,即再次发送请求
       return "forward:/emp/update.action";
       //重定向到EmpAction的另一个方法中去,即再次发送请求,也可以吧id放到session中,也可以吧id直接写在末尾。
       //return "redirect:/emp/update.action?id=" + id;
 
    }

5.5@InitBinder来解决字符串转日期类型

/**
     * 自定义类型转换器,springmvc在转换参数时候,
     * 如果转不成功,会去自定义类型转换器中用
     */
    @InitBinder
    public void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {
       binder.registerCustomEditor(
              Date.class,
              new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),true));
    }

六、异常处理器

    springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。

   系统中异常包括两类:预期异常(自己知道可能有异常)和运行时未知异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段     减少运行时异常的发生。

   在springmvc中,系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:

  

6.1自定义异常处理器

public class CustomHandleException implements HandlerExceptionResolver {
                        
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
           Exception exception) {
       // 定义异常信息
       String msg;
 
       // 判断异常类型
       if (exception instanceof MyException) {
           // 如果是自定义异常,读取异常信息
           msg = exception.getMessage();
       } else {
           // 如果是运行时异常,则取错误堆栈,从堆栈中获取异常信息
           Writer out = new StringWriter();
           PrintWriter s = new PrintWriter(out);
           exception.printStackTrace(s);
           msg = out.toString();
 
       }
 
       // 把错误信息发给相关人员,邮件,短信等方式
       // TODO
 
       // 返回错误页面,给用户友好页面显示错误信息
       ModelAndView modelAndView = new ModelAndView();
       modelAndView.addObject("msg", msg);
       modelAndView.setViewName("error");
 
       return modelAndView;
    }
}

在springmvc中配置

<!-- 配置全局异常处理器 -->
<bean
id="customHandleException"     class="cn.itcast.ssm.exception.CustomHandleException"/>

6.2自定义异常类

public class MyException extends Exception {
    private String message; // 异常信息
    public MyException() {
       super();
    }
    public MyException(String message) {
       super();
       this.message = message;
    }
    public String getMessage() {
       return message;
    }
    public void setMessage(String message) {
       this.message = message;
    }
}

七、springmvc中的拦截器

Spring Web MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。

实现HandlerInterceptor接口

如下:

public class HandlerInterceptor1 implements HandlerInterceptor {
 
    // Controller执行前调用此方法
    // 返回true表示继续执行,返回false中止执行
    // 这里可以加入登录校验、权限拦截等
    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
       System.out.println("HandlerInterceptor1....preHandle");
        // 设置为true,测试使用
       return true;
    }
 
    // controller执行后且视图返回后调用此方法
    // 这里可得到执行controller时的异常信息
    // 这里可记录操作日志
    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
           throws Exception {
       System.out.println("HandlerInterceptor1....afterCompletion");
    }
 
    // controller执行后但未返回视图前调用此方法
    // 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
           throws Exception {
       System.out.println("HandlerInterceptor1....postHandle");
    }
}

拦截器配置

上面定义的拦截器再复制一份HandlerInterceptor2,注意新的拦截器修改代码:

System.out.println("HandlerInterceptor2....preHandle");

在springmvc.xml中配置拦截器

<!-- 配置拦截器 -->

<mvc:interceptors>

 

    <mvc:interceptor>

       <!-- 所有的请求都进入拦截器 -->

       <mvc:mapping path="/**" />

       <!-- 配置具体的拦截器 -->

       <bean class="cn.itcast.ssm.interceptor.HandlerInterceptor1" />

    </mvc:interceptor>

    <mvc:interceptor>

       <!-- 所有的请求都进入拦截器 -->

       <mvc:mapping path="/**" />

       <!-- 配置具体的拦截器 -->

       <bean class="cn.itcast.ssm.interceptor.HandlerInterceptor2" />

    </mvc:interceptor>

</mvc:interceptors>

正常流程测试

浏览器访问地址

http://127.0.0.1:8080/springmvc-web2/itemList.action

运行流程

控制台打印:

HandlerInterceptor1..preHandle..

HandlerInterceptor2..preHandle..

 

HandlerInterceptor2..postHandle..

HandlerInterceptor1..postHandle..

 

HandlerInterceptor2..afterCompletion..

HandlerInterceptor1..afterCompletion..

中断流程测试

浏览器访问地址

http://127.0.0.1:8080/springmvc-web2/itemList.action

 

运行流程

HandlerInterceptor1的preHandler方法返回false,HandlerInterceptor2返回true,

运行流程如下:

HandlerInterceptor1..preHandle..

 

 从日志看出第一个拦截器的preHandler方法返回false后第一个拦截器只执行了preHandler方法,其它两个方法没有执行,第二个拦截器的所有方法不执行,且Controller也不执行了。

HandlerInterceptor1的preHandler方法返回true,HandlerInterceptor2的preHandler方法返回false,运行流程如下:

HandlerInterceptor1..preHandle..

HandlerInterceptor2..preHandle..

HandlerInterceptor1..afterCompletion..

 

   从日志看出第二个拦截器的preHandler方法返回false后第一个拦截器的postHandler没有执行,第二个拦截器的postHandler和afterCompletion没有执行,且controller也不执行了。

总结:

preHandle按拦截器定义顺序调用

postHandler按拦截器定义逆序调用

afterCompletion按拦截器定义逆序调用

 

postHandler在拦截器链内所有拦截器返回true调用

afterCompletion只有preHandle返回true才调用

八、使用json数据交互

8.1@RequestBody注解

   用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容(json数据)转换为java对象并绑定到Controller方法的参数上。

8.2请求json和响应json的实现

1)导入jar包

2)配置json转换器

如果不使用注解驱动<mvc:annotation-driven />,就需要给处理器适配器配置json转换器,参考之前学习的自定义参数绑定。

在springmvc.xml配置文件中,给处理器适配器加入json转换器:

<!--处理器适配器 -->

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">

 <property name="messageConverters">

   <list>

     <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">

     </bean>

    </list>

  </property>

</bean>

3)写javabean

Item.java

public class Item {

    private Integer id;

    private String name;

    private Double sal;

    public User(){}

    public Integer getId() {

       return id;

    }

    public void setId(Integer id) {

       this.id = id;

    }

    public String getName() {

       return name;

    }

    public void setName(String name) {

       this.name = name;

    }

    public Double getSal() {

       return sal;

    }

    public void setSal(Double sal) {

       this.sal = sal;

    }

}

4)jsp编写 

<form>

       编号:<input type="text" name="id" value="1"/><br/>

       姓名:<input type="text" name="name" value="哈哈"/><br/>

       薪水:<input type="text" name="sal" value="5000"/><br/>

       <input type="button" value="异步提交注册"/>

    </form>

   

    <script type="text/javascript">

       $(":button").click(function(){

           var url = "${pageContext.request.contextPath}/ testJson ";

           var sendData = {

              "id":1,

              "name":"哈哈",

              "sal":5000

           };

           $.post(url,sendData,function(backData,textStatus,ajax){

              alert(ajax.responseText);

           });

       });

    </script>

5)控制器编写 

/**

 * 测试json的交互

 * @param item

 * @return

 */

@RequestMapping("testJson")

// @ResponseBody

public @ResponseBody Item testJson(@RequestBody Item item) {

System.out.println(item.getId()+":"+item.getName()+":"+item.getSal());

    return item;

}

  

 

原文地址:https://www.cnblogs.com/mercuryji/p/springmvc.html