文章目录
一、问题出现
@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)如代码:控制层加了@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 值);
 那么:
- 在方法上加 RequestMapping 注解便是直接拦截这个 url;
 - 在类上加 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";
    }
}
 
- 如果我访问
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/");
    }
 
我已经将 所有对静态资源访问的路径(/**)都映射为 /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"/>
    <!-- jquery -->
    <script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
    <!-- bootstrap -->
    <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>
    <!-- jquery-validator -->
    <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>
    <!-- layer -->
    <script type="text/javascript" th:src="@{/layer/layer.js}"></script>
    <!-- md5.js -->
    <script type="text/javascript" th:src="@{/js/md5.min.js}"></script>
    <!-- common.js -->
    <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>
 
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>
 
加上了斜杠 /,emmm
 
 然后就恢复正常了????
 这说明https://blog.csdn.net/CatAndBeer/article/details/108460781 该文章说的没错,的确是绝对路径的原因,我一开始疏忽大意,但是 加上 / 和 不加 / 为什么会让两个路径完全不同:
- 加上 
/,我的图片路径:http://localhost:8080/img/iphone12.png; - 不加 
/,我的图片路径:http://localhost:8080/goods/img/iphone12.png 
我很想知道其中的原因😭😭😭
五、深入思考—html页面中相对路径
html页面中相对路径有两种:
-  
/test/page1,这是相对于服务器根路径而言的,以之前的例子为例,使用结果就是直接从8080以后开始替换,如http://localhost:8080/test/page1 -  
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>
 

貌似是的,因为成功时 如下显示:
 
 失败时:
 
 失败时,路径为 http://localhost:8080/goods/img/iphone12.png,我认为 这意味着它发出一个非获取静态资源的请求给 SpringBoot,SpringBoot 去找 Controller,没找到,所以这个响应不了;
所以,我标题是起错了嘛 😂,是HTML相对路径的问题,就当是顺便普及知识;
六、注意点
- 问题的解决在于 HTML 页面的相对路径,细节没把握好;
 - 项目Debug时,最好关闭 浏览器的 缓存,否则可能导致非正确方法解决问题的情况;

 
参考文章
- https://blog.csdn.net/CatAndBeer/article/details/108460781
 - https://blog.csdn.net/qq_40059532/article/details/104155358
 - https://blog.csdn.net/xia4820723/article/details/49659263
 - https://blog.csdn.net/qq_35603331/article/details/76255125
 










