• 解决SpringBoot 中Controller层加入RequestMapping导致HTML页面的静态文件路径变化问题


    关键词:[SpringBoot] [RequestMapping] [文件路径]

    在这里插入图片描述

    一、问题出现

    @Controller
    @RequestMapping("/goods")
    public class GoodsController {
        @Autowired
        UserServiceImpl userService;
        @Autowired
        IGoodsService goodsService;
        /**
         * 跳转到商品列表页
         *
         * @return
         */
        @RequestMapping("/toList")
        public String toList(User user, Model model) {
            if (user == null) {
                return "login";
            }
            model.addAttribute("user", user);
            model.addAttribute("goodsList", goodsService.findGoodVo());
            return "goodsList";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    二、初步思考

    1)如代码:控制层加了@RequestMapping("/goods")后,访问 goodsImg 的路径奇怪的变成了 http://localhost:8080/goods/img/iphone12.png,且加载不出,而我直接在地址栏输入 http://localhost:8080/img/iphone12.png却能够访问;

    2)再加上,检查->网络 这里面所有的当前页面静态文件都是 http://localhost:8080/static目录下的子目录/xxx的形式,没有一个像 ihpone12.png 一样在路径中出现 /goods
    在这里插入图片描述
    3)我就觉得是不是路径中这个 /goods导致了这个错误;

    三、逐个细化

    3.1 target 文件

    • target 文件夹是用来存放项目构建后的文件和目录、jar包、war包、编译的class文件,都是maven构建时生成的;
    • 在idea的spring boot项目中,如果target目录中没有同步更新目录文件和资源就会报错;

    然而我的项目中,多次运行包括删除target文件再运行,都是含有 img 文件的
    在这里插入图片描述
    所以肯定不是 target 文件的问题,即我的 图片 已经完成了资源构建,但是我的访问地址有问题,导致访问不到它;

    3.2 @RequestMapping

    本质上 RequestMapping 是起到请求映射的作用,将对应的 url (也就是 RequestMapping 的 value 值)放行,经过一顿处理,映射到某一页面(return 值);
    那么:

    1. 在方法上加 RequestMapping 注解便是直接拦截这个 url;
    2. 在类上加 RequestMapping 注解便是在这个类的所有方法之前加上这层路径;

    比如这个代码:

    @Controller
    @RequestMapping("/goods")
    public class GoodsController {
        @Autowired
        UserServiceImpl userService;
        @Autowired
        IGoodsService goodsService;
        /**
         * 跳转到商品列表页
         *
         * @return
         */
        @RequestMapping("/toList")
        public String toList(User user, Model model) {
            if (user == null) {
                return "login";
            }
            model.addAttribute("user", user);
            model.addAttribute("goodsList", goodsService.findGoodVo());
            return "goodsList";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 如果我访问http://localhost:8080/goods/toList时就会被放行,进入到 toList 方法中,一顿处理,映射到 goodsList 页面;
    • 如果没加 @RequestMapping("/goods")在类上,我访问http://localhost:8080/toList就进入到 toList 方法中,然后映射到 goodsList 页面;

    这么一来我能理解为什么 img/iphone12.png前面会加一个 /goods,但为什么其他所有的静态文件确没加/goods?这更加让我确信是 /goods 让我无法访问 已有的 img 中的图片;

    3.3 Spring 与 Themeleaf 相对路径绝对路径

    再来看一下 我 WebMvcConfigurer

        /**
         * 保证静态资源能够被访问
         * @param registry
         */
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    我已经将 所有对静态资源访问的路径(/**)都映射为 /static/了,那无论是 http://localhost:8080/goods/img/iphone12.png 还是 http://localhost:8080/img/iphone12.png 应该都是去访问 static 文件夹下的东西;

    https://blog.csdn.net/CatAndBeer/article/details/108460781 这篇文章指出是 页面中 相对路径的原因导致 RequestMapping 在资源上面多加了一层目录,页面中使用绝对路径即可;

    但实际上我页面中都用的绝对路径

    DOCTYPE HTML>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>商品列表title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        
        <script type="text/javascript" th:src="@{/js/jquery.min.js}">script>
        
        <link rel="stylesheet" type="text/css" th:href="@{/bootstrap/css/bootstrap.min.css}"/>
        <script type="text/javascript" th:src="@{/bootstrap/js/bootstrap.min.js}">script>
        
        <script type="text/javascript" th:src="@{/jquery-validation/jquery.validate.min.js}">script>
        <script type="text/javascript" th:src="@{/jquery-validation/localization/messages_zh.min.js}">script>
        
        <script type="text/javascript" th:src="@{/layer/layer.js}">script>
        
        <script type="text/javascript" th:src="@{/js/md5.min.js}">script>
        
        <script type="text/javascript" th:src="@{/js/common.js}">script>
    head>
    <body>
    <div class="panel panel-default" style="height:100%;background-color:rgba(222,222,222,0.8)">
        <div class="panel-heading">秒杀商品列表div>
        <table class="table" id="goodslist">
            <tr>
                <td>商品名称td>
                <td>商品图片td>
                <td>商品原价td>
                <td>秒杀价td>
                <td>库存数量td>
                <td>详情td>
            tr>
            <tr th:each="goods,goodsStat : ${goodsList}">
                <td th:text="${goods.goodsName}">td>
                <td><img th:src="@{${goods.goodsImg}}" width="100" height="100"/>td>
                <td th:text="${goods.goodsPrice}">td>
                <td th:text="${goods.seckillPrice}">td>
                <td th:text="${goods.stockCount}">td>
                <td><a th:href="'/goods/toDetail/'+${goods.id}">详情a>td>
            tr>
        table>
    div>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    th:src="@{xxx路径}" 表示在 xxx路径 前加上上下文路径,那不就是绝对路径么;

    3.4 关于 配置类 和 约定的配置

    • @EnableWebMvc 默认会将这里配置类 覆盖 MVC事先约定的配置;
    • SpringBoot 中 MVC 约定的配置就是 /**,但这里我们有了配置类,覆盖约定的配置 @EnableWebMvc 就是启动你这个配置类;
      在这里插入图片描述

    所以,这里要么不加 @EnableWebMvc,让 SpringBoot 用自己的 MVC 配置,要么就是加上 @EnableWebMvc,然后在类里面把这个静态资源映射也给写上;
    在这里插入图片描述
    但这两个不是我问题所在,因为我 target 文件中已有 img文件夹和两张图片,所以必然不是这里的问题

    四、一个尝试

    其实,通过第三部分,我确定是 路径的 /goods导致的问题,而其他静态资源不受影响,就 img 受影响,那我就把注意力放在 页面上的路径,其实是可以发现:
    在这里插入图片描述
    这两个红框地方,唯一的区别就是在 上下文路径后有没有一个 /,所以我进行尝试:

            <tr th:each="goods,goodsStat : ${goodsList}">
                <td th:text="${goods.goodsName}">td>
                <td><img th:src="@{${'/'+goods.goodsImg}}" width="100" height="100"/>td>
                <td th:text="${goods.goodsPrice}">td>
                <td th:text="${goods.seckillPrice}">td>
                <td th:text="${goods.stockCount}">td>
                <td><a th:href="'/goods/toDetail/'+${goods.id}">详情a>td>
            tr>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    加上了斜杠 /,emmm
    在这里插入图片描述
    然后就恢复正常了????
    这说明https://blog.csdn.net/CatAndBeer/article/details/108460781 该文章说的没错,的确是绝对路径的原因,我一开始疏忽大意,但是 加上 / 和 不加 / 为什么会让两个路径完全不同:

    • 加上 / ,我的图片路径:http://localhost:8080/img/iphone12.png
    • 不加 /,我的图片路径:http://localhost:8080/goods/img/iphone12.png

    我很想知道其中的原因😭😭😭

    五、深入思考—html页面中相对路径

    html页面中相对路径有两种:

    1. /test/page1,这是相对于服务器根路径而言的,以之前的例子为例,使用结果就是直接从8080以后开始替换,如http://localhost:8080/test/page1

    2. test/page2,这是相对于当前路径而言的,比如当前路径为http://localhost:8080/test/page1,那么替换以后就是

    绝对路径:

    绝对路径就是直接http://localhost:8080/test/page1,十分简单,但是也相当于写死了

    http://localhost:8080/test/test/page,在这种情况下也有对应的语法,../表示上级目录,./表示当前目录,如test/page2就相当于./test/page2,如果写成../test/page2,那么替换后的路径就是http://localhost:8080/test/page了;

    这么一想就清楚了:

    • 我不加/,表示相对当前路径,即当前 url + /img/iphone12.png = http://localhost:8080/goods/img/iphone12.png
    • 我加上/,表示相对服务器根路径,http://localhost:8080/img/iphone12.png,这样的话,经过 MVC 配置的静态资源映射就直接变成了 http://localhost:8080/static/img/iphone12.png

    所以,这实际上跟 Themeleaf 并没有多大关系,因为去掉 @{},只要加上 /,我依旧可以访问静态资源:

      <tr th:each="goods,goodsStat : ${goodsList}">
            <td th:text="${goods.goodsName}"></td>
            <td><img th:src="${'/'+goods.goodsImg}" width="100" height="100"/></td>
            <td th:text="${goods.goodsPrice}"></td>
            <td th:text="${goods.seckillPrice}"></td>
            <td th:text="${goods.stockCount}"></td>
            <td><a th:href="'/goods/toDetail/'+${goods.id}">详情</a></td>
        </tr>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    但为什么 http://localhost:8080/goods/img/iphone12.png就不能匹配 /**映射到 /static/呢?难道是认为他不是获取静态资源?

    貌似是的,因为成功时 如下显示:
    在这里插入图片描述
    失败时:
    在这里插入图片描述
    失败时,路径为 http://localhost:8080/goods/img/iphone12.png,我认为 这意味着它发出一个非获取静态资源的请求给 SpringBoot,SpringBoot 去找 Controller,没找到,所以这个响应不了;

    所以,我标题是起错了嘛 😂,是HTML相对路径的问题,就当是顺便普及知识;

    六、注意点

    • 问题的解决在于 HTML 页面的相对路径,细节没把握好;
    • 项目Debug时,最好关闭 浏览器的 缓存,否则可能导致非正确方法解决问题的情况;
      在这里插入图片描述

    参考文章

  • 相关阅读:
    对话安谋科技周华:编解码硬件的机遇与挑战
    开源数据库postgresql在统信系统上的离线安装shell脚本
    web前端期末大作业 基于HTML+CSS+JavaScript绿色的在线教育平台网站响应式企业网站模板
    数据分析之Tebleau可视化:树状图、日历图、气泡图
    Java学习笔记 --- 泛型
    Koreographer Professional Edition丨一款Unity音游插件教程
    CentOS 7 安装 docker-compose
    springboot视图渲染技术
    牛客网刷题-(4)
    【从零开始游戏开发】Unity 前后端网络通信该如何搭建?注释解答 | 全面总结 |建议收藏
  • 原文地址:https://blog.csdn.net/wyll19980812/article/details/126452586