SpringMVC入门

news2024/11/27 8:44:51

SpringMVC

一、SpringMVC简介

1、什么是MVC

MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分

M:Model,模型层,指工程中的JavaBean,作用是处理数据

JavaBean分为两类:

  • 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
  • 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。

V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据

C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器

MVC的工作流程: 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器

2、什么是SpringMVC

SpringMVC是Spring的一个后续产品,是Spring的一个子项目

SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、

WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目

表述层开发的首选方案

注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet

3、SpringMVC的特点

  • Spring 家族原生产品,与 IOC 容器等基础设施无缝对接

  • 基于原生的Servlet,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理

  • 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案

  • 代码清新简洁,大幅度提升开发效率

  • 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可

  • 性能卓著,尤其适合现代大型、超大型互联网项目要求

二、入门案例

1、开发环境

IDE:idea

构建工具:maven

服务器:tomcat

Spring版本:5.3.1

2、创建maven工程

①引入依赖

<dependencies>
    <!--springMVC-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <!--依赖servlet和jsp的jar包-->
    <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>

    <!--日志-->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>

    <!--测试-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
</dependencies>

注:由于 Maven 的传递性,我们不必将所有需要的包全部配置依赖,而是配置最顶端的依赖,其他靠传递性导入。

3、配置web.xml

注册SpringMVC的前端控制器DispatcherServlet

①默认配置方式

此配置作用下,SpringMVC的配置文件默认位于WEB-INF下,默认名称为<servlet-name>springMVC-servlet.xml

springMVC-servlet.xml

<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

②扩展配置方式

可通过init-param标签设置SpringMVC配置文件的位置和名称,通过load-on-startup标签设置

SpringMVC前端控制器DispatcherServlet的初始化时间

<!--配置SpringMVC提供的一个Servlet核心的前端控制器-->
<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--配置SpringMVC配置文件的位置和名称-->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:SpringMVC.xml</param-value>
    </init-param>
    <!--将DispatcherServlet的初始化时间提前到服务器启动时-->
    <load-on-startup>0</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <!--
    设置springMVC的核心控制器所能处理的请求的请求路径
    url-pattern中/和/*的区别:
        /:匹配浏览器向服务器发送的所有请求(不包括.jsp)
        /*:匹配浏览器向服务器发送的所有请求(包括.jsp)
     -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

<!--处理post请求中文乱码的配置-->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--指定字符集 encoding这个属性可以在CharacterEncodingFilter类中找到-->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

注:

url-pattern中/和/*的区别:
/:匹配浏览器向服务器发送的所有请求(不包括.jsp)
/*:匹配浏览器向服务器发送的所有请求(包括.jsp)

4、创建请求控制器

由于前端控制器对浏览器发送的请求进行了统一的处理,但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器

请求控制器中每一个处理请求的方法成为控制器方法

因为SpringMVC的控制器由一个POJO(普通的Java类)担任,因此需要通过@Controller注解将其标识为一个控制层组件,交给Spring的IOC容器管理,此时SpringMVC才能够识别控制器的存在

@Controller
public class HelloController {
}

5、创建SpringMVC的配置文件

<!--扫描控制层组件-->
<context:component-scan base-package="com.edu"/>

<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">
    <!--视图前缀-->
    <property name="prefix" value="/WEB-INF/"/>
    <!--视图后缀-->
    <property name="suffix" value=".jsp"/>
</bean>

6、测试HelloWorld

①实现对首页的访问

这个是以html结尾的文件

在请求控制器中创建处理请求的方法

//@RequestMapping注解:处理请求和控制器方法之间的映射关系
//@RequestMapping注解的value属性可以通过请求地址匹配请求,/表示的当前工程的上下文路径
//localhost:8080/springMVC/
@RequestMapping("/")
public String index() {
    //设置视图名称
    return "index";
}

②通过超链接跳转到指定页面

在主页index.jsp中设置超链接

<a href="${pageContext.request.contextPath}/hello">hello</a>

在请求控制器中创建处理请求的方法

@Controller
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        //将逻辑视图返回
        return "success";
    }
}

7、总结

浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面

三、@RequestMapping注解

1、@RequestMapping注解的功能

从注解名称上我们可以看到,@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。

SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。

2、@RequestMapping注解的位置

@RequestMapping标识一个类:设置映射请求的请求路径的初始信息

@RequestMapping标识一个方法:设置映射请求请求路径的具体信息

@Controller
@RequestMapping("/test")
public class TestRequestMappingController {
    //此时控制器方法所匹配的请求的请求路径为/test/hello
    @RequestMapping("/hello")
    public String hello() {
        return "success";
    }
}

3、@RequestMapping注解的value属性

@RequestMapping注解的value属性通过请求的请求路径匹配请求

@RequestMapping注解的value属性是一个字符串类型的数组,表示该请求映射能够匹配多个请求路径所对应的请求

@RequestMapping注解的value属性必须设置,至少通过请求路径匹配请求映射

index.jsp

<a href="${pageContext.request.contextPath}/test/hello">测试@RequestMapping注解标识的位置</a>
<a href="${pageContext.request.contextPath}/test/abc">测试@RequestMapping注解的value属性</a>

TestRequestMappingController.java

@Controller
@RequestMapping("/test")
public class TestRequestMappingController {
    //此时控制器方法所匹配的请求的请求路径为/test/hello
    //此时控制器方法所匹配的请求的请求路径为/test/abc
    @RequestMapping({"/hello", "/abc"})
    public String hello() {
        return "success";
    }
}

4、@RequestMapping注解的method属性

@RequestMapping注解的method属性通过请求的请求方式(get或post)匹配请求映射

@RequestMapping注解的method属性是一个RequestMethod类型的数组,表示该请求映射能够匹配多种请求方式的请求

若浏览器所发送的请求的请求路径和@RequestMapping注解value属性匹配,但请求方式不匹配,此时页面报错:405 - Request method ‘POST’ not supported

index.jsp

<form action="${pageContext.request.contextPath}/test/hello" method="get">
    <input type="submit" value="测试@RequestMapping注解的method属性">
</form>

TestRequestMappingController.java

@Controller
@RequestMapping("/test")
public class TestRequestMappingController {
    @RequestMapping(
    	value = {"/hello", "/abc"},
    	method = {RequestMethod.GET, RequestMethod.POST})
    public String hello() {
        return "success";
    }
}

注:

1、对于处理指定请求方式的控制器方法,SpringMVC中提供了@RequestMapping的派生注解

处理get请求的映射–>@GetMapping

处理post请求的映射–>@PostMapping

处理put请求的映射–>@PutMapping

处理delete请求的映射–>@DeleteMapping

2、常用的请求方式有get,post,put,delete

但是目前浏览器只支持get和post,若在form表单提交时,为method设置了其他请求方式的字符串(put或delete),则按照默认的请求方式get处理

若要发送put和delete请求,则需要通过spring提供的过滤器HiddenHttpMethodFilter,在RESTful部分会讲到

5、@RequestMapping注解的params属性(了解)

@RequestMapping注解的params属性通过请求的请求参数匹配请求映射,即浏览器发送的请求的请求参数必须满足param属性的设置

@RequestMapping注解的params属性是一个字符串类型的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系

“param”:要求请求映射所匹配的请求必须携带param请求参数

“!param”:要求请求映射所匹配的请求必须不能携带param请求参数

“param=value”:要求请求映射所匹配的请求必须携带param请求参数且值必须为value

“param!=value”:要求请求映射所匹配的请求可以不携带param,若携带请求参数其值一定不能是value

index.jsp

<a href="${pageContext.request.contextPath}/test/abc?username=admin">测试@RequestMapping注解的param属性</a>

TestRequestMappingController.java

@Controller
@RequestMapping("/test")
public class TestRequestMappingController {
    @RequestMapping(
    	value = {"/hello", "/abc"},
        params = {"username", "!password", "age=20", "gender!=女"})
    public String hello() {
        return "success";
    }
}

注:

若浏览器所发送的请求的请求路径和@RequestMapping注解value属性匹配,但请求参数不匹配,此时页面报错:400 - Parameter conditions “username” not met for actual request parameters

6、@RequestMapping注解的headers属性(了解)

@RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射,即浏览器发送的请求的请求头信息必须满足headers属性的设置

@RequestMapping注解的headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系

“header”:要求请求映射所匹配的请求必须携带header请求头信息

“!header”:要求请求映射所匹配的请求必须不能携带header请求头信息

“header=value”:要求请求映射所匹配的请求必须携带header请求头信息且请求头信息的值为value

“header!=value”:要求请求映射所匹配的请求可以不携带header请求头信息,若携带请求头信息其值一定不能是value

若浏览器所发送的请求的请求路径和@RequestMapping注解value属性匹配,但请求头信息不匹配,此时页面报错:404,即资源未找到

TestRequestMappingController.java

@Controller
@RequestMapping("/test")
public class TestRequestMappingController {
    @RequestMapping(
        value = {"/hello", "/abc"},
        headers = {"referer"}
    )
    public String hello() {
        return "success";
    }
}

7、SpringMVC支持ant风格的路径

在@RequestMapping注解的value属性值中设置一些特殊字符

?:表示任意的单个字符(不包括?)

*:表示任意的0个或多个字符(不包括?和/)

**:表示任意层数的任意目录

注意:

在使用**时,只能使用/**/xxx的方式

