SSM框架之SpringMVC超详解

SpringMVC框架

三层框架结构和mvc的基本概念:
m - model 模型 用于类型封装
v - view 视图 用于展现数据,例如jsp等
c - controller 控制器 用于接收请求 ,如servlet程序。

在这里插入图片描述

SpringMVC第一天

1.springMVC的概述

1.1 SpringMVC是什么

springMVC是一种基于Java 的实现 MVC设计模型的请求驱动类型的轻量级web框架,属于SpringFrameWork 的后续产品,已经融合在Spring Web Flow里面。Spring框架提供了构建web应用程序的全功能MVC模块。使用Spring可插入的MVC架构,从而在使用Spring进行WEB开发时,可以选择使用spring的 Spring Mvc框架或集成其他MVC开发框架,如struts1(现在一般不用),Struts2等。
SpringMVc已经成为目前最主流的MVc框架之一,并且随着Spring3.0的发布,全面超越struts2,成为最优秀的 MVC框架。

它通过一套注解,让一个简单的 Java类成为处理请求的控制器,而无须实现任何接口。

同时它还支持RESTful编程风格的请求。

由于springMVC 和spring整合会变得非常容易,我们在开发中常用。

1.2 SpringMVC的位置

在这里插入图片描述

1.3 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风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配
置支持等等。

1.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的入门程序

2.1 入门需求的分析

在这里插入图片描述

2.2 入门需求的环境搭建

1.注意选择webapp。
在这里插入图片描述
2.注意加入java文件和resources文件并将其设置为主程序目录和主程序资源目录
在这里插入图片描述
3.注意选择jdk版本为1.8
在这里插入图片描述
4.导入pom.xml配置文件,这里可以把版本提取出来
在这里插入图片描述
具体依赖:

<!-- 版本锁定 -->
<properties>
	<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>
</dependencies>

5.想要使用springMVC,必须先配置控制器。这个控制器就是一个servlet程序。所以需要在web.xml中配置servlet程序

在这里插入图片描述
注意:这个servlet-class是由spring提供的。
注意:url-pattern 中的’’/'表示拦截所有。

6.springMVC的框架,还需要一个配置文件:springmvc.xml
在这里插入图片描述

2.3 配置服务器

注意在选择服务器时,对项目进行部署。
在这里插入图片描述
在这里插入图片描述

2.4 入门程序的建立

1.如图所示,重新创建index.jsp文件。因为系统自带的jsp文件没有头配置。并输入如下程序。
在这里插入图片描述
2.创建一个servlet程序用来接收请求
在这里插入图片描述
3.为了能够执行这个servlet程序中的方法,需要把这个控制器类先变成一个对象。我们可以把这个类交给ioc容器去管理。我们需要在springmvc的配置文件中进行配置。

(1)拷贝约束

<?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">

(2)开启注解扫描

<!-- 配置spring创建容器时要扫描的包 -->
<context:component-scan base-package="com.itheima"></context:component-scan>

(3)在类中加入注解,同时注意配置path路径
在这里插入图片描述
(4)继续在xml文件中进行参数的配置
在这里插入图片描述
(5)在控制器类中返回字符串
在这里插入图片描述
(6)如图所示,在WEB-INF/pages目录下,添加success.jsp文件。
在这里插入图片描述
(7)在springmvc.xml文件中,配置视图解析器。
在这里插入图片描述
(8)在springmvc.xml文件中,开启springmvc框架对注解的支持
在这里插入图片描述
(9)在index.jsp中的href标签中,加入hello地址。注意当前这个路径是相对路径。当运行时,你可以启动tomcat服务器,鼠标点到入门程序处,查看此处的地址是否正确,不对的话再改正即可。
在这里插入图片描述

2.5 入门案例的流程分析

1.启动服务器,加载一些配置文件

