英文:
Why can I run my app VSCode but not correctly in CLI?, its a spring boot application
问题
我正在使用Spring Boot构建一个Web应用程序。
开发环境是Gradle,我正在使用Visual Studio Code。
我正在使用Visual Studio Code的调试功能、Spring Boot仪表板,当我启动应用程序时,页面能正确显示,但当我将Web应用程序制作成jar文件并用java -jar
运行时,部分页面转换无法正常工作。
请告诉我如何使其正常工作以及出现了什么情况。
(我认为Spring Boot无法找到某些路径,但我不知道是什么路径,以及如何修复它。)
以下是我访问「localhost:8080/gallery」时所在的页面:
Whitewabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Sep 01 23:09:16 JST 2020
There was an unexpected error (type=Internal Server Error, status=500).
以下是我使用java -jar
访问特定图库页面时收到的错误:
2020-09-01 23:09:14.129 INFO 15464 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-09-01 23:09:14.143 INFO 15464 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 14 ms
Check image file path
2020-09-01 23:09:16.656 ERROR 15464 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
at com.example.sweepea.GetImage.getImage(GetImage.java:23) ~[classes!/:na]
at com.example.sweepea.swepeaController.getGallery(swepeaController.java:21) ~[classes!/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
控制器类中的方法如下。"index"和"about"可以正常工作:
@GetMapping("/index")
public String getIndex(){
return "index";
}
@GetMapping("/gallery")
public String getGallery(Model model){
List<String> imagePath = new GetImage().getImage(new File("src/main/resources/static/images"));
model.addAttribute("imagePath", imagePath);
return "gallery";
}
@GetMapping("/about")
public String getAbout(){
return "about";
}
GetImage类如下所示。它获取.jpg
图像,添加到列表并返回:
@Service
public class GetImage {
String month = "202009";
List<String> pathname = new ArrayList<String>();
List<String> getImage(File file){
File[] filelist = file.listFiles();
if(filelist == null){
System.out.println("Check image file path");
}
for (File tmpFile : filelist){
if(tmpFile.isDirectory()){
month = tmpFile.getName();
getImage(tmpFile);
}else{
String imagePath = "images/" + month + "/" + tmpFile.getName();
if(imagePath.substring(imagePath.length() - 3).equals("jpg")){
pathname.add(imagePath);
}
}
}
return pathname;
}
}
gallery.html文件如下所示:
<body>
<div id="content">
<header class="page_header wrapper">
<h1><a th:href="@{/index}"><img class="logo" th:src="@{images/logo.svg}" alt=""></a></h1>
<nav class="main_nav">
<ul>
<li><a th:href="@{/index}">TOP</a></li>
<li><a th:href="@{/gallery}">GALLERY</a></li>
<li><a th:href="@{/about}">ABOUT</a></li>
</ul>
</nav>
</header>
<main>
<div class="edition">
<p>sub title</p>
</div>
<h2 class="mounth">Gallery</h2>
<div class="grid item">
<a th:each="image : ${imagePath}" th:href="@{${image}}">
<img th:src="@{${image}}" alt="">
</a>
</div>
</main>
</div>
</body>
目录结构如下所示:
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── sweepea
│ │ ├── DemoApplication.java
│ │ ├── GetImage.java
│ │ └── swepeaController.java
│ └── resources
│ ├── application.properties
│ ├── static
│ │ ├── logo.svg
│ │ ├── images
│ │ │ ├── ... (各月份和图像文件)
│ │ └── style.css
│ └── templates
│ ├── about.html
│ ├── gallery.html
│ └── index.html
└── test
└── java
└── com
└── example
└── sweepea
└── DemoApplicationTests.java
英文:
I'm building a web application in spring boot.
The development environment is Gradle and I am using visual studio code.
I'm using visual studio code's debug function, spring boot dashboard, and when I start the application, the page is displayed correctly, but when I make the web application a jar file and run it with java -jar
, it doesn't work with some page transitions.
Please tell me what I should do to make it work and what is happening.
(I think that spring boot can't find the some path, but I don't know what is and how to fix it.)
Here's the page I was on when I accessed 「localhost:8080/gallery」
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Sep 01 23:09:16 JST 2020
There was an unexpected error (type=Internal Server Error, status=500).
The following is the error I get when I use java -jar to access a specific gallery page.
2020-09-01 23:09:14.129 INFO 15464 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-09-01 23:09:14.143 INFO 15464 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 14 ms
Check image file path
2020-09-01 23:09:16.656 ERROR 15464 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
at com.example.sweepea.GetImage.getImage(GetImage.java:23) ~[classes!/:na]
at com.example.sweepea.swepeaController.getGallery(swepeaController.java:21) ~[classes!/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
The methods in the controller class are as follows. 「index」and「about」is work.
@GetMapping("/index")
public String getIndex(){
return "index";
}
@GetMapping("/gallery")
public String getGallery(Model model){
List<String> imagePath = new GetImage().getImage(new File("src/main/resources/static/images"));
model.addAttribute("imagePath", imagePath);
return "gallery";
}
@GetMapping("/about")
public String getAbout(){
return "about";
}
}
GetImage class are as follw.
It is get .jpg
images , add List and return.
@Service
public class GetImage {
String month = "202009";
List<String> pathname = new ArrayList<String>();
List<String> getImage(File file){
File[] filelist = file.listFiles();
if(filelist == null){
System.out.println("Check image file path");
}
for (File tmpFile : filelist){
if(tmpFile.isDirectory()){
month = tmpFile.getName();
//System.out.println(month);
//pathname.add(month);
getImage(tmpFile);
}else{
String imagePath = "images/" + month + "/" + tmpFile.getName();
if(imagePath.substring(imagePath.length() - 3).equals("jpg")){
pathname.add(imagePath);
//System.out.println(imagePath);
}
}
}
return pathname;
}
}
gallery.html
<body>
<div id="content">
<header class="page_header wrapper" >
<h1><a th:href="@{'/index'}"><img class="logo" th:src="@{images/logo.svg}" alt=""></a></h1>
<nav class="main_nav">
<ul>
<ii><a th:href="@{'/index'}">TOP</a></ii>
<ii><a th:href="@{'/gallery'}">GALLERY</a></ii>
<ii><a th:href="@{'/about'}">ABOUT</a></ii>
</ul>
</nav>
</header>
<main>
<div class="edition">
<p>sub title</p>
</div>
<h2 class="mounth">Gallery</h2>
<div class="grid item">
<a th:each="image : ${imagePath}" th:href="@{${image}}"><img th:src="@{${image}}" alt=""></a>
</div>
</main>
</body>
source tree is like that
└── src
├── main
│   ├── java
│   │   └── com
│   │   └── example
│   │   └── sweepea
│   │   ├── DemoApplication.java
│   │   ├── GetImage.java
│   │   ├── Test.java
│   │   └── swepeaController.java
│   └── resources
│   ├── application.properties
│   ├── static
│   │   ├── logo.svg
│   │   ├── images
│   │   │   ├── 201910
│   │   │   │   ├── 1.jpg
│   │   │   ├── 201911
│   │   │   ├── 201912
│   │   │   │   ├── 1.jpg
│   │   │   ├── 202001
│   │   │   ├── 202002
│   │   │   │   ├── 1.jpg
│   │   │   ├── 202003
│   │   │   │   ├── 1.jpg
│   │   │   ├── 202004
│   │   │   │   ├── 1.jpg
│   │   │   ├── 202005
│   │   │   │   ├── 1.jpg
│   │   │   ├── 202006
│   │   │   ├── 202007
│   │   │   ├── 202008
│   │   │   │   ├── 1.jpg
│   │   │   ├── 202009
│   │   │   ├── logo.svg
│   │   │   └── logo_favicon.png
│   │   └── style.css
│   └── templates
│   ├── about.html
│   ├── gallery.html
│   ├── index.html
│   └── video.html
└── test
└── java
└── com
└── example
└── sweepea
└── DemoApplicationTests.java
答案1
得分: 3
这一行代码:
List<String> imagePath = new GetImage().getImage(new File("src/main/resources/static/images"));
存在问题。资源应该始终从Jar文件内部读取,而不是通过指定路径来读取,无论是绝对路径还是相对于您从中运行应用程序的任何目录的路径。
这篇文章展示了如何正确地从资源文件夹中读取文件。
英文:
This line:
List<String> imagePath = new GetImage().getImage(new File("src/main/resources/static/images"));
is the problem. The resources should always be read from within the Jar file, not by specifying path, either an absolute one or relative to whatever directory your run your app from.
This article shows how to properly read file from the resources folder.
答案2
得分: 1
如果你将应用程序打包成一个jar文件,它就不再依赖于源代码。
如果你在另一个文件夹或另一台服务器中使用 java -jar ...
来启动应用程序,那么 new File("src/main/resources/static/images")
将不再起作用。
我认为当你在项目的根文件夹中执行 java -jar ...
时,它可能会起作用,但这可能不是一个长期的解决方案。
Maven将 src/main/resources
文件夹视为需要包含在jar中的文件的输入文件夹,因此在打包后,这些文件将可以通过 getClass().getResource("/static/images/202008/1.jpg")
从Java中访问,这就是它们在Spring Boot中的提供方式(使用ResourceHttpRequestHandler,在没有 static/
前缀的情况下)。
如果你想在以后添加图片而又不必重新构建和重新打包应用程序,最好使用绝对服务器路径,比如 C:\gallery\images
或者 /opt/gallery/images
。
英文:
If you package you application in a jar, it's no longer dependent on the source code.
If you start your application using java -jar ...
in another folder or on another server, then new File("src/main/resources/static/images")
will no longer work.
I think it will work when you execute java -jar ...
in the root folder of your project, but that's probably not a long-term solution.
Maven considers the src/main/resources
folder as an input folder for files that need to be included in the jar, so after packaging, those files will be available from java as getClass().getResource("/static/images/202008/1.jpg")
, and that's how they will be served in Spring Boot (using the ResourceHttpRequestHandler, without the static/
prefix).
If you want to add images later without having to rebuild and repackage your application, it's better to use an absolute server path like "C:\gallery\images"
or "/opt/gallery/images"
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论