index.jsp

<a href="${pageContext.request.contextPath}/test/aba/ant">测试@RequestMapping注解支持ant风格的路径</a>

TestRequestMappingController.java

@Controller
@RequestMapping("/test")
public class TestRequestMappingController {
    @RequestMapping("/a?a/ant")
    public String testAnt() {
        return "success";
    }
}

8、SpringMVC支持路径中的占位符(重点)

原始方式:/deleteUser?id=1

rest方式:/user/delete/1

SpringMVC路径中的占位符常用于RESTful风格中,当请求路径中将某些数据通过路径的方式传输到服务器中

可以在相应的@RequestMapping注解的value属性中通过占位符{xxx}表示传输的数据,再通过@PathVariable注解,将占位符所表示的数据赋值给控制器方法的形参进行绑定

index.jsp

<a href="${pageContext.request.contextPath}/test/rest/admin/1">测试@RequestMapping注解的value属性中的占位符</a>

TestRequestMappingController.java

@Controller
@RequestMapping("/test")
public class TestRequestMappingController {
    @RequestMapping("/rest/{username}/{id}")
    public String testRest(@PathVariable("id") Integer id, @PathVariable("username") String username) {
        System.out.println("id:" + id + " username:" + username);
        return "success";
    }
}
//id:1 username:admin

四、SpringMVC获取请求参数

1、通过ServletAPI获取

在控制器方法的形参位置设置HttpServletRequest类型的形参,就可以在控制器方法中使用request对象获取请求参数

index.jsp

<form action="${pageContext.request.contextPath}/param/servletAPI" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录"><br>
</form>

TestParamController.java

@Controller
@RequestMapping("param")
public class TestParamController {
    @RequestMapping("/servletAPI")
    public String getParamServletAPI(HttpServletRequest request) {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println(username + " -- " + password);
        return "success";
    }
}
//jack -- 123456

2、通过控制器方法的形参获取请求参数

在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参

index.jsp

<form action="${pageContext.request.contextPath}/param" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录"><br>
</form>

TestParamController.java

@Controller
public class TestParamController {
    @RequestMapping("/param")
    public String getParam(String username,String password) {
        System.out.println(username + " -- " + password);
        return "success";
    }
}
//smith -- 000000

注:

若请求所传输的请求参数中有多个同名的请求参数,此时可以在控制器方法的形参中设置字符串数组或者字符串类型的形参接收此请求参数

若使用字符串数组类型的形参,此参数的数组中包含了每一个数据

