SpringMVC框架第一天

#

SpringMVC框架第一天

##SpringMVC大纲
1.MVC回顾
2.SpringMVC入门案例
3.@RequestMapping注解
4.请求参数绑定
5.常用注解

重点:
	SpringMVC入门案例
	@RequestMapping注解的使用
	@RequestParam注解的使用。
	重点掌握请求参数绑定

第一章:三层架构和MVC

1.1 三层架构
1. 咱们开发服务器端程序,一般都基于两种形式,一种C/S架构程序,一种B/S架构程序
2. 使用Java语言基本上都是开发B/S架构的程序,B/S架构又分成了三层架构
3. 三层架构
   a. 表现层:WEB层,用来和客户端进行数据交互的。表现层一般会采用MVC的设计模型
   b. 业务层:处理公司具体的业务逻辑的
   c. 持久层:用来操作数据库的
1.2 MVC模型
1. MVC全名是Model View Controller 模型视图控制器,每个部分各司其职。
2. Model:数据模型,JavaBean的类,用来进行数据封装。
3. View:指JSP、HTML用来展示数据给用户
4. Controller:用来接收用户的请求,整个流程的控制器。用来进行数据校验等。

第二章:SpringMVC的入门案例

####2.1 SpringMVC的概述(查看大纲文档)

#####2.1.1 SpringMVC的概述
1. 是一种基于Java实现的MVC设计模型的请求驱动类型的轻量级WEB框架。
2. Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。
3. 使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的SpringMVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts2等。
4. SpringMVC在三层架构中的位置
1. 表现层框架
5. SpringMVC的优势
1. 清晰的角色划分:控制器(controller)、验证器(validator)、命令对象(command obect)、表单对象(form object)、模型对象(model object)、Servlet分发器(DispatcherServlet)、处理器映射(handler mapping)、试图解析器(view resoler)等等。每一个角色都可以由一个专门的对象来实现。

 	2. 强大而直接的配置方式:将框架类和应用程序类都能作为JavaBean配置,支持跨多个context的引用,例如,在web控制器中对业务对象和验证器validator)的引用。

	3. 可适配、非侵入:可以根据不同的应用场景,选择何事的控制器子类(simple型、command型、from型、wizard型、multi-action型或者自定义),而不是一个单一控制器(比如Action/ActionForm)继承。

	4. 可重用的业务代码:可以使用现有的业务对象作为命令或表单对象,而不需要去扩展某个特定框架的基类。

	5. 可定制的绑定(binding)和验证(validation):比如将类型不匹配作为应用级的验证错误,这可以保证错误的值。再比如本地化的日期和数字绑定等等。在其他某些框架中,你只能使用字符串表单对象,需要手动解析它并转换到业务对象。

	6. 可定制的handler mapping和view resolution:Spring提供从最简单的URL映射,到复杂的、专用的定制策略。与某些web MVC框架强制开发人员使用单一特定技术相比,Spring显得更加灵活。

	7. 灵活的model转换:在Springweb框架中,使用基于Map的键/值对来达到轻易的与各种视图技术集成。

	8. 可定制的本地化和主题(theme)解析:支持在JSP中可选择地使用Spring标签库、支持JSTL、支持Velocity(不需要额外的中间层)等等。

	9. 简单而强大的JSP标签库(Spring Tag Library):支持包括诸如数据绑定和主题(theme)之类的许多功能。他提供在标记方面的最大灵活性。

	10. JSP表单标签库:在Spring2.0中引入的表单标签库,使用在JSP编写表单更加容易。

	11. Spring Bean的生命周期可以被限制在当前的HTTp Request或者HTTp Session。准确的说,这并非Spring MVC框架本身特性,而应归属于Spring MVC使用的WebApplicationContext容器。
	
6. SpringMVC和Struts2框架的对比
	1、Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上SpringMVC就容易实现restful url,而struts2的架构实现起来要费劲,因为Struts2中Action的一个方法可以对应一个url,而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。

	2、由上边原因,SpringMVC的方法之间基本上独立的,独享request response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架,方法之间不共享变量,而Struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码 读程序时带来麻烦,每次来了请求就创建一个Action,一个Action对象对应一个request上下文。
