MVC架构
MVC是一种著名的设计模式,特别是在 Web 应用程序领域。模式全都是关于将包含业务数据的模块与显示模块的视图解耦的。这是怎样发生的?视图(例如,JSP 页面)怎样能够与其模型(例如,包含数据的 JavaBean)解耦?记得这句格言么?一个层次的重定向几乎可以解决计算机业中的所有问题。确实,在模型和视图之间引入重定向层可以解决问题。此重定向层是控制器。控制器将接收请求,执行更新模型的操作,然后通知视图关于模型更改的消息。依赖于模型的状态并且依赖于请求的控制器可以决定要显示哪个视图。
MVC(Model-View-Controller)三元组的概念:
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或 JavaBean 组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据) 和 服务层(行为)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。 领域模型javaBean组件等价于 域模型层 + 业务逻辑层 + 持久层(M)
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西(V)。
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图©
springMVC架构
SpringMVC是Spring框架的一个模块,Spring和SpringMVC无需通过中间整合层进行整合。
SpringMVC是基于MVC架构的WEB框架。
SpringMVC框架是一个基于请求驱动的Web框架,使用了前端控制器模式来进行设计,再根据请求映射规则分发给相应的页面控制器(动作/处理器)进行处理。首先让我们来整体看一下Spring Web MVC请求的处理流程。
SpringMVC处理流程
前端控制器(DispatcherServlet)是springmvc的心脏,用来拦截用户的请求,
其本质是一个servlet,其收到请求后将数据交给处理器(handler)去执行相关处理
对工作原理解释说明:
用户发送请求到springmvc框架提供的DispatcherServlet 这个前端控制器 前端控制器会去找处理器映射器(HandlerMapping),
处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet 。
根据处理器映射器返回的处理器,DispatcherServlet 会找“合适”的处理器适配器(HandlerAdapter)。
处理器适配器HandlerAdpater会去执行处理器(Handler开发的时候会被叫成Controller也叫后端控制器) 执行之前会有转换器、数据绑定、校验器等等完成上面这些才会去正在执行Handler。
后端控制器Handler执行完成之后返回一个ModelAndView对象
处理器适配器HandlerAdpater会将这个ModelAndView返回前端控制器DispatcherServlet。前端控制器会将ModelAndView对象交给视图解析器ViewResolver。
视图解析器ViewResolver解析ModelAndView对象之后返回逻辑视图。
视图解析器ViewResolver解析ModelAndView对象之后返回逻辑视图。
对组件说明:
DispatherServlet:前端控制器
用户请求到达前端控制器,相当于MVC中的C,而DispatherServlet是整个流程的核心,它来调用其他组件来处理用户的请求,前端控制器的存在降低了其他组件之间的耦合度。
HandlerMapping:处理器映射器
它的作用就好比去看电影要拿着电影票根据电影票上面的座位号找到座位其中座位就是Handler,电影票以及上面的座位号就是URL HandlerMapping 负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
HandlerAdapter:处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过适配器可以对更多类型的处理器进行执行。 播放的电影是3D的你看不清楚,因此电影院跟你说你要想看清电影就必须戴3D眼镜。也就是说Handler满足一定的要求才可以被执行。
Handler:后端控制器
Handler是后端控制器,在前端控制器的控制下后端控制器对具体的用户请求进行处理,Handler涉及到具体的用户业务请求,所以一般情况下需要程序员根据业务需求开发。
ViewResolver:视图解析器
ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
springMVC优势
1、清晰的角色划分:
前端控制器(DispatcherServlet)
请求到处理器映射(HandlerMapping)
处理器适配器(HandlerAdapter)
视图解析器(ViewResolver)
后端控制器(Handler)
2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要;
3、由于命令对象就是一个POJO,无需继承框架特定API,可以使用命令对象直接作为业务对象;
4、和Spring 其他框架无缝集成,是其它Web框架所不具备的;
5、可适配,通过HandlerAdapter可以支持任意的类作为处理器;
6、可定制性,HandlerMapping、ViewResolver等能够非常简单的定制;
7、功能强大的数据验证、格式化、绑定机制;
8、利用Spring提供的Mock对象能够非常简单的进行Web层单元测试;
9、本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
10、强大的JSP标签库,使JSP编写更容易。 ……还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等。
验证器( Validator)
命令对象(Command 请求参数绑定到的对象就叫命令对象)
表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象
入门程序
1.创建maven web工程
2.配置pom.xml文件
(添加spring-webmvc依赖)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
在src/main/resources目录下创建spring.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置controller(处理器)的映射路径
id:映射路径
class:Controller的类名
-->
<bean id="/hello" class="com.zhiyou.controller.HelloController"></bean>
<!-- 配置处理器映射器 handlerMapper
(默认)
根据映射路径查找对应处理器
-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 配置处理器适配器 handerAdapter
(默认)
调用处理器的方法 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
配置前端控制器web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1"
metadata-complete="true">
<!--是否加载注解-->
<!-- 展示应用名称 -->
<display-name>WebDemo</display-name>
<!--配置前端控制器servlet-->
<servlet>
<!--配置前端控制器路径 -->
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--指定上下文配置位置,spring.xml-->
<init-param>
<!-- web.xml通过contextConfigLocation配置spring -->
<param-name>contextConfigLocation</param-name>
<!--指定要配置的spring的文件 -->
<param-value>classpath:spring.xml</param-value>
</init-param>
<!--表示随web服务器启动 -->
<!--服务器启动时就会加载
当小于0时,servlet被选择时才会启动
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<!--资源路径
.url-pattern编写方式:
2.1 url-pattern 可以编写多个
2.2 精确匹配
<url-pattern>/hello</url-pattern>
<url-pattern>/system/hello</url-pattern>
2.3 扩展匹配
<url-pattern>/abc/*</url-pattern>
2.4 后缀匹配:
<url-pattern>*.action</url-pattern>
<url-pattern>*.do</url-pattern>
2.5全部匹配
<url-pattern>*</url-pattern>
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
方法返回值的设置、web跳转路径的设置、提交方法的设置
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="house/add">添加界面</a>
<form action="add" method="post">
<input type="submit" value="添加"/>
</form>
</body>
</html>
package com.zhiyou.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
//@Controller创建对象
@Controller
//配置跳转路径
@RequestMapping("house")
public class MsgController {
/* @RequestMapping参数:
* method:请求方式,可以限定此方法可以接受到的请求方式
*/
@RequestMapping(path="add",method=RequestMethod.GET)
public String toAddView(){
System.out.println("界面跳转");
return "home";
}
@RequestMapping(path="add",method=RequestMethod.POST)
public String addAction() {
System.out.println("添加数据");
return "list";
}
}
package com.zhiyou.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class HelloController {
@RequestMapping("/hello")
public ModelAndView helloAction(){
ModelAndView mView = new ModelAndView();
//request.setAttribute("name","张三")
//把数据存放到request域中
mView.addObject("name", "张三");
mView.setViewName("list");
return mView;
}
@RequestMapping("/login")
public ModelAndView login(){
ModelAndView mView = new ModelAndView();
mView.setViewName("home");
return mView;
}
}
package com.zhiyou.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.log.UserDataHelper.Mode;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/* 方法的返回值:
* 1.ModelAndView
* 通过model在request域中存数据
* 使用请求转发的方式进行界面跳转--路径会经过视图解析器
*
* 2.String
* 直接写路径,使用请求转发方式跳转,路径会经过视图解析器
* 路径前加 forward: 前缀:指定使用请求转发方式处理
* 路径不会经过视图解析器
* 路径前加redirect: 前缀: 指定使用重定向的方式处理
* 路径不会经过视图解析器
*
* 3.void
* 需要自己使用request,response实现界面跳转
*/
@Controller
public class FristController {
@RequestMapping("m1")
public String method1(){
System.out.println("method1.....");
//return "list";
// /WEB-INF/view/msglist.jsp
//return "forward:/msglist";
return "redirect:/msglist";
}
@RequestMapping("msglist")
public ModelAndView listAction(){
ModelAndView mView = new ModelAndView();
System.out.println("获取数据,界面跳转");
mView.setViewName("list");
return mView;
}
@RequestMapping("m2")
public void method2(HttpServletRequest request,HttpServletResponse response){
System.out.println("method22222...");
try {
request.getRequestDispatcher("/WEB-INF/view/list.jsp").forward(request, response);
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
方法的参数
package com.zhiyou.controller;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane.IconifyAction;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import com.zhiyou.pojo.User;
/* Controller中方法的参数
* 1.请求的参数名称和 方法中的参数名称保持一致
* 2.基本数据类型的数据在方法中使用时,写成对应的包装类类型
* 3.当请求的参数名称和方法的参数名称不一样时,使用@RequestParam注解绑定
* 4.@RequestParam 注解
* value: 设置 方法中的参数要和 哪个请求参数绑定
* required: 请求的参数是否是必须的
* defaultValue:请求参数的默认值
*
* @Param @RequetParam @RequestMapping
*
*/
@Controller
public class UserController {
@RequestMapping("login")
public ModelAndView login(@RequestParam(required=true,defaultValue="admin")String username,@RequestParam("password")String pwd,Integer age,HttpServletRequest request) throws UnsupportedEncodingException{
//request.setCharacterEncoding("UTF-8");
ModelAndView mView = new ModelAndView();
//String username = request.getParameter("username");
//Integer.parseInt(age); null
System.out.println("name:"+username);
System.out.println("password:"+pwd);
System.out.println("age:"+age);
mView.setViewName("home");
return mView;
}
@RequestMapping("register")
public String register(User user,Integer pid){
//String username = request.getParameter("username");
//User user = new User();
//user.setUsername(username);
System.out.println(user);
System.out.println(pid);
return "home";
}
@RequestMapping("hobby")
public String chooseHobby(Integer[] hobby){
//String[] hobbys= request.getParameterValues("hobby");
System.out.println(Arrays.toString(hobby));
return "home";
}
// user/id ---delete请求
// user/id ---get请求
// user/id ---put请求
//@PathVariable 绑定路径中的数据
@RequestMapping("delete/{delId}")
public String delete(@PathVariable("delId")Integer id){
System.out.println("要刪除的id:"+id);
return "home";
}
}