若使用字符串类型的形参,此参数的值为每个数据中间使用逗号拼接的结果

3、@RequestParam

@RequestParam是将请求参数和控制器方法的形参创建映射关系

@RequestParam注解一共有三个属性:

​ value:设置和形参绑定的请求参数的参数名

​ required:设置是否必须传输value所对应的请求参数,默认值为true

若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue属性,则页面报错400:Required String parameter ‘xxx’ is not present;

若设置为false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为null

​ defaultValue:设置当没有传输value所对应的请求参数时,为形参设置的默认值,此时和required属性值无关

index.jsp

<form action="${pageContext.request.contextPath}/param" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录"><br>
</form>

TestParamController.java

@Controller
public class TestParamController {
    @RequestMapping("/param")
    public String getParam(
    	@RequestParam(value = "userName", required = true, defaultValue = "hello") String username,
        String password) {
        System.out.println(username + " -- " + password);
        return "success";
    }
}

4、@RequestHeader

@RequestHeader是将请求头信息和控制器方法的形参创建映射关系

@RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam

index.jsp

<form action="${pageContext.request.contextPath}/param" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录"><br>
</form>

TestParamController.java

@Controller
public class TestParamController {
    @RequestMapping("/param")
    public String getParam(
            String username,
            String password,
            @RequestHeader(value = "referer") String referer) {
        System.out.println("referer:" + referer);
        return "success";
    }
}
//  referer:http://localhost:8080/springmvc_demo_war/

5、@CookieValue

@CookieValue是将cookie数据和控制器方法的形参创建映射关系

@CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam

index.jsp

<form action="${pageContext.request.contextPath}/param" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录"><br>
</form>

TestParamController.java

@Controller
public class TestParamController {
     @RequestMapping("/sessionTest")
    public String getSessionTest(HttpServletRequest request) {
        HttpSession session = request.getSession();
        return "success";
    }
    
    @RequestMapping("/param")
    public String getParam(
            String username,
            String password,
            String referer,
            @CookieValue("JSESSIONID") String jsessionId) {
        System.out.println("jsessionId:" + jsessionId);
        return "success";
    }
}
// jsessionId:8A525FF358633CD1159F0CB7EA0DFD2A

6、通过POJO获取请求参数

可以在控制器方法的形参位置设置一个实体类类型的形参,此时若浏览器传输的请求参数的参数名和实体类中的属性名一致,那么请求参数就会为此属性赋值

User.java

@Data
public class User {
    private Integer id;
    private String username;
    private String password;
}

index.jsp

<form action="${pageContext.request.contextPath}/param/pojo" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录"><br>
</form>

TestParamController.java

@Controller
public class TestParamController {
    @RequestMapping("/param/pojo")
    public String getParamByPojo(User user) {
        System.out.println(user);
        return "success";
    }
}
// User(id=null, username=jack, password=123)

7、解决获取请求参数的乱码问题

解决获取请求参数的乱码问题,可以使用SpringMVC提供的编码过滤器CharacterEncodingFilter,但是必须在web.xml中进行注册

<!--配置springMVC的编码过滤器-->
<!--处理post请求中文乱码的配置-->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--指定字符集 encoding这个属性可以在CharacterEncodingFilter类中找到-->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

注:

SpringMVC中处理编码的过滤器一定要配置到其他过滤器之前,否则无效

五、域对象共享数据

1、使用ServletAPI向request域对象共享数据

@Controller
public class TestScopeController {
    @RequestMapping("/testServletAPI")
    public String testServletAPI(HttpServletRequest request) {
        request.setAttribute("testScope", "hello,servletAPI");
        return "success";
    }
}

2、使用ModelAndView向request域对象共享数据

index.jsp

<a href="${pageContext.request.contextPath}/test/mav">测试通过ModelAndView向请求域共享数据</a>

TestScopeController.java

@Controller
public class TestScopeController {
    @RequestMapping("/test/mav")
    public ModelAndView testMAV() {
        /**
         * ModelAndView有Model和View的功能
         * Model主要用于向请求域共享数据
         * View主要用于设置视图,实现页面跳转
         */
        ModelAndView mav = new ModelAndView();
        //向请求域中共享数据
        mav.addObject("testRequestScope","hello,ModelAndView");
        //设置逻辑视图
        mav.setViewName("success");
        return mav;
    }
}

success.jsp

<h2>${testRequestScope}</h2>

3、使用Model向request域对象共享数据

index.jsp

<a href="${pageContext.request.contextPath}/test/model">测试通过Model向请求域共享数据</a>

TestScopeController.java

@Controller
public class TestScopeController {
    @RequestMapping("/test/model")
    public String testModel(Model model) {
        System.out.println(model.getClass().getName());
        //org.springframework.validation.support.BindingAwareModelMap

        //向请求域中共享数据
        model.addAttribute("testRequestScope", "hello,Model");
        return "success";
    }
}

success.jsp

<h2>${testRequestScope}</h2>

4、使用ModelMap向request域对象共享数据

index.jsp

<a href="${pageContext.request.contextPath}/test/modelMap">测试通过ModelMap向请求域共享数据</a>

TestScopeController.java

@Controller
public class TestScopeController {
    @RequestMapping("/test/modelMap")
    public String testModelMap(ModelMap modelMap) {
        System.out.println(modelMap.getClass().getName());
        //org.springframework.validation.support.BindingAwareModelMap

        //向请求域中共享数据
        modelMap.addAttribute("testRequestScope", "hello,ModelMap");
        return "success";
    }
}

success.jsp

<h2>${testRequestScope}</h2>

5、使用map向request域对象共享数据

index.jsp

<a href="${pageContext.request.contextPath}/test/map">测试通过Map向请求域共享数据</a>

TestScopeController.java

@Controller
public class TestScopeController {
    @RequestMapping("/test/map")
    public String testMap(Map<String, Object> map) {
        System.out.println(map.getClass().getName());
        //org.springframework.validation.support.BindingAwareModelMap

        //向请求域中共享数据
        map.put("testRequestScope", "hello,Map");
        return "success";
    }
}

