一、Sping MVC
由于Servlet整个生命周期都是被Tomcat进行管理的,无法把Servlet放入到Spring容器中。所以每次在编写Servlet时都需要编写init方法先获取到Spring容器,然后从Spring容器中取出需要使用的Bean。
整个init方法显然都是固定套路的代码,对于这样的代码,完全可以使用Front设计模式进行修改。
●使用Front设计模式
Front (前端)设计模式就是有一个前端(不是前端专业那个前端,是最前面的意思)统一入口,在统一入口根据请求url调用自己的编写的普通方法。
●使用Front设计模式的优点
•只需要在一个Servlet中编写获取容器Bean的代码,减少了代码冗余。
•不需要为每个控制器都创建一个类,而是可以在一个普通Java类中提供普通实例方法代表以前servlet中的services方法。
•因为可以自己编写普通Java类,这类可以放入到Spring容器中,注入Service更方便
•同时因为是自己编写的Java,所以可以进行一些封装,对其他操作进行简化。
●Spring MVC
Spring MVC虽然在平时认为是一个独立的框架。但其本质为Spring框架的一个扩展,在pring官方ZIP包就是一个spring-webmvc.jar的jar包。
Spring MVC在Spring官方的Projects里面顶级项目并没有,可以认为Spring MVC属于Spring Framework的二级子项目。
Spring MVC是基于Front设计模式,总体效果和自己写的Front结果类似,在Spring MVC中已经帮助编写了前端入口DispatcherServlet,里面编写了请求分发功能,但是并没有提供@webservlet 注解,需要我们在web.xml手动编写<servlet>配置。
MyController在Spring MVC称为控制器类(Handler),里面的方法称为:控制单元(HandlerMethod)
从Spring TVC容器取出 放入Spring IVC容器 放入Spring容器
Spring MVC这个框架必定在MVC三层中都有自己的功能。例如:
M:在模型层包含:数据校验
V:在视图层包含:国际化、标签库
C:在控制层包含的功能就更多了:转发重定向、参数、拦截器、作用域等
●Spring中的父子容器
因为Spring MVC属于Spring的子框架,所以Spring MVC中可以使用Spring框架的全部内容。
Spring官方为Spring MVC专门定义了一个容器,这个容器里面放Spring MVC中全部Bean。
这个容器属于Spring容器的子容器。
规定:Spring MVC子容器可以调用Spring父容器的全部内容。但是Spring父容器不能调用Spring MVC子容器内容。
二、Spring MVC环境搭建
●创建项目并添加依赖
新建Maven项目springmvc1,并添加webapp/WEB-INF/web.xml,在IDEA中把web模块相关配置配置上。
在pom.xml中添加Spring MVC的依赖和Tomcat插件。
Spring MVC在平时随意可以当成一个独立框架看待,但其本质只是Spring Framework中的spring-webmvc.jar文件,这个jar文件依赖了spring web模块。所以在只使用Spring MVC框架时需要导入springwebmvc依赖即可。
●Spring MVC-路径匹配
注意:1、定义路径中的/ 可以不携带,因为框架底层做了对应封装 即使不写也不会报错,但是建议写上:/abc
2、路径书写时候规则(ant表达式)
?:匹配任意【一个】字符例子:abc?代表路径整体长度是4 abc代表是开头?任意字符
*:匹配任意【一级目录】 /dahjd:一级
**:匹配任意多级目录 /adjks/dasda/da/s:多级
路径匹配顺序:固定值(bjsxt1)>?形式(bjsxt?)>一个*号(/*)>**形式
3、在整个项目模块中不可以出现@RequestMapping地址
4、@RequestMapping可以放到类上和方法上
三、@RequestMapping注解
@RequestMapping注解可以写在控制器类上,也可以写在控制单元方法上。
•写在类上,表示当前类所有控制单元的映射路径,都以指定路径开头。
•写在方法上,表示当前方法的映射路径。最终访问这个控制单元的映射路径为:类上@RequestMapping映射路径+方法上@RequestMapping映射路径。
●value属性
value:定义映射路径。URL中出现指定映射路径时会执行当前控制单元。支持一个方法多个映射路径。value属性可以省略不写,且Java的注解中,如果属性是数组类型,且取值只有一个时,可以省略不写。所以一共有四种写法。
注意:如果@RequestMapping只需要设置value属性的话可以省略。但是需要设置多个属性时value不能省略。取值前面的/表示映射到项目根目录,可以省略不写
●name属性
name:给控制单元定义一个名称。可以理解name是控制单元的注释。
●path属性
path属性和value属性使用方式是相同的,都是设置控制单元的映射路径。
●method属性
method属性类型是RequestMethod,,RequestMethod是枚举类型,支持HTTP协议中绝大多数请求类型。
当设置了method属性后,表示只有指定类型请求方式才能访问这个控制单元方法,其他的请求方式访问时,响应会出现405状态码。
•Spring MVC框架针对不同请求方式提供了5个专门请求方式的注解
①@PostMapping("/first")
等效于@RequestMapping(value = "first",method = RequestMethod.POST)
②@GetMapping("/first")
等效于@RequestMapping(value = "/first",method = RequestMethod.GET)
③@DeleteMapping("/first")
等效于 @RequestMapping(value = "/first",method = RequestMethod.DELETE)
④@PutMapping("/first")
等效于@RequestMapping(value = "/first",method = RequestMethod.PUT)
⑤@PatchMapping("/first")
等效于@RequestMapping(value = "/first",method = RequestMethod.PATCH)
●params属性
params属性类型是String,,表示请求中必须包含指定名称的请求参数。
如果请求中没有包含指定类型参数,响应会出现400状态码。并且明确提示在实际的请求参数中没有明确设置name属性。
●headers属性
headers属性类型是String,,表示请求头中必须包含指定的请求头参数。
如果请求头中没有指定的请求头参数,浏览器会报404
●consumes属性
consumers表示处理请求内容(Content-Type)的类型,平时多不设置,由Spring MVC自动判断。
●produces属性
produces类型是String,作用是设置@ResponseBody注解的响应内容类型。且仅当请求头中Accept中包含的值才生效。
四、映射路径
映射路径就是web.xml中<ur1-pattern>的值或者@WebServlet("")注解的值。
映射路径无论是在Servlet中还是在Spring MVC中,都表示:当URL中出现指定路径时会执行Servlet的方法或执行Spring MVC的控制单元。
只要访问URL中 http://localhost:8081/bjsxt/test中URI是/bjsxt/test,其中/bjsxt表示当前项目的名称,/test 表示映射路径。SpringMVC发现映射路径是/test 时就会执行上面的控制单元。
由于在Servlet中url-pattern必须以/开头,所以在Spring MVC中定义映射路径时也是习惯以/开头
●多级路径
映射路径:既然名字中已经叫做路径了,所以写法上也支持路径的写法。
在计算机中路径都是1以\进行分隔,例如在我的电脑中DK就是下面的路径。
但是在Java中\表示转义字符,在之前学习10时同学们就知道,在Java中路径是使用/进行分隔,表示目录层次。
在Spring MVC 的映射路径也支持多层写法
●映射路径中映射表示当控制器需要和视图资源进行跳转、引用等涉及到路径问题时会认为在webapp目录中映射一个虚拟资源。映射路径最后一个表示资源名称(test2),前面无论多少层都表示文件夹。
●多层路径中最优写法
只需要在返回值中使用绝对路径就可以减少出错的情况。
跳转时/表示项目根目录,也就是webapp目录的根目录。
●Ant风格的映射路径
在Spring MVC中支持Ant风格的映射路径写法。所谓的Ant风格就是支持三种特殊的符号
? 匹配任意单字符
* 匹配0或者任意数量的字符
** 匹配0或者更多数量的目录
•使用Ant的特殊符号时,表示模糊匹配。可能出现客户端发送过来的URL能匹配上多个映射路径,这时的优先级为:
固定值(bjsxt1)>?形式(bjsxt?)> 一个*号(/* )**形式
五、静态资源放行
按照SpringMVC的使用流程,需要在web.xml文件中配置DispatcherServlet的拦截范围,配置的拦截范围为“/”,表示拦截除jsp请求以外的所有请求。这样造成,请求是js,css,图片等静态资源的请求,也会被拦截,调用对应的单元方法来处理请求。但是,是一个静态资源的请求,不应该按照普通单元方法请求的流程来处理,而是将对应的静态资源响应给浏览器使用.
Spring MVC支持静态资源配置,当URL满足指定路径要求时不再去找控制单元,而是直接转发到特定路径中静态资源。
•配置静态资源放行
mapping:当URI是什么样格式时,不再执行控制器,而是寻找静态资源。**是通配符,表示任意层路径
location:去哪个目录中寻找静态资源。mapping中**的值是什么,就去1ocation目录中找对应资源
●关于Spring 5.3.xxx和Tomcat7插件不兼容问题
因为Spring MVC 5.3.xx里面需要使用servlet-api.jar(对应Tomcat插件中叫做:tomcat-servlet-api.jar的依赖)中HttpServletResponse中setContentLengthLong0),但是Tomcat7插件的tomcat-servlet-api.jar中没有这个方法,所以会报NoSuchMethodException。解决办法有三个:
•把Spring版本换成5.2.x或以下版本
• 使用本机Tomcat运行项目
•使用Tomcat8插件
前两种方式虽然能够让项目成功运行起来,但是属于逃避了问题,使用Tomcat8插件是最好的解决办法。
●Tomcat8配置步骤
pluginRepositories指定插件去哪个私服下载。因为在Maven中央仓库中没有这个插件,所以只能使用个人提供的仓库地址。即使内容下载完成,以后使用Tomcat8插件也需要配置这个标签。
plugin中内容和tomcat7插件类似,除了坐标换成了tomcat8的坐标。 configuration>中内容还是和以前一样。
直接点击Maven面板的plugin -> Tomcat8:run-war。
•注意,是tomcat8:run-war不是tomcat8:run
六、控制单元的方法参数
●控制单元方法参数写法
控制单元方法参数一共有两种写法:
•紧耦方式。获取原生Servlet API,通过原生Servlet API获取请求参数、设置响应内容、设置作用域的值。
•解耦方式。使用Spring MVC提供的方式获取请求参数、设置响应内容、设置作用域的值。
七、Restful请求格式
Rest(Representational State Transfer:表现层状态转译)是一种软件架构风格,其核心是面向资源的一种设计。
面向资源,意思是网络上的所有事物都可以抽象为资源,而每个资源都有唯一的资源标识,对资源的操作不应该改变这些标识。
就是每个资源都有一个url地址,而不是不同的操作有不同的url地址,比如对用户信息的增删改查,用户就是资源,增删改查是操作,以前是一个操作一个url地址,现在按照Restful的说法,url地址只能有一个。
Restful的出现同时也解决了客户端的种类多种多样造成请求的格式比较混乱的问题,Restful提供了一种统一的前后端交互的接口规范,可以更好的实现数据的交互。
@RequestMapping注解可以接收任意请求方式的请求
@GetMapping("地址"):接收GET请求,一般用在查询方法上
@DeleteMapping("地址"):接收DELETE请求,一般用在删除方法上
@PostMapping("地址"):接收POST请求,一般用户在新增上
@PutMapping("地址”):接收PUT请求,一般用在修改上
八、Spring MVC中的转发和重定向
转发和重定向。这两个概念都是出现在资源之间相互跳转的。两者区别
•转发只能跳转到当前项目内部资源。重定向可以跳转到外部资源。例如:从自己的项目中跳转到百度应该使用重定向。
•转发是一次请求,无论服务器内部转发多少次,请求对象都不变。所以转发可以共享请求域的值。同时对于客户端浏览器URL是不变的。
重定向后需要客户端重新发起请求,和重定向之前不是一个请求。所以重定向后不能获取到之前设置在请求域的值。同时客户端浏览器URL是改变的。
•转发时资源路径如果是绝对路径,第一个/表示当前项目根目录。重定向时资源路径时绝对路径,第一个/表示Tomcat的webapps目录,即:当前项目的上层目录。
•转发的代码实现
request.getRequestDispatcher("/first.jsp").forward(request,response);
•重定向的代码实现
response.sendRedirect("/bjsxt/first.jsp");
●Spring MVC中的转发和重定向
在Spring MVC框架中,默认情况下都使用转发进行寻找资源。
在资源路径前面添加forward:表示转发。因为写不写forward:都是转发,所以为了代码写起来简单一些,多省略forward。
●设置作用域的值
Spring MVC中提供了request作用域的解耦写法。没有提供Session组用域和Application作用域的解耦写法。也就是说当像给Request作用域设置内容时有两种写法,给Session和Application作用域设置值只有紧耦方式。
Spring MVC中提供的两种方式都是在控制单元方法参数中添加org.springframework.ui.Model或java.util.Map对象。这两种方式的本质都是使用了Servlet中request.setAttribute(String,String);方法。
•使用Model设置请求域的值
只需要在控制单元方法参数中添加Model对象,对象名称任意。
Model是一个接口,里面有很多子接口和实现类。当放置Model接口时,Spring MVC默认注入的是BindingAwareModelMap
在Model接口中有很多个方法,里面最常用的有两个addAttribute(String,Object)和addAllAtributes(Map)
●使用ModelAndView转发重定向
ModelAndView中的Model代表模型,View代表视图,业务处理器调用模型层处理完用户请求后,把结果数据存储在该类的model属性中,把要返回的视图信息存储在该类的view属性中,然后让该ModelAndView返回该SpringMVC框架。
九、@ResponseBody注解
@ResponseBody注解是类或方法级注解。
当方法上添加@ResponseBody注解后,控制单元方法返回值将不再被视图解析器进行解析。而是把返回值放入到响应流中进行响应。
●最简单使用
直接在方法上添加上@ResponseBody,Spring MVC会把返回值设置到响应流中。
●Spring MVC转发和重定向时绝对路径
在Spring MVC中无论是转发还是重定向,使用绝对路径时/都表示项目根目录。