SpringMVC是什么:
Spring家族的一员,属于SpringFrameWork的后续产品,是一种基于Java实现MVC设计模型的请求驱动类型的轻量级表现层框架。该框架可以接收浏览器的请求,对数据进行处理,然后响应。
MVC是软件的架构方式,把软件系统分为模型M(Model),视图V(View),控制器C(Controller),将数据,页面,代码进行分离。
而在SpringMVC中的MVC,M可以代表JavaBean,V可以代表页面,C则代表Controller类。
SpringMVC开发方式:
SpringMVC通过web.xml和springmvc.xml两个配置文件来进行相关配置,在服务器启动时进行初始化,通过调用各个组件来进行各种操作,最终执行Controller类中的方法处理数据。
web.xml需要配置的部分内容:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!--配置前端控制器,用户发出的请求需要通过DispatcherServlet类,来找到我们自定义用于处理请求的类
DispatcherServlet类是整个流程控制中心,所有请求都经过它来控制,它来决定下一步做什么。
-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--加载springmvc.xml配置文件,-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--配置启动加载,服务器启动时,就把该加载的配置文件(如springmvc.xml)和资源加载完毕-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!--通用写法: /表示所有请求都会被该servlet处理,.jsp不会被处理,要想处理.jsp使用//*-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置解决中文乱码问题的过滤器filter-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--指定使用编码集-->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
</web-app>
springmvc.xml需要配置的部分内容:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置spring创建容器时要扫描的包(开启注解扫描) -->
<context:component-scan base-package="cn.cx"/>
<!-- 配置视图解析器,进行页面跳转
当资源位置改变后,不修改源码,可以直接在配置文件中修改
-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--跳转页面前面的路径-->
<property name="prefix" value="/"></property>
<!--跳转页面资源的后缀名-->
<property name="suffix" value=".jsp"></property>
</bean>
<!--配置日期转换器,类型转换器的组件,把我们的日期转换器注入到组件中-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<!--把我们的日期转换器注入到组件中-->
<bean class="cn.cx.demo1.StringToDate"/>
</set>
</property>
</bean>
</beans>
一个简单Controller类:
/**
* 用于处理用户发出请求的类,表现层,用@Controller配置,加入IOC容器
* 使用@RestController修饰的类,其下所有方法不走视图解析器,直接返回字符串
* */
@Controller
@RequestMapping("/user")
public class UserController {
/**
* RequestMapping也可以写在类上,代表一级路径,而类中方法上的RequestMapping则代表二级目录
* path、value表示发送的请求名称(用哪个都行,value可以用直接写字符串)
* method表示当前方法允许何种请求方式能访问 method = {RequestMethod.GET}表示只允许get方法
* params表示请求路径上必须有指定的参数名称
*
* 请求参数绑定:当前端传递一个参数,我们只需要在方法中添加一个名称和前端name一致的参数,即可接收收到
* springmvc框架底层通过反射方式绑定到了方法参数上
* */
@RequestMapping("/save")
public String save(User user){
//....业务逻辑代码
//如果springmvc.xml配置了视图解析器,可以就只写资源名称,不用写路径和后缀名
return "suc";
}
}
SpringMVC执行流程图:
上图中映射器,适配器,解析器等等,我们称之为SpringMVC组件,上图仅包含SpringMVC中比较关键的组件,并不是全部组件,这些组件是“可插拔”的,可以在springmvc.xml中仅配置。
用文字描述其流程:
用户发出的请求需要通过DispatcherServlet类,来找到我们自定义用于处理请求的类(Controller类),
DispatcherServlet类是整个流程控制中心,所有请求都经过它来控制,它来决定下一步做什么。
1、当点击超链接,发出请求后,先调用映射器组件(解析出 /user/save请求)。
2、调用适配器组件(查找IOC容器中的所有类,找到对应类及其方法)。
3、调用控制器组件,返回ModelAndView对象(让找到的Controller类对应的方法执行,拿到需要返回资源的资源名)。
4、调用视图解析器组件,根据springmvc.xml中的视图解析器和返回资源名组成一个完整页面访问路径,然后将jsp翻译成Servlet生成html,进行请求转发。
SpringMVC相关注解:
@RequestMapping:表示映射请求,来指定该控制类可以处理哪些请求,相当于servlet中web.xml的下面这段配置:
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>xx.xxx.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/user/save</url-pattern>
</servlet-mapping>
@RequestParam:把请求中指定名称的参数传递给对应形参。(接收前端参数就加上这个注解)
注意:请求参数绑定实体类,形参直接是对应实体类对象即可(类中属性,前端传递name值要保持一致),springmvc底层自动封装
@RequestBody:获取请求体(get方法的不行),加在方法返回类型前,表示以json数据封装。
@ResponseBody:不会走视图解析器,会直接返回一个json字符串。(比如异步获取 json 数据,加上 @ResponseBody 后,会直接返回 json 数据)
@PathVariable:绑定@RequestMapping里url中的占位符(如/user/save/{id}),可实现RestFul风格。
@CookieValue:获取指定cookie名称的值。
@GetMapping:处理get方式请求
@PostMapping:处理post方式请求
@ResponseBody:将返回对象以json数据格式封装。
SpringMVC方法响应数据类型:
String:直接走视图解析器,转发返回字符串的地址(请求转发forward:、重定向redirect:)。
void:默认去查询@RequestMapping中路径页面,可以手动获取request,response参数转发。
ModleAndView:可以通过addObject()和setViewName返回对象,设置视图(返回地址),返回给前端。
SpringMVC文件上传组件:
<!--配置文件上传的解析器组件。id的名称是固定,不能乱写-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置上传文件的最大兆:1024*1024*8,8MB-->
<property name="maxInMemorySize" value="8388608"/>
</bean>
SpringMVC异常处理组件:
首先需要自定义异常类,继承Exception。
/**
* 自定义异常类
* */
public class SysException extends Exception {
private String message;
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public SysException(String message){
this.message = message;
}
}
然后自己编写异常处理组件的类,实现HandlerExceptionResolver。
/**
* 自定义异常处理器,需要实现HandlerExceptionResolver接口
* 当我们配置异常处理器后,Springmvc会自己调用该类方法
* */
public class SysExceptionResolver implements HandlerExceptionResolver{
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
e.printStackTrace();
SysException exception = null;
if(e instanceof SysException){
//如果类型是我们自定义的异常,直接转换
exception = (SysException) e;
}
//如果不是我们自定义的异常,自己创建一个
exception = new SysException("系统可能正在维护,出现错误,不好意思呀");
//创建返回对象,存入异常信息
ModelAndView mv = new ModelAndView();
mv.addObject("message", e.getMessage());
mv.setViewName("exception");
return mv;
}
}
最后在springmvc.xml中将异常处理器类控制反转。
<!--将异常处理器控制反转-->
<bean id="sysExceptionResolver" class="xx.xxx.SysExceptionResolver"/>
SpringMVC拦截器:
用于对处理器进行预处理和后处理的技术,拦截器也是AOP思想的一种体现方式,想要自定义拦截器,需要实现HandlerInterceptor接口。
实现HandlerInterceptor的类,需要复写3个方法:
preHandle():在controller中方法执行前拦截,return true表示放行,反之表示拦截。
postHandle():在controller中方法执行后拦截。
afterCompletion():当跳转页面执行后,最后执行该方法。
/**
* 自定义拦截器,需要实现HandlerInterceptor接口,重写里面的方法
*
* */
public class MyInterceptor1 implements HandlerInterceptor {
/**
* preHandle方法在controller中的方法执行前拦截,只有return true,才能执行其中方法
* 可以使用request或者response跳转到指定的页面
* */
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器MyInterceptor1,preHandle方法执行...");
//request.getRequestDispatcher("/exception.jsp").forward(request,response);
//true放行,false拦截
return true;
}
/**
* controller中方法执行后,进行拦截
* */
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器MyInterceptor1,拦截器postHandle...");
// 也是可以进行页面的跳转
//request.getRequestDispatcher("/index.jsp").forward(request,response);
return;
}
/**
* 跳转的jsp页面都执行完成了,最后执行该方法
* */
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("拦截器MyInterceptor1,afterCompletion方法执行...");
}
}
涉及方法执行顺序(preHandle放行是前提):
preHandle方法→controller方法→postHandle方法→页面→afterCompletion方法。
springmvc.xml拦截器配置:
<!--配置拦截器组,如果有多个拦截器,在遵循拦截器方法执行顺序的前提下,
preHandle方法按照拦截器配置顺序执行,其他方法按照拦截器配置倒序执行,
与java Web Filter执行效果相同,如下:
拦截器MyInterceptor1,preHandle方法执行...
拦截器MyInterceptor2,preHandle方法执行...
拦截器MyInterceptor3,preHandle方法执行...
DeptController类内,findAll方法执行...
拦截器MyInterceptor3,拦截器postHandle...
拦截器MyInterceptor2,拦截器postHandle...
拦截器MyInterceptor1,拦截器postHandle...
jsp页面执行
拦截器MyInterceptor3,afterCompletion方法执行...
拦截器MyInterceptor2,afterCompletion方法执行...
拦截器MyInterceptor1,afterCompletion方法执行...
-->
<mvc:interceptors>
<mvc:interceptor>
<!--该拦截器拦截哪些资源,此处表示/dept下的所有方法-->
<mvc:mapping path="/dept/**"/>
<!--该拦截器不拦截哪些资源-->
<mvc:exclude-mapping path=""/>
<!--应用拦截器对象-->
<bean class="xx.xxx.MyInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/dept/**"/>
<bean class="xx.xxx.MyInterceptor2"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/dept/**"/>
<bean class="xx.xxx.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
SpringMVC的拦截器和Servlet中的过滤器功能很相似,但也有区别:
1、过滤器是Servlet的一部分,任何框架都可以使用,但拦截器是SpringMVC独有的。
2、过滤器配置/*,可以拦截所有资源,但拦截器只对控制器中方法进行拦截。