Odczytaj plik z folderu zasobów w Spring Boot

89

Używam Spring Boot i json-schema-validator. Próbuję odczytać plik o nazwie jsonschema.jsonz resourcesfolderu. Próbowałem na kilka różnych sposobów, ale nie mogę zmusić go do pracy. To jest mój kod.

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("jsonschema.json").getFile());
JsonNode mySchema = JsonLoader.fromFile(file);

To jest lokalizacja pliku.

wprowadź opis obrazu tutaj

I tutaj widzę plik w classesfolderze.

wprowadź opis obrazu tutaj

Ale kiedy uruchamiam kod, pojawia się następujący błąd.

jsonSchemaValidator error: java.io.FileNotFoundException: /home/user/Dev/Java/Java%20Programs/SystemRoutines/target/classes/jsonschema.json (No such file or directory)

Co robię źle w swoim kodzie?

g3blv
źródło
Możesz tego spróbować? ClassLoader classLoader = getClass().getClassLoader(); JsonNode mySchema = JsonLoader.getJson(classLoader.getResourceAsStream("jsonschema.json"));
harshavmb

Odpowiedzi:

92

Po spędzeniu dużo czasu na próbie rozwiązania tego problemu w końcu znalazłem rozwiązanie, które działa. Rozwiązanie wykorzystuje ResourceUtils Springa. Powinien działać również dla plików JSON.

Dzięki za dobrze napisaną stronę przez Lokesh Gupta: Blog

wprowadź opis obrazu tutaj

package utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ResourceUtils;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.io.File;


public class Utils {

    private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class.getName());

    public static Properties fetchProperties(){
        Properties properties = new Properties();
        try {
            File file = ResourceUtils.getFile("classpath:application.properties");
            InputStream in = new FileInputStream(file);
            properties.load(in);
        } catch (IOException e) {
            LOGGER.error(e.getMessage());
        }
        return properties;
    }
}

Aby odpowiedzieć na kilka wątpliwości dotyczących komentarzy:

Jestem prawie pewien, że miałem to uruchomione na Amazon EC2 przy użyciu java -jar target/image-service-slave-1.0-SNAPSHOT.jar

Spójrz na moje repozytorium github: https://github.com/johnsanthosh/image-service, aby znaleźć właściwy sposób uruchomienia tego z JAR.

Jan
źródło
1
Dzięki John za dodanie tego. To działa i na pewno jest lepszym podejściem przy użyciu ResourceUtil.
Athar
1
@Athar Cieszę się, że mogłem pomóc.
Jan
39
To zadziała tylko wtedy, gdy spróbujesz uruchomić aplikację z IDE, ale po uruchomieniu jar nie znajdzie pliku za Ciebie.
Hassan Mudassir
11
Zgadzam się z Hassanem, zamiast tego powinniśmy użyć new ClassPathResource("filename").getInputStream()jeśli uruchamiamy aplikację z jar. Szczegół
Jingchao Luan
2
Zgadzam się z Hassanem. Jako ostrzeżenie, ResourceUtils Javadoc jasno określa, że ​​klasa jest przeznaczona głównie do użytku wewnętrznego. Sprawdź jak dobrze stackoverflow.com/questions/25869428/...
Eric Jiang
36

Bardzo krótka odpowiedź: szukasz swojej nieruchomości w zakresie konkretnej klasy ładującej zamiast klasy docelowej. To powinno działać:

File file = new File(getClass().getResource("jsonschema.json").getFile());
JsonNode mySchema = JsonLoader.fromFile(file);

Zobacz też:

PS Może wystąpić problem, jeśli projekt został skompilowany na jednym komputerze, a następnie został uruchomiony na innym, lub jeśli uruchomisz aplikację w Dockerze. W takim przypadku ścieżki do folderu zasobów mogą być nieprawidłowe. W takim przypadku lepiej byłoby określić ścieżki do zasobów w czasie wykonywania:

ClassPathResource res = new ClassPathResource("jsonschema.json");    
File file = new File(res.getPath());
JsonNode mySchema = JsonLoader.fromFile(file);

Aktualizacja z 2020 r

Ponadto, jeśli chcesz na przykład odczytać plik zasobów jako ciąg znaków w swoich testach, możesz użyć tych statycznych metod narzędzi:

public static String getResourceFileAsString(String fileName) {
    InputStream is = getResourceFileAsInputStream(fileName);
    if (is != null) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        return (String)reader.lines().collect(Collectors.joining(System.lineSeparator()));
    } else {
        throw new RuntimeException("resource not found");
    }
}

public static InputStream getResourceFileAsInputStream(String fileName) {
    ClassLoader classLoader = {CurrentClass}.class.getClassLoader();
    return classLoader.getResourceAsStream(fileName);
}

Przykład użycia:

String soapXML = getResourceFileAsString("some_folder_in_resources/SOPA_request.xml");
Serhii Povisenko
źródło
2
getClass().getResource("jsonschema.json")zwraca null. Próbowałem też, ClassPathResource res = new ClassPathResource("jsonschema.json")który właśnie wraca jsonschema.json. Czy ma to coś wspólnego z tym, że używam Spring Boot?
g3blv,
@ g3blv odnośnie getClass().getResource("jsonschema.json")zwrotów nullmogę odnieść się do tego tematu stackoverflow.com/questions/26328040/… . Oprócz tego spróbuj odbudować swój projekt. Będziemy wdzięczni za opinie.
Serhii Povisenko
@ g3blv Udostępniłem aktualizację odpowiedzi, sprawdź
Serhii Povisenko,
1
@povisenko Proponuję zgłosić wyjątek, jeśli jest ispusty. Oznacza to, że nie ma tam pliku / zasobu, którego szukasz.
endertunc
pełna odpowiedź. Działa zarówno w IDE, jak i dla słoika. Dzięki.
Digao
24