3、由于Struts2需要针对每个request进行封装,把request,session等servlet生命周期的变量封装成一个一个Map,供给每个Action使用,并保证线程安全,所以在原则上,是比较耗费内存的。

	4、 拦截器实现机制上,Struts2有以自己的interceptor机制,SpringMVC用的是独立的AOP方式,这样导致Struts2的配置文件量还是比SpringMVC大。

	5、SpringMVC的入口是servlet,而Struts2是filter(这里要指出,filter和servlet是不同的。以前认为filter是servlet的一种特殊),这就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。

	6、SpringMVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可,而Struts2拦截器集成了Ajax,在Action中处理时一般必须安装插件或者自己写代码集成进去,使用起来也相对不方便。

	7、SpringMVC验证支持JSR303,处理起来相对更加灵活方便,而Struts2验证比较繁琐,感觉太烦乱。

	8、Spring MVC和Spring是无缝的。从这个项目的管理和安全上也比Struts2高(当然Struts2也可以通过不同的目录结构和相关配置做到SpringMVC一样的效果,但是需要xml配置的地方不少)。

	9、 设计思想上,Struts2更加符合OOP的编程思想, SpringMVC就比较谨慎,在servlet上扩展。

	10、SpringMVC开发效率和性能高于Struts2。
	11、SpringMVC可以认为已经100%零配置。 

####2.2 SpringMVC的入门程序

#####2.2.1 创建WEB工程,引入开发的jar包

######2.2.1.1 具体的坐标如下


<spring.version>5.0.2.RELEASE</spring.version>

<dependencies>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
		<version>${spring.version}</version>
	</dependency>

	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-web</artifactId>
		<version>${spring.version}</version>
	</dependency>

	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
		<version>${spring.version}</version>
	</dependency>

	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>servlet-api</artifactId>
		<version>2.5</version>
		<scope>provided</scope>
	</dependency>

	<dependency>
		<groupId>javax.servlet.jsp</groupId>
		<artifactId>jsp-api</artifactId>
		<version>2.0</version>
		<scope>provided</scope>
	</dependency>
</dependencies>

<build>
    <plugins>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <!--端口号-->
          <port>8833</port>
          <!--path就相当于部署项目时候的ContextPath-->
          <path>/</path>
        </configuration>
      </plugin>
    </plugins>
  </build>

#####2.2.2 配置核心的控制器(配置DispatcherServlet)

######2.2.2.1 在web.xml配置文件中核心控制器DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?>

    <!-- SpringMVC的核心控制器 -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!-- 配置servlet启动时加载对象 -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

#####2.2.3 编写springmvc.xml的配置文件
<?xml version="1.0" encoding="UTF-8"?>

    <!-- 配置spring创建容器时要扫描的包 -->
    <context:component-scan base-package="com.gavin"></context:component-scan>
    
    <!-- 配置spring开启注解mvc的支持-->
    <mvc:annotation-driven></mvc:annotation-driven>
    
    <!-- 配置视图解析器 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

#####2.2.4 编写index.jsp和HelloController控制器类

######2.2.4.1 index.jsp

  <body>
  	<h3>入门案例</h3>
  	<a href="${ pageContext.request.contextPath }/hello">入门案例</a>
  </body>

######2.2.4.2 HelloController
package com.gavin.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
/**
* 接收请求
* @return
*/
@RequestMapping(path=“/hello”)
public String sayHello() {
System.out.println(“Hello SpringMVC!!”);
return “success”;
}
}

#####2.2.5 在WEB-INF目录下创建pages文件夹,编写success.jsp的成功页面

入门成功!!


#####2.2.6 启动Tomcat服务器,进行测试
输入访问地址 http://localhost:8585/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AHPKmL7d-1574262890495)(img/tu01.png)]

点击入门案例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c88MaCdr-1574262890496)(img/tu02.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pYm5RN3Z-1574262890497)(img/tu03.png)]

SpringMvc入门程序的步骤总结
  1. 在web.xml中配置核心控制器
    1. 配置DispatcherServlet
    2. 配置初始化参数contextConfigLocation,指定参数值为要加载的spring配置文件的类路径
    3. 通过load-on-startup标签,配置DispatcherServlet在服务器启动的时候加载
  2. 创建一个springmvc的配置文件
    1. 开启包扫描
    2. 运行springmvc的注解
    3. 配置视图解析器
  3. 创建一个控制器
    1. 给控制器上添加Controller注解
    2. 给要访问的控制器的方法上添加RequestMapping注解用于指定映射路径

