SpringMVC设计模式

什么是MVC


        MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。是将业务逻辑、数据、显示分离的方法来组织代码。MVC主要作用是降低了视图与业务逻辑间的双向偶合。MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。

  • Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
  • View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
  • Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。

SpringMVC

SpringMVC设计模式_第1张图片

运行步骤: 

1、用户发起恩恩请求URL到达前端控制器

2、前端控制器请求处理器映射器查询Handler

3、处理器映射器返回给前端控制器,返回处理器执行链(HanderExecutionChain)(包含多个处理拦截器和一个Handler实例)

4、前端控制器请求处理器适配器执行Handler。

5、处理器适配器根据适配规则找到特定的处理器(后端controller层URL所绑定的方法),由处理器来执行Handler

6、处理器执行结束后返回给处理器适配器一个ModelAndView对象,该对象包含数据(Model)和逻辑视图名

7、处理器适配器将ModelAndView对象返回给前端控制器

8、前端控制器请求视图解析器解析视图地址,找到真正的视图

9、视图解析器将真正视图对象返回到前端控制器

10、将数据渲染到视图上

11、将渲染的页面响应给请求用户

 

前端控制器

前端控制器为DispatcherServlet

不需要进行开发

前端控制器是整个用户请求的入口和完成各组件业务转发

所有组件都是直接和前端控制器交互,减少组件间的耦合性

 

处理器映射器

处理器映射为HandlerMapping

不需要进行开发

来存储URL和Handler之间的映射关系,

由前端控制器来判断请求URL是否存在,并返回包含Handler的处理器执行链

 

处理器适配器

处理器适配器为HadlerAdapter

不需要进行开发

按照特定的规则(HandlerAdapter要求的规则)去执行,Handler通过适配器找到真正的执行器,是适配器模式的使用

 

处理器

按照HandlerAdapter的要求开发,Handler是针对用户具体的业务逻辑做响应的处理,Handler涉及到就用户的具体的业务逻辑需要自行开发Handler

 

视图解析器

视图解析器为ViewResolver

不需要进行开发

解析视图,根据逻辑视图名找到真正的视图,视图解析器负责解析View视图即页面的具体的地址位置,jsp、pdf、freeMark等都能完成解析

 

视图

视图为View

需要进行开发

View是一个接口,支持不同的View类型(jsp、pdf、freeMark...),例如jsp是提供了一个jstl

视图是展示给用户的页面,不同的业务展示不同的页面

 

SpringMVC的使用Demo

展示用户列表页面(开发的是处理器(获取用户信息)视图列表页面(JSP))

1.导入依赖

        
        
            org.springframework
            spring-webmvc
            4.1.7.RELEASE
        
        
            org.springframework
            spring-web
            4.1.7.RELEASE
        
        
            javax.servlet
            javax.servlet-api
            3.1.0
        

2.配置前端控制器

在web.xml配置文件下引入前端控制器的配置





  
  
    springMVC
    org.springframework.web.servlet.DispatcherServlet
    
    
      contextConfigLocation
      classpath:spring-mvc.xml
    
  

  
    springMVC
    /
  

需要在web.xml配置文件中引入前端控制器的实现类:org.springframework.web.servlet.DispatcherServlet,并将SPringMVC的配置添加在web.xml文件中

  
    springMVC
    org.springframework.web.servlet.DispatcherServlet
    
    
      contextConfigLocation
      classpath:spring-mvc.xml
    
  

除此之外也有其他的映射方式

    
        
        springMVC
        /
    

在视图中可以配置访问url的前缀后缀

    
    
        
        
    

  

3.配置映射器、处理器等

映射器、处理器等需要给定SPringMVC特定的配置文件,这里新建了spring-mvc.xml




    
    
    
    
    
    
    
    
    
    

4.开发视图(UserList.jsp) 

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
        <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
        <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
        

        
        
        数据展示
        
        
        
            
用户id 用户名
${user.id} ${user.name}

这里用到了标签,有可能两个jstl报错标红,导致foreach没法用,解决办法是手动在pom.xml中添加这两个依赖。

    
      jstl
      jstl
      1.2
    
    
      taglibs
      standard
      1.1.2
    

5.开发Handler

RequestMapping注解用于实现jsp与url之间的映射。这里的setViewName如果配置了前缀和后缀,就不用把路径写全了,就只需要写一个userlist

@Controller
public class UserController {

    /**
     * 执行器
     * @return
     */
    @RequestMapping("/userlist")
    public ModelAndView userList(){
        
        //返回用户列表
        ArrayList  users = new ArrayList <>();

        User u1= new User(1, "tom");
        User u2 = new User(2, "jack");
        User u3 = new User(3, "rose");
        users.add(u1);
        users.add(u2 );
        users.add(u3 );
        
        //封装ModelAndView对象
        ModelAndView modelAndView = new ModelAndView();
        //封装数据
        modelAndView.addObject("users",users);
        //封装逻辑视图名
        modelAndView.setViewName("/WEB-INF/jsp/userlist.jsp");
        
        return modelAndView;

    }
}

6.将服务部署到Jetty容器

在pom.xml中添加jetty的插件


          
              org.mortbay.jetty
              maven-jetty-plugin
              6.1.24
              
                  
                      
                          8080
                          30000
                      
                  
                  /
              
          

SpringMVC设计模式_第2张图片

只后配置目录,在命令行加入jetty:run命令完成即可运行,然后就能运行成功了。

SpringMVC设计模式_第3张图片

7.将服务部署到Tomcat容器

