“一锅端“ Spring MVC 常见使用大全 港控/mmm° 2024-03-16 16:51 8阅读 0赞 ## 一. Spring Boot 里的 Spring MVC ## 1. **Spring Boot 是什么 ?** Spring Boot 在之前的文章中有介绍过, 它是一个快速构建生产级别的 Spring 引用程序的框架, 它基于 Spring Frameword, 并通过自动配置、约点大于配置、快速开发等方式, 开发人员更快地创建出高效、可靠的 Spring 应用程序 1. **Spring MVC 是什么?** Spring MVC 是基于 Servlet API 构建的原始 Web 框架, 它全称叫做 Spring Web MVC 来自于其源模块的名称( spring-webmvc ), 也就是我们现在常叫做的 Spring MVC Spring MVC 中的 MVC 全程为 Model View Controller, M-模型, V-视图, C-控制器, 也就是视图模型控制器, 它是一种软件构架模式( 它是后面出现的一种设计模式 ) ![image.png][] **所以 MVC 是一种思想, 而 Spring MVC 是对 MVC 的一种具体实现** 1. **Spring Boot 和 Spring MVC 之前有什么关系 ?** 对于这二者之间, Spring Boot 是构建在 Spring Framework 之上的, 而 Spring MVC 是 Spring Framework 中的一个模块, 因此 Spring Boot 中也包含了 Spring MVC. 具体来说便是, Spring Boot 中默认使用 Spring MVC 作为 Web 开发框架, 并通过自动配置的方式简化了 Spring MVC 的配置过程, 开发人员通过添加正确的依赖和一些简单的配置, 快速的搭建一个完整的 Web 应用程序 因此可以说 Spring Boot 是围绕 Spring MVC 和其他 Spring 模块构建的一个全新引用程序开发框架, 在提供 Spring MVC 功能的同时又提供了额外的便利功能, 使得开发可以更加高效便捷的构建 Web 应用程序 ## 二. Spring MVC 的具体使用 ## ### 1. Spring MVC 的创建 ### 我们前面说道, Spring MVC 是 Spring 中的一个模块而已, 因此我们在用 Spring Boot 框架开发时, 只需要添加 Spring MVC 的起步依赖就好. 并且通过添加 Spring Web 依赖说明时, 就可以看到 Spring Web 其实就是 Spring MVC ![image.png][image.png 1] ### 2. 和浏览器建立连接 ### #### 2.1 @RequestMapping 注解建立连接 #### 通过标准分层, 在controller 包下创建一个 UserController, 并添加一个方法, 方法上添加 @RequestMapping 注解 // 等同于 @ResponseBody 和 @Controller 注解 @RestController // 让 Spring 框架启动时加载, 并且返回的非页面数据 public class UserController { @RequestMapping("/user1") public String fun1() { return "这是 user1 路由下的 fun1 方法"; } } 启动项目后, 此时通过本地 localhost 就可以访问当前页面了.这样就和浏览器建立了连接 ![image.png][image.png 2] 可以看到的是, 这里@RequestMapping 注解是 Spring Web 程序中最常用的一个注解, 它用来注册接口的路由映射的( **当用户访问一个 url 时, 将用户的请求对应到程序中某个类下的某个方法的过程就为路由映射** ). 1. **而这里的 @RequestMapping 注解除了上面加在了方法上, 它也可以加载类上, 此时访问的 url 就为类上的路径 + 方法的路径** // 等同于 @ResponseBody 和 @Controller 注解 @RestController // 让 Spring 框架启动时加载, 并且返回的非页面数据 @RequestMapping("user") public class UserController { @RequestMapping("/user1") public String fun1() { return "这是 user1 路由下的 fun1 方法"; } } 只访问方法上的路径是不对的, 必须是类路径加方法路径 ![image.png][image.png 3] ![image.png][image.png 4] 1. **方法上和类上也可以实现多级路由** // 等同于 @ResponseBody 和 @Controller 注解 @RestController // 让 Spring 框架启动时加载, 并且返回的非页面数据 @RequestMapping("user") public class UserController { @RequestMapping("/user1/fun") public String fun1() { return "这是 user1 路由下的 fun1 方法"; } } ![image.png][image.png 5] 具体要如何实现, 可以根据自己的需求来实现. 1. **@RequestMapping 是什么类型的请求 ?** **首先, 它肯定是支持 Get 请求的, 因为我们之前访问 localhost 时, 使用的就是 Get 方法. 那它支不支持其他方法呢 ?** // 等同于 @ResponseBody 和 @Controller 注解 @RestController // 让 Spring 框架启动时加载, 并且返回的非页面数据 public class UserController { @RequestMapping("/user1") public String fun1() { return "这是 user1 路由下的 fun1 方法"; } } 1. **使用 Postman 构造一个 Post 请求和 Delete 请求看看, 还能访问这个方法嘛 ?** ![image.png][image.png 6] ![image.png][image.png 7] 可以看到的是, @RequestMapping 注解不指定特定路由方法下, 是支持多种路由请求的, 具体有哪些我们可以在源码中看到, 下面这些都是 @RequestMapping 注解支持的路由方法 ![image.png][image.png 8] **b. 只允许 Post 请求或者 Get 请求能实现嘛 ?** // 等同于 @ResponseBody 和 @Controller 注解 @RestController // 让 Spring 框架启动时加载, 并且返回的非页面数据 public class UserController { @RequestMapping(value = "/user1", method = RequestMethod.POST) public String fun1() { return "这是 user1 路由下的 fun1 方法"; } } 在@RequestMapping 里设置 method 属性, 选择路由方法为 POST. 在去通过 Postman 构建一个 Get 请求, 看看还能发送成功嘛 ? ![image.png][image.png 9] **可以看到, 此时它报了 405, 提示方法不被允许, 因此可以看到在 @RequestMapping 注解里, 不仅可以设置多级路由, 还可以限定路由的访问方法** 只能由指定的路由方法访问 ! ! ! ![image.png][image.png 10] #### 2.2 其他注解建立连接 #### 上面的指定路由方法建立连接, 在我们的 Spring Web 里提供了更便捷的注解进行连接, 例如只允许 Post 的路由方法 @PostMapping("/user2") public String fun() { return "这是 user2 路由下的 Post治党路由方法"; } 还是一样, 当我们去通过 Postman 进行构造一个 GET 方法访问时, 是不被允许的 ![image.png][image.png 11] 只有 POST 方法才可以, 其他路由方法都不行 ![image.png][image.png 12] ### 3. 获取参数 ### 建立连接后, 对于我们的项目中, 最重要的就是获取 web 项目中的一些参数. #### 3.1 获取 url 参数 #### @RequestMapping("/user3") public String getParameter(String name) { return "这是获取到的参数 : " + name; } 建立路由方法, 启动项目后访问, 此时我们并没有传入参数, 因此此处为默认值 ( 需要注意, 包装类的默认值也是 null ) ![image.png][image.png 13] 当我们 url 中传入参数时, 可以正确获取到参数属性 ![image.png][image.png 14] 需要注意的时, 必须和方法的参数一致, 才能在 url 中获取到正确的属性值, 当参数为 user 时, 与方法中的参数对不上, 因此无法正确获取 ![image.png][image.png 15] \*\*既然可以获取一个参数, 那么是不是也可以获取两个参数呢 ? \*\* @RequestMapping("/user5") public String getParameter1(String name, String password) { return "获取到的 name : " + name + " password : " + password; } **注意, 此时我在 url 中是先输入的 password 后 输入的 name 但是, 并不会影响正确获取参数, 因为此处是通过 key 和 value 去匹配的, 只需要 key 正确即可匹配对应的 value** ![image.png][image.png 16] **之前我们 Servlet 是通过 request 去获取 url 的参数的, 而 Spring MVC 值基于 Servlet API 的, 因此 Servlet 的方法也是可以在这里使用的** @RequestMapping("/user4") public String getParameter1(HttpServletRequest request, HttpServletResponse response) { return "这是获取到的参数 : " + request.getParameter("name"); } 这里的 request 和 response 等同于是框架内置的, 可以直接使用, 因此这里也是可以正确获取的 ![image.png][image.png 17] #### 3.2 获取 url 对象 #### Web 项目中除了获取 URL 参数外, 获取对象也是非常常见和重要的, 下面就来看如何获取一个对象 1. 先构建一个实体类 userInfo @Data public class UserInfo { private int age; private String name; private String password; } 1. 构造路由方法 @RequestMapping("/reg") public Object reg(UserInfo userInfo) { return userInfo; } 1. 访问路由方法观察 ![image.png][image.png 18] 是不是特别简单 ? 并且, 我们前端传来的是参数, 怎么会变成了对象呢 ?\*\* 原因就在于我们的框架帮我们做了这事, 当程序执行后, Spring MVC 会自动将我们的参数对象映射, 只需要我们传入的属性和对象拥有的属性一致, 框架会根据返回的类型, 自动帮我们匹配是返回标签 还是 JSON 对象返回\*\* 例如 : @RequestMapping("/html") public Object reg1() { return "<h1> 这是一个 HTML 标签</h1>"; } ![image.png][image.png 19] 在抓包确认一下, 框架自动将我们返回的 Object 对象转为需要的 HTML 形式了 ![image.png][image.png 20] #### 3.3 参数重命名( 前端传入参数和后端参数不一致 ) #### ##### 3.3.1 @Value 注解 ##### 在生产中, 前后端的约定不一致时, 比如在注册中, 前端传入的是 username 而后端规定要使用的为 name, 这时候怎么办 ? 如果还用之前的方法, 那么我们将无法获取到对应的属性值, 为了解决这个问题, Spring Boot 框架提供了 @Value 注解, 将指定属性获取后赋值给指定参数, 例如下面 : @RequestMapping("/reg1") public Object reg1(@Value("username") String name, String password) { return "name : " + name + " password : " + password; } 此时, 我们方法中的参数为 name, 但 url 中传入的为 username 但是同样正确获取了 username 的参数. 由于我们此处的重命名, 将 username 属性对应的值获取后赋值给了 name 属性 ![image.png][image.png 21] ##### 3.3.2 @RequestParam 注解 ##### **使用 @RequestParam 注解同样可以重命名参数, 但是 @RequestParam 注解还有一个别的功能, 设置参数是否为非必传参数** @RequestMapping("/reg2") public Object reg2(@RequestParam("username") String name, String password) { return "name : " + name + " password : " + password; } 同样, 使用@RequestParam 是否能够重命名呢 ? 运行后发现是可以的 ![image.png][image.png 22] 那么, 刚刚说的是否为非必传参数又是怎么回事呢 ? **当我们不传入 password, 预期应该是 password 为 null, 并且可以正确访问** ![image.png][image.png 23] **当我们尝试不传 username 属性看看, 预期是否和之前一样, 不传入那么默认为 null 呢 并且可以正确访问呢 ?** ![image.png][image.png 24] 可以看到, 是无法正确访问的, 并且还给我们提示了报错信息 : **username 为一个该方法的必传参数** ![image.png][image.png 25] 因此, 在重命名时, 如果使用 @RequestParam 注解会带来一个必传参数的问题, 那么, 如何解决这个问题呢 ? 我们可以在 @RequestParam 里面添加 required 属性, 可以看到, 默认是 true 的代表这是一个必传参数, 当设置为 false 时, 此时这个重命名的参数就不是必传的了 ![image.png][image.png 26] @RequestMapping("/reg2") public Object reg2(@RequestParam(value = "username", required = false) String name, String password) { return "name : " + name + " password : " + password; } 此时不传入重命名后的 username 也可以正确访问了. ![image.png][image.png 27] #### 3.4 获取 JSON 对象 #### 前面获取的参数, 都是 URL 的形式获取的参数, 哪前端传来的是 JSON 对象, 那么该如何接受获取呢 ? 对于 UserInfo 这个对象, 如果传入的是一个 JSON 格式的 UserInfo, 在用之前的获取方式还能行得通吗 ? @RequestMapping("/reg") public Object reg(UserInfo userInfo) { System.out.println(userInfo); return userInfo; } 利用 Postman 构造请求提交一个 UserInfo 到后端 : ![image.png][image.png 28] 可以看到, 虽然传入了一个 UserInfo 对象, 但是后端根本没有收到正确的对象, 该怎么解决这问题呢 ? ![image.png][image.png 29] ##### 3.4.1 @RequestBody 注解 ##### 在 Spring MVC 里提供了 @RequestBody 注解来接收传来的 JSON 对象 @RequestMapping("/reg3") public Object reg3(@RequestBody UserInfo userInfo) { return userInfo; } 利用 Postman 构造请求 : ![image.png][image.png 30] 可以看到, 后端是成功的拿取到了前端传来的这个 JSON 格式的对象 ![image.png][image.png 31] 对于前端传来的 JSON 对象, Spring Boot 框架和之前一样, 会将拿到的信息赋值给参数, 并自动适配数据格式 #### 3.5 路径传参 #### ##### 3.5.1 @PathVariable 注解 ##### 这样传入参数, 和之前 URL 传参中 user?username=张三&password=123 来说, 搜索引擎抓取关键字的权重更高, 能让人更多的搜索到. 同时当传入的参数更多时, Path 传参的 URL 更简洁. @RequestMapping("/reg4/{username}/{password}") public String reg3(@PathVariable String username, @PathVariable String password) { return "username : " + username + " password : " + password; } ![image.png][image.png 32] 通过 path : reg/4/zhangsan/123 访问, 此处username 就对应到了 zhangsan, password 就对应到了 123, 但这里并不是键值的关系, 因此它对位置是非常敏感的, 无法调换位置, 比如下面这段代码, 此时在去通过刚刚的 Path 获取是无法正确获取的 ![image.png][image.png 33] 可以看到, 此时username=123, 而password=zhangsan, **所以 Path 路径的参数它不是键值的关系, 受到 URL 位置对应影响, 这点需要注意** ![image.png][image.png 34] ##### 3.5.2 @PathVariable 注解的重命名 ##### 对于 @PathVariable 也是有重命名规则的, 并且它还和我们之前的 @RequestParam 注解一样, 有则必传参数的原则, 当设置了 @PathVariable 注解后, 该参数就为必传参数, 如果不需要可以将 required 属性设置为 false. @RequestMapping("/reg4/{username}/{password}") public String reg3(@PathVariable String username, @PathVariable String password) { return "username : " + username + " password : " + password; } 当我们不传入password 时, 再去访问就会报错, 想要 password 不传, 在 @PathVariable 参数后面设置 required 属性为 false 即可 ![image.png][image.png 35] 在来看看 @PathVariable 重命名, 还是和前面的重命名一样的 ![image.png][image.png 36] 同样还是重命名后, 将获取到的 name 的属性值赋值给 username 使用 ![image.png][image.png 37] #### 3.6 获取上传文件 #### 前端除了传来参数、对象意外, 还会传来一些文件, 因此对于如何获取上传的文件也是非常重要的 ##### 3.6.1 MultipartFile 对象 ##### @RequestParam 注解中, 可以设置参数名称, 例如我设置的 myimg, 而 MultipartFile 接口代表了上传文件, 用于处理 HTTP 请求中上传文件的相关操作, 在 Spring MVC 中通常会将上传文件包装成 MultipartFile 对象进行处理 @RequestMapping("/upload") public String upLoad(@RequestParam("myimg") MultipartFile file) throws IOException { File saveFile = new File("E:\\Javacode\\spring\\spring-mvc\\myimg.png"); // 文件保存的路径 try { file.transferTo(saveFile); // 上传文件 - 本身是没有返回值的, 通过 try catch 来检验是否上传成功 return "文件上传成功! "; }catch (IOException e) { e.printStackTrace(); } return "文件上传失败 !"; } 利用 Postman 构造上传文件 ![image.png][image.png 38] 当上传成功后, 可以在之间设置的保存文件路径中查看是否成功上传保存 ![image.png][image.png 39] ![image.png][image.png 40] 同样, 该图片是可以正常打开的 ![image.png][image.png 41] **PS : 需要注意的是, 图片上传的单次文件默认最大大小为 1MB, 单次请求默认最大大小为 10MB, 如果需要上传更大的, 可以在配置文件中进行设置** # 设置单次图片最大大小 spring.servlet.multipart.max-file-size=100MB # 设置单次请求最大大小 spring.servlet.multipart.max-request-size=100MB 虽然上面的代码是成功的获取了前端传来的文件, 但是它并不适用于生产之中, **原因在于每次上次的文件都会进行覆盖上一个文件, 因为它的名称是一样的, 会在相同路径下保存同一个名称的文件而覆盖上一个文**件, 因此不具备生产能力. 那么, 要如何解决这个问题, 让每次生产的文件都不一样呢 ? 想要不重覆, 可以用时间戳、 时间戳加随机数、系统时间等方法, 但是尽管时间戳在不断变化, 但是当并发量够大时, 总有可能出现二者相同时间上传文件, 导致其重复的. 为了更好地解决上面问题, 我们引入了 UUID( 通用唯一标识符 ) . 文件名解决后, 还需要解决一件事, 那就是文件的后缀名, 之前我们用的是固定的文件后缀名 .png, 但是用户上传的文件是很多的, 后缀名不是固定的, 因此我们要想办法获取到用户上传的后缀名并且将获取到的后缀名添加到保存的文件后缀中. @RequestMapping("upload2") public String upload2(@RequestParam("myimg") MultipartFile file) { // 创建文件名名称 String fileName = UUID.randomUUID() + //文件名 file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); // 后缀名 // lastIndexOf 左闭右开需要注意, 包含分割后的 . 的 File saveFile = new File("E:\\Javacode\\spring\\spring-mvc\\" + fileName); // 保存文件 try { file.transferTo(saveFile); // 上传文件 return "上传文件成功 !"; }catch (IOException e) { e.printStackTrace(); } return "上传文件失败"; } 启动后用 Postman 构建表达请求发送文件 ![image.png][image.png 42] 查看是否发送成功 ![image.png][image.png 43] 同时检查我们的文件是否保存在对应路径之中, 可以看到此时文件名已经正确保存并且生成了一串文件名非常复杂的名称, 这个就是 UUID 生成的 ![image.png][image.png 44] 即使多次上传同一文件, 它也不会覆盖 ![image.png][image.png 45] #### 3.7 获取 Cookie (@CookieValue 注解) #### 之前说过, Spring MVC 是基于 Servlet API 的, 因此之前的获取 Cookie 的方法任然可以用, 不同的是用 Servlet 里的 request 去获取 Cookie 获取的是整个页面的所有 Cookie, 也就是得到的是一个 Cookie 数组 @RequestMapping("getCK") public void getCookie(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); } 如果想要去获取指定的某个 Cookie, 还需要去遍历这个 Cookie 数组去拿取指定的 Cookie, 会比较麻烦, **因此在 Spring MVC 中提供了 @CookieValue 注解, 该注解添加后, 一样是一个必传参数, 并且前端必须有这个 Cookie 否则会错误, 也可以通过设置 required 属性来解决这个问题** @RequestMapping("getCK2") public String getCookie(@CookieValue("spring") String spring) { return spring; } 由于并没有事先在浏览器中构造一个名为 spring 的 cookie, 因此此时直接去访问时获取不到的 ![image.png][image.png 46] 由于我们并没有指定的 Cookie, 因此利用浏览器开发者工具伪造一个 Cookie 来进行验证 ![image.png][image.png 47] 构造好后, 再去获取就可以成功拿取到了 ![image.png][image.png 48] #### 3.8 获取 Header (@RequestHeader 注解) #### 请求头里面包含了许多信息, 通过@RequestHeader 注解也是很容易获取到的, 先来回顾一下 Header 请求头中都有哪些字段 ( 下面是我的浏览器中的请求字段 ) ![image.png][image.png 49] 这些字段都是可以通过 @RequestHeader 注解来获取的, 尝试获取一下当前的 Host, 还和之前一样, 获取注解里面指定的 Host 属性后赋值给 host 变量 @RequestMapping("getHD") public String getHeader(@RequestHeader("Host") String host) { return host; } 可以看到, 我当前的 Host 如下 : ![image.png][image.png 50] 其他的字段也是同样的获取方法, 只需修改获取的指定属性就行, 大家可以试试 ! #### 3.9 获取 Session (@RequestAttribute 注解) #### 在那之前, 先回顾之前 Servlet 如何创建会话, 由于此处我没有具体的业务代码, 因此我手动建立一个会话 SESSION\_KEY private static final String SESSION_KEY = "DEFAULT_VALUE"; @RequestMapping("/createSession") public void CreateSession(HttpServletRequest request) { HttpSession session = request.getSession(true); // 没有 session 就创建 session session.setAttribute(SESSION_KEY, "username"); // 将username存入到会话中 } 通过 Servlet 来获取 Session, 在获取之前先要运行建立会话路由方法才能有会话可获取 @RequestMapping("/getSession") public String getSession2(HttpServletRequest request) { HttpSession session = request.getSession(false); // 有则获取, 没有就不建立 return " Servlet 获取 : " + (String) session.getAttribute(SESSION_KEY); } 访问 Servlet 获取 Session 的路由方法 ![image.png][image.png 51] 访问注解方式获取 Session 的路由方法 ![image.png][image.png 52] ### 4. 返回数据 ### 获取前端的参数非常重要, 但是给前端返还数据一样是很重要的, 下面就来看几个常见的返回数据 #### 4.1 返回静态页面 #### static 包底下创建一个 spring.html 文件, 并在文件中写一个 < h1 > Spring MVC < /h1 > 标签 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>Spring MVC</h1> </body> </html> 之前我们返回的都是数据, 而并非页面, 因此我们使用了 @RestBody 注解 或者 @RestController 注解, 但此处我们要返回的就是一个静态页面, 而并非数据, 因此此处不需要在加上面的注解了 @Controller @RequestMapping("/test") public class ControllerDemo { @RequestMapping("/getHtml/test2") public String getHtml() { return "spring.html"; // 返回的液面必须与创建的静态页面名称一致 } } 根据路由方法访问, 结果出现了 404, 根本获取不到对应的页面 ![在这里插入图片描述][53b4d94c8020459ab9d37074cff00719.png] 这是为什么 ? **当我们在返回的 spring.html 中不加上斜杠, 也就是 “/spring.html” 时, 去访问路由方法并不会在根目录底下去获取, 因此获取不到指定页面, 当我们加上 " / " 以后, 就会让它在根目录底下去获取**, 从而可以正确拿到返回的页面 ![image.png][image.png 53] #### 4.2 返回 JSON 对象 #### 除了静态页面, 后端也会经常给前端返回 JSON 格式的对象 @RestController @RequestMapping("/resJson") public HashMap<String, String> resJson() { HashMap<String, String> map = new HashMap<>(); map.put("zhangsan", "1"); map.put("lisi", "2"); return map; } 还是一样的, 加了注解以后, Spring Boot 框架会自动将你返回的数据进行包装. ![image.png][image.png 54] #### 4.3 请求转发和请求重定向 #### Spring MVC 天生就是返回静态页面的, 因此对于重定向、转发等返回是很容易的. @Controller public class ControllerDemo { // 请求转发 @RequestMapping("/fw") public String index2() { return "forward: /spring.html"; } } ![在这里插入图片描述][6c96855519a04b5f848fcf996749e90f.png] **有没有发现, 这和我们之前返回静态页面好像是一样的 ? 其实不然, 当我们访问路由返回的是一个静态页面时, 由于我们访问的是接口, 而你要返回一个静态页面, 实际上就是一个请求转发的过程.** 看看请求重定向 : @Controller public class ControllerDemo { // 请求重定向 @RequestMapping("/re") public String index() { return "redirect: /spring.html"; } } ![image.png][image.png 55] 惊奇的发现, 我们访问重定向的路由地址不是 localhost:8080/re 嘛 ? 怎么页面展示出来结果后, URL 就变成了 localhost:8080/spring.html, 我们可以抓包看看 ![image.png][image.png 56] 可以看到, 当访问路由地址时, 它直接 302 给我们跳转到了 spring.html 页面. **那么, 请求转发和请求重定向有什么区别呢 ?** * 请求转发地址没变, 而请求重定向后地址会发生改变 * 请求转发由服务端转发, 而请求重定向重新定位到资源 * 请求转发由服务端转发, 有可能造成原外部资源不能访问; 而请求重定向与直接访问新地址效果一样, 不存在原来外部资源不能访问 **请求转发由服务器内部进行转发, 用户的感知是不明显的, 因为它的地址并没有发生变化, 但是给你展示的是你想要的页面; 但是重定向用户感知是比较明显的, 它类似于通过他人之手, 直接让你去找谁谁谁( 你重定向的位置 ).** 外部资源不能访问 : **经过服务器进行转发的, 服务器并不像你重定向一样明确的知道你要的是什么, 有可能会出错, 并不觉得清楚你需要什么. 当层级目录过多, 服务器去转发一个静态页面的时候有可能就会出错.** [image.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/50efe5842d1547869ed53d34f577e74a.png [image.png 1]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/90f47e5591f84433be150759ffa61f05.png [image.png 2]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/ed5258282047410d91a0024609be97f3.png [image.png 3]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/c8c5b1fc8ebb46818acc5facbf36e1c9.png [image.png 4]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/734614c0756e43428bc0978a83f22fbc.png [image.png 5]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/b180745594624d3583fe0be45690dd54.png [image.png 6]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/74e4159ff4c64327a7f419a284ffd6f0.png [image.png 7]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/1fe5071d6a8f42dca9889ad63356e744.png [image.png 8]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/b13880e28cb04476bf468ce6f04b387c.png [image.png 9]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/17d9676832af4ce1b0e4fa34399ec923.png [image.png 10]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/32656ab548b44451bf9fc72686f184b0.png [image.png 11]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/51253c089e37453b9c94aa5e05ff0dec.png [image.png 12]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/4dff3914d8714593a6b5e100508ee0ff.png [image.png 13]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/b25cf7de6eca449d85bdcf6827aa5b13.png [image.png 14]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/9785f302655b4923b578f754762ccceb.png [image.png 15]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/63ced253fb8c48348db25541f7998199.png [image.png 16]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/4197a929d814417a945655c57cad65e2.png [image.png 17]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/69d4206f915847baa5a1838a3818be5a.png [image.png 18]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/0e54943d13544f669bbb767c695afe32.png [image.png 19]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/406c7174ee3944b6b137aa3e47e8405a.png [image.png 20]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/088e8999aa6746b5af7ed34d7c5acef3.png [image.png 21]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/b461ce10695844edad9de7e7097602a2.png [image.png 22]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/2540b7d5bf4d4cab965bbf3a599223c1.png [image.png 23]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/befa9245fc9740e691c68dadb3c48d28.png [image.png 24]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/e907c67b10e0440d9ade0d82187643f6.png [image.png 25]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/645379b2a0544bc58d81abbe110bd064.png [image.png 26]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/4c0d60292eba4a07a5782a9c4b04bb6d.png [image.png 27]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/80f3b229fcf647ac8f386c03a886ea73.png [image.png 28]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/37a4175999db4dc1b774bc651fd84247.png [image.png 29]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/8f1ae03d21104eb18d71397ad7a2fcd4.png [image.png 30]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/883c0a893ce14534b8b211eb14579e9b.png [image.png 31]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/b61ff84fcccc455b822242e9de5bceef.png [image.png 32]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/17709432616d41549966b55166ae67a5.png [image.png 33]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/a960061d88624766acdf0608869f6372.png [image.png 34]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/7cdd2cc2de2f4e5b86ae2f9d10caa465.png [image.png 35]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/2840f2eac8b74777b064495811fd0105.png [image.png 36]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/458fd1d754454fcbab1d36a0a81b0965.png [image.png 37]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/72878c70f6fb410eb1ec14689575dc3f.png [image.png 38]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/ab5207ef0b1d40e1816589245383b903.png [image.png 39]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/9cf529c5746c482e8cb34f138cc68482.png [image.png 40]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/5130dd88885d42bd8e7c545d6640ae3f.png [image.png 41]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/5e3ab49a615144b5b93676dd790d40ba.png [image.png 42]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/54b1c7ca14ea41cd8ea7741e24ffc1bd.png [image.png 43]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/1bc7027237754e89aa1e111eba35a27b.png [image.png 44]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/2a4d6707eb7443ccad775729dbfaa8a9.png [image.png 45]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/1a001015caab4d1e85d7a5f2221e0c8d.png [image.png 46]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/4b83bb95094e485ab4f43838cc07d108.png [image.png 47]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/31cc4daa9e9143618b954fc8f9b4be04.png [image.png 48]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/c787beb55529420999b326315c2c2fde.png [image.png 49]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/0ac8ac16af084653a50dbfe63063a0e2.png [image.png 50]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/c9ec4462cc4f400d96df12b533ac0918.png [image.png 51]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/e9be2b29786943538fcdaceedd65a79e.png [image.png 52]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/9bde94e619124a1fa86409be94acaf1f.png [53b4d94c8020459ab9d37074cff00719.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/3c933e3cfc84451daaba8e5b49d2fef1.png [image.png 53]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/627f4a3af2354e1387eb905fa9907989.png [image.png 54]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/2bec73a15d0c4ae8a8b79564f94dd173.png [6c96855519a04b5f848fcf996749e90f.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/e20e71a534594829af8794999f992cdc.png [image.png 55]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/40cf577133a240ff86bf3f0b45bdb3ee.png [image.png 56]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/16/a1eb775fc8fe4ce0a9c554555ac75983.png
相关 “一锅端“ Spring MVC 常见使用大全 一. Spring Boot 里的 Spring MVC 1. Spring Boot 是什么 ? Spring Boot 在之前的文章中有介绍过, 它是一个快速构建 港控/mmm°/ 2024年03月16日 16:51/ 0 赞/ 9 阅读
相关 【Spring MVC】Spring MVC程序开发教程:常见的注解及使用方式详情 前言 Spring MVC是一种常用的Web框架,它可以帮助开发人员快速构建可扩展的Web应用程序。为了提供更好的开发体验和更高的代码效率,Spring MVC提供了各 川长思鸟来/ 2023年10月13日 12:20/ 0 赞/ 11 阅读
相关 Spring MVC(spring-webmvc)使用指南 MVC 模式和 Spring MVC 介绍 MVC : 是一种用于设计创建web应用表现层的模式,主要作用是将视图展示和业务控制代码分离开来 MVC 使用了三种角色来分 素颜马尾好姑娘i/ 2023年09月23日 16:01/ 0 赞/ 75 阅读
相关 常见食谱大全 1:吃芋头相当于注射免疫球蛋白,增强人体的免疫功能。 2:枸杞子:嚼服枸杞口中津液长生,具有抗动脉硬化、降低血糖、促进肝细胞新生等作用,服之有增强体质、延缓衰老之功效。 3 左手的ㄟ右手/ 2022年09月11日 15:27/ 0 赞/ 134 阅读
相关 Spring MVC数据绑定大全 刚开始用spring mvc 做web开发时,经常会不知道如何合适绑定页面数据.用惯struts2的朋友更认为spring mvc 绑定数据不如struts2方便(本人最开始也 Love The Way You Lie/ 2022年08月25日 08:36/ 0 赞/ 148 阅读
相关 Spring MVC使用主题 Spring MVC通过使用一组静态资源(比如图像、样式等)提供了主题化支持。主题架构包含三个主要机制:支持主题的资源包、主题解析器和主题更改拦截器。 主题支持的资源包:是T 超、凢脫俗/ 2022年06月18日 02:09/ 0 赞/ 105 阅读
相关 spring mvc @ModelAttribute使用 @ModelAttribute 绑定请求参数到命令对象 @ModelAttribute一个具有如下三个作用: ①绑定请求参数到命令对象:放在功能处理方法的入参上时,用 不念不忘少年蓝@/ 2022年06月16日 05:40/ 0 赞/ 170 阅读
相关 Spring常见问题大全 Spring 概述 1. 什么是spring? Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2 末蓝、/ 2022年05月10日 02:36/ 0 赞/ 157 阅读
相关 Spring MVC数据绑定大全 spring mvc 提供了多种绑定数据的方式,先看一下springmvc的源码: org.springframework.beans.PropertyEditorRegis 绝地灬酷狼/ 2021年09月10日 11:38/ 0 赞/ 213 阅读
还没有评论,来说两句吧...