(1)DispatcherServlet对象创建
load-on-startup标签:在xml配置文件中,默认情况下是发送请求时,就会直接创建servlet,但是如果使用此标签,则证明开启服务器时,就会创建servlet。
(2)springmvc配置文件被加载
(3) HelloController被创建成对象,默认单例
(4)视图解析器类也会创建对象。如果谁调用解析器,完成跳转页面功能。
(5)开启springmvc注解的支持,即完成方法上@RequestMapping注解的读取。

2.发送请求,后台处理请求
(1)超链接index.jsp中发送请求。路径=>项目名称/hello
(2)被servlet程序拦截.DispatcherServlet控制指挥
(3)让sayHello方法执行,return success
(4)DispatcherServlet找视图解析器对象。通过找到这个对象之后,视图解析器跳转到success.jsp页面。
(5)响应给客户端。
在这里插入图片描述

2.6 入门案例的详细流程

在这里插入图片描述
每个组件都有固定作用。
前端控制器: 控制方法执行。控制整个流程的执行。调用其他组件。
处理器映射器: 具体找到哪个类、哪个方法去执行。springMVC提供了不同的映射器实现不同的映射方式。例如:配置文件方式、实现接口方式、注解方式等。
Handler处理器: 它就是我们开发中要编写的具体业务控制器。由DispatcherServlet把用户请求转发到Handler,由Handler对具体的用户请求进行处理。
适配器: 可以把任何的controller全适配上。帮你去执行方法。对处理器进行执行。这是适配器模式的应用。通过扩展适配器可以对更多类型的处理器进行执行。
视图解析器: 跳转到具体的页面。负责将处理结果生成View视图。View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View 视图对象,最后对View进行渲染将处理结果通过页面显示给用户。
View视图: SpringMVC 框架提供了很多的View视图类型的支持,包括jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp.一般情况下需要通过页面标签或页面模板数据将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
mvc:annotation-driven 说明

SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使 用 <mvc:annotation-driven> 自动加载 RequestMappingHandlerMapping (处理映射器) 和
RequestMappingHandlerAdapter ( 处 理 适 配 器 ) , 可 用 在 SpringMVC.xml 配 置 文 件 中 使 用
<mvc:annotation-driven>替代注解处理器和适配器的配置。
它就相当于在 xml 中配置了:
<!-- 上面的标签相当于 如下配置-->
<!-- Begin -->
<!-- HandlerMapping -->
<bean
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 -->
注意:
一般开发中,我们都需要写上此标签(虽然从入门案例中看,我们不写也行,随着课程的深入,该标签还
有具体的使用场景)。
明确:
我们只需要编写处理具体业务的控制器以及视图。

2.7RequestMapping注解

作用:建立请求URL和处理请求方法之间的对应关系。
作用范围:方法和类
使用说明:

源码:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
}
作用:
用于建立请求 URL 和处理请求方法之间的对应关系。

出现位置:
类上:
请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。
它出现的目的是为了使我们的 URL 可以按照模块化管理:
例如:
账户模块:
/account/add
/account/update
/account/delete
...
订单模块:
/order/add
/order/update
/order/delete
一级目录的部分就是把 RequsetMappding 写在类上,使我们的 URL 更加精细。
方法上:
请求 URL 的第二级访问目录。
属性:
value:用于指定请求的 URL。它和 path 属性的作用是一样的。
method:用于指定请求的方式。
请注意:@RequestMapping的请求方式
(1)如果方法上的@RequestMapping注解没有设置method属性,则get和post请求默认都可以访问。
(2)如果方法上的@RequestMapping注解设置了method属性,则只能是相应的请求方式可以访问。
params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和
		配置的一模一样。
		例如:
		params = {"accountName"},表示请求参数必须有 accountName
		params = {"moeny!100"},表示请求参数中 money 不能是 100。
headers:用于指定限制请求消息头的条件。
注意:
以上四个属性只要出现 2 个或以上时,他们的关系是与的关系。

