源码:https://github.com/tripleDemo/springmvc
三层架构
Web开发的最佳实践就是根据功能职责的不同,划分为控制层,划分为控制层、业务层、持久层。
MVC原理
MVC模型:是一种架构型的模式,本身不引入新功能,只是帮助我们将开发的结构组织的更加合理,使展示与模型分离、流程控制逻辑、业务逻辑调用与展示逻辑分离---->责任分离。
MVC框架的功能作用(WEB开发常见功能):
MVC令程序开发有章可循,但是表现层的困惑来了,因为需要处理的功能太多:设置编码、接受请求参数、输入校验、参数类型转换、把参数封装成对象、文件上传、处理响应、国际化处理、自定义标签等。
在CS架构标准的MVC中模型能主动推数据给视图进行更新(观察者设计模式,在模型上注册视图,当模型更新时自动更新视图)。但在Web开发中模型是无法主动推给视图(无法主动更新用户界面),因为在Web开发是请求-响应模型。
Front Controller模型要求在WEB应用系统的前端(Front)设置一个入口控制器(Controller),所有的request请求都被发往该控制器统一处理,处理所有请求共同的操作。学习MVC框架:都得先配置前端控制器。
什么是前端控制器
Front Controller模式要求在WEB应用系统的前端(Front)设置一个入口控制器(Controller),是用来提供一个集中的请求处理机制,所有的请求都被发往该控制器统一处理,然后把请求分发给各自相应的处理程序。一般用来做一个共同的处理,如权限检查,授权,日志记录等。因为前端控制的集中处理请求的能力,因此提高了可重用性和可拓展性。
什么是SpringMVC
MVC框架,它解决WEB开发中常见的问题(参数接收、文件上传、表单验证、国际化、等等),而且使用简单,与Spring无缝集成。Spring3.0后全面超越Struts2,成为最优秀的MVC框架(更安全,性能更好,更简单)。
支持RESTful风格的URL请求,非常容易与其他视图技术集成,如Velocity、FreeMarker。
采用了松散耦合可插拔组件结构,比其他MVC框架更具扩展性和灵活性。
(SpringMVC是同步阻塞的IO模型,资源浪费相对来说比较严重,当处理一个比较耗时的任务时,服务器的线程一直在等待接收文件,而Spring WebFlux(Spring的异步非阻塞Web框架)可以做到异步非阻塞。)
SpringMVC和Struts2对比:
- Spring MVC的前端控制器是Servlet,而Struts2是Filter。
- Spring MVC会稍微比Struts2快些,Spring MVC是基于方法设计,处理器是单例,而Struts2是基于类,每次发一次请求都会实例一个新的Action对象,Action是多例的。
- Spring MVC更加简洁,开发效率Spring MVC比Struts2高,如支持JSR303校验,且处理AJAX请求更方便。
- Struts2的OGNL表达式使页面的开发效率相比Spring MVC更高些,但是Spring MVC也不差。
SpringMVC核心组件分析
1.前端控制器DispatcherServlet
不需要我们开发,由框架提供,需要在web.xml中配置。
作用:接受请求,处理响应结果,转发器,中央处理器
2.处理器映射器HandlerMapping
不需要我们开发,由框架提供
作用:根据请求URL,找到对应的Handler
3.处理器适配器HandlerAdapter
不需要我们开发,由框架提供
作用:调用处理器(Handler/Controller)的方法
4.处理器Handler(又名Controller),后端控制器
需要我们开发,必须按照HandlerAdapter的规范去开发
作用:接受用户请求数据,调用业务方法处理请求
5.视图解析器ViewResolver
不需要我们开发,由框架/第三方提供
作用:视图解析,把逻辑视图名称解析成真正的物理视图,支持多种视图技术,JSTLView、FreeMarker、PdfView...
6.视图View
需要我们开发
作用:把数据展现给用户
@RequestMapping
RequestMapping是一个用来处理请求地址映射的注解,可以贴在类或方法上。贴在类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
RequestMapping注解有六个属性,下面我们把她分成三类进行说明。
1、 value, method;
value: 指定请求的实际地址,和path一样,指定请求URL;
method: 指定请求的method类型, GET、POST、PUT、DELETE等;
2、 consumes,produces;
consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
3、 params,headers;
params: 指定request中必须包含某些参数值是,才让该方法处理。
headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。
前端控制器url-pattern拦截方式
第一种:*.拓展名,比如*.do,古老的方式,不会导致静态资源文件(比如图片,html,css,js这些)被拦截问题,但是不支持RESTfull编码风格。
第二种:/,支持RESTfull风格,但是会导致静态资源文件被拦截。
第三种:/*,错误的方式,可以请求到Controller方法,但是跳转到JSP时会被拦截,JSP不能正常显示。
(启动项目的时候,启动Tomcat,加载web.xml文件,启动项目,加载web.xml文件,项目中的web.xml所映射的 / 所覆盖了Tomcat中web.xml配置的映射规则。)
解决静态资源文件被拦截问题:
- 使用<mvc:default-servlet-handler/>(在开发中使用比较多)
将静态资源有SpringMVC交回给Servlet来处理
原理:SpringMVC上下文中定义了一个DefaultServletHttpRequestHandler,对所有前端控制器的请求做筛选和盘查,如果发现没有经过映射请求,就交给Tomcat的默认servlet来处理。
- 资源映射:<mvc:resources location="/" mapping="/**"/>
SpringMVC自己来处理静态资源,而且还附件了很多功能
(SpringBoot运行把静态资源放在任何地方,比如WEB-INF里面,resources目录,设置把JS等静态文件打包放在jar中,也能找到。都可以通过location去指定静态资源路径,location是Resource类型,可以使用前缀,如classpath:)
请求和响应
处理多个对象封装
- 框架把ServletRequest对象和请求参数传递给DataBinder
- DataBinder首先调用Spring Web环境中的ConversionService组件,数据类型转换和格式化操作
- DataBinder调用Validator组件,对绑定参数数据做合法性校验
- DataBinder最后输出数据绑定的结果----->BindingResult
- 最后SpringMVC框架会把BindingResult中的数据,分别传递给响应的处理方法
处理JSON的注解:
@ResponseBody:处理响应,把对象转换为JSON字符串
贴到方法上:只针对当前方法做JSON处理
贴到类上:会对当前类中所有的方法做JSON处理
@Restcontroller:@Controller + @ResponseBody
@RequestBody:处理请求,用于读取HTTP请求的内容,把JSON格式的请求数据封装成对象
一般的请求数据格式:
application/x-www-form-urlencoded:传统的key-value格式,处理起来非常方便,不需要RequestBody都可以,贴上也可以
application/multipart:文件上传的请求,SpringMVC装饰设计模式,既能处理文件上传,也能处理普通表单数据
application/json:参数是JSON格式的,此时就必须使用RequestBody
RequestContextHolder
SpringMVC提供了一个非常方便的工具类,能够在任意地方很方便的获取request和session对象。RequestContextHolder顾名思义,持有上下文的Request容器。
public class UserContext {
public static final String USER_IN_SESSION = “user_in_session”;
private static HttpSession getSession() {
return ((ServletRequestAttributes(RequestContextHolder.getRequestAttributes())).getRequest().getSession();
}
public static void setCurrentUser(Employee current) {
If(current != null){
getSession().setAttribute(USER_IN_SESSION,current);
}else {
getSession().invalidate();
}
}
public static Employee getCurrentUser() {
return (Employee) getSession().getAttribute(USER_IN_SESSION);
}
}
拦截器
应用场景
1、日志记录,可以记录请求信息的日志,以便进行信息监控、信息统计等。
2、权限检查:如登陆检测,进入处理器检测是否登陆,如果没有直接返回到登陆页面。
3、性能监控:典型的是慢日志。
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception {}
}
1.preHandle方法:在请求达到Handler之前,先执行这个前置处理方法。当该方法返回false时,请求直接返回,不会传递到链中的下一个拦截器,更不会传递到处理链末端的Handler中。只有返回true时,请求才向链中的下一个处理节点传递。
2.postHandle方法:控制器方法执行后,视图渲染之前执行(可以加入统一的响应信息)。
3.afterCompletion方法:视图渲染之后执行(处理Controller异常信息,记录操作日志,清理资源等)
开发SpringMVC拦截器步骤:
1.定义拦截器类实现接口org.springframework.web.servlet.HandlerInterceptor
2.在xml中配置拦截器
<!-- 注册拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 对哪些资源做拦截
/*:只能拦截一级路径
/**:可以拦截一级或多级路径
-->
<mvc:mapping path=""/>
<!-- 排除不需要被拦截的资源 -->
<mvc:exclude-mapping path=""/>
<!-- 拦截器类 -->
<bean class=""></bean>
</mvc:interceptor>
</mvc:interceptors>
异常处理
SpringMVC统一处理异常的解决和实现过程
SpringMVC处理异常有三种方式:
(1)使用SpringMVC提供的简单异常处理器SimpleMappingExceptionResolver;
<!-- 配置异常处理器 -->
<bean class=”org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”>
<!-- 设置错误的视图 -->
<property name=”defaultErrorView” value=”” />
<!-- 在错误页面,获取异常信息对象变量名称,缺省exception -->
<property name=”exceptionAttribute” value=”” />
<!-- 根据不同类型异常,跳转到不同的错误页面 -->
<property name=”exceptionMappings”></property>
</bean>
(2)实现Spring的异常处理接口HandlerExceptionResolver自定义自己的异常处理器;
(3)使用@ExceptionHandler注解实现异常处理;
数据校验
是Web开发任务之一,在SpringMVC中有两种方式可以实现,分别是使用Spring自带的验证框架和使用JSR303实现,也称之为spring-validator和jsr303-validator,在开发中更建议使用jsr303-validator。
jsr303-validator标准的校验框架
步骤
1.SpringMVC 虽然提供了对这套标准的支持,提供了接口,但是本身并没有提供JSR-303 的实现,一般会引入 Hibernate-validator 的 jar 包。
classmate-1.3.4.jar
javax.el-3.0.1-b09.jar
jboss-logging-3.3.2.Final.jar
validation-api-2.0.1.Final.jar
2.在SpringMVC中,可直接通过注解驱动的方式进行数据校验Spring的LocalValidatorFactory即实现Spring的Validator接口,也实现了jsr303的Validator接口。
3.Spring在进行数据绑定时,可同时调用校验框架完成数据校验工作,在 bean对象的属性标准@NotNull @Max @min 等注解标签,来指定他的校验规则。
4.在 handler 方法上将需要校验的对象加上@validated标签,并且紧随其后加上 BindingResult 对象接收校验信息。