springmvc-执行流程

1. Web开发的发展

1.1 model1的开发方式

统一把显示层、控制层、数据层的操作全部交给 JSP 或者 JavaBean 来进行处理

请添加图片描述

出现的弊端:

  • JSP 和 Java Bean 之间严重耦合,Java 代码和 HTML 代码也耦合在了一起
  • 要求开发者不仅要掌握 Java ,还要有高超的前端水平
  • 前端和后端相互依赖,前端需要等待后端完成,后端也依赖前端完成,才能进行有效的测试
  • 代码难以复用

1.2 model2的开发方式

Servlet + JSP + Java Bean

在这里插入图片描述

首先用户的请求会到达 Servlet,然后根据请求调用相应的 Java Bean,并把所有的显示结果交给 JSP 去完成,这样的模式我们就称为 MVC 模式。

  • M 代表 模型(Model)
    模型是什么呢? 模型就是数据,就是 dao,bean
  • V 代表 视图(View)
    视图是什么呢? 就是网页, JSP,用来展示模型中的数据
  • C 代表 控制器(controller)
    控制器是什么? 控制器的作用就是把不同的数据(Model),显示在不同的视图(View)上,Servlet 扮演的就是这样的角色。

2. Spring MVC 框架介绍

SpringMVC 是类似于 Struts2 的一个 MVC 框架,在实际开发中,接收浏览器的请求响应,对数据进行处理,然后返回页面进行显示,但是上手难度却比 Struts2 简单多了。而且由于 Struts2 所暴露出来的安全问题,SpringMVC 已经成为了大多数企业优先选择的框架。

  • 特点:
    • 结构松散,几乎可以在 Spring MVC 中使用各类视图
    • 松耦合,各个模块分离
    • 与 Spring 无缝集成

3. SpringMvc的执行流程

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

  • 一个请求匹配前端控制器 DispatcherServlet 的请求映射路径(在 web.xml中指定), WEB 容器将该请求转交给 DispatcherServlet 处理
  • DispatcherServlet 接收到请求后, 将根据 请求信息 交给 处理器映射器 (HandlerMapping)
  • HandlerMapping 根据用户的url请求 查找匹配该url的 Handler,并返回一个执行链
  • DispatcherServlet 再 请求 处理器适配器(HandlerAdapter) 调用相应的 Handler 进行处理并返回 ModelAndView 给 DispatcherServlet
  • DispatcherServlet 将 ModelAndView 请求 ViewReslover(视图解析器)解析,返回具体 View
  • DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中)
  • DispatcherServlet 将页面响应给用户

3. SpringMvc应用程序的编写

引入依赖

<!--只需要引入这一个依赖即可,因为这个依赖包含  beans  core  context   web ..-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.1.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>javax.servlet.jsp-api</artifactId>
    <version>2.3.3</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>

创建Spring与SpringMvc配置文件

  • applicationContext.xml
  • spring-mvc.xml

修改web.xml

<web-app>
    <!--Spring的配置文件-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

    <!--    监听tomcat的启动,在启动时初始化容器-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!--配置springmvc的前端控制器-->

    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <!--大于0:代表tomcat启动时加载这个Servlet,小于等于0:代表第一次访问时加载这个Servlet-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

编写spring的applicationContext.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"
       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">
    <!--配置注解扫描器-->
    <context:component-scan base-package="com.xzy.spring"/>
</beans>

编写springmvc配置文件 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:aop="http://www.springframework.org/schema/aop"
       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/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/mvc
                           http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--配置前端控制器(在web.xml中配置)-->

    <!--配置处理器映射器-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
    <!--处理器适配器-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
    <!--配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>
    <!--必须配置处理器的包扫描路径,如果想要去掉applicationContext中的这个注解,就要把这个扫描路径配置成父类的-->
    <context:component-scan base-package="com.xzy.spring.controller"/>
</beans>

编写处理器(Controller)

package com.xzy.spring.controller;

import com.xzy.spring.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    UserService userService;

    @GetMapping("/login")
    public ModelAndView login() {
        userService.login();
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/login.jsp");
        Map map = new HashMap();
        map.put("name", "admin");
        map.put("age", 20);
        modelAndView.addObject(map);
        return modelAndView;
    }
}

编写视图

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"  %>
<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        登录视图${requestScope.user}
        <%= request.getAttribute("user")%>
    </body>
</html>

4. 浏览器访问

http://localhost:8080/user/login.do