如下图所示,这张图说明了 path属性和value属性的作用是一样的。
在这里插入图片描述

RequestMapping注解的使用示例:

控制器代码:
/**
* RequestMapping 注解出现的位置
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
@Controller("accountController")
@RequestMapping("/account")
public class AccountController {
	@RequestMapping("/findAccount")
	public String findAccount() {
		System.out.println("查询了账户。。。。");
		return "success";
	}
}


jsp 中的代码:

<html>
	<head>
	<title>requestmapping 的使用</title>
	</head>
	<body>
		<!-- 第一种访问方式 -->
		<a href="${pageContext.request.contextPath}/account/findAccount">
		查询账户
		</a>
		<br/>
		<!-- 第二种访问方式 -->
		<a href="account/findAccount">查询账户</a>
	</body>
</html>

注意:
当我们使用此种方式配置时,在 jsp 中第二种写法时,不要在访问 URL 前面加/,否则无法找到资源。

**Method属性的使用案例:请注意:@RequestMapping的请求方式
(1)如果方法上的@RequestMapping注解没有设置method属性,则get和post请求默认都可以访问。
(2)如果方法上的@RequestMapping注解设置了method属性,则只能是相应的请求方式可以访问。
**
在这里插入图片描述
注意:①method属性中的值是一个数组,这个数组类型是一个枚举类。所以使用大括号写method的属性值。
②当requestMapping指定多个属性值时,需要使用属性名=属性值的形式。中间用逗号隔开。
Params使用实例:要求请求发送时,必须携带参数,否则无法收到请求执行方法
在这里插入图片描述
在这里插入图片描述
headers使用案例:
在这里插入图片描述
如图所示,在servlet类的requestMapping中添加headers属性,请求发送时如果没有accept请求头,就无法发送过来。
在这里插入图片描述

3.请求参数的绑定

客户端发请求过来会携带请求参数,服务器需要拿到参数,拿到参数的过程称为请求参数的绑定。例如:servlet 的getParameter拿到请求参数

3.1 理解过程

  1. 请求参数的绑定说明
    1. 绑定机制
      1. 表单提交的数据都是k=v格式的 username=haha&password=123
      2. SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
      3. 要求:提交表单的name和参数的名称是相同的
    2. 支持的数据类型
      1. 基本数据类型和字符串类型
      2. 实体类型(JavaBean)
      3. 集合数据类型(List、map集合等)
  2. 基本数据类型和字符串类型
    1. 提交表单的name和参数的名称是相同的
    2. 区分大小写
  3. 实体类型(JavaBean)
    1. 提交表单的name和JavaBean中的属性名称需要一致
    2. 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如:address.name

演示(String类型的封装):如下图所示,当href标签加入参数后,在方法中可以收到传过来的参数。这就代替了getParameter方法。
在这里插入图片描述
在这里插入图片描述
演示(JavaBean类型的封装):注意表单中的name属性必须与javaBean的属性名是相同的。因为springMVC会找set方法,如果写的不一致,set方法找不到,就无法封装。
1.编写account类和user类

package cn.itcast.domain;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

public class Account implements Serializable{

    private String username;
    private String password;
    private Double money;
    private User user;
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }


    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "Account{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", money=" + money +
                ", user=" + user 
              
                '}';
    }
}

package cn.itcast.domain;

import java.io.Serializable;
import java.util.Date;

public class User implements Serializable{

    private String uname;
    private Integer age;

    private Date date;

    public String getUname() {
        return uname;
    }

    public void setUname(String uname) {
        this.uname = uname;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "User{" +
                "uname='" + uname + '\'' +
                ", age=" + age +
                ", date=" + date +
                '}';
    }

2.在index.jsp中输入form标签。注意:用户姓名和用户年龄的name属性值应该写成user.uname和user.age的形式
在这里插入图片描述
3. 在Controller类中测试

package cn.itcast.controller;

import cn.itcast.domain.Account;
import cn.itcast.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

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

/**
 * 请求参数绑定
 */
