[JAVA] Bis INSERT und SELECT für Postgres mit Spring Boot und Thymianblatt

Was ich getan habe

Frühlingsstiefel Zusammenfassung des Fortschritts während des Studiums. In Artikel, den ich das letzte Mal geschrieben habe habe ich Hello World mit Spring Boot gemacht. Immerhin arbeite ich vor Ort. Folgendes habe ich diesmal getan.

Ich habe es zu einem Format gemacht, um Kommentare für jeden Code und jede Datei zu schreiben. Es ist nicht sehr gut organisiert, daher scheint es schwierig, später darauf zurückzublicken ...

Was wurde gemacht

Code

https://github.com/PG-practice/lyricWall/tree/simple_ui_connect_db

Bildschirmübergangsdiagramm

spring画面遷移.png

Pseudo-Kollaborationsdiagramm

Spring20200503構成.png

Was ich gelernt habe

Andere Vorbereitung als Code

Tabelle erstellen

Die Tabelle wurde manuell mit dem folgenden SQL generiert.

CREATE TABLE IF NOT EXISTS lyricTable (
    artist VARCHAR(32),
    title VARCHAR(32),
    words_writer VARCHAR(16),
    music_composer VARCHAR(16),
    lyric VARCHAR(1024),
    url VARCHAR(256),
    PRIMARY KEY (artist,title)
);

Einstellungen für die Postgres-Verbindung

Abhängigkeit hinzufügen

Artikel, den ich das letzte Mal geschrieben habe Zu der Zeit dachte ich, es wäre schön, postgresql zu haben, aber es scheint, dass jdbc benötigt wird, also habe ich Folgendes hinzugefügt.

build.gradle


dependencies {
         //Kürzung
	compile('org.springframework.boot:spring-boot-starter-jdbc')
}

Beschreibung der Verbindungsinformationen

Es scheint, dass application.propaties yaml sein kann, also habe ich es yaml gemacht. Der letzte DB-Name in der URL ist erforderlich.

application.yaml


spring:
 datasource:
    driver-class-name: "org.postgresql.Driver"
    #Der letzte DB-Name in der URL ist erforderlich
    url: "jdbc:postgresql://ubuntu:5432/postgres"
    username: "postgres"
    password: "" 

Hinweis für jeden Code

Detaillierte Kommentare, damit Sie später darauf zurückblicken können.

Lyric.java

Lyric.java


public class Lyric {
    private String artist;
    private String title;
    private String words_writer;
    private String music_composer;
    private String lyric;
    private String url;
    
    //Setter, Getter, Konstruktor ohne Argumente
    //(Kürzung)
}

LyricDaoImpl.java Der Schnittstellencode wird weggelassen. Nur Implementierung.

LyricDaoImpl.java


//Viele Importanweisungen

@Repository
public class LyricDaoImpl implements LyricDao {
    //Vorlage für DI. Alles was Sie tun müssen, ist es mit AutoWired ohne neu aufzurufen.
    private final JdbcTemplate jdbcTemplate;
    //DI verweist bei Bedarf auf Instanzen in Kombination mit den oben genannten
    @Autowired
    public LyricDaoImpl(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    //Holen Sie sich Song-Informationen des designierten Sängers
    @Override
    public List<Lyric> getSongs(String artistName) {
        //Ich möchte das prepareStatement neu schreiben, da es eine Gegenmaßnahme gegen SQL-Injection ist, aber diesmal ist es so, wie es ist.
        String sql = "SELECT * FROM lyricTable WHERE artist='" + artistName + "';";
        List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sql);

        List<Lyric> list = new ArrayList<Lyric>();
        for(Map<String, Object> result:resultList){
            Lyric lyric = new Lyric();
            lyric.setArtist((String)result.get("artist"));
            lyric.setTitle((String)result.get("title"));
            lyric.setWords_writer((String)result.get("words_writer"));
            lyric.setMusic_composer((String)result.get("music_composer"));
            lyric.setLyric((String)result.get("lyric"));
            lyric.setUrl((String)result.get("url"));
            list.add(lyric);
        }
        return list;
    }