DispatcherServlet会接收到这个请求,并且去掉.do去到相应的处理器


5. SpringMvc接收客户端的请求参数

http://localhost:8080/user/login.do?username=admin&password=admin123

5.1 通过servlet原始的api接收参数(了解)

@RequestMapping("/login")
public ModelAndView login(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
}

5.2 通过springmvc自带的功能完成参数的接收(重要)

@RequestMapping("/login")
public ModelAndView login(@RequestParam("username") String uname, @RequestParam("password") String upassword,@RequestParam("loves") List<String> loves) {
    System.out.println(uname);
    System.out.println(upassword);
    ModelAndView modelAndView = new ModelAndView();
    return modelAndView;
}

但是我们如果接收很多的参数每个参数都需要添加@RequestParam注解,这样就显得很繁琐,我们可以省略@RequestParam注解,那么就需要让我们形参的名称和请求的参数的名称一致;

eg:

@RequestMapping("/login")
public ModelAndView login(String username,String password) {
    System.out.println(username);
    System.out.println(password);
    ModelAndView modelAndView = new ModelAndView();
    return modelAndView;
}


5.3 获取Rest请求风格的参数(路径参数)

什么是RestFul?

RESTFUL是一种网络应用程序的设计风格和开发方式;

Post

Put

Get

Delete

查询:
GET /user/selectUser?id=10   #传统方式
GET /user/10            #RestFul的方式

删除:
POST /user/deleteUser?id=10   #传统方式
DELETE  /user/10    #RestFul的方式

修改:
POST /user/updateUser?id=10    #传统方式
 	xxxxxx
PUT  /user/10  #RestFul的方式
	xxxx

请求url:

POST: http://localhost:8080/user

DELET:http://localhost:8080/user/10

/**
     * 添加用户
     */
@PostMapping()
public void add(String name) {
    System.out.println("添加用户:name=" + name);
}


/**
     * 添加用户
     */
@DeleteMapping("/{id}")
public void del(@PathVariable("id") String id) {
    System.out.println("删除:id=" + id);
}

@PathVariable注解不能省略;


5.4 获取请求实体的内容

在这里插入图片描述

//需要添加 <mvc:annotation-driven/> 高级功能支持
@PostMapping(value = "/login")
public ModelAndView login(@RequestBody User user) {
    System.out.println(user);
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("index.jsp");
    return modelAndView;
}

注意

  • 导入依赖

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.11.0</version>
    </dependency>
    
  • spring-mvc.xml配置高级注解功能的支持

    <!--@RequestBody注解必须得配置这一项-->
    <mvc:annotation-driven/>
    

    此注解需要配置在之前


6. SpringMvc的响应处理

6.1 方法的返回值为void

@PostMapping(value = "/login")
public void login(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    request.setAttribute("username", "admin678");
    request.getRequestDispatcher("/index01.jsp").forward(request, response);
}

6.2 方法的返回值为String类型

@PostMapping(value = "/login")
public String login(HttpServletRequest request, HttpServletResponse response, Model model) throws IOException {
    //这个model里面的数据会被携带到视图中去
    model.addAttribute("username", "admin234");
    return "/index01.jsp";
}

6.3 方法的返回值为ModelAndView

@PostMapping(value = "/login")
public ModelAndView login(HttpServletRequest request, HttpServletResponse response) throws IOException {
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("/index01.jsp");
    modelAndView.addObject("username", "admin");
    return modelAndView;
}

7. mvc:annotation-driven

我们如果使用springmvc的基础功能比如:@Controller @RequestMapping @RequestParam,是不需要添加 mvc:annotation-driven的支持,但是我们如果要使用高级功能,例如: @RequestBody @ResponseBody这一些高级功能注解就需要添加mvc:annotation-driven的支持了;

我们要在 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:aop="http://www.springframework.org/schema/aop"
       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/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/mvc
                           http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--高级功能注解的扩展支持(一定要放在其他配置的最前面,要不然不生效)-->
    <mvc:annotation-driven/>

    <!--注册处理器映射器-->
    <bean name="requestMappingHandlerMapping"
          class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

    <!--注册处理器适配器-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>

    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>

    <!--开启Springmvc的注解扫描,主要扫描处理器的注解  @Controller  @RequestMapping  @GetMapping  @PostMapping-->
    <context:component-scan base-package="com.xzy.goods.controller"></context:component-scan>
</beans>

mvc:annotation-driven一定要放在其他注解之前,要不然不会生效;


8. @ReponseBody注解