@Controller
@RequestMapping("/param")
public class ParamController {

    /**
     * 请求参数绑定入门
     * @return
     */
    @RequestMapping("/testParam")
    public String testParam(String username,String password){
        System.out.println("执行了...");
        System.out.println("用户名:"+username);
        System.out.println("密码:"+password);
        return "success";
    }

    /**
     * 请求参数绑定把数据封装到JavaBean的类中
     * @return
     */
    @RequestMapping("/saveAccount")
    public String saveAccount(Account account){
        System.out.println("执行了...");
        System.out.println(account);
        return "success";
    }

注意:post中文乱码问题的解决方式-提供过滤器解决


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

演示:集合类型的封装

在这里插入图片描述
如图所示,红框为List(User)集合封装的书写方式
蓝框为Map(String,User)集合封装的书写方式,key为’one’

3.2 自定义类型转换器

3.2.1 问题提出

springMVC可以实现对数据类型的自动转换,但也存在着转换异常的问题。
例子:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
测试:当输入“XXXX/XX/XX”格式时,可以实现数据的封装。
在这里插入图片描述
在这里插入图片描述
当输入“XXXX-XX-XX”类型的格式时,实现不了自动封装。
在这里插入图片描述
在这里插入图片描述
为此,需要配置自定义类型转换器。

3.2.2自定义类型转换器

当程序在转换类型出错时:如果想自定义数据类型转换,可以实现Converter的接口
(1) 自定义类型转换器

package cn.itcast.utils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
/**
* 把字符串转换成日期的转换器
* @author rt
*/
public class StringToDateConverter implements Converter<String, Date>{
//S:表示接受的类型,T:表示目标类型
/**
* 进行类型转换的方法
*/
	public Date convert(String source) {
		// 判断
		if(source == null) {
			throw new RuntimeException("参数不能为空");
		}
		try {
			DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		// 解析字符串
			Date date = df.parse(source);
			return date;
	} catch (Exception e) {
			throw new RuntimeException("类型转换错误");
	}
  }
}


(2) 注册自定义类型转换器,在springmvc.xml配置文件中编写配置

在这里插入图片描述
注意!!!!!!!!!!!!需要开启自定义类型转换器。
在这里插入图片描述

3.3 在控制器中使用原生的servletAPI对象(HttpServletRequest和HttpServletResponse对象)

只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象。当访问时,就可以拿到该对象

在这里插入图片描述

4.常用注解

4.1RequestParam

作用:把请求中指定名称的参数给控制器中的形参赋值。
属性:value:请求参数中的名称
required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将会报错。

举例:
在这里插入图片描述
注意:value属性和name属性是一样的。都表示请求参数中的名称。由于required属性默认是true,所以不提供或者提供的请求参数名不是name就会报错。
在这里插入图片描述

4.2RequestBody注解

作用: 用于获得请求体内容,直接使用得到的是key=value, key=value结构的数据。
get请求方式不适用(因为get请求没有请求体)
属性:required:是否必须有请求体。默认值是:true。当取值为true时,get请求方式会报错。如果取值为false, get请求得到的是null.
举例:
在这里插入图片描述
只需要在形参body的前面加上@RequestBody注解就可以得到请求体。
在这里插入图片描述

4.3PathVariable注解

作用:用于绑定url中的占位符。例如:请求url中/delete/(id) , 这个(id)就是url占位符。
属性:
value:用于指定url占位符名称。
required:是否必须提供占位符
这个注解适用于restful的编程风格。

什么是restful编程风格?
1.请求的路径一样,可以根据不同的请求方式去执行后台的不同方法。
2.restful风格的url特点:结构清晰、符合标准、易于理解、扩展方便。
在这里插入图片描述
演示:
在这里插入图片描述