jeśli masz na przykład folder config w folderze Resources, próbowałem tej klasy działającej doskonale, mam nadzieję, że będzie przydatna

File file = ResourceUtils.getFile("classpath:config/sample.txt")

//Read File Content
String content = new String(Files.readAllBytes(file.toPath()));
System.out.println(content);
Ismail
źródło
3
Wypróbowałem twoje rozwiązanie, działa w IDE, ale kiedy utworzysz strumień wejściowy słoika sprężynowego, pomoże.
Ameya
13

Spędziłem zbyt dużo czasu, wracając do tej strony, więc zostaw to tutaj:

File file = new ClassPathResource("data/data.json").getFile();
Emmanuel Osimosu
źródło
7

Zobacz moją odpowiedź tutaj: https://stackoverflow.com/a/56854431/4453282

import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

Użyj tych 2 importów.

Ogłosić

@Autowired
ResourceLoader resourceLoader;

Użyj tego w jakiejś funkcji

Resource resource=resourceLoader.getResource("classpath:preferences.json");

W twoim przypadku, ponieważ potrzebujesz pliku, którego możesz użyć poniżej

File file = resource.getFile()

Źródła : http://frugalisminds.com/spring/load-file-classpath-spring-boot/ Jak już wspomniano w poprzednich odpowiedziach, nie używaj ResourceUtils, to nie działa po wdrożeniu JAR, zadziała również w IDE jak po wdrożeniu

sajal rajabhoj
źródło
To nie zadziała z JAR
Abhishek
5

utwórz folder json w zasobach jako podfolder, a następnie dodaj plik json w folderze, a następnie możesz użyć tego kodu: wprowadź opis obrazu tutaj

import com.fasterxml.jackson.core.type.TypeReference;

InputStream is = TypeReference.class.getResourceAsStream("/json/fcmgoogletoken.json");

to działa w Dockerze.

MostafaMashayekhi
źródło
3

utknąłem w tym samym problemie, to mi pomaga

URL resource = getClass().getClassLoader().getResource("jsonschema.json");
JsonNode jsonNode = JsonLoader.fromURL(resource);
Govind Singh
źródło
w rzeczywistości jest to prawie to samo, co udzielona odpowiedź, aby uzyskać więcej informacji, patrz tutaj stackoverflow.com/questions/14739550/…
Serhii Povisenko
2

Oto moje rozwiązanie. Może komuś pomóc;

Zwraca InputStream, ale zakładam, że możesz też z niego czytać.

InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("jsonschema.json");
Erçin Akçay
źródło
1

Poniżej znajduje się mój działający kod.

List<sampleObject> list = new ArrayList<>();
File file = new ClassPathResource("json/test.json").getFile();
ObjectMapper objectMapper = new ObjectMapper();
sampleObject = Arrays.asList(objectMapper.readValue(file, sampleObject[].class));

Mam nadzieję, że to pomoże!

Bhaumik Thakkar
źródło
1

U mnie błąd miał dwie poprawki.

  1. XML, który został nazwany SAMPLE.XML, który powodował, że nawet poniższe rozwiązanie nie działało po wdrożeniu w aws ec2. Poprawka polegała na zmianie nazwy na new_sample.xml i zastosowaniu rozwiązania podanego poniżej.
  2. Podejście do rozwiązania https://medium.com/@jonathan.henrique.smtp/reading-files-in-resource-path-from-jar-artifact-459ce00d2130

Używałem Spring boot jako jar i wdrożyłem do aws ec2 Java wariant rozwiązania jest następujący:

package com.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;


public class XmlReader {

    private static Logger LOGGER = LoggerFactory.getLogger(XmlReader.class);

  public static void main(String[] args) {


      String fileLocation = "classpath:cbs_response.xml";
      String reponseXML = null;
      try (ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext()){

        Resource resource = appContext.getResource(fileLocation);
        if (resource.isReadable()) {
          BufferedReader reader =
              new BufferedReader(new InputStreamReader(resource.getInputStream()));
          Stream<String> lines = reader.lines();
          reponseXML = lines.collect(Collectors.joining("\n"));

        }      
      } catch (IOException e) {
        LOGGER.error(e.getMessage(), e);
      }
  }
}
Vijayakumar S
źródło
0

Najprostszą metodą przeniesienia zasobu ze ścieżki klasy w przeanalizowanym katalogu zasobów do postaci ciągu znaków jest następujący wiersz.

Jako ciąg (przy użyciu bibliotek Spring):

         String resource = StreamUtils.copyToString(
                new ClassPathResource("resource.json").getInputStream(), defaultCharset());

Ta metoda używa narzędzia StreamUtils i przesyła strumieniowo plik jako strumień wejściowy do ciągu w zwięzły sposób.

Jeśli chcesz, aby plik był tablicą bajtów, możesz użyć podstawowych bibliotek we / wy Java File:

Jako tablica bajtów (przy użyciu bibliotek Java):

byte[] resource = Files.readAllBytes(Paths.get("/src/test/resources/resource.json"));
anataliocs
źródło
0

Myślę, że problem leży w miejscu w nazwie folderu, w którym znajduje się twój projekt. /home/user/Dev/Java/Java%20Programs/SystemRoutines/target/classes/jsonschema.json

jest spacja między programami Java. Zmiana nazwy folderu powinna sprawić, że zadziała

sam
źródło