ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

SpringMVC(看这一篇就够了)

2026/8/22 18:37:31 拓冰建站 浏览量
SpringMVC(看这一篇就够了) 目录*SpringMVC* * 什么是MVC模型 * SpringMVC * 案例 * SpringMVC执行流程 * SpringMVC封装参数 * * 简单数据类型 * 简单对象 * 关联对象 * 简单数据类型集合 * Map集合 * 参数类型转换器 * 编码过滤器 * Servlet原生对象 * SpringMVC处理响应 * * 视图解析器 * 返回值为void * 返回值为ModelAndView * 向request域设置数据 * 向session域设置数据 * 向context域设置数据 * 请求转发重定向 * SpringMVC注解 * * Controlle r和 RequestMapping * RequestParam * RequestHeader、CookieValue * SessionAttributes * ModelAttribute * RESTful风格支持 * PathVariable * PostMapping、GetMapping、PutMapping、DeleteMapping * HiddenHttpMethodFilter * ResponseBody * RestController * 静态资源映射 * RequestBody * SpringMVC上传 * * 原生方式上传 * SpringMVC方式上传 * 上传多文件 * 异步上传 * 跨服务器上传 * 查询可下载的文件 * 下载文件 * SpringMVC异常处理 * * 单个控制器异常处理 * 全局异常处理 * 自定义异常处理器 * SpringMVC拦截器 * * 拦截器的使用 * 全局拦截器 * 拦截器链与执行顺序 * 过滤敏感词 * SpringMVC跨域请求 * * 同源策略 * 跨域请求 * 接收跨域请求SpringMVC---------### 什么是MVC模型MVC全称Model View Controller是一种设计创建Web应用程序的模式。这三个单词分别代表Web应用程序的三个部分Model模型指数据模型。用于存储数据以及处理用户请求的业务逻辑。在Web应用中JavaBean对象业务模型等都属于Model。View视图用于展示模型中的数据的一般为jsp或html文件。Controller控制器是应用程序中处理用户交互的部分。接受视图提出的请求将数据交给模型处理并将处理后的结果交给视图显示。### SpringMVCSpringMVC是一个基于MVC模式的轻量级Web框架是Spring框架的一个模块和Spring可以直接整合使用我们使用的版本是Spring6所以JDK需要17以上。SpringMVC代替了Servlet技术它通过一套注解让一个简单的Java类成为处理请求的控制器而无须实现任何接口。### 案例1. 使用maven创建web项目补齐包结构。 2. 引入相关依赖 org.springframework spring-context 6.0.11 org.springframework spring-web 6.0.11 org.springframework spring-webmvc 6.0.11 jakarta.servlet jakarta.servlet-api 6.0.0 provided jakarta.servlet.jsp jakarta.servlet.jsp-api 3.0.0 provided 3. 在web.xml中配置前端控制器DispatcherServlet。 Archetype Created Web Application dispatcherServlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:springmvc.xml 1 dispatcherServlet / 4.编写SpringMVC核心配置文件springmvc.xml该文件和Spring配置文件写法一样。 ?xml version1.0 encodingUTF-8? context:component-scan base-package“com.jjy”/ mvc:annotation-driven/ 5.编写控制器 Controller public class MyController1 { // 该方法的访问路径是/c1/hello1 RequestMapping(“/c1/hello1”) public void helloMVC(){ System.out.println(“hello SpringMVC”); } } 6. 配置tomcat10启动项目访问 http://localhost:8080/c1/hello1### SpringMVC执行流程SpringMVC的组件* DispatcherServlet前端控制器接受所有请求调用其他组件。* HandlerMapping处理器映射器根据配置找到方法的执行链。* HandlerAdapter处理器适配器根据方法类型找到对应的处理器。* ViewResolver视图解析器找到指定视图。组件的工作流程1. 客户端将请求发送给前端控制器。2. 前端控制器将请求发送给处理器映射器处理器映射器根据路径找到方法的执行链返回给前端控制器。3. 前端控制器将方法的执行链发送给处理器适配器处理器适配器根据方法类型找到对应的处理器。4. 处理器执行方法将结果返回给前端控制器。5. 前端控制器将结果发送给视图解析器视图解析器找到视图文件位置。6. 视图渲染数据并将结果显示到客户端。### SpringMVC封装参数#### 简单数据类型在Servlet中我们通过request.getParameter(name)获取请求参数。该方式存在两个问题* 请求参数较多时会出现代码冗余。* 与容器紧耦合。而SpringMVC支持参数注入的方式用于获取请求数据即将请求参数直接封装到方法的参数当中。用法如下1. 编写控制器方法 // 封装为简单数据类型类型参数 RequestMapping(“/c1/param1”) public void simpleParam(String username,int age){ System.out.println(username); System.out.println(age); } 2. 访问该方法时请求参数名和方法参数名相同即可完成自动封装。http://localhost:8080/c1/param1usernamebzage10#### 简单对象SpringMVC支持将参数直接封装为对象写法如下1. 编写实体类 public class Student { private int id; private String name; private String sex; // 省略getter/setter/tostring } 2. 编写控制器方法 // 封装为简单对象类型参数 RequestMapping(“/c1/param2”) public void objParam(Student student){ System.out.println(student); } 3. 访问该方法时请求参数名和对象参数的属性名相同即可完成自动封装。http://localhost:8080/c1/param2id1namebzsexfemale#### 关联对象SpringMVC还可以将请求参数封装为关联对象即对象的属性也是一个对象。写法如下1. 编写实体类 public class Student { private int id; private String name; private String sex; private Address address; // 地址对象 // 省略getter/setter/tostring } public class Address { private String info; //地址信息 private String postcode; //邮编 // 省略getter/setter/tostring } 2. 编写控制器方法 // 获取关联对象类型参数 RequestMapping(“/c1/param3”) public void objParam2(Student student){ System.out.println(student); } 3. 访问该方法时请求参数名和方法参数的属性名相同即可完成自动封装。http://localhost:8080/c1/param3id1namebzsexfemaleaddress.infobeijingaddress.postcode030000我们也可以使用表单发送带有参数的请求 % page contentType“text/html;charsetUTF-8” language“java” %表单提交id: 姓名: 性别: 住址: 邮编: #### 简单数据类型集合1.编写控制器方法// 封装为简单数据类型集合参数前必须添加RequestParam注解 RequestMapping(“/c1/param4”) public void listParam(RequestParam List users){ System.out.println(users); } 2. 该方式也可以封装为简单数据类型数组 RequestMapping(“/c1/param5”) public void listParam2(RequestParam String[] users){ System.out.println(users[0]); System.out.println(users[1]); } 3. 请求的参数写法http://localhost:8080/c1/param4usersbjuserssxt#### Map集合同样SpringMVC要想把参数封装到Map集合中需要封装到有Map属性的对象中。1. 编写实体类 public class AddressMap { private MapString,Address address; // 省略getter/setter/tostring } 2. 编写控制器方法 // 对象中包含map属性 RequestMapping(“/c1/param7”) public void mapParam3(AddressMap addressMap){ System.out.println(addressMap.getAddress()); } 3. 请求的参数写法参数的写法为map属性名[键].值中的属性例如address[one].info请求的路径如下http://localhost:8080/c1/param7address[one].infobjaddress[one].postcode100010address[two].infoshaddress[two].postcode100011编码后为http://localhost:8080/c1/param7address%5Bone%5D.infobjaddress%5Bone%5D.postcode100010address%5Btwo%5D.infoshaddress%5Btwo%5D.postcode100011#### 参数类型转换器前端传来的参数全部为字符串类型SpringMVC使用自带的转换器将字符串参数转为需要的类型。如 // 获取简单类型参数 RequestMapping(“/c1/param1”) public void simpleParam(String username,int age){ System.out.println(username); System.out.println(age); } 但在某些情况下无法将字符串转为需要的类型如 RequestMapping(“/c1/param8”) public void dateParam(Date birthday){ System.out.println(birthday); } 由于日期数据有很多种格式SpringMVC默认只能转换2050/1/1这样的日期格式。但假如前端传来的参数格式为2025-01-01时SpringMVC就无法解析参数。此时需要自定义参数类型转换器。1. 定义类型转换器类实现Converter接口 // 类型转换器必须实现Converter接口两个泛型代表转换前的类型转换后的类型 public class DateConverter implements ConverterString, Date { /* 转换方法 * param source 转换前的数据 * return 转换后的数据/ Override public Date convert(String source) { SimpleDateFormat sdf new SimpleDateFormat(“yyyy-MM-dd”); Date date null; try { date sdf.parse(source); } catch (ParseException e) { e.printStackTrace(); } return date; } } 2. 0注册类型转换器对象 mvc:annotation-driven conversion-service“dateConverter”/mvc:annotation-driven 3. 此时再访问http://localhost:8080/c1/param9birthday2025-01-01时SpringMVC即可将请求参数封装为Date类型的参数。#### 编码过滤器在传递参数时tomcat10以上不会出现中文乱码tomcat8以上能处理get请求的中文乱码但不能处理post请求的中文乱码。编写jsp表单 % page contentType“text/html;charsetUTF-8” language“java” %编码过滤器姓名: 编写控制器方法 RequestMapping(“/cn/code”) public void code(String username){ System.out.println(username); } SpringMVC提供了处理中文乱码的过滤器在web.xml中配置该过滤器即可解决中文乱码问题 encFilter org.springframework.web.filter.CharacterEncodingFilter encoding utf-8 encFilter /#### Servlet原生对象SpringMVC的方法中已经封装好了Servlet原生对象在方法参数中定义HttpServletRequest、HttpServletResponse、HttpSession等类型的参数即可直接在方法中使用。 // 使用Servlet原生对象 RequestMapping(“/c1/param9”) public void servletParam(HttpServletRequest request, HttpServletResponse response, HttpSession session){ // 原生对象获取参数 System.out.println(request.getParameter(“name”)); System.out.println(response.getCharacterEncoding()); System.out.println(session.getId()); } 访问该方法即可http://localhost:8080/c1/param9namebjsxt 一般情况下在SpringMVC中都有对Servlet原生对象的方法的替代推荐使用SpringMVC的方式代替Servlet原生对象。### SpringMVC处理响应#### 视图解析器SpringMVC默认情况下会在控制器执行完成后跳转到视图页面视图解析器能找到相应的视图之前的404异常就是由于没有配置视图解析器导致找不到视图。在SpringMVC中提供了13个视图解析器用于支持不同的视图技术。InternalResourceViewResolver是SpringMVC的默认视图解析器用来解析JSP视图。 #### 返回值为void我们可以通过控制器方法的返回值设置跳转的视图控制器方法支持的返回值类型为void、String、ModelAndView我们以此进行介绍。当控制器方法的返回值为void时会跳转到名字是前缀方法路径名后缀的jsp页面1. 编写控制器方法 // 路径是helloMVC方法执行完后会跳转到/helloMVC.jsp RequestMapping(“/helloMVC”) public void helloMVC(){ System.out.println(“hello SpringMVC”); } 2. 编写helloMVC.jsp % page contentType“text/html;charsetUTF-8” language“java” %MVC欢迎来到SpringMVC6 #### 返回值为ModelAndViewModelAndView是SpringMVC提供的对象该对象可以向request域设置数据并指定跳转的页面。该对象中包含Model对象和View对象。 Model向request域中设置数据。 View指定跳转的页面。编写控制器方法 // 返回值为ModelAndView RequestMapping(“/c2/hello2”) public ModelAndView useMAV(){ System.out.println(“返回值类型为ModelAndView”); // 1.创建ModelAndView对象 ModelAndView modelAndView new ModelAndView(); // 2.获取Model对象本质是一个Map MapString, Object model modelAndView.getModel(); // 3.使用Model对象向request域设置数据 model.put(“name”,“jjy”); // 4.使用View对象设置跳转的路径为/baizhan.jsp modelAndView.setViewName(“jjy”); return modelAndView; } 2. 编写jsp页面 % page contentType“text/html;charsetUTF-8” language“java”%中北你好KaTeX parse error: Double subscript at position 329: …avaee/web-app_3_̲1.xsd …{requestScope.name}地址是KaTeX parse error: Expected EOF, got # at position 117: …n域设置数据后面我们会讲到。#̲### 向context域设置…{requestScope.name}地址是s e s s i o n S c o p e . a d d r e s s / h 1 h 1 年纪是 {sessionScope.address}/h1 h1年纪是sessionScope.address/h1h1年纪是{applicationScope.age}#### 请求转发重定向之前的案例我们发现request域中的值可以传到jsp页面中也就是通过视图解析器跳转到视图的底层是请求转发。如果我们跳转时不想使用视图解析器可以使用原生HttpServletRequest进行请求转发或HttpServletResponse进行重定向 RequestMapping(“/c2/hello8”) public void myForward1(HttpServletRequest request, HttpServletResponse response) throws Exception{ request.setAttribute(“name”,“中北”); // 请求转发 // request.getRequestDispatcher(“/c2/hello9”).forward(request,response); // 原生重定向 response.sendRedirect(“/c2/hello9”); } RequestMapping(“/c2/hello9”) public void myForward2(HttpServletRequest request){ System.out.println(“hello”); System.out.println(request.getAttribute(“name”)); } SpringMVC还提供了一种更简单的请求转发和重定向的写法 RequestMapping(“/c2/hello10”) public String myForward3(HttpServletRequest request){ request.setAttribute(“name”,“中北”); // 请求转发 return “forward:/c2/hello9”; // 重定向 // return “redirect:/c2/hello9”; } ### SpringMVC注解#### Controlle r和 RequestMappingController作用标记控制器将控制器交给Spring容器管理。位置类上方RequestMapping作用给控制器方法设置请求路径位置方法或类上方。用于类上表示类中的所有控制器方法都是以该地址作为父路径。属性* value/path:请求路径* method:指定请求方式* params:规定必须发送的请求参数* headers:规定请求必须包含的请求头 Controller RequestMapping(“/c3”) public class MyController3 { /* 访问路径是 /c3/a1 * 支持post和get请求 * 请求必须带有username参数 * 请求必须带有User-agen请求头 */ RequestMapping(path “/a1”, method {RequestMethod.POST, RequestMethod.GET}, params {“username”}, headers {“User-agent”}) public String annotation1(String username) { System.out.println(username); return “baizhan”; } } #### RequestParam作用在控制器方法中封装请求参数位置方法参数前属性value/name指定请求参数名称* defaultValue 为参数设置默认值* required设置是否是必须要传入的参数 /* 定义请求的参数名为name默认值为sxt不是必须的参数/ RequestMapping(“/a2”) public String annotation2(RequestParam(name “name”,defaultValue “sxt”,required false) String username) { System.out.println(username); return “baizhan”; } 请求URL的写法http://localhost:8080/c3/a2namebz#### RequestHeader、CookieValue*RequestHeader作用将请求头数据封装到控制器方法参数中位置方法参数前CookieValue作用将Cookie数据封装到控制器方法参数中位置方法参数前 /* 获取User-Agent请求头 获取JSESSIONID的Cookie值/ RequestMapping(“/annotation3”) public String annotation3(RequestHeader(“User-Agent”) String userAgent, CookieValue(“JSESSIONID”) String jSessionId){ System.out.println(userAgent); System.out.println(jSessionId); return “baizhan”; } #### SessionAttributes作用将Model模型中的数据存到session域中位置类上方 Controller RequestMapping(“/c4”) // 将模型中的name数据保存到session中 SessionAttributes(“name”) public class MyController4 { RequestMapping(“/t1”) public String t1(Model model){ // model中保存name数据 model.addAttribute(“name”,“中北 1111”); return “baizhan”; } RequestMapping(“/t2”) public String t2(HttpSession session){ // 从session中获取name数据 Object name session.getAttribute(“name”); System.out.println(name); return “baizhan”; } } #### ModelAttribute作用1设置指定方法在控制器其他方法前执行位置 方法上方 Controller RequestMapping(“/c5”) public class MyController5 { ModelAttribute public void before(){ System.out.println(“前置方法”); } RequestMapping(“/t1”) public Stringt1(){ System.out.println(“t1”); return “zb”; } } 作用2 从Model模型中获取数据给参数赋值 位置方法参数前 Controller RequestMapping(“/c6”) public class MyController6 { //前置方法向Model中设置数据 ModelAttribute public void before(Model model){ model.addAttribute(“name”,“中北”); } //该参数不是从请求中获取而是从Model中获取 RequestMapping(“/t1”) public String t1(ModelAttribute(“name”) String name){ System.out.println(name); return “baizhan”; } } #### RESTful风格支持RESTful风格是一种URL路径的设计风格。在RESTful风格的URL路径中网络上的任意数据都可以看成一个资源它可以是一段文本、一张图片也可以是一个Java对象。而每个资源都会占据一个网络路径无论对该资源进行增删改查访问的路径是一致的。传统URL查找id为1的学生http://localhost:8080/student/findByIdid30* 删除id为1的学生http://localhost:8080/student/deleteByIdid30RESTful风格URL*** 查找id为30的学生http://localhost:8080/student/30* 删除id为30的学生http://localhost:8080/student/30那么如何区分对该资源是哪一种操作通过请求方式不同判断进行的是什么操作。之前我们学过两种请求方式GET请求和POST请求而访问RESTful风格的URL一共有四种请求方式* GET请求查询操作* POST请求新增操作* DELETE请求删除操作* PUT请求修改操作RESTful风格URL * 查找id为30的学生 http://localhost:8080/student/30 GET方式请求 * 删除id为30的学生 http://localhost:8080/student/30 DELETE方式请求RESTful风格的优点:结构清晰、符合标准、易于理解、扩展方便。#### PathVariable作用在RESTful风格的URL中获取占位符的值位置方法参数前属性value获取哪个占位符的值作为参数值如果占位符和参数名相同可以省略该属性。 Controller RequestMapping(“/student”) // 模拟学生的增删改查控制器 public class MyController6 { // 路径中的/{id}表示占位符最后会封装到方法的参数中使用 // 删除学生 RequestMapping(value “/{id}”,method RequestMethod.DELETE) public String deleteStudent(PathVariable(“id”) int id){ System.out.println(“删除id为”id“的学生”); return “baizhan”; } // 如果占位符和参数名相同可以省略PathVariable中的value属性 // 根据id查询学生 RequestMapping(value “/{id}”,method RequestMethod.GET) public String findStudentById(PathVariable int id){ System.out.println(“查找id为”id“的学生”); return “baizhan”; } // 新增学生 RequestMapping(value “/{id}”,method RequestMethod.POST) public String addStudent(PathVariable int id, Student student){ System.out.println(“新增id为”id“的学生”); System.out.println(student); return “baizhan”; } // 修改学生 RequestMapping(value “/{id}”,method RequestMethod.PUT) public String updateStudent(PathVariable int id, Student student){ System.out.println(“修改id为”id“的学生”); System.out.println(student); return “baizhan”; } } 访问方式* 新增学生POST localhost:8080/student/100name百战sex女* 修改学生PUT localhost:8080/student/100name百战1sex女1* 删除学生DELETE localhost:8080/student/100* 查询学生GET localhost:8080/student/100#### PostMapping、GetMapping、PutMapping、DeleteMapping作用简化设置请求方式的RequestMapping写法位置方法上方。 Controller RequestMapping(“/student”) public class StudentController { // 删除学生 DeleteMapping(“/{id}”) public String deleteStudent(PathVariable(“id”) int id){ System.out.println(“删除id为”id“的学生”); return “baizhan”; } // 根据id查询学生 GetMapping(“/{id}”) public String findStudentById(PathVariable int id){ System.out.println(id); System.out.println(“根据id查询学生”); return “baizhan”; } // 新增学生 PostMapping(“/{id}”) public String addStudent(PathVariable int id, Student student){ System.out.println(id); System.out.println(student); System.out.println(“新增学生”); return “baizhan”; } // 修改学生 PutMapping(“/{id}”) public String updateStudent(PathVariable int id, Student student){ System.out.println(id); System.out.println(student); System.out.println(“修改学生”); return “baizhan”; } } #### HiddenHttpMethodFilter由于浏览器的表单只支持GET与POST请求不支持DELETE、PUT请求。所以SpringMVC提供了一个过滤器可以将浏览器的POST请求改为指定的请求方式发送给控制器的方法。用法如下1. 在web.xml中配置过滤器 httpMethodFilter org.springframework.web.filter.HiddenHttpMethodFilter httpMethodFilter / 2. 编写控制器方法 Controller RequestMapping(“/c7”) public class MyController7 { DeleteMapping(“/delete”) public String testDelete(){ System.out.println(“删除方法”); return “baizhan”; } PutMapping(“/put”) public String testPut(){ System.out.println(“修改方法”); return “baizhan”; } } 3. 在jsp中编写表单 % page contentType“text/html;charsetUTF-8” language“java” %DELETE、PUT提交%-- 提交DELETE、PUT请求表单必须提交方式为post --% %-- 表单中有一个隐藏域name值为_methodvalue值为提交方式 --%#### ResponseBody作用方法返回的对象转换为JSON格式并将JSON数据直接写入到输出流中使用此注解后不会再经过视图解析器。使用该注解可以处理Ajax请求。位置方法上方或方法返回值前1. 编写jsp页面发送ajax请求 % page contentType“text/html;charsetUTF-8” language“java” %ajax请求异步请求 **结果当浏览器通过http://localhost:8080/cross.jsp访问JSP页面时http://localhost:8080/c12/t1 能发送异步请求http://127.0.0.1:8080/c12/t1 由于同源无法发送异步请求报以下异常#### 接收跨域请求SpringMVC提供了注解CrossOrigin解决跨域问题。用法如下 RequestMapping(“/t1”) ResponseBody // 如果请求从http://localhost:8080发出则允许跨域访问 CrossOrigin(“http://localhost:8080”) public String t1(){ System.out.println(“测试跨域请求”); return “success”; } 如果我的内容对你有帮助请点赞评论收藏。创作不易大家的支持就是我坚持下去的动力