SpringMVC框架
回顾
项目开发步骤:
- 准备maven项目
- 加入Spring MVC依赖
- 在web.xml添加大C的配置
- 创建配置类, 需要@Configuration, @ComponentScan, @EnableWebMvc
- 开发控制器
如何做静态资源的处理[让静态资源的请求不经过大C]
- 详见第一天笔记
控制器的开发
- 写一个JAVA类,打上
@Controller
注解 - 在控制器,开发处理用户请求的方法,这个方法上要打上
@RequestMapping
, 并且写在请求的URI。
注:
@RequestMapping
即可以写在类上面,也可以写在 方法上面。@Controller @RequestMapping("/hello") public class HelloController { @RequestMapping("/abc") public String hello() { return "hello.jsp"; } }
如果在类上面和方法上面都有写 @RequestMapping的话,则我们的请求URI是两者的结合。
请求参数的处理
- 在SpringMVC的控制器方法中,可以使用Servlet时代的任意对象做为参数。比如:我们可以在方法中添加
HttpServletRequest
,HttpServletResponse
,HttpSession
, ... - 前台表单数据提交后,Spring MVC可以自动帮助我们封装成JavaBean,我们可以直接以这个JAVABEAN做为方法的参数来接。要求是:表单域的名字要与JAVABEAN的属性名保持一样。
- 有关Model参数,它本质就是一个LinkedHashMap, key就是字符串,不允许为NULL,Value就是Object, 我们可以通过Model来添加任意的对象到前端页面。
视图处理器
SpringMVC框架默认的视图是采用JSP。
我们可以配置视图解析器。
编码问题
- 请求的方式如果是GET的话,浏览器会把请求数据封装到请求头【Request Header】中传输到后端.
- 请求的方式如果是POST的话,浏览器会把请求数据封装到请求体【Request Body】中传输到后端。
编码过滤器中设置请求和响应的编码,它只能影响请求体部,不能改变头部的编码。换句话说,它只对POST请求有效。
如果需要修改请求头的编码,只能修改容器的配置。Tomcat 的配置如下:
<Connector connectionTimeout="20000" port="8088" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
如果你使用的是maven的tomcat7插件,则只需要在 pom.xml中配置即可:如下:
<plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8888</port> <path>/</path> <!-- 指定请求头部的编码 --> <uriEncoding>utf8</uriEncoding> </configuration> </plugin>
SpringMVC框架
请求的转发和重定向处理
默认情况下,SPRINGMVC的请求都是以“转发”到下一个资源的,如果在控制方法中,没有指定@ResponseBody注解,则默认采用 jsp 为视图。
如果我们要重定向一个请求,则需要使用 "redirect:" 开头,后面再接 视图的名字。如: "redirect:/user/list"
默认情况下,视图解析器采用转发来跳转请求,那么使用了 forward关键字和默认情况的区别是什么 ?
使用了 forward: 或 redirect: 为前缀的话,则这个请求跳转会忽略视图解析器。如:
return "user/register"; //真正的URI: /WEB-INF/user/register.jsp
return "forward:/WEB-INF/user/register.jsp"; //自已写完整的URI
使用redirect,相当于是重定向请求。
异常的处理
其实,在 容器层面也有全局的异常处理机制,它是通过在 web.xml中配置
的标签来实现的,如下: <error-page> <exception-type>java.lang.Exception</exception-type> <location>/error.jsp</location> </error-page> <error-page> <error-code>404</error-code> <location>/404.jsp</location> </error-page>
当容器收到控制器抛出的异常时或者容器出现了服务端错误【500】时,则根据配置把页面转发到 /error.jsp 中,在 这个页面是,通过在 page 指令中加入 isErrorpage="true"属性后,就可以拿到容器中出现的异常对象.
在SpringMVC中,我们也可以针对异常进行处理,这个处理是由大C来负责。有如下方式:
-
配置全局的异常处理器
在
WebMvcConfig.java
中,添加一个HandlerExceptionResolver
的 @Bean, 如下:@Bean public HandlerExceptionResolver exceptionHandler() { //创建 SimpleMappingExceptionResolver SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver(); //设置属性 exceptionResolver.setDefaultErrorView("forward:/error.jsp"); //排除的异常 exceptionResolver.setExcludedExceptions(LoginException.class); // exceptionResolver.setDefaultStatusCode(500); // exceptionResolver.setWarnLogCategory("org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"); //返回 return exceptionResolver; }
注: exceptionResolver.setWarnLogCategory 是表示打开全局的异常日志功能
-
配置控制器级别的异常处理器
利用注解 @ExceptionHandler 来修饰一个方法,这个方法必需要在 @Controller修饰的类中,这样一来,此 Controller中的方法有任何一个抛出异常后,框架都会回调 @ExceptionHandler 修饰的方法,这样一来,我们就可以在此方法中做异常信息的日志、记录或信息的展示,并把某些信息绑定一前台页面中供用户查看【这个由程序员决定】
它的代码如下:
@ExceptionHandler(value = {RuntimeException.class, IOException.class}) public String initEx(Model model,Exception e) { System.out.println("---> ExceptionController中的方法出异常了..."); /* System.out.println(e.getMessage()); e.printStackTrace();*/ model.addAttribute("server.ex",e); // return "forward:/ex.jsp"; }
以上只是一个代码片断。
拦截器的使用[Interceptor]
注:
SpringMVC的拦截器是针对控制器级别的拦截,它由 大C 来处理,而不是由容器来处理。它主要是针对控制器的拦截,下面的图示分别说明了 Filter, Interceptor, AOP 三种拦截的范围
开发拦截器的步骤:
- 写一个类实现
HandlerInterceptor
接口,并重写它的三个方法- preHandle 方法 , 在调用目标小C 之前
- postHandle 方法, 在调用目标小C之后,但是视图渲染之前
- afterCompletion 方法,视图渲染之后
- 配置这个拦截器,采用 xml 的配置法
拦截器的使用:
把小C中需要执行的一些共性操作拿出来做为 拦截器的功能。比如:
日志,认证,授权,性能监测....
此处我们编写一个拦截器,用来记录每一次请求的处理时间,为了精切地记录这个时间值,我们建议采用拦截器来完成,从 preHandle 方法中开始计算,在 afterCompletion 方法结束计时,并计算出两个时间差,把这个时间差写入到数据库的性能监控表中。
注:
这里我们不去直接实现
HandlerInterceptor
类,而是继承一个抽象父类HandlerInterceptorAdapter
注:
当我们配置多个拦截器时,它的 preHandle 方法是按顺序执行的,而 postHandle和afterCompletion方法则是按逆序进行执行的。
json数据格式的使用
在SpringMVC框架中,@RequestMapping方法一般有如下几种返回值:
- 返回 String, 表示视图的逻辑名【前提是配置视图解析器】
- 返回void,表示没有返回值,此时,你需要在方法体中,通过request或是 response来编程进行跳转或重定向,当然,也可以通过 response.getWriter.println(".....") 输出内容到浏览器端。
- 返回ModelAndView, 表示返回一个模型和视图,我们需要自己创建这个对象,并且设置Model数据和视图的名字。
- 如果不是以上三种,那就是返回单个JAVABEAN或是它的集合体,这种情况一般都需要把这个数据转换成JSON格式,这个过程是自动的,只需要在RequestMapping中,添加produce属性,指定生成的内容就是 json,同时,还要加上 @ResponseBody 注解。
案例:
文件上传和下载
构建SpringMVC框架的结构
- 构建maven项目
- 添加 spring mvc框架相关的依赖
- 在web.xml中配置大C以及编码过滤器
Spring MVC框架的核心API和核心注解
- DispatcherServlet,俗称大 C, 也就是前置控制器
- 核心注解:
- @EnableWebMvc
- @Import 导入另一个配置类
- @ImportResource 读入 spring框架的 xml 配置
- @PropertySource 读入 .properties 属性文件
SpringMVC框架的注解配置类
一般的策略是: 把WEB层、业务层和持久层 分开配置,其中,AppConfig.java 配置类负责像数据源、持久层的支持类、事务、等。而在 WebMvcConfig.java 配置类中负责像 静态资源处理器、视图解析器、文件上传处理器、BeanValidation处理器、全局异常处理等
SpringMVC的注解配置类需要继承 WebMvcConfigurerAdapter
类,它的意义在于给我们一个机会,让我们参与到配置的过程当中。
有关这个类的详细的配置,请参考代码。
有关大C的匹配规则
- 扩展名匹配, 如: *.do, *.action, *.xxx
- 通配匹配, 如: /
如何处理静态资源?
只是针对大C采用 / 来做为请求匹配规则时才需要的操作。
控制器的开发
记住如下几个核心注解:
- @Controller 它是 @Component 的一种
- @RequestMapping
- @ResponseBody
- @RequestParam
- @PathVariable
- @ModelAttribute
- @SessionAttribute
- @ExceptionHandler
- @RestController 支持RESTFul 风格URI的控制器,它相当于:@Controller+@ResponseBody
- ...
与业务层、持久层的整合
直接导入 AppConfig.java 即可。
SpringMVC中的重要功能点
1. 静态资源处理
2. SpringMVC对请求参数的自动化封装
3. 请求的转发和重定向
4. 视图解析器的配置
5. 异常的处理
6. 拦截器的开发
7. 返回 json 数据格式
8. 文件上传和下载
9. Bean Validation
10. RESTFUL 风格的URI
文件上传和下载
文件的上传必需要使用 post方式提交,所以,我们需要定义一个表单
另外一个,表单的 enctype一定要指定为: multipart/form-data
在服务端,需要能过一个特殊对象: MultipartFile 来接收用户的文件上传请求。
Bean Validation
前端页面的验证是极其不安全的,可以轻易地跳过前端的验证。
为了数据的有效性和一致性,我们在后端也需要对前端传递过来的数据进行验证。
JSR303 规范就是定义了 Bean Validation的规范,目前,官方说明中,Hibernate Validator 组件是JSR303的参考实现。所以,Spring MVC框架结合 Hibernate Validator。
操作步骤
- 导入 hibernate-validtor 的依赖
- 在 WebMvcConfig.java 中重写父类的 getValidator 方法, 在实现中返回 LocalValidatorFactoryBean
- 在需要验证的对象中,使用 JSR303 的注解进行注解
- 在控制器的方法参数中,使用 @Validated 注解需要验证的对象,并添加 BindingResult 对象为参数。