目录
一、MVC简介
MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。MVC主要作用是降低了视图与业务逻辑间的双向偶合
。
- Model:包括Value Object(数据Dao) 和 服务层(行为Service),提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
- View:负责进行模型的展示,用户界面
- Controller:接收请求并处理请求返回给View
二、SpringMVC简介
1.概述
Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。
Spring的web框架围绕DispatcherServlet
[ 调度Servlet ] 设计。DispatcherServlet的作用是将请求分发到不同的处理器(Controller),SpringMVC框架是以请求为驱动,围绕DispatcherServlet(继承了HttpServlet,由SpringMVC提供,从而简化手动处理并分发请求)分派请求并提供其他功能。
2.执行原理
当发起请求时被前端控制器拦截到请求
,根据请求参数生成代理请求,找到请求对应的页面控制器,页面控制器处理请求
,创建数据模型,访问数据库,将模型响应给前端控制器
,前端控制器
使用模型与视图渲染视图
,将结果返回给控制器,前端控制器再将视图展示
给请求者。
执行流程:
- DispatcherServlet(前置控制器)接收请求并拦截请求
- DispatcherServlet调用HandlerMapping(处理器映射器)
- HandlerMapping根据URL查找到具体的处理器但并不执行,生成处理器对象并返回给DispatcherServlet
- DispatcherServlet调用HandlerAdapter(处理器适配器)
- HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)
- Controller执行并将具体的执行信息返回给HandlerAdapter
(Controller的具体执行过程由我们设计,来获取相应数据[Model]和视图[View]信息)
- HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)
- ViewReslover解析后返回具体View
- DispatcherServlet根据Model进行渲染视图
- DispatcherServlet响应用户
三、SpringMVC简单实现
前提:构建Maven项目,导入SpringMVC依赖
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
1.xml配置文件实现
1.注册DispatcherServlet(前置处理器)
<!--1.注册DispatcherServlet-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springmvc的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别-1-->
<!--随服务器一起启动-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<!--不能使用/*,因为返回的 .jsp 会再次被sDispatcherServlet处理,导致找不到对应的controller,报404错-->
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2.编写SpringMVC的配置文件(HandlerMapping、HandlerAdapter、ViewResolver)
在resources目录下
<!--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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--添加 处理器映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--添加 处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--视图解析器:DispatcherServlet给他的ModelAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<!--前缀,页面目录前缀-->
<property name="prefix" value="/"/>
<!--后缀,页面名称后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
3.实现具体控制器(Controller),并根据Spring创建
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
//封装对象,放在ModelAndView中。Model
mv.addObject("msg","HelloSpringMVC!");
//封装要跳转的视图,放在ModelAndView中
mv.setViewName("hello"); // /hello.jsp
return mv;
}
}
<!--根据URL,找到对应Controller-->
<bean id="/hello" class="com.dxs.controller.HelloController"/>
4.实现View,并发出请求
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>title</title>
</head>
<body>
${msg}
</body>
</html>
http://localhost:8080/controller/hello.jsp
注意
:如果jar包存在,显示无法输出,就在IDEA的项目发布中,添加lib依赖
2.注解实现
1.修改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:context="http://www.springframework.org/schema/context"
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
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="com.dxs.controller"/>
<!-- 让Spring MVC不处理静态资源 -->
<mvc:default-servlet-handler />
<!--
支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
需注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter实例
-->
<mvc:annotation-driven />
<!--上两条mvc配置,实际上会默认配置,不添加也行-->
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
</beans>
2.修改Controller类
//@Controller是为了让Spring IOC容器初始化时自动扫描到
//@RequestMapping是为了映射请求路径
@Controller
@RequestMapping("/HelloController")
public class HelloController {
//真实访问地址 : /项目名/HelloController/hello
@RequestMapping("/hello")
public String sayHello(Model model){
//向模型中添加属性msg与值,可以在JSP页面中取出并渲染
model.addAttribute("msg","hello,SpringMVC");
//返回的字符串经ViewResolver处理得到准确的View路径
// /hello.jsp
return "hello";
}
}
四、Controller控制器
- 控制器提供访问应用程序的行为,通常通过
接口
定义或注解
定义两种方法实现。 - 控制器负责解析用户的请求并将其转换为一个Model
- 在Spring MVC中一个控制器类可以包含多个方法
1.实现Controller接口
上文中的xml配置方式中,就已经展示了通过实现Controller接口来创建一个Controller。
//实现该接口的类获得控制器功能
public interface Controller {
//处理请求且返回一个ModelAndView对象
ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
public class Test implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","TestController");
mv.setViewName("test");
return mv;
}
}
缺点
:一个控制器中只有一个方法,如果要多个方法则需要定义多个Controller;定义的方式比较麻烦。
2.注解@Controller
通过@Controller用于在SpringIOC容器中创建一个Controller实例。
@Controller
public class Test{
//映射访问路径
@RequestMapping("/test")
public String index(Model model){
//Spring MVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", "ControllerTest");
//返回视图位置
return "test";
}
}
控制器与视图之间是弱偶合关系
。通过不同Controller可以指向同一个View,但可以通过Controller提供的Model,在页面上展示不同内容。
(1)@RequestMapping
@RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上
。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
ResquestMapping中还有属性method来指定请求类型,如果类型不匹配,就不会映射到这个Controller。
//映射访问路径,必须是POST请求
@RequestMapping(value = "/hello",method = {RequestMethod.POST})
public String test(Model model){
model.addAttribute("msg", "hello!");
return "test";
}
此外,还有以下方法级别的组合注释:
@GetMapping //映射Get方法的请求
@PostMapping //映射Post方法的请求
@PutMapping
@DeleteMapping
@PatchMapping
3.RestFul风格
Restful是一个资源定位及资源操作的风格
。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
@Controller
public class RestFulController {
//例如请求传递a,b参数,控制器返回给界面结果
//传统请求:http://localhost:8080/工程名/test?a=1&b=2
//RestFul风格请求:http://localhost:8080/工程名/test/1/2
//使用RestFul风格的请求更简洁,同时也相对更安全。
//RequestMapping通过{}的方式获取参数
//方法的对应参数前要添加@PathVariable参数,以告知这些参数通过请求获得
@RequestMapping("/{a}/{b}")
public String index(@PathVariable int a, @PathVariable int b, Model model){
int result = a+b;
//Spring MVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", "结果:"+result);
//返回视图位置
return "test";
}
}
五、结果跳转方式
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest1");
//{视图解析器设置的前缀} + viewName +{视图解析器设置的后缀}
//就是页面的URL
mv.setViewName("test");
return mv;
}
}
1.ServletAPI
通过设置ServletAPI , 不需要视图解析器 :
- 通过HttpServletResponse进行输出
- 通过HttpServletResponse实现重定向
- 通过HttpServletResponse实现转发
@Controller
public class ResultGo {
@RequestMapping("/t1")
public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
//通过Response输出
rsp.getWriter().println("Hello,Spring BY servlet API");
}
@RequestMapping("/t2")
public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
//通过Response重定向
rsp.sendRedirect(req.getContextPath()+"/index.jsp");
}
@RequestMapping("/t3")
public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
//通过Request转发
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
}
}
2.SpringMVC
1.通过SpringMVC来实现转发和重定向 - 无需视图解析器
@Controller
public class ResultSpringMVC {
@RequestMapping("/rsm/t1")
public String test1(){
//转发
return "/index.jsp";
}
@RequestMapping("/rsm/t2")
public String test2(){
//转发二
return "forward:/index.jsp";
}
@RequestMapping("/rsm/t3")
public String test3(){
//重定向
return "redirect:/index.jsp";
}
}
2.通过SpringMVC来实现转发和重定向 - 有视图解析器
@Controller
public class ResultSpringMVC2 {
@RequestMapping("/rsm2/t1")
public String test1(){
//转发,默认方式即可
return "test";
}
@RequestMapping("/rsm2/t2")
public String test2(){
//重定向,不会采用视图解析器
return "redirect:/test.jsp";
}
}
六、数据处理
1.处理请求提交的数据
1.提交的域名称和处理方法的参数名一致
//http://localhost:8080/hello?name=dxs
@RequestMapping("/hello")
public String hello(String name){
System.out.println(name);
return "hello";
}
2.提交的域名称和处理方法的参数名不一致
http://localhost:8080/hello?username=dxs
//@RequestParam("username") : username提交的域的名称 .
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name){
System.out.println(name);
return "hello";
}
3.提交的是一个对象
public class User {
private int id;
private String name;
private int age;
//构造
//get/set
//tostring()
}
//http://localhost:8080/工程名/user?name=dxs&id=1
//如果使用对象的话,前端传递的参数名和对象名必须一致,否则就是null
@RequestMapping("/user")
public String user(User user){
System.out.println(user);
return "hello";
}
2.数据回显到前端
1.通过ModelAndView
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest1");
mv.setViewName("test");
return mv;
2.通过ModelMap
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap model){
//封装要显示到视图中的数据
//相当于req.setAttribute("name",name);
model.addAttribute("name",name);
System.out.println(name);
return "hello";
}
3.通过Model
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, Model model){
//封装要显示到视图中的数据
//相当于req.setAttribute("name",name);
model.addAttribute("msg",name);
System.out.println(name);
return "test";
}
区别
:
- Model 只有几个方法,只适合用于储存数据,简化了对于Model对象的操作
- ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性
- ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图(setViewName),进行控制展示层的跳转
七、参考
https://blog.csdn.net/floating_dreaming/article/details/89089214
https://www.bilibili.com/video/BV1aE41167Tu?from=search&seid=4116023290148988295