Grails ist ein Full-Stack-Framework, das entwickelt wurde, um viele der Herausforderungen der Webentwicklung durch Kerntechnologie und verwandte Plugins zu lösen.
Während viele Web-Frameworks in der Java-Welt komplex sind und keine DRY-Prinzipien berücksichtigen, baut Grails auf dynamischen Framework-Konzepten auf, die zu modernem Denken über Webanwendungen wie Rails und Django geführt haben. , Basiert auf vorhandenen Java-Technologien wie Spring und Hibernate.
Referenz http://docs.grails.org/latest/guide/single.html#requirements
Ich habe die folgende Version im Artikel verwendet.
Wir haben den Vorgang nur unter Ubuntu 16 bestätigt. Weitere Informationen finden Sie in der SDKMAN-Dokumentation (https://sdkman.io/).
Installieren Sie SDKMAN (siehe SDKMAN-Installation (https://sdkman.io/install))
Installieren Sie Java
$ sdk install java
Installiere Grails
$ sdk install grails
C: \ grails
usw.)grails -version
aus und wenn die Grails-Version angezeigt wird, ist die Installation abgeschlossen.Verwenden Sie beim Erstellen einer Grails-Anwendung den Befehl grails create-app, um die erforderlichen Dateien in großen Mengen zu erstellen.
$ cd ${Zielverzeichnis der Anwendung speichern}
$ grails create-app grails-sample-app
# grails-sample-Ändern Sie die App entsprechend in den Anwendungsnamen.
# "grails-sample-app"Ein Verzeichnis wird erstellt
#Der Paketname der Anwendung lautet"grails.sample.app"Wird sein.
Grails Sie können auch einen Modus verwenden, in dem Sie jeden Befehl interaktiv ausführen können. Der interaktive Modus ist verfügbar, wenn Sie den Befehl grails
ohne Optionen ausführen und den Befehl im interaktiven Modus mit der Tabulatortaste ausführen können.
Führen Sie den Befehl run-app
aus, um die Anwendung auszuführen.
Führen Sie die Grails-Anwendung aus(Wenn Sie den interaktiven Grails-Modus nicht verwenden)
$ cd ${create-App Zielverzeichnis speichern}
$ grails run-app
Führen Sie die Grails-Anwendung aus(Bei Verwendung des interaktiven Grails-Modus)
$ cd ${create-App Zielverzeichnis speichern}
$ grails #Starten Sie Grails im interaktiven Modus
grails> run-app
Nachdem Sie die Anwendung mit run-app ausgeführt haben, greifen Sie auf http: // localhost: 8080 / zu, und Sie sehen den Grails-Intro-Bildschirm wie unten gezeigt. (Der Bildschirm zeigt den HelloController, der zusätzlich zu der von create-app erstellten Datei erstellt wurde.)
.gradle/
.idea/ ...Konfigurationsdatei für IntelliJ IDE
build/ ...Datei erstellen(create-Existiert nicht sofort nach dem Ausführen der App)
gradle/
grails-app/ ...Quellcode der Anwendung
assets/ ...Speicherung von Ressourcen(Von der Asset-Pipeline verarbeitete Dateien)
conf/ ...Laufzeiteinstellungen
controllers/ ...Regler(MVC Modell C.)
${App Name}/ ...App Name(Wenn Bindestriche enthalten sind, wird das Verzeichnis für jeden Bindestrich getrennt)
UrlMappings.groovy ...URL-Zuordnung
domain/ ...Domänenklasse(MVC Modell M.)
i18n/ ... internationalization(i18n)Konfigurationsunterstützung
init/ ...Verarbeitung beim Start der Anwendung
services/ ...Serviceschicht
taglib/ ...Tag-Bibliothek(Definierte benutzerdefinierte Tags, die in der Ansicht verwendet werden können)
utils/ ...Grails-spezifischer Nutzen
views/ ... Groovy Server Page(GSP) or JSON Views (MVC Modell V.)
src/
integration-test/ ...Integrationstest
main/ ...Statische Datei, die keine Asset-Pipeline-Verarbeitung durchläuft
groovy/ ...Domänenklasse, die Sie der DB-Tabelle nicht zuordnen möchten
webapp/ ...Statische Datei(In WAR enthalten, nicht in JAR)
resources/public ...Statische Datei(/static/x/y/Zugang mit z)
test/ ...Gerätetest
groovy/
${App Name}/
${***Spec}.groovy
.gitignore ...Nicht verwaltete VCS-Dateieinstellungen für Git
build.gradle ...Einstellungen erstellen
gradle.properties ...Gradle-Einstellungen
gradlew ...Gradle-Startskript(UN*Für X.)
gradlew.bat ...Gradle-Startskript(Für Windows)
grails-wrapper.jar
grailsw ...Grails startet Skript(UN*Für X.)
grailsw.bat ...Grails startet Skript(Für Windows)
README.md ... README
Genaue Information
Lassen Sie uns "Hello World!" Als Zeichenkette anzeigen.
Wenn Sie in Grails einen Controller erstellen und eine Aktion in dieser Klasse beschreiben, wird dieser einer eindeutigen URL zugeordnet und kann von einem Browser aufgerufen werden.
Die Zuordnungsregel lautet "/
Gehen Sie wie folgt vor, um einen "HelloController" zu erstellen und die "Index" -Aktion "HelloWorld" anzuzeigen:
Führen Sie die Grails-Anwendung aus
grails> create-controller hello #HelloController-Klasse wird erstellt
Bearbeiten Sie die in grails-app / controller / grails / sample / app / HelloController.groovy
erstellte HelloController-Klasse mit den folgenden Inhalten.
grails-app/controllers/grails/sample/app/HelloController.groovy
package grails.sample.app
class HelloController {
def index() {
render "Hello World!"
}
}
Wenn Sie die Anwendung ausführen und auf http: // localhost: 8080 / hello / index oder http: // localhost: 8080 / hello / zugreifen, wird die Zeichenfolge "Hello World!" Angezeigt. (Die Indexaktion kann in der URL weggelassen werden.)
Die Domäne ist M von MVC in Grails. Sie können einzelne Controller und Ansichten wie im vorherigen HelloWorld-Anzeigebeispiel erstellen, aber Sie können die Option "Alles generieren" verwenden, um Controller und Ansichten mit CRUD-Funktionalität für Ihre Domäne zu erstellen (plus zum Testen). Sie können eine Klasse erstellen).
Erstellen Sie eine Mitarbeiterdomänenklasse, einen Controller für CRUD, eine Ansicht und einen Test
#Erstellen Sie eine Mitarbeiterdomänenklasse
$ grails create-domain-class employee
| Created grails-app/domain/grails/sample/app/Employee.groovy
| Created src/test/groovy/grails/sample/app/EmployeeSpec.groovy
#Erstellen Sie Controller-, Ansichts- und Testklassen für CRUD Employee-Domänenklassen
$ grails generate-all grails.sample.app.Employee
| Rendered template Controller.groovy to destination grails-app\controllers\grails\sample\app\EmployeeController.groovy
| Rendered template Service.groovy to destination grails-app\services\grails\sample\app\EmployeeService.groovy
| Rendered template Spec.groovy to destination src\test\groovy\grails\sample\app\EmployeeControllerSpec.groovy
| Rendered template ServiceSpec.groovy to destination src\integration-test\groovy\grails\sample\app\EmployeeServiceSpec.groovy
| Scaffolding completed for grails-app\domain\grails\sample\app\Employee.groovy
| Rendered template create.gsp to destination grails-app\views\employee\create.gsp
| Rendered template edit.gsp to destination grails-app\views\employee\edit.gsp
| Rendered template index.gsp to destination grails-app\views\employee\index.gsp
| Rendered template show.gsp to destination grails-app\views\employee\show.gsp
| Views generated for grails-app\domain\grails\sample\app\Employee.groovy
Sie haben jetzt die Möglichkeit erstellt, die Domänenklasse "Mitarbeiter" zu CRUDEN.
Die Domänenklasse hat noch keine Attribute. Bearbeiten Sie daher die Datei "grails-app / domain / grails / sample / app / Employee.groovy" und fügen Sie die entsprechenden Attribute hinzu.
grails-app/domain/grails/sample/app/Employee.groovy
package grails.sample.app
class Employee {
String name
static constraints = {
}
}
Wenn ich run-app erneut starte, um den TOP-Bildschirm der Anwendung im Browser anzuzeigen, wird grails.sample.app.EmployeeController
zu Available Controllers hinzugefügt :.
Die Zeichenfolge von grails.sample.app.EmployeeController ist ein Link. Wenn Sie darauf klicken, gelangen Sie zum Bildschirm Mitarbeiterliste (http: // localhost: 8080 / employee / index).
Bildschirm mit der Mitarbeiterliste |
---|
Wie Sie bei einigen Vorgängen sehen können, wurden die folgenden Routen hinzugefügt.
Wurzel | Funktion |
---|---|
GET /employee/index | Bildschirm "Mitarbeiterliste" anzeigen |
GET /employee/create | Bildschirm "Mitarbeiter neu erstellen" anzeigen |
GET /employee/show/:id | Bildschirm mit Mitarbeiterdetails(:id ist die ID der Domänenklasse)Show |
GET /employee/edit/:id | Bildschirm zum Bearbeiten von Mitarbeitern(:id ist die ID der Domänenklasse)Show |
POST /employee/save | Mitarbeiter neue Kreation |
PUT /employee/update/:id | Mitarbeiter-Update(:id ist die ID der Domänenklasse) |
DELETE /employee/delete/:id | Mitarbeiter gelöscht(:id ist die ID der Domänenklasse) |
Die von der Anwendung verwendete Datenbank kann für jede Umgebungsvariable wie Entwicklung, Test und Produktion geändert werden. Grails verwendet standardmäßig in allen Umgebungen H2-Datenbank.
Sie werden auch feststellen, dass die Datenbank initialisiert wird, wenn Sie den CRUD-Vorgang beenden, run-app beenden und die Anwendung erneut ausführen. Dies liegt daran, dass H2 eine speicherinterne Datenbank ist und die Datenbank in der Entwicklungsumgebung so eingestellt ist, dass die Datenbank am Ende der Anwendung TROPFEN und beim Start erstellt wird.
Diese Einstellungen werden in grails-app / conf / application.yml festgelegt. (Weitere Informationen zu den Einstellungen finden Sie unter The Grails Framework> The DataSource.)
Dieses Mal werden wir festlegen, dass die in der Entwicklungsumgebung erstellte Datenbank nicht zerstört wird.
Schreiben Sie grails-app / conf / application.yml
mit dem folgenden Inhalt neu.
grails-app/conf/application.yml
environments:
development:
dataSource:
# create-Wechseln Sie von Drop zu Update
dbCreate: update
# mem:von devDb./Wechseln Sie zu devDb
url: jdbc:h2:./devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
Folgende Werte können mit dbCreate festgelegt werden.
dbEinstellungen erstellen | Erläuterung |
---|---|
create | Vorhandenes Schema beim Start(Tabelle,Index,andere)Löschen und neu erstellen |
create-drop | Entspricht dem Erstellen, löscht jedoch die Tabelle beim Beenden der Anwendung |
update | Erstellen oder aktualisieren Sie eine nicht vorhandene Tabelle oder einen nicht vorhandenen Index. Löschen Sie keine vorhandenen Tabellen oder Daten.(Beachten Sie, dass alte Spalten und Daten erhalten bleiben, da Änderungen des Spaltennamens nicht ordnungsgemäß behandelt werden können.) |
validate | Geben Sie eine Warnung aus, indem Sie das vorhandene Schema und die Einstellungen vergleichen, ohne Änderungen an der Datenbank vorzunehmen |
any other value | nichts tun |
def p = new Person(name: "Fred", age: 40, lastVisit: new Date())
p.save()
def p = Person.get(1)
println('name: ' + p.name)
org.hibernate.ObjectNotFoundException
tritt auf, wenn eine andere Methode als getId () aufgerufen wirddef p = Person.get(1)
p.name = 'Bob'
p.save()
def p = Person.get(1)
p.delete()
Lassen Sie uns die Employee-Domain-Klasse etwas erweitern und praktischer gestalten.
grails-app/domain/grails/sample/app/Employee.groovy
package grails.sample.app
class Employee {
String name
String department
String gender
Date birth
Date joinedDate
Long payment
String note
static constraints = {
name blank: false, unique: true
department blank: false
gender blank: false, inList: ['male', 'female', 'other']
birth blank: false
joinedDate blank: false
payment min: new Long(0), blank: false
note blank: true
}
/**
*Dienstalter
*/
public int serviceYears() {
def today = new Date()
return Math.max(0, today.year - this.joinedDate.year)
}
}
Bis auf den Hinweis setze ich vorerst "nullable: false" (da dies Standard ist, wird es nicht in Einschränkungen angegeben) und "blank: false". Wenn Sie wie in Anmerkung "leer: wahr" setzen, müssen Sie den Konvertierungsprozess in null deaktivieren, wenn die Daten leer sind.
Die Einstellung kann deaktiviert werden, indem application.groovy
wie folgt eingestellt wird.
Wenn die Datei nicht existiert, erstellen Sie sie unter "grails-app / conf /".
grails-app/conf/application.groovy
// the default value for this property is true
grails.databinding.convertEmptyStringsToNull = false
Ändern Sie nun den Listenbildschirm und den Bearbeitungsbildschirm, um Mitarbeiter wie folgt anzuzeigen.
Listenbildschirmansicht(grails-app/views/employee/index.gsp)
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main" />
<g:set var="entityName" value="${message(code: 'employee.label', default: 'Employee')}" />
<title><g:message code="default.list.label" args="[entityName]" /></title>
<script type="text/javascript">
/*Legen Sie den Status der Bearbeitungsschaltfläche basierend auf dem Optionsfeldstatus fest*/
function setEditButtonStatusByRadioButton() {
var edit_button_id = "edit_button";
var radios = document.getElementsByName('id');
var checkedNum = 0;
radios.forEach(e => e.checked && checkedNum++);
if (checkedNum > 0) {
document.getElementById(edit_button_id).disabled = false;
} else {
document.getElementById(edit_button_id).disabled = true;
}
}
</script>
</head>
<body>
<a href="#list-employee" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content…"/></a>
<div class="nav" role="navigation">
<ul>
<li><a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
<li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
</ul>
</div>
<div id="list-employee" class="content scaffold-list" role="main">
<h1><g:message code="default.list.label" args="[entityName]" /></h1>
<g:if test="${flash.message}">
<div class="message" role="status">${flash.message}</div>
</g:if>
<g:form action="edit">
<table class="table table-striped">
<thead>
<tr>
<th>Edit</th>
<g:each in="${['id', 'name', 'department', 'gender']}" var="p">
<g:sortableColumn property="${p}" title="${p}" />
</g:each>
</tr>
</thead>
<tbody>
<g:each in="${employeeList}" var="employee">
<tr>
<td><input name="id" type="radio" value="${employee.id}" onclick="setEditButtonStatusByRadioButton()" /></td>
<g:each in="${['id', 'name', 'department', 'gender']}" var="p">
<g:if test="${p=='id'}">
<td><g:link method="GET" resource="${employee}">${employee.properties[p]}</g:link></td>
</g:if>
<g:else>
<td>${employee.properties[p]}</td>
</g:else>
</g:each>
</tr>
</g:each>
</tbody>
</table>
<button disabled="false" id="edit_button"><g:message code="default.edit.label" args="[entityName]" /></button>
</g:form>
<div class="pagination">
<g:paginate total="${employeeCount ?: 0}" />
</div>
</div>
</body>
</html>
Detailbildschirmansicht(grails-app/views/employee/show.gsp)
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main" />
<g:set var="entityName" value="${message(code: 'employee.label', default: 'Employee')}" />
<title><g:message code="default.show.label" args="[entityName]" /></title>
</head>
<body>
<a href="#show-employee" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content…"/></a>
<div class="nav" role="navigation">
<ul>
<li><a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
<li><g:link class="list" action="index"><g:message code="default.list.label" args="[entityName]" /></g:link></li>
<li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
</ul>
</div>
<div id="show-employee" class="content scaffold-show" role="main">
<h1><g:message code="default.show.label" args="[entityName]" /></h1>
<g:if test="${flash.message}">
<div class="message" role="status">${flash.message}</div>
</g:if>
<ol class="property-list employee">
<li class="fieldcontain">
<g:each in="${['id', 'name', 'department', 'gender', 'birth', 'serviceYears', 'payment', 'note']}" var="p">
<span id="name-label" class="property-label">${p}</span>
<g:if test="${p=='serviceYears'}">
<div class="property-value" aria-labelledby="name-label">${employee.serviceYears()}</div>
</g:if>
<g:else>
<div class="property-value" aria-labelledby="name-label">${employee.properties[p]}</div>
</g:else>
</g:each>
</li>
</ol>
<g:form resource="${this.employee}" method="DELETE">
<fieldset class="buttons">
<g:link class="edit" action="edit" resource="${this.employee}"><g:message code="default.button.edit.label" default="Edit" /></g:link>
<input class="delete" type="submit" value="${message(code: 'default.button.delete.label', default: 'Delete')}" onclick="return confirm('${message(code: 'default.button.delete.confirm.message', default: 'Are you sure?')}');" />
</fieldset>
</g:form>
</div>
</body>
</html>
Das ist etwas praktischer.
Die Ansicht wird in Groovy Server Pages (GSP) beschrieben, und <g: link>
, <g: form>
usw. sind GSP-Tags. (Weitere Informationen finden Sie unter Groovy Server Pages (GSP).)
Grails 3.3.5 führte standardmäßig Bootstrap 3.3.6 ein.
Es scheint Twitter-Bootstrap-Grails-Plugin des Grails-Plugins zu geben, aber die aktuelle Version ist 3.3.5 am 18. September '18. Es scheint, dass das endgültige Commit vor zwei Jahren stattgefunden hat, daher scheint es nicht gut gepflegt zu sein. Deshalb habe ich beschlossen, Bootstrap v4 manuell einzuführen.
grails-app / assets / javascripts / application.js
// = erfordern jquery-2.2.0.min
zu // = erfordern jquery-3.3.1.min
Führen Sie die Anwendung erneut aus und Sie sind fertig. (Navbar bricht zusammen, aber ich benutze es nicht, also ignoriere es)
Lassen Sie uns die zuvor beschriebene index.gsp-Ansicht bearbeiten.
grails-app/views/layouts/main.gsp
<head>
: <snip>
<asset:stylesheet src="application.css"/>
<asset:javascript src="application.js"/> <!--Bewegen Sie die im Körper geschriebene Linie in den Kopf-->
: <snip>
</head>
: <snip>
grails-app/views/employee/index.gsp
: <snip>
<button class="btn btn-secondary" disabled="false" id="edit_button"><g:message code="default.edit.label" args="[entityName]" /></button>
: <snip>
Es ist in Ordnung, wenn auf die Schaltfläche der Bootstrap 4-Stil angewendet wird.
Fügen wir dem Bildschirm "Mitarbeiterliste" eine Filterfunktion hinzu, um ihn ein wenig praktischer zu gestalten.
Ich werde DataTables verwenden, um die Suchfunktion diesmal zu der Tabelle hinzuzufügen, die auf dem Listenbildschirm angezeigt wird.
Es gab grails-datatables als Grails-Plugin, aber installieren Sie die neueste Version von DataTables wie Bootstrap und jquery. Ich werde entscheiden.
Wählen Sie die folgenden Elemente auf der DataTables-Download-Seite aus, um die Datei herunterzuladen.
Kopieren Sie die folgenden Dateien aus der heruntergeladenen Datei entsprechend dem Typ in grails-app / assets / (javascripts | stylesheets) /.
Zum Schluss bearbeiten Sie grails-app / assets / application (Js | css). Die in der Anwendung beschriebenen erforderlichen Zieldateien (js | css) werden in der Reihenfolge von oben gelesen. Achten Sie daher auf die Beschreibungsreihenfolge für Pakete mit Abhängigkeiten.
grails-app/assets/javascripts/application.js
: <snip>
//= require jquery-3.3.1.min
//= require bootstrap.bundle
//= require jquery.dataTables
//= require dataTables.bootstrap4
//= require_tree .
//= require_self
: <snip>
grails-app/assets/stylesheets/application.css
/*
: <snip>
*= require bootstrap
*= require dataTables.bootstrap4
*= require grails
*= require main
*= require mobile
*= require_self
: <snip>
*/
Jetzt können Sie DataTables verwenden.
Wenden Sie DataTables auf die Tabellen im Listenbildschirm an.
Wenden Sie zum Anwenden von DataTables die Methode "dataTable ()" auf das DOM an, das auf die Tabelle verweist, die Sie in jQuery anwenden möchten.
grails-app/views/employee/index.gsp
<!DOCTYPE html>
<html>
<head>
: <snip>
<script type="text/javascript">
/*Legen Sie den Status der Bearbeitungsschaltfläche basierend auf dem Optionsfeldstatus fest*/
function setEditButtonStatusByRadioButton() {
var edit_button_id = "edit_button";
var radios = document.getElementsByName('id');
var checkedNum = 0;
radios.forEach(e => e.checked && checkedNum++);
if (checkedNum > 0) {
document.getElementById(edit_button_id).disabled = false;
} else {
document.getElementById(edit_button_id).disabled = true;
}
}
$(document).ready(function() {
$('#employeeindex').dataTable();
} );
</script>
</head>
<body>
: <snip>
<table id="employeeindex" class="display table table-striped">
: <snip>
</table>
: <snip>
</body>
</html>
Wenn Sie die Anwendung ausführen, können Sie sehen, dass DataTables angewendet wurde.
Hier können Sie sehen, dass die Paginierungsfunktionen von DataTables und Grails überflüssig geworden sind.
Welche Funktion aktiviert werden soll, hängt vom Design der Anwendung ab. Dieses Mal verlassen wir jedoch die Paginierungsfunktion von Grails, um die Datenverarbeitung zu reduzieren.
Um die Paginierungsfunktion von DataTables zu deaktivieren, fügen Sie der dataTable () -Methode den Parameter "paging: true" hinzu, wie auf der offiziellen Seite (https://datatables.net/reference/option/paging) beschrieben. Ich werde es bestehen.
#Wenden Sie DataTables ohne Paginierung auf das Index-DOM an
$(document).ready(function() {
$('#employeeindex').dataTable({
"paging": false
});
} );
Ändern Sie abschließend die Navigationsleiste am oberen Bildschirmrand. Ändern Sie außerdem den Stil entsprechend und fügen Sie Font Awesome im CDN hinzu, um ICON zu verwenden.
grails-app/assets/stylesheets/main.css
/* NAVIGATION MENU */
.nav, nav {
zoom: 1;
}
.nav ul {
overflow: hidden;
padding-left: 0;
zoom: 1;
}
.nav li {
display: block;
float: left;
list-style-type: none;
margin-right: 0.5em;
padding: 0;
}
.nav a, nav a {
color: #666666;
display: block;
padding: 0.25em 0.7em;
text-decoration: none;
-moz-border-radius: 0.3em;
-webkit-border-radius: 0.3em;
border-radius: 0.3em;
}
.nav a:active, .nav a:visited, nav a:active, nav a:visited {
color: #666666;
}
.nav a:focus, .nav a:hover, nav a:focus, nav a:hover {
background-color: #999999;
color: #ffffff;
outline: none;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8);
}
.no-borderradius .nav a:focus, .no-borderradius nav a:focus, .no-borderradius .nav a:hover, .no-borderradius nav a:hover {
background-color: transparent;
color: #444444;
text-decoration: underline;
}
.nav a.home, .nav a.list, .nav a.create, nav a.home, nav a.list, nav a.create {
background-position: 0.7em center;
background-repeat: no-repeat;
text-indent: 25px;
}
.nav a.home, nav a.home {
background-image: url(../images/skin/house.png);
}
.nav a.list, nav a.list {
background-image: url(../images/skin/database_table.png);
}
.nav a.create, nav a.create {
background-image: url(../images/skin/database_add.png);
}
.nav li.dropdown ul.dropdown-menu, nav li.dropdown ul.dropdown-menu {
background-color: #424649;
}
grails-app/assets/stylesheets/mobile.css
@media screen and (max-width: 480px) {
.nav, nav {
padding: 0.5em;
}
.nav li, nav li {
margin: 0 0.5em 0 0;
padding: 0.25em;
}
: <snip>
}
grails-app/views/layouts/main.gsp
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>
<g:layoutTitle default="Grails"/>
</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<asset:link rel="icon" href="favicon.ico" type="image/x-ico" />
<asset:stylesheet src="application.css"/>
<asset:javascript src="application.js"/>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous">
<g:layoutHead/>
</head>
<body>
<nav class="navbar-expand-lg pr-3 navbar navbar-default">
<a class="navbar-brand" href="/#">
<asset:image src="grails.svg" alt="Grails Logo"/>
</a>
<button class="navbar-toggler mx-2" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="fas fa-bars" style="font-size: 3rem;"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav ml-auto">
<g:pageProperty name="page.nav" />
</ul>
</div>
</nav>
<g:layoutBody/>
<div class="footer" role="contentinfo"></div>
<div id="spinner" class="spinner" style="display:none;">
<g:message code="spinner.alt" default="Loading…"/>
</div>
</body>
</html>
Large Display Size | Small Display Size |
---|---|
Bisher wurde die Datenbank aktualisiert, indem "dbCreate: update" unter Bezugnahme auf die Modelldatei beim Starten der Anwendung festgelegt wurde. Aufgrund der begrenzten Bedingungen, die geändert werden können und die alten Spalten verbleiben, bleiben jedoch mehrere Personen übrig Bei der Entwicklung einer Anwendung können unterschiedliche Personen unterschiedliche Datenbankstrukturen haben.
Aus diesem Grund habe ich beschlossen, eine Migrationsdatei zu erstellen und daraus eine Datenbank zu erstellen.
Verwenden Sie das Plug-In "Datenbankmigration", um die Datenbankmigration in Grails durchzuführen. (Das Plugin "Datenbankmigration" verwendet die Bibliothek Liquibase.)
Die Migration erfolgt über eine oder mehrere Änderungsprotokolldateien, die in Groovy DSL oder nativem Liquibase XML geschrieben sind.
Änderungsprotokolldateien haben eine global eindeutige ID. (Die ID enthält den Benutzernamen des Benutzers, der das Änderungsprotokoll erstellt hat.)
Bearbeiten Sie "bundle.gradle" wie folgt, um das Plug-In "Datenbankmigration" zu verwenden. (Ändern Sie die Plug-Version entsprechend)
Beachten Sie, dass "bundle.gradle" eine Konfigurationsdatei für Gradle ist und Gradle ein Open-Source-Build-Automatisierungssystem ist, das auf den Konzepten von Apache Ant und Apache Maven basiert. (Referenz: Wikipedia> Gradle)
buildscript {
repositories {
: <snip>
}
dependencies {
: <snip>
classpath 'org.grails.plugins:database-migration:3.0.4' # database-Migrations-Plug-In hinzugefügt
}
}
dependencies {
: <snip>
compile 'org.grails.plugins:database-migration:3.0.4'
compile 'org.liquibase:liquibase-core:3.5.5'
: <snip>
}
: <snip>
sourceSets {
main {
resources {
srcDir 'grails-app/migrations'
}
}
}
Setzen Sie dann die Datenbank dbCreate
auf none
.
Andernfalls erhalten Sie keinen Unterschied, wenn Sie eine Migrationsdatei mit der Option "dbm-gorm-diff" erstellen.
grails-app/conf/application.yml
environments:
development:
dataSource:
dbCreate: none
url: jdbc:h2:./devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
: <snip>
Erstellen Sie als Nächstes eine Änderungsprotokolldatei.
Sie können das Beschreibungsformat wählen, aber ich werde Groovy DSL verwenden.
Es gibt zwei Möglichkeiten, ein Änderungsprotokoll zu erstellen: eine stammt aus der Datenbank und die andere aus der Domänenklasse. Im Moment denke ich, dass die Datenbank beim Start automatisch aus der Domänenklasse erstellt wird. Wählen Sie daher die Methode zum Erstellen des Änderungsprotokolls aus der Datenbank aus.
So erstellen Sie ein Änderungsprotokoll aus einer Datenbank im Groovy DSL-Format
$ grails dbm-generate-changelog changelog.groovy
: <snip>Plugins werden nach Bedarf heruntergeladen
:compileJava NO-SOURCE
:compileGroovy UP-TO-DATE
:buildProperties UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:findMainClass
:dbmGenerateChangelog
BUILD SUCCESSFUL
Total time: 16.478 secs
Anschließend wird das folgende Änderungsprotokoll erstellt.
Änderungsprotokoll(grails-app/migrations/changelog.groovy)
databaseChangeLog = {
changeSet(author: "tatsurou (generated)", id: "1537102923747-1") {
createTable(tableName: "EMPLOYEE") {
column(autoIncrement: "true", name: "ID", type: "BIGINT(19)") {
constraints(primaryKey: "true", primaryKeyName: "CONSTRAINT_7")
}
column(name: "VERSION", type: "BIGINT(19)") {
constraints(nullable: "false")
}
column(name: "NAME", type: "VARCHAR(255)") {
constraints(nullable: "false")
}
}
}
}
Jetzt können Sie die Datenbank basierend auf dem Änderungsprotokoll erstellen. (Es wird nur das Datenbankschema erstellt, es werden keine Daten migriert.)
Von nun an erstellen Sie nach dem Bearbeiten der Domänenklasse manuell oder automatisch ein Änderungsprotokoll und führen "dbm-update" aus.
$ grails dbm-gorm-diff add_birth_column_to_employee.groovy --add
Die Groovy-Konsole ist eine Anwendung, mit der Sie Groovy-Quellcode eingeben und ausführen können. Sie können auch eine in einer Grails-Anwendung implementierte Domänenklasse laden oder das ORM dieser Domänenklasse verwenden, um die Datenbank zu bearbeiten.
Sie können die Grails-Konsole starten, indem Sie den Befehl grails console ausführen.
Starten Sie die groovige Konsole
$ cd ${Anwendungsverzeichnis}
$ grails console
package grails.sample.app
def id = 1
def e = Employee.get(id)
if (e == null) {
println("Not found employee id " + id)
exit()
}
println("employee: " + e)
println("name: " + e.name)
e.name = 'test99'
e.save(flush: true)
Beschreibt die Fehler, die beim Ausführen des Befehls Grails auftreten, und wie mit ihnen umgegangen werden soll.
Could not acquire change log lock
Command execution error: Could not acquire change log lock. Currently locked by ${COMPUTER_NAME} (${IP_ADDRESS}) since 18/09/17 0:09
grails dbm-release-locks
oder DBRecommended Posts