####2.3 入门案例的执行过程分析

#####2.3.1 入门案例的执行流程
1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象,就会加载springmvc.xml配置文件
2. 开启了注解扫描,那么HelloController对象就会被创建
3. 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解找到执行的具体方法
4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
5. Tomcat服务器渲染页面,做出响应

#####2.3.2 SpringMVC官方提供图形
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NbWCBItA-1574262890498)(img/tu04.png)]

#####2.3.3 入门案例中的组件分析
1. 前端控制器(DispatcherServlet)
1. 在服务器启动的时候创建,并且加载spring的配置文件
2. 分发请求,去查找对应的映射处理器
2. 处理器映射器(HandlerMapping)
1. 根据映射路径找到对应的处理器
3. 处理器(Handler)
1. 处理请求
4. 处理器适配器(HandlAdapter)
5. 视图解析器(View Resolver)
1. 找到对应的视图
6. 视图(View)
1. 渲染界面

####2.4 RequestMapping注解
源码:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}

#####2.4.1 RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系

	出现位置:
	类上:
	请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。 写的话需要以/开头。
	它出现的目的是为了使我们的 URL 可以按照模块化管理:
	例如:
	账户模块:
	/account/add
	/account/update
	/account/delete
	...
	订单模块:
	/order/add
	/order/update
	/order/delete
	红色的部分就是把 RequsetMappding 写在类上,使我们的 URL 更加精细。
	方法上:
	请求 URL 的第二级访问目录。

#####2.4.2 RequestMapping注解可以作用在方法和类上
1. 作用在类上:第一级的访问目录
2. 作用在方法上:第二级的访问目录
3. 细节:路径可以不编写 / 表示应用的根目录开始

	案例:处理的请求路径是   http://localhost:8085/hello/say
	@Controller
	@RequestMapping(value = "/hello")
	public class HelloController {
	    /**
	     * 接收请求
	     * @return
	     */
	    @RequestMapping(value = "/say")
	    public String sayHello() {
	        System.out.println("Hello SpringMVC!!");
	        return "success";
	    }
	}

#####2.4.3 RequestMapping的属性

  1. path 指定请求路径的url
在HelloController方法上加了@RequestMapping(path="/hello"),而sayHello方法上加了@RequestMapping(path="/say"),此时用户可以直接访问  http://localhost:8085/hello/say 来访问该方法.
	
	@Controller
	@RequestMapping(path = "/hello")
	public class HelloController {
	    /**
	     * 此时用户访问此方法路径为 http://localhost:8085/hello/say
	     * @return
	     */
	    @RequestMapping(value = "/say")
	    public String sayHello() {
	        System.out.println("Hello SpringMVC!!");
	        return "success";
	    }
	}
  1. value value属性和path属性是一样的
把上述方法中的path换成value即可,用户可以直接访问  http://localhost:8085/hello/say 来访问该方法。


	@Controller
	@RequestMapping(value = "/hello")
	public class HelloController {
	    /**
	     * 此时用户访问此方法路径为 http://localhost:8085/hello/say
	     * @return
	     */
	    @RequestMapping(value = "/say")
	    public String sayHello() {
	        System.out.println("Hello SpringMVC!!");
	        return "success";
	    }
	}
  1. mthod 指定该方法的请求方式
我们这里写了sayHello()和sayYourName()2个方法,但他们请求路径相同,而method属性的值不一样,如果是RequestMethod.GET,则只能以方式请求,如果是RequestMethod.POST则只能以POST方式请求。

	@Controller
	@RequestMapping(value = "/hello")
	public class HelloController {
	    /**
	     * 加了method = RequestMethod.GET
	     * 此时此方法只接收 http://localhost:8085/hello/say 的GET提交方式请求
	     * @return
	     */
	    @RequestMapping(value = "/say",method = RequestMethod.GET)
	    public String sayHello() {
	        System.out.println("Hello SpringMVC!!调用了GET方法");
	        return "success";
	    }
	
	    /**
	     * 加了method = RequestMethod.POST
	     * 此时此方法只接收 http://localhost:8085/hello/say 的POST提交方式请求
	     * @return
	     */
	    @RequestMapping(value = "/say",method = RequestMethod.POST)
	    public String sayYourName() {
	        System.out.println("Hello SpringMVC!!调用了POST方法");
	        return "success";
	    }
	}
  1. params 指定限制请求参数的条件(了解)

    params用的比较少,这里不做要求掌握。
    param1: 表示请求必须包含名为 param1 的请求参数
    !param1: 表示请求不能包含名为 param1 的请求参数
    param1 != value1: 表示请求包含名为 param1 的请求参数,但其值不能为 value1
    {“param1=value1”, “param2”}: 请求必须包含名为 param1 和param2 的两个请求参数,且 param1 参数的值必须为 value1


