Odbieranie danych POST w servlecie

0

Cześć,

Niedawno przerobiłem kurs tworzenia aplikacji webowych w javie, teraz próbuję zrobić swoją pierwszą apke, ale utknąłem w następującym punkcie:

  1. Chce zrobić dodawanie do DB, przy pomocy formularza napisanego w Js w pliku index.html
  2. Niestety dostaję cały czas błąd informujący, że jeden z parametrów jest NULL (w db jest pole not null), ale nie rozumiem dlaczego, bo formularz czyta wartość pola i np. potrafi wyświetlić wpisaną treść przy pomocy: alert(tresc z labela)
  3. DOSTAJĘ NASTĘPUJĄCY BŁĄD:
WARN: SQL Error: 23502, SQLState: 23502
maj 06, 2021 11:04:58 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Pole nie może być NULL"NAZWA"
NULL not allowed for column "NAZWA"; SQL statement:
insert into MAGAZYN_SUROWCOW (ilosc, nazwa, typ, id) values (?, ?, ?, ?) [23502-200]
[qtp95395916-23] WARN org.eclipse.jetty.server.HttpChannel - /magazyn
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
	at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
	at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
	at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
	at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1364)
	at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:451)
	at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3210)
	at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2378)
	at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447)
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183)
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40)
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281)
	at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
	at io.github.mat3e.MagazynRepository.addMagazyn(MagazynRepository.java:33)
	at io.github.mat3e.MagazynService.dodajdoDB(MagazynService.java:27)
	at io.github.mat3e.MagazynServlet.doPost(MagazynServlet.java:52)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:859)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:542)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1588)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1345)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1557)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1247)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.server.Server.handle(Server.java:502)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
	at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
	at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
	at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
	at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
	at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:200)
	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3254)
	at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3779)
	at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:107)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
	at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)
	at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
	at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
	at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348)
	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)
	at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102)
	at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1360)
	... 43 more
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Pole nie może być NULL"NAZWA"
NULL not allowed for column "NAZWA"; SQL statement:
insert into MAGAZYN_SUROWCOW (ilosc, nazwa, typ, id) values (?, ?, ?, ?) [23502-200]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:459)
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)
	at org.h2.message.DbException.get(DbException.java:205)
	at org.h2.message.DbException.get(DbException.java:181)
	at org.h2.table.Column.validateConvertUpdateSequence(Column.java:374)
	at org.h2.table.Table.validateConvertUpdateSequence(Table.java:845)
	at org.h2.command.dml.Insert.insertRows(Insert.java:187)
	at org.h2.command.dml.Insert.update(Insert.java:151)
	at org.h2.command.CommandContainer.update(CommandContainer.java:198)
	at org.h2.command.Command.executeUpdate(Command.java:251)
	at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:191)
	at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:152)
	at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
	... 54 more
Hibernate: select max(id) from MAGAZYN_SUROWCOW
Hibernate: insert into MAGAZYN_SUROWCOW (ilosc, nazwa, typ, id) values (?, ?, ?, ?)

Process finished with exit code -1

WYGLĄDA TO OGÓLNIE TAK:
a) w pliku index.html po wcisnieciu przycisku wysylam metodą POST wartości do servleta

document.getElementById('btndodsurX').addEventListener('click', (event) => {
        const xxnazwa = document.getElementById('nazwa');
        const xxilosc = document.getElementById('ilosc');
        event.preventDefault();
        fetch("http://localhost:8080/magazyn", {
                method: 'POST',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                },

                body: JSON.stringify({ ilosc: xxilosc.value, nazwa: xxnazwa.value, typ: "1"})
            }

        )
    })

b) Dalej mam SERVLET z metodą, która to obsługuje:

@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        var newSurowce = mapper.readValue(req.getInputStream(), Magazyn.class);
        logger.info("MAGAZYN_SERVLET_METODA_DO_POST!!");
        logger.info("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + req.getParameter(NAME2_PARAM));
        resp.setContentType("application/json;charset=UTF-8");
        mapper.writeValue(resp.getOutputStream(), service.dodajdoDB(newSurowce));

    }

c) Dalej mam metodę z SERVICE:

public Magazyn dodajdoDB(Magazyn newSurowce) { repository.addMagazyn(newSurowce); return newSurowce; }

d)Dalej mam metodę z REPOSITORY:

Magazyn addMagazyn(Magazyn newSurowce){
    var session = HibernateUtil.getSessionFactory().openSession();
    var transaction = session.beginTransaction();
    session.persist(newSurowce);
        transaction.commit();
        session.close();
        return newSurowce;
}

e) Poniżej dodam jeszcze klasę związaną z Hibernate:

