Spring Boot, problem z implementacja metody

0

Potrzebuje lekkiej pomocy, probuje zrobic apke w springboocie, gre slownikowa, cos na zasadzie fiszek.
Podaje slowo po ang, odpowiadam po polsku. tak na start.
Powstal mi problem natury technicznej. Poki co, stworzylem tak, by wyswietlalo odpowiedz w konsoli.
Slowko wyskakuje mi po strone htmla, wpisuje odpowiedz, ktora sprawdza program i wyrzuca mi do konsoli czy dobrze czy zle.
Wszystko dziala, problem pojawil sie w momencie, gdy postanowielm przerzucic cala instrukcje warunkowa do innej klasy, w celu stworzenia metody.
tak by, getMappingu bylo czysciej. Niezaleznie jak robie, zawsze wywala mi nullpointerexception. probowalem na wiele sposob to obejsc, rowniez z try catchem.
siedze przy tym juz pare godzin i po prostu przestaje myslec, nic mi do glowy nowego nie przychodzi a efekt dalej zerowy. Problem pewnie trywialny, no ale coz...
Proby powyrzucalem z kodu by nie wprowadzac zamieszania.
W skrocie, chce wyrzucic wszystko z getmappingu do innej klasy( w tym PWord, EWord, count) tam wykonac wszystkie warunki i wrocic jedynie z odnosnikiem do metody, wstawiajac do modelmapy. Prosilbym o nakierowanie/ pokazanie zapisu krok po kroku, mam wrazenie, ze jakis step pomijam i wychodzi bagno.

@Scope(value = "session")
@Controller
public class DictionaryController {

    private Random random = new Random();
    private User user = new User();

    private static String previousWord;

    @Autowired
    private LibraryRepository libraryRepository;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @GetMapping("/game")
    public String showEnglish(@RequestParam(required = false) String name, ModelMap modelMap) {

        long count = libraryRepository.count();
        int index = random.nextInt((int) count);

        String EWord = libraryRepository.findById(index).get().getEnglishWord();
        String PWord = libraryRepository.findById(index).get().getPolishWord();

        modelMap.put("englishW", EWord);
        modelMap.put("polishW", PWord);


        if (name != null) {

            if (previousWord.equals(name)) {
                System.out.println("dobrze");
            } else {
                System.out.println("zle");
            }
        }
        previousWord = PWord;
        return "game";
    }
}

0

Nie napisałeś w którym miejscu leci ten nullpointer, nie wiemy też jak wyglądają klasy które tu wołasz.
Ale...

private static String previousWord;

previousWord.equals(name)

A po drodzę nie widzę by ten previousWord był stworzony. Jest do niego przypisane PWord ale dopiero po wywołaniu equals, czyli w pierwszej iteracji to rzuci wyjątkiem.

Poza tym, masz w tym kodzie parę WTFów, nie wiem czy wyciąłeś za dużo czy po prostu tak to wygląda...

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

Pomijam fakt, że tego nigdzie nie używasz, ale w jakim celu masz to w kontrolerze?

 @Autowired
 private LibraryRepository libraryRepository;

wstrzykiwanie przez pole zamiast przez konstruktor

private User user = new User();

znów, tworzysz coś i nic z tym nie robisz

String EWord = libraryRepository.findById(index).get().getEnglishWord();

Optional pobrany przez get(), nie użyte ifPresent() albo chociaż isPresent()

Poza tym, logika "biznesowa" w kontrolerze? Nawet jak na taki mały projekt to IMO słaby pomysł.

0

previousWord jest stworzony na gorze jako static. w innym wypadku podmienia mi na kolejne wylosowane slowo. ( zakladamy, ze losowane slowo jest kluczem w mapie, my wpisujemy wartosc, tak by rownala sie wartosci z mapy przypisanej do klucza wyswietlanego). Co do tych kilku anomalii, ktorych nie uzywam, wyszedlem troche w przod z rzeczami, mam zamiar zliczac punkty itd, dlatego czesc rzeczy jest nieuzywana. Jestem osoba uczaca sie, wiec tez nie wykluczam bledow.
Co do libraryrepository. w repo mam podpietego hybernate z baza slow, nadawana w klasie library.

