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 ...
https://github.com/PG-practice/lyricWall/tree/simple_ui_connect_db
model
und geben Sie HTML zurück.
--PRG (POST-REDIRECT-GET), eine der Maßnahmen zur Verhinderung einer doppelten Übertragung
--Multiple INSERT bis zum Frühjahr jdbc + vorbereitete Anweisung scheint langsam zu sein?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)
);
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')
}
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: ""
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)
}
@ Entity
nicht hinzugefügt (vielleicht weil ich nicht DI?)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;
}
}
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,
model
→ Das Objekt bleibt im Browser gebundenDie 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>
@ ModelAttribute
ist in Ordnung, da der Wert nicht automatisch dem nicht verwandten Formular zugeordnet wurde.model
packen und zurückgeben, erhalten Sie einen White-Label-Fehler aufgrund von etwas wie th: value =" $ * {artistName} "
. Aus diesem Grund erstellt der Fehlerhandler von "WebMvcControllerAdvice.java" absichtlich eine Instanz und fügt sie in "model" ein.――Vorteile und Verhalten von DI
<div th:if="${#fields.hasErrors('title')}" th:errors="*{title}"></div>
--Was ist die jsesessionid, die nach dem POST in der URL angezeigt wird?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