SpringMVC

MVC:

  • Model
  • View
  • Controller

概述

​ Spring Web MVC是建立在Servlet API上的原始Web框架,从一开始就包含在Spring框架中。正式名称 "Spring Web MVC" 来自其源模块的名称spring-webmvc,但它更常被称为 "Spring MVC"

​ SpringMVC主要执行请求的处理,底层实际上是Servlet

​ SpringMVC是约定大于配置的

​ 对于Servlet,它的一个重要作用就是请求转发和重定向

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 请求为/test?method=参数具体值,根据不同的参数转发到不同的页面
        String method =req.getParameter("method");
        if(method.equals("add")){
            req.getSession().setAttribute("msg","调用add");

        }else if (method.equals("delete")){
            req.getSession().setAttribute("msg","调用delete");

        }
        req.getRequestDispatcher("add.jsp").forward(req,resp);
    }
}

​ 每一个请求都对应一个Servlet,而Servlet又将面向用户,这样就会造成用户面向数量不菲的Servlet

​ 所以ServletMVC提供了DispatcherServlet,作为请求的调度器,将不同的请求交付给对应的处理器(Controller)

使用SpringMVC所需要的依赖:

<!--spring-web-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<!--spring-webmvc-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<!--spring-jdbc-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<!--spring注解-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

DispatcherServlet

​ DispatcherServlet是SpringMVC的一个中央Servlet,它的作用是将请求分发到不同的处理器

​ 它是已经被实现的类,直接使用即可

<!--注册DispatcherServlet-->
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc-servlet.xml</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

​ url-pattern为/,代表所有请求都会走一遍DispatcherServlet