    /**
     * PathVariable注解
     * @return
     */
    @RequestMapping(value="/testPathVariable/{sid}")
    public String testPathVariable(@PathVariable(name="sid") String id){
        System.out.println("执行了...");
        System.out.println(id);
        return "success";
    }

4.4RequestHeader注解(用处不大)

作用:用于获取请求消息头
属性:value:提供消息头名称
required:是否必须有此消息头。
举例:获取Accept请求头的值
在这里插入图片描述

4.5CookieValue注解

作用:把指定cookie名称的值传入控制器方法参数。
属性:value:指定cookie的名称
required:是否必须有此cookie.
在这里插入图片描述

4.6ModelAttribute注解

该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。
出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。出现在参数上,获取指定的数据给参数赋值。
属性:
value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。
应用场景:
当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
例如:
我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。

作用:

  1. 出现在方法上:表示当前方法会在控制器方法执行前线执行。
  2. 出现在参数上:获取指定的数据给参数赋值。

应用场景:
当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
举例: 如下图所示,表示修饰的方法有返回值。首先会执行showUser方法。当请求发送过来之后,会把请求发送过来的数据进行封装,没有发送过来的数据依然保持为数据库原数据。然后再执行修改用户方法。
在这里插入图片描述

1.修饰的方法有返回值

    /**
     * ModelAttribute注解
     * @return
     */
    @RequestMapping(value="/testModelAttribute")
    public String testModelAttribute(User user){
        System.out.println("testModelAttribute执行了...");
        System.out.println(user);
        return "success";
    }
    /**
     * 该方法会先执行
*/
    @ModelAttribute
    public User showUser(String uname){
        System.out.println("showUser执行了...");
        // 通过用户查询数据库(模拟)
        User user = new User();
        user.setUname(uname);
        user.setAge(20);
        user.setDate(new Date());
        return user;
    }
     

2.修饰的方法没有返回值

   /**
     * ModelAttribute注解
     * @return
     */
    @RequestMapping(value="/testModelAttribute")
    public String testModelAttribute(@ModelAttribute("abc") User user){
        System.out.println("testModelAttribute执行了...");
        System.out.println(user);
        return "success";
    }

    @ModelAttribute
    public void showUser(String uname, Map<String,User> map){
        System.out.println("showUser执行了...");
        // 通过用户查询数据库(模拟)
        User user = new User();
        user.setUname(uname);
        user.setAge(20);
        user.setDate(new Date());
        map.put("abc",user);
    }

4.7SessionAttribute注解

作用:用于多次执行控制器方法间的参数共享
属性:value:用于指定存入的属性名称
type:用于指定存入的参数类型
举例:如下图所示,使用Model可以将key-value键值对存入到request域对象中。


    /**
     * SessionAttributes的注解
     * @return
     */
    @RequestMapping(value="/testSessionAttributes")
    public String testSessionAttributes(Model model){
        System.out.println("testSessionAttributes...");
        // 底层会存储到request域对象中
        model.addAttribute("msg","美美");
        return "success";
    }

为了将数据存储到session域对象中,加入如下注解:

@SessionAttributes(value={"msg"})   把msg=美美存入到session域对中
public class AnnoController {

用于从session域中获取数据

    /**
     * 获取值
     * @param modelMap
     * @return
     */
    @RequestMapping(value="/getSessionAttributes")
    public String getSessionAttributes(ModelMap modelMap){
        System.out.println("getSessionAttributes...");
        String msg = (String) modelMap.get("msg");
        System.out.println(msg);
        return "success";
    }

用于删除session域中的数据
如果想删除session中共享的参数,可以通过SessionStatus.setComplete(),这句只会删除通过@SessionAttribute保存到session中的参数

