Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Hallo, wie mir freundlicherweise schon im anderen Thread der Hinweis gegeben wurde, das "vor" einer Datenbank eine REST-API muss.
Ich habe mich schon ein bisschen schlau gemacht (die REST-API greift auf die Datenbank zu und holt sich so die Daten), aber bevor ich in falsche Richtungen mich orientiere, habe ich mal 2 Fragen.
Kann man eine REST-API selbst bauen (Java, Python)? Und wenn ja gibt es (vielleicht deutsche) Anleitungen dazu?
Ziel ist so etwas auf einen eigenen Linux-Server bzw einen Linux-Server VPS-Server zu installieren.
Ich kenne vor allem Englische Anleitungen. Man kann sich da z.B. Spring Boot oder Quarkus ansehen. (Und da auch mal nach Deutschen Anleitungen suchen. Sollten aber nicht zu alt sein, da sich beide Frameworks zügig weiter entwickeln.)
und habe darüber hinaus noch weitere Video-Tutorial angeschaut.
Jetzt bin ich soweit, das ich zu erste Test's komme, doch leider gibt er ein Fehler aus.
Code:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Das heißt ich muss eine Datenbanktabelle anlegen.
Aber zum generellen testen möchte ich es ohne Datenbank machen. Geht das überhaupt?
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
Hast du eine Abhängigkeit zu MySQL im Ptojekt? In Maven wäre es etwas wie:
<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.31</version>
</dependency>
Jetzt habe ich viele Anleitungen sorgfältig durchgearbeitet,z.B. auch diese, Das mit den Ausgaben von allen Daten und eins hinzufügen klappt schon mal ohne Probleme.
Jetzt wollte ich in der Klasse Controller eine Methode hinzufügen, welche ein bestimmter Name oder nur eine bestimmte id ausgibt.
Leider klappt das noch nicht so wie ich mir das vorstelle.
Ich habe eine Klasse "User" erstellt, was name und ort beinhaltet, inklusive den Methoden set- und getter.
Dann eine Klasse UserRebo, die als interface von CrudRepository dient (was kann man noch hier eintragen?).
Und eine Klasse ControllerUser, welche beim Aufruf über eine url angesteuert wird und die "GetMapping" - Methoden ausgewertet werden.
Nun möchte ich alles erweitern, so das man entweder nach einer id oder einen Namen sucht und ausgeben lässt.
Aufrufen möchte ich die letzte Methode im controller "getID"
Postman gibt mir einen Fehler wenn ich "localhost:8082/api/user/2" eingebe.
Die id 2 gibt es wenn ich "all" ausgebe sehe ich es.
Hier mal die Klassen damit ihr wisst, was ich bis jetzt gemacht habe.
Java:
@Entity
public class User {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
private String ort;
public void setID(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setOrt(String ort) {
this.ort = ort;
}
public Long getID() {
return this.id;
}
public String getName() {
return this.name;
}
public String getOrt() {
return this.ort;
}
}
Java:
public interface UserRepo extends CrudRepository<User, Long>{
List<User> findByName(String lastName);
User findById(long id);
}
Java:
@Controller
@RequestMapping("api") //der Pfad nach der url:port also url:port/api -- name kann beliebeig sein
public class ControllerUser{
// Dies bedeutet, die Bean namens userRepository zu erhalten
// Wird von Spring automatisch generiert, wir werden es verwenden, um die Daten zu verarbeiten
@Autowired
private UserRepo userRepository;
@PostMapping("/add") //nur an post -Anfragen also url:port/api/add
// @ResponseBody bedeutet, dass der zurückgegebene String die Antwort ist, kein Ansichtsname
// @RequestParam bedeutet, dass es sich um einen Parameter aus der GET- oder POST-Anfrage handelt
public @ResponseBody String addNewUser (@RequestParam String name, @RequestParam String ort) {
User n = new User();
n.setName(name);
n.setOrt(ort);
userRepository.save(n);
return "Saved";
}
@GetMapping("/all") //nur anzeigen -Anfragen also url:port/api/all
public @ResponseBody Iterable<User> getAllUsers() {
// Dies gibt ein JSON oder XML mit den Benutzern zurück
return userRepository.findAll();
}
//die besagt Methode funktionier so leider nicht,
@GetMapping("user/{id}")
public Optional<User> getID(@PathVariable Long id) {
return userRepository.findById(id);
}
}
Wie war das mit meinem Auto? Mein Auto gibt mir einen Fehler. Kannst Du mir sagen, was kaputt ist?
Was ist denn so schwer daran, einfach einmal genau zu sagen, was Du zurück bekommst? Die Response Codes haben alle eine Bedeutung und die kann man durchaus mit angeben.
Ansonsten fällt mir auf, dass Du in den Mappings nicht einheitlich mit den / arbeitest. Ich habe eigentlich immer, dass ich mit / starte. Sprich: @GetMapping("/user/{id}")
Ob das weggelassen werden kann, kann ich im Augenblick nicht sagen, da ich mir das im Detail so nicht angesehen habe. (Für mich startet man mit einem / und gut ist es - damit bin ich bisher sehr gut gefahren. Und ich werde es jetzt nicht ausprobieren, ob es auch anders geht.)
Und bitte: Fang nicht mit Abkürzungen an! Das ist ein UserRepository und nicht UserRepo oder so! Und gibt Variablen vernünftige Bezeichner! n ist kein vernünftiger Bezeichner. Zumal n für einen User? Das kann der createdUser sein - dann ist klar: In der Variable ist der User drin, der erzeugt wurde!
So ich habe jetzt nochmal alles "durchstudiert", jetzt habe ich die Methoden "put", "delete" und "get" erstellt bzw. überarbeitet.
Jetzt funktioniert es wie es soll.
Alle Methoden funktionieren. Die Frage ist ob es vom Code sauber ist.
Hier erstmal der Controller:
Java:
@Controller
@RequestMapping("/api") //der Pfad nach der url:port also url:port/api -- name kann beliebeig sein
public class ControllerUser{
@Autowired
private UserRepo userRepository;
@PostMapping("/add")
public @ResponseBody String addNewUser (@RequestParam String name, @RequestParam String ort) {
User user = new User();
user.setName(name);
user.setOrt(ort);
userRepository.save(user);
return "Saved";
}
@GetMapping("/all")
public @ResponseBody Iterable<User> getAllUsers () {
return userRepository.findAll();
}
//hier wird explizit die ID als Parameter angegeben
@GetMapping("/user")
public @ResponseBody Optional<User> nameSearch(@RequestParam Long id) {
return userRepository.findById(id);
}
//die ID wird an die URL gehängt
@GetMapping("/user/{id}")
public @ResponseBody Optional<User> idSearch(@PathVariable Long id) {
return userRepository.findById(id);
}
//ein Eintrag löschen mit dem Parameter ID
@DeleteMapping("/del")
public @ResponseBody String loeschen(@RequestParam Long id) {
userRepository.deleteById(id);
return "gelöscht";
}
//einen Eintrag verändern
@PutMapping("/put")
public @ResponseBody String put(@RequestParam Long id, @RequestParam String ort) {
User user = new User();
//gesetzt wird die übergebene ID und den Ort
user.setID(id);
user.setOrt(ort);
//hier wird der Name zurückgegeben
String name = userRepository.findById(id).get().getName();
//den Namen setzen
user.setName(name);
//und speichern
userRepository.save(user);
return "erfolgreich";
}
//hier wird explizit nach dem Namen gesuch und wiedergegeben
@GetMapping("/einzelausgabe")
public @ResponseBody List<User> einzel(@RequestParam String name) {
return userRepository.findByName(name);
}
}
Was mir noch für Fragen aufwerfen ist, das es viele Tutorial's gibt und alle unterschiedliche Controller mit verschiedenen Methoden haben wie z.B. ResponseEntity.
Mir stellt sich die Frage was braucht man wann und was wirklich?
Oder kann man mit meinen Controller "leben" der alles beinhaltet?
Sauber ist es eigentlich nicht. User ist eine Entity, es ist ein Antipattern eine Entity aus einem Rest-Endpunkt zurückzugeben. Man würde ein UserDTO erstellen und dieses zurückgeben.
Der Hintergrund ist: Stell dir vor jemand erweitert User und schreibt da ein Feld rein, welches schutzwürdig ist, z.B.: sexuelle Orientierung. Jetzt gibt dein Rest-Endpunkt automatische diese Daten weiter. Das sollte nicht passieren, auch wenn die Daten nicht direkt in deiner Programmoberfläche oder Webseite sichtbar sind, können sie trotzdem ausgelesen werden. Daher erstellt man ein DTO-Objekt, welches nur die Daten enthält, welche der Endpunkt zurückgeben soll. Auch wenn die Daten im Moment identisch sind. Programme werden sich aber mit der Zeit verändern.
Eine vernünftige IDE(-Einstellung) würde dich auch automatisch auf das Problem hinweisen. Es empfiehlt sich immer die statische Codeanalyse einzuschalten/installieren, z.B.: Sonarlint finde ich ganz gut für Einsteiger.
//einen Eintrag verändern
@PutMapping("/put")
public @ResponseBody String put(@RequestParam Long id, @RequestParam String ort) {
User user = new User();
//gesetzt wird die übergebene ID und den Ort
user.setID(id);
user.setOrt(ort);
//hier wird der Name zurückgegeben
String name = userRepository.findById(id).get().getName();
//den Namen setzen
user.setName(name);
//und speichern
userRepository.save(user);
return "erfolgreich";
}
Ich würde es eher so schreiben:
Java:
//einen Eintrag verändern
@PutMapping("/put")
@Transactional
public @ResponseBody String put(@RequestParam Long id, @RequestParam String ort) {
User user = userRepository.findById(id).orElseThrow(...);
user.setOrt(ort);
//und speichern
userRepository.save(user); // das sollte gar nicht nötig sein, weglassen
return "erfolgreich";
}
Statt "erfolgreich" geben wir eigentlich immer das vollständige Object zurück. Es können sich zwischenzeitlich noch weiter Felder geändert haben. So kann man sein Programm aktualisieren.
Sauber ist es eigentlich nicht. User ist eine Entity, es ist ein Antipattern eine Entity aus einem Rest-Endpunkt zurückzugeben. Man würde ein UserDTO erstellen und dieses zurückgeben.
Der Hintergrund ist: Stell dir vor jemand erweitert User und schreibt da ein Feld rein, welches schutzwürdig ist, z.B.: sexuelle Orientierung. Jetzt gibt dein Rest-Endpunkt automatische diese Daten weiter. Das sollte nicht passieren, auch wenn die Daten nicht direkt in deiner Programmoberfläche oder Webseite sichtbar sind, können sie trotzdem ausgelesen werden. Daher erstellt man ein DTO-Objekt, welches nur die Daten enthält, welche der Endpunkt zurückgeben soll. Auch wenn die Daten im Moment identisch sind. Programme werden sich aber mit der Zeit verändern.
Eine vernünftige IDE(-Einstellung) würde dich auch automatisch auf das Problem hinweisen. Es empfiehlt sich immer die statische Codeanalyse einzuschalten/installieren, z.B.: Sonarlint finde ich ganz gut für Einsteiger.
Was heißt das jetzt genau? Wie sollte ich vorgehen? Was ist ein DTO-Objekt? Vielleicht kannst du dazu ein Schema verlinken was aufzeigt wie man es richtig macht.
Ich habe mir mal die Seite angeschaut, versucht es zu verstehen. Aber leider kommen mehr Fragen auf als Antworten.
Ich weiß nicht mal wie ich den Code verstehen soll, wo soll er hin, wie binde ich mein vorhandenes Rest-Projekt ein?
Was macht die Klasse
Java:
PostDto
u.s.w. Leider habe ich im Netz auch nicht so viel gesehen, was mich weiter bringt.
Ich habe mir mal die Seite angeschaut, versucht es zu verstehen. Aber leider kommen mehr Fragen auf als Antworten.
Ich weiß nicht mal wie ich den Code verstehen soll, wo soll er hin, wie binde ich mein vorhandenes Rest-Projekt ein?
Was macht die Klasse
Java:
PostDto
u.s.w. Leider habe ich im Netz auch nicht so viel gesehen, was mich weiter bringt.
Also das Beispiel hat eine Entity Post und man will nun nicht dieses Entity raus geben sondern nur ein modifiziertes PostDTO.
Daher braucht man nun eunen Mapper, der aus einer Post Instanz eine PostDTO Instanz macht.
Das ist alles. Und das kannst Du 1:1 umwandeln. Dazu "Post" durch den Namen deiner Entity ersetzen.
Alles gut und schön, aber ich würde gerne wissen wie das ganze im Prinzip arbeitet, also auch die einzelnen Methoden etc.
Ich wünschte mir in den Anleitungen steht über jede Method und Klasse eine kleine Beschreibung. Es wird leider immer alles im Groben beschrieben.
aber ich würde gerne wissen wie das ganze im Prinzip arbeitet, also auch die einzelnen Methoden etc.
Ich wünschte mir in den Anleitungen steht über jede Method und Klasse eine kleine Beschreibung.
Im Artikel findest Du einen Link auf http://modelmapper.org/getting-started/ - dort steht beschrieben, wie der ModelMapper funktioniert inkl. Benutzerhandbuch.
Ansonsten besteht ja kein Zwang, diese Bibliothek - oder überhaupt eine - für das Mapping zu verwenden. Wir erzeugen z. T. direkt JsonObject-Instanzen, die wir zurückgeben oder haben DTO-Klassen, die wir manuell füllen bzw. als Adapter fungieren.
Ansonsten besteht ja kein Zwang, diese Bibliothek - oder überhaupt eine - für das Mapping zu verwenden. Wir erzeugen z. T. direkt JsonObject-Instanzen, die wir zurückgeben oder haben DTO-Klassen, die wir manuell füllen bzw. als Adapter fungieren.
Genau, das meine ich ja, ich habe aktuell kein grundsätzlichen Überblick wie so etwas generell funktionieren muss.
Aber ich werde mich nach und nach mal durcharbeiten, inkl. mit den hilfreichen Tipps hier im Forum.
Wenn ich mal noch eine Frage melde ich mich zu gegebener Zeit nochmal.
Ganz grundsätzlich ist es einfach so, dass über die Leitung keine Objekte sondern eine Serialisierung der Objekte bzw. der Objektdaten gehen können. Damit Sender und Empfänger Daten austauschen können, müssen sie die "gleiche Sprache" sprechen. In Webservices wird oft JSON verwendet, weil es a) weit weniger geschwätzig als XML ist und b) von JavaScript im Browser sowieso verstanden wird.
Jetzt hast Du also ein Person-Objekt und das muss irgendwie, sagen wir mal in JSON, serialisiert werden. SpringBoot/Jakarta EE können das automatisch: man gibt als Rückgabetyp z. B. Person an, liefert ein Person-Objekt zurück und das Framework erzeugt daraus einen JSON-Text.
Statt nun direkt ein Person-Objekt zurückzuliefern, kann man auch eine "Sicht" auf eine Person (oder auf Person und Objekte weiterer Klassen) zurückliefern, dazu kann man ein DTO verwenden (s. dazu Kommentar #21 von @Oneixee5).
Ein DTO ist einfach ein Objekt, das eben gerade die Daten enthält, die über die Leitung gehen sollen. Erstellt werden kann dieses wie jedes andere Objekt auch: man schreibt eine Klasse, erzeugt eine Instanz, setzt die Properties.
Nehmen wir mal an, wir hätten eine Person-Klasse, die Name, Vorname und Geburtsdatum darstellt. Aus Gründen des Datenschutzes sollen aber nur Name und Vorname über den REST-Endpoint geliefert werden.
Java:
class PersonDTO {
public String name;
public String vorname;
public PersonDTO(Perosn perosn) {
name = person.getName();
vorname = person.getVorname();
}
}
Gibst Du jetzt in Deiner REST-Methode statt Person PersonDTO zurück, wird niemals das Geburtsdatum über die Leitung gehen. Die Person-Klasse kann später auch weitere Attribute erhalten, die die Außenwelt nichts angehen: das DTO stellt sicher, dass diese nicht übermittelt wreden.
Das Prinzip ist, soweit ich es verstanden habe, ich habe wie in mein Post 17 und 20 eine normale User-Klasse, eine User-Repository-Klasse, eine Controller-Klasse.
Hinzu füge ich in folgendes: in der UserdtoApplication Klasse
Java:
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
Warum auch immer das braucht.
Dann lege ich eine Klasse UserDTO , die z.b. nur die ID und den Namen frei gibt. Der Ort bleibt "geheim".
In Der Controller-Klasse lege ich diese Methode an
Das Spring-Framework muss für die Injection einer ModelMapper-Instanz via @Autowired wissen, wie es eine Instanz von ModelMapper erzeugen kann. Das wird hier mit einer Factory-Method erledigt, die mit @Bean annotiert werden muss.
Die Annotation dient m. W. schlicht dazu, eine Spring-Komponente im Code explizit als Service (i. S. des Domain-Driven-Design) und nicht einfach als gewöhnliche Komponente darzustellen.
Dien Repository gibt offenbar ein Optional statt eines Entity zurück.
Java:
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}
...
@GetMapping("/user/{id}")
@ResponseBody
public UserDTO getPost(@PathVariable Long id) {
return convertToDto(userRepository.findById(id).orElseThrow(() -> new UserNotFoundException("Unavailable")));
}
Ich bin gerade dabei vom UserDTO zum User einen Eintrag zu verändern.
Dabei legte ich die Methode "convertToEntity" an und die Methode die ein Name verändert.
Im Beispiel wurde gezeigt, dass man auch "UserDTO" mit als Parameter übergeben soll.
Jetzt stellt sich mir die Frage wie ich das zum testen in Postman eingeben soll und ob das so überhaupt funktioniert, denn ich möchte ja den Namen von UserDTO (der nur von außerhalb sichtbar ist) ändern, das User den Namen ändert.
Vielleicht kann mir jemand einen kleinen Tipp geben, ich habe vom vielen lesen leider den durchblick verloren.
Java:
//einen Eintrag verändern
@PutMapping("/put")
@ResponseBody
public UserDTO put(@RequestParam Long id, @RequestBody UserDTO userDto, @RequestParam String name) throws ParseException {
User user = convertToEntity(userDto);
user.setName(name);
userRepository.save(user);
return convertToDto(userRepository.findById(id).orElseThrow(() -> new UserNotFoundException("Unavailable")));
}
//von UserTDO zum User, hier uebergebe ich den modelMapper den UserDTO und soll ihn in User "umwandeln"
private User convertToEntity(UserDTO userDTO) throws ParseException {
User user = modelMapper.map(userDTO,User.class);
return user;
}
Das ganze habe ich jetzt nochmal auf komplett anderen Wege gemacht.
Es funktioniert auch und zeige es euch mal:
UserRepository
Java:
public interface UserRepo extends JpaRepository<User, Long>{
List<User> findByName(String lastName);
User findById(long id);
}
User
Java:
@Entity
public class User {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
private String ort;
public void setID(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setOrt(String ort) {
this.ort = ort;
}
public Long getID() {
return this.id;
}
public String getName() {
return this.name;
}
public String getOrt() {
return this.ort;
}
}
UserDTO
Java:
public class UserDTO {
private String name;
private Long id;
public void setName(String name) {
this.name = name;
}
public void setID(Long id) {
this.id = id;
}
public Long getID() {
return this.id;
}
public String getName() {
return this.name;
}
}
UserConverter
Java:
@Component
public class UserConverter {
public UserDTO entityToDTOo(User user) {
ModelMapper mapper =new ModelMapper();
UserDTO map = mapper.map(user, UserDTO.class);
return map;
}
public List<UserDTO> entityToDTO(List<User> user) {
return user.stream().map(x -> entityToDTOo(x)).collect(Collectors.toList());
}
public User dtoToEntity(UserDTO userdto) {
ModelMapper mapper = new ModelMapper();
User map = mapper.map(userdto, User.class);
return map;
}
public List<User> dtoToEntity(List<UserDTO> userdto){
return userdto.stream().map(x -> dtoToEntity(x)).collect(Collectors.toList());
}
}
und der Controller
Java:
@RestController
@RequestMapping("/api")
public class ControllerUser{
@Autowired
private UserRepo userRepository;
@Autowired
private UserConverter converter;
//Alles ausgeben
@GetMapping("/all")
public List<UserDTO> findAll(){
List<User> findAll = userRepository.findAll();
return converter.entityToDTO(findAll);
}
//Ausgabe Objekt mit bestimmter ID
@GetMapping("/user/{id}")
public UserDTO findById(@PathVariable Long id) {
User orElse = userRepository.findById(id).orElse(null);
return converter.entityToDTOo(orElse);
}
//ein kompletes neues Objekt hinzufuegen
@PostMapping("/neu")
public UserDTO save(@RequestParam String name) {
UserDTO dto = new UserDTO();
dto.setName(name);
User user = converter.dtoToEntity(dto);
user = userRepository.save(user);
return converter.entityToDTOo(user);
}
//einen Eintrag verändern
//und dien gesamten eintrag zurueck geben
@PutMapping("/put")
public UserDTO put(@RequestParam Long id, @RequestParam String name) {
UserDTO dto = new UserDTO();
dto.setName(name);
dto.setID(id);
User user = converter.dtoToEntity(dto);
user = userRepository.save(user);
return converter.entityToDTOo(user);
}
//ein Eintrag löschen mit dem Parameter ID
@DeleteMapping("/del")
public List<UserDTO> loeschen(@RequestParam Long id) {
userRepository.deleteById(id);
return converter.entityToDTO(userRepository.findAll());
}
//hier wird explizit nach dem Namen gesuch und wiedergegeben
@GetMapping("/einzelausgabe")
public List<UserDTO> einzel(@RequestParam String name) {
List<User> user = userRepository.findByName(name);
return converter.entityToDTO(user);
}
}
Das einzige Problem, das ich hier sehe ist, dass das DTO ggf. den User überschreibt. Wir würden den User aus dem Repo holen und die Properties des DTO auf den persistenten User mappen.
Es geht einfach darum, dass Du aus dem DTO direkt einen User erstellst. Diese Entity kann aber nur über die Informationen verfügen, die im DTO existieren, der Rest wäre "leer". Würdest Du nun das so erzeugte User-Objekt im Repo speichern, wären die ggf. im existierenden User bereits vorhandenen Informationen verloren.
Spendier der User-Entity einfach mal ein Geburtsdatum. Jetzt bekommst Du von außen eine Änderung via UserDTO, das neben der ID nur den Namen enthält. Du erzeugst nun ein neues User-Objekt mit ID und Namen und speicherst den Spaß im Repository ab. Damit überschreibst Du Dir das Geburtsdatum des bereits vorhandenen Users.
Deswegen machen wir etwas wie
Java:
User user = userRepository.findById(dto.getId());
user.setName(dto.getName()); // mappen der DTO-Properties auf den User
userRepository.save(user);
Das ist ja jetzt vom bisherigen Thema losgelöst. Generell ist das der Weg, den ich empfehlen würde. Also ein separates Identity Management (z.B. Keycloak - das ist einfach aufzusetzen auf Entwickler Systemen) und dann wird das lediglich genutzt.
Damit umgehst Du viele kritische Dinge wie z.B, die sicherer Verwahrung von Daten. (Du hattest das speichern von Passwörtern erwähnt. Wenn, dann wird nur ein Hash - oder besser: "seeded hash" - gespeichert, aber niemals die Passwörter.) Etwas, das Du nicht speicherst, das kann nicht böswillig gelesen werden.
Und es bietet Firmen die Möglichkeit, da eigene identity Management Lösungen zu nutzen. (Kennt evtl. der eine oder andere: man will sich irgendwo anmelden wie z.B. Microsoft und nach Eingabe der Email Adresse erscheint dann ein Login des Firmen Systems)
Spendier der User-Entity einfach mal ein Geburtsdatum. Jetzt bekommst Du von außen eine Änderung via UserDTO, das neben der ID nur den Namen enthält. Du erzeugst nun ein neues User-Objekt mit ID und Namen und speicherst den Spaß im Repository ab. Damit überschreibst Du Dir das Geburtsdatum des bereits vorhandenen Users.
Aber was ich mich gerade frage, das geht nur bei Objekten die schon existieren.
Das geht aber nicht wenn man ein neues Objekt erstellt, denn der DTO User hat ja nur "Rechte" auf name und id.
Da macht ja das erstellen keinen Sinn über DTO User. Oder wie ist das in der Prxis?
Das geht aber nicht wenn man ein neues Objekt erstellt, denn der DTO User hat ja nur "Rechte" auf name und id.
Da macht ja das erstellen keinen Sinn über DTO User. Oder wie ist das in der Prxis?
Prinzipiell geht es genau so beim Erstellem von neuen Usern.
Aber die fachlichen Fragen kannst nur Du klären. Generell kann man mehrere DTO Klassen haben. Dann ahst Du halt noch eine UserCreateDTO Klasse, die nur Felder hat, die beim Erzeugen Sinn machen.
Genau, die habe ich jetzt erstellt und funktioniert wie es funktionieren soll.
Bei der Put-Methode hatte ich einen Denkfehler, da wurde der ort z.b. immer gelöscht.
Jetzt sieht es so aus, und es funktioniert auch.
Vielen dank euch allen.
Java:
@PutMapping("/put")
public UserDTO put(@RequestParam Long id, @RequestParam String name) {
UserDTO dto = new UserDTO();
dto.setID(id);
dto.setName(name);
User user = userRepository.findById(dto.getID()).orElse(null);
user.setName(dto.getName());
userRepository.save(user);
return converter.entityToDTOo(user);
}
a) Warum erzeugst Du erst ein DTO, wenn Du es eh nicht brauchst? DTO sind Data Transfer Objects - also zur Weitergabe von Daten. Aber in Zeile 3 des Codes erzeugst Du eine Instanz, die Du nicht weiter gibst. Das ist so also schlicht sinnlos. In Zeile 6 kannst Du direkt die id verwenden und in Zeile 7 den Namen. Die DTO Klasse kommt also wirklich erst am Ende ins Spiel.
b) Was soll dieses orElse(null)? Damit kann user null sein und Du rennst in der folgenden Zeile in eine NPE. Und die NPE ist eine typische "EntwicklerIstZuBlödException" - das sollte dir bewusst sein!