Moj pierwszy CRUD

0

Cześć,
Ostatnio pytałem w tym temacie Zmiana trybu studiów na zaoczne do pracy(bez doświadczenia) co zrobić żeby jakoś wykazać się umiejętnościami. Zacząłem więc pisać swoją pierwszą większą aplikację chciałbym zapytać czy idę w dobrym kierunku, co mógłbym poprawić itp.

Aplikacja w internecie: http://goo.gl/LHCVkZ
Kod na Githubie: https://github.com/MiloszFilimowski/sknera

W sumie to tak myślę, że nikomu się nie będzie chciało rejestrować to może opiszę co zrobiłem do tej pory:

Możliwość rejestracji i logowania , Relacyjna Baza danych ,Dodawanie produktów do panelu użytkownika, Słaby front-end (nie znam się na tym kompletnie wiem że leży...)

Użyłem w projekcie Springa i JPA. Gdyby komuś chciało się zajrzeć na Githuba i coś doradzić to byłbym bardzo wdzięczny :)

3
  1. Skomitowałeś targeta do repo :D i .settings i różne inne cuda na kiju. Do repo wrzuca się KOD czyli u ciebie pom.xml + /src/main (i ewentualnie gitignore).
  2. Java 1.6 :( starszej nie było? Spring 3, to samo.
  3. Wyciągnij sobie też wersje frameworka do property w pomie, bo potem będziesz miał problem jak gdzieś ci się wersja nie zgodzi. Co zresztą ma u ciebie miejsce i chyba tylko cudem to sie w ogóle składa. Widocznie akurat nie było pomiędzy tymi wersjami żadnej dużej zmiany. Jak używasz np. Springa to wszystkie komponenty powinny być w tej samej wersji!
  4. MySQL :(
  5. Słabo mi. Wrzucasz do repo login i hasło na swojego AmazonWS? To jest jakiś social experiment ile czasu potrzeba żeby cię ktoś shackował? I pamiętaj że repo na historie commitów więc teraz to musisz dropnąć to repo albo zmienić hasła...
  6. ISO-8859-1 :(
  7. Transakcje na poziomie DAO :( edit: no tak, nie masz tam w ogóle warstwy logiki to pewnie nie było gdzie tego dać.
  8. Same Native Query zamiast Criteria (type safe!) albo JPQL.
  9. Klepane identyczne DAO zamiast użyc Spring Data albo chociaż jakiegoś GenericDao. Przecież jakieś insert, remove, find... są zawsze takie same...
  10. @Autowired zamiast @Inject
    Tyle na pierwszy rzut oka. Nie wczytywałem sie w kod.

Popatrz może np. na to: https://github.com/Pharisaeus/SpringScaffoldApplication (nie ma tam Spring Security ani Spring Data bom leniwy, ale jak ktoś sie nudzi to może dopisać o zrobić pull request!)

1

1.
https://github.com/MiloszFili[...]filimowski/dao/PersonDAO.java

wywal z metod dodaj na klasie, DRY

@Repository
@Transactional
public class PersonDAO {

    @PersistenceContext
    EntityManager entityManager;

2.

    @Transactional
    public void assignProduct(Long personId, Long productId) {
        Query query = entityManager.createNativeQuery("insert into expenses (id_person,id_product) values(?1,?2)")
                .setParameter(1, personId).setParameter(2, productId);
        query.executeUpdate();
    }

mondre ksionsszki mówią że "Named queries are a powerful tool for organizing query definitions and improving application performance. "
"Pro JPA 2 Mastering the Java Persistence API" znajdziesz pdf;a

3.

        Query query = entityManager.createNativeQuery("SELECT * FROM person where email = \"" + email + "\"",
                Person.class);

sry ?

  1. https://github.com/MiloszFili[...]om/filimowski/dao/Person.java
    po co to ?

  2. https://github.com/MiloszFili[...]ilimowski/dao/ProductDAO.java
    dlaczego EntityManager entityManager; ma default scopa ? powinno być private

    @Transactional
    public List<Product> getProductList(Long personID) {
        List<Product> productList;
        Query query = entityManager.createNativeQuery(
                "select * from products inner join expenses on expenses.id_product=products.id where expenses.id_person="
                        + personID.toString(),Product.class);
        productList = query.getResultList();
        System.out.println(productList);
        return productList;

    }

ten productList powinien być definiowany od razu przy użyciu, nie możesz definiować "na potem" , Effective java This is Item 45

7.

    System.out.println(productList);

poczytaj o loggerach

8.
https://github.com/MiloszFili[...]/src/main/java/com/filimowski
jak już masz package to używaj wszędzie, zrób sobie package na dto, na modele

9.
Tu jest fajniej :D

    if (!result.hasErrors() && request.getMethod().equalsIgnoreCase("post")) {

            Person person = new Person();
            person.setName(form.getName());
            person.setEmail(form.getEmail());
            person.setPassword(form.getPassword());
            person.setRole("ROLE_USER");
            person.setEnabled(true);
            personDAO.addPerson(person);
            return "redirect:/login?register=1";
        } else {
            return "form";
        }

ta validacja, tworzenie person powinno iść do jakiegoś serwisu, wgl ... btw dlaczego w metodzie która odbiera GET'a sprawdzasz czy request jest postem ? to się nigdy nie stanie ?? o.0 ?

ta metoda powinna wyglądać mniej wiecej tak

@RequestMapping(value = "/form", method=POST) // to nie zadziala, poszukaj jak sie definiuje posta W SPRING MVC
    public String obsluzFormularz(HttpServletRequest request, @ModelAttribute("form") @Valid FormularzDTO form,
            BindingResult result) {
        userService.saveUser(form); // i to moze wywalic wyjatek jakby cos poszlo nie tak, wyjatek tez moze przechowywać stan tego obiektu
              return "widok";
    }

a wyjątek który wyrzuci może być łapany przez advice controller, jak np:

@ControllerAdvice
public class ExceptionHandlerController {

    @ExceptionHandler(NoResourceFoundException.class)
    public String handleNoResourceFoundException(){

        return Views.Exceptions.resourceNotFound;
    }
}

e @Shalom @Koziołek @furious programming jakby wywalić wyjątek z takiego serwisu i w tym wyjątku zapisać stan tego usera ktory jest zły, żeby go potem użyć, to by było ok czy raczej nie ?

EDIT

według jakieś mądrej głowy z dużą ilością pkt można http://stackoverflow.com/ques[...]parameters-in-the-constructor

1

Natywne zapytania to się raczej do skomplikowanych rzeczy używa np. raportowania / analizy danych. W Twoim przypadku wystarczą @NamedQuery w JPQL, których poprawność będzie sprawdzana na etapie walidacji: każde z nich jest kompilowane (jak będą trefne prawdopodobnie deploy się nie uda, więc jest bezpieczniej). Criteria nie jest tak często używane, ma sens wtedy, gdy robimy dużo dynamicznych zapytań tzn. z dużą ilością zmiennych parametrów. Są też mniej czytelne.

0

Hehehe wiedziałem, że jest źle ale to, że wrzuciłem hasło na Githuba to sam siebie zaskoczyłem :O (na szczęście tylko do bazdy danych). Dziękuję wam bardzo za odpowiedzi i że chciało wam się grzebać w tym syfie, spróbuję się trochę wytłumaczyć i dopytać :)

@Shalom Co do punktu 2 i 4, akurat takie znalazłem tutoriale, te nowe trochę mnie przerosły i uznałem ,że łatwiej mi będzie zacząć od Springa 3. A MySQL troche znam dlatego wybrałem. Ale racja poczytam o innych opcjach. Pkt 6 nie skomentuje nie wiem skąd to się tam wzięło ... 7. Tutaj własnie mam pytanie, wydawało mi się, że DAO to właśnie klasy które służą do łączenia z bazą danych i zwracania już gotowych obiektów. 8. Racja, byłem leniwy, JPQL mi nie działał to uznałem zrobię nativequery naprawie potem :P 10. Podobno to prawie to samo tak przeczytałem w Spring in Action.

@JasnyPatryk 4. A chciałem robić interfejsy i zmieniłem zdanie, a zapomniałem usunąć :p 7. Wiem wiem chciałem nawet użyć tylko nie potrafiłem zmienić koloru niektórych logów w eclipsie a syso zawsze na czarno... 9. Miałem klasy z serwisami coś tam poprzenosiłem, ale było to takie na siłę więc zrezygnowałem. Nie czuję jeszcze do końca kiedy czego używać itp.

Cieszę się, że wystawiłem tutaj ten kod bo pędziłem bez opamiętania zostawiając niektóre rzeczy w opłakanym stanie. Za jakiś czas jak poprawie i doczytam pochwalę się jeszcze znowu. Jeszcze raz dzięki :D

0
capoeira napisał(a):

Nie czuję jeszcze do końca kiedy czego używać itp.
Możesz na razie założyć, że każda logika musi być wywołana z poziomu serwisu.

0

Cześć ponownie :)
Minął trochę ponad miesiąc odkąd utworzyłem tego posta. Zgodnie z waszymi poradami spróbowałem trochę przerobić projekt. Gdyby ktoś chciał zerknąć na 5 minut i zobaczyć, czy znowu nie uprawiam jakiś herezji to zapraszam ponownie:) Będę wdzięczny za wszelkie uwagi!

0

Założyłem sobie konto i podbijam do góry, bo jako anonim chyba się nie da.

0
@Service
public class ProductService {

    // ...

    public boolean saveProduct(HttpServletRequest request, ProductDTO form, BindingResult result) {
        if (!result.hasErrors() && request.getMethod().equalsIgnoreCase("post")) {
            Product product = new Product();
            product.setProductName(form.getProductName());
            product.setPrice(form.getPrice());
            product.setCategory(categoryDAO.findByCategoryId(form.getCategoryId()));
            productDAO.save(product);
            return true;
        } else {
            return false;
        }

    }

    // ...
}

Moim zdaniem w tym momencie uzależniasz warstwę modelu od warstwy kontrolerów poprzez posługiwanie się parametrem HttpServletRequest. A co jeśli chciałbyś stworzyć aplikację desktopową, gdzie nie ma HttpServletRequest? Warstwa modelu powinna i w aplikacji desktopowej ruszyć ;).

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