文章目录
Grails4.0.11介绍相关依赖入门⎮Java环境搭建⎮Grails环境搭建⎮如何创建grails应用⎮如何选择开发工具IDEA如何导入Grails项目
⎮目录结构,约定优于配置⎮如何部署Grails项目1. 使用默认内嵌的Tomcat8部署2. 使用外部Tomtcat8部署3. 使用外部Tomcat7部署
⎮Grails4支持的JavaEE容器有哪些⎮如何快速创建控制器和领域类1. 创建领域类2. 使用脚手架创建控制器和视图3. 使用脚手架生成的代码为我们实现了哪些功能3.1 - 书籍列表页面3.2 - 添加书籍页面3.3 - 书籍详情页面3.4 - 修改书籍页面3.5 - 删除书籍页面3.6 - 小结
⎮完成入门
Grails4.0.11
介绍
Grails 是一个全栈框架,它建立在已存在的 Java 技术(如 Spring 和 Hibernate)之上。 Grails核心技术及其相关插件解决了很多 Web 开发难题,降低了在 Java 平台上构建 Web 应用程序的复杂性。 Grails提供了开箱即用的功能:
GORM - 一个易于使用的对象映射库,支持 SQL、MongoDB、Neo4j 等。查看用于呈现 HTML 和 JSON 的技术基于 Spring Boot 构建的控制器层一个包含数百个插件的插件系统使用 AngularJS、React 等创建应用程序的灵活配置文件基于 Gradle 的交互式命令行环境和构建系统一个嵌入式 Tomcat 容器,配置为即时重新加载
相关依赖
GroovyGORMHibernateSpringFrameworkSpringBootGradleSpock2.5.1475.45.1.202.1.185.6.41.3
入门
⎮Java环境搭建
在安装 Grails 4.0.11 之前,至少需要安装JDK1.8版本才行,并且设置JAVA_HOME 的环境变量。
JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home"
export PATH=".:$PATH:$JAVA_HOME/bin"
export JAVA_HOME
⎮Grails环境搭建
下载 Grails4.0.11 的二进制发行版并将生成的 zip 文件解压缩到/opt目录。设置GRAILS_HOME环境变量,编辑~/.bash_profileexport GRAILS_HOME=/opt/grails-4.0.11
然后将 bin 目录添加到您的 PATH 变量中:export PATH="$PATH:$GRAILS_HOME/bin"
打开新的命令行窗口,输入命令 grails -version查看输出内容➜ /Users/xiaosan > grails -version
| Grails Version: 4.0.11
| JVM Version: 1.8.0_171
⎮如何创建grails应用
进入要创建项目的目录 ➜ /Users/xiaosan >cd Documents/work 使用create-app命令创建应用
➜ /Users/xiaosan/Documents/work >grails create-app helloworldgrails4
| Application created at /Users/xiaosan/Documents/work/helloworldgrails4
该命令会创建一个helloworldgrails4的项目目录,进入项目目录 ➜ /Users/xiaosan/Documents/work >cd helloworldgrails4 输入grails命令,启动 Grails 交互式控制台 ➜ /Users/xiaosan/Documents/work >grails 等待几秒会看到如下提示:
| Resolving Dependencies. Please wait...
| Starting interactive mode...
| Enter a command name to run. Use TAB for completion:
grails>
我们想要的是一个简单的页面,它只打印消息“Hello World!”到浏览器。在 Grails 中,无论何时您想要一个新页面,您只需为它创建一个新的控制器操作。由于我们还没有控制器,让我们现在使用 create-controller 命令创建一个:
grails> create-controller hello
| Created grails-app/controllers/helloworldgrails4/HelloController.groovy
| Created src/test/groovy/helloworldgrails4/HelloControllerSpec.groovy
创建hello时没有指定包名,默认以项目名称helloworldgrails4作为包名。 在输入命令时可以使用tab键,会自动补全命令或者提示命令。 查看HelloController.groovy文件:
package helloworldgrails4
class HelloController {
def index() { }
}
修改这个控制器,添加一个动作来生成“Hello World”页。
package helloworldgrails4
class HelloController {
def index() {
render "Hello World!"
}
}
动作只是一种方法。在这种特殊情况下,它调用 Grails 提供的特殊方法来呈现页面。 在grails交互控制台中启动项目:
grails> run-app
| Running application...
The Class-Path manifest attribute in /Users/xiaosan/.gradle/caches/modules-2/files-2.1/org.glassfish.jaxb/jaxb-runtime/2.3.1/dd6dda9da676a54c5b36ca2806ff95ee017d8738/jaxb-runtime-2.3.1.jar referenced one or more files that do not exist: file:/Users/xiaosan/.gradle/caches/modules-2/files-2.1/org.glassfish.jaxb/jaxb-runtime/2.3.1/dd6dda9da676a54c5b36ca2806ff95ee017d8738/jaxb-api-2.3.1.jar,file:/Users/xiaosan/.gradle/caches/modules-2/files-2.1/org.glassfish.jaxb/jaxb-runtime/2.3.1/dd6dda9da676a54c5b36ca2806ff95ee017d8738/txw2-2.3.1.jar,file:/Users/xiaosan/.gradle/caches/modules-2/files-2.1/org.glassfish.jaxb/jaxb-runtime/2.3.1/dd6dda9da676a54c5b36ca2806ff95ee017d8738/istack-commons-runtime-3.0.7.jar,file:/Users/xiaosan/.gradle/caches/modules-2/files-2.1/org.glassfish.jaxb/jaxb-runtime/2.3.1/dd6dda9da676a54c5b36ca2806ff95ee017d8738/stax-ex-1.8.jar,file:/Users/xiaosan/.gradle/caches/modules-2/files-2.1/org.glassfish.jaxb/jaxb-runtime/2.3.1/dd6dda9da676a54c5b36ca2806ff95ee017d8738/FastInfoset-1.2.15.jar,file:/Users/xiaosan/.gradle/caches/modules-2/files-2.1/org.glassfish.jaxb/jaxb-runtime/2.3.1/dd6dda9da676a54c5b36ca2806ff95ee017d8738/javax.activation-api-1.2.0.jar
The Class-Path manifest attribute in /Users/xiaosan/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-impl/2.3.1/a1a12b85ba1435b4189e065f7dafcc3fb9410d38/jaxb-impl-2.3.1.jar referenced one or more files that do not exist: file:/Users/xiaosan/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-impl/2.3.1/a1a12b85ba1435b4189e065f7dafcc3fb9410d38/jaxb-runtime-2.3.1.jar,file:/Users/xiaosan/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-impl/2.3.1/a1a12b85ba1435b4189e065f7dafcc3fb9410d38/txw2-2.3.1.jar,file:/Users/xiaosan/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-impl/2.3.1/a1a12b85ba1435b4189e065f7dafcc3fb9410d38/istack-commons-runtime-3.0.7.jar,file:/Users/xiaosan/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-impl/2.3.1/a1a12b85ba1435b4189e065f7dafcc3fb9410d38/stax-ex-1.8.jar,file:/Users/xiaosan/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-impl/2.3.1/a1a12b85ba1435b4189e065f7dafcc3fb9410d38/FastInfoset-1.2.15.jar,file:/Users/xiaosan/.gradle/caches/modules-2/files-2.1/com.sun.xml.bind/jaxb-impl/2.3.1/a1a12b85ba1435b4189e065f7dafcc3fb9410d38/javax.activation-api-1.2.0.jar
Grails application running at http://localhost:8080 in environment: development
<=======<==========---> 83% EXECUTING [2m 11s]
> :bootR> :bootRun
grails>
默认使用内嵌Tomcat8服务器,默认端口8080,在浏览器中输入http://localhost:8080/ 访问 这是Grails提供的介绍页面,页面位置在 grails-app/view/index.gsp。显示有多少个控制器,并提供指向它们的链接。 单击“HelloController”链接就可以看到包含文本“Hello World!”的自定义页面。
现在第一个 Grails 应用程序已经成功运行起来了。
为应用程序设置上下文路径,在 grails-app/conf/application.yml 中添加一个配置属性:
server:
servlet:
context-path: /helloworld
添加后的代码:
---
server:
servlet:
context-path: /helloworld
grails:
profile: web
codegen:
后面代码省略···
···
保存之后,系统会自动将项目运行在helloworld上,不需要重启
Grails application running at http://localhost:8080/helloworld in environment: development
<==========---> 83% EXECUTING [28m 43s]
> :bootRun
这个时候就不能使用http://localhost:8080访问项目了 要使用http://localhost:8080/helloworld访问项目 访问"HelloWorld"页面 注意:
控制器(Controller)可以包含许多动作(Action),每个动作对应一个不同的页面(此时忽略 AJAX)。每个页面都可以通过一个唯一的 URL 访问。该 URL 由控制器名称和操作名称组成: /上下文路径/控制器/动作 /appname/controller/action。 这意味着您可以通过 /helloworld/hello/index 访问 Hello World 页面,其中 ‘hello’ 是控制器名称(从类名中删除 ‘Controller’ 后缀和小写首字母), ‘index’ 是控制器动作名称。 因为“index”是默认操作,可以省略。例如 http://localhost:8080/helloworld/hello/index http://localhost:8080/helloworld/hello 都可以访问到HelloWorld页面
可以在启动项目时,通过命令参数指定上下文路径,这样就不用在applicatioin.yml中配置了
grails> run-app -Dgrails.server.servlet.context-path=/helloworld
| Running application...
...
...
Grails application running at http://localhost:8080/helloworld in environment: development
<=======<==========---> 83% EXECUTING [24s]
> :bootR> :bootRun
grails>
也可以在命令行中指定端口号,端口号范围在1024 ~ 49151 。
grails> run-app -Dgrails.server.servlet.context-path=/helloworld -port=9999
| Running application...
...
...
Grails application running at http://localhost:9999/helloworld in environment: development
<=======<==========---> 83% EXECUTING [43s]
> :bootR> :bootRun
grails>
可以在grails交互模式中,输入quit命令来退出交互模式并停止项目
也可以不在grails交互模式中启动项目,直接在外面使用命令启动: ➜ /Users/xiaosan/Documents/work/helloworldgrails4 >grails run-app -Dgrails.server.servlet.context-path=/helloworld -port=9999
官方说最好以交互模式启动应用程序,因为容器重启要快得多,但实际使用时没感觉快多少。
⎮如何选择开发工具
推荐使用IDEA 其他可选开发工具:
可以通过 Sublime 文本编辑器的 Sublime Package Control 安装插件sublimetext-grails将 VIM 设置为 Grails 编辑器,参考using-vim-as-your-grails-ide-part-1-navigating-your-projectAtom 编辑器安装插件atom-grailsVisual Studio Code安装扩展code-groovy。
IDEA如何导入Grails项目
选择 File / Open, 选择grails项目的 build.gradle文件。 以项目形式打开。 信任项目 等待导入配置 导入完成
⎮目录结构,约定优于配置
Grails 使用“约定优于配置”来配置自身。意味着Grails的文件名称和位置不需要显示的去配置,按照Grails的默认约定就可以了,因此需要熟悉 Grails 提供的目录结构。
grails-app:Groovy 源码的顶级目录
conf:存放配置文件的目录,可以配置日志,数据源,Spring bean配置等。controllers:Web控制器,MVC中的C。负责处理请求并创建或准备响应,控制器可以直接生成响应或委托给视图。doamin:领域类,MVC中的M。定义业务流程的状态和行为,配置属性约束,配置一对一、一对多或多对多关系。i18n:支持开箱即用的国际化(i18n)。Grails底层利用SpringMVC的国际化支持。services:业务层。用于存放应用程序逻辑,让控制器负责处理带有重定向等的请求。taglib:标签库。utils:Grails 特定的实用程序。views:Groovy 服务器页面或 JSON 视图 - MVC 中的 V。 - src/main/scripts:代码生成脚本,用于创建脚本,类似月create-app、run-app脚本。 grails4.0.11中没有该目录 src/main/groovy:存放groovy代码src/test/groovy:存放单元测试
⎮如何部署Grails项目
1. 使用默认内嵌的Tomcat8部署
先打包成war文件➜ /Users/xiaosan/Documents/work/helloworldgrails4 >grails war
Processing File 2 of 43 - bootstrap.bundle.js
...
Processing File 43 of 43 - bootstrap.min.css.map
> Task :assetCompile
Finished Precompiling Assets
BUILD SUCCESSFUL in 15s
7 actionable tasks: 5 executed, 2 up-to-date
| Built application to build/libs using environment: production
默认打包环境为生产环境。 打包文件默认生成在build/libs/helloworldgrails4-0.1.war 。 默认情况下,Grails 将在 WAR 文件中包含可嵌入版本的 Tomcat使用java命令启动内嵌Tomcat的war文件➜ /Users/xiaosan/Documents/work/helloworldgrails4 >java -Dgrails.env=prod -jar build/libs/helloworldgrails4-0.1.war
Grails application running at http://localhost:8080 in environment: production
启动可以添加一些参数: -Dgrails.env参数可以指定启动的环境,不加这个参数默认是生产环境。 例如: -Dgrails.env=prod:生产环境 -Dgrails.env=dev:开发环境 -Dgrails.env=test:测试环境 使用 -server 参数给JVM容器分配内存。 例如: -server -Xmx768M -XX:MaxPermSize=256m 参数一起使用:➜ /Users/xiaosan/Documents/work/helloworldgrails4 >java -Dgrails.env=prod -server -Xmx768M -XX:MaxPermSize=256m -jar build/libs/helloworldgrails4-0.1.war
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
Grails application running at http://localhost:8080 in environment: production
启动成功访问http://localhost:8080,注意这里我将application.yml中的上下文路径给删除了,没有配置上下文路径。 由于MaxPermSize参数在JDK8中已经删除了,所以这里可以去掉这个参数。
jvm参数含义 -vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M -vmargs 说明后面是VM的参数,所以后面的其实都是JVM的参数了 -Xms128m JVM初始分配的堆内存 -Xmx512m JVM最大允许分配的堆内存,按需分配 -XX:PermSize=64M JVM初始分配的非堆内存 -XX:MaxPermSize=128M JVM最大允许分配的非堆内存,按需分配
2. 使用外部Tomtcat8部署
打包前修改build.gradle 文件,在依赖项中将 Tomcat 依赖的范围更改为provided compile "org.springframework.boot:spring-boot-starter-tomcat" 改为 provided "org.springframework.boot:spring-boot-starter-tomcat" 如果使用IDEA工具修改,改后后记得gradle图标,重新加载依赖 开始打包,进入项目所在目录,执行grails war命令。| Resolving Dependencies. Please wait...
CONFIGURE SUCCESSFUL in 1s
BUILD SUCCESSFUL in 6s
7 actionable tasks: 6 executed, 1 up-to-date
| Built application to build/libs using environment: production
下载Tomcat8,解压到目录/opt/apache-tomcat-8.5-grails4删除/opt/apache-tomcat-8.5-grails4/webapps/ROOT目录将war包复制到/opt/apache-tomcat-8.5-grails4/webapps/,并改名为ROOT.war cp build/libs/helloworldgrails4-0.1.war /opt/apache-tomcat-8.5-grails4/webapps/ROOT.war 修改Tomcat的端口号。修改/opt/apache-tomcat-8.5-grails4/conf/server.xml,将8080端口改为8880启动Tomcat。进入/opt/apache-tomcat-8.5-grails4/bin目录,执行➜ /opt/apache-tomcat-8.5-grails4/bin >./startup.sh
Using CATALINA_BASE: /opt/apache-tomcat-8.5-grails4
Using CATALINA_HOME: /opt/apache-tomcat-8.5-grails4
Using CATALINA_TMPDIR: /opt/apache-tomcat-8.5-grails4/temp
Using JRE_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home
Using CLASSPATH: /opt/apache-tomcat-8.5-grails4/bin/bootstrap.jar:/opt/apache-tomcat-8.5-grails4/bin/tomcat-juli.jar
Tomcat started.
查看tomcat日志输出➜ /opt/apache-tomcat-8.5-grails4/bin >tail -f ../logs/catalina.out
...
...
04-Aug-2021 16:02:03.911 信息 [main] org.apache.coyote.AbstractProtocol.start 开始协议处理句柄["http-nio-8880"]
04-Aug-2021 16:02:03.918 信息 [main] org.apache.coyote.AbstractProtocol.start 开始协议处理句柄["ajp-nio-8809"]
04-Aug-2021 16:02:03.920 信息 [main] org.apache.catalina.startup.Catalina.start Server startup in 13480 ms
访问项目http://localhost:8080 注意编译的时候依赖的是Tomcat8,打包后的war只能在Tomcat8中运行,不能放在Tomcat7中运行。
3. 使用外部Tomcat7部署
修改build.gradle文件,修改Tomcat的依赖版本,例如改为7.0.88,在dependencies{}上面添加ext['tomcat.version'] = '7.0.88'
打包前修改build.gradle 文件,在依赖项中将 Tomcat 依赖的范围更改为provided compile "org.springframework.boot:spring-boot-starter-tomcat" 改为 provided "org.springframework.boot:spring-boot-starter-tomcat"
如果IDEA修改的build.gradle,修改后注意点击gradle图标重新加载依赖
开始打包,进入项目所在目录,执行grails war命令。
| Resolving Dependencies. Please wait...
CONFIGURE SUCCESSFUL in 1s
Processing File 7 of 43 - application.js
...
...
> Task :assetCompile
Finished Precompiling Assets
BUILD SUCCESSFUL in 9s
7 actionable tasks: 5 executed, 2 up-to-date
| Built application to build/libs using environment: production
下载Tomcat7.0.88,解压到目录/opt/apache-tomcat-7.0.88
删除/opt/apache-tomcat-7.0.88/webapps/ROOT目录
将war包复制到/opt/apache-tomcat-7.0.88/webapps/,并改名为ROOT.war cp build/libs/helloworldgrails4-0.1.war /opt/apache-tomcat-7.0.88/webapps/ROOT.war
修改Tomcat7的端口号。修改/opt/apache-tomcat-7.0.88/conf/server.xml,将8005端口改为8705,将8080改为8780,将8009改为8709。该端口主要是为了避免多个Tomcat端口冲突,如果只有一个Tomcat就可以不用修改
启动Tomcat。进入/opt/apache-tomcat-7.0.88/bin目录,执行./startup.sh
➜ /opt/apache-tomcat-7.0.88/bin >./startup.sh
Using CATALINA_BASE: /opt/apache-tomcat-7.0.88
Using CATALINA_HOME: /opt/apache-tomcat-7.0.88
Using CATALINA_TMPDIR: /opt/apache-tomcat-7.0.88/temp
Using JRE_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home
Using CLASSPATH: /opt/apache-tomcat-7.0.88/bin/bootstrap.jar:/opt/apache-tomcat-7.0.88/bin/tomcat-juli.jar
Tomcat started.
查看tomcat日志输出
八月 04, 2021 7:59:54 下午 org.apache.catalina.loader.WebappClassLoaderBase validateJarFile
信息: validateJarFile(/opt/apache-tomcat-7.0.88/webapps/ROOT/WEB-INF/lib/el-api-2.1.2-b03.jar) - jar not loaded. See Servlet Spec 3.0, section 10.7.2. Offending class: javax/el/Expression.class
八月 04, 2021 7:59:54 下午 org.apache.catalina.loader.WebappClassLoaderBase validateJarFile
信息: validateJarFile(/opt/apache-tomcat-7.0.88/webapps/ROOT/WEB-INF/lib/javax.el-3.0.0.jar) - jar not loaded. See Servlet Spec 3.0, section 10.7.2. Offending class: javax/el/Expression.class
八月 04, 2021 7:59:54 下午 org.apache.catalina.loader.WebappClassLoaderBase validateJarFile
信息: validateJarFile(/opt/apache-tomcat-7.0.88/webapps/ROOT/WEB-INF/lib/javax.el-api-3.0.1-b06.jar) - jar not loaded. See Servlet Spec 3.0, section 10.7.2. Offending class: javax/el/Expression.class
八月 04, 2021 7:59:54 下午 org.apache.catalina.loader.WebappClassLoaderBase validateJarFile
信息: validateJarFile(/opt/apache-tomcat-7.0.88/webapps/ROOT/WEB-INF/lib/javax.servlet-api-4.0.1.jar) - jar not loaded. See Servlet Spec 3.0, section 10.7.2. Offending class: javax/servlet/Servlet.class
八月 04, 2021 7:59:56 下午 org.apache.catalina.startup.TldConfig execute
信息: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
2021-08-04 20:00:02.899 ERROR --- [ost-startStop-1] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerAdapter' defined in org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter]: Factory method 'requestMappingHandlerAdapter' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mvcValidator' defined in org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: javax/el/ELManager
报错nested exception is java.lang.NoClassDefFoundError: javax/el/ELManager 因为Grails4.0.11对el-api的版本要求比较高,Tomcat7.0.88/lib/目录里自带的el-api.jar是2.1版本的,版本比较底,启动tomcat时先加载自己的底el-api.jar,后面就不会再去加载ROOT/WEB-INF/lib/目录下的高版本el-api.jar了。 执行➜ /opt/apache-tomcat-7.0.88/bin >./shutdown.sh停止tomcat 复制/opt/apache-tomcat-7.0.88/webapps/ROOT/WEB-INF/lib/javax.el-api-3.0.1-b06.jar 到/opt/apache-tomcat-7.0.88/lib 重新启动Tomcat7
八月 04, 2021 8:08:40 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deployment of web application directory /opt/apache-tomcat-7.0.88/webapps/examples has finished in 149 ms
八月 04, 2021 8:08:40 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deploying web application directory /opt/apache-tomcat-7.0.88/webapps/host-manager
八月 04, 2021 8:08:40 下午 org.apache.catalina.startup.TldConfig execute
信息: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
八月 04, 2021 8:08:40 下午 org.apache.catalina.startup.HostConfig deployDirectory
信息: Deployment of web application directory /opt/apache-tomcat-7.0.88/webapps/host-manager has finished in 35 ms
八月 04, 2021 8:08:40 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-bio-8780"]
八月 04, 2021 8:08:40 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["ajp-bio-8709"]
八月 04, 2021 8:08:40 下午 org.apache.catalina.startup.Catalina start
信息: Server startup in 12017 ms
启动成功,访问http://localhost:8780 注意高版本编译的代码,不要使用底版本的servlet容器运行,很容易出现由于jar包不兼容导致冲突,最好使用默认的servlet容器来运行。
⎮Grails4支持的JavaEE容器有哪些
Grails 可以在任何支持 Servlet 3.0 及更高版本的容器上运行,并且可以在以下特定的容器产品上运行:
Tomcat 7GlassFish 3 或以上版本Resin 4 或以上版本JBoss 6 或以上版本Jetty 8 或以上版本Oracle Weblogic 12c 或以上版本IBM WebSphere 8.0 或以上版本
Grails4.0.11默认是使用Tomcat8作为内嵌servlet容器,部署时也最好使用Tomcat8。
⎮如何快速创建控制器和领域类
1. 创建领域类
Grails提供了一些create-*命令,用于快速创建应用。当然使用IDEA创建更快。 例如:创建领域类命令create-domain-class grails create-domain-class book 这将会创建一个helloworldgrails4.Book.groovy领域类 和对应的测试类helloworldgrails4.BookSpec.groovy 创建时没有给book指定包名,默认使用项目名作为包名。
➜ /Users/xiaosan/Documents/work/helloworldgrails4 >grails create-domain-class book
| Created grails-app/domain/helloworldgrails4/Book.groovy
| Created src/test/groovy/helloworldgrails4/BookSpec.groovy
查看创建的领域类
package helloworldgrails4
class Book {
static constraints = {
}
}
修改领域类,添加两个字段
package helloworldgrails4
class Book {
String title //书名
Date releaseDate = new Date() //发布日期
static constraints = {
}
}
2. 使用脚手架创建控制器和视图
Grails提供了一些脚手架功能用来快速生成应用程序的骨架。 命令以 generate-* 开头,例如 generate-all,它将生成控制器(及其单元测试)和相关视图:
grails generate-all Book -force -force 参数强制生成覆盖已有文件。
➜ /Users/xiaosan/Documents/work/helloworldgrails4 >grails generate-all Book -force
| Rendered template Controller.groovy to destination grails-app/controllers/helloworldgrails4/BookController.groovy
| Rendered template Service.groovy to destination grails-app/services/helloworldgrails4/BookService.groovy
| Rendered template Spec.groovy to destination src/test/groovy/helloworldgrails4/BookControllerSpec.groovy
| Rendered template ServiceSpec.groovy to destination src/integration-test/groovy/helloworldgrails4/BookServiceSpec.groovy
| Scaffolding completed for grails-app/domain/helloworldgrails4/Book.groovy
| Rendered template show.gsp to destination grails-app/views/book/show.gsp
| Rendered template index.gsp to destination grails-app/views/book/index.gsp
| Rendered template create.gsp to destination grails-app/views/book/create.gsp
| Rendered template edit.gsp to destination grails-app/views/book/edit.gsp
| Views generated for grails-app/domain/helloworldgrails4/Book.groovy
自动生成的有:
控制器:grails-app/controllers/helloworldgrails4/BookController.groovy业务层:grails-app/services/helloworldgrails4/BookService.groovy控制器测试:src/test/groovy/helloworldgrails4/BookControllerSpec.groovy业务层测试:src/integration-test/groovy/helloworldgrails4/BookServiceSpec.groovy详情页面:grails-app/views/book/show.gsp列表页面:grails-app/views/book/index.gsp添加页面:grails-app/views/book/create.gsp修改页面:grails-app/views/book/edit.gsp
grails-app/controllers/helloworldgrails4/BookController.groovy代码
package helloworldgrails4
import grails.validation.ValidationException
import static org.springframework.http.HttpStatus.*
class BookController {
BookService bookService
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond bookService.list(params), model:[bookCount: bookService.count()]
}
def show(Long id) {
respond bookService.get(id)
}
def create() {
respond new Book(params)
}
def save(Book book) {
if (book == null) {
notFound()
return
}
try {
bookService.save(book)
} catch (ValidationException e) {
respond book.errors, view:'create'
return
}
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'book.label', default: 'Book'), book.id])
redirect book
}
'*' { respond book, [status: CREATED] }
}
}
def edit(Long id) {
respond bookService.get(id)
}
def update(Book book) {
if (book == null) {
notFound()
return
}
try {
bookService.save(book)
} catch (ValidationException e) {
respond book.errors, view:'edit'
return
}
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.updated.message', args: [message(code: 'book.label', default: 'Book'), book.id])
redirect book
}
'*'{ respond book, [status: OK] }
}
}
def delete(Long id) {
if (id == null) {
notFound()
return
}
bookService.delete(id)
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.deleted.message', args: [message(code: 'book.label', default: 'Book'), id])
redirect action:"index", method:"GET"
}
'*'{ render status: NO_CONTENT }
}
}
protected void notFound() {
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'book.label', default: 'Book'), params.id])
redirect action: "index", method: "GET"
}
'*'{ render status: NOT_FOUND }
}
}
}
grails-app/services/helloworldgrails4/BookService.groovy代码:
package helloworldgrails4
import grails.gorm.services.Service
@Service(Book)
interface BookService {
Book get(Serializable id)
List
Long count()
void delete(Serializable id)
Book save(Book book)
}
grails-app/views/book/show.gsp代码:
grails-app/views/book/index.gsp代码
grails-app/views/book/create.gsp代码:
- data-field-id="${error.field}">
grails-app/views/book/edit.gsp代码:
- data-field-id="${error.field}">
3. 使用脚手架生成的代码为我们实现了哪些功能
启动项目,看看Grails脚手架生成的代码为我们提供了哪些功能。 在这之前,将grails项目改为使用内嵌Tomcat方式启动,修改build.gradle 注释掉ext['tomcat.version'] = '7.0.88' 将provided "org.springframework.boot:spring-boot-starter-tomcat" 改为compile "org.springframework.boot:spring-boot-starter-tomcat" 使用grails run-app命令启动项目 默认使用8080端口,没有配置上下文路径,打来浏览器访问http://localhost:8080
3.1 - 书籍列表页面
点击helloworldgrails4.BookConroller跳转到书籍列表页面http://localhost:8080/book/index
3.2 - 添加书籍页面
点击NewBook跳转到添加书籍页面http://localhost:8080/book/create 默认提供了领域类的属性表单,并且提供了非空验证。 添加一个书籍 点击Create保存跳转到书籍详情页面
3.3 - 书籍详情页面
点击Create后跳转到书籍详情页面http://localhost:8080/book/show/1 /book/show/1 /控制器/动作/ID 默认展示刚刚添加的属性信息,有添加成功提示信息 提供导航到书籍页面,添加书籍,修改书籍,删除书籍的链接。
3.4 - 修改书籍页面
点击Edit跳转到修改书籍页面http://localhost:8080/book/edit/1 默认提供了领域类属性表单,同样有领域类属性校验。 提供导航到书籍页面,添加书籍的链接。 点击Update跳转到书籍详情页面。 点击Create Book再次添加一本书籍 点击Book List跳转到书籍列表页面
3.5 - 删除书籍页面
先在列表页面点击要删除的书籍,进入书籍详情页面 点击“好” ,确认删除,删除成功后跳转到书籍列表页面 在列表页面显示删除成功的提示信息。
3.6 - 小结
脚手架为我们提供的功能有:
包含全部属性表单的添加页面包含属性的列表页面,点击属性标题可以排序包含全部属性表单的修改页面包含全部属性表单的详情页面包含删除数据功能列表页面-详情页面-添加页面-修改页面的导航链接操作数据后的提示信息属性表单的校验(非空等)
基本上为我们提供了所有的数据操作功能,我们只需要修改默认的css样式就可以了。如果不喜欢默认的排版,就需要自己写页面布局,将属性一个一个的写出来了。
⎮完成入门
到目前为止,我们完成了从创建grails项目,到创建领域类,创建控制器,创建视图,完成增删改查,最后发布的所有流程。这只是一个简单的入门教程,主要先了解grails项目开发的几个大概步骤。Grails默认使用的H2内存数据库,数据库配置每次重启项目都会清空数据。后面会讲连接其他数据库,并持久化数据。