mybatis的核心设计是<resultMap>
spring的核心设计是<bean>(别跟我提IOC和AOP思想)
springMVC的核心就是servlet
一、认识SpringMVC
1、 SpringMVC是什么
SpringMVC 是 Spring 框架内置的 MVC 的实现。SpringMVC 就是一个 Spring 内置的 MVC 子框架
Spring 子框架:意味着 SpringMVC 的包都在 Spring 框架里面。
MVC:Model-View-Control(模型--视图--控制器),这是一个解决页面代码(视图代码)和后台代码分离的设计思想。
2、SpringMVC的作用
MVC 模式(Model-View-Controller):为了解决页面代码和后台代码的分离。
既然 SpringMVC 是一个 MVC 框架,首先就要解决 MVC 理念提出的问题。页面代码和后台代码分离。
3、为什么要学习 SpringMVC
问题:我们已经学习了 Servlet/JSP 了。为什么还要学习 SpringMVC 呢?
我们知道,Servlet /JSP就是一套MVC模式的实现!!SpringMVC也是MVC的实现,那么学SpringMVC的意义在哪里?
SpringMVC不仅仅是MVC的实现,它还是一个框架。这意味着,除了MVC的实现以外还提供了大量的辅助页面请求处理的功能组件!!!
① 支持直接一个方法对一个请求
② 支持数据的自动封装
③ 自动支持上传组件
④ 自动支持JSON的转成
一、回顾servlet
为什么要回顾servlet?因为springMVC的底层是servlet。
Servlet 是一种实现动态页面的技术。我们可以继承httpServlet接口写一个自己的servlet类,所以也可以把servelet理解成一个java类。
这个servlet类运行起来的作用就是收集前端的request请求,映射到后端业务逻辑,再把后端的结果返回给前端(或者直接理解成分割前端和后端更好一些),实现动态页面。
之前学tomcat的时候没有手动开启过servlet,因为tomcat内置了servlet。
现在我们手动写一个自己的servlet,主要分2步:
创建一个java类并且继承HttpServlet,重写doGet()或者doPost()方法
在web.xml里注册servlet
1.1 创建maven项目,导入jar包,提升为web项目
创建一个空的maven project
删掉项目的src目录
在project下创建一个空的maven module(也不选webapp模板),然后将其提升为web项目
就出现了webapps的发布目录:
PS:通过tomcat发布一个项目project01,将其上下文改为“/”(不改的话,访问这个项目的url是localhost:8080/project01),则localhost:8080/默认定位到web目录下,也就是这个项目,如果我在web下新建一个/new/new.jsp,访问的url便是localhost:8080/new/new.jsp 。web下的网页是公开的,为了更安全我们可以放在web/WEB-INF下
导入jar包(最好project的pom.xm文件和module的pom.xml文件都导,这样方便把module拷给别人。而且打包的时候maven会自动查重并不会打两份)
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.16</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
1.2继承HttpServlet类
新建包,新建MyServlet类,继承HttpServlet类
重写doGet和doPost方法
package com.company.kuang;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取前端request参数
String method = req.getParameter("method");
if(method.equals("add")){
req.getSession().setAttribute("msg","执行了add方法");
}
if(method.equals("delete")){
req.getSession().setAttribute("msg","执行了delete方法");
}
//2.调用后端业务层
//在这里我们只是测试,所以不写了
//3.视图转发或重定向
req.getRequestDispatcher("WEB-INF/jsp/test.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp); //直接调用上面的doGet
}
}
PS:如果有两个页面,那么就要写两个servlet类,然后在web.xml里注册两个servlet。
首页的配置:
跳转页面的创建:在web/WEB-INF下新建jsp/test.jsp,让其获取msg
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
1.3 在web.xml里注册servlet
<?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">
<servlet>
<servlet-name>myservlet</servlet-name>
<servlet-class>com.company.kuang.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myservlet</servlet-name>
<url-pattern>/hello</url-pattern>
<!--访问localhost:8080/项目站名/hello 就会被servlet拦截
不过我们一般把项目站名配置为‘/’-->
</servlet-mapping>
</web-app>
1.4 给项目配置tomcat
由于我们建的是maven项目,不像springboot内置了tomcat,我们需要手动给这个项目配置我们本地的tomcat。
下面是在给tomcat配置项目,不然你有四五个项目,tomcat也不知道该替你跑哪个呀
1.5 测试
二、springMVC原理讲解
2.1 手动实现springMVC
从此以后不用再手动写servlet了!之前访问多个页面要写多个servlet,现在出现了一个servlet的集中调度器DispatcherServlet,只用一个DispatcherServlet,它可以帮我们匹配所有页面。现在我们不需要写多个servlet了,但是需要写多个controller类。
2.1 在web.xml里配置spring帮我们写好的DispatcherServlet
2.2 xml配置
2.3 手动编写Controller
因为在上面的springmvc-servlet.xml中配置了前缀/WEB-INF/jsp和后缀.jsp,所以跳转的视图是/WEB-INF/jsp/hello.jsp
2.2 springMVC底层原理——解析上述过程
PS:红色线部分是需要我们自己写的,黑色线是springMVC底层实现的
DispatcherServlet表示前端控制器,是整个springMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求
对应的配置:
我们假设请求的url为:http://localhost:8080/SpringMVC/hello
如上url拆分成3部分
http://localhost:8080 服务器域名
SpringMVC 部署在服务器上的web站点,我们一般直接用‘/’
hello 控制器
通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器
2~5:根据控制器名字“hello”,找到对应的controller。
对应的配置:
具体步骤:
2:HandlerMapping为处理映射,由DispatcherServlet调用。
3:HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找的控制器为:hello
4:HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等
5:HandlerAdapter表示处理器配置器,按照特定的规则去执行Handler
6:Handler让具体的Controller执行
7:Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView
8:HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet
9:DispatcherServlet调用视图解析器(ViewResolver)来解析视图逻辑名
10:视图解析器(ViewResolver)将解析的视图逻辑名传给DispatcherServlet
11:DispatcherServlet调用具体的视图
12:最终视图呈现给用户
三、约定大于配置,使用注解开发springMVC
spring还用着配置文件,但是从springMVC开始,全面使用注解开发
1.创建一个新的maven module,提升为web项目,导入依赖(前门步骤有)
给依赖关闭一下过滤,防止我们的配置文件被“约定大于配置”过滤掉
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
给项目打包增加lib目录
然后apply
2.死配置——DispatcherServlet
意思是以后凡是要写springMVC的项目,直接拷进去。
<?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">
<!--1.注册DispatcherServlet-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联SpringMVC配置文件:通过初始化参数指定SpringMVC配置文件的位置-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--配置DispatcherServlet启动级别:数字越小,启动越早-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有请求都会被springmvc拦截-->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3.死配置——springmvc配置文件
handler映射器
handler适配器
视图解析器
意思是以后凡是要写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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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">
<!--自动扫描扫描指定包里的注解(我们创建一个com.kuang.controller包,用来写controller)-->
<context:component-scan base-package="com.kuang.controller"></context:component-scan>
<!--开启注解的支持-->
<!--<context:annotation-config/>-->
<!--让springMVC不处理静态资源-->
<mvc:default-servlet-handler/>
<!--
①替代了之前的handler映射器和handler适配器的配置。
②要想使@RequestMapping注解生效,必须向上下文中注册handler映射器和handler适配器的实例
annotation-driver配置自动帮我们完成了!
-->
<mvc:annotation-driven/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/" />
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
里面的<mvc:annotation-driven>注解就是替代了下面这两行配置。
根据视图解析器的配置,我们知道,要把jsp页面建在/WEB-INF/jsp下
4. 编写Controller
如果返回值是String,并且有具体的页面可以跳转(意思是我们写了hello.jsp),那么就会被视图解析器解析。如果没有写hello.jsp,那么访问的时候会报404错误。
@Controller
public class MyController {
@RequestMapping("/hello")
public String hello(Model model){
//封装数据
model.addAttribute("msg","Hello,SpringMVC!");
return "hello"; //视图名,会被视图解析器处理(拼接成/WEB-INF/jsp/hello.jsp)
}
}
PS:方法的参数可以用Model或者ModelAndView,Model是ModelAndView的简化版
5. 编写要跳转的jsp页面
在/WEB-INF目录下新建jsp目录,创建hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
处理过程:用户请求localhost:8080/hello后,会被DispatcherServlet拦截(根据DispatcherServlet的配置,所有localhost:8080/请求都被拦截),然后分发给@RequstMapping("/hello")对应的controller,controller调用业务层,然后封装数据,跳转到hello.jsp显示,
来开启tomcat测试一下,重新配置一下tomcat要发布的新项目
四、controller控制器详解
实现controller的两种方式:① 注解(√) ②实现接口(×)
五、@RequestMapping详解
六、Restful 风格
普通风格:
前端要①用?分割方法和参数 ②指定参数名 ③多个参数用&连接
Restful风格
前端要这样写:①不用写参数名了 ②不同的参数用/分割
七、重定向和转发的区别
7.1 重定向与转发的区别
1.重定向访问服务器两次,转发只访问服务器一次。
2.转发页面的URL不会改变,而重定向地址会改变
3.转发只能转发到自己的web应用内,重定向可以重定义到任意资源路径。
4.转发相当于服务器跳转,相当于方法调用,在执行当前文件的过程中转向执行目标文件,两个文件(当前文件和目标文件)属于同一次请求,前后页 共用一个request,可以通过此来传递一些数据或者session信息,request.setAttribute()和 request.getAttribute()。而重定向会产生一个新的request,不能共享request域信息与请求参数
5.由于转发相当于服务器内部方法调用,所以转发后面的代码仍然会执行(转发之后记得return);重定向代码执行之后是方法执行完成之后进行重定向操作,也就是访问第二个请求,如果是方法的最后一行进行重定向那就会马上进行重定向(重定向也需要return)。
6.无论是RequestDispatcher.forward方法,还是HttpServletResponse.sendRedirect方法,在调用它们之前,都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容,这些内容将被从缓冲区中移除。
可以这么理解:
转发相当于,张三向你借钱,但是你兜里没钱,所以你去找李四借到钱之后借给张三。对于张三而言并不知道你的钱是和李四借的。
重定向相当于,张三向你借钱,你兜里没钱,你告诉他李四有钱,所以张三再次去找李四借钱。
7.2 调用方式
转发和重定向在Java中的方法如下:
request.getRequestDispatcher("/SecondServlet?addParam=newParam").forward(request, response);
response.sendRedirect("/WebSocket/SecondServlet");
WebSocket相当于项目名称,SecondServlet是具体的servlet请求。也就是转发不加项目名称,重定向可以写绝对URL,也可以写相对URL。
补充:3xx状态码与重定向相关。301是永久重定向,302是临时重定向,我们有时候希望发送永久重定向的code。上面sendRedirect默认是302。如下:
response.setStatus(301);
response.addHeader("Location", "/WebSocket/SecondServlet");
7.3 应用场景
1. 转发 request.getRequestDispatcher().forward(request,response):
属于转发,也是服务器跳转,相当于方法调用,在执行当前文件的过程中转向执行目标文件,两个文件(当前文件和目标文件)属于同一次请求,前后页 共用一个request,可以通过此来传递一些数据或者session信息,request.setAttribute()和 request.getAttribute()。
在前后两次执行后,地址栏不变,仍是当前文件的地址。
不能转向到本web应用之外的页面和网站,所以转向的速度要快。
URL中所包含的“/”表示应用程序(项目)的路径。
2. 重定向 response.sendRedirect():
属于重定向,也是客户端跳转,相当于客户端向服务端发送请求之后,服务器返回一个响应,客户端接收到响应之后又向服务端发送一次请求,一共是2次请求,前后页不共用一个request,不能读取转向前通过request.setAttribute()设置的属性值。
在前后两次执行后,地址栏发生改变,是目标文件的地址。
可以转向到本web应用之外的页面和网站,所以转向的速度相对要慢。
URL种所包含的"/"表示根目录的路径。
特殊的应用:对数据进行修改、删除、添加操作的时候,应该用response.sendRedirect()。如果是采用了 request.getRequestDispatcher().forward(request,response),那么操作前后的地址栏都不会发生 改变,仍然是修改的控制器,如果此时再对当前页面刷新的话,就会重新发送一次请求对数据进行修改,这也就是有的人在刷新一次页面就增加一条数据的原因。
7.4 springMVC使用重定向和转发
有使用视图解析器和不使用视图解析器两种方式,但是我们99%情况下都使用视图解析器。
有视图解析器的情况下,默认是转发,如果想要重定向,加一个“redirect:”
八、获取前端传来的请求参数及回显给前端
8.1 获取前端传来的请求参数
(1)当url里的参数和controller方法里的参数名称相同时
(2)当url里的参数和controller方法里的参数名称不同时
此时应该用到@RequestParam注解。这个注解和mybatis的@Param注解一样,无论参数名称是否相同,都加上他这个注解,这是编码的规范。
(3)当controller方法里的参数是一个对象时
而且智能的是,如果url中只有部分参数名匹配上了User的成员变量名,那么匹配上的部分就有值,没匹配上的为null。
8.2 回显给前端的3种方式
@RequestMapping("/test")
public void test(Model model){
//ModelAndView modelAndViw
//ModelMap modelMap