一、三层架构介绍和MVC设计模型介绍
1. 三册架构
2. MVC设计模式
MVC全名是Model View Controller
Model(模型):通常指的是数据模型,一般情况下用于封装数据
View(视图):通常指定的就是我们的jsp或者html
Controller(控制器)
二、SpringMVC简介
1. SpringMVC概述
SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架
2. 快速入门
- 导入SpringMVC相关坐标
<!--Spring坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--SpringMVC坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--Servlet坐标-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<!--Jsp坐标-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
- 在web.xml中配置SpringMVC的核心配置器DispatcherServlet
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--创建初始化参数-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!--启动时加载-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
- 创建Controller和业务方法
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/quick")
public String quickMethod() {
System.out.println("QuickMethod running...");
return "/success.jsp";
}
}
- 创建spring-mvc.xml
<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">
<!--配置注解扫描-->
<context:component-scan base-package="cn.mvc.controller"/>
</beans>
- 访问测试
访问http:localhost:8080/mvc/user/quick
3. SpringMVC的组件解析
3.1 SpringMVC的执行流程
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求调用HandlerMapping处理器映射器
- 处理器映射器找到具体的处理器(根据xml配置或注解),生成处理器对象及处理器拦截器(如果有处理器拦截器则生成)一并返回给DispatcherServlet
- DispatcherServlet调用HandlerAdapter处理器适配器
- HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)
- Controller执行完成返回ModelAndView
- HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器
- ViewReslover解析后返回具体View
- DispatcherServlet根据View进行渲染视图(即将模型数据填充值至视图中),DipatcherServlet响应用户
3.2 SpringMVC组件解析
-
前端控制器:DispatcherServlet
用户请求到达前端控制器,相当于MVC模式中的C(controller),DispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet的存在降低了组件之间的耦合性。
-
处理器映射器:HandlerMapping
HandlerMapping负责根据用户请求找到Handler处理器,SpringMVC提供了不同的映射器实现不同的映射方式,如配置文件方式、实现接口、注解等。
-
处理器适配器:HandlerAdapter
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
-
处理器:Handler
就是编写的具体业务控制器。由DispatcherServlet把用户请求转发到Handler,然后Handler对具体的用户请求进行处理。
-
视图解析器:View Resolver
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户
-
视图:View
SpringMVC框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等
3.3 RequestMapping注解
- RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系
- RequestMapping注解可以作用在方法和类上
- 作用在类上:第一级的访问目录
- 作用在方法上:第二级的访问目录
- 细节:路径可以不编写 / 表示应用的根目录开始
- 细节:${pageContext.request.contextPath}也可以省略不写,但是路径上不能写 /
- RequestMapping的属性
- path 指定请求路径的URL
- value value属性和path属性是一样的
- method 指定该方法的请求方式
- params 指定限制请求参数的条件
- headers 发送的请求中必须包含的请求头
3.4 SpringMVC的XML配置解析
SpringMVC的默认组件配置由DispatcherServlet.properties配置,该文件配置了默认的视图解析器,这个视图解析器的默认设置有
REDIRECT_URL_PREFIX = "redirect:" --重定向前缀
FORWARD_URL_PREFIX = "forward:" --转发前缀(默认值)
prefix = ""; --视图名称前缀
suffix = ""; --视图名称后缀
我们可以通过属性注入的方式修改视图的前后缀
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
三、SpringMVC的请求和响应
1. 数据响应
1.1 页面跳转
(1) 返回字符串形式
(2) 返回ModelAndView形式
//自己创建ModelAndView对象
@RequestMapping("/quick2")
public ModelAndView test2() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username","itcast");
modelAndView.setViewName("success");
return modelAndView;
}
//在形参中声明ModelAndView
@RequestMapping("/quick3")
public ModelAndView test3(ModelAndView modelAndView) {
modelAndView.addObject("username","itcast");
modelAndView.setViewName("success");
return modelAndView;
}
@RequestMapping("/quick4")
public String test3(Model model) {
model.addObject("username","itcast");
return "success";
}
1.2 回写数据
(1) 直接回写字符串
@RequestMapping("/quick5")
@ResponseBody //告知SpringMVC框架,不进行视图跳转,直接进行数据响应
public String test5() {
return "Hello MVC";
}
(2) 直接回写json格式字符串
使用jackson工具进行转换,需导入jackson工具的依赖
@RequestMapping("/quick6")
@ResponseBody //告知SpringMVC框架,不进行视图跳转,直接进行数据响应
public String test6() throws IOException {
User user= new User("lisi", 30);
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(User);
return json;
}
(3) 返回对象或集合
SpringMVC可以自动将对象或集合转换成json字符串,我们只需要为处理器适配器配置消息转换参数
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</list>
</property>
</bean>
配置之后返回对象或集合就可以自动转换
@RequestMapping("/quick7")
@ResponseBody
public User test7(){
User user = new User();
user.setUsername("lisi2");
user.setAge(32);
return user;
}
在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器被称为SpringMVC的三大组件。
在spring-mvc.xml配置文件中使用mvc:annotation-driven/替代注解处理器和适配器的配置,mvc:annotation-driven/默认底层就会集成jackson进行对象或集合的json字符串的转换
2. 数据请求
2.1 获取基本类型参数
Controller中业务方法的参数名称要与请求参数的名称一致,参数值会自动映射,并且能将请求参数中的文本类型转换为其他数据类型。
@RequestMapping("/quick8")
@ResponseBody
public void test8(String username, int age) {
System.out.println(username);
System.out.println(age);
}
2.2 获得POJO类型参数
Controller中业务方法的参数对象的属性名要与请求参数的名称一致,参数值会自动映射。
@RequestMapping("/quick9")
@ResponseBody
public void test9(User user) {
System.out.println(user.getUsername());
System.out.println(user.getAge());
}
2.3 获得数组类型参数
Controller中的业务方法的数组参数名称要与请求参数的名称一致,参数值会自动映射
@RequestMapping("/quick10")
@ResponseBody
public void test10(String[] strs) {
System.out.println(Arrays.asList(strs));
}
2.4 获得集合类型参数
(1) 方式1
可以将集合参数包装到一个POJO中,通常这个POJO名称为VO
<form action="user/quick11" method="post">
<input type="text" name="userList[0].username"><br>
<input type="text" name="userList[0].age"><br>
<input type="text" name="userList[1].username"><br>
<input type="text" name="userList[1].age"><br>
<input type="submit" value="提交">
</form>
VO对象
public class VO {
private List<User> userList;
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
@Override
public String toString() {
return "VO{" +
"userList=" + userList +
'}';
}
}
Controller对象
@RequestMapping("/quick11")
@ResponseBody
public void test11(VO vo) {
System.out.println(vo);
}
(2) 方式二
当使用ajax提交时,可以指定contentType为json形式,那么在方法参数位置使用**@RequestBody**可以直接接收集合数据而无需使用POJO进行包装
<script src="${pageContext.request.contextPath}/js/jquery.js"></script>
<script>
var userList = new Array();
userList.push({username:"zhangsan",age:18});
userList.push({username:"lisi",age:19});
$.ajax({
type:"POST",
url:"${pageContext.request.contextPath}/user/quick12",
data:JSON.stringify(userList),
contentType:"application/json;charset=utf-8"
});
</script>
因为前端控制器无法访问静态资源,所以需要在spring-mvc.xml中开放资源的权限或者使用默认Tomcat服务器处理。
<!-- 开放资源的权限 -->
<mvc:resources mapping="/js/**" location="/js/"/>
<!-- 使用默认服务器处理 -->
<mvc:default-servlet-handler/>
2.5 配置全局乱码过滤器
当post请求中有中文时,数据会出现乱码,我们可以设置一个过滤器来进行编码的过滤。
<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>
2.6 参数绑定注解
当请求的参数与Controller的业务方法不一致时,就需要通过@RequestParam注解来进行参数的绑定
@RuquesteMapping("/quick12")
@ResponseBdoy
public void test12(@RequestBody(value="name", required=false, defaultValue="springmvc") String username) {
System.out.println(username);
}
2.7 Restful风格的参数的获取
Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。
Restful风格的请求是使用“url+请求方式”表示一次请求目的的,HTTP 协议里面四个表示操作方式的动词如下:
(1) GET:用于获取资源
(2) POST:用于新建资源
(3) PUT:用于更新资源
(4) DELETE:用于删除资源
在SpringMVC中可以使用占位符进行参数绑定,在业务方法中使用@PathVariable注解进行占位符的匹配获取工作。
http://localhost:8080/spring_mvc_war_exploded/quick13/zhangsan
@RuquesteMapping("/quick13/{name}")
@ResponseBdoy
public void test13(@PathVariable("name") String username) String username) {
System.out.println(username);
}
2.8 自定义类型转换器
Spring默认提供的类型转换器可能会不满足业务的需求,因此需要配置自定义的类型转换器。
//通过实现Converter接口创建自定义转换器
public class Date2StringConverter implements Converter<String, Date> {
@Override
public Date converter(String dateStr) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = sdf.parse(dateStr);
return date;
} catch (Exception e){
e.printStackTrace();
}
return null;
}
}
@RequestMapping("/quick13")
@ResponseBody
public void test13(Date date) {
System.out.println(date);
}
2. 9 获得Servlet相关API
@RequestMapping("/quick14")
@ResponseBody
public void test14(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
System.out.println(request);
System.out.println(response);
System.out.println(session);
}
2. 10 获得请求参数
@RequestHeader
@RequestMapping("/quick15")
@ResponseBody
public void test15(@RequestHeader(value = "User-Agent",required = false) String user_agent) {
System.out.println(user_agent);
}
@CookieValue
@RequestMapping("/quick16")
@ResponseBody
public void test16(@CookieValue(value = "JSESSIONID") String jsessionId) {
System.out.println(jsessionId);
}
四、 SpringMVC实现文件上传
1. 客户端表单实现
实现文件上传客户端表单需要满足三个条件:
(1) 表单项type=“file”
(2) 表单提交方式是post
(3) 表单的enctype属性是多部分表单形式,enctype=“multipart/form-data”
<form action="user/quick17" method="post" enctype="multipart/form-data">
名称<input type="text" name="username"><br>
文件1<input type="file" name="uploadFiles"><br>
文件2<input type="file" name="uploadFiles"><br>
<input type="submit" value="提交">
</form>
2. 文件上传实现
2.1 添加依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.3</version>
</dependency>
2.2 配置文件上传解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UYF-8"/>
<property name="maxUploadSize" value="500000"/>
</bean>
2.3 后台程序
@RequestMapping("/quick18")
@ResponseBody
public void test18(String username, MultipartFile[] uploadFiles) {
System.out.println(username);
for (MultipartFile uploadFile : uploadFiles) {
String originalFilename = uploadFile.getOriginalFilename();
uploadFile.transferTo(new File("D:\\" + originalFilename));
}
}
五、 SpringMVC拦截器
1. 概念
1.1 作用
Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(InterceptorChain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
1.2 interceptor和filter的区别
使用范围 | 拦截范围 | |
---|---|---|
interceptor | 是属于SpringMVC框架的,只有使用了SpringMVC框架的工程才能使用 | 只会拦截访问控制器的方法,不会拦截静态资源的访问 |
filter | 是Servlet规范中的一部分,任何Web工程都可以使用 | 在url-pattern中配置/*后可以对所有要访问的资源拦截 |
2. 开发
1. 步骤
- 创建拦截器类实现HandlerInterceptor接口
public class MyInterceptor implements HandlerInterceptor {
//在目标方法执行之前执行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String param = request.getParameter("param");
System.out.println("preHandle11111111");
if("yes".equals(param)) {
return true;
} else {
request.getRequestDispatcher("/jsp/error.jsp").forward(request, response);
return false;
}
// return true; //返回true代表放行,返回false代表拦截
}
//在目标方法执行之后,视图返回之前执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
modelAndView.addObject("name","mvc");
System.out.println("postHandle1111111");
}
//在整个流程都执行完毕后执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion1111111111");
}
}
- 配置拦截器
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 对哪些资源进行拦截操作 -->
<mvc:mapping path="/target"/>
<!-- 排除哪些资源进行拦截 -->
<mvc:exclude-mapping path="/login"/>
<bean class="cn.mvc.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
注意:
1. 多个拦截器组成InterceptorChain时,配置在前的先执行;
2. 拦截器方法的执行顺序:preHandler-------目标资源----postHandle---- afterCompletion
方法名 | 说明 |
---|---|
preHandle() | 方法将在请求处理之前进行调用,该方法的返回值是布尔值Boolean类型的,当返回false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时就会继续调用下一个interceptor的preHandler方法 |
postHandle() | 当preHandle方法返回true之后会被调用,它执行在目标资源执行完之后,DispatcherServlet进行视图渲染之前。常用于对Controller处理之后的ModlAndView对象操作 |
afterCompletion | 该方法执行在整个请求结束之后,前提是preHandle方法的返回值为true |
六、 SpringMVC异常处理
1. 异常处理的思路
系统中异常包括两类:预期异常和运行时异常,预期异常通过捕获异常从而获取异常信息,而运行时异常主要通过规范代码开发、测试等手段减少运行时异常的发生。
系统的Dao、Service、Controller出现都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理。
2. 简单异常处理器SimpleMappingExceptionResolver
SpringMVC已经定义好了该异常处理器,在使用时可以根据项目情况进行相应异常与视图的映射配置
<!--配置简单映射异常处理器-->
<bean class=“org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”> <property name=“defaultErrorView” value=“error”/> <!--默认错误视图-->
<property name=“exceptionMappings”>
<map> <!--key是异常类型--> <!--value是错误视图-->
<entry key="com.itheima.exception.MyException" value="error"/>
<entry key="java.lang.ClassCastException" value="error"/>
</map>
</property>
</bean>
3. 自定义异常处理步骤
- 创建异常处理器类实现HandlerExceptionResolver
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
//处理异常的代码实现
//创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("exceptionPage");
return modelAndView;
}
}
- 配置自定义异常处理器
<bean id="exceptionResolver" class="com.itheima.exception.MyExceptionResolver"/>