【21.11.7】SpringMVC
1. 入门须知
1.1、知识脉络
-
javaSE:认真学习、老师带
-
javaWeb:认真学习、老师带
-
-
剩下的java路线:SpringMVC + Vue + SpringBoot + SpringCloud + Linux
1.2、重点
-
掌握SpringMVC的执行流程!【理论】
-
SpringMVC官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html
-
SSM框架整合【实践】
2. 了解MVC
MVC:(Model)模型(dao,service)、(View)视图(jsp等)、(Controller)控制器(Servlet)
2.1、什么是MVC


JSP本质就是一个Servlet!!


面试题:你项目的架构是设计好的,还是演进的?
那肯定是演进的!!随着时代的进步、用户量的增加等、优秀流行框架的层出不从使得我们必须优化我们的项目,使得项目更好、更快地适应当前阶段的运行!!



2.2、回顾servlet
(1). 创建maven项目,删除src,让其变成父工程
(2). 在父工程的pom.xml文件上导入所需要的依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl-api -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
(3). 创建子工程项目并让其变成web项目



(4). 查看子项目有没有承接了父项目的依赖,如果没有,那就需要在子工程的pom.xml里重新导入依赖!

(5). 编写一个servlet类
注意点:
-
获取前端参数:req.getParameter("method")
-
获得session设置属性:req.getSession().setAttribute("msg","执行了add方法");
-
携带请求和反馈回来的数据转发视图: req.getRequestDispatcher("/WEB-INF/jsp/test.xml").forward(req,resp);
public class HelloServlet extends HttpServlet {
(6). 创建简单的页面
如果是一些公共可见的页面,可以放在web目录下面;如果是用户不可见的,为了安全起见,放在WEB-INF目录下!!

简单的test.jsp:
<%
form.jsp:
<%
(7). 去web.xml注册servlet
代码流程:首现页面通过表单action=“/hello”配置一个请求,然后这个表单所携带的数据会通过post的方法来到xml配置文件,根据“/hello”找到servlet-mapping映射,再通过servlet-name找到servlet-class,根据servlet-class绑定的类会找到servlet类的所在,从而实现跳转,当跳转到servlet类就会进行相应的业务处理,然后重定向或转发到相应的页面,其中可以通过request、response、session在页面获取数据并进行显示!!
(8). 配置tomcat服务器





3. 第一个SpringMVC项目
3.1、为什么要学习SpringMVC?

简单原理:



3.2、第一个程序hellomvc
(1). 在web.xml里注册dispatchServlet
(2). 在spring-servlet.xml文件中配置
(3). 写一个controller类来实现Controller接口
//注意:这里我们先导入Controller接口
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
//封装对象--存数据,放在ModelAndView中
mv.addObject("msg","HelloSpringMVC!");
//封装要跳转的视图,放在ModelAndView中
//设置视图的名字
mv.setViewName("hello"); //表示:自动拼拼接成这样子: /WEB-INF/jsp/hello.jsp
return mv;
}
}
(4). 编写一个简单的hello.jsp页面
<%
(5). 结果展示:

代码流程:当Tomcat发布成功,从浏览器地址栏输入请求"/hello",会跳到web.xml里的servlet-mapping去匹配,因为我们在那里设置了<url-pattern>/</url-pattern>表示除了.jsp的请求,其余的请求都能匹配到,然后根据servlet-name往上找到这个名字所绑定的类,由代码可以知道,这个类关联了spring的核心配置文件,即表示找到了这个类就能找到了spring的核心配置文件,接着“/hello”这个请求会通过diapatcherservlet转发到spring核心配置文件里并依次经过映射器、适配器,到达适配器之后,适配器会根据这个请求去匹配spring容器里包含的bean的id,看是否能匹配上,能匹配上的话,就会通过这个bean绑定的class跳转到相应的controller类,在这个类中会把相关数据(调用业务层所返回来的结果)和要去的页面名字封装进ModelAndView,然后通过return把ModelAndView返回到适配器,再由适配器转发到dispatcherservlet,接着再经dispatcherservlet转发到spring核心配置文件里的视图解析器,最后这个视图解析器会根据ModelAndView的信息自动拼接所要去往的页面路径,并将ModelAndView里所携带的数据显示到页面上!!
(5). 可能遇到的问题:
启动tomcat时,报404找不到页面!
解决方法:
-
查看控制台输出,看一下是不是缺少了jar包
-
如果jar包存在,但在out文件夹没有找到,就在IDEA的项目中添加lib文件夹,把项目所需要的所有jar包放进去
![image-20211107212710210]()
![image-20211107212905554]()
![image-20211107212947371]()
![image-20211107213034615]()
-
重启Tomcat即可解决!
3.3、SpringMVC执行原理