    //Fügen Sie mehrere Songinformationen in die Liste ein.
    @Override
    public void insertSongs(List<Lyric> list) {
        String sql = "INSERT INTO lyricTable VALUES (?,?,?,?,?,?)";
        //vorbereitete Erklärung Mehrere INSERTs. Ich habe es so verwendet, wie es ist, als Vorlage. Jetzt funktioniert es.
        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter(){
            
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                Lyric lyric = list.get(i);
                ps.setString(1, lyric.getArtist());
                ps.setString(2, lyric.getTitle());
                ps.setString(3, lyric.getWords_writer());
                ps.setString(4, lyric.getMusic_composer());
                ps.setString(5, lyric.getLyric());
                ps.setString(6, lyric.getUrl());
            }
        
            @Override
            public int getBatchSize() {
                return list.size();
            }
        });

    }

    
}

--insertSongs () erlaubt mehrere INSERTs, aber nur ein Song kommt vom Bildschirm. ――Es scheint, dass batchUpdate Abfragen für jede Stapelgröße in einem Stapel sendet, aber es ist langsam, da nur eine Zeile gleichzeitig eingefügt wird, indem nur Verbindungen gruppiert werden. Es scheint, dass Batch INSERT durchgeführt werden kann, wenn es gesetzt ist.

LyricServiceImpl.java Der Schnittstellencode wird weggelassen. Nur Implementierung.

LyricServiceImple.java


//Viele Importanweisungen
@Service
public class LyricServiceImpl implements LyricService {
    //Vorlage für DI.
    private final LyricDao dao;

    @Autowired
    public LyricServiceImpl(LyricDao dao) {
        //Die Instanz der Implementierungsklasse ist DI
        this.dao = dao;
    }

    @Override
    public List<Lyric> getSongs(String artistName) {
        // TODO Auto-generated method stub
        return dao.getSongs(artistName);
    }

    @Override
    public void insertSongs(List<Lyric> list) {
        // TODO Auto-generated method stub
        dao.insertSongs(list);
    }

}

WebMvcControllerAdvice.java Definieren Sie eine Methode, die üblicherweise vor dem Controller verarbeitet wird

WebMvcControllerAdvice.java


@ControllerAdvice
public class WebMvcControllerAdvice {

    //Es scheint, dass leere Zeichen, die von HTML gesendet werden, als null behandelt werden
    @InitBinder
    public void initBinder(WebDataBinder dataBinder) {
        dataBinder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
    }

    //Wenn ein DB-Fehler auftritt, fügen Sie eine Fehlermeldung und ein leeres Formularobjekt in das Modell ein und geben Sie HTML zurück
    @ExceptionHandler(PSQLException.class)
    public String sqlException(PSQLException e, Model model){
        model.addAttribute("errorMessage",e.getMessage());
        model.addAttribute("searchForm", new SearchForm());
        model.addAttribute("insertForm", new InsertForm());
        return "form.html";
    }
   
}

--Sie setzen ein leeres Formularobjekt in model. Ich versuche, auf eine Eigenschaft in HTML zuzugreifen, daher wird eine Fehlermeldung angezeigt, wenn kein Objekt vorhanden ist (siehe unten). Was ist die beste Vorgehensweise?

SearchForm.java Der Typ, der an th: object =" $ {searchForm} " im Formular-Tag gebunden wird, das die Auswahlschaltfläche enthält. Der Variablenname sollte mit dem Argument der Methode in HTML und Controller übereinstimmen.

SearchForm.java


//Ein wenig Import etc.

public class SearchForm {
    @NotNull(message="Bitte geben Sie den Namen des Sängers ein")
    private String artistName;

   //Setter, Getter, Konstrukteur
}

InsertForm.java Der Typ, der an th: object =" $ {searchForm} " im Formular-Tag gebunden wird, das die Schaltfläche zum Einfügen enthält. Der Variablenname sollte mit dem Argument der Methode in HTML und Controller übereinstimmen.

InsertForm.java


public class InsertForm {
//Eine kleine Importanweisung etc.
    @NotNull(message="Die Eingabe des Namens des Sängers ist für die Registrierung erforderlich")
    private String artistName;

    @NotNull(message = "Die Eingabe des Songtitels ist für die Registrierung erforderlich")
    private String title;

    private String wordsWriter;
    private String musicComposer;
    private String lyric;
    private String url;

   //Setter, Getter, Konstrukteur
}

LyricController.java

LyricController.java


//Importanweisung usw.

