SpringMVC基础学习

MVC模式

MVC是Model,View和Controller的缩写
模型:用于存储数据以及处理用户请求的业务逻辑
视图:向控制器提交数据,显示模型中的数据
控制器:根据视图提出的请求判断请求和数据交给哪个模型处理,将处理后的有关结果交给哪个视图更新显示

基于Servlet的MVC模式

模型:一个或多个javaBean对象
视图:一个或多个JSP页面
控制器:一个或多个Servlet对象

在这里插入图片描述

SpringMVC工作原理

Spring核心组件
DispatcherServlet : 前端控制器,接收所有请求(不包含jsp)
HandlerMapping: 解析请求格式的.判断希望要执行哪个具体的方法.
HandlerAdapter: 负责调用具体的方法.
ViewResovler:视图解析器.解析结果,准备跳转到具体的物理视图

执行流程

1.客户端请求提交到DispatcherServlet
2.由DispatcherServlet根据请求路径寻找一个或多个HandlerMapping,找到对应的HandlerAdapter
3.由HandlerAdapter执行对应的Controller
4.Controller调用业务逻辑,然后返回一个ModelAndView对象
5.DispatcherServlet寻找一个或多个ViewResovler视图解析器,找到ModelAndView指定的视图

在这里插入图片描述

public class DispatcherServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String path=req.getServletPath();
        System.out.println(path);
        if(path.equals("/abc")){
            show1(req, resp);
        }
        if(path.equals("/def")){
            show2(req, resp);
        }
        if(path.equals("/ddd")){
            show3(req, resp);
        }
        if(path.equals("/qqqq")){
            show4(req, resp);
        }
    }

    private void show1(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("show1");
        req.getRequestDispatcher("/index.jsp").forward(req,resp);
    }
    private void show2(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        System.out.println("show2");
        resp.sendRedirect("/login.jsp");
    }
    private void show3(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("show3");
    }
    private void show4(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("sho4");
    }
}

每个show1,show2,…相当于一个Controller
原理基本类似,根据请求的路径名来调用对应的Controller
这里的if相当于HandlerMapping,只不过人家使用的是map
而调用方法不是像这样简单调用,而是通过HandlerAdapter去调用
返回请求转发或者重定向是通过ModelAndView和ViewResovler去完成

环境搭建

在这里插入图片描述
导入相应jar包

基于配置文件的SpringMVC

1.在web.xml中部署DispatcherServlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
         
    <!--部署DispatcherServlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>           <!--springmvc的配置文件 默认在web-inf下 这里重新配置位置 -->
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

DispatcherServlet是基于Servlet的,所以需要在web.xml下进行配置
接下来需要配置springmvc的配置文件,如果没有在<servlet>标签下进行配置<init-param>,那么springmvc的配置文件就在WEB_INF下,并且配置文件名字为<servlet-name>的内容加上 - servlet.xml

可以通过<init-param>来配置springmvc的文件

2.创建controller

创建一个实现Controller接口的类

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

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

public class LoginContorller implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        System.out.println("LoginContorller");
        return new ModelAndView("/login.jsp");
    }
}