先找处理器,再找适配器,接着去调用视图解释器,最后DispatcherServlet根据视图解析器的结果调用具体的视图,并将其呈现给用户!!
3.4、再建一个项目巩固学习
(1). 新建一个test.jsp页面

<%
(2). 配置DispatchServlet
(4). 编写springMVC配置文件
(5). 编写controller类
package com.kuang.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//7.实现Controller接口
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//8.先new一个ModelAndView
//这个类是返回一个ModelAndView交给视图解析器去执行
ModelAndView mv = new ModelAndView();
//9.业务代码(执行完会有返回值的!!)
//假设现在就返回了字符串
String result="HelloSpringMVC";
// //这个是键值对,把我们的返回值封装到ModelAndView中
mv.addObject("msg",result);
//10.视图跳转 :直接设置视图的名字就可以了
mv.setViewName("test");
//11.就会把mv返回到视图解析器去处理
return mv;
}
}
4. 使用注解开发SpringMVC
4.1、代码示例
(1). 在web.xml中配置DispatchServlet
(2). 在springmvc-servlet.xml中配置支持注解驱动
springmvc核心!!
(3). 编写Controller类
@Controller、@RequestMapping("XXX")、Model model
4.2、Controller配置总结
(1). 控制器Controller
-
控制器提供复杂的访问应用程序的行为,通常通过接口定义或注解定义这两种方式来实现
-
控制器负责解析用户的请求并将其转换为一个模型
-
在springMVC使用注解的情况下,一个控制器类可以包含多个方法
-
在springMVC中,对于Controller的配置方式有很多种
(2). 编写一个controller类实现Controller接口
-
Controller是一个接口,在org.springframework.web.servlet.mvc包下,接口中只有一个方法ModelAndView handleRequest
-
实现该接口的类就会获得控制器的功能:处理请求并返回一个模型与视图对象!
-
controller类写完,要去spring配置文件中注册请求的bean,name或id对应请求路径,class对应处理请求的类
<bean id="/hello" class="com.kuang.controller.HelloController"/> -
缺点:一个控制器中只能写一个方法,如果要多个方法则需要定义多个controller类,这种定义方式比较麻烦!!
(3). 使用注解@Controller
-
@Controller注解用于声明spring类的实例是一个控制器
-
spring可以使用扫描机制来找到应用程序中所有基于该注解的控制器类,为了保证spring能找到你的控制器,一定要在配置文件中声明组件扫描!!
-
@Controller代表这个类会被spring接管,这个类中的所有方法,如果返回值是String,并且有具体的页面可以跳转,那么就会被视图解析器解析!!
4.3、@RequestMapping总结
-
@RequestMapping注解用于映射url到控制器类或一个特定的处理程序的方法
-
既可以用于类上也可以用于方法上
-
用于类上,表示类中所有相应请求的方法都要以该地址作为父路径才能进行跳转!!
-
多个请求走同一个方法时:只需用value加花括号设置多个请求即可!!
5. RestFul风格
5.1、介绍
(1). 概念:RestFul就是一个资源定位及资源操作的风格,不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简介、更有层次、更安全(不暴露变量名)、更易于实现缓存等机制。
(2). 功能
-
资源:互联网所有的事务都可以被抽象为资源
-
资源操作:使用POST、DELETE、PUT、GET,使用不同的请求方式对资源进行操作
-
分别对应添加、删除、修改、查询

传统的参数通过问号分隔且暴露变量名;RestFul通过/来分隔,不暴露变量名!!
(3). @PathVariable

