SpringMVC概述和使用入门

概述

SpringMVC的概念

SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring 的 Spring MVC 框架或集成其他 MVC 开发框架,如 Struts1(现在一般不用),Struts2 等。

它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful 编程风格的请求。

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和Struts2的优劣分析

共同点:

  • 它们都是表现层框架,都是基于 MVC 模型编写的。
  • 它们的底层都离不开原始 ServletAPI。
  • 它们处理请求的机制都是一个核心控制器。

区别:

  • Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter
  • Spring MVC 是基于方法设计的,而 Struts2 是基于类,Struts2 每次执行都会创建一个动作类。所以 Spring MVC 会稍微比 Struts2 快些。
  • Spring MVC 使用更加简洁,同时还支持 JSR303, 处理 ajax 的请求更方便
    >(JSR303 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们 JavaBean 的属性上面,就可以在需要校验的时候进行校验了。)
  • Struts2 的 OGNL 表达式使页面的开发效率相比 Spring MVC 更高些,但执行效率并没有比 JSTL 提升,尤其是 struts2 的表单标签,远没有 html 执行效率高。

入门案例

maven配置

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <spring.version>5.2.3.RELEASE</spring.version>
</properties>

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <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>

web.xml配置

<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

DispatcherServlet就是用于分发请求的,这里可以视为过滤器。它配合Controller中的@RequestMapping分发请求。

init-param里面的contextConfigLocation指引springmvc去加载spring配置

Spring配置文件

<?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:mvc="http://www.springframework.org/schema/mvc"
       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-3.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd
      http://www.springframework.org/schema/mvc
      http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    <!--启用组件扫描-->
    <context:component-scan base-package="com.test.controller"/>
    <!--启动SpringMVC的注解功能,完成请求和注解POJO的映射-->
    <mvc:annotation-driven/>
    <!--配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/" />
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

控制类编写

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/showUser")
    public String ShowUser(){
        return "ShowUser";
    }
}

这里的@RequestMapping代表要访问项目目录下的/user/showUser才会被分发到该Controller类

注意返回的字符串配合视图解析器会跳转到/WEB-INF/pages/ShowUser.jsp

入门案例涉及的组件

SpringMVC概述和使用入门

DispatcherServlet

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

HandlerMapping

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

Handler

处理器:它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。

HandlerAdapter

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

View Resolver

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

View

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

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

总结

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

使用 <mvc:annotation-driven> 自动加载 HandlerMapping(处理映射器)和HandlerAdapter(处理适配器),可用在 SpringMVC.xml 配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置。

RequestMapping注解

value属性

value属性就是path属性的别名,填需要指定请求的地址,可以填写:

  1. 普通的具体值
    @RequestMapping("/user")
  2. 含有某一变量的一类值

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping(value="/{userId}/deleteUser",method=RequestMethod.GET)
    public String deleteUser(@PathVariable String userId){
        System.out.println("delete:"+userId);
        return "ShowUser";
    }
}
  1. 含正值表达式的一类值
@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping(value="/{userBirth:\\d{4}-\\d{2}-\\d{2}}/updateUser",method=RequestMethod.GET)
    public String updateUser(@PathVariable String userBirth){
        System.out.println("userBirth:"+userBirth);
        return "ShowUser";
    }
}

method属性

GET\POST\PUT\DELETE...

consumes属性

指定处理请求的提交内容类型,例如application/jsontext/html

produces属性

指定返回的内容类型,仅当request请求头中的Accept类型中包含该指定类型才返回。

params属性

指定request中必须包含某些参数值时才让该方法处理请求

headers属性

指定request中必须包含某些指定的header值时才让该方法处理请求

spring前后台交互

Controller获取前台传递的参数

(GET参数、POST参数等)

直接通过形参获取

形参的名字必须和前端传递的数据名一样

@RequestMapping(value = "/addUser",method = RequestMethod.POST)
public String ShowUser(Model model,String name,Integer age){
    System.out.println("name:"+name+"age:"+age);
    return "ShowUser";
}

如果不一致可以使用@ModelAttribute@RequestParam来指定形参要接受的参数的值。

@RequestMapping(value = "/addUser",method = RequestMethod.POST)
public String ShowUser(Model model, @ModelAttribute("name") String nickname, Integer age){
    System.out.println("name:"+nickname+"age:"+age);
    return "ShowUser";
}

使用对象接受前台传递的参数

前台传递的参数名必须和对象的属性名一致

@RequestMapping(value = "/addUser",method = RequestMethod.POST)
public String ShowUser(Model model, User user,@ModelAttribute("name")String nickname){
    System.out.println("name:"+nickname+"age:"+user.getAge());
    return "ShowUser";
}

@ModelAttribute注解应用在方法前的时候,SpringMVC在调用目标处理方法前,会先逐个调用在方法级上标注了@ModelAttribute的方法(把它看成获取必要属性的前置方法)

如下面的代码可以实现在每次调用处理方法前获取request response session

public class BaseController{
    protected HttpServletRequest request;
    protected HttpServletResponse request;
    protected HttpSession session;
    @ModelAttribute
    public void setReqAndRes(HttpServletRequest request,HttpServletResponse response){
        this.request = request;
        this.response = response;
        this.session = request.getSession();
    }
}

使用集合接受前台传递的参数

如果是list则前台传递的参数名是list[index].propName(index下标,propName属性名)

如果是Map则前台传递的参数名是map['key'].propName(key键名,propName属性名)

Controller传递参数到前台

直接通过request对象传递