//Lokal"http://localhost:8080/lyric"Die angeforderte Anforderung wird in dieser Klasse zugeordnet
@Controller
@RequestMapping("/lyric")
public class LyricController {
    //DI ohne neu
    private final LyricService lyricService;

    @Autowired
    public LyricController(LyricService lyricService) {
        this.lyricService = lyricService;
    }
    //Für den Modellschlüssel"insertCompleteMessage"Wenn ja, verwenden Sie es so wie es ist, wenn nicht hinzufügen
    @GetMapping("/form")
    public String form(Model model, @ModelAttribute("insertCompleteMessage") String message){
        model.addAttribute("title", "artist name");
        //Gibt die entsprechende Datei im Vorlagenordner zurück
        return "form.html";
    }
    //Ich erhalte eine Fehlermeldung im Ergebnis, wenn ich in der Validierungsanotation der SearchForm-Klasse gefangen werde
    @GetMapping("/select")
    public String select(@Validated SearchForm searchForm, BindingResult result, Model model){
        if(result.hasErrors()){
            model.addAttribute("title", "Error Page");
            return "form.html";
        }
        List<Lyric> list = lyricService.getSongs(searchForm.getArtistName());
        if(list.size()!=0){
            model.addAttribute("lyricList", list);
        }else{
            model.addAttribute("noResultMessage", "Das Lied des entsprechenden Künstlers ist nicht registriert");
        }
        return "list.html";
    }
    //Umleitungs- und Flash-Bereich für PRG(Attribute, die nach einer Anforderung verschwinden)verwenden
    @PostMapping("/insert")
    public String insert(@Validated InsertForm insertForm, BindingResult result, Model model, RedirectAttributes redirectAttributes){
        if(result.hasErrors()){
            model.addAttribute("title", "Error Page");
            return "form.html";
        }
        //Erstens gibt es nur ein Eingabeformular. DAO ist ein Listenformat, erstellen Sie also eine Liste mit einem Element
        List<Lyric> list = convertInsertForm(insertForm);
        //Schreiben Sie die Verarbeitung, wenn ein TDDO-Fehler vorliegt
        lyricService.insertSongs(list);
        //@GetMapping("/form")Weiterleiten an. Einstellungen für den Flash-Bereich.
        redirectAttributes.addFlashAttribute("insertCompleteMessage", "insert complete");
        return "redirect:form";
    }

    //Auch wenn SearchForm im obigen Argument nicht enthalten ist, wird es ohne Erlaubnis in das Modell aufgenommen. Der Methodenname kann beliebig sein.
    @ModelAttribute
    SearchForm setSearchForm(){
        return new SearchForm();
    }    

    @ModelAttribute
    InsertForm setInsertForm(){
        return new InsertForm();
    }

    //Konvertieren Sie von Inseart Form zu Lyric
    public static List<Lyric> convertInsertForm(InsertForm insertForm){
        List<Lyric> list = new ArrayList<>();
        Lyric lyric = new Lyric();
        lyric.setArtist(insertForm.getArtistName());
        lyric.setTitle(insertForm.getTitle());
        lyric.setWords_writer(insertForm.getWordsWriter());
        lyric.setMusic_composer(insertForm.getMusicComposer());
        lyric.setLyric(insertForm.getLyric());
        lyric.setUrl(insertForm.getUrl());
        list.add(lyric);
        return list;
    }

}

Was ist PRG?

Die letzte Umleitung von "@ PostMapping" heißt PRG, um eine doppelte Übertragung zu verhindern.

Wenn Sie das Ende auf "return form.html" setzen und HTML ohne Umleitung zurückgeben,

  1. Das Attribut bleibt in model → Das Objekt bleibt im Browser gebunden
  2. Die letzte Anforderung wird POST → POSTed, wenn der Browser aktualisiert wird Es stellt sich heraus, dass. Um dies zu verhindern
  3. Binden Sie das Modell ab
  4. Stellen Sie zwangsweise eine GET-Anfrage und geben Sie HTML zurück Es ist PRG (POST-REDIRECT-GET) zu tun.