在浏览器地址栏中输入:local host:8080/commit/1/2,那么就会将参数传给p1,p2,将进行运算,将结果返回到jsp页面上!

地址栏一样,但是设置的请求方式不同,所以会有不同jsp页面,可以达到url的复用。如果请求方式相同且地址栏相同,那么就会报以下错误:

5.2、指定请求方式
(1). 方式一(使用method)

(2). 方式二(使用注解)

@RequestMapping是一个总的注解,无论是哪种请求方式都适用!!
6. 转发和重定向
(1). 没有视图解析器(原生态的)

(2). 没有视图解析器2

相当于用了原生的转发和重定向,只不过比原来代码的简洁而已!!
地址栏输入原来的请求:

重定向之后:

(3). 有视图解析器

7. 前端接收请求参数及数据回显的方式
7.1、接收请求参数的方式
(1). 传统的获得表单的数据
request.getParameters( )
(2). 处理前端提交的数据
-
提交的域名称和处理方法的参数名一致
地址栏输入:loacalhost:8080/user/t1?name=yuzhou
控制台输出:接收到前端的数据为yuzhou
页面输出:yuzhou
-
提交的域名称和处理方法的参数名不一致
@RequestParam:这个注解用不用都加上,可以清晰地让你知道这个参数是从前端接收的,方便你维护,而从前端传参只能按注解里的名字来传。这个注解限定可以避免很多无用的请求。比如上面那种方式,无论你在地址栏里输入什么,它都会传给name,这有可能造成无用的请求出现!!所以要养成这个习惯!!
地址栏输入:loacalhost:8080/user/t1?username=zhangyuzhou
控制台输入:接收到前端的数据为zhangyuzhou
页面显示:zhangyuzhou
-
提交的是一个对象
假设转递的是一个对象User并能匹配User对象(实体类)中的字段名,那么就传参成功,如果匹配不到就为null!!
地址栏输入:loacalhost:8080/user/t1?id=1&name=yuzhou&age=21
实体类:
public class User {
private int id;
private String name;
private int age;
}控制台输入:User(id=1,name=zhangyuhzou,age=21)
假设如果name不一致,那么就为null,结果如下:User(id=1,name=null,age=21)
7.2、数据返回到前端
页面
(1). 通过ModelAndView返回(最原始的)
(2). 通过Model(继承了ModelMap)返回---精简版的,大多数情况下我们会使用它!!
(3). 通过ModelMap(继承了LinkedHashMap)返回,用法和Model是一样的!!
(4). 三者的区别
-
Model:只有寥寥几个方法适合用于存储数据,简化了新手对于Model对象的操作和理解
-
ModelMap继承了LinkedMap,除了实现了自身的一些方法,同样继承了LinkedMap的方法和特性
-
ModelAndView可以在存储数据的同时,可以进行设置返回的逻辑视图,进行控制视图层的跳转!!
8. 乱码问题
8.1、用servlet来解决
request.setCharacterEncoding("utf-8");
8.2、改请求方式
有时候用Post请求会出现乱码,你把它改成用Get请求,有机会能把乱码问题解决!!
8.3、写过滤器解决乱码
自写一个类实现Filter接口
public class EncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
//让这个链走下去,不要让它卡在这
filterChain.doFilter(request,response);
}
public void destroy() {
}
}
一定要去配置文件web.xml配置一下
<url-pattern>/*</url-pattern>
<!--配置过滤器-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.kuang.Filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<!--这里是要用/*,因为它的乱码有可能出现在jsp页面里,所以
我们要拦截有关jsp页面的请求并处理它-->
<url-pattern>/*</url-pattern>
</filter-mapping>
8.4、用SpringMVC提供的过滤器解决乱码
直接在web.xml配置就可以用了!!
<!--配置SpringMVC的过滤器-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
8.5、检查Tomcat的配置文件
找到tomcat----->conf---->打开servlet.xml,做以下修改:

8.6、网上大神写的自定义过滤器(终极方法了)
/**
* 解决get和post请求 全部乱码的过滤器
*/
public class GenericEncodingFilter implements Filter {