0

Co z tego że jest jako static? Nie jest nigdzie zainicjalizowany. Robiąc equalsa robisz null.equals("value") co rzuca nullpointerem.

0

akurat to wersja konsolowa, czyli dzialajaca

0

Po pierwsze primo

Jestem osoba uczaca sie, wiec tez nie wykluczam bledow.

Mam nadzieje że nie odbierasz tego jako atak, ja po prostu starałem się wyłapać błędy które widać w Twoim kodzie, wyciągnąć wnioski, poprawić kod i na przyszłość nie pisać w ten sposób.

Po drugie primo

akurat to wersja konsolowa, czyli dzialajaca

Mam rozumieć, że masz gdzieś kod który nie działa, ale wysłałeś nam do weryfikacji wersje która działa i pytasz gdzie jest błąd w Twoim niedziałającym kodzie?...

Po trzecie primo, ultimo
Static nie oznacza że zmienna się sama zainicjalizuje

title

0

racja, troche zamotalem sprawe.
podrzucam kod jeszcze raz :
To wersja nie dzialajaca, ta, ktora wrzucilem na poczatku postu, dzialala w konstoli, gdy chce stworzyc metode i wyrzucic instrukcje warunkowe z controllera, wtedy wywala mi nulla.
DictionaryController, chcialbym by wygladal plus minus tak, bez instrukcji warunkowej


@Scope(value = "session") 
@Controller
public class DictionaryController {

    private Random random = new Random();
    private User user = new User();

    private static String previousWord;

    @Autowired
    private LibraryRepository libraryRepository;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;


    @GetMapping("/game")
    public String showEnglish(@RequestParam(required = false) String name, ModelMap modelMap) {

        DictionaryService dictionaryService = new DictionaryService(name);

        modelMap.put("englishW", dictionaryService.getEWord());
        modelMap.put("polishW", dictionaryService.getPWord());
        modelMap.put("answer", dictionaryService.getMessage());


        return "game";
    }
}

tutaj jest klasa Service, w ktorej probuje stwrozyc metode losowania randomowej pary i ta metode wrzucic pozniej w DictionaryController


public class DictionaryService {

        private String name;
        private Random random = new Random();
        private static String previousWord;

        private LibraryRepository libraryRepository;

        long count = libraryRepository.count();
        int index = random.nextInt((int) count);

       private String EWord = libraryRepository.findById(index).get().getEnglishWord();
       private String PWord = libraryRepository.findById(index).get().getPolishWord();

    public void setEWord(String EWord) {
        this.EWord = EWord;
    }

    public void setPWord(String PWord) {
        this.PWord = PWord;
    }

    public String getEWord() {
            return EWord;
        }

        public String getPWord() {
            return PWord;
        }

        public DictionaryService(String name){
            this.name = name;

        }
        public String getName() {
            return this.name;

        }

        public  String getMessage() {

//        if (name != null) {

            if (PWord.equals(name)) {
                return "dobrze";
            } else {
                return "zle";
            }
        }


    }



tak wyglada moj kod po stronie html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Gra Słowna</title>
</head>
<body>
<h2>Podaj tłumaczenie słowa: </h2>
<form action="/game">  <!-- po wykonaniu akcji, wraca do result-->
    <p th:text="${englishW}"></p>

    <label>Przetłumacz</label>
    <!--<form action="/result">   -->
    <input type="text" name="name">
    <p th:text="${answer}"></p>

    <input type="submit" value="Sprawdz">

</form>
</body>
</html>

oraz libraryrepo, w ktorej jest adnotacja do pobierania wyrazow z bazy

        import org.springframework.data.jpa.repository.Query;
        import org.springframework.data.repository.CrudRepository;

        import java.util.List;