`
返回值为ModelAndView,默认为请求转发

3.创建springmvc配置文件

<?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:mvc="http://www.springframework.org/schema/mvc"
       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/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">


    <!--配置controller-->
    <bean name="login" class="cn.com.controller.LoginContorller"></bean>


    <!--配置HandlerMapping接口-->
    <bean  class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="urlMap">
            <map>
                <!-- 解析出来控制器逻辑名 -->
                <!--key为控制器的逻辑名-->
                <entry key="login" value-ref="login"></entry>
            </map>
        </property>
    </bean>

    <!--配置调用控制器的接口-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
</beans>

4.测试
index.jsp为测试页面
在这里插入图片描述
点击登陆后
在这里插入图片描述
在这里插入图片描述
登陆成功

注:
上述的配置是没有配置viewResolver的
可以配置viewResolver,其作用是在ModelAndView的内容加前缀和后缀

<?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:mvc="http://www.springframework.org/schema/mvc"
       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/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">


    <!--配置controller-->
    <bean name="login" class="cn.com.controller.LoginContorller"></bean>


    <!--配置HandlerMapping接口-->
    <bean  class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="urlMap">
            <map>
                <!-- 解析出来控制器逻辑名 -->
                <!--key为控制器的逻辑名-->
                <entry key="login" value-ref="login"></entry>
            </map>
        </property>
    </bean>

    <!--配置调用控制器的接口-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>


    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>
package cn.com.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

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

public class LoginContorller implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        System.out.println("LoginContorller");
        return new ModelAndView("login");
    }
}

这时ModelAndView的内容可以只写名字,viewResolver将自动添加前缀和后缀

SpringMVC的容器与组件

spring的容器是ApplicationContext,SpringMVC的容器是ConfigurableWebApplicationContext

ApplicationContext和ConfigurableWebApplicationContext有什么关系?
查看ApplicationContext的结构
在这里插入图片描述
可以看出ApplicationContext有两个子类,而WebApplicatonContext是spirng整合web的容器

接下来就探究springmvc的容器和spring容器的关系

首先,基于spingmvc的原理,首先是要启动DispatcherServlet,而DispatcherServlet是基于serlvet的,所以它必定有init()方法,service()方法,destroy()方法

DispatcherServlet

首先来看DispatcherServlet
在这里插入图片描述
可以看出springmvc将创建自己的配置上下文,基于servlet的init-param
init-param的ContextConfigLoaction将指示一个被xmlwebapplicationContext加载的xml文件
所以可以通过init-param标签指示springmvc的配置文件的位置

1.init()
1.在DispatcherServlet的源码里并没有Init()方法,所以找寻它的父类FrameworkServlet
在这里插入图片描述
2.DispatcherServlet的父类FrameworkServlet也没有Init()方法,继续找寻FrameworkServlet的父类
在这里插入图片描述

3.在HttpServletBean有init()方法并且是final的
在这里插入图片描述

在init()方法中有个initServletBean的方法,查看结构可以看出实现该方法的有FramworkServlet和ResourceServlet,而FramworkServlet是HttpServletBean的子类所以是调用的FramworkServlet中的initServletBean

4.进入FramworkServlet的initServletBean方法
在这里插入图片描述
5.进入到initWebApplicationContext方法中
在这里插入图片描述
getServletContext()获取的是spring容器
由WebApplicationContext rootContext=WebApplicationContextUtils.getWebApplicationContext(getServletContext());可以看出spring容器整合为WebApplicationContext

wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;

由这三行代码可以看出webApplicationContext强制转换为了ConfigurableWebApplicationContext

cwac.setParent(rootContext);

由这行代码可以看出ConfigurableWebApplicationContext 的父容器就是webApplicationContext也就是ApplicationContext

在这里插入图片描述

在这里插入图片描述
所以SpringMVC容器是Spring容器的子容器,SpringMVC容器是可以获取到Spring容器的内容

2.service()

在DispatcherServlet中没有service()方法,所以到其父类FrameworkServlet中找
1.可以在FrameworkServlet中找到service()方法
在这里插入图片描述
2.进入到processRequest
在这里插入图片描述
在processRequest中调用了doService方法
在这里插入图片描述
而在frameworkservlet中是一个抽象方法,所以它会调用子类的方法,也就是DispatcherServlet的方法

3.进入DispatcherServlet的doService
在这里插入图片描述
在这里插入图片描述

4.进入doDispatch
在这里插入图片描述
查看getHandler方法
在这里插入图片描述
可以看出是通过HandlerMapping获取Handler

再查看getHandlerAdapter方法
在这里插入图片描述
返回了对应的HandlerAdapter

继续查看doDispatch
在这里插入图片描述
可以看出通过handler执行了handle方法,并返回了ModelAndView的一个对象

所以看出springMVC的执行是在DispatcherServlet的doservie()方法中,而不同的类它们的分工是不同的

所以具体流程就是
1.客户端请求提交到DispatcherServlet
2.由DispatcherServlet根据请求路径寻找一个或多个HandlerMapping,找到对应的HandlerAdapter
3.由HandlerAdapter执行对应的Controller
4.Controller调用业务逻辑,然后返回一个ModelAndView对象
5.DispatcherServlet寻找一个或多个ViewResovler视图解析器,找到ModelAndView指定的视图

HandlerMapping

在DispatcherServlet中,通过请求可以获取一个HandlerMapping,而handler是如何找寻到HandlerAdpter
HandlerMapping是一个接口,进入一个具体的实现类
因为在配置文件中配置的是SimpleUrlHandlerMapping,所以查看SimpleUrlHandlerMapping
在这里插入图片描述
在这里插入图片描述
在实现类中有一个map结构,所以这可以和springmvc配置文件对应起来

<!--配置HandlerMapping接口-->
    <bean  class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="urlMap">
            <map>
                <!-- 解析出来控制器逻辑名 -->
                <!--key为控制器的逻辑名-->
                <entry key="login" value-ref="login"></entry>
            </map>
        </property>
    </bean>

1.进入其初始化方法
在这里插入图片描述
2.进入registerHandlers方法
在这里插入图片描述
enty.getKey()就是配置文件里配置的key
enty.getValue就是配置文件里配置的value

可以看出不管有没有以"/"开头,它都会自动加上

3.进入registerHandler方法
在这里插入图片描述
可以看出它从spring容器中拿取了对象,对象就是配置文件里的value-ref

在这里插入图片描述
接下来就是找寻对应HandlerAdpater,可以看出它是有默认的HandlerAdpater的,在springMVC中,HandlerAdpater和ViewResolver如果没有配置是有默认的

HandlerAdpter

HandlerAdpter的方法很简单,DispatcherServlet调用了handle,所以来看handle()方法
1.handle()方法

在这里插入图片描述
HandlerAdpter是一个接口,所以去看其实现类的接口,因为在配置文件中配置的是SimpleControllerHandlerAdapter,所以查看SimpleControllerHandlerAdapter
在这里插入图片描述

它强制转化为了Controller,并调用了Controller的handlerRequest()方法,而自己写的控制器类是实现了Controller接口的

2.进入Controller接口handlerRequest()方法
在这里插入图片描述
此时查看结构可以看到是有自己写的实现类的,也就是走到这它就去调用了自己写的实现类

基于注解的SpringMVC

1.配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
         
    <!--部署DispatcherServlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>           <!--springmvc的配置文件 默认在web-inf下 这里重新配置位置 -->
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

2.配置springMVC.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	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
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">
     <!--扫描注解-->
    <context:component-scan base-package="cn.com.controller"></context:component-scan>
    <!--注解驱动-->
    <mvc:annotation-driven></mvc:annotation-driven>
    
</beans>

3.配置Controller

package cn.com.controller;

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


@Controller
public class LoginContorller  {
   @RequestMapping("login")
    public String login(){
       System.out.println("登陆");
      return "/login.jsp";    //如果配置了viewResolver,可以只写一个login
   }
}

在控制器类上配置@Controller

在其处理方法上配置@RequestMapping

Controller的参数

把内容写到方法参数中,SpringMVC 只要有这个内容就自动注入内容.

基本数据类型

1.默认保证参数名称和请求中传递的参数名相同

<form action="login" >
    姓名:<input name="name" ></br>
    年龄:<input name="age"></br>
    <input type="submit">
</form>

写了一个表单

@Controller
public class LoginContorller  {
   @RequestMapping("login")
    public String login(String name,int age){
       System.out.println(name+" "+age);
      return "/login.jsp";
   }
}

在方法中获取参数

在这里插入图片描述
可以看出是获取到了的

这是因为在请求参数中有name和age,springMVC会根据名称自动进行注入,如果找不到就注入null

<form action="login" >
    姓名:<input name="name11" ></br>
    年龄:<input name="age11"></br>
    <input type="submit">
  </form>

在这里插入图片描述
可以看出报错,报错的原因不是找不到,而是因为age是个Int类型,而springmvc无法找到参数内容的话会自动注入null,而nul无法赋值给Int

2.果请求参数名和方法参数名不对应使用@RequestParam()赋 值

<form action="login" >
    姓名:<input name="name11" ></br>
    年龄:<input name="age11"></br>
    <input type="submit">
  </form>
@Controller
public class Contorller  {
   @RequestMapping("login")
    public String login(@RequestParam("name11") String name, @RequestParam("age11") int age){
       System.out.println(name+" "+age);
      return "/login.jsp";
   }
}

在这里插入图片描述
获取成功

3.@RequestParam 设置默认值.
如果方法参数是基本数据类型(不是封装类)注入Null时会报错,此时可以通过@RequestParam 设置默认值.

<form action="login" >
    姓名:<input name="name11" ></br>
    年龄:<input name="age11"></br>
    <input type="submit">
  </form>
@Controller
public class Contorller  {
   @RequestMapping("login")
    public String login(@RequestParam(defaultValue = "zhangsan") String name, @RequestParam(defaultValue ="20") int age){
       System.out.println(name+" "+age);
      return "/login.jsp";
   }
}

在这里插入图片描述
可以看出参数名没有对应,但是没报错,输出默认值

4.强制设置参数

@Controller
public class Contorller  {
   @RequestMapping("login")
    public String login(@RequestParam(required = true) String name, @RequestParam(defaultValue ="20") int age){
       System.out.println(name+" "+age);
      return "/login.jsp";
   }
}

required = true表示必须有参数
在这里插入图片描述
可以看出直接没有执行到对应的方法

在这里插入图片描述
直接在浏览器返回错误,而服务器没有500

参数是对象

1.请求参数名和对象属性名相同

<form action="login" >
    姓名:<input name="name" ></br>
    年龄:<input name="age"></br>
    <input type="submit">
  </form>

建立实体类

package cn.com.pojo;

public class Student {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

属性和请求参数对应

@Controller
public class Contorller  {
   @RequestMapping("login")
    public String login(Student student){
       System.out.println(student);
      return "/login.jsp";
   }
}

在这里插入图片描述

可以看出自动注入值了
如果对象的属性和请求参数对应,springMVC自动注入值,调用的是getset方法

2.请求参数包含多个同名参数

<form action="login" >
    姓名:<input name="name" ></br>
    年龄:<input name="age"></br>
    打球<input type="checkbox" name="hobby" value="1">
    绘画 <input type="checkbox" name="hobby" value=2">
    电影<input type="checkbox" name="hobby" value="3"></br>
    <input type="submit">
  </form>

hobby是同名参数

@Controller
public class Contorller  {
   @RequestMapping("login")
    public String login(Student student,@RequestParam("hobby") List<String> hobby){
       System.out.println(student+""+hobby);
      return "/login.jsp";
   }
}

使用List获取同名参数,并在前面加上@RequestParam
在这里插入图片描述
在这里插入图片描述
获取成功

3.类中包含对象

package cn.com.pojo;

public class Student {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

package cn.com.pojo;

public class People {
    private Student student;

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    @Override
    public String toString() {
        return "People{" +
                "student=" + student +
                '}';
    }
}

@Controller
public class Contorller  {
   @RequestMapping("login")
    public String login(People people){
       System.out.println(people);
      return "/login.jsp";
   }
}
<form action="login" >
    姓名:<input name="student.name" ></br>
    年龄:<input name="student.age"></br>
    <input type="submit">
  </form>

使用对象名.属性注入值
在这里插入图片描述

4.restful传值
request获取参数一般都是键值对的形式
如 /login?name=xxx&age=xxxx

使用restful方法传值就不是键值对
请求格式使用特殊格式

<a href="login/kryie/11">跳转</a>
@Controller
public class Contorller  {
   @RequestMapping("login/{name}/{age}")
    public String login(@PathVariable String name,@PathVariable int age){
       System.out.println(name+" "+age);
      return "/login.jsp";
   }
}

@RequestMapping 中一定要和请求格式对应
{} 中名称自定义名称
@PathVariable 获取@RequestMapping 中内容,默认按照 方法参数名称去寻找

@PathVariable(“指定名称”)可以指定去寻找名称

在这里插入图片描述

跳转方式

SpringMVC默认跳转方式是请求转发.

可以通过设置返回字符串的内容设置跳转方式

@Controller
public class Contorller  {
   @RequestMapping("login")
    public String login(String name,int age){
       System.out.println(name+" "+age);
      return "redirect:/login.jsp";
   }
}

重定向
在这里插入图片描述

@Controller
public class Contorller  {
   @RequestMapping("login")
    public String login(String name,int age){
       System.out.println(name+" "+age);
      return "forward:/login.jsp";
   }
}

请求转发
在这里插入图片描述

@ResponseBody

在方法上只有@RequestMapping 时,无论方法返回值是什么认为需要跳转

1.普通字符串

.在方法上添加@ResponseBody时,恒不跳转,直接返回对应的值

@Controller
public class Contorller  {
    
   @RequestMapping("login")
   @ResponseBody
    public String login(String name,int age){
       System.out.println(name+" "+age);
      return name+" "+age;
   }
}

在这里插入图片描述

2.返回对象
返回值为对象时,@ResponseBody将对象转化为json字符串

在使用@ResponseBody时需要导入jackson的jar包
在这里插入图片描述

@Controller
public class Contorller  {

   @RequestMapping("login")
   @ResponseBody
    public Student login(){
       Student student=new Student();
       student.setName("Zhangsan");
       student.setAge(11);
      return student;
   }
}

在这里插入图片描述

如果返回值包含中文,出现中文乱码 ,则在RequestMapping中添加属性

@RequestMapping(value="login",produces="application/json; charset=utf-8")

produces 表示响应头中 Content-Type 取值.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值