springMVC

1 - springMVC(概念)

1、什么是springMVC

Spring MVC是基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级web框架。属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。

使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts 2(一般老项目使用)等。

2、springMVC(三层框架)

  • Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或 JavaBean 组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据) 和 服务层(行为)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。

  • View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。

  • Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。

3、springMCV的优势

  1、清晰的角色划分:

    前端控制器(DispatcherServlet)

    请求到处理器映射(HandlerMapping)

    处理器适配器(HandlerAdapter)

    视图解析器(ViewResolver)

    处理器或页面控制器(Controller)

    验证器( Validator)

    命令对象(Command 请求参数绑定到的对象就叫命令对象)

    表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。

  2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。

  3、由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。

  4、和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。

4、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 执行效率高。

2 - 搭建开发环境(springMVC入门程序)

1. 创建WEB工程,引入开发的jar包 ( 具体坐标如下)

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.howie</groupId>
  <artifactId>day02</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>day02 Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <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>
  </properties>

  <dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>

    <!--beans依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--expression依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!--spring-aop依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.1</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>day02</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <!--包括目录下的.properties,.xml 文件都会扫描到-->
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <!--filtering 选项 false 不启用过滤器, *.property 已经起到过滤的作用了-->
        <filtering>false</filtering>
      </resource>
    </resources>
  </build>
</project>
pom.xml

2. 配置核心的控制器(配置DispatcherServlet 即 在web.xml配置文件中核心控制器DispatcherServlet)

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!-- 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:spring-mvc.xml</param-value>
    </init-param>
    <!-- 配置servlet启动时加载对象 -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>
</web-app>
web.xml

3. 编写spring-mvc.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: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.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.xsd">
    <!--开启组件扫描-->
    <context:component-scan base-package="com.howie.controller"></context:component-scan>
    <!--配置视图解析器对象-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
    <!--配置spring开启注解mvc的支持-->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>
spring-mvc.xml

4. 编写index.jsp和HelloController控制器类

<%@ page language="java" import="java.util.*" pageEncoding="utf-8" %>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<html>
<head>
    <title>入门程序</title>
</head>
<body>
    <h2>入门程序</h2>
    <a href="hello">入门程序</a>
</body>
</html>
index.jsp
package com.howie.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

// 控制器的类
@Controller
public class HelloController {
    @RequestMapping(path = "/hello") // 请求映射
    public String sayHello(){
        System.out.println("hello springMVC");
        return "success";
    }
}
HelloController.java

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

<%@ page language="java" import="java.util.*" pageEncoding="utf-8" %>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<html>
<head>
    <title>success</title>
</head>
<body>
    <h1>hello springMVC</h1>
</body>
</html>
success.jsp

6. 启动Tomcat服务器,进行测试

3. 入门案例的执行过程分析

1. 入门案例的执行流程

  1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象, 就会加载springmvc.xml配置文件

  2. 开启了注解扫描,那么HelloController对象就会被创建

  3. 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解 找到执行的具体方法

  4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件

  5. Tomcat服务器渲染页面,做出响应

2. SpringMVC官方提供图形

入门案例执行流程

 3. 入门案例中的组件分析

  1. 前端控制器(DispatcherServlet)

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

  2. 处理器映射器(HandlerMapping)

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

  3. 处理器(Handler)

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

  4. 处理器适配器(HandlAdapter)

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

  5. 视图解析器(View Resolver)

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

  6. 视图(View)

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

 4、<mvc:annotation-driven>说明