Die Eigenschaft von "model" wird zum Zeitpunkt der Umleitung nicht vererbt (vom Debugger wurde bestätigt, dass das Form-Objekt im Modell zum Zeitpunkt der Umleitung initialisiert wird). Daher erfolgt die Antwort mit Ausnahme der Zeichen "Einfügen abgeschlossen" in "RedirectAttributes" im initialisierten Zustand. Darüber hinaus befindet sich die Meldung "Einfügen abgeschlossen" im Flash-Bereich (der mit einer einzelnen Anforderung verschwindet) und verschwindet, wenn Sie Ihren Browser aktualisieren.

list.html Das Objekt, das dem Schlüssel für "Modell" entspricht, kann auf der Serverseite mit "$ {Eigenschaftsname}" empfangen werden.

list.html


<!DOCTYPE html>
<html xmlns:th="http://www.thymeLeaf.org">
<head>
    <meta charset="UTF-8">
    <title th:text="${title}">Insert</title>
</head>
<body>
    <h1 th:text="${title}">title</h1>
    <p th:text="${noResultMessage}"></p>
    <table th:if="${lyricList}">
        <tr>
            <th>Artist Name</th><th>song title</th><th>lyric</th>
        </tr>
        <tr th:each="lyric:${lyricList}">
            <td th:text="${lyric.artist}"></td>
            <td th:text="${lyric.title}"></td>
            <td th:text="${lyric.lyric}"></td>
        </tr>
    </table>
</body>

form.html Hauptbildschirm. Zugriff unter http: // localhost: 8080 / lyric / form.

form.html


<!DOCTYPE html>
<html xmlns:th="http://www.thymeLeaf.org">
<head>
    <meta charset="UTF-8">
    <title th:text="${title}">Insert</title>
</head>
<body>
    <h1 th:text="${title}">title</h1>
    <h1 th:text="${redirectTitle}">title</h1>
    <form method="GET" action="#" th:action="@{/lyric/select}" th:object="${searchForm}">
        <label for="selArtistNameId">Artist Name:</label>
        <input id="selArtistNameId" name="artistName" type="text" th:value="*{artistName}">
        <div th:if="${#fields.hasErrors('artistName')}" th:errors="*{artistName}"></div>
        <input type="submit" value="search">
    </form>
    <h1>Songregistrierung</h1>
    <form method="POST" action="#" th:action="@{/lyric/insert}" th:object="${insertForm}">
        <label for="insArtistNameId">Artist Name:</label>
        <input id="insArtistNameId" name="artistName" type="text" th:value="*{artistName}">
        <div th:if="${#fields.hasErrors('artistName')}" th:errors="*{artistName}"></div>
        <label for="title">Song Title:</label>
        <input id="titleId" name="title" type="text" th:value="*{title}">
        <div th:if="${#fields.hasErrors('title')}" th:errors="*{title}"></div>
        <label for="wordsWriter">Text:</label>
        <input id="wordsWriterId" name="wordsWriter" type="text" th:value="*{wordsWriter}">
        <label for="musicComposer">Komposition:</label>
        <input id="musicComposerId" name="musicComposer" type="text" th:value="*{musicComposer}">
        <label for="lyric">Text:</label>
        <input id="lyricId" name="lyric" type="text" th:value="*{lyric}">
        <label for="url">Lyrics URL:</label>
        <input id="urlId" name="url" type="text" th:value="*{url}">
        <input type="submit" value="insert">
    </form>
    <p th:text="${insertCompleteMessage}"></p>
    <p th:if="${errorMessage}" th:text="'Fehlermeldung:'+${errorMessage}"></p>
</body>
</html>

Herausfinden

――Vorteile und Verhalten von DI

Referenz:

Dank der Aufnahme des Unternehmens in udemy for Business war GW beschäftigt, aber dieser Artikel basiert wahrscheinlich auf den folgenden Kursen. Der Inhalt ist völlig anders, aber es gibt einige Methoden, die so ausgeliehen werden, wie sie sind. https://www.udemy.com/course/java_spring_beginner/

Recommended Posts

