菜鸟学SpringMVC之——SpringMVC执行原理、向前端返回数据的三种方式

SpringMVC

SpringMVC原理

SpringMVC请求发送到返回请求的全过程

在这里插入图片描述

在这里插入图片描述

流程:

  1. 客户端发送一个请求,Tomcat获得这个请求后将其做了一个映射判断(<url-pattern>/</url-pattern>,如果访问地址符合/,则交给DisPatcherServlet )传给DispatcherServlet(前端控制器)

  2. DispatcherServlet会根据请求去 HandlerMapping查找Handler(可以根据xml配置、注解@RequestMapping进行查找 )生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet.

  3. DispatcherServlet调用HandlerAdaptor执行对应的处理器Handler(Interceptor/Controller),并将请求传来的参数传给Handler,

  4. Handler(后端控制器)通过Service调用数据库找到对应的信息然后返回给Handler

  5. Handler将ModelAndView返回给HandlerAdaptor

    当Handler在完成逻辑处理后,通常会产生一些信息,这些信息就是需要返回给用户并在浏览器上显示的信息,它们被称为模型(Model)。仅仅返回原始的信息时不够的——这些信息需要以用户友好的方式进行格式化,一般会是 HTML,所以,信息需要发送给一个视图(view),通常会是 JSP。

    Handler所做的最后一件事就是将模型数据打包,并且表示出用于渲染输出的视图名(即代码中:mav.setViewName("index")的index,就是逻辑视图名)(逻辑视图名)。它接下来会将请求连同ModelAndView发送回HandlerAdaptor。

  6. HandlerAdaptor再将ModelAndView返回给DispatcherServlet,

  7. 但是DispatcherServlet不会处理这个ModelAndView,所以将其传给ViewResolver进行解析,ViewResolver根据逻辑视图名称解析真正的视图 ,并返回给DispatcherServlet。

    这样以来,控制器就不会和特定的视图相耦合,传递给 DispatcherServlet 的视图名并不直接表示某个特定的 JSP。(实际上,它甚至不能确定视图就是 JSP)相反,它传递的仅仅是一个逻辑名称,这个名称将会用来查找产生结果的真正视图(给逻辑视图名拼接前缀和后缀, 进而确定一个 Web 应用中视图资源的物理路径 )

    在这里插入图片描述

  8. DispatcherServlet进行视图渲染,就是将Model填充到Response中显示在view上。最后在传到前端

上面的这些组件中,只有Handler和View需要程序员开发。 Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。 View是一个接口,实现类支持不同的View类型(jstlView、freemarkerView、pdfView…)

源码

HandlerMapping(处理器映射器):根据配置或注解找到最重要执行的Handler

  • HandlerMapping接口的实现类:

    SimpleUrlHandlerMapping类通过配置文件把URL映射到Controller类。

    DefaultAnnotationHandlerMapping类通过注解把URL映射到Controller类。

HandlerAdapter(处理器适配器):帮助DispatcherServlet处理映射请求处理程序的适配器,而不用考虑实际调用的是 哪个处理程序

  • AnnotationMethodHandlerAdapter:通过注解,把请求URL映射到Controller类的方法上。

ViewResolver: 它接受一个由 DispaterServlet 传递过来的逻辑视图名来拼装为物理视图名即具体的页面地址。

  • UrlBasedViewResolver类 通过配置文件,把一个视图名交给到一个View来处理。

向前端返回数据的三种方式

了解了SpringMVC的原理后接下来看一下怎么同SpringMVC给前端返回数据(有三种方式)

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

    @Autowired
    IUserService service;

    @RequestMapping(value = "/login.do", method = {
    
    RequestMethod.GET})
    public String login(User user) {
    
    
        User result = service.login(user);
        //登录是否成功就看result是否有返回值
//        System.out.println("判断登录是否成功" + result.getId());
        return result.getId() + "";
    }
}

在这里插入图片描述
所以这里报错的原因就是:

代码中返回一个String,这个返回的String就代表ModelAndView的View的逻辑视图名,然后交给ViewResolver,进行解析返回给DispatcherServlet,打开路径/user/1下的视图,DispatcherServlet发现并找不到这个路径,所以返回404。现在就需要让视图解析器将1当作文字内容处理,而不要当作视图解析处理。

向前端返回数据的第一种方式:直接返回字符串

加注解@ResponseBody,将返回值当作文字处理。

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

    @Autowired
    IUserService service;

    @RequestMapping(value = "/login.do", method = {
    
    RequestMethod.GET})
    @ResponseBody
    public String login(User user) {
    
    
        User result = service.login(user);
        return result.getId() + "";
    }
}

在这里插入图片描述

也可以返回一个对象。它会将这个对象当作json格式返回给前端

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

    @Autowired
    IUserService service;

    @RequestMapping(value = "/login.do", method = {
    
    RequestMethod.GET})
    @ResponseBody
    public User login(User user) {
    
    
        User result = service.login(user);
        return result;
    }
}

但是配置文件需要稍加修改,打开mvc注解驱动,添加mvc:annotation-driven标签,它的作用就是让@ResponseBody等其他注解生效

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
	<!--mvc注解驱动-->
    <mvc:annotation-driven></mvc:annotation-driven>
	<!--其他配置省略-->