<!--配置spring开启注解mvc的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使 用 <mvc:annotation-driven> 自动加载 RequestMappingHandlerMapping (处理映射器) 和
RequestMappingHandlerAdapter ( 处 理 适 配 器 ) , 可 用 在 SpringMVC.xml 配 置 文 件 中 使 用
<mvc:annotation-driven>替代注解处理器和适配器的配置。
它就相当于在 xml 中配置了:
<!-- 上面的标签相当于 如下配置-->
<!-- Begin -->
<!-- HandlerMapping -->
<bean
传智播客——专注于 Java、.Net 和 Php、网页平面设计工程师的培训
北京市昌平区建材城西路金燕龙办公楼一层 电话:400-618-9090
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerM
apping"></bean>
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- HandlerAdapter -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerA
dapter"></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.ExceptionHandlerExcept
ionResolver"></bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolv
er"></bean>
<bean
class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"
></bean>
<!-- End -->
注意:
一般开发中,我们都需要写上此标签(虽然从入门案例中看,我们不写也行,随着课程的深入,该标签还
有具体的使用场景)。
明确:
我们只需要编写处理具体业务的控制器以及视图。
View Code

4 - RequestMapping 注解

1、源码:

@Target({ElementType.METHOD, ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Mapping

public @interface RequestMapping { }

2、作用: 用于建立请求 URL 和处理请求方法之间的对应关系。

3、出现位置:

  ①类上: 请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。

    它出现的目的是为了使我们的 URL 可以按照模块化管理:

      例如:

        账户模块:

          /account/add

          /account/update

          /account/delete ...

        订单模块:

          /order/add

          /order/update

          /order/delete

        红色的部分就是把 RequsetMappding 写在类上,使我们的 URL 更加精细。

  ②方法上: 请求 URL 的第二级访问目录。

  ③属性:

    value:用于指定请求的 URL。它和 path 属性的作用是一样的。

    method:用于指定请求的方式。@RequestMapping(path = "/test",method = {RequestMethod.GET})

    params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的一模一样。

      例如:

        params = {"accountName"},表示请求参数必须有 accountName

        params = {"moeny!100"},表示请求参数中 money 不能是 100。

        params = {"userId=1"},表示请求参数中userId必须是1

    headers:用于指定限制请求消息头的条件。

  注意: 以上四个属性只要出现 2 个或以上时,他们的关系是 的关系。

@RequestMapping(path = "/test",method = {RequestMethod.GET},params = {"username"},headers = {"Accept"})
    public String requestMappingTest(String username){
        System.out.println("test requestMapping ...");
        System.out.println(username);
        return "success";
    }
使用示例

5 - 请求参数的绑定

1. 请求参数的绑定说明

  1. 绑定机制

    1. 表单提交的数据都是k=v格式的 username=haha&password=123

    2. SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的

    3. 要求:提交表单的name和参数的名称是相同的

  2. 支持的数据类型

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

    2. 实体类型(JavaBean)

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

2. 基本数据类型和字符串类型

  1. 提交表单的name和参数的名称是相同的

  2. 区分大小写

  例如:<a href="user/findById?userId=1">查询记录</a>

  @Controller

  @RequestMapping(path = "/user")

  class UserController(){

    @RequestMapping(path = "/findById")

    public String findById(String userId){

      System.out.println(userId);

    }

  }

3. 实体类型(JavaBean)

  1. 提交表单的nameJavaBean中的属性名称需要一致

  2. 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如: address.name

<!--把数据封装到Account类中,其中Account类中有一个User属性-->
<form action="param/saveAccount" method="post">
    姓名:<input type="text" name="username"/><br>
    密码:<input type="password" name="password"/><br>
    金额:<input type="text" name="balance"/><br>
    用户姓名:<input type="text" name="user.username"/><br>
    年龄:<input type="text" name="user.age"/><br>
    <input type="submit" value="提交">
</form>
前端jsp代码
package com.howie.controller;

import com.howie.domain.Account;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping(path = "/param") // 设置一级访问目录,便于模块化管理
public class ParamController {
    /*
    把请求参数封装到JavaBean中
    */
    @RequestMapping(path = "/saveAccount")
    public String saveAccount(Account account){
        System.out.println("执行添加操作");
        System.out.println(account);
        return "success";
    }
    
    /*@RequestMapping(path = "/testParam")
    // 参数名与形参名相同即可自动赋值
    public String paramTest(String username){
        System.out.println(username);
        return "success";
    }*/
    
}
后端控制器代码

4. 给集合(list与map)属性数据封装

  1.list集合JSP页面编写方式:list[0].属性

  2.map集合JSP页面编写方式:map['key'].属性

<!--把数据封装到Account类中,Account类中有List和Map集合属性-->
<form action="param/saveAccount" method="post">
    姓名:<input type="text" name="username"/><br>
    密码:<input type="password" name="password"/><br>
    金额:<input type="text" name="balance"/><br>

    用户姓名:<input type="text" name="userList[0].username"/><br>
    年龄:<input type="text" name="userList[0].age"/><br>

    用户姓名:<input type="text" name="map['one'].username"/><br>
    年龄:<input type="text" name="map['oen'].age"/><br>
    <input type="submit" value="提交">
</form>
JSP代码

5. 请求参数中文乱码的解决

   1. 在web.xml中配置Spring提供的过滤器类

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!-- 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:spring-mvc.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>

  <!--配置解决中文乱码的过滤器-->
  <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>
</web-app>
web.xml

6. 自定义类型转换器

  1. 表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明 Spring框架内部会默认进行数据类型转换。

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

1. 自定义类型转换器(新建utils包,新建类且实现Converter接口)

package com.howie.utils;

import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 把字符串转换成日期
 */
public class StringToDateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String s) {
        // 判断
        if(s == null){
            throw new RuntimeException("数据为空!");
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            // 把字符串转为日期
            return sdf.parse(s);
        } catch (Exception e) {
            throw new RuntimeException("传入的日期格式不正确哦!推荐使用格式(2020-5-20)");
        }
    }
}
接口实现类