Bis INSERT und SELECT für Postgres mit Spring Boot und Thymianblatt
Versuch, SSR Vue.js mit Spring Boot und GraalJS zu verwenden
Behandeln Sie die Java 8-Datums- und Uhrzeit-API mit Thymeleaf mit Spring Boot
Bis "Hallo Welt" mit Spring Boot
Stellen Sie mit spring boot + spring jpa eine Verbindung zur Datenbank her und führen Sie die CRUD-Operation durch
Fluss bis zur Ausgabe von Tabellendaten, die mit Spring Boot angezeigt werden sollen
8 Dinge, die mit Spring Boot und JPA in die DB eingefügt werden müssen
Implementieren Sie CRUD mit Spring Boot + Thymeleaf + MySQL
Implementieren Sie die Paging-Funktion mit Spring Boot + Thymeleaf
Fügen Sie Frühlingsstiefel und Gradle zur Sonnenfinsternis hinzu
Führen Sie die WEB-Anwendung mit Spring Boot + Thymeleaf aus
So wenden Sie Thymeleaf-Änderungen sofort mit #Spring Boot + maven auf den Browser an
Bis zur Datenerfassung mit Spring Boot + MyBatis + PostgreSQL
Verwendung von MyBatis2 (iBatis) mit Spring Boot 1.4 (Spring 4)
Verwendung des eingebauten h2db mit Federstiefel
Versuchen Sie, die Anmeldefunktion mit Spring Boot zu implementieren
Erstellen Sie eine CRUD-App mit Spring Boot 2 + Thymeleaf + MyBatis
Erstellen Sie Ihr eigenes Dienstprogramm mit Thymeleaf mit Spring Boot
Versuchen Sie, die Migration mit Spring Boot Flyway zu automatisieren
[Java] Artikel zum Hinzufügen einer Validierung mit Spring Boot 2.3.1.
Ich wollte Spring Boot in einem Multiprojekt gradle
[Einführung in Spring Boot] Authentifizierungsfunktion mit Spring Security
Frühlingsstiefel + Heroku Postgres
Mit Spring Boot herunterladen
Pläne zur Unterstützung von JDK 11 für Eclipse und Spring Boot
Einstellungen für die Verbindung zu MySQL mit Spring Boot + Spring JDBC
Versuchen Sie es mit einem DI-Container mit Laravel und Spring Boot
Wechseln Sie die Umgebung mit Spring Boot application.properties und @ Profile-Annotation
Ordnen Sie DTO automatisch Entitäten mit der Spring Boot-API zu
Wenn Sie die Spring Boot + Thymeleaf-Verarbeitung trennen möchten
Spring Boot mit Spring Security Filter-Einstellungen und Suchtpunkten
[Einführung in Spring Boot] Senden Sie ein Formular mit thymeleaf
Erstellen Sie Restapi mit Spring Boot (bis zum Ausführen der App)
Bis Sie mit der Entwicklung mit Spring Boot in Eclipse 1 beginnen
Booten nach Umgebung mit Spring Boot of Maven
Bis Sie mit der Entwicklung mit Spring Boot in Eclipse 2 beginnen
Verbinden Sie Spring Boot und Angular typsicher mit OpenAPI Generator
Bis Sie ein Spring Boot-Projekt in Intellij erstellen und an Github senden
Versuchen Sie Spring Boot von 0 bis 100.
Generieren Sie mit Spring Boot einen Barcode
Hallo Welt mit Spring Boot
Implementieren Sie GraphQL mit Spring Boot
Beginnen Sie mit Spring Boot
Implementieren Sie die REST-API mit Spring Boot und JPA (Application Layer).
Implementieren Sie die REST-API mit Spring Boot und JPA (Infrastructure Layer).
Schneiden Sie SQL in die Eigenschaftendatei mit jdbcTemplate von Spring Boot aus
Führen Sie LIFF mit Spring Boot aus
SNS-Login mit Spring Boot
Einführung in Spring Boot ~ ~ DI ~
Datei-Upload mit Spring Boot
Spring Boot beginnt mit dem Kopieren
Einführung in Spring Boot ② ~ AOP ~
Aufrufen und Verwenden der API in Java (Spring Boot)
Spring Boot beginnend mit Docker
Hallo Welt mit Spring Boot
Setzen Sie Cookies mit Spring Boot
Verwenden Sie thymeleaf3 mit parent, ohne Spring-Boot-Starter-Parent in Spring Boot anzugeben
Verwenden Sie Spring JDBC mit Spring Boot
Hash beim Spring-Boot das Passwort und verwenden Sie die Mitgliederregistrierung und die Spring-Sicherheit, um die Anmeldefunktion zu implementieren.
Modul mit Spring Boot hinzufügen