@Entity
@Table(name = "MAGAZYN_SUROWCOW")
public class Magazyn {
@Id
@GeneratedValue(generator = "inc")
@GenericGenerator(name = "inc", strategy = "increment")
private Integer id;
private String nazwa;
private String ilosc;
private Integer typ;


    public Magazyn()
    { }

    public Magazyn(Integer id, String nazwa, String ilosc, Integer typ)
    {
        this.id = id;
        this.nazwa=nazwa;
        this.ilosc=ilosc;
        this.typ=typ;
    }

    public Integer getId() {
        return id;
    }


    public String getNazwa() {
        return nazwa;
    }

    public void setNazwa(String nazwa) {
        nazwa = nazwa;
    }

    public String getIlosc() {
        return ilosc;
    }

    public void setIlosc(String ilosc) {
        ilosc = ilosc;
    }

    public Integer getTyp() {
        return typ;
    }

    public void setTyp(String typ) {
        typ = typ;
    }
}

Utknąłem w martwym punkcie i przyznam, że naprawdę nie wiem już w czym problem. Gdy w servlecie jak chcę pobrać jakiś parametr/argument to jest on NULLem. Wygląda tak jakby metoda POST z frontendu napisana w JS nie przekazywała dalej wartości tych parametrów. Nie rozumiem tylko dlaczego, bo mogę pobrać z pola tekstowego wartosc i wyswietlic ja na ekranie z pomocą javascript i działa. W konsoli przeglądarki metoda post wraz z body istnieje. Dodałem loggera i całość dochodzi do metody doPOST w servlecie bo loguje w konsoli.

Problem zaczyna sie w tych liniach:

logger.info("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + req.getParameter(NAME2_PARAM));
i tutaj niestety req.getParameter rzuca NULLEM

 resp.setContentType("application/json");
 mapper.writeValue(resp.getOutputStream(), service.dodajdoDB(newSurowce));

idzie dalej do servisu, dalej do klasy magazyn, gdzie są metody związane z dodawaniem do DB, ale tam krzaczy, bo wartość jest nullowa.

Ma ktoś jakiś pomysł, albo chociaż wskazówkę gdzie szukąc/kiedy występuje taki błąd ?

2
  1. Serio masz var czyli nowa javę a piszesz goły servlet? o_O
  2. Użyj debuggera? Wpinasz się w ten swój servlet i zobacz co dostajesz. Zrób sobie tam req.getInputStream().readAllBytes() i zobacz co ci tam przyszło. Nie wiem po co wstawiasz tutaj tyle kodu, kiedy 95% z niego nie ma w ogóle związku z twoim problemem.
  3. Może jednak porzuć te servlety i napisz to z uzyciem jakiegoś webowego frameoworka który to wszystko zrobi za ciebie? Serio mamy rok 2021 i bawienie się w czytanie bajtów z input streama requestu http i mapowanie tego z jsona do DTO to lekka przesada.
0

Ok, dopiero zaczynam z apkami webowymi. Tak mnie trochę pokierował kurs, niby bardzo podstawowy żeby pisać te servlety. Zdaję sobie sprawę, że teraz raczej używa się frameworkow, ale nie wiem jeszcze jak działają i nie spodziewałem się, że to co robię to aż taki starożytny sposób już xD

Ale skoro tak radzisz, to wezmę się w takim razie za Spring'a i spróbuję coś napisać z użyciem tego. Dzięki wielkie za uświadomienie :-)

1

Rzuć ten kurs w cholerę.

Serwlety przestali używac nawet programiści z ciepłych krajów gdzieś ze 20 lat temu
Surowe interfejsy Hibernate ... nawet nie wiem, o ile dziesięcioleci to przestarzałe

*) serwlet stoi pod spodem każdego tradycyjnego frameworku **), ale to tyle opowieści, jest obudowany frameworkiem i normalny kod nigdy go nie używa.
**) za wyjątkiem Apache Wicket - tak jest Filter, he he.

1
Imperator109 napisał(a):

Ale skoro tak radzisz, to wezmę się w takim razie za Spring'a i spróbuję coś napisać z użyciem tego. Dzięki wielkie za uświadomienie :-)

Ostatnio sypnęło na 4p problemami ze springiem wynikającymi z patrzenia magicznego i "programowania stochastycznego".
Rzeczywiście jest to framework, który daje chleb wielu, ale czy każdemu przybliża głębokie zrozumienie tego, co się dzieje pod maską ... niekoniecznie.
Wielu / część zostaje na poziomie cargo cult'u i voo-doo i to również pracujących

W sensie edukacyjnym bardziej poszerzające są ćwiczenia poza Springiem, które będziesz 100% rozumiał.
Jednym z miłych frameworków a bardziej bibliotek do RESTa (nomem omen nie-servletowych - jest tego rosnącą ilość) jest RatPack

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