success.jsp

<h2>${testRequestScope}</h2>

6、Model、ModelMap、Map的关系

Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的

public interface Model{}
public class ModelMap extends LinkedHashMap<String, Object> {}
public class ExtendedModelMap extends ModelMap implements Model {}
public class BindingAwareModelMap extends ExtendedModelMap {}

7、向session域共享数据

index.jsp

<a href="${pageContext.request.contextPath}/test/session">测试向会话域共享数据</a>

TestScopeController.java

@Controller
public class TestScopeController {
    @RequestMapping("/test/session")
    public String testSession(HttpSession session) {
        session.setAttribute("testSessionScope","hello,session");
        return "success";
    }
}

success.jsp

<h2>${sessionScope.testSessionScope}</h2>

8、向application域共享数据

index.jsp

<a href="${pageContext.request.contextPath}/test/application">测试向应用域共享数据</a>

TestScopeController.java

@Controller
public class TestScopeController {
    @RequestMapping("/test/application")
    public String testApplication(HttpSession session) {
        ServletContext servletContext = session.getServletContext();
        servletContext.setAttribute("testApplicationScope","hello,application");
        return "success";
    }
}

success.jsp

<h2>${applicationScope.testApplicationScope}</h2>

六、SpringMVC的视图

SpringMVC中的视图是View接口,视图的作用渲染数据,将模型Model中的数据展示给用户

SpringMVC视图的种类很多,默认有转发视图和重定向视图

当工程引入jstl的依赖,转发视图会自动转换为JstlView

若使用的视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视图解析器解析之后所得到的是ThymeleafView

1、ThymeleafView

当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置的视图解析器解析,视图名称拼接视图前缀和视图后缀所得到的最终路径,会通过转发的方式实现跳转

index.jsp

<a href="${pageContext.request.contextPath}/test/view/thymeleaf">测试SpringMVC的视图ThymeleafView</a>

TestViewController.java

@Controller
@RequestMapping("/test/view")
public class TestViewController {
    @RequestMapping("/thymeleaf")
    public String testThymeleafView(){
        return "success";
    }
}

2、转发视图

SpringMVC中默认的转发视图是InternalResourceView

SpringMVC中创建转发视图的情况:

当控制器方法中所设置的视图名称以"forward:"为前缀时,创建InternalResourceView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"forward:"去掉,剩余部分作为最终路径通过转发的方式实现跳转

index.jsp

<a href="${pageContext.request.contextPath}/test/view/forward">测试SpringMVC的视图InternalResourceView</a>

TestViewController.java

@Controller
@RequestMapping("/test/view")
public class TestViewController {
    @RequestMapping("/forward")
    public String testInternalResourceView(){
        return "forward:/WEB-INF/success.jsp";
    }
}

3、重定向视图

SpringMVC中默认的重定向视图是RedirectView

当控制器方法中所设置的视图名称以"redirect:"为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"redirect:"去掉,剩余部分作为最终路径通过重定向的方式实现跳转

index.jsp

<a href="${pageContext.request.contextPath}/test/view/redirect">测试SpringMVC的视图RedirectView</a>

TestViewController.java

@Controller
@RequestMapping("/test/view")
public class TestViewController {
    @RequestMapping("/redirect")
    public String testRedirectView() {
        return "redirect:/test/model";
    }
}

注:

重定向视图在解析时,会先将redirect:前缀去掉,然后会判断剩余部分是否以/开头,若是则会自动拼接上下文路径

4、视图控制器view-controller

当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用mvc:view-controller标签进行表示

<!--
    视图控制器:为当前的请求直接设置视图名称实现页面跳转
    path:设置处理的请求地址
    view-name:设置请求地址所对应的视图名称
-->
<mvc:view-controller path="/testViewSuccess" view-name="success"/>

<!--开启springmvc的注解驱动-->
<mvc:annotation-driven/>

注:

当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签:<mvc:annotation-driven />

七、RESTful

1、RESTful简介

REST:Representational State Transfer,表现层资源状态转移。

①资源

资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端应用开发者能够理解。与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个资源可以由一个或多个URI来标识。URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互。

②资源的表述

资源的表述是一段对于资源在某个特定时刻的状态的描述。可以在客户端-服务器端之间转移(交换)。资源的表述可以有多种格式,例如HTML/XML/JSON/纯文本/图片/视频/音频等等。资源的表述格式可以通过协商机制来确定。请求-响应方向的表述通常使用不同的格式。

③状态转移

状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述,来间接实现操作资源的目的。

2、RESTful的实现

具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。

它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE用来删除资源。

REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性。

操作传统方式*REST***风格
查询操作getUserById?id=1user/1–>get请求方式
保存操作saveUseruser–>post请求方式
删除操作deleteUser?id=1user/1–>delete请求方式
更新操作updateUseruser–>put请求方式

3、HiddenHttpMethodFilter

由于浏览器只支持发送get和post方式的请求,那么该如何发送put和delete请求呢?

SpringMVC 提供了 HiddenHttpMethodFilter 帮助我们将 POST 请求转换为DELETE或PUT 请求

HiddenHttpMethodFilter 处理put和delete请求的条件:

a>当前请求的请求方式必须为post
b>当前请求必须传输请求参数_method,_method的值才是最终的请求方式

在web.xml中注册HiddenHttpMethodFilter

<!--设置处理请求方式的过滤器-->
<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

注:

目前为止,SpringMVC中提供了两个过滤器:CharacterEncodingFilter和

HiddenHttpMethodFilter

在web.xml中注册时,必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter

原因:

  • 在 CharacterEncodingFilter 中通过request.setCharacterEncoding(encoding) 方法设置字符集的

  • request.setCharacterEncoding(encoding) 方法要求前面不能有任何获取请求参数的操作

  • 而 HiddenHttpMethodFilter 恰恰有一个获取请求方式的操作:

  • String paramValue = request.getParameter(this.methodParam);
    

