文章目录
SpringMVC简介
开发步骤
- 导入spring-webmvc的依赖坐标
- 配置Spring的前端控制器
DispatcherServlet
(相当于一个执行公共行为的Servlet) - 创建Controller类和视图页面
- 使用注解
RequestMapping
配置类中业务方法的映射地址 - 配置spring-mvc.xml配置文件,并在web.xml中加载要读取的spring-mvc配置文件
- 测试
SpringMVC执行流程图(粗略)
SpringMVC 组件解析
代码实现
web.xml
<!--配置Spring的前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--加载要读取的spring-mvc配置文件-->
<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>
UserController.java
@Controller
public class UserController {
@RequestMapping("/quick")
public String save(){
System.out.println("Controller save running ....");
return "success.jsp";//success.jsp放在webapp目录下
}
}
spring-mvc.xml
<!--开启Controller的组件扫描-->
<context:component-scan base-package="com.itheima.controller"/>
SpringMVC执行流程(代码层面)
SpringMVC执行流程(底层部件)
注解解析
- RequestMapping:
- 作用:用于建立请求URL和请求处理方法方法之间的关系
- 位置:
- 类上:请求URL的一级目录,此处不写的话,就相当于应用的根目录
- 方法上:请求URL的第二级访问目录,会和方法上的value拼接起来组成访问虚拟路径
- 属性:
- value 代表请求的url
- method 指定请求的方式,枚举类型
- params 用于指定请求参数的条件,支持简单的表达式要求,请求参数必须符合该参数要求
@Controller
@RequestMapping("/user")
public class UserController {
//方法上的RequestMapping的value会和方法上的value拼接起来组成访问虚拟路径
// value 代表请求的url
// method 指定请求的方式,枚举类型
// params 用于指定请求参数的条件,支持简单的表达式要求,请求参数必须符合该参数要求
@RequestMapping(value = "/quick", method = RequestMethod.GET, params = {"username"})
public String save(){
System.out.println("Controller save running ....");
// 加"/"表示在当前web应用,即webapp下寻找资源,即找当前 http://localhost:3306/user/ 下的success.jsp,不加"/"表是相对路径
return "/success.jsp";
}
}
XML配置解析
- 视图解析器
SpringMVC有默认组件配置,默认组件都是 DispatcherServlet.properties 配置文件中配置的,该配置文件地址org.springframework.web.servlet.DispatcherServlet.properties
,该文件中配置了默认的视图解析器org.springframework.web.servlet.view.InternalResourceViewResolver
我们可以在spring-mvc.xml
中配置 InternalResourceViewResolver 来修改和查看默认配置,如:
<!--配置内部视图资源解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
REDIRECT_URL_PREFIX = "redirect:"; 重定向前缀
FORWARD_URL_PREFIX = "forward:"; 转发前缀(默认)
prefix = ""; 视图名称前缀
suffix = ""; 视图名称后缀
SpringMVC数据响应
页面跳转
- 返回字符串形式
就是前面的可以自定义前后缀的拼接字符串返回的方式 - 返回ModelAndView
在参数上写ModelAndView让SpringMVC帮我们注入
@RequestMapping("/quick3")
public ModelAndView save3(ModelAndView mad){
//设置模型数据
mad.addObject("username", "Powers");
//设置视图名称
mad.setViewName("success");
return mad;
}
只设置模型数据,直接返回视图名字
@RequestMapping("/quick4")
public String save4(Model model){
//设置模型数据
model.addAttribute("username", "violet");
return "success";
}
回写数据
- 返回字符串
要加上@ResponseBody
注解,即返回String类型 - 返回对象或集合
也要家上@ResponseBody
注解,返回的是String类型的json字符串
SpringMVC自动将对象转换为json格式字符串,指定jackson进行对象或集合的转换
要导入jackson-core,jackson-databind 和jackson-annotations的依赖
spring-mvc.xml
<!--配置处理器映射器-->
<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>
上面的配置可以使用mvc的注解驱动代替,默认集成jackson进行对象或者集合的json转换
<mvc:annotation-driven/>
Controller
@RequestMapping("/quick7")
@ResponseBody
public User save7() throws JsonProcessingException {
User user = new User("lisi", 19);
return user;
}
SpringMVC获得请求参数
获得基本类型参数
@RequestMapping("/quick8")
@ResponseBody
public void save8(String username, int age) {
System.out.println(username);
System.out.println(age);
}
输入:localhost:8080/user/quick8?username=zhangsan&age=18
来传递参数
使用@PathVariable在url中传递参数
前端页面跳转地址:location.href = "${pageContext.request.contextPath}/user/del/" + userId;
@RequestMapping("/del/{userId}")
public String del(@PathVariable Long userId) {
userService.del(userId);
return "redirect:/user/list";
}
获得POJO类型参数
springmvc自动将进行数据类型转换,将String类型的age 转换为int,前提是
实体类POJO要和请求参数name一致
@RequestMapping("/quick9")
@ResponseBody
//springmvc自动将进行数据类型转换,将String类型的age 转换为int
public void save9(User user) {
System.out.println(user);
}
输入:localhost:8080/user/quick9?username=zhangsan&age=18
来传递POJO类型参数
获得集合类型参数
要自己写一个类(ViewObject)将集合作为实例字段
@RequestMapping("/quick11")
@ResponseBody
public void save11(ViewObject viewObject) {
System.out.println(viewObject);
}
同时在前端使用一个form表单将集合数据传入
<form method="post" action="${pageContext.request.contextPath}/user/quick11">
<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="提交"><br>
</form>
可以简化不写类包装集合,直接获得集合类型参数,在方法上写集合
并标注@RequestBody
注解
@RequestMapping("/quick12")
@ResponseBody
public void save12(@RequestBody List<User> userList) {
System.out.println(userList);
}
但此时需要使用ajax异步请求发送请求参数
<script src="${pageContext.request.contextPath}/js/jquery-3.3.1.js"></script>
<script>
var userList = new Array();
userList.push({username:"zhangsan", age:18});
userList.push({username:"lisi", age:100});
$.ajax({
type:"POST",
url:"${pageContext.request.contextPath}/user/quick12",
data:JSON.stringify(userList),
contentType:"application/json;charset=utf-8"
});
</script>
同时需要在 spring-mvc.xml 中配置,静态资源的访问,这样才能使用 jQuery 静态资源
<!--开发资源的访问-->
<!--mapping代表访问时的url地址, location代表真实目录-->
<!--<mvc:resources mapping="/js/**" location="/js/"/>-->
<mvc:default-servlet-handler/>
参数绑定@RequestParam
value是指定请求参数的新名字,指定之后旧名字就不可用
required是指定该参数是否必须包括,默认true
defaultValue是未指定请求参数的值时,默认传入的值
@RequestMapping("/quick13")
@ResponseBody
public void save13(@RequestParam(value = "name", required = false, defaultValue = "Powerstot") String username) {
System.out.println(username);
}
SpringMVC文件上传
表单上传客户端三要素
- 表单项:
type = "file"
- 表单提交方式是
post
- 表单enctype属性是多部份表单形式,
enctype = "multipart/form-data"
文件上传原理
- form表单修改为 多部份表单时,
request.getParameter()
将失效 - 当form表单默认为
enctype = "application/x-www-form-urlencoded"
url编码时,form表单的正文内容是键值对形式key=value&key=value
- 当form表单为
enctype = "Mutilpart/form-data"
时,请求正文变成多部分形式:
单文件上传步骤
- 将form表单修改为
enctype = "Mutilpart/form-data"
,同时添加inputtype = "file"
该项input的name值必须要和Controller中的MultipartFile名称一致 - 导入
commons-fileupload
和commons-io
jar包 - 在
spring-mvc.xml
中配置文件上传解析器
<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--默认编码-->
<property name="defaultEncoding" value="UTF-8"/>
<!--文件上传总大小-->
<property name="maxUploadSize" value="50000"/>
</bean>
- 编写文件上传代码
//上传单文件
@RequestMapping("/quick14")
@ResponseBody
public void save14(String username, MultipartFile uploadFile) throws IOException {
System.out.println(username);
//将文件保存到本地
String originalFilename = uploadFile.getOriginalFilename();
uploadFile.transferTo(new File("D:\\Development\\" + originalFilename));
}
//上传多文件
@RequestMapping("/quick15")
@ResponseBody
public void save15(String username, MultipartFile[] uploadFiles) throws IOException {
System.out.println(username);
//遍历文件数组将文件分别存储到本地
for (MultipartFile multipartFile : uploadFiles) {
String originalFilename = multipartFile.getOriginalFilename();
multipartFile.transferTo(new File("D:\\Development\\" + originalFilename));
}
}
SpirngMVC拦截器
作用
- 拦截器(interceptor)类似于 web 开发过程中的 Filter,用于对处理器进行预处理 和 后处理
- 拦截器按照一定顺序链接成链,被称为 拦截器链, 访问被拦截的方法或字段时,拦截器链中的拦截器就会按定义的顺序被执行
- 拦截器 也是 AOP 思想的具体实现
拦截器(Interceptor)和过滤器(Filter)的区别
区别 | 过滤器Filter | 拦截器Interceptor |
---|---|---|
使用范围 | servlet规范的一部分,Java Web工程都可使用 | SpringMVC框架自己的功能 |
拦截范围 | 在url-pattern中配置了 /* 之后,可以对所有资源进行拦截 | 只拦截访问的控制器方法,如果访问的是jsp,html,css或者js是不会进行拦截的 |
拦截器使用步骤
- 创建拦截器并实现
HanderInterceptor
接口
public class MyInterceptor1 implements HandlerInterceptor {
//方法执行前
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
String param = request.getParameter("param");
if ("yes".equals(param)) {
return true;
} else {
request.getRequestDispatcher("/error.jsp").forward(request,response);
return false;
}
}
//方法执行后,视图返回前
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//一般在postHandle对模型进行修改操作
modelAndView.addObject("name", "Powerstot");
System.out.println("postHandle");
}
//视图返回之后
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterHandle");
}
}
- 在
web.xml
中配置拦截器(可以配置多个拦截器,按照定义的顺序执行)
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--要拦截的路径-->
<mvc:mapping path="/**"/>
<bean class="com.itheima.interceptor.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
<mvc:mapping path="/**"/>
SpringMVC的path配置为
/**
表示拦截所有文件夹及其子文件夹
/*
表示拦截当前文件夹内文件,不包含子文件夹
/
表示web的根目录
拦截器方法详解
preHandle
:返回true代表放行,false不放行,是最常用的方法。
当返回true时,继续调用下一个拦截器的preHandle
或 目标方法
当返回false时,则后续的Interceptor
和Controller
都不会再执行postHandle
:只有preHandle返回true才执行。在请求方法执行之后,DispatcherServlet 进行视图渲染之前执行afterCompletion
:只有preHandle返回true才执行。在整个请求结束之后,也就是DispatcherServlet渲染了对应的视图之后才执行
SpringMVC异常处理
异常处理的思路
DAO,Service,Controller出现异常都通过 throws Exception 向上抛出,最后由前端控制器交由异常处理器处理
简单异常处理器SimpleMappingExceptionResolver
SpringMVC已经定义好了该类型转换器,使用时直接进行对应视图和异常的映射即可
spring-mvc.xml中
<!--简单异常处理器-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!--默认异常错误视图-->
<property name="defaultErrorView" value="error"/>
<property name="exceptionMappings">
<map>
<!--key:异常类型 value:错误视图,这里已经配置了视图资源解析器修改前后缀-->
<entry key="java.lang.ClassCastException" value="error1"/>
<entry key="java.lang.ArithmeticException" value="error2"/>
</map>
</property>
</bean>
自定义异常处理器
- 创建异常处理器类实现
HandlerExceptionResolver
接口中的方法
通过判断传入的异常对象的种类,进行逻辑的编写,并返回 ModelAndView 对象 - 配置异常处理器(将异常处理器放到Spring容器当中即可)
- 编写异常页面
补充
在web.xml中配置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>
总结
- SpringMVC 主要是可以通过一些简单的配置注解,让 Java 类成为处理请求的控制器,而无需实现任何接口,替代了原先 web 中的 Servlet,使用 Controller 作为替代
- 主要是通过 前端控制器 DispatcherServlet 对指定的路径进行处理,根据请求 分发到不同的 Controller 中,从而执行不同的业务,并且处理返回的 ModelAndView,对页面进行渲染,返回响应
- 主要通过
@RequestMapping
注解,可以实现页面跳转,回写数据等操作,还可以通过@ResponseBody
实现数据的直接回显 - 文件上传主要是通过传递 多部份表单 multipart 的数据
- MVC的拦截器 Interceptor 主要是利用了AOP思想,不会对静态资源进行拦截
- MVC的异常处理,原则是将所有异常向上抛出,最后由异常处理器统一处理,异常处理器中配置 异常 和 对应视图的 映射。
参考
2020年IDEA版黑马Java :BV1WZ4y1H7du