2. 注册自定义类型转换器,在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: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.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.xsd">
    <!--开启组件扫描-->
    <context:component-scan base-package="com.howie.controller"/>
    <!--配置视图解析器对象-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--配置自定义类型转换器-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.howie.utils.StringToDateConverter"/>
            </set>
        </property>
    </bean>
    <!--配置spring开启注解mvc的支持-->
    <mvc:annotation-driven conversion-service="conversionService"/>
</beans>
spring-mvc.xml

7. 在控制器中使用原生的ServletAPI对象

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

  例如:

  // 获取原生servletAPI

  @RequestMapping(path = "/getServletAPI")

  public String getServletAPI(HttpServletRequest request, HttpServletResponse response){

    System.out.println("request:" + request);

    System.out.println("response:" + response);

    return "success";
  }

6 - 常用注解

1. RequestParam注解

  1. 作用:把请求中的指定名称的参数传递给控制器中的形参赋值

  2. 属性

    1. value:请求参数中的名称

    2.name:与value参数相同

 

    3. required:请求参数中是否必须提供此参数,默认值是true,必须提供

  3.使用示例:

<!--常用注解之RequestParam-->
<a href="annotation/requestParam?name=python">requestParam</a>
jsp代码
@RequestMapping(path = "/requestParam")
    public String requestParamTest(@RequestParam(name = "name") String course){ // courses = name
        // 此时请求地址必须传 "name" 参数
        System.out.println("run this method ...");
        System.out.println("course : " + course);
        return "success";
    }
控制器代码

2. RequestBody注解

  1. 作用:用于获取请求体的内容(注意:get方法不可以)

  2. 属性

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

  3.使用示例:

<!--常用注解之RequestBody-->
<form action="annotation/requestBody" method="post">
    姓名:<input type="text" name="name"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="提交">
</form>
jsp代码
    /**
     * 获取到请求体的内容,只适用于post请求,因为get把请求封装到请求地址里
     * @return
     */
    @RequestMapping(path = "/requestBody")
    public String requestBodyTest(@RequestBody String body){
        System.out.println(body); // name=alex&password=123
        return "success";
    }
控制器代码

3.PathVariable注解

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

  2. 属性

    1. value/name:指定url中的占位符名称

  3. Restful风格的URL

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

    2. restful风格的URL优点

      1. 结构清晰

      2. 符合标准

      3. 易于理解

      4. 扩展方便

  4.使用示例:

<!--常用注解之PathVariable-->
<a href="annotation/delete/10">testPathVariable</a>
jsp代码
    /**
     * PathVariable注解
     */
    @RequestMapping(path = "/delete/{id}")
    public String pathVariableTest(@PathVariable(name = "id") String id){
        System.out.println("id=" + id); // id=10
        return "success";
    }
控制器代码

4. RequestHeader注解

  1. 作用:获取指定请求头的值

  2. 属性

    1. value/name:请求头的名称

  3.使用示例:

<!--常用注解之RequestHeader-->
<a href="annotation/requestHeader">requestHeaderTest</a>
jsp代码
    /**
     * RequestHeader注解:获取指定的请求头信息
     */
    @RequestMapping(path = "/requestHeader")
    public String requestHeaderTest(@RequestHeader(value = "Accept") String header){
        System.out.println(header);
        return "success";
    }
控制器代码

5. CookieValue注解

  1. 作用:用于获取指定cookie的名称的值

  2. 属性

    1. value/name:cookie的名称

  3.使用示例:

<!--常用注解之CookieValue-->
<a href="annotation/cookieValue">cookieValueTest</a><br>
jsp代码
/**
     * CookieValue注解:获取指定名称cookie的值
     */
    @RequestMapping(path = "/cookieValue")
    public String cookieValueTest(@CookieValue(value = "JSESSIONID") String cookieValue){
        System.out.println(cookieValue);
        return "success";
    }
控制器代码

6. ModelAttribute注解

  1. 作用

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

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

  2. 应用场景

    1. 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据

    3.使用示例

  ①修饰的方法有返回值

<!--常用注解值ModelAttribute-->
<form action="annotation/modelAttribute" method="post">
    姓名:<input type="text" name="username"><br>
    年龄:<input type="text" name="age"><br>
    <input type="submit" value="提交">
</form>
jsp代码
    /**
     * ModelAttribute注解
     */
    @RequestMapping(path = "/modelAttribute")
    public String modelAttributeTest(@ModelAttribute("user") User user){
        System.out.println("run modelAttributeTest ...");
        System.out.println(user);
        return "success";
    }
    @ModelAttribute
    public User showUser(String username){
        // 处理请求时,此方法都会优先执行
        // System.out.println("showUser ...");
        // 模拟根据 username 查询数据信息
        User user = new User();
        user.setUsername(username);
        user.setAge(20);
        user.setDate(new Date());
        return user;
    }
控制器代码

  ②修饰的方法没有返回值

<!--常用注解值ModelAttribute-->
<form action="annotation/modelAttribute" method="post">
    姓名:<input type="text" name="username"><br>
    年龄:<input type="text" name="age"><br>
    <input type="submit" value="提交">
</form>
jsp代码
    /**
     * ModelAttribute注解
     */
    @RequestMapping(path = "/modelAttribute")
    public String modelAttributeTest(@ModelAttribute("user") User user){
        System.out.println("run modelAttributeTest ...");
        System.out.println(user);
        return "success";
    }
    
    @ModelAttribute
    public void setMap(String username, String age,Map<String,User> map){
        User user = new User();
        user.setUsername(username);
        user.setAge(Integer.parseInt(age));
        user.setDate(new Date());
        map.put("user",user);
    }
控制器代码

7. SessionAttributes注解

  1. 作用:用于多次执行控制器方法间的参数共享(说明该注解用在类中)

  2. 属性

    1. value:指定存入属性的名称

  3.使用示例:

<!--常用注解之sessionAttribute-->
<a href="annotation/setSessionAttribute">setSessionAttribute</a><br>
<a href="annotation/getSessionAttribute">getSessionAttribute</a><br>
jsp代码
package com.howie.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

/**
 * 常用的注解
 */
@Controller
@RequestMapping(path = "/annotation") // 一级请求目录
@SessionAttributes(value = {"data"}) // 把data='李白存入session域对象中
public class AnnotationController {
    /**
     * SessionAttribute注解
     */
    // 设置session域对象,并存值
    @RequestMapping(path = "/setSessionAttribute")
    public String setSessionAttribute(Model model){
        // 底层会存储到request域对象中
        model.addAttribute("data","李白");
        System.out.println("run ...");
        return "success";
    }