</beans>

导入依赖jar包

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.62</version>
    </dependency>

所以以后向前端传json就很简单。


接下来如果要直接打开一个静态页面将不能打开,是因为DispatcherServlet将他拦截处理了,但是静态资源根本不需要他来处理,这么来修改:

  • 方式一:改web.xml文件,让他只过滤.do的请求(<url-pattern>*.do</url-pattern>),这时index.html就不会拦截。

    配置成*.do表示请求发到Tomcat后,Tomcat发现是.html请求,所以不用给DispatcherServlet,所以Tomcat直接到对应文件夹去找对应的文件返回给前端

  • 还有一种改法,这个web.xml文件不改动,在webapp下创建static文件夹

在这里插入图片描述
​ 然后修改applicationContext文件,添加mvc:resources标签,这个标签的作用就是为资源文件(html、传css、js)做映射。

比如我们当前的这个例子中配置的,DispatcherServlet将不会拦截以/pages开头的所有请求路径,并将其当作静态资源交由Servlet处理

<mvc:resources mapping="/pages/**" location="/static/"></mvc:resources><!--表示前端请求的pages下的所有内容去static下面去找-->

因为web中配置的是只要是/*的请求都会先传给DispatcherServlet,所以不管是请求页面还是接口,都将传给DispatcherServlet,DispatcherServlet拿到后发现Spring中配置了mvc:resources,所以他就不用管了,直接到对应的文件目录下找到对应文件将其返回给前端

向前端返回数据的方式二:接下来实现重定向

@Controller
@RequestMapping("/user")
public class UserController {
    
    
    @Autowired
    IUserService service;
    @RequestMapping(value = "/login.do", method = {
    
    RequestMethod.GET})

    public String login(User user) {
    
    
        User result = service.login(user);
        if (result != null) {
    
    
            return "redirect:/pages/index.html";
        } else {
    
    
            return "redirect:/pages/error.html";
        }
    }
}

发送请求:http://localhost:8080/user/login.do?username=zaq&pwd=123,看地址栏变化了,重定向

在这里插入图片描述

向前端返回数据的方式三:接下来实现转发

转发是有可能携带数据的,那么怎么把数据带入到对应的页面中去,在对应的页面又怎么填充这些数据呢。一般转发都用的是jsp页面,jsp页面展示的时候填充对应的数据。

转发的时候直接返回页面位置就行了

@RequestMapping(value = "/login2.do", method = {
    
    RequestMethod.GET})
//    @ResponseBody
    public String login2(User user) {
    
    
        User result = service.login(user);
        return "jsp/success.jsp";//这时就会做转发动作
    }

但是要注意配置DispatcherServlet不能过滤它,即配置<url-pattern>*.do</url-pattern>,这时它就不会被视图解析器解析

注意地址栏地址没有改变,所以是转发

在这里插入图片描述
但是在开发过程中出于某种原因,就是不能设置为只过滤*.do,还是要过滤所有的请求,则直接设置<url-pattern>/</url-pattern>就行了,(注意不能设置为/*,他还是会拦截.jsp文件的)

还要在Spring的配置文件中加入资源解析器。

<!--这里配置了一个 Spring MVC 内置的一个视图解析器,
    该解析器是遵循着一种约定:会在逻辑视图名上添加前缀和后缀,
    进而确定一个 Web 应用中视图资源的物理路径-->
<mvc:view-resolvers>
    <mvc:jsp prefix="/jsp/" suffix=".jsp" view-class="org.springframework.web.servlet.view.JstlView"></mvc:jsp>
</mvc:view-resolvers>
@RequestMapping(value = "/login2.do", method = {
    
    RequestMethod.GET})
//    @ResponseBody
    public String login2(User user) {
    
    
        User result = service.login(user);
        return "success";//注意这时就不要写物理路径了,只需要写逻辑视图名就行了。
    }

总结:

SpringMVC接收前端传来的数据,直接通过方法的参数直接接收

SpringMVC向前端返回数据的三种方式:

  • 返回字符串:@ResponseBody

  • 重定向:返回字符串,以redirect: 开头

  • 转发:

    • 如果返回的时候不带数据,直接返回字符串,直接写路径。

    • 如果返回的时候要带数据,则返回ModelAndView

          @RequestMapping(value = "/login2.do", method = {
              
              RequestMethod.GET})
          public ModelAndView login2(User user) {
              
              
              User result = service.login(user);
              ModelAndView mav = new ModelAndView();
              mav.addObject("result",result);//要返回的数据添加到这里,返回几个对象,则添加几个。
              mav.setViewName("success");//这就相当于原来要直接返回的String,即逻辑视图名
              return mav;
          }
      

      在JSP页面中获取

      <body>
          成功登录,这个是一个JSP页面 <%=((User) request.getAttribute("result")).getUsername()%>
      </body>
      </html>
      

部分内容参考:
https://www.iteye.com/blog/elf8848-875830
https://www.jianshu.com/p/91a2d0a1e45a
https://www.cnblogs.com/selene/p/4658554.html

Guess you like

Origin blog.csdn.net/ysf15609260848/article/details/106648598