<!--返回的对象转换成json字符串必须导入jackson的依赖-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.11.0</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.11.0</version>
</dependency>

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

@ReponseBody@Controller进行结合使用,可以直接返回json对象给客户端

package com.xzy.goods.controller;

import com.xzy.goods.entity.User;
import com.xzy.goods.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

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

    @Autowired
    UserService userService;

    @PostMapping(value = "/login")
    @ResponseBody
    public User login(@RequestBody User user) {
        System.out.println(user);
        user.setId(1001);
        return user;// 返回一个对象,在springmvc的底层会把对象自动转换为json字符串进行返回,还自动添加了 Content-Type: application/json
    }
}

但是我们如果在每个方法上面都添加ReponseBody注解实在太繁琐了,所以Spring给我们提供了一种非常好的解决方案: @RestController

通过源码可知:

在这里插入图片描述

@RestController=@Controller+@ResponseBody`


9. SpringMvc的请求转发与请求重定向

9.1 传统的Servlet的方式

请求转发:

//请求转发
request.setAttribute("orderNum", "7823432");
request.getRequestDispatcher("/orderList.jsp").forward(request, response);

请求重定向:

//传统方式的请求重定向
response.sendRedirect("/orderList.jsp");

9.2 SpringMvc提供的方式

请求转发:

@GetMapping("/findById")
/**
     * 方法的返回值为String类型,返回的是视图逻辑名称
     */
public String findById(Model model) throws ServletException, IOException {
    model.addAttribute("orderNum", 220);
    return "/orderList.jsp";
}

请求重定向:

public String findById(Model model) throws ServletException, IOException {
    //重定向时会把orderNum以参数的形式携带在url中
    model.addAttribute("orderNum", 220);
    return "redirect:/orderList.jsp";
}

10. Springmvc中的拦截器

SpringMVC 中的Interceptor 拦截器是有相当重要的,它的主要作用是拦截用户的请求并进行相应的处理;

定义拦截器可以通过两种方式:

  • 通过实现 HandlerInterceptor 接口或继承 HandlerInterceptor 接口的实现类来定义;
  • 通过实现 WebRequestInterceptor 接口或继承 WebRequestInterceptor 接口的实现类来定义。

编写拦截器

package com.xzy.goods.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 MyAllRequestInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyAllRequestInterceptor...请求处理之前....");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyAllRequestInterceptor...请求处理之后......");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyAllRequestInterceptor...视图渲染结束之后");
    }
}

拦截器的定义中实现了 HandlerInterceptor 接口,并实现了接口中的 3 个方法。

  • preHandle 方法:该方法在控制器的处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。
  • postHandle 方法:该方法在控制器的处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步的修改。
  • afterCompletion 方法:该方法在控制器的处理请求方法执行完成后执行,即视图渲染结束后执行,可以通过此方法实现一些资源清理、记录日志信息等工作。

注册拦截器

<mvc:interceptors>
    <!--配置全局拦截器,拦截所有请求-->
    <bean class="com.xzy.goods.interceptor.MyAllRequestInterceptor"></bean>

    <!--配置某个请求的拦截器,可以使用/**通配符-->
    <mvc:interceptor>
        <mvc:mapping path="/user/findById.do"/>
        <bean class="com.xzy.goods.interceptor.Interceptor01"></bean>
    </mvc:interceptor>
</mvc:interceptors>

拦截器与过滤器的区别

过滤器是原生的servlet中提供的过滤请求的一种机制

拦截器是SpringMvc中基于Aop的一种过滤handler的一种机制

在纯Servlet开发中不能直接使用拦截器,拦截器只能在SpringMvc中使用,

在SpringMvc中是直接可以使用过滤器的


11. SpringMvc请求参数限定

@RequestMapping("/findById")
public User findById(@RequestParam(name = "id",required = false,defaultValue = "110") Integer id) {
    User user = new User(id, "admin", "admin123");
    return user;
}

required: 默认为true,也就是说发送的请求必须要传递这个参数,不传递就会报错,我们想要不传递也不报错就要设置为false

defaultValue: 不传递时的默认值,一般与 required = false来进行结合使用;


12. SpringMvc接收数组参数

      /**
         * 接收数组参数,前端访问的格式: /user/u3.do?loves=java&loves=python
         * @param loves
         * @return
         */
        @GetMapping("/u3")
        public String u3(String[] loves) {
            System.out.println(Arrays.toString(loves));
            return "/login.jsp";
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值