SpringMVC简介与入门教程

😂 这篇文章最后更新于1712天前,您需要注意相关的内容是否还可用。
目录导航
  • SpringMVC简介
  • SpringMVC配置
    • 坐标依赖
    • web.xml
    • springmvc.xml配置文件
      • <mvc:annotation-driven />解析
      • 小流程
  • 常用注解
    • @RequestMapping
    • @RequestParam
    • @RequestBody
    • @PathVariable
      • Restful风格的URL
    • @RequestHeader
    • @CookieValue
    • @ModelAttribute
    • @SessionAttributes
  • 参数绑定
  • 过滤器解决中文乱码
    • Get情况下乱码
    • Post情况下乱码
  • HiddentHttpMethodFilter
  • SpringMVC简介

    SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring

    FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。


    SpringMVC优势:

    1、清晰的角色划分:
    前端控制器(DispatcherServlet)
    请求到处理器映射(HandlerMapping)
    处理器适配器(HandlerAdapter)
    视图解析器(ViewResolver)
    处理器或页面控制器(Controller)
    验证器( Validator)
    命令对象(Command 请求参数绑定到的对象就叫命令对象)
    表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
    2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。
    3、由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。
    4、和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。
    5、可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。
    6、可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制。
    7、功能强大的数据验证、格式化、绑定机制。
    8、利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。
    9、本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
    10、强大的 JSP 标签库,使 JSP 编写更容易。
    ………………还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配
    置支持等等。

    SpringMVC配置

    坐标依赖

     <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.0.2.RELEASE</spring.version>
      </properties>
    
      <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>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
      </dependencies>

    web.xml

    <web-app>
        <display-name>Archetype Created Web Application</display-name>
        <!--  配置前端控制器servlet跟mapping-->
        <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>

    springmvc.xml配置文件

    该xml文件名称可自定义,需要在web.xml中指定,详见上方web.xml配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:context="http://www.springframework.org/schema/context"
           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.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
        <!--    配置所需要的名称空间后 配置注解扫描-->
        <context:component-scan base-package="com.cheng"></context:component-scan>
        <!-- 配置视图解析器 -->
        <bean id="viewResolver"
              class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <!--        配置视图解析器解析的前缀目录-->
            <property name="prefix" value="/WEB-INF/pages/"></property>
            <!--        配置解析的后缀 下列也就是只解析到jsp文件-->
            <property name="suffix" value=".jsp"></property>
        </bean>
        <!--    配置spring开启注解mvc的支持 该注解包含SpringMVC中的其他处理器-->
        <mvc:annotation-driven></mvc:annotation-driven>
    </beans>

    <mvc:annotation-driven />解析

    用  自动加载 RequestMappingHandlerMapping(处理映射器)和RequestMappingHandlerAdapter ( 处理适配器 ),如果不使用这种写法,可以使用下列配置,下载配置其实就是细化,可让你根据适合场景使用适合的处理器,而非全部加载。

        <!-- Begin -->
        <!-- HandlerMapping -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
        <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
        <!-- HandlerAdapter -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
        <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
        <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
        <!-- HadnlerExceptionResolvers -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>
        <bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"></bean>
        <bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"></bean>
        <!-- End -->

    小流程

    启动Tomcat->加载web.xml->由于配置load-on-startup启动即创建前端控制器->加载springmvc.xml->开启注解扫描->扫描@Controller注解的类创建对象

    前端jsp页面发请求->到前端控制器->根据@RequestMapping找具体方法执行->根据方法返回结果->根据视图解析器->查找指定的页面->Tomcat渲染页面->响应给页面

    常用注解

    @RequestMapping

    作用:建立请求URL与方法之间对应关系。

    写法:可以写在类与方法上,value值为 / 表示根目录

    属性:

    1. path/value  指定请求路径的url 例:@RequestMapping(path ="/hello")、@RequestMapping(value="/hello") 其中如果只有value一个属性的话可以省略不写,即@RequestMapping("/hello")

    2. mthod 指定该方法的请求方式

      @RequestMapping(value="/saveAccount",method=RequestMethod.POST)
      可以配置多种方式,在{}中写
    3. params 指定限制请求参数的条件

      RequestMapping(value="/remove",params= {"accountName","money>100"})
      //限制传来参数中必须有accountName、money参数,money还需要>100
    4. headers 发送的请求中必须包含的请求头

      RequestMapping(value="/remove",header= {"Accept"})
      //限制header中必须有Accept

    在jsp中可以采用绝对与相对URL访问mapping

    <a href="${pageContext.request.contextPath}/account/findAccount">绝对</a>
    <a href="account/findAccount">相对</a>
    ${pageContext.request.contextPath}取的是虚拟目录的名称

    @RequestParam

    与前台传递参数不一致,用它进行与形参关联,例如下列前台传的参数username,但后台必须用name时

    public String sayHello(@RequestParam(value="username",required=false)String name) {}

    @RequestBody

    用于获取请求体的内容(注意:get方法不适用,适用于post或ajax异步请求)

    required:是否必须有请求体,默认值是true

    public String sayHello(@RequestBody String body) {}

    @PathVariable

    拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符

    <a href="user/hello/1">入门案例</a>
    /**
    * 接收请求
    * @return
    */
    @RequestMapping(path="/hello/{id}")
    public String sayHello(@PathVariable(value="id") String id) {
    	System.out.println(id);
    	return "success";
    }

    Restful风格的URL

    1. 请求路径一样,可以根据不同的请求方式去执行后台的不同方法

    2. restful风格的URL优点

      1. 结构清晰

      2. 符合标准

      3. 易于理解

      4. 扩展方便

    @RequestHeader

    获取指定请求头的值

    public String sayHello(@RequestHeader(value="Accept") String header) {}

    @CookieValue

    获取指定cookie的名称的值

    @RequestMapping(path="/hello")
    public String sayHello(@CookieValue(value="JSESSIONID") String cookieValue) {
    	System.out.println(cookieValue);
    	return "success";
    }

    @ModelAttribute

    1. 出现在方法上:表示当前方法会在控制器方法执行前线执行。

    2. 出现在参数上:获取指定的数据给参数赋值。

    应用场景:当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。

        /**
         *假设User对象中有name跟password字段,前端只传了name
         * 要知道password 第一种在该Controller中写读数据库操作
         * 第二种在@ModelAttribute修饰的方法中写数据库操作 因为它优先执行
         */
        @RequestMapping(path = "/updateUser")
        public String updateUser(User user) {
            System.out.println(user);
            return "success";
        }
    
        /**
         * 作用在方法,先执行
         * 通过前端传的name查询password并返回给user
         */
        @ModelAttribute
        public User showUser(String name) {
            System.out.println("showUser执行了...");
    // 模拟从数据库中查询对象,此处为演示直接设置对象属性
            User user = new User();
            user.setName("哈哈");
            user.setPassword("123");
            return user;
        }

    假设@ModelAttribute修饰的先行方法没返回值怎么办?可在方法参数中加合适类型Map,然后将数据库查询的对象put进去,在需要的Controller方法的参数上再加@ModelAttribute注解把值再赋给user

        @RequestMapping(path = "/updateUser")
        public String updateUser(@ModelAttribute(value = "abc") User user) {
            System.out.println(user);
            return "success";
        }
        
        @ModelAttribute
        public void showUser(String name, Map<String, User> map) {
            System.out.println("showUser执行了...");
    // 模拟从数据库中查询对象
            User user = new User();
            user.setName("哈哈");
            user.setPassword("123");
            map.put("abc", user);
        }

    @SessionAttributes

    用于多次执行控制器方法间的参数共享。只能写在类上。

    @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域中保存数据");
    //        会向Request域中添加数据
    //        加SessionAttributes注解会再次向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) {
    //        ModelMap是Model的实现类,可以取数据
            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) {
    //        将session状态设置为完成则清除session
            status.setComplete();
            return "success";
        }
    }

    参数绑定

    1、传什么接收什么

    <a href="account/findAccount?accountId=10">查询账户</a>
    后端:
    public String findAccount(Integer accountId){}

    2、实体类

    User实体类中有name跟age属性,前台传uname、age,后台用实体类直接接收
    后台:
    public String findAccount(User user){}

    3、关联实体类(类中有类),例如Account类中含User类:

    public class Account implements Serializable{
        private String username;
        private String password;
        private Double money;
        private User user;
        ...
        }

    那它前端就是:

    <form action="param/saveAccount" method="post">
            姓名:<input type="text" name="username" /><br/>
            密码:<input type="text" name="password" /><br/>
            金额:<input type="text" name="money" /><br/>
            用户姓名:<input type="text" name="user.uname" /><br/>
            用户年龄:<input type="text" name="user.age" /><br/>
            <input type="submit" value="提交" />
     </form>

    4、数组和集合类型参数,实体类中包含List于Map

        <form action="param/saveAccount" method="post">
            姓名:<input type="text" name="username" /><br/>
            密码:<input type="text" name="password" /><br/>
            金额:<input type="text" name="money" /><br/>
    
            用户姓名:<input type="text" name="list[0].uname" /><br/>
            用户年龄:<input type="text" name="list[0].age" /><br/>
    
            用户姓名:<input type="text" name="map['one'].uname" /><br/>
            用户年龄:<input type="text" name="map['one'].age" /><br/>
            <input type="submit" value="提交" />
        </form>

    过滤器解决中文乱码

    Get情况下乱码

    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>
             <!-- 启动过滤器 可不加-->
            <init-param>
                <param-name>forceEncoding</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>characterEncodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

    在springmvc.xml中可以配置静态资源不过滤

    <!-- location 表示路径,mapping 表示文件,**表示该目录下的文件以及子目录的文件 -->
    <mvc:resources location="/css/" mapping="/css/**"/>
    <mvc:resources location="/images/" mapping="/images/**"/>
    <mvc:resources location="/scripts/" mapping="/javascript/**"/>

    Post情况下乱码

    tomacat 对 GET 和 POST 请求处理方式是不同的,GET 请求的编码问题,要改 tomcat 的 server.xml
    配置文件,如下:
    <Connector connectionTimeout="20000" port="8080"
    protocol="HTTP/1.1" redirectPort="8443"/>
    改为:
    <Connector connectionTimeout="20000" port="8080"
    protocol="HTTP/1.1" redirectPort="8443"
    useBodyEncodingForURI="true"/>
    如果遇到 ajax 请求仍然乱码,请把:
    useBodyEncodingForURI="true"改为 URIEncoding="UTF-8"

    HiddentHttpMethodFilter

    由于浏览器 form 表单只支持 GET 与 POST 请求,而 DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将浏览器请求改为指定的请求方式,发送给我们的控制器方法,使得支持 GET、POST、PUT  与 DELETE 请求。

    使用方法:

    第一步:在 web.xml 中配置该过滤器。

    第二步:请求方式必须使用 post 请求。

    第三步:按照要求提供_method 请求参数,该参数的取值就是我们需要的请求方式。

     <filter>
            <filter-name>hiddenHttpMethodFilter</filter-name>
            <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>hiddenHttpMethodFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

    此时,前端就要改成如下:

    		<!-- 保存 -->
    		<form action="springmvc/testRestPOST" method="post">
    			用户名称:<input type="text" name="username"><br />
    			<!-- <input type="hidden" name="_method" value="POST"> -->
    			<input type="submit" value="保存">
    		</form>
    		<hr />
    		<!-- 更新 -->
    		<form action="springmvc/testRestPUT/1" method="post">
    			用户名称:<input type="text" name="username"><br />
    			<input type="hidden" name="_method" value="PUT">
    			<input type="submit" value="更新">
    		</form>

    说白了就是在表单中加入了

    <input type="hidden" name="_method" value="PUT">

    持续更新中……