    /**
     * 从session域取值
     * @param modelMap
     * @return
     */
    @RequestMapping(path = "/getSessionAttribute")
    public String getSessionAttribute(ModelMap modelMap){
        String data = (String) modelMap.get("data");
        System.out.println(data);
        return "success";
    }
}
控制器代码

7 - 响应数据和结果视图(返回值分类)

1. 返回字符串

  1. Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。

    @RequestMapping(value="/hello")

    public String sayHello() {

      System.out.println("Hello SpringMVC!!");

    // 跳转到XX页面

    return "success";

    }

  2. 具体应用:

@Controller
@RequestMapping("/user")
public class UserController {
/**
* 请求参数的绑定
*/
@RequestMapping(value="/initUpdate")
public String initUpdate(Model model) {
    // 模拟从数据库中查询的数据
    User user = new User();
    user.setUsername("张三");
    user.setPassword("123");
    user.setMoney(100d);
    user.setBirthday(new Date());
    model.addAttribute("user", user);
    return "update";
    }
}


<h3>修改用户</h3>
${ requestScope }
<form action="user/update" method="post">
姓名:<input type="text" name="username" value="${ user.username }"><br>
密码:<input type="text" name="password" value="${ user.password }"><br>
金额:<input type="text" name="money" value="${ user.money }"><br>
<input type="submit" value="提交">
</form>
View Code

2. 返回值是void

  1. 如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。

    1. 默认会跳转到@RequestMapping(value="/initUpdate") initUpdate的页面。

  2. 可以使用请求转发或者重定向跳转到指定的页面

    /**
     * 返回值是void
     */
    @RequestMapping(path = "testVoid")
    public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("testVoid is run");
        // 1.编写请求转发(请求转发只发起一次请求,并且会停留在老路径)
        // request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
        // 2.重定向(重新发起新的请求)
        // response.sendRedirect(request.getContextPath()+"/spring.jsp");
        // 3.直接进行响应
        // 设置编码格式
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().print("<h1>响应成功</h1>");
    }
控制器代码

3. 返回值是ModelAndView对象

ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图

* 可以传入视图的名称(即跳转的页面),还可以传入对象。

    /**
     * 返回ModelAndView对象
     * @return
     */
    @RequestMapping(path = "/testModelAndView")
    public ModelAndView testModelAndView(){
        // 创建ModelAndView对象
        ModelAndView mav = new ModelAndView();
        // 模拟从数据库中查询出user对象
        User user = new User();
        user.setUsername("韩信");
        user.setPassword("123");
        user.setAge(21);
        // 把user对象存储到ModelAndView对象中,springMVC也会把user对象存储到request域对象中
        mav.addObject("user",user);

        // 设置视图名称(跳转到那个页面)
        mav.setViewName("success"); // 调用视图解析器
        return mav;
    }

// jsp代码
<html>
<head>
    <title>response</title>
</head>
<body>
    <h3>跳转成功!</h3><br>
    ${user.toString()}
</body>
</html>
View Code

8 - SpringMVC框架提供的转发和重定向

1. forward请求转发

  1. controller方法返回String类型,想进行请求转发也可以编写成

/**
* 使用forward关键字进行请求转发
* "forward:转发的JSP路径",不走视图解析器了,所以需要编写完整的路径
* @return
* @throws Exception
*/
@RequestMapping("/delete")
public String delete() throws Exception {
    System.out.println("delete方法执行了...");
    // return "forward:/WEB-INF/pages/success.jsp";
    return "forward:/user/findAll";
}
forward请求转发

2. redirect重定向

  1. controller方法返回String类型,想进行重定向也可以编写成

/**
* 重定向
* @return
* @throws Exception
*/
@RequestMapping("/count")
public String count() throws Exception {
    System.out.println("count方法执行了...");
    return "redirect:/add.jsp";
    // return "redirect:/user/findAll";
}
redirect重定向

