zoukankan      html  css  js  c++  java
  • SpringMVC介绍及参数绑定

    本节内容:

    • SpringMVC介绍
    • 入门程序
    • SpringMVC架构
    • SpringMVC整合MyBatis
    • 参数绑定
    • SpringMVC和Struts2的区别

    一、SpringMVC介绍

    1. 什么是SpringMVC

    Spring web mvc和Struts2都属于表现层的框架,它是Spring框架的一部分,我们可以从Spring的整体结构中看得出来,如下图:

    SpringMVC和Spring是一家的,它两之间不存在整合。非要说整合,那也是无缝整合,因为它俩不需要整合包。

    2. SpringMVC处理流程

    这个前端控制器就是servlet容器。前端控制器相当于SpringMVC的心脏。

    图中的处理器就是controller层。

    二、入门程序

    【需求】:使用浏览器显示商品列表。

    1. 创建web工程

    springMVC是表现层框架,需要搭建web工程开发。

    2. 导入jar包

    在WEB-INF下创建lib,导入jar包如下,并加入到classpath中。

    3. 配置前端控制器

    web.xml里配置前端控制器,如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
    
        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
            <welcome-file>index.htm</welcome-file>
            <welcome-file>index.jsp</welcome-file>
            <welcome-file>default.html</welcome-file>
            <welcome-file>default.htm</welcome-file>
            <welcome-file>default.jsp</welcome-file>
        </welcome-file-list>
    
    
        <!-- 前端控制器 -->
        <servlet>
            <servlet-name>springmvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- 指定SpringMVC配置文件 -->
            <!-- SpringMVC的配置文件的默认路径是/WEB-INF/${servlet-name}-servlet.xml -->
            <init-param>
                <param-name>contextConfigLocation</param-name> <!--SpringMVC和Spring是一家,放配置文件都是放在 contextConfigLocation -->
                <param-value>classpath:springmvc.xml</param-value>
            </init-param>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <!--
                1. /*  拦截所有   jsp  js png .css  真的全拦截   建议不使用
                2. *.action *.do 拦截以do action 结尾的请求     肯定能使用,一般用在后台上,比如ERP。
                3. /  拦截所有 (不包括jsp) (但是包含.js .png .css)  强烈建议使用,一般用在前台上,面向消费者,比如www.jd.com/search。但是这种拦截需要考虑对静态资源放行
             -->
            <url-pattern>*.action</url-pattern>
        </servlet-mapping>
    </web-app>

    在src下创建springmvc的配置文件springmvc.xml,该文件的头和Spring的配置文件的头是一样的:

    <?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:p="http://www.springframework.org/schema/p"
    	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-4.0.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
          
    </beans>

    4. 加入jsp文件(用于显示商品)

    先创建一个数据库springmvc,然后导入下面两张表:

    DROP TABLE IF EXISTS `items`;
    CREATE TABLE `items` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(32) NOT NULL COMMENT '商品名称',
      `price` float(10,1) NOT NULL COMMENT '商品定价',
      `detail` text COMMENT '商品描述',
      `pic` varchar(64) DEFAULT NULL COMMENT '商品图片',
      `createtime` datetime NOT NULL COMMENT '生产日期',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of items
    -- ----------------------------
    INSERT INTO `items` VALUES ('1', '台式机', '3000.0', '该电脑质量非常好!!!!', null, '2016-02-03 13:22:53');
    INSERT INTO `items` VALUES ('2', '笔记本', '6000.0', '笔记本性能好,质量好!!!!!', null, '2015-02-09 13:22:57');
    INSERT INTO `items` VALUES ('3', '背包', '200.0', '名牌背包,容量大质量好!!!!', null, '2015-02-06 13:23:02');
    
    -- ----------------------------
    -- Table structure for user
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(32) NOT NULL COMMENT '用户名称',
      `birthday` date DEFAULT NULL COMMENT '生日',
      `sex` char(1) DEFAULT NULL COMMENT '性别',
      `address` varchar(256) DEFAULT NULL COMMENT '地址',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES ('1', '王五', null, '2', null);
    INSERT INTO `user` VALUES ('10', '张三', '2014-07-10', '1', '北京市');
    INSERT INTO `user` VALUES ('16', '张小明', null, '1', '河南郑州');
    INSERT INTO `user` VALUES ('22', '陈小明', null, '1', '河南郑州');
    INSERT INTO `user` VALUES ('24', '张三丰', null, '1', '河南郑州');
    INSERT INTO `user` VALUES ('25', '陈小明', null, '1', '河南郑州');
    INSERT INTO `user` VALUES ('26', '王五', null, null, null);

    itemList.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"  prefix="fmt"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>查询商品列表</title>
    </head>
    <body> 
    <form action="${pageContext.request.contextPath }/item/queryitem.action" method="post">
    查询条件:
    <table width="100%" border=1>
    <tr>
    <td><input type="submit" value="查询"/></td>
    </tr>
    </table>
    商品列表:
    <table width="100%" border=1>
    <tr>
    	<td>商品名称</td>
    	<td>商品价格</td>
    	<td>生产日期</td>
    	<td>商品描述</td>
    	<td>操作</td>
    </tr>
    <c:forEach items="${itemList }" var="item">
    <tr>
    	<td>${item.name }</td>
    	<td>${item.price }</td>
    	<td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
    	<td>${item.detail }</td>
    	
    	<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
    
    </tr>
    </c:forEach>
    
    </table>
    </form>
    </body>
    
    </html>

    因为jsp中用到了jstl和el表达式,所以需要导入 jstl-1.2.jar。

    5. 准备pojo

    分析页面,查看页面需要的数据,自己手动创建pojo。或者使用Mybatis的generator逆向工程生成pojo代码。我这里选择逆向生成代码,然后复制到现在这个项目里。

    6. 创建ItemController

    新建一个包 com.wisedu.springmvc.controller,Struts2叫action,SpringMVC叫controller,或者叫handler。在包下面创建一个ItemController.java

    package com.wisedu.springmvc.controller;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.HttpRequestHandler;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.servlet.ModelAndView;
    
    import com.wisedu.springmvc.pojo.Items;
    
    /**
     * 商品管理
     * 
     * @author jkzhao
     *
     */
    @Controller
    public class ItemController {
    	
    	// @RequestMapping:里面放的是请求的url,和用户请求的url进行匹配
    	// 这里的.action可以写也可以不写。因为你在浏览器访问localhost:8080/item/itemlist.action(浏览器上输入地址时必须加上.action,不然就不会被拦截了),就被拦截进来了,
         // 然后和@RequestMapping进行比对时,只会比对/item/itemlist,但是最好还是把.action写上,遵循规范 @RequestMapping(value = "/item/itemlist.action") public ModelAndView itemList(){ // 创建页面需要显示的商品数据 List<Items> list = new ArrayList<Items>(); list.add(new Items(1, "1华为 荣耀8", 2399f, new Date(), "质量好!1")); list.add(new Items(2, "2华为 荣耀8", 2399f, new Date(), "质量好!2")); list.add(new Items(3, "3华为 荣耀8", 2399f, new Date(), "质量好!3")); list.add(new Items(4, "4华为 荣耀8", 2399f, new Date(), "质量好!4")); list.add(new Items(5, "5华为 荣耀8", 2399f, new Date(), "质量好!5")); list.add(new Items(6, "6华为 荣耀8", 2399f, new Date(), "质量好!6")); // 创建ModelAndView,用来存放数据和视图 ModelAndView mav = new ModelAndView(); // 设置数据到模型中 mav.addObject("itemList", list); //页面上循环的是itemList // 设置视图的路径,需要设置视图的物理地址 mav.setViewName("/WEB-INF/jsp/itemList.jsp"); return mav; } }

    ItemController是一个普通的java类,不需要实现任何接口。需要在类上添加@Controller注解,把Controller交由Spring管理。

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

    在springmvc.xml中配置扫描 com.wisedu.springmvc 包(Controller类上加了注解,交给Spring容器管理)

    <?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:p="http://www.springframework.org/schema/p"
    	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-4.0.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    	
            <!-- 扫描@Controler  @Service   -->
            <context:component-scan base-package="com.wisedu.springmvc"/>
            
    </beans>

    7. 启动项目测试

    启动程序,在浏览器输入:http://localhost:8080/item/itemlist.action

    三、SpringMVC架构

    1. 框架结构

    基本上需要我们手动写的只有处理器Handler和视图部分。前端控制器DispatcherServlet是核心,只需要我们配置下。

    处理器映射器HandlerMapping、处理器适配器HandlerAdapter和视图解析器ViewResolver是springmvc三大组件,都是已经实现好了,我们也是配置下。

    2. 架构流程

    1. 用户发送请求至前端控制器DispatcherServlet
    2. DispatcherServlet收到请求调用HandlerMapping处理器映射器
    3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;拦截器比如做一些权限判断啊,没登录就拦截下来等。
    4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
    5. 执行处理器(Controller,也叫后端控制器)
    6. Controller执行完成返回ModelAndView
    7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
    8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器
    9. ViewReslover解析后返回具体View
    10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
    11. DispatcherServlet响应用户

    3. 组件说明

    • DispatcherServlet:前端控制器

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

    • HandlerMapping:处理器映射器

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

    • Handler:处理器

    Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
    由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。

    • HandlAdapter:处理器适配器

    通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
    下图是许多不同的适配器,最终都可以使用usb接口连接。

    • ViewResolver:视图解析器

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

    • View:视图

    springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

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

    需要程序员开发的组件有handler、view。

    4. 默认加载的组件 

    但是我们在上面的示例中好像只配置了前端控制器,并没有配置三大组件,程序一样跑起来了,能正常访问。这是因为框架默认加载了这些组件了。配置文件位置如下图:

    文件内容如下:

    # Default implementation classes for DispatcherPortlet's strategy interfaces.
    # Used as fallback when no matching beans are found in the DispatcherPortlet context.
    # Not meant to be customized by application developers.
    
    # 处理器映射器,默认是注解式开发(比如@RequestMapping(value = "/item/itemlist.action"))
    org.springframework.web.portlet.HandlerMapping=org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping
    
    # 处理器适配器,有2个,默认是AnnotationMethodHandlerAdapter,注解处理器适配器
    org.springframework.web.portlet.HandlerAdapter=org.springframework.web.portlet.mvc.SimpleControllerHandlerAdapter,
    	org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter
    
    # 异常处理
    org.springframework.web.portlet.HandlerExceptionResolver=org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver
    
    # 视图解析器
    org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

    5. 组件扫描器

    使用组件扫描器省去在spring容器配置每个Controller类的繁琐。

    使用<context:component-scan>自动扫描标记@Controller的控制器类,在springmvc.xml配置文件中配置如下:

    <!-- 配置controller扫描包,多个包之间用,分隔 -->
    <context:component-scan base-package="cn.itcast.springmvc.controller" />

    6. 注解映射器和适配器

    (1)配置处理器映射器

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

    HandlerMethod对象中封装url对应的方法Method。

    从spring3.1版本开始,废除了DefaultAnnotationHandlerMapping的使用,推荐使用RequestMappingHandlerMapping完成注解式处理器映射。

    在springmvc.xml配置文件中配置如下:

            <!-- 处理器映射器 -->
             <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> 

    注解描述:

    @RequestMapping:定义请求url到处理器功能方法的映射

    (2)配置处理器适配器

    注解式处理器适配器,对标记@ResquestMapping的方法进行适配。

    从spring3.1版本开始,废除了AnnotationMethodHandlerAdapter的使用,推荐使用RequestMappingHandlerAdapter完成注解式处理器适配。

    在springmvc.xml配置文件中配置如下:

            <!-- 处理器适配器 -->
    	<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> 
    

    (3)注解驱动

    直接配置处理器映射器和处理器适配器比较麻烦,可以使用注解驱动来加载。

    SpringMVC使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping和RequestMappingHandlerAdapter

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

            <!-- 注解驱动
              这一个配置相当于上面两个配置-->
            <mvc:annotation-driven/>
    

      

    7. 视图解析器

    视图解析器使用SpringMVC框架默认的InternalResourceViewResolver,这个视图解析器支持JSP视图解析

    在springmvc.xml配置文件中配置如下:

            <!-- Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> 
    		"/WEB-INF/jsp/test.jsp" -->
    	<!-- 配置视图解析器 -->
    	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    		<!-- 配置逻辑视图的前缀 -->
    		<property name="prefix" value="/WEB-INF/jsp/" />
    		<!-- 配置逻辑视图的后缀 -->
    		<property name="suffix" value=".jsp" />
    	</bean>
    

    逻辑视图名需要在controller中返回ModelAndView指定,比如逻辑视图名为ItemList,则最终返回的jsp视图地址:
    “WEB-INF/jsp/itemList.jsp”

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

    这样,可以修改ItemController中设置视图的代码:

    @Controller
    public class ItemController {
    
    	// @RequestMapping:里面放的是请求的url,和用户请求的url进行匹配
    	// action可以写也可以不写
    	@RequestMapping(value = "/item/itemlist.action")
    	public ModelAndView itemList(){
    		
    		// 创建页面需要显示的商品数据
    		List<Items> list = new ArrayList<Items>();
    		list.add(new Items(1, "1华为 荣耀8", 2399f, new Date(), "质量好!1"));
    		list.add(new Items(2, "2华为 荣耀8", 2399f, new Date(), "质量好!2"));
    		list.add(new Items(3, "3华为 荣耀8", 2399f, new Date(), "质量好!3"));
    		list.add(new Items(4, "4华为 荣耀8", 2399f, new Date(), "质量好!4"));
    		list.add(new Items(5, "5华为 荣耀8", 2399f, new Date(), "质量好!5"));
    		list.add(new Items(6, "6华为 荣耀8", 2399f, new Date(), "质量好!6"));
    
    		// 创建ModelAndView,用来存放数据和视图
    		ModelAndView mav = new ModelAndView();
    		// 设置数据到模型中
    		mav.addObject("itemList", list); //页面上循环的是itemList
    		// 设置视图的路径,需要设置视图的物理地址
    		//mav.setViewName("/WEB-INF/jsp/itemList.jsp"); 
    		mav.setViewName("itemList"); //在springmvc.xml中替换掉默认的视图解析器
    
    		return mav;
    	}
    	
    }
    

    四、SpringMVC整合MyBatis

    整合目标:控制层采用springmvc、持久层使用mybatis实现。

    创建一个新工程,springmvc-mybatis。

    先整合spring和mybatis,然后在整合springmvc,其实springmvc不叫整合,把配置文件拿过来放一起即可。

    1. 需要的jar包

    1. spring(包括springmvc)
    2. mybatis
    3. mybatis-spring整合包
    4. 数据库驱动包
    5. 第三方连接池

    2. 配置文件

    Dao层:

    • SqlMapConfig.xml,空文件即可(或者在里面配置下别名),但是需要文件头。
    • applicationContext-dao.xml
      • 数据库连接池
      • SqlSessionFactory对象,需要spring和mybatis整合包下的。
      • 配置mapper文件扫描器。

    Service层:

    • applicationContext-service.xml包扫描器,扫描@service注解的类。
    • applicationContext-trans.xml配置事务。

    Controller层:

    •  springmvc.xml
      • 包扫描器,扫描@Controller注解的类。
      • 配置注解驱动
      • 配置视图解析器

    web.xml文件:(web工程,需要在web.xml中配置读取)

    • 配置spring
    • 配置前端控制器。

    我这里合并了一些配置文件,最终是如下5个配置文件。

    applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
           xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
           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-4.0.xsd
    	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
    
        <!-- 加载配置文件 -->
        <context:property-placeholder location="classpath:db.properties" />
    
        <!-- 数据库连接池 -->
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
              destroy-method="close">
            <property name="driverClassName" value="${jdbc.driver}" />
            <property name="url" value="${jdbc.url}" />
            <property name="username" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
            <property name="maxActive" value="10" />
            <property name="maxIdle" value="5" />
        </bean>
    
        <!-- 配置Mybatis的工程 SqlSessionFactory -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <!-- 配置mybatis核心配置文件,原来核心配置文件中是有连接池的,现在交给Spring了 -->
            <property name="configLocation" value="classpath:sqlMapConfig.xml" />
            <!-- 配置数据源 -->
            <property name="dataSource" ref="dataSource" />
        </bean>
    
        <!-- Mapper代理的方式开发方式二,扫描包方式配置代理(不注入工厂也可以,org.mybatis.spring.mapper.MapperScannerConfigurer会自己去Spring容器中去找) -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <!-- 配置Mapper接口 -->
            <property name="basePackage" value="com.wisedu.springmvc.dao.mapper" />
        </bean>
    
        <!-- 配置注解式事务 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
        <!--开启注解-->
        <tx:annotation-driven transaction-manager="transactionManager"/>
    
    </beans>

    springmvc.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:p="http://www.springframework.org/schema/p"
    	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-4.0.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
    	<!-- 扫描@Controler  @Service   -->
    	<context:component-scan base-package="com.wisedu.springmvc"/>
    
    	<!-- 处理器映射器 -->
    	<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>-->
    	<!-- 处理器适配器 -->
    	<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>-->
    	<!-- 注解驱动
          这一个配置相当于上面两个配置-->
    	<mvc:annotation-driven/>
    
    	<!-- 视图解析器 -->
    	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    		<property name="prefix" value="/WEB-INF/jsp/"/>
    		<property name="suffix" value=".jsp"/>
    	</bean>
            
    </beans>

    sqlMapConfig.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <!-- 设置别名 -->
        <typeAliases>
            <!-- 2. 指定扫描包,会把包内所有的类都设置别名,别名的名称就是类名,大小写不敏感 -->
            <package name="com.wisedu.springmvc.pojo" />
        </typeAliases>
    </configuration>

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
    
        <!-- 配置spring -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </context-param>
        <!-- 使用监听器加载Spring配置文件 -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <!-- 配置SrpingMVC的前端控制器 -->
        <servlet>
            <servlet-name>springmvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- 指定SpringMVC配置文件 -->
            <!-- SpringMVC的配置文件的默认路径是/WEB-INF/${servlet-name}-servlet.xml -->
            <init-param>
                <param-name>contextConfigLocation</param-name> <!--SpringMVC和Spring是一家,放配置文件都是放在 contextConfigLocation -->
                <param-value>classpath:springmvc.xml</param-value>
            </init-param>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <!--
                1. /*  拦截所有   jsp  js png .css  真的全拦截   建议不使用
                2. *.action *.do 拦截以do action 结尾的请求     肯定能使用,一般用在后台上,比如ERP。
                3. /  拦截所有 (不包括jsp) (但是包含.js .png .css)  强烈建议使用,一般用在前台上,面向消费者,比如www.jd.com/search。但是这种拦截需要考虑对静态资源放行
             -->
            <url-pattern>*.action</url-pattern>
        </servlet-mapping>
    
    </web-app>

    db.properties

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/springmvc?characterEncoding=utf-8
    jdbc.username=root
    jdbc.password=123456

    log4j.properties

    # Global logging configuration
    log4j.rootLogger=DEBUG, stdout
    # Console output...
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
    

    3. 加入pojo和mapper文件

    将上个案例中逆向工程生成的pojo和mapper文件复制到该工程中来。

    这样就整合完毕了。 

    【示例】:从Mysql中查询商品列表。

    引入jsp文件itemLiust.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"  prefix="fmt"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>查询商品列表</title>
    </head>
    <body> 
    <form action="${pageContext.request.contextPath }/item/queryitem.action" method="post">
    查询条件:
    <table width="100%" border=1>
    <tr>
    <td><input type="submit" value="查询"/></td>
    </tr>
    </table>
    商品列表:
    <table width="100%" border=1>
    <tr>
    	<td>商品名称</td>
    	<td>商品价格</td>
    	<td>生产日期</td>
    	<td>商品描述</td>
    	<td>操作</td>
    </tr>
    <c:forEach items="${itemList }" var="item">
    <tr>
    	<td>${item.name }</td>
    	<td>${item.price }</td>
    	<td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
    	<td>${item.detail }</td>
    	
    	<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
    
    </tr>
    </c:forEach>
    
    </table>
    </form>
    </body>
    
    </html>

    编写service层 ItemService.java ItemServiceImpl.java

    package com.wisedu.springmvc.service;
    
    import com.wisedu.springmvc.pojo.Items;
    
    import java.util.List;
    
    /**
     * Created by jkzhao on 1/2/18.
     */
    public interface ItemService {
        List<Items> selectItemsList();
    
    }
    
    package com.wisedu.springmvc.service.impl;
    
    import com.wisedu.springmvc.dao.mapper.ItemsMapper;
    import com.wisedu.springmvc.pojo.Items;
    import com.wisedu.springmvc.service.ItemService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    /**
     * Created by jkzhao on 1/2/18.
     * 查询商品信息
     */
    @Service
    public class ItemServiceImpl implements ItemService {
        @Autowired
        private ItemsMapper itemsMapper;
    
        //查询商品列表(无条件)
        public List<Items> selectItemsList(){
            List<Items> itemses = itemsMapper.selectByExampleWithBLOBs(null);
    
            return itemses;
        }
    
    }

    编写controller层 ItemController.java

    import com.wisedu.springmvc.service.ItemService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.servlet.ModelAndView;
    
    import java.util.List;
    
    /**
     * 商品管理
     * 
     * @author jkzhao
     *
     */
    @Controller
    public class ItemController {
    
        @Autowired
        private ItemService itemService;
    
    	// @RequestMapping:里面放的是请求的url,和用户请求的url进行匹配
    	// action可以写也可以不写
    	@RequestMapping(value = "/item/itemlist.action")
    	public ModelAndView itemList(){
    		
    		// 从MySQL中查询数据
    		List<Items> list = itemService.selectItemsList();
    
    		// 创建ModelAndView,用来存放数据和视图
    		ModelAndView mav = new ModelAndView();
    		// 设置数据到模型中
    		mav.addObject("itemList", list); //页面上循环的是itemList
    		// 设置视图的路径,需要设置视图的物理地址
    		//mav.setViewName("/WEB-INF/jsp/itemList.jsp");
    		mav.setViewName("itemList"); //在springmvc.xml中替换掉默认的视图解析器
    
    		return mav;
    	}
    	
    }

    启动项目,浏览器访问:http://localhost:8080/item/itemlist.action

    因为log4j.properties里开启了DEBUG,可以看到控制台日志把sql语句打印出来了。

    如果我们在IDEA中使用Maven管理项目,IDEA中,如果把生成的Mapper.xml文件放在java目录下,编译和打包时是不会打包进WEB-INF/classes下的,需要在pom文件中配置:

     <build>
        <!--mybatis逆向工程生成代码-->
        <plugins>
          <plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>${mybatis_general.version}</version>
          </plugin>
          <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
              <source>1.7</source>
              <target>1.7</target>
            </configuration>
          </plugin>
        </plugins>
        <!--打包时包含源代码包下的资源文件-->
        <resources>
          <resource>
            <directory>src/main/java</directory>
            <includes>
              <include>**/*.properties</include>
              <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
          </resource>
        </resources>
      </build>

    这样编译后,会将src/main/java下的xml文件随同java编译后的class文件一同copy到相应的class目录。

    如果不加这个配置,在执行时会报类似如下错误:

    org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.spring.learn.dao.automatic.UserMapper.selectByPrimaryKey
    

    五、参数绑定

    什么是参数绑定?

    例如上面的例子中,我在“操作”那一列点击“修改”,就得传参到后台,比如把商品的id传到后台,在controller再写一个方法处理这个修改操作,入参为整数id。这个id是绑在Controller的成员变量上,还是某个方法的形参上呢?

    绑定在方法的形参上,如果绑定在controller的成员变量上,比如private Integer id; 第一个请求过来了,传来id=1,第二个请求过来了,传来id=2,这就会替换掉之前的1。因为controller的成员变量被别人共用,每个进程只使用本方法,不使用成员变量。100个请求进来,也就只有ItemController这一个类。假设100个请求访问同一个方法,并不会冲突。单例模式下如何处理并发?多线程(这个多线程不是我们写的,而是Spring框架实现好了)。Spring是如何帮我们实现多线程的?

    【需求】:打开商品编辑页面,展示商品信息。

    【需求分析】:

    编辑商品信息,首先要显示商品详情。
    需要根据商品id查询商品信息,然后展示到页面。
    请求的url:/itemEdit.action
    参数:id(商品id)
    响应结果:商品编辑页面,展示商品详细信息。

    【示例代码】:

    editItem.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"  prefix="fmt"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>修改商品信息</title>
    
    </head>
    <body> 
    	<!-- 上传图片是需要指定属性 enctype="multipart/form-data" -->
    	<!-- <form id="itemForm" action="" method="post" enctype="multipart/form-data"> -->
    	<form id="itemForm"	action="${pageContext.request.contextPath }/updateitem.action" method="post">
    		<input type="hidden" name="id" value="${item.id }" /> 修改商品信息:
    		<table width="100%" border=1>
    			<tr>
    				<td>商品名称</td>
    				<td><input type="text" name="name" value="${item.name }" /></td>
    			</tr>
    			<tr>
    				<td>商品价格</td>
    				<td><input type="text" name="price" value="${item.price }" /></td>
    			</tr>
    			<%-- 
    			<tr>
    				<td>商品生产日期</td>
    				<td><input type="text" name="createtime"
    					value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>" /></td>
    			</tr>
    			<tr>
    				<td>商品图片</td>
    				<td>
    					<c:if test="${item.pic !=null}">
    						<img src="/pic/${item.pic}" width=100 height=100/>
    						<br/>
    					</c:if>
    					<input type="file"  name="pictureFile"/> 
    				</td>
    			</tr>
    			 --%>
    			<tr>
    				<td>商品简介</td>
    				<td><textarea rows="3" cols="30" name="detail">${item.detail }</textarea>
    				</td>
    			</tr>
    			<tr>
    				<td colspan="2" align="center"><input type="submit" value="提交" />
    				</td>
    			</tr>
    		</table>
    
    	</form>
    </body>
    
    </html>
    

    ItemService.java

    package com.wisedu.springmvc.service;
    
    import com.wisedu.springmvc.pojo.Items;
    
    import java.util.List;
    
    /**
     * Created by jkzhao on 1/2/18.
     */
    public interface ItemService {
        List<Items> selectItemsList();
        Items selectItemsById(Integer id);
    
    }
    

    ItemServiceImpl.java

    package com.wisedu.springmvc.service.impl;
    
    import com.wisedu.springmvc.dao.mapper.ItemsMapper;
    import com.wisedu.springmvc.pojo.Items;
    import com.wisedu.springmvc.service.ItemService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    /**
     * Created by jkzhao on 1/2/18.
     * 查询商品信息
     */
    @Service
    public class ItemServiceImpl implements ItemService {
        @Autowired
        private ItemsMapper itemsMapper;
    
        //查询商品列表(无条件)
        public List<Items> selectItemsList(){
            List<Items> itemses = itemsMapper.selectByExampleWithBLOBs(null);
    
            return itemses;
        }
    
        //查询商品列表(根据id)
        public Items selectItemsById(Integer id){
            Items items = itemsMapper.selectByPrimaryKey(id);
    
            return items;
        }
    
    }
    

    ItemController.java

    package com.wisedu.springmvc.controller;
    
    import com.wisedu.springmvc.pojo.Items;
    import com.wisedu.springmvc.service.ItemService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import java.util.List;
    
    /**
     * 商品管理
     * 
     * @author jkzhao
     *
     */
    @Controller
    public class ItemController {
    
    	@Autowired
        private ItemService itemService;
    
    	// @RequestMapping:里面放的是请求的url,和用户请求的url进行匹配
    	// 这里的.action可以写也可以不写,因为你在浏览器访问localhost:8080/item/itemlist.action(浏览器上的.action必须加,不然就不会被拦截了),就被拦截进来了,
        // 然后和@RequestMapping进行比对时,只会比对/item/itemlist,但是最好还是把.action写上,遵循规范。
    	@RequestMapping(value = "/item/itemlist.action")
    	public ModelAndView itemList(){
    		
    		// 从MySQL中查询数据
    		List<Items> list = itemService.selectItemsList();
    
    		// 创建ModelAndView,用来存放数据和视图
    		ModelAndView mav = new ModelAndView();
    		// 设置数据到模型中
    		mav.addObject("itemList", list); //页面上循环的是itemList
    		// 设置视图的路径,需要设置视图的物理地址
    		//mav.setViewName("/WEB-INF/jsp/itemList.jsp");
    		mav.setViewName("itemList"); //在springmvc.xml中替换掉默认的视图解析器
    
    		return mav;
    	}
    
    	//修改商品页面 入参id
        @RequestMapping(value = "/itemEdit.action")
        public ModelAndView toEdit(HttpServletRequest request, HttpServletResponse response, HttpSession session, Model model){
    
            //Servlet时代开发
            String id = request.getParameter("id");
            //根据id查询一个商品
            Items items = itemService.selectItemsById(Integer.parseInt(id));
    
            // 创建ModelAndView,用来存放数据和视图
            ModelAndView mav = new ModelAndView();
            // 设置数据到模型中
            mav.addObject("item", items); //页面上循环的是item
            // 设置视图的路径,需要设置视图的物理地址
            mav.setViewName("editItem"); //在springmvc.xml中替换掉默认的视图解析器
    
            return mav;
    
        }
    
    }
    

    1. 默认支持的参数类型

    处理器形参中添加如下类型的参数处理适配器会默认识别并进行赋值。

    • HttpServletRequest:通过request对象获取请求信息
    • HttpServletResponse:通过response处理响应信息
    • HttpSession:通过session对象得到session中存放的对象

    2. Model/ModelMap
    (1)Model

    除了ModelAndView以外,还可以使用Model来向页面传递数据。Model是一个接口,在参数里直接声明model即可。

    如果使用Model则可以不使用ModelAndView对象,Model对象可以向页面传递数据,View对象则可以使用String返回值替代。

    不管是Model还是ModelAndView,其本质都是使用Request对象向jsp传递数据。

    代码实现:

    /**
     * 根据id查询商品,使用Model
     * 
     * @param request
     * @param model
     * @return
     */
    @RequestMapping("/itemEdit.action")
    public String queryItemById(HttpServletRequest request, Model model) {
    	// 从request中获取请求参数
    	String strId = request.getParameter("id");
    	Integer id = Integer.valueOf(strId);
    
    	// 根据id查询商品数据
    	Item item = this.itemService.selectItemsById(id);
    
    	// 把结果传递给页面
    	// ModelAndView modelAndView = new ModelAndView();
    	// 把商品数据放在模型中
    	// modelAndView.addObject("item", item);
    	// 设置逻辑视图
    	// modelAndView.setViewName("itemEdit");
    
    	// 把商品数据放在模型中
    	model.addAttribute("item", item);
    
    	return "itemEdit";
    }

    (2)ModelMap
    ModelMap是Model接口的实现类,也可以通过ModelMap向页面传递数据。

    使用Model和ModelMap的效果一样,如果直接使用Model,springmvc会实例化ModelMap。

    代码实现:

    /**
     * 根据id查询商品,使用ModelMap
     * 
     * @param request
     * @param model
     * @return
     */
    @RequestMapping("/itemEdit.action")
    public String queryItemById(HttpServletRequest request, ModelMap model) {
    	// 从request中获取请求参数
    	String strId = request.getParameter("id");
    	Integer id = Integer.valueOf(strId);
    
    	// 根据id查询商品数据
    	Item item = this.itemService.selectItemById(id);
    
    	// 把结果传递给页面
    	// ModelAndView modelAndView = new ModelAndView();
    	// 把商品数据放在模型中
    	// modelAndView.addObject("item", item);
    	// 设置逻辑视图
    	// modelAndView.setViewName("itemEdit");
    
    	// 把商品数据放在模型中
    	model.addAttribute("item", item);
    
    	return "itemEdit";
    }

    3. 绑定简单类型

    当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定。

    这样,从Request取参数的方法就可以进一步简化。

       /**
         * 根据id查询商品,绑定简单数据类型
         *
         * @param id
         * @param model
         * @return
         */
        @RequestMapping("/itemEdit")
        public String queryItemById(Integer id, ModelMap model) { //不要用int,万一传进来一个long
            // 根据id查询商品数据
            Items item = this.itemService.selectItemsById(id);
    
            // 把商品数据放在模型中
            model.addAttribute("item", item);
    
            return "itemEdit";
        }
    

    (1)支持的数据类型

    参数类型推荐使用包装数据类型,因为基础数据类型不可以为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)

    (2)@RequestParam

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

    • value:参数名字,即入参的请求参数名字,如value=“itemId”表示请求的参数区中的名字为itemId的参数的值将传入
    • required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报错:HTTP Status 400 - Required Integer parameter 'XXXX' is not present
    • defaultValue:默认值,表示如果请求中没有同名参数时的默认值

    定义如下:

        @RequestMapping("/itemEdit")
        public String queryItemById2(
                //这个itemId对应于页面上的参数名称,也就是传过来的请求中的参数,绑定在该方法的形参上 id 上,有些人他不喜欢传过来的参数名称。但是这个id必须有值,如果没值会报错。你可以设置 required = false
                @RequestParam(value = "itemId", required = true, defaultValue = "1") Integer id,
                                    ModelMap modelMap) {
            // 根据id查询商品数据
            Items item = this.itemService.selectItemsById(id);
    
            // 把商品数据放在模型中
            modelMap.addAttribute("item", item);
    
            return "itemEdit";
        }
    

    4. 绑定pojo类型

    【需求】:将页面修改后的商品信息保存到数据库中。 

    【需求分析】:

    请求的url:/updateItem.action
    参数:表单中的数据。
    响应内容:更新成功页面。

    (1)使用pojo接收表单数据

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

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

    (2)ItemService接口

    ItemService里编写接口方法:

    void updateItemById(Items item);

    (3)ItemServiceImpl实现类

    ItemServiceImpl里实现接口方法:

    使用updateByPrimaryKeySelective(item)方法,忽略空参数。

        @Override
        public void updateItemById(Items item) {
            this.itemsMapper.updateByPrimaryKeySelective(item);
        }
    

      

    (4)ItemController

         /**
         * 更新商品,绑定pojo类型
         *
         * @param item
         * @return
         */
        @RequestMapping("/updateItem.action")
        public String updateItem(Items item) {
            // 调用服务更新商品
            this.itemService.updateItemById(item);
    
            // 跳转成功页面,不需要数据。跳转list,需要数据
            return "success";
        }
    

    (5)编写success页面success.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
             pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Insert title here</title>
    </head>
    <body>
    
    <h1>商品修改成功!</h1>
    
    </body>
    </html>

    (6)解决post乱码问题

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

    在web.xml中加入:

        <!-- 解决post乱码问题 -->
        <filter>
            <filter-name>encoding</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!--类名不要记,去spring-web的jar包中filter包下找-->
            <!-- 设置编码参是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. 绑定包装pojo

    【需求】:使用包装的pojo接收商品信息的查询条件。

    (1)在pojo包下创建一个包装pojo类,QueryVo.java

    package com.wisedu.springmvc.pojo;
    
    public class QueryVo {
    	
    	//商品
    	private Items item;
    
    	public Items getItems() {
    		return item;
    	}
    
    	public void setItems(Items item) {
    		this.item = item;
    	}
    	
    }
    

    (2)修改页面的input的name值

    (3)ItemController

        @RequestMapping("/updateItem.action")
        public String updateItem(QueryVo vo) {
            // 调用服务更新商品
            this.itemService.updateItemById(vo.getItems());
    
            // 跳转成功页面,不需要数据。跳转list,需要数据
            return "success";
        }

    6. 自定义参数绑定

    【需求】:在商品修改页面可以修改商品的生产日期,并且根据业务需求自定义日期格式。

    【需求分析】:

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

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

    一般使用<mvc:annotation-driven />注解驱动加载处理器适配器,可以在此标签上进行配置。

     (1)修改editItem.jsp页面

    (2)自定义Converter

    创建一个包 com.wisedu.springmvc.converter,在下面编写一个自定义转换器类DataConverter.java:

    package com.wisedu.springmvc.converter;
    
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import org.springframework.core.convert.converter.Converter;
    
    /**
     * 转换日期类型的数据
     * S : 页面传递过来的类型
     * T : 转换后的类型
     * @author jkzhao
     *
     */
    public class DateConverter implements Converter<String, Date>{
    
    	public Date convert(String source) {
    		try {
    			if(null != source){//页面传过来的格式 2017:12-31 11_43-50
    				//把字符串转换为日期类型
    				DateFormat df = new SimpleDateFormat("yyyy:MM-dd HH_mm-ss");
    				return df.parse(source);
    			}
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    		return null;
    	}
    
    }

    (3)配置Converter

    我们同时可以配置多个的转换器。类似下图的usb设备,可以接入多个usb设备

    springmvc配置如下:

    <?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:p="http://www.springframework.org/schema/p"
    	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-4.0.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
    	<!-- 扫描@Controler  @Service   -->
    	<context:component-scan base-package="com.wisedu.springmvc"/>
    
    	<!-- 处理器映射器 -->
    	<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>-->
    	<!-- 处理器适配器 -->
    	<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>-->
    	<!-- 注解驱动
          这一个配置相当于上面两个配置-->
    	<mvc:annotation-driven conversion-service="conversionService"/>
    
    	<!--转换器配置 这里转换日期-->
    	<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
            <!--配置多个转换器-->
            <property name="converters">
                <set> <!--用list或者其他也可以-->
                    <!--自定义转换器类-->
                    <bean class="com.wisedu.springmvc.converter.DateConverter"></bean>
                </set>
            </property>
        </bean>
    
    	<!-- 视图解析器 -->
    	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    		<property name="prefix" value="/WEB-INF/jsp/"/>
    		<property name="suffix" value=".jsp"/>
    	</bean>
            
    </beans>

    配置方式2(了解)

    <!--注解适配器 -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    	<property name="webBindingInitializer" ref="customBinder"></property>
    </bean>
    
    <!-- 自定义webBinder -->
    <bean id="customBinder" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
    	<property name="conversionService" ref="conversionService" />
    </bean>
    
    <!-- 转换器配置 -->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    	<property name="converters">
    		<set>
    			<bean class="cn.itcast.springmvc.convert.DateConverter" />
    		</set>
    	</property>
    </bean>
    

    【注意】:此方法需要独立配置处理器映射器、适配器,不再使用<mvc:annotation-driven/>

    六、SpringMVC和Struts2的区别

    1. springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过滤器。
    2. springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
    3. Struts采用值栈存储请求和响应的数据,通过OGNL存取数据, springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过request域传输到页面。Jsp视图解析器默认使用jstl。
  • 相关阅读:
    dubbo+zookeeper注册服务报错问题:No service registed on zookeeper
    悲观锁和乐观锁的区别,它们是怎么实现
    cookie和session的区别,分布式环境怎么保存用户状态
    深入理解Java接口和抽象类
    Java中堆内存和栈内存详解
    Java基础梳理(一)
    Spring的@Transactional注解详细用法
    SpringBoot学习笔记(一)基础
    项目实体类使用@Data注解,但是项目业务类中使用getA(),setA()方法报错,eclipse中配置lombok
    有依赖的背包问题-购物单
  • 原文地址:https://www.cnblogs.com/zhaojiankai/p/8142834.html
Copyright © 2011-2022 走看看