  /**
     * 清除
     * @param status
     * @return
     */
    @RequestMapping(value="/delSessionAttributes")
    public String delSessionAttributes(SessionStatus status){
        System.out.println("getSessionAttributes...");
        status.setComplete();
        return "success";
    }

注意:使用EI表达式时,需要让jsp知道:
<%@ page contentType=“text/html;charset=UTF-8” language=“java” isELIgnored=“false” %>

SpingMVC第二天

搭建开发环境:(和入门程序案例一样)

1.响应数据和结果视图

1.1 响应数据

1.1.1 响应数据之返回值是string类型

案例:
在这里插入图片描述
在这里插入图片描述

1.1.2 响应数据之返回值是void类型

当相应数据的返回值类型是void类型时,可以有以下三种操作:
1.使用请求转发,注意为了防止执行请求转发之后的代码,要写上return.当写请求转发的路径时,需要按照规范路径来写。不能采用返回string类型那样写。
在这里插入图片描述
2.通过重定向重新锁定位置
在这里插入图片描述
3.直接进行响应。注意再设置中文乱码的两行代码中,只写第二行代码即可。不用写第一行代码。
在这里插入图片描述
注意这三种方法都需要return.

1.1.3 响应数据之使用forward和redict关键字

注意:在redict关键字中,工程路径已经被springMVC框架自动补全,所以我们只需要写/index.jsp即可。
在这里插入图片描述

1.1.4 响应json数据之1:过滤静态资源

1.1. DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置。

1.mvc:resources标签配置不过滤
(1)location元素表示webapp目录下的包下的所有文件
(2) mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b
这里的 "/"打头表示工程路径,映射到webapp目录下。

<!-- 设置静态资源不过滤 -->
<mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 -->
<mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 -->
<mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
1.1.4 响应json数据之2:收到json数据和响应json数据

注意:json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包

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

jsp前端代码:注意:datatype是返回类型的数据。对象.属性可以得到值。
在这里插入图片描述
后台代码:

requestBody注解表示将ajax发送过来的json字符串封装到user对象中
responseBody表示把user对象转化成json字符串存放到data中。
   /**
     * 模拟异步请求响应
     */
    @RequestMapping("/testAjax")
    public @ResponseBody User testAjax(@RequestBody User user){
        System.out.println("testAjax方法执行了...");
        // 客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中
        System.out.println(user);
        // 做响应,模拟查询数据库
        user.setUsername("haha");
        user.setAge(40);
        // 做响应
        return user;
    }

1.1.5 响应之返回值是modelandview类型
    /**
     * 返回ModelAndView
     * @return
     */
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        // 创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        System.out.println("testModelAndView方法执行了...");
        // 模拟从数据库中查询出User对象
        User user = new User();
        user.setUsername("小凤");
        user.setPassword("456");
        user.setAge(30);

        // 把user对象存储到mv对象中,也会把user对象存入到request对象
        mv.addObject("user",user); modelandview对象中使用addObject方法

        // 跳转到哪个页面
        mv.setViewName("success");

        return mv;
    }

2.springMVC实现文件上传

2.1 文件上传的基本回顾


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 springmvc方式的文件上传代码实现

2.2.1 环境搭建

环境搭建过程与之前mvc传统的方式相同。
jsp前端:

<h3>文件上传</h3>
    <form action="user/fileupload1" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"/>
        <input type="submit" value="上传">
    </form>

为了能够实现文件上传,需要导入jar包

<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
2.2.2 springmvc实现文件上传的原理

在这里插入图片描述
需要注意的两个问题:
①SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的name属性名称相同。

<!-- 配置文件解析器对象,要求id名称必须是multipartResolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"/>
</bean>
2.2.3 springmvc实现文件上传的代码

index.jsp程序:

<%--
  Created by IntelliJ IDEA.
  Date: 2021/11/29
  Time: 9:07
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>文件上传</h3>
    <form action="user/fileupload1" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"/>
        <input type="submit" value="上传">
    </form>
</body>
</html>

success.jsp程序:

<%--
  Created by IntelliJ IDEA.
  User: 李昊
  Date: 2021/11/29
  Time: 9:25
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>文件上传成功!</h3>
</body>
</html>

servlet程序:

package com.lihao;

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

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.UUID;

/**
 * @author lhstart
 * @create 2021-11-29-9:08
 */
@Controller
@RequestMapping("/user")
public class servletRequest {


//    @RequestMapping("/hello")
//    public String sayHello(){
//        System.out.println("hello!");
//        return "success";
//    }