9 - ResponseBody注解 响应json数据

1. DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而 不能被使用。

  解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置

   <!--
        DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到.
        所以要配置前端控制器,不需要拦截的静态资源
    -->
    <mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 -->
    <mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 -->
    <mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
<?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: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.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.xsd">
    <!--开启组件扫描-->
    <context:component-scan base-package="com.howie.controller"/>
    <!--配置视图解析器对象-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--配置自定义类型转换器-->

    <!--
        DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到.
        所以要配置前端控制器,不需要拦截的静态资源
    -->
    <mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 -->
    <mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 -->
    <mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->

    <!--配置spring开启注解mvc的支持-->
    <mvc:annotation-driven/>
</beans>
spring-mvc.xml

2. 使用@RequestBody获取请求体数据

    <script src="js/jquery-3.4.1.js"></script>
    <script type="text/javascript">
        // 页面加载,绑定单击事件
        $(function () {
            $("#btn").click(function () {
                // alert("hello world");
                // 发起ajax请求
                $.ajax({
                    // 编写json格式,设置属性和值
                    url: "user/testAjax",
                    type: "post",
                    contentType: "application/json;charset=utf-8",
                    data: '{"username":"关羽","password":"123","age":20}',
                    dataType: "json",
                    success :function(data){
                        // data:服务端响应的json数据
                        alert(data);
                        alert(data.username);
                    }
                })
            })
        });
    </script>
jsp代码
/**
* 获取请求体的数据
* @param body
*/
@RequestMapping("/testJson")
    public void testJson(@RequestBody String body) {
    System.out.println(body);
}
使用@RequestBody获取请求体数据

3. 使用@RequestBody注解把json的字符串转换成JavaBean的对象

 ①json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包,依赖如下

    <!--jackson相关依赖-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.0</version>
    </dependency>
View Code
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.howie</groupId>
  <artifactId>day01</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>day01 Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <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>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>

    <!--beans依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--expression依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!--spring-aop依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.1</version>
      <scope>provided</scope>
    </dependency>
    <!--jackson相关依赖-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.0</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>day01</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>
pom.xml

②使用@RequestBody注解

  @RequestMapping("/testJson")

  public void testJson(@RequestBody Address address) {

    System.out.println(address);

  }

4. 使用@ResponseBody注解把JavaBean对象转换成json字符串,直接响应

要求方法需要返回JavaBean的对象

    /**
     * 模拟异步请求和响应
     */
    @RequestMapping(path = "testAjax")
    public @ResponseBody User testAjax(@RequestBody User user){
        // 客户端发送ajax请求,传的是json字符串,后端已经把json字符串封装到user对象中
        System.out.println(user);
        // 响应客户端,模拟从数据库查询出数据
        user.setUsername("盾山");
        return user;
    }
控制器代码

10 - SpringMVC实现文件上传 

1.传统文件上传方式

①导入文件上传的jar包

    <!--文件上传相关依赖-->
    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
依赖坐标
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.howie</groupId>
  <artifactId>day01</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>day01 Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <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>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>

    <!--beans依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--expression依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!--spring-aop依赖-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.1</version>
      <scope>provided</scope>
    </dependency>
    <!--jackson相关依赖-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.0</version>
    </dependency>
    <!--文件上传相关依赖-->
    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.4</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>

    <!--跨服务器相关依赖坐标
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-core</artifactId>
      <version>1.18.1</version>
    </dependency>
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
      <version>1.18.1</version>
    </dependency>
    -->
  </dependencies>
  <build>
    <finalName>day01</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>
pom.xml

②编写文件上传的JSP页面

    <h2>传统文件上传</h2><br>
    <form action="user/fileUpload1" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"><br>
        <input type="submit" value="上传">
    </form><br>
jsp代码