4、RESTful的实现

①查询所有的用户信息–>/user–>get

index.jsp

<a href="${pageContext.request.contextPath}/user">查询所有用户信息</a><br>

TestRestController.java

@Controller
public class TestRestController {
    //@RequestMapping(value = "/user", method = RequestMethod.GET)
    @GetMapping("/user")
    public String getAllUser() {
        System.out.println("查询所有的用户信息 --> /user --> get");
        return "success";
    }
}

②根据id查询用户信息–>/user/1–>get

index.jsp

<a href="${pageContext.request.contextPath}/user/1">根据id查询用户信息</a><br>

TestRestController.java

@Controller
public class TestRestController {
    //@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
    @GetMapping("/user/{id}")
    public String getUserById(@PathVariable("id") Integer id) {
        System.out.println("根据id查询用户信息 --> /user/" + id + " --> get");
        return "success";
    }
}

③添加用户信息–>/user–>post

index.jsp

<form action="${pageContext.request.contextPath}/user" method="post">
    <input type="submit" value="添加用户">
</form>

TestRestController.java

@Controller
public class TestRestController {
    //@RequestMapping(value = "/user", method = RequestMethod.POST)
    @PostMapping("/user")
    public String insertUser() {
        System.out.println("添加用户信息 --> /user --> post");
        return "success";
    }
}

④修改用户信息–>/user–>put

index.jsp

<form action="${pageContext.request.contextPath}/user" method="post">
    <input type="hidden" name="_method" value="put">
    <input type="submit" value="修改用户">
</form>

TestRestController.java

@Controller
public class TestRestController {
	//@RequestMapping(value = "/user", method = RequestMethod.PUT)
    @PutMapping("/user")
    public String updateUser() {
        System.out.println("修改用户信息 --> /user --> put");
        return "success";
    }
}

⑤删除用户信息–>/user/1–>delete

index.jsp

<form action="${pageContext.request.contextPath}/user/1" method="post">
    <input type="hidden" name="_method" value="delete">
    <input type="submit" value="删除用户">
</form>

TestRestController.java

@Controller
public class TestRestController {
    //@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
    @DeleteMapping("/user/{id}")
    public String deleteUser(@PathVariable("id") Integer id) {
        System.out.println("删除用户信息 --> /user/" + id + " --> delete");
        return "success";
    }
}

八、SpringMVC处理ajax请求

1、@RequestBody

@RequestBody可以获取请求体信息,使用@RequestBody注解标识控制器方法的形参,当前请求的请求体就会为当前注解所标识的形参赋值

index.jsp

<!--此时必须使用post请求方式,因为get请求没有请求体-->
<form action="${pageContext.request.contextPath}/test/requestBody" method="post">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit">
</form>

TestAjaxController.java

@Controller
public class TestAjaxController {
    @RequestMapping("/test/requestBody")
    public String testRequestBody(@RequestBody String requestBody){
        System.out.println("requestBody:"+requestBody);
        return "success";
    }
}

2、@RequestBody获取并处理json格式的请求参数

在SpringMVC中,直接使用@RequestBody注解标识控制器方法的形参即可将此类请求参数转换为java对象

使用@RequestBody获取json格式的请求参数的条件:

①导入jackson的依赖

<!--json转换器-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.0</version>
</dependency>

②SpringMVC的配置文件中设置开启mvc的注解驱动

<!--开启mvc的注解驱动-->
<mvc:annotation-driven />

③在控制器方法的形参位置,设置json格式的请求参数要转换成的java类型(实体类或map)的参数,并使用@RequestBody注解标识

index.jsp

<head>
    <script src="${pageContext.request.contextPath}/js/jquery-3.4.1.js"></script>
</head>

<body>

<button id="btn">使用@RequestBody注解处理JSON格式的请求参数</button>
<script>
    $(function () {
        
        $('#btn').click(function () {
            $.ajax({
                url: "${pageContext.request.contextPath}/test/requestBody/json", //请求后台路径
                type: "post", //请求方式
                contentType: "application/json;charset=UTF-8", //发送信息至服务器时内容编码类型
                //给后台发送json数据,注意json语法,最外面用''单引号引起来,里面的键值用双引号引起来,而且json用紧凑格式
                data: '{"username":"张三","password":"123456","age":100,"gender":"男"}',
                dataType: "json",//预期服务器返回的数据类型。我们让服务器返回json格式
                success: function (data) { //服务器成功响应后的,回调函数
                    console.log(data)
                }
            });
        });

    });
</script>

</body>

TestAjaxController.java

@Controller
public class TestAjaxController {

    //实体类
    @RequestMapping("/test/requestBody/json")
    public void testRequestBody(@RequestBody User user, HttpServletResponse response) throws IOException {
        System.out.println(user);
        //User(username=张三, password=123456, age=100, gender=男)
        response.getWriter().write("hello,requestBody");
    }

    //Map
    @RequestMapping("/test/requestBody/json")
    public void testRequestBody(@RequestBody Map<String, Object> map, HttpServletResponse response) throws IOException {
        System.out.println(map);
        //{username=张三, password=123456, age=100, gender=男}
        response.getWriter().write("hello,requestBody");
    }

}

3、@ResponseBody

@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器

@RequestMapping("/testResponseBody")
public String testResponseBody(){
    //此时会跳转到逻辑视图success所对应的页面
    return "success";
}

@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
    //此时响应浏览器数据success
    return "success";
}

4、@ResponseBody响应浏览器json数据

服务器处理ajax请求之后,大多数情况都需要向浏览器响应一个java对象,此时必须将java对象转换为json字符串才可以响应到浏览器,之前我们使用操作json数据的jar包gson或jackson将java对象转换为json字符串。在SpringMVC中,我们可以直接使用@ResponseBody注解实现此功能

@ResponseBody响应浏览器json数据的条件:

①导入jackson的依赖

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.1</version>
</dependency>

②SpringMVC的配置文件中设置开启mvc的注解驱动