    @RequestMapping("/fileupload1")
    //注意,这里的upload必须要和index中的name属性值一致
    public String sayHello(HttpServletRequest request, MultipartFile upload) throws Exception {
        System.out.println("springmvc实现文件上传");
        //编写path目录

        /*
        在使用ServletContext.getRealPath() 时,传入的参数是从 当前servlet 部署在tomcat中的文件夹算起的相对路径,
        要以"/" 开头,否则会找不到路径,导致NullPointerException
        /表示在webapp目录下,对应到target目录下的springmvc_fileupload目录中
         */
        String path = request.getSession().getServletContext().getRealPath("/uploads/");

        //判断该路径是否存在,
        //file类的说明:
        /*
            File 类是 java.io 包中唯一代表磁盘文件本身的对象。
            File 类提供了如下三种形式构造方法。
            File(String path):如果 path 是实际存在的路径,则该 File 对象表示的是目录;如果 path 是文件名,则该 File 对象表示的是文件。
            File(String path, String name):path 是路径名,name 是文件名。
            File(File dir, String name):dir 是路径对象,name 是文件名。


         */

        //判断该路径是否存在,如果不存在,则自动创建该目录
        File file = new File(path);
        if(!file.exists()){
            //自动创建该路径的目录
            file.mkdirs();
        }

        //获取文件上传的名称
        String filename = upload.getOriginalFilename();
        //把文件上传的名称获取到唯一值
        String uuid = UUID.randomUUID().toString().replace("-","");
        filename = uuid+"_"+filename;

        upload.transferTo(new File(path,filename));



        return "success";
    }
}
2.2.4 springmvc实现跨服务器上传的代码实现
2.2.4.1 跨服务器上传的流程

在这里插入图片描述

2.2.4.2 跨服务器上传的演示

首先导入跨服务器上传需要的依赖。

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

配置两个服务器,分别为springmvc和fileupload.注意两个服务器部署的项目和端口号均不相同。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
环境搭建完成后,编写代码

<h3>跨服务器的文件上传</h3>
<form action="user/fileupload3" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上传文件"/>
</form>
 /**
     * 跨服务器文件上传
     * @return
     */
    @RequestMapping("/fileupload3")
    public String fileuoload3(MultipartFile upload) throws Exception {
        System.out.println("跨服务器文件上传...");

        // 定义上传文件服务器路径
        String path = "http://localhost:9090/uploads/";

        // 说明上传文件项
        // 获取上传文件的名称
        String filename = upload.getOriginalFilename();
        // 把文件的名称设置唯一值,uuid
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid+"_"+filename;

        // 创建客户端的对象
        Client client = Client.create();

        // 和图片服务器进行连接
        WebResource webResource = client.resource(path + filename);

        // 上传文件
        webResource.put(upload.getBytes());

        return "success";
    }

注意:在测试过程中若出现409异常,则是因为在第二个工程中的target目录下的工程目录里面没有upload文件夹导致的。

3.springmvc的异常处理

3.1 springmvc的异常处理流程

在这里插入图片描述

3.2 springmvc的异常处理演示

3.2.1 编写自定义异常类,用于做提示信息
package cn.itcast.exception;

/**
 * 自定义异常类
 */
public class SysException extends Exception{

    // 存储提示信息的
    private String message;

    public String getMessage() {
        return message;
    }

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

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

}

3.2.2 在controller程序中使用自定义异常类处理
package cn.itcast.controller;

import cn.itcast.exception.SysException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/user")
public class UserController {