③编写文件上传的Controller控制器

    /**
     * 文件上传(传统方式)
     */
    @RequestMapping(path = "fileUpload1")
    public String fileUpload1(HttpServletRequest request) throws Exception {
        System.out.println("文件上传!");
        // 使用fileUpload组件完成文件上传
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        File file = new File(path);
        if(!file.exists()){
            // 创建该文件夹
            file.mkdirs();
        }
        // System.out.println(path);
        // 解析request对象,获取上传文件项
        // 创建磁盘文件项工厂
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 解析request
        List<FileItem> items = upload.parseRequest(request); // 文件项
        // 遍历
        for(FileItem item:items){
            // 进行判断,当前item对象是否是上传文件项
            if(item.isFormField()){
                // 普通表单项
            } else{
                // 上传文件项
                // 获取上传文件名称
                String fileName = item.getName();
                // 把文件名称设置成唯一,uuid
                String uuid = UUID.randomUUID().toString().replace("-", "");
                fileName = uuid+"_"+fileName;
                // 完成文件上传
                item.write(new File(path,fileName));
                // 删除临时文件
                item.delete();
            }
        }
        return "success";
    }
控制器代码

2.springMVC上传文件方式

SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的 name属性名称相同。在spring-mvc.xml配置文件解析器对象

    <!--配置文件解析器对象-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760"/>
    </bean>

②控制代码如下

    /**
     * 文件上传(springMVC方式)
     */
    @RequestMapping(path = "/fileUpload2")
    public String fileUpload2(HttpServletRequest request, MultipartFile upload) throws IOException { // load必须是文件上传的参数名即name="load"
        System.out.println("springMVC上传文件");
        // 上传位置
        String path = request.getSession().getServletContext().getRealPath("/uploads/");
        File file = new File(path);
        // 判断该路径是否存在
        if(!file.exists()){
            file.mkdirs();
        }
        // 获取上传文件名称,并设置成唯一值
        String fileName = UUID.randomUUID().toString().replace("-","")+"_"+upload.getOriginalFilename();
        // 完成文件上传
        upload.transferTo(new File(path,fileName));
        return "success";
    }
View Code

3. SpringMVC跨服务器方式文件上传

1. 搭建图片服务器

  1. 根据文档配置tomcat9的服务器,现在是2个服务器

  2. 导入资料中day02_springmvc5_02image项目,作为图片服务器使用

 

2. 实现SpringMVC跨服务器方式文件上传

①导入开发需要的jar包

    <!--跨服务器相关依赖坐标
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-core</artifactId>
      <version>1.18.1</version>
    </dependency>
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
      <version>1.18.1</version>
    </dependency>
    -->
依赖坐标

②编写文件上传的JSP页面

    <h2>springMVC跨服务器文件上传</h2><br>
    <form action="user/fileUpload3" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"><br>
        <input type="submit" value="上传">
    </form>
jsp代码

③编写控制器

    /**
     * 文件上传(springMVC跨服务器)
     */
    @RequestMapping(path = "/fileUpload3")
    public String fileUpload3(MultipartFile upload) throws IOException {
        System.out.println("跨服务器上传文件");
        // 定义上传文件服务器路径
        String path = "http://localhost:9090/uploads/";
        // 获取上传文件名称,并设置成唯一值
        String fileName = UUID.randomUUID().toString().replace("-","")+"_"+upload.getOriginalFilename();
        // 完成文件上传,跨服务器上传
        // 1.创建客户端对象
        Client client = Client.create();
        // 2.和图片服务器进行连接
        WebResource resource = client.resource(path + fileName);
        // 3.上传文件
        resource.put(upload.getBytes());
        return "success";
    }
控制器代码

11 - SpringMVC的异常处理

1. 异常处理思路

  1. Controller调用serviceservice调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进 行异常的处理。

2. SpringMVC的异常处理

①自定义异常类

package com.howie.exception;

/**
 * 自定义异常类
 */
public class SysException extends Exception{
    // 存储提示信息
    private String message;