<!--开启mvc的注解驱动-->
<mvc:annotation-driven />

③使用@ResponseBody注解标识控制器方法,在方法中,将需要转换为json字符串并响应到浏览器的java对象作为控制器方法的返回值,此时SpringMVC就可以将此对象直接转换为json字符串并响应到浏览器

index.jsp

<head>
    <script src="${pageContext.request.contextPath}/js/jquery-3.4.1.js"></script>
</head>
    
<body>
<button id="btn3">测试@ResponseBody响应浏览器json格式的数据</button><br>

<script>
    $(function () {
        
        $('#btn').click(function () {
            $.ajax({
                url: "${pageContext.request.contextPath}/test/responseBody/json", //请求后台路径
                type: "post", //请求方式
                contentType: "application/json;charset=UTF-8", //发送信息至服务器时内容编码类型
                dataType: "json",//预期服务器返回的数据类型。我们让服务器返回json格式
                success: function (data) { //服务器成功响应后的,回调函数
                    console.log(data)
                }
            });
        });

    });
</script>
</body>

TestAjaxController.java

@Controller
public class TestAjaxController {
    //封装成实体类
    @RequestMapping("/test/responseBody/json")
    @ResponseBody
    public User testResponseBodyJson() {
        User user = new User(1001, "admin", "123456", 20, "男");
        return user;
    }

    //封装成Map集合
    @RequestMapping("/test/responseBody/json")
    @ResponseBody
    public Map<String,Object> testResponseBodyJson() {
        User user1 = new User(1001, "admin1", "123456", 20, "男");
        User user2 = new User(1002, "admin2", "123456", 20, "男");
        User user3 = new User(1003, "admin3", "123456", 20, "男");

        HashMap<String, Object> map = new HashMap<>();
        map.put("1001",user1);
        map.put("1002",user2);
        map.put("1003",user3);
        return map;
    }

    //封装成List集合
    @RequestMapping("/test/responseBody/json")
    @ResponseBody
    public List<User> testResponseBodyJson() {
        User user1 = new User(1001, "admin1", "123456", 20, "男");
        User user2 = new User(1002, "admin2", "123456", 20, "男");
        User user3 = new User(1003, "admin3", "123456", 20, "男");

        List<User> list = new ArrayList<>();
        list.add(user1);
        list.add(user2);
        list.add(user3);
        return list;
    }
}

5、@RestController注解

@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解。

@RestController相当于@Controller+@ResponseBody

九、文件上传和下载

1、文件下载

ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文

使用ResponseEntity实现下载文件的功能

index.jsp

<a href="${pageContext.request.contextPath}/test/down">下载图片</a><br>

FileUpAndDownController.java

@Controller
public class FileUpAndDownController {
    @RequestMapping("/test/down")
    public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
        //获取ServletContext对象
        ServletContext servletContext = session.getServletContext();
        //获取服务器中文件的真实路径
        String realPath = servletContext.getRealPath("/img/dog.webp");
        //创建输入流
        InputStream is = new FileInputStream(realPath);
        //创建字节数组  is.available()获取输入流所对应文件的字节数
        byte[] bytes = new byte[is.available()];
        //将流读到字节数组中
        is.read(bytes);
        //创建HttpHeaders对象设置响应头信息
        MultiValueMap<String, String> headers = new HttpHeaders();
        //设置要下载方式以及下载文件的名字
        headers.add("Content-Disposition", "attachment;filename=dog.webp");
        //设置响应状态码
        HttpStatus statusCode = HttpStatus.OK;
        //创建ResponseEntity对象
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
        //关闭输入流
        is.close();
        return responseEntity;
    }
}

2、文件上传

文件上传要求:

form表单的请求方式必须为post,并且添加属性enctype=“multipart/form-data”

SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息

上传步骤:

①添加依赖:

<!--上传文件所需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>

②在SpringMVC的配置文件中添加配置:

<!-- 配置文件解析器对象,要求id名称必须是multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--限制上传文件的大小 单位是字节-->
    <property name="maxUploadSize" value="#{1024*1024*10}"/>
</bean>

③控制器方法:

index.jsp

<form action="${pageContext.request.contextPath}/test/up" enctype="multipart/form-data" method="post">
    图像:<input type="file" name="photo"><br>
    <input type="submit" value="上传">
</form>

FileUpAndDownController.java

@Controller
public class FileUpAndDownController {
    @RequestMapping("/test/up")
    public String testUp(MultipartFile photo, HttpSession session) throws IOException {
        //获取上传的文件的文件名
        String fileName = photo.getOriginalFilename();
        //处理文件重名问题
        String hzName = fileName.substring(fileName.lastIndexOf("."));
        fileName = UUID.randomUUID().toString() + hzName;
        //获取servletContext对象
        ServletContext servletContext = session.getServletContext();
        //获取当前工程下photo目录的路径
        String photoPath = servletContext.getRealPath("img");
        //创建photoPath所对应的File对象
        File file = new File(photoPath);
        //判断file所对应目录是否存在
        if(!file.exists()){
            file.mkdir();
        }
        String finalPath = photoPath + File.separator + fileName;
        //实现上传功能
        photo.transferTo(new File(finalPath));
        return "success";
    }
}

十、拦截器

1、拦截器的配置

SpringMVC中的拦截器用于拦截控制器方法的执行

SpringMVC中的拦截器需要实现HandlerInterceptor

SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置:

<!--配置拦截器-->
<mvc:interceptors>
    <!--1.根据bean配置拦截器-->
    <mvc:interceptor>
        <!--配置需要拦截的请求的请求路径 /** 拦截所有-->
        <mvc:mapping path="/**"/>
        <!--配置不需要拦截的请求的请求路径-->
        <mvc:exclude-mapping path="/success"/>
        <!--注册自定义拦截器-->
        <bean class="com.edu.interceptor.FirstInterceptor" id="firstInterceptor"/>
    </mvc:interceptor>
    <!--2.根据注解配置拦截器-->
    <ref bean="secondInterceptor"/>
</mvc:interceptors>

2、拦截器的三个抽象方法

SpringMVC中的拦截器有三个抽象方法:

preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法

postHandle:控制器方法执行之后执行postHandle()

afterCompletion:处理完视图和模型数据,渲染视图完毕之后执行afterCompletion()

public class FirstInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("在控制器方法执行之前执行");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("在控制器方法执行之后执行");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("在控制器方法执行之后,且渲染视图完毕之后执行");
    }
}

3、多个拦截器的执行顺序

①若每个拦截器的preHandle()都返回true

此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:

preHandle()会按照配置的顺序执行,而postHandle()和afterCompletion()会按照配置的反序执行

拦截器1 拦截器2
preHandle1 preHandle2 
postHandle2 postHandle1 
afterCompletion2 afterCompletion1

②若某个拦截器的preHandle()返回了false

preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的拦截器的afterCompletion()会执行

拦截器1  拦截器2(false)
preHandle1 preHandle2 
afterCompletion1

十一、异常处理器

1、基于配置的异常处理

SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver

HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和

SimpleMappingExceptionResolver

SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,使用方式:

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <!--
            	key表示处理器方法执行过程中出现的异常
            	value表示若出现指定异常时,设置一个新的视图名称,跳转到指定页面
            -->
            <prop key="java.lang.ArithmeticException">error</prop>
        </props>
    </property>
    <!--
		exceptionAttribute属性设置一个属性名,将出现的异常信息在请求域中进行共享
	-->
    <property name="exceptionAttribute" value="ex"></property>
</bean>

error.jsp

<body>
    <h1>error.jsp</h1>
    <p>${ex}</p>
</body>

TestController.java

@Controller
public class TestController {
    @RequestMapping("/test")
    public String test() {
        int i = 1 / 0;
        return "success";
    }
}

2、基于注解的异常处理

//将当前类标识为异常处理的组件
@ControllerAdvice
public class ExceptionController {
    //@ExceptionHandler设置要处理的异常信息
    @ExceptionHandler(ArithmeticException.class)
    //ex表示控制器方法所出现的异常
    public String handleArithmeticException(Exception ex, Model model) {
        model.addAttribute("ex", ex);
        return "error";
    }
}

十二、SpringMVC执行流程

1、SpringMVC常用组件

1.DispatcherServlet:前端控制器 
	不需要工程师开发,由框架提供
	用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,相当于是SpringMVC的大脑,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
	
2.HandlerMapping:处理器映射器
	不需要工程师开发,由框架提供
	HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
	
3.Handler:处理器
	需要工程师开发
	Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
	由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。这里所说的Handler就是我们自己编写的Controller

5.HandlAdapter:处理器适配器
	不需要工程师开发,由框架提供
	通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
     
6.ViewResolver:视图解析器
	不需要工程师开发,由框架提供
	View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。

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

说明:

在springmvc的各个组件中,处理器映射器、处理器适配器、视图解析器称为springmvc的三大组件。
需要用户开发的组件有handler、view

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

相当于在xml中配置了: 
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" id="handlerMapping"/> 
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" id="handlerAdapter"/> 

2、执行流程

请添加图片描述

1、	用户发送请求至前端控制器DispatcherServlet
2、	DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、	HandlerMapping处理器映射器根据请求url找到具体的处理器(也就是我们所说的Controller),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、	DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
5、	执行处理器(Controller,也叫后端控制器,也就是我们自己编写的Controller)。
6、	Controller执行完成返回ModelAndView
7、	HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
8、	DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9、	ViewReslover解析后返回具体View
10、	DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
11、	DispatcherServlet响应用户

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/51731.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件工程SSM毕设项目 - 基于SSM的中药店商城网站(含源码+论文)

文章目录1 项目简介2 实现效果2.1 界面展示3 设计方案3.1 概述3.2 系统流程3.3 系统结构设计4 项目获取1 项目简介 Hi&#xff0c;各位同学好呀&#xff0c;这里是M学姐&#xff01; 今天向大家分享一个今年(2022)最新完成的毕业设计项目作品&#xff0c;【基于SSM的中药店商…

微信小程序能给花店带来哪些作用_分享花店微信小程序开发优势

在开发过小程序的线下实体店铺中&#xff0c;有不少花店。开发了小程序的花店纷纷表示&#xff1a;"小程序提供了非常大的帮助&#xff0c;现在越来越离不开小程序了"。那么&#xff0c;小程序能给花店带来哪些帮助&#xff1f; 1、提升店铺曝光半径挖掘更多流量 对…

哈希表题目:键盘行

文章目录题目标题和出处难度题目描述要求示例数据范围解法思路和算法代码复杂度分析题目 标题和出处 标题&#xff1a;键盘行 出处&#xff1a;500. 键盘行 难度 2 级 题目描述 要求 给你一个字符串数组 words\texttt{words}words&#xff0c;只返回可以使用在美式键盘…

Scala集合习题Ⅱ

行是知之始&#xff0c;知是行之成。——陶行知 目录 练习题 3 &#xff1a;求出各城市的平均温度 练习题4&#xff1a;请用scala得出以下的结果 练习题 3 &#xff1a;求出各城市的平均温度 val d1 Array(("bj", 28.1), ("sh", 28.7), ("gz"…

RK3588平台开发系列讲解(PWM篇)PWM及backlight的使用方法

平台内核版本安卓版本RK3588Linux 5.10Android12🚀返回专栏总目录 文章目录 一、PWM驱动二、DTS配置三、PWM在user space的使用四、PWM在背光中的使用4.1 Backlight DTS4.2 PWM Backlight 调试沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍PWM以及backli…

SpringBoot结合Quartz实现定时任务

《从零打造项目》系列文章 工具 比MyBatis Generator更强大的代码生成器 ORM框架选型 SpringBoot项目基础设施搭建SpringBoot集成Mybatis项目实操SpringBoot集成MybatisPlus项目实操SpringBoot集成Spring Data JPA项目实操 数据库变更管理 数据库变更管理&#xff1a;Liquibase…

深入讲解Netty那些事儿之从内核角度看IO模型(上)

我们都知道Netty是一个高性能异步事件驱动的网络框架。 它的设计异常优雅简洁&#xff0c;扩展性高&#xff0c;稳定性强。拥有非常详细完整的用户文档。 同时内置了很多非常有用的模块基本上做到了开箱即用&#xff0c;用户只需要编写短短几行代码&#xff0c;就可以快速构建…

8、python中的模块和包

文章目录模块模块导入的方式直接导入部分导入import module 和from module import *的区别模块的其他信息_ _ name _ _ 的特殊使用模块的分类包从包中导入模块的方式模块 模块就是工具包,要想使用这个工具包中的工具(就好比函数),就需要导入这个模块 模块是非常简单的Python文…

pandas交叉表与透视表pd.crosstab()和pd.pivot_table()函数详解

一、交叉表 交叉表&#xff1a;用于计算一列数据对于另外一列数据的分组个数(用于统计分组频率的特殊透视表)&#xff0c;pd.crosstab(value1, value2)pandas.crosstab(index, columns, valuesNone, rownamesNone, colnamesNone, aggfuncNone, marginsFalse, margins_nameAll,…

【虚幻引擎】UE4/UE5 动画蓝图,混合空间,目标偏移,动画蒙太奇之间的联系

一、UE动画介绍 虚幻引擎在为角色设置移动行走时&#xff0c;为了更好的调节和控制人物的相关动画&#xff0c;设置了一系列的跟人物相关的动画&#xff0c;其中包括一维混合空间&#xff0c;二维混合空间&#xff0c;动画蒙太奇&#xff0c;目标偏移等&#xff0c;动画蓝图的出…

Day16--加入购物车-动态设置tabBar的数组徽标

问题1&#xff1a; ①&#xff1a;刚开始 ②&#xff1a;点击购物车的图标后&#xff0c;跳转到cart页面发现&#xff0c;并没有徽标在tabbar上&#xff1a; 提纲挈领&#xff1a; 我的操作&#xff1a; 1》把 Store 中的 total 映射到 cart.vue 中使用&#xff1a; 2》在页面…

Java ArrayLIst与顺序表

什么是集合类&#xff1f; Java当中的集合类&#xff0c;其实就是封装号的数据结构 原始的数据结构——>Java当中封装成的集合对应的那个原始的数据结构——>用Java封装的集合对应的。 集合类所在的包&#xff1a;java.util这个包底下 顺序表的底层是一个数组&#xff0…

Flutter状态管理

前言 状态管理是什么&#xff1f;简单的来说&#xff0c;就是当某个状态发生变化的时候&#xff0c;告知该状态的监听者&#xff0c;让状态所监听的属性随之而改变&#xff0c;达到UI层随着数据层变化而变化的效果。在Flutter中的状态(State)是一个组件的UI数据模型&#xff0…

【MySQL 读写分离】Sharding JDBC + Spring boot 实现数据库读写分离的登录 Demo

上篇文章我们搭建了 MySQL 数据库主从复制集群 MySQL 搭建主从复制集群~~~ 本篇文章我们利用搭建好的主从复制集群&#xff0c;使用 SpringBoot 结合 Sharding-JDBC 搭建一个小的 登录 Demo&#xff0c;测试实现数据库的读写分离 项目源码地址&#xff1a; https://gitee.com/l…

13 【操作mysql数据库】

13 【操作mysql数据库】 1.mysql 介绍 付费的商用数据库&#xff1a; Oracle&#xff0c;典型的高富帅&#xff1b;SQL Server&#xff0c;微软自家产品&#xff0c;Windows定制专款&#xff1b;DB2&#xff0c;IBM的产品&#xff0c;听起来挺高端&#xff1b;Sybase&#x…

android WebRtc 视频通话(P2P)

概述 WebRTC名称源自网页实时通信(Web Real-Time Communication)的缩写&#xff0c;是一个支持网页浏览器进行实时语音对话或视频对话的技术&#xff0c;是谷歌2010年以6820万美元收购Global IP Solutions公司而获得的一项技术。Google于2011年6月3日开源的即时通讯项目&#x…

centos7中mysql5.7.32服务离线升级到5.7.39教程

目录 一、导入新的离线安装包 二、备份原有mysql数据库 1、停止tomcat服务 2、查看mysql服务 3、备份数据库 三、停止mysql服务并打包备份旧版本 1、停止mysql 2、打包旧的mysql文件夹 3、删除旧的mysql文件夹 4、删除/etc/init.d/下跟mysql有关的全部文件&#xff0…

MongoDB数据迁移之迁移工具Kettle

MongoDB数据迁移之迁移工具Kettle ETL:简介 ETL&#xff08;Extract-Transform-Load的缩写&#xff0c;即数据抽取、转换、装载的过程&#xff09;&#xff0c;对于企业或行业应用来说&#xff0c;我们经常会遇到各种数据的处理&#xff0c;转换&#xff0c;迁移&#xff0c;所…

Java+JSP+MySQL基于SSM的医院挂号就诊系统-计算机毕业设计

项目介绍 随着计算机科技的快速发展&#xff0c;很多地方都实现了自动化管理&#xff0c;医院也不例外。在大多数医院&#xff0c;无论是挂号处&#xff0c;还是取药的窗口&#xff0c;都会看到有很长的队伍&#xff0c;很显然这样会让患者就医的过程中浪费太多的时间。其次&a…

【读论文】GANMcC

GANMcC简单介绍网络结构生成器辨别器损失函数生成器损失函数辨别器tips总结参考论文&#xff1a;https://ieeexplore.ieee.org/document/9274337 如有侵权请联系博主 这几天又读了一篇关于GAN实现红外融合的论文&#xff0c;不出意外&#xff0c;还是FusionGAN作者团队的人写…