直接通过获取的request的setAttribute方法传递。

直接通过返回值ModelAndView对象传递

@RequestMapping(value = "/showUser")
public ModelAndView ShowUser(){
    return new ModelAndView("ShowUser","message","test message!");
}
  • 第一个参数是逻辑视图字符串
  • 第二个参数是要往ShowUser视图上传递参数的名称
  • 第三个参数是要往ShowUser视图上传递参数的值

当要传递多个参数时可以多次调用ModelAndView.addObject("attributeName",attributeValue)

这些数据也是存放在request中的。

直接通过参数列表中添加形参ModelMap传递

写成接口Model也行

@RequestMapping(value = "/addUser")
public String ShowUser(ModelMap map){
    map.put("message","test message!");
    map.addAttribute("attributeName","attributeValue");
    return "showUser";
}

配置解决中文乱码的过滤器

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>

自定义类型转换器

第一步:定义一个类,实现 Converter 接口,该接口有两个泛型参数。

public interface Converter<S, T> {//S:表示接受的类型,T:表示目标类型
    /**
    * 实现类型转换的方法
    */
    @Nullable
    T convert(S source);
}
public class StringToDateConverter implements Converter<String, Date> {
    /**
    * 用于把 String 类型转成日期类型
    */
    @Override
    public Date convert(String source) {
        DateFormat format = null;
        try {
            if(StringUtils.isEmpty(source)) {
                throw new NullPointerException("请输入要转换的日期");
            }
            format = new SimpleDateFormat("yyyy-MM-dd");
            Date date = format.parse(source);
            return date;
        } catch (Exception e) {
            throw new RuntimeException("输入日期有误");
        }
    }
}

第二步:在 spring 配置文件中配置类型转换器。

<!-- 配置类型转换器工厂 -->
<bean id="converterService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
    <!-- 给工厂注入一个新的类型转换器 -->
    <property name="converters">
        <array>
            <!-- 配置自定义类型转换器 -->
            <bean class="com.itheima.web.converter.StringToDateConverter"></bean>
        </array>
    </property>
</bean>

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

SpringMVC常用注解

@Controller

控制器负责处理由DispatcherServlet分发过来的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model,然后再把该Model返回给对应的View进行展示。SpringMVC使用@Controller定义控制器,它还允许自动检测定义在类路径下的组件并自动注册。

@RequestMapping

将URL映射到整个类或特定的处理方法上。

@PathVariable

将注解方法参数绑定到URI模板遍历的值上。"/{userId}/deleteUser"

url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。

实例:

@RequestMapping("/usePathVariable/{id}")
public String usePathVariable(@PathVariable("id") Integer id){
    System.out.println(id);
    return "success";
}

@RequestParam

将请求的参数绑定到方法中的参数上。

属性:
+ value:请求参数中的名称。
+ required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。

@RequestBody

方法参数应该被绑定到HTTP的Body上。直接使用得到是 key=value&key=value...结构的数据。
get 请求方式不适用。

属性:
+ required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值为 false,get 请求得到是 null。

@RequestHeader

用于获取请求消息头。

属性:
+ value:提供消息头名称
+ required:是否必须有此消息头

@CookieValue

用于把指定 cookie 名称的值传入控制器方法参数。

属性:
value:指定 cookie 的名称。
required:是否必须有此 cookie。

@SessionAttribute

用于多次执行控制器方法间的参数共享。

用在方法参数上。

属性:
+ value:用于指定存入的属性名称。

@SessionAttributes

用于多次执行控制器方法间的参数共享。

用在类上。

属性:
+ value:用于指定存入的属性名称
+ type:用于指定存入的数据类型。

实例:

@Controller
@SessionAttributes(value = "age",types = String.class)
public class HelloController {
    @RequestMapping(value = "/addUser")
    public String ShowUser(ModelMap map,@RequestParam("age") int userAge){
        System.out.println("age:"+userAge);
        map.put("age",userAge);
        return "ShowUser";
    }
}

调用map.put("age",userAge);的时候就会同步存到session域中。

@RestController

创建REST类型的控制器(RESTFUL API)

HttpEntity(不是注解)

能获得request请求和response响应,还能访问请求和请求头

@ModelAttribute

可以作用在方法或方法参数上。作用在方法上时,表明该方法的目的时添加一个或多个模型属性。

@ModelAttribute一共具有如下三个作用:

  1. 绑定请求参数到命令对象:放在功能处理方法的入参上时,用于将多个请求参数绑定到一个命令对象,从而简化绑定流程,而且自动暴露为模型数据用于视图页面展示时使用;
  2. 暴露表单引用对象为模型数据:放在处理器的一般方法(非功能处理方法)上时,是为表单准备要展示的表单引用对象,如注册时需要选择的所在城市等,而且在执行功能处理方法(@RequestMapping注解的方法)之前,自动添加到模型对象中,用于视图页面展示时使用;

  3. 暴露@RequestMapping方法返回值为模型数据:放在功能处理方法的返回值上时,是暴露功能处理方法的返回值为模型数据,用于视图页面展示时使用。

HiddentHttpMethodFilter

作用

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

使用方法

  1. 在 web.xml 中配置该过滤器。
  2. 请求方式必须使用 post 请求。
  3. 按照要求提供_method 请求参数,该参数的取值就是我们需要的请求方式。

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/springmvc%e6%a6%82%e8%bf%b0%e5%92%8c%e4%bd%bf%e7%94%a8%e5%85%a5%e9%97%a8/

发表评论

电子邮件地址不会被公开。