1、配置
1.1、web.xml
| <?xml version="1.0" encoding="UTF-8"?> |
| <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" |
| version="4.0"> |
| |
| |
| <filter> |
| <filter-name>encFilter</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>encFilter</filter-name> |
| <url-pattern>/*</url-pattern> |
| </filter-mapping> |
| |
| |
| |
| |
| <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> |
| |
| |
| |
| <filter> |
| <filter-name>hiddenHttpMethodFilter</filter-name> |
| <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> |
| </filter> |
| <filter-mapping> |
| <filter-name>hiddenHttpMethodFilter</filter-name> |
| <url-pattern>/*</url-pattern> |
| </filter-mapping> |
| |
| </web-app> |
1.2、spring-mvc.xml
| |
| |
| public class DateConverter implements Converter<String, Date> { |
| |
| @Override |
| public Date convert(String s) { |
| Date date = null; |
| try { |
| date = new SimpleDateFormat("yyyy-MM-dd").parse(s); |
| } catch (ParseException e) { |
| e.printStackTrace(); |
| } |
| return date; |
| } |
| } |
| <?xml version="1.0" encoding="UTF-8"?> |
| <beans xmlns="http://www.springframework.org/schema/beans" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xmlns:p="http://www.springframework.org/schema/p" |
| xmlns:c="http://www.springframework.org/schema/c" |
| xmlns:util="http://www.springframework.org/schema/util" |
| xmlns:context="http://www.springframework.org/schema/context" |
| xmlns:aop="http://www.springframework.org/schema/aop" |
| xmlns:tx="http://www.springframework.org/schema/tx" |
| xmlns:mvc="http://www.springframework.org/schema/mvc" |
| xsi:schemaLocation=" |
| http://www.springframework.org/schema/beans |
| http://www.springframework.org/schema/beans/spring-beans.xsd |
| http://www.springframework.org/schema/util |
| http://www.springframework.org/schema/util/spring-util.xsd |
| http://www.springframework.org/schema/context |
| http://www.springframework.org/schema/context/spring-context.xsd |
| http://www.springframework.org/schema/aop |
| http://www.springframework.org/schema/aop/spring-aop.xsd |
| http://www.springframework.org/schema/tx |
| http://www.springframework.org/schema/tx/spring-tx.xsd |
| http://www.springframework.org/schema/mvc |
| http://www.springframework.org/schema/mvc/spring-mvc.xsd"> |
| |
| |
| |
| <context:component-scan base-package="com.zzw.controller" conversion-service="converter"/> |
| |
| <bean id="converter" class="org.springframework.context.support.ConversionServiceFactoryBean"> |
| <property name="converters"> |
| <set> |
| <bean class="com.zzw.converter.DateConverter"/> |
| </set> |
| </property> |
| </bean> |
| |
| |
| |
| |
| |
| |
| |
| |
| <mvc:annotation-driven /> |
| |
| |
| <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> |
| |
| <property name="prefix" value="/WEB-INF/view/"/> |
| <property name="suffix" value=".jsp"/> |
| </bean> |
| |
| |
| |
| <mvc:resources mapping="/static/**" location="/static/"/> |
| |
| |
| |
| |
| |
| <mvc:default-servlet-handler/> |
| </beans> |
1.3、文件上传
导入依赖
| |
| <dependency> |
| <groupId>commons-fileupload</groupId> |
| <artifactId>commons-fileupload</artifactId> |
| <version>1.4</version> |
| </dependency> |
在 spring-mvc.xml 中配置
| |
| <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> |
| |
| <property name="maxUploadSize" value="10485760"/> |
| </bean> |
2、执行流程
前端控制器 DispatcherServlet 三大组件
- 处理器映射器:Handler Mapping
- 处理器适配器:Handler Adapter
- 视图解析器:View Resolver

- 用户发送请求至前端控制器 DispatcherServlet
- DispatcherServlet 收到请求,调用 HandlerMapping 处理器映射器
- 处理器映射器找到具体的处理器(可以根据 xml 配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet
- DispatcherServlet 调用 HandlerAdapter 处理器适配器
- HandlerAdapter 经过适配调用具体的处理器(Controller,也叫后端控制器)
- Controller 执行完成返回 ModelAndView
- HandlerAdapter 将 controller 执行结果 ModelAndView 返回给 DispatcherServlet
- DispatcherServlet 将 ModelAndView 传给 ViewReslover 视图解析器
- ViewReslover 解析后返回具体 View
- DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中),DispatcherServlet 响应用户
3、请求控制
3.1、@RequestMapping
- 控制请求方式(method)
- @RequestMapping(value = "/***" , method = {RequestMethod.GET})
- value / path = "URL"
- method:Get、Post、Put、Delete
- 控制请求参数(param)
- param: 表示请求中必须包含名为 param 的参数
- !param:表示请求中不能包含名为 param 的参数
- param = value:表示请求中包含名为 param 的参数,但是值必须是 value
- param != value:表示请求中包含名为 param 的参数,但是值不能是 value
- {"param1", "param2 = value"}:可以将对于多个参数的要求写入数组
- 请求头(headers)
| @Controller |
| @RequestMapping("/zzw") |
| public class MyController { |
| |
| |
| |
| |
| @RequestMapping(path = {"/firstController.do"}) |
| public String firstController() { |
| System.out.println("firstController"); |
| return "first"; |
| } |
| |
| |
| @RequestMapping(path = "/testRequest1.do", method = {RequestMethod.POST}) |
| public String testRequest1() { |
| System.out.println("testRequest1"); |
| return "first"; |
| } |
| |
| |
| @RequestMapping(path = "/testRequest2.do", params = {"username != root", "password"}) |
| public String testRequest2() { |
| System.out.println("testRequest2"); |
| return "first"; |
| } |
| |
| |
| @RequestMapping(path = "/testRequest3.do", headers = {"Accept-Encoding = gzip, deflate"}) |
| public String testRequest3() { |
| System.out.println("testRequest3"); |
| return "first"; |
| } |
| } |
3.2、@PathVariable
@PathVariable 注解和 restful 风格的支持
| @Controller |
| public class PathController { |
| |
| @RequestMapping(path = "/testPathVariable/{id}/{username}") |
| public String testPathVariable(@PathVariable("id") String id, @PathVariable("username") String username) { |
| System.out.println("id:" + id); |
| System.out.println("username:" + username); |
| System.out.println("testPathVariable1"); |
| return "first"; |
| } |
| } |
4、获取请求参数
4.1、普通类型 @RequestParam
@RequestParam:把请求中指定名称的参数给控制器中的形参赋值,名称参数不一致时可以使用它
- value:请求参数中的名称
- required:请求参数中是否必须提供此参数,默认为 true,表示必须提供,如果不提供将报错
- defaultValue:当没有指定请求参数时,则使用指定的默认值赋值
| |
| |
| |
| @RequestMapping("/test") |
| public String test(String username, @RequestParam("pwd") String password) { |
| System.out.println("username:" + username); |
| System.out.println("password:" + password); |
| return "getParamSuccess"; |
| } |
http://localhost:8080/zzw/test?usErnaMe=&passwoRd=123&pagesize=5&students=张三&students=李四
| |
| |
| |
| |
| |
| @RequestMapping("/test") |
| public String test(@RequestParam("usErnaMe") String username, @RequestParam("passwoRd") String password, |
| @RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize, |
| @RequestParam(value = "sex", required = false) String sex, |
| @RequestParam("students") List<String> students) { |
| System.out.println(username + ":" + password); |
| System.out.println(pageNum + ":" + pageSize); |
| System.out.println(sex); |
| System.out.println(Arrays.toString(students.toArray())); |
| return "success"; |
| } |
4.2、数组类型
http://localhost:8080/zzw/test?strs=111&strs=222&strs=333
| @RequestMapping("/test") |
| public void test(String[] strs) { |
| System.out.println(Arrays.asList(strs)); |
| } |
4.3、对象类型
- 提交的参数名必须和 POJO 的属性名保持一致
- springmvc 底层通过反射给参数列表的属性赋值
通过 set 方法设置属性值的,不是直接通过操作属性
POJO 的属性一定要有 set 方法,要不然就会接收失败
| @RequestMapping("/test") |
| public void test(User user) { |
| System.out.println(user); |
| } |
4.4、集合类型 @RequestBody
- 要么 POJO 封装集合来完成
- 要么 AJAX 异步完成:当使用 ajax 提交时,可以指定 contentType 为 json 形式
那么在方法参数位置使用 @RequestBody 可以直接收集合数据而无需使用 POJO 进行包装
@RequestBody
- required:是否必须有请求体,默认为 true
当取值为 true 时,get 请求方式会报错
如果取值为 false,get 请求得到是 null
- 标注在参数前面,用于将请求体(get 没有请求体)中的 Json 数据转换成指定的对象
如果没有具体的实体类来接收参数,就要用 Map 来接收
| @RequestMapping("/test") |
| public void test(@RequestBody List<User> userList) throws IOException { |
| System.out.println(userList); |
| } |
| <script> |
| |
| var userList = new Array(); |
| userList.push({username: "zhangsan",age: "20"}); |
| userList.push({username: "lisi",age: "20"}); |
| |
| $.ajax({ |
| type: "POST", |
| url: "/zzw/test", |
| data: JSON.stringify(userList), |
| contentType : 'application/json;charset=utf-8' |
| }); |
| </script> |
用于获取请求消息头
- value:提供消息头名称
- required:是否必须有此消息头
@RequestHeader 注解可以获取请求头中的数据,并封装到指定的 map 中
@RequestHeader(headerKey) 指定的键接收请求头中某一项的值,例如 @RequestHeader("cookie") 就是接收请求头中的 cookie 的值
| |
| |
| |
| |
| |
| @RequestMapping("/test") |
| public String test(@RequestHeader Map<String, String> headers, @RequestHeader("cookie") String cookie) { |
| System.out.println(headers); |
| System.out.println(headers.get("cookie")); |
| |
| System.out.println(cookie); |
| |
| return "success"; |
| } |
4.6、@CookieValue
用于把指定 cookie 名称的值传入控制器方法参数
- value:提供消息头名称
- required:是否必须有此 cookie
日期类型转换 @DateTimeFormat(pattern = "yyyy-MM-dd") 可以用于:方法参数列表、类的属性
| @RequestMapping("/test") |
| public string test(@DateTimeFormat(pattern "yyyy-MM-dd") Date birthday){ |
| System.out.println(birthday); |
| return "success"; |
| } |
| @Data |
| @ALLArgsconstructor |
| @NoArgsconstructor |
| public class Person implements Serializable { |
| |
| private String name; |
| private String age; |
| private string gender; |
| private String[]hobby; |
| |
| @DateTimeFormat(pattern = "yyyy-MM-dd") |
| private Date birthdate; |
| } |
5、响应
| |
| <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> |
| <property name="prefix" value="/WEB-INF/" /> |
| <property name="suffix" value=".jsp" /> |
| </bean> |
| * 请求转发 |
| - return "success"; 会去拼接配置文件中的前后缀 |
| - return "forward:/error.jsp"; 写全路径 |
| - request.getRequestDispatcher("/WEB-INF/success.jsp").forward(request, response); 写全路径 |
| |
| * 转发过程中传递数据:存入 request 域 |
| - request.setAttribute("username", "zw"); |
| - model.addAttribute("username", "zw"); |
| - ModelAndView mv = new ModelAndView(); |
| mv.setViewName("success"); 会去拼接配置文件中的前后缀 |
| mv.addObject("username", "zw"); |
| return mv; |
| |
| * 响应重定向 |
| - return "redirect:/error.jsp"; 写全路径 |
| - response.sendRedirect(request.getContextPath() + "/error.jsp"); 写全路径 |
5.1、@ResponseBody
- 方法的返回值不再作为界面跳转依据,将方法返回的数据自动转换为 JSON(使用 ObjectMapper)
- 把我们要响应的数据直接 return 即可,返回值类型为要 return 的数据类型
- 也可以这样回写数据:response.getWriter().print("hello world");
5.2、@RestController
@RestController = @Controller + @ResponseBody
- 相当于 @Controller + @ResponseBody 两个注解的结合,返回 json 数据,不需要在方法前面加 @ResponseBody 注解了
- 但使用 @RestController 这个注解,就不能返回 jsp、html 页面,视图解析器无法解析 jsp、html 页面
@JsonFormat 可以用于:方法参数列表、类的属性,响应 json 数据的处理
- pattern:指定响应时间日期的格式
- Timezone:指定响应的时区,否则会有 8 个小时的时间差
| @DateTimeFormat(pattern = "yyyy-MM-dd") |
| @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") |
| private Date birth; |
6、异常处理
| * 对于异常的处理一般有两种方式 |
| - 当前方法处理(try-catch),这种处理方式会造成业务代码和异常处理代码的耦合 |
| - 当前方法不处理,出现异常后直接抛给调用者处理 |
| * 使用 Spring 框架后,我们的代码最终是由框架来调用的 |
| * 也就是说,异常最终会抛到框架中,然后由框架指定异常处理器来统一处理异常 |

6.1、配置方式
| * SpringMVC 允许自定义一个全局异常处理类来统一处理异常 |
| * 它要求这个类必须实现 HandlerExceptionResolver 接口,并重写类中异常的处理方法 |
| @Component |
| public class GlobalExceptionHandler implements HandlerExceptionResolver { |
| |
| @Override |
| public ModelAndView resolveException(HttpServletRequest httpServletRequest, |
| HttpServletResponse httpServletResponse, Object o, Exception e) { |
| |
| if (e instanceof ArithmeticException) { |
| System.out.println("数学异常"); |
| } else if (e instanceof NullPointerException) { |
| System.out.println("空指针异常"); |
| } else { |
| System.out.println("其它异常"); |
| } |
| |
| ModelAndView mv = new ModelAndView(); |
| mv.setViewName("forward/error.jsp"); |
| return mv; |
| } |
| } |
| |
| <context:component-scan base-package="com.zzw.handler"/> |
6.2、注解方式
| * SpringMVC 支持下面两个注解来实现全局异常处理 |
| - @ControllerAdvice 要标注在类上,表示当前类是一个全局异常处理器的类 |
| - @ExceptionHandler 标注在方法上,表示当前方法可以处理哪些异常 |
| @ControllerAdvice |
| public class GlobalExceptionHandlerAnno { |
| |
| |
| @ExceptionHandler(Throwable.class) |
| public String handlerThrowable() { |
| System.out.println("大异常"); |
| return "forward:/error.jsp"; |
| } |
| |
| |
| @ExceptionHandler(ArithmeticException.class) |
| public String handlerArithmeticException() { |
| System.out.println("数学异常"); |
| return "forward:/error.jsp"; |
| } |
| |
| |
| @ExceptionHandler(NullPointerException.class) |
| public String handlerNullPointerException() { |
| System.out.println("空指针异常"); |
| return "forward:/error.jsp"; |
| } |
| } |
7、拦截器
7.1、什么是拦截器
拦截器是 Spring 提供的一种技术,它的功能似于过滤器 Filter,它会在进入 controller 之前,离开 controller 之后以及页面渲染完毕之后进行拦截

7.2、自定义拦截器
1、开发拦截器
要对拦截的资源做什么,自定义一个类实现 HandlerInterceptor 接口
| public class MyHandlerInterceptor implements HandlerInterceptor { |
| |
| @Override |
| public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
| System.out.println("请求进入 controller 之前"); |
| return true; |
| } |
| |
| @Override |
| public void postHandle(HttpServletRequest request, |
| HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { |
| System.out.println("请求离开 controller 之后"); |
| } |
| |
| @Override |
| public void afterCompletion(HttpServletRequest request, |
| HttpServletResponse response, Object handler, Exception ex) throws Exception { |
| System.out.println("页面渲染完毕之后"); |
| } |
| } |
2、配置拦截器
在 spring-mvc.xml 中配置你要拦截哪些资源
| |
| <mvc:interceptors> |
| <mvc:interceptor> |
| |
| <mvc:mapping path="/**"/> |
| |
| <mvc:exclude-mapping path="/zzw/test"/> |
| |
| <bean class="com.zzw.handler.MyHandlerInterceptor"/> |
| </mvc:interceptor> |
| </mvc:interceptors> |
7.3、自定义拦截器链
| |
| <mvc:interceptors> |
| <mvc:interceptor> |
| <mvc:mapping path="/zzw/test"/> |
| <bean class="com.zzw.handler.MyHandlerInterceptor1"/> |
| </mvc:interceptor> |
| <mvc:interceptor> |
| <mvc:mapping path="/zzw/test"/> |
| <bean class="com.zzw.handler.MyHandlerInterceptor2"/> |
| </mvc:interceptor> |
| </mvc:interceptors> |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步