public interface LibraryRepository extends CrudRepository<Library, Integer> {

    @Query("SELECT l FROM Library l where l.polishWord=?1")
    List<Library> findByPolishWord(String polishWord);

    @Query("SELECT l FROM Library l where l.englishWord=?1")
    List<Library> findByEnglishWord(String englishWord);
}

0
private LibraryRepository libraryRepository;
private String EWord = libraryRepository.findById(index).get().getEnglishWord();

Obstawiam że tutaj jest problem. Repository nie jest wstrzyknięte do tego serwisu, a Ty i tak próbujesz już go użyć.
Poza tym, oczekujesz że name przyjdzie jako parametr w zapytaniu /game, ale w HTMLu nie przekazujesz już tego parametru.

0

Jak to ugryzc w takim razie? Jesli robie to konsolowo, troche zmieniajac kod tak by byl jak na poczatku postu. zapytanie idzie do htmla i zwraca, sprwdzajac po instrukcji warunkowej czy wszystko jest ok. sytuacja dziala bez klasy service, ktora wtedy nie jest potrzebna

0

Powinno wystarczyć, że do konstruktora DictionaryService dodasz parametr LibraryRepository

public DictionaryService(String name, LibraryRepository libraryRepository){
           this.name = name;
           this.libraryRepository = libraryRepository;
       }

i przekażesz instancję którą masz w DictionaryController tworząc ten serwis

 DictionaryService dictionaryService = new DictionaryService(name, libraryDictionary);

Ale generalnie przemyślałbym design tego wszystkiego, bo to trochę łatanie dziur w tonącym statku ;)

0

Tez rozwazalem tak jak ty piszesz, niestety dalej jest kaplica

1

Jak wspomniałem, używasz libraryRepository zanim go zanicjalizujesz.
IIRC, kolejność tworzenia obiektu przebiega tak:

  1. Zmienne statyczne
  2. super() w kosntruktorze
  3. zmienne klasowe
  4. reszta konstruktora

U Ciebie wygląda to tak

    private Random random = new Random();
    private static String previousWord;
    private LibraryRepository libraryRepository;
    
    long count = libraryRepository.count();
    
    public DictionaryService(String name, LibraryRepository libraryRepository) {
        this.name = name;
        this.libraryRepository = libraryRepository;
    }
  1. Zmienna statyczna previousWord - zostałaby zaincjalizowana jako pierwsza, jakbyś coś do niej przypisał, ale że tego nie zrobiłeś to jest nadal nullem.
  2. super() pomijamy bo go tutaj nie ma jawnie wpisanego
  3. Teraz następuje inicjalizacja zmiennych nie statycznych klasy, tworzony jest new Random(), ale nie przypisujesz nic do libraryRepository więć nie jest on tworzony, zostaje on == null;
    W następnej linicje jednak, próbujesz stworzyć zmienną count() która jest metodą nie utworzonego obiektu libraryRepository - tutaj leci pierwszy null pointer.
  4. Dopiero w tym momencie możesz korzystać z libraryRepository, bo dopiero teraz ta zmienna jest stworzona w konstruktorze.

Jeżeli potrzebujesz stworzyć zmienną na podstawie metody z libraryRepository musisz to zrobić PO zainicjalizowaniu libraryRepository wewnątrz swojej klasy.

0

dzieki ci za wszystkie skazowki :) problem rozwiazany. Tak jak pisales, duzo u mnie problemow z implementacja repository. dodatkowo jak sytuacje opanowalem, w bazie danych wartosci zaczynaly sie od 1, a w randomie liczylo od 0, wiec tu tez byl nullpointer, wiec rozwiazaniem bylo albo dodac+1 do indexu, albo zmienic recznie w bazie danych. Co do implementacji, poradzilem sobie za pomoca @Autowired. Postaram sie zrobic porzadek w kodzie miedzy innymi wedlug twoich instrukcji

1 użytkowników online, w tym zalogowanych: 0, gości: 1