    @RequestMapping("/testException")
    public String testException() throws SysException{
        System.out.println("testException执行了...");

        try {
            // 模拟异常
            int a = 10/0;
        } catch (Exception e) {
            // 打印异常信息
            e.printStackTrace();
            // 抛出自定义异常信息
            throw new SysException("查询所有用户出现错误了...");
        }



        return "success";
    }

}

3.2.3 编写异常处理器,使用异常处理器处理异常
package cn.itcast.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{

    /**
     * 处理异常业务逻辑
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @return
     */
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 获取到异常对象
        SysException e = null;
        if(ex instanceof SysException){
            e = (SysException)ex;
        }else{
            e = new SysException("系统正在维护....");
        }
        // 创建ModelAndView对象
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg",e.getMessage());
        mv.setViewName("error");
        return mv;
    }

}
3.2.4 在springmvc.xml中配置异常处理器组件
    <!--配置异常处理器-->
    <bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"/>
3.2.5编写error.jsp
<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2018/5/5
  Time: 22:28
  To change this template use File | Settings | File Templates.
--%>
注意开启不忽略ei表达式选项。
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    ${errorMsg}

</body>
</html>

4.springmvc框架中的拦截器

4.1 拦截器的概述

在这里插入图片描述

4.2拦截器的原理流程

在这里插入图片描述

4.3拦截器的代码演示

package cn.itcast.controller.cn.itcast.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 MyInterceptor1 implements HandlerInterceptor{

    /**
     * 预处理,controller方法执行前
     * return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
     * return false不放行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor1执行了...前1111");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
        return true;
    }

    /**
     * 后处理方法,controller方法执行后,success.jsp执行之前
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor1执行了...后1111");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }

    /**
     * success.jsp页面执行后,该方法会执行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor1执行了...最后1111");
    }

}

在springmvc.xml中配置拦截器类

   <!--配置拦截器-->
    <mvc:interceptors>
        <!--配置拦截器-->
        <mvc:interceptor>
            <!--要拦截的具体的方法-->
            <mvc:mapping path="/user/*"/>
            <!--配置拦截器对象-->
            <bean class="cn.itcast.controller.cn.itcast.interceptor.MyInterceptor1" />
        </mvc:interceptor>
    </mvc:interceptors>

此外,还可以实现拦截器链的配置

package cn.itcast.controller.cn.itcast.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 MyInterceptor2 implements HandlerInterceptor{

    /**
     * 预处理,controller方法执行前
     * return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
     * return false不放行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor1执行了...前2222");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
        return true;
    }

    /**
     * 后处理方法,controller方法执行后,success.jsp执行之前
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor1执行了...后2222");
        // request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
    }

    /**
     * success.jsp页面执行后,该方法会执行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyInterceptor1执行了...最后2222");
    }

}

同样在springmvc.xml中配置拦截器类

    <!--配置拦截器-->
    <mvc:interceptors>
        <!--配置拦截器-->
        <mvc:interceptor>
            <!--要拦截的具体的方法-->
            <mvc:mapping path="/user/*"/>
            <!--不要拦截的方法
            <mvc:exclude-mapping path=""/>
            -->
            <!--配置拦截器对象-->
            <bean class="cn.itcast.controller.cn.itcast.interceptor.MyInterceptor1" />
        </mvc:interceptor>

        <!--配置第二个拦截器-->
        <mvc:interceptor>
            <!--要拦截的具体的方法-->
            <mvc:mapping path="/**"/>
            <!--不要拦截的方法
            <mvc:exclude-mapping path=""/>
            -->
            <!--配置拦截器对象-->
            <bean class="cn.itcast.controller.cn.itcast.interceptor.MyInterceptor2" />
        </mvc:interceptor>
    </mvc:interceptors>

4.4拦截器中的接口方法总结

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值