    public SysException(String message) {
        this.message = message;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
SysException.java

②自定义异常处理器(实现特定的接口HandlerHandlerExceptionResolver,并重写相关方法)

package com.howie.exception;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 异常处理器类
 */
public class SysExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        // 获取到异常对象
        SysException exception = null;
        if(e instanceof SysException){
            exception = (SysException) e;
        } else{
            exception = new SysException("系统正在维护");
        }
        // 创建ModelAndView对象
        ModelAndView modelAndView = new ModelAndView();
        // 存入错误提示信息
        modelAndView.addObject("errorMessage",exception.getMessage()); // 最终会存储到request域对象中
        // 跳转的jsp页面
        modelAndView.setViewName("error");
        return modelAndView;
    }
}
SysExceptionResolver.java

③在配置文件中配置异常处理器对象

  <!--配置异常处理器对象-->
  <bean id="sysExceptionResolver" class="com.howie.exception.SysExceptionResolver"/>

④使用示例

    @RequestMapping(path = "/testException")
    public String testException() throws SysException {
        System.out.println("testException is run ...");
        // 模拟异常
        try {
            int a = 1/0;
        } catch (Exception e) {
            e.printStackTrace();
            throw new SysException("查询错误");
        }
        return "success";
    }
View Code

12 - SpringMVC框架中的拦截器

1. 拦截器的概述

  1. SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。

  2. 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链 中的拦截器会按着定义的顺序执行。

  3. 拦截器和过滤器的功能比较类似,有区别

    1. 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。

    2. 拦截器是SpringMVC框架独有的。

    3. 过滤器 url-pattern 配置了/*,可以拦截任何资源。

    4. 拦截器只会对控制器中的方法进行拦截。

  4. 拦截器也是AOP思想的一种实现方式

  5. 想要自定义拦截器,需要实现HandlerInterceptor接口。

2. 自定义拦截器步骤

①创建类(com.howie.interceptor),实现HandlerInterceptor接口,重写需要的方法

package com.howie.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义拦截器
 */
public class MyInterceptor implements HandlerInterceptor {
    /**
     * 预处理:controller方法执行前。
     * return true 放行,执行下一个拦截器,如果没有执行controller中的方法
     * return false 不放行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("controller 方法前,我就执行。");
        // 请求转发
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
        return true;
    }

    /**
     * 后处理方法:controller方法执行后,success.jsp 之前
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("controller 方法后,我就执行。");
        // 请求转发
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
        /*
        预处理方法和后处理方法都可以指定跳转方法
         */
    }

    /**
     * 最后执行,在success.jsp执行完毕后执行。
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("最后执行");
    }
    /*
    controller 方法前,我就执行。
    testInterceptor is run ...
    controller 方法后,我就执行。
    success.jsp is run ...
    最后执行
     */
}
MyInterceptor.java

② 在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: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.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.xsd">
    <!--开启组件扫描-->
    <context:component-scan base-package="com.howie.controller"/>
    <!--配置视图解析器对象-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--配置自定义类型转换器-->

    <!--
        DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到.
        所以要配置前端控制器,不需要拦截的静态资源
    -->
    <mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 -->
    <mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 -->
    <mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->

    <!--配置文件解析器对象-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760"/>
    </bean>
    <!--配置异常处理器对象-->
    <!-- <bean id="sysExceptionResolver" class="com.howie.exception.SysExceptionResolver"/> -->
    
    <!--配置拦截器-->
    <mvc:interceptors>
        <!--可配置多个拦截器-->
        <mvc:interceptor>
            <!--要拦截的具体方法-->
            <mvc:mapping path="/user/*"/>
            <!--不要拦截的具体方法
            <mvc:exclude-mapping path=""/>-->
            <!--配置拦截器对象-->
            <bean class="com.howie.interceptor.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
    <!--配置spring开启注解mvc的支持-->
    <mvc:annotation-driven/>
</beans>
spring-mvc.xml

③配置多个拦截器时,只需创建多个实现HandlerInterceptor接口的类即可。

 

posted @ 2020-09-18 22:14  赖正华  阅读(111)  评论(0编辑  收藏  举报