/**
* params参数:
* “name”:表示请求必须包含name参数
* “!age”:表示请求不能包含age参数
* “address!=usa”:表示请求中address参数的值不能为usa
* “working=sz”:表示请求参数中的working参数必须为sz
* @return
*/
@RequestMapping(params = {“name”,“!age”,“address!=usa”,“working=sz”},
value = “/say”,method = RequestMethod.GET)
public String sayHello() {
System.out.println(“Hello SpringMVC!!调用了GET方法”);
return “success”;
}

  1. headers 发送的请求中必须包含的请求头(了解)

    headers用的比较少,这里不做要求掌握。
    param1: 表示请求头必须包含名为 param1 的请求头信息
    !param1: 表示请求头不能包含名为 param1 的请求头信息
    param1 != value1: 表示请求头包含名为 param1 的请求头信息,但其值不能为 value1
    {“param1=value1”, “param2”}: 请求必头须包含头信息 param1 和param2的两个请求头信息 ,且 param1 的值必须为 value1

    /**
     * headers参数:
     *      "Accept":表示请求头必须包含Accept头信息
     *      "!Date":表示请求头中不能包含Date的头信息
     *      "Accept-Encoding!=zh-CN":表示请求头中Accept-Encoding头信息的值不能为zh-CN
     *      "Host=localhost:18081":表示请求头中Host的值必须为localhost:18081
     * @return
     */
    @RequestMapping(headers = {"Accept","!Date","Accept-Encoding!=zh-CN","Host=localhost:18081"},
                    value = "/say",method = RequestMethod.GET)
    public String sayHello() {
        System.out.println("Hello SpringMVC!!调用了GET方法");
        return "success";
    }
    

第三章:请求参数的绑定

####3.1 请求参数的绑定说明

  1. 绑定机制

    1. 表单提交的数据都是k=v格式的 username=haha&password=123
    2. SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
    3. 要求:提交表单的name和参数的名称是相同的
  2. 支持的数据类型

    1). 基本数据类型和字符串类型

      @Controller
      @RequestMapping(value = "/user")
      public class UserController {
      
          /***
           * 接收基本数据类型和String
           * 此时可以访问 http://localhost:18081/user/add?id=9&name=Gavin
           * 注意:此时请求地址的id和name和addUser(int id,String name)中的入参名字要一致才能接到参数。
           * @return
           */
          @RequestMapping(value = "/add")
          public String addUser(int id,String name){
              System.out.println("ID:"+id+",NAME:"+name);
              return "success";
          }
      }
    

    2). 实体类型(JavaBean)

      2.1)创建User实体Bean
    
      public class User {
          private String name;
          private Integer age;
      	//get...set...
      }
    
      2.2)修改addUser方法
      @Controller
      @RequestMapping(value = "/user")
      public class UserController {
      
          /***
           * 这里直接接收一个User 对象即可
           * 注意:
           *      页面表单需要和user对应的属性名字一致
           *      姓名:<input name="name" />  name="name"和User的name属性名一样
           *      年龄:<input name="age" />  name="age"和User的age属性名一样
           * @return
           */
          @RequestMapping(value = "/add")
          public String addUser(User user){
              System.out.println("AGE:"+user.getAge()+",NAME:"+user.getName());
              return "success";
          }
      }
    
      2.3)创建index.jsp,在index.jsp中加入如下表单
      <form action="/user/add" method="post">
          <div>
              名字:<input name="name" >
          </div>
          <div>
              年龄:<input name="age" >
          </div>
          <div>
              <input type="submit" value="提交">
          </div>
      </form>
    

    3). 集合数据类型(List、map集合等)