​ / 代表所有不为/xxx.jsp的请求,/*包括.jsp请求

​ DispatcherServlet就相当于Controller,他要配合一下几个对象来去处理Model和View:

  • HandlerMapping:处理器映射器
  • HandlerAdapter:处理器适配器
  • ViewResolver:视图解析器
SpringMVC的执行流程

1.查找请求

​ 当用户执行一次请求后,DispatcherServlet就会接收到该请求,DispatcherServlet首先调用HandlerMapping,来找到该请求的Handler(处理器)

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

<!--id即为请求名-->
<bean id="/hello" class="HelloController"/>

​ BeanNameUrlHandlerMapping是已经被实现的用于查找请求对应Handler的类,直接使用即可

​ BeanNameUrlHandlerMapping查找的范围是bean,bean的id为请求名,class是对应的Handler,找到对应的Handler后,将Handler返回给DispatcherServlet

2.执行请求

​ DispatcherServlet接收到请求对应的Handler,将Handler交给HandlerAdapter,用适配器执行Handler

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

​ SimpleControllerHandlerAdapter为处理器适配器,用于调用执行Handler

​ 此外,Handler实际上是一个实现了Controller接口的类

public class HelloController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        ModelAndView mv = new ModelAndView();
        //可以向ModelAndView对象里添加参数,类似于setAttribute
        mv.addObject("msg", "Hello World");
        //设置请求要访问的view的名字
        mv.setViewName("hello");
        return mv;
    }
}

​ 调用DispatcherServlet传入的Handler,将其返回的ModelAndView对象再返回给DispatcherServlet

3.执行转发

​ DispatcherServlet接收到ModelAndView对象,使用ViewResolver来解析该对象

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

​ InternalResourceViewResolver解析ModelAndView对象,在Handler里通过setViewName已经设置了即将访问的页面名,在这里来设置它的具体路径

​ 在InternalResourceViewResolver对象的bean里有前缀和后缀两个属性,这两个属性将会附加在setViewName所设置的值上。例如上面我们设置的为hello,最终得到的就是 /WEB-INF/jsp/hello.jsp ,也就是将要访问的View的路径

​ 这个路径就相当于一个具体的View,将其返回给DispatcherServlet

​ 最终DispatcherServlet将具体的View进行渲染,然后响应给用户

​ 整个流程我们的业务代码只有两部分:编写Handler和注册Handler的bean,大部分步骤都是DispatcherServlet自动执行的

QQ截图20241206092532

注解实现

​ 使用注解配置将进一步简化上面的步骤

​ 首先在web.xml配置DispatcherServlet,步骤同上

​ 然后配置springmvc-servlet.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:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--扫描该路径下的包,使其中的注解生效,由IOC容器统一管理-->
    <context:component-scan base-package="Controller"/>
    <!--使SpringMVC不处理静态资源,避免请求HTML,css资源时被处理-->
    <mvc:default-servlet-handler/>
    <!--支持mvc注解驱动,该驱动配置了HandlerMapping和HandlerAdapter对象,不用再去配置他们的bean
        注解采用@ResquestMapping来完成映射关系
        在此之前,需要在上下文注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例
        这两个实例分别在类级别和方法级别处理
        annotation-driven标签会帮助我们自动完成这两个实例的配置
    -->
    <mvc:annotation-driven/>
    
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

​

然后使用注解来配置HelloController,主要使用以下注解:

  • @Controller:标识为Controller,和实现Controller接口作用相同
  • @RequestMapping:请求映射
//@Controller:标识为Controller,和实现Controller接口作用相同
@Controller
//请求映射
//@RequestMapping("/hello")
public class HelloController {

    //@RequestMapping如果同时写在了类和方法上,代表需要经过类上的请求再进行方法上的请求才能到这里
    //以此为例,如果类上有@RequestMapping,请求为/hello/h1,会执行此处的Controller
    //一般写方法上的即可,如果有一组类型相似的请求,可以这样做
    @RequestMapping("/h1")
    public String sayHello(Model model) {
        //向Model对象里附加数据
        model.addAttribute("message", "Hello World");
        //return的值被ViewResolver解析
        return "hello";
    }
}

RESTful风格

​ RESTful是一种资源定位和资源操作的格式,不是一种标准或协议

​ 传统方式操作资源,是通过不同的参数来请求,方法也一般只使用Get和Post

​ 例如我要进行增删改查四个操作:

  • 增:localhost/item/add.action?id=1,GET
  • 删:localhost/item/delete.action,POST
  • 改:localhost/item/update.action,POST
  • 查:localhost/item/query.action?id=1,GET

​ RESTful操作资源是通过不同的请求方式来确定的,使得同样的请求地址可以由不同的功能

  • 增:localhost/item/1,POST
  • 删:localhost/item,DELETE
  • 改:localhost/item,PUT
  • 查:localhost/item/1,GET

比如这个Controller:

@Controller
public class RESTController {

    @RequestMapping("/add")
    public String test(int a, int b, Model model){
        int res=a+b;

        model.addAttribute("msg","result="+res);
        return "test";
    }
}

​ 我要走add请求,就必须要附带着a,b的值,否则就会报错

http 😕/localhost:8080/add?a=1&b=2

可以使用@PathVariable注解,该注解支持从url中获取参数@Controller

public class RESTController {

//通过@PathVariable注解获取到的参数可以用于请求映射上
@RequestMapping("/add/{a1}/{b}")
//可以为参数设置别名,默认为变量名
public String test(@PathVariable("a1") int a,@PathVariable int b, Model model){
int res=a+b;

model.addAttribute("msg","result="+res);
return "test";
}

}对于RequestMapping,可以设置其Method

​ SpringMVC提供了枚举类RequestMethod,包含了若干方法

public enum RequestMethod {
    GET,
    HEAD,
    POST,
    PUT,
    PATCH,
    DELETE,
    OPTIONS,
    TRACE;

    private RequestMethod() {
    }
}
@Controller
public class RESTController {
//name为请求路径,method为方法,默认为GET
    @RequestMapping(value="/add/{a1}/{b}",method = RequestMethod.DELETE)
    public String test(@PathVariable("a1") int a,@PathVariable int b, Model model){
        int res=a+b;

        model.addAttribute("msg","result="+res);
        return "test";
    }
}

​ 也可以将@RequestMapping注解替换为@GetMapping注解,代表使用Get方法

​ 同样的,也有@PostMapping,@DeleteMapping等注解

@Controller
public class RESTController {

    @GetMapping("/add/{a}/{b}")
    public String test(@PathVariable int a,@PathVariable int b, Model model){
        int res=a+b;

        model.addAttribute("msg","GETresult="+res);
        return "test";
    }

    //同样的路径,通过不同的方法返回不同的结果
    @PostMapping("/add/{a}/{b}")
    public String test2(@PathVariable int a,@PathVariable int b, Model model){
        int res=a+b;

        model.addAttribute("msg","POSTresult="+res);
        return "test";
    }
}

转发和重定向

​ 没用,了解即可

​ SpringMVC除了通过视图解析器来进行转发,还可以通过一些字段来实现转发或重定向

@Controller
public class ModelTest {

    @RequestMapping("/m1")
    public String test(){
        return "forward:WEB-INF/jsp/test.jsp";
        //return "redirect:/test2.jsp";
    }

}

​ 在没有视图解析器的前提下,进行转发需要写全路径

​ 使用forward:来代表转发,redirect:代表重定向

请求参数接收

​ 上面的@PathVariable注解可以获取请求中参数并应用到路径中

​ @RequestParam可以从请求中提取查询参数、表单参数甚至是多个参数

​ 如果方法中的参数是一个对象,SpringMVC会自动匹配请求中参数的名字和对象的属性名,如果匹配就会给该对象赋值

<form action="${pageContext.request.contextPath}/t1" method="get">
    id:<input type="text" name="id">
    name:<input type="text" name="name">
    age:<input type="text" name="age">
    <input type="submit">
</form>
---------------------------------------------------
@GetMapping("/t1")
public String test(@RequestParam String name, Model model){

    model.addAttribute("msg", name);
    return "test";
}

@GetMapping("/test2")
public String test2(User user){
    System.out.println(user);

    return "test";
}

过滤器

SpringMVC提供了过滤器类CharacterEncodingFilter,直接使用即可

<filter>
    <filter-name>EncodingFilter</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>EncodingFilter</filter-name>
    <url-pattern>/</url-pattern>
</filter-mapping>

JackSon

​ JackSon是一种JSON解析工具,将java对象转化成JSON字符串

<!--JackSon-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.18.1</version>
</dependency>
posted @ 2024-12-11 08:38  顾巧  阅读(29)  评论(0)    收藏  举报