我还是习惯用Tomcat,可以去官网下载需要的Tomcat版本。IDEA配置Tomcat可以参考https://www.cnblogs.com/weixinyu98/p/9822048.html

如果Tomcat出现乱码的情况,去tomcat的安装目录下的conf的logging.properties,在最后一行添加下列命令,如我的就是E:\apache-tomcat-7.0.108-windows-x64\apache-tomcat-7.0.108\conf就能解决。

 java.util.logging.ConsoleHandler.encoding = GBK

如果啥都配好了还是运行不起来,检查端口占用,要么kell掉tomcat使用的端口,要么就直接给tomcat改个不容易占用的端口号。

运行成功如下:

SpringMVC设计模式_第4张图片

在浏览器进入到http://localhost:8088/springMVC_war/userlist,显示如下

SpringMVC设计模式_第5张图片

不知道为啥,我在jetty设置了默认跳转,它死活不跳,tomcat就能跳,至此SpringDemo运行成功。

前端控制器的源码实现流程

前端控制器的实现类org.springframework.web.servlet.DispatcherServlet的执行过程:

所有的请求都会请求到doService方法上

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
       //省略无关代码

		try {
			doDispatch(request, response);
		}
		finally {
			//
		}
	}
    

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
       //mappedHandler是处理器映射器返回的HandlerExecutionChain类型的对象
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
                //第二步:前端控制器调用处理器查找Handler
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
                //调用处理器适配器执行Handler,得到执行结果ModelAndViewView
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(request, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
            //视图渲染,将数据渲染到视图中
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

处理器和适配器的配置

 

基于配置方式来处理处理器和适配器

springMVC中处理器和适配器的使用可以使用配置和注解方式,配置处理器适配器,springMVC提供了org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter类实现,通过源码查看,该适配器支持的Handler必须是Controller接口的实现类,即需要实现COntroller接口,SimpleControllerHandlerAdapter适配器才能支持执行

SpringMVC设计模式_第6张图片

SpringMVC设计模式_第7张图片

spring-mvc1.xml配置





    

    
    



    
    


    
    


    
    
        
        

        
        
    

handler开发 

package com.tulun.controller;

import com.tulun.controller.bean.User;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;

/**
 * Description :
 * Created by Resumebb
 * Date :2021/4/18
 */
public class UserController1 implements Controller {

    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        ArrayList users = new ArrayList<>();
        User u1 = new User(1,"张三");
        User u2 = new User(2,"李四");
        User u3 = new User(3,"王五");
        users.add(u1);
        users.add(u2);
        users.add(u3);

        //返回ModelAndView对象
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("users",users);
        modelAndView.setViewName("userlist");
        return modelAndView;

    }
}

 基于该配置形式是,一个Controller实现类只能针对特定的一个URL做处理,即一个Handler只能一个类来处理,多个Handler(即针对不同的URL)是需要不同的Controller实现类来处理,且将实现类都要交给容器管理

注意:在基于非注解的处理器中使用的两个框架类:

  • org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
  • org.springframework.web.servlet.handler.SimpleUrlHandlerMapping

为了区别userlist.jsp,将handler映射到userlist1.jsp上,jsp内容无异。

部署结果

SpringMVC设计模式_第8张图片

网页显示: 

SpringMVC设计模式_第9张图片

基于注解形式处理适配器处理器

spring-mvc.xml






    
    

    
    
    
    
    
    

    
    

    
    


    
    

    
    

    
    
        
        

        
        
    

handler开发

基于配置方式的url只能对应一个handler,但是基于注解的可以对应多个url

package com.tulun.controller;

import com.tulun.controller.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.util.ArrayList;

/**
 * Description :
 * Created by Resumebb
 * Date :2021/4/17
 */
@Controller
public class UserController {


    @RequestMapping("/test")
    public @ResponseBody
    String test(){
        return "hello Tulun";
    }

    /**
     * 执行器
     * @return
     */
    @RequestMapping("/userlist")
    public ModelAndView userList(){

        //返回用户列表
        ArrayList  users = new ArrayList <>();

        User tulun = new User(1, "tom");
        User java = new User(2, "jack");
        User user = new User(3, "rose");
        users.add(tulun);
        users.add(java);
        users.add(user);

        //封装ModelAndView对象
        ModelAndView modelAndView = new ModelAndView();
        //封装数据
        modelAndView.addObject("users",users);
        //封装逻辑视图名 /WEB-INF/jsp/userlist.jsp
        modelAndView.setViewName("userlist");

        return modelAndView;

    }

    @RequestMapping("/userlist1")
    public ModelAndView test1(){

        //返回用户列表
        ArrayList  users = new ArrayList <>();

        User tulun = new User(1, "张三");
        User java = new User(2, "李四");
        User user = new User(3, "王五");
        users.add(tulun);
        users.add(java);
        users.add(user);

        //封装ModelAndView对象
        ModelAndView modelAndView = new ModelAndView();
        //封装数据
        modelAndView.addObject("users",users);
        //封装逻辑视图名 /WEB-INF/jsp/userlist.jsp
        modelAndView.setViewName("userlist1");

        return modelAndView;

    }
}

部署结果 

http://localhost:8088/springMVC_war/test:

http://localhost:8088/springMVC_war/userlist:

SpringMVC设计模式_第10张图片

http://localhost:8088/springMVC_war/userlist1:

SpringMVC设计模式_第11张图片

 

你可能感兴趣的:(SSM框架,spring,web,java,spring,mvc)