3.1).接收Map数据

	在上面案例中,修改addUser方法,注意需要加上一个注解@RequestParam来接收Map数据
	
	@Controller
	@RequestMapping(value = "/user")
	public class UserController {
	    /***
	     * 接收Map
	     * @return
	     */
	    @RequestMapping(value = "/add")
	    public String addUser(@RequestParam Map userMap){
	        System.out.println(userMap);
	        return "success";
	    }
	}

3.2)接收List
	
在上面案例中,把addUser方法修改一下,注意需要加上一个注解@RequestParam来接收List数据

	@Controller
	@RequestMapping(value = "/user")
	public class UserController {
	    /***
	     * 接收List
	     *      注意:接收List,需要在方法中加入注解@RequestParam
	     *            一会儿页面传过来的表单参数名字也要和方法名字id一致
	     *            例如:
	     *                  ID1:<input name="id">
	     *                  ID2:<input name="id">
	     *                  ID3:<input name="id">
	     * @return
	     */
	    @RequestMapping(value = "/add")
	    public String addUser(@RequestParam List<Integer> id){
	        System.out.println(id);
	        return "success";
	    }
	}

修改index.jsp表单

	<form action="/user/add">
	    <div>
	        ID1:<input name="id" >
	    </div>
	    <div>
	        ID2:<input name="id" >
	    </div>
	    <div>
	        ID3:<input name="id" >
	    </div>
	    <div>
	        <input type="submit" value="提交">
	    </div>
	</form>

####3.2 入参参数总结

  1. 提交表单的name和参数的名称是相同的
  2. 如果接收JavaBean则必须和JavaBean的属性名相同
  3. 区分大小写
  4. 如果将参数封装到Map或者是List中,必须在方法的参数前添加@RequestParam注解

####3.3 实体引用类型(JavaBean)
比如现在有一个User对象,它里面有个属性IdCard,也可以直接接收,只需要页面表单的名字和JavaBean属性名字保持一致即可。

#####3.3.1 定义JavaBean
创建IdCard
public class IdCard {
//身份证号
private String number;
//身份证地址
private String address;

    //get..set..
}

修改User
public class User {
    private String name;
    private Integer age;
    //引用IdCard作为子属性
    private IdCard idCard;
	
	//get.. set..
}

修改addUser方法
@Controller
@RequestMapping(value = "/user")
public class UserController {
    /***
     * 接收引用JavaBean
     *      注意:页面填充表单的时候,name的值仍然要和后台接收的JavaBean的属性名一样。
     *            但如果有引用属性填充,就写[引用属性名].[引用属性自身对应属性名]
     *      例如:
     *          身份证号:<input name="idCard.number" >
     *          地址:<input name="idCard.address" >
     *
     * @return
     */
    @RequestMapping(value = "/add")
    public String addUser(User user){
        System.out.println("用户" + user.getName() + "今年" + user.getAge() + "岁,住在" + user.getIdCard().getAddress() + ",身份证号是" + user.getIdCard().getNumber());
        return "success";
    }
}


修改index.jsp的表单
<form action="/user/add">
    <div>
        名字:<input name="name" >
    </div>
    <div>
        年龄:<input name="age" >
    </div>
    <div>
        身份证号:<input name="idCard.number" >
    </div>
    <div>
        地址:<input name="idCard.address" >
    </div>
    <div>
        <input type="submit" value="提交">
    </div>
</form>

####3.4 给JavaBean集合属性数据封装
如果JavaBean有集合属性,JSP页面编写方式:list[0].属性

我们在上面案例基础上添加一个Mobile对象,再在User中添加一个集合属性List mobiles属性。

#####3.4.1 创建Mobile并修改User
我们保持addUser方法不变,只修改JavaBean和页面即可。

创建Mobile
public class Mobile {
    //手机名字
    private String mobileName;
    //手机价格
    private Float price;
    //get..set..
}

修改User
public class User {
    private String name;
    private Integer age;
    //引用IdCard作为子属性
    private IdCard idCard;
    //一个人买了多个手机
    private List<Mobile> mobiles;

	//get.. set..
}

addUser方法不变,我们可以打印一些信息
@Controller
@RequestMapping(value = "/user")
public class UserController {
    /***
     * 接收引用JavaBean
     *      注意:页面填充表单的时候,name的值仍然要和后台接收的JavaBean的属性名一样。
     *            但如果有引用属性填充,就写[引用属性名].[引用属性自身对应属性名]
     *      例如:
     *          身份证号:<input name="idCard.number" >
     *          地址:<input name="idCard.address" >
     *
     * 接收的JavaBean里如果存在List集合,则页面需要每次用下标来告诉程序是第几个,其他的用法和单个JavaBean用法一样
     *      例如:
     *          第1个手机名字:<input name="mobiles[0].mobileName" >
     *          第1个手机价格:<input name="mobiles[0].price" >
     *
     *          第2个手机名字:<input name="mobiles[1].mobileName" >
     *          第2个手机价格:<input name="mobiles[1].price" >
     * @return
     */
    @RequestMapping(value = "/add")
    public String addUser(User user){
        System.out.println("用户" + user.getName() + "今年" + user.getAge() + "岁,住在" + user.getIdCard().getAddress() + ",身份证号是" + user.getIdCard().getNumber());
        for (Mobile mobile : user.getMobiles()) {
            System.out.println(mobile.getMobileName()+"花了"+mobile.getPrice());
        }
        return "success";
    }
}

修改index.jsp的表单
<form action="/user/add">
    <div>
        名字:<input name="name" >
    </div>
    <div>
        年龄:<input name="age" >
    </div>
    <div>
        身份证号:<input name="idCard.number" >
    </div>
    <div>
        地址:<input name="idCard.address" >
    </div>

    <div>
        第1个手机名字:<input name="mobiles[0].mobileName" >
    </div>
    <div>
        第1个手机价格:<input name="mobiles[0].price" >
    </div>
    <div>
        第2个手机名字:<input name="mobiles[1].mobileName" >
    </div>
    <div>
        第2个手机价格:<input name="mobiles[1].price" >
    </div>
    <div>
        <input type="submit" value="提交">
    </div>
</form>

####3.5 请求参数POST请求中文乱码的解决
在web.xml中配置Spring提供的过滤器类

<!-- 配置过滤器,解决中文乱码的问题 -->
<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>

请求参数部分的小结:

  1. 获取简单类型的请求参数,那么我们生命在方法中的参数名要和请求参数名一致
  2. 获取请求 参数封装到JavaBean对象中,那么我们声明处理请求的方法中的参数类型为JavaBean类型,要求JavaBean的属性名要和请求参数的参数名一致
  3. 获取请求参数封装到JavaBean的List集合中,要求请求参数名应该是"集合的属性名[下标].JavaBean的属性名"
  4. 解决POST请求参数的中文乱码问题,我们要配置一个CharacterEncodingFilter过滤器,并且通过init-param标签指定初始化参数"encoding"

####3.6 自定义类型转换器

表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明Spring框架内部会默认进行数据类型转换。但Date类型并不能实现转换,需要我们手动解决。

如果想自定义数据类型转换,可以实现Converter的接口

自定义类型转换器
package com.gavin.util;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateConverter implements Converter<String,Date>{
    /***
     * 将String类型转成Date类型
     * @param str
     * @return
     */
    public Date convert(String str) {
        try {
            //定义一个时间转换工具对象
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            //将字符串转Date并返回
            return simpleDateFormat.parse(str);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}



注册自定义类型转换器,在springmvc.xml配置文件中编写配置
<!-- 配置spring开启注解mvc的支持-->
<mvc:annotation-driven conversion-service="conversionService" />

<!--
    注册自定义类型转换器
-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <bean class="com.gavin.util.DateConverter" />
    </property>
</bean>

自定义类型转换的小结:

  1. 可以使用Spring内置的DateTimeFormate注解进行日期类型的转换

    1. 给要转换的变量,添加DateTimeFormate注解
    2. 给注解添加pattern属性,指定转换规则
  2. 自己编写类型转换器,将String转换成Date

    1. 写一个类实现Converter接口,并且重写convert,在方法中编写转换规则

    2. 在spring的配置文件中配置自定义类型转换器

      <!--配置使用类型转换器-->
          <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
              <property name="converters">
                  <bean id="dateConverter" class="com.gavin.converter.DateConverter"></bean>
              </property>
          </bean>
      
    3. 在开启MVC注解驱动的地方,注册类型转换服务

      <mvc:annotation-driven conversion-service="conversionService"/>
      

####3.7 在控制器中使用原生的ServletAPI对象

只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象

第四章:常用的注解

####4.1 RequestParam注解(了解)
作用:把请求中的指定名称的参数传递给控制器中的形参赋值
属性
value:请求参数中的名称
required:请求参数中是否必须提供此参数,默认值是true,必须提供

代码如下
/**
 * 接收请求
 * @return
 */
@RequestMapping(path="/hello")
public String sayHello(@RequestParam(value="username",required=false)String name) {
	System.out.println("aaaa");
	System.out.println(name);
	return "success";
}

####4.2 RequestBody注解
作用:用于获取请求体的内容(注意:get方法不可以)
属性
required:是否必须有请求体,默认值是true

代码如下
/**
 * 接收请求
 * @return
 */
@RequestMapping(path="/hello")
public String sayHello(@RequestBody String body) {
	System.out.println("aaaa");
	System.out.println(body);
	return "success";
}

####4.3 PathVariable注解
作用:拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符
属性
value:指定url中的占位符名称

Restful风格的URL
	1.使用通用的协议,比如说Http
	2.url中使用小写字母,不要使用大写字母
	3.url中使用下划线,不要使用中划线
	4.一个路径就代表一个资源
	请求路径一样,可以根据不同的请求方式去执行后台的不同方法
	restful风格的URL优点
        结构清晰
        符合标准
        易于理解
        扩展方便

####4.4 PathVariable案例代码如下
入门案例

/**
 * 接收请求
 * @return
 */
@RequestMapping(path="/hello/{id}")
public String sayHello(@PathVariable(value="id") String id) {
	System.out.println(id);
	return "success";
}	

####4.5 RequestHeader注解(了解)
作用:获取指定请求头的值
属性
value:请求头的名称

   代码如下

  @RequestMapping(path="/hello")
  public String sayHello(@RequestHeader(value="Accept") String header) {
  	System.out.println(header);
  	return "success";
  }

####4.6 CookieValue注解(了解)
作用:用于获取指定cookie的名称的值
属性
value:cookie的名称
代码
@RequestMapping(path=“/hello”)
public String sayHello(@CookieValue(value=“JSESSIONID”) String cookieValue) {
System.out.println(cookieValue);
return “success”;
}

####4.7 ModelAttribute注解(了解)
作用
出现在方法上:表示当前方法会在控制器方法执行前先执行。
出现在参数上:获取指定的数据给参数赋值。
应用场景
当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
具体的代码

根据用户提交的数据修改用户信息,id、username、password、nickname、address
而用户只提交了id、username、password
所以为了避免在修改的时候,将nickname和address改成null,我们应该在修改之前先查询到用户信息

#####4.7.1 修饰的方法有返回值

在上面的案例基础之上,给User中添加一个sex属性,再到UserController中添加一个parameterUser()方法,并创建User再赋值返回,方法上加上注解@ModelAttribute注解。

@Controller
@RequestMapping(value = "/user")
public class UserController {
    /***
     * 优先执行
     * @return
     */
    @ModelAttribute
    public User parameterUser(){
        User user = new User();
        user.setSex("男");
        return user;
    }

    /***
     * 此时的user已经被上面的parameterUser先执行了修改,已经给sex赋值
     */
    @RequestMapping(value = "/add")
    public String addUser(User user){
        System.out.println("用户" + user.getName() +",性别:"+user.getSex()+","+ "今年" + user.getAge() + "岁,住在" + user.getIdCard().getAddress() + ",身份证号是" + user.getIdCard().getNumber());
        for (Mobile mobile : user.getMobiles()) {
            System.out.println(mobile.getMobileName()+"花了"+mobile.getPrice());
        }
        return "success";
    }
}

#####4.7.2 修饰的方法没有返回值
在上面案例基础上,把parameterUser的返回值去掉,增加一个Map来存储数据,存储的key为user,在addUser中使用@ModelAttribute(“user”)User user获取在parameterUser()方法中赋值的数据。程序运行后,我们发现addUser方法的user参数能取到parameterUser方法赋值的数据。

@Controller
@RequestMapping(value = "/user")
public class UserController {
    /***
     * 优先执行
     * @return
     */
    @ModelAttribute
    public void parameterUser(Map<String,User> userMap){
        User user = new User();
        user.setSex("男");
        userMap.put("user",user);
    }

    /***
     * 此时的user已经被上面的parameterUser先执行了修改,已经给sex赋值
     */
    @RequestMapping(value = "/add")
    public String addUser(@ModelAttribute("user")User user){
        System.out.println("用户" + user.getName() +",性别:"+user.getSex()+","+ "今年" + user.getAge() + "岁,住在" + user.getIdCard().getAddress() + ",身份证号是" + user.getIdCard().getNumber());
        for (Mobile mobile : user.getMobiles()) {
            System.out.println(mobile.getMobileName()+"花了"+mobile.getPrice());
        }
        return "success";
    }
}

####4.8 Model使用(有点重要)
SpringMVC会把Model(模型信息)中的的数据放入到request域对象中,页面可以通过EL表达式来取request域中的数据。我们可以先写一个案例,在后台使用Model的addAttribute方法,页面使用EL表达式取数据。

创建	ModelController
@Controller
@RequestMapping(value = "/model")
public class ModelController {

    /***
     * Model的使用
     * @param model
     * @return
     */
    @RequestMapping(value = "/add")
    public String add(Model model){
        model.addAttribute("msg","张三");
        return "success";
    }
}

success.jsp页面从request域中取数据
${requestScopr.msg}

####4.9 SessionAttributes注解

作用:用于多次执行控制器方法间的参数共享
	属性
	value:指定存入属性的名称

代码如下
@Controller
@RequestMapping(path="/user")
@SessionAttributes(value= {"username","password","age"},types= {String.class,Integer.class})		// 把数据存入到session域对象中
public class HelloController {
	
	/**
	 * 向session中存入值
	 * @return
	 */
	@RequestMapping(path="/save")
	public String save(Model model) {
		System.out.println("向session域中保存数据");
		model.addAttribute("username", "root");
		model.addAttribute("password", "123");
		model.addAttribute("age", 20);
		return "success";
	}
	
	/**
	 * 从session中获取值
	 * @return
	 */
	@RequestMapping(path="/find")
	public String find(ModelMap modelMap) {
		String username = (String) modelMap.get("username");
		String password = (String) modelMap.get("password");
		Integer age = (Integer) modelMap.get("age");
		System.out.println(username + " : "+password +" : "+age);
		return "success";
	}
	
	/**
	 * 清除值
	 * @return
	 */
	@RequestMapping(path="/delete")
	public String delete(SessionStatus status) {
		status.setComplete();
		return "success";
	}

}


     ​

课程总结

  1. SpringMVC的概述
  2. 入门
    1. 创建工程,导入坐标
    2. 在web.xml中配置前端控制器(启动服务器,加载springmvc.xml配置文件)
    3. 编写springmvc.xml配置文件
    4. 编写index.jsp的页面,发送请求
    5. 编写Controller类,编写方法(@RequestMapping(path=“/hello”)),处理请求
    6. 编写配置文件(开启注解扫描),配置视图解析器
    7. 执行的流程
    8. @RequestMapping注解
      1. path
      2. value
      3. method
  3. 参数绑定
    1. 参数绑定必须会
    2. 解决中文乱码,配置过滤器
    3. 自定义数据类型转换器

ssword", “123”);
model.addAttribute(“age”, 20);
return “success”;
}

	/**
	 * 从session中获取值
	 * @return
	 */
	@RequestMapping(path="/find")
	public String find(ModelMap modelMap) {
		String username = (String) modelMap.get("username");
		String password = (String) modelMap.get("password");
		Integer age = (Integer) modelMap.get("age");
		System.out.println(username + " : "+password +" : "+age);
		return "success";
	}
	
	/**
	 * 清除值
	 * @return
	 */
	@RequestMapping(path="/delete")
	public String delete(SessionStatus status) {
		status.setComplete();
		return "success";
	}

}


     ​

课程总结

  1. SpringMVC的概述
  2. 入门
    1. 创建工程,导入坐标
    2. 在web.xml中配置前端控制器(启动服务器,加载springmvc.xml配置文件)
    3. 编写springmvc.xml配置文件
    4. 编写index.jsp的页面,发送请求
    5. 编写Controller类,编写方法(@RequestMapping(path=“/hello”)),处理请求
    6. 编写配置文件(开启注解扫描),配置视图解析器
    7. 执行的流程
    8. @RequestMapping注解
      1. path
      2. value
      3. method
  3. 参数绑定
    1. 参数绑定必须会
    2. 解决中文乱码,配置过滤器
    3. 自定义数据类型转换器
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值