文章目录
- Grails配置
- 基本配置
- ⎮Grails4风格配置
- ⎮Grails2风格的Groovy配置
- ⎮使用GrailsApplication对象访问配置信息
- 在控制器中使用grailsApplication对象
- 能获取到的配置信息有哪些
- 在业务层中使用grailsApplication对象方式一
- 在业务层中使用grailsApplication对象方式二
- ⎮使用Spring值注解注入配置信息
- ⎮在application.yml中访问命令行参数或者系统参数
- ⎮使用外部application.yml文件
- ⎮内置的一些设置,了解一下有好处
- ⎮Logging配置
- Logging实例演示
- logback.groovy 默认的日志配置
- 彩色日志
- 1. IDEA控制台彩色日志输出方式一
- 2. IDEA控制台彩色日志输出方式二
- 3. 打包后的项目默认是彩色日志,不需其他配置
- 程序报错时,指定敏感请求参数不写入日志
- 完全关闭请求参数日志记录功能
- 使用外部日志配置文件
- 1.使用logging.config指定外部Logback配置文件
- 2.使用JVM启动参数配置外部日志文件
- 3. 系统环境变量添加`LOGGING_CONFIG`
- ⎮GORM配置
- 为所有领域类启用 failOnError
- 按包名为领域类启用 failOnError
- ⎮小结
Grails配置
在上一讲中,我们使用Grails的默认约定配置,没有进行任何其他配置就完成了Grails入门学习。Grails是一个“约定优于配置”的框架,只使用默认配置是不够的,我们还需要了解在需要时在哪里以及如何覆盖约定配置。
基本配置
⎮Grails4风格配置
Grails4 中有两种配置:构建配置和运行时配置。
- 构建配置:通常通过 Gradle 和 build.gradle 文件完成。
- 运行时配置:默认情况下,在 YAML 文件中指定,文件位于 grails-app/conf/application.yml。
⎮Grails2风格的Groovy配置
如果喜欢以前的Grails2风格的Groovy配置,可以使用Groovy 的 ConfigSlurper 语法指定配置。有两个 Groovy 配置文件可用:grails-app/conf/application.groovy 和 grails-app/conf/runtime.groovy:
- application.groovy:用于不依赖于应用程序类的配置,因为加载这个配置文件的时候还没有加载应用程序的类。
- runtime.groovy: 用于依赖于应用程序类的配置。
在Groovy配置中可以使用以下内置变量。
变量 | 描述 |
---|---|
userHome | 运行 Grails 应用程序的帐户的主目录的位置。对于Linux系统就是/home下的账户目录,例如/home/test |
grailsHome | 安装 Grails 的目录的位置。如果设置了 GRAILS_HOME 环境变量,则使用它。 |
appName | 出现在 build.gradle 中的应用程序名称。 |
appVersion | 出现在 build.gradle 中的应用程序版本。 |
这些变量不能在conf/application.yml和build.gradle中使用。
⎮使用GrailsApplication对象访问配置信息
可以在控制器和标签库中使用内置的grailsApplication对象获取运行时配置(application.yml中)的信息。
现在添加一个运行时配置信息
book.title="《Grails教程》"
book.author.name="肖伞"
添加到conf/application.yml中的格式为:
book:title: "《Grails教程》"author:name: "肖伞"
在控制器中使用grailsApplication对象
修改HelloController.groovy,添加hello动作,读取application.yml信息
package helloworldgrails4class HelloController {def index() {render "Hello World!"}def hello() {// 内置grailsApplication变量可以直接使用,使用getProperty(String name)方法获取application.yml中的配置信息def bookTitle = grailsApplication.config.getProperty('book.title')// 获取application.xml中配置的作者姓名def bookAuthorName = grailsApplication.config.getProperty('book.author.name')// 获取application.xml中配置的书籍价格,默认获取值的类型是String类型,通过第二个参数值的类型,值为空时返回第三个参数作为默认值def bookPrice = grailsApplication.config.getProperty('book.price', Integer, 50)// 注意这里没有配置 book.price, 应该返回默认值 50render "bookTitle = ${bookTitle}, bookAuthorName = ${bookAuthorName}, bookPrice = ${bookPrice}"}
}
启动项目访问http://localhost:8080/hello/helo
第一个hello是控制器的名字
第二个hello是动作的名字
grailsApplication 对象的 config 属性是 Config 接口的一个实例,它提供了许多有用的方法来读取应用程序的配置。
特别是getProperty 方法,可以很方便的获取运行时配置属性信息,同时指定属性类型(默认类型为 String)和提供默认返回值。
注意:
Config 实例是基于 Spring 的 PropertySource 概念的合并配置。
即将开发环境、计算机操作系统属性和本地应用程序中的配置信息合并为一个对象了。
那么到底将哪些配置信息合并到一起了呢,我们将config对象里的配置信息输入一下。
能获取到的配置信息有哪些
修改HelloController.groovy,添加allConfig方法输出所有配置信息。
/*** 获取 grailsApplication.config 中所有配置信息* @return*/def allConfig() {grailsApplication.config?.sort{it.key}?.each {if( it.value.getClass().toString() != "class org.grails.config.NavigableMap"){render it.key + "=" + it.value + "<br/>"}}}
访问http://localhost:8080/hello/allConfig
页面
可以看到有很多的配置信息,例如:
GRAILS_HOME:本地配置的Grails4环境
JAVA_HOME:本地配置的Java8开发环境
book.author.name:应用程序中配置的信息
配置的信息,太多了截图不完整。
完整信息如下:
ANDROID_HOME=/Users/xiaosan/Library/Android/sdk
Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.GGLczpfvow/Render
CLASS_PATH=.:/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/lib
GOBIN=/Users/xiaosan/go/bin
GOPATH=/Users/xiaosan/go
GRAILS_FORK_OPTS=
GRAILS_HOME=/opt/grails-4.0.0
HOME=/Users/xiaosan
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home
JAVA_MAIN_CLASS_82071=org.grails.cli.GrailsCli
JAVA_MAIN_CLASS_82089=helloworldgrails4.Application
LANG=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
LESS=-R
LOGNAME=xiaosan
LSCOLORS=Gxfxcxdxbxegedabagacad
M2_HOME=/opt/apache-maven-3.6.2/bin
MAVEN_HOME=/opt/apache-maven-3.6.2
OLDPWD=/
PAGER=less
PATH=/usr/local/opt/icu4c/sbin:/usr/local/opt/icu4c/bin:/usr/local/opt/curl/bin:/usr/local/bin:/usr/local/sbin:/opt/apache-maven-3.6.2/bin:.:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/Applications/Wireshark.app/Contents/MacOS:/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/bin:/usr/local/mysql/bin:/opt/grails-4.0.0/bin:/Users/xiaosan/Library/Android/sdk/platform-tools:/Users/xiaosan/Library/Android/sdk/tools:/Users/xiaosan/Library/Android/sdk/tools/bin:/Users/xiaosan/Library/Android/sdk/build-tools/26.0.0:/Users/xiaosan/go/bin:/Applications/OpenOffice.app/Contents/MacOS:/usr/local/nginx/sbin:/opt/gradle-6.4.1/bin
PID=82089
PWD=/Users/xiaosan/Documents/work/helloworldgrails4
SDKMAN_CANDIDATES_DIR=/Users/xiaosan/.sdkman/candidates
SDKMAN_CURRENT_API=https://api.sdkman.io/2
SDKMAN_DIR=/Users/xiaosan/.sdkman
SDKMAN_LEGACY_API=https://api.sdkman.io/1
SDKMAN_PLATFORM=Darwin
SDKMAN_VERSION=5.6.3+299
SHELL=/bin/zsh
SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.tnmreq3K7O/Listeners
TMPDIR=/var/folders/5p/0lhw6dwj45nfn0zrchplk46m0000gn/T/
USER=xiaosan
VERSIONER_PYTHON_PREFER_32_BIT=no
VERSIONER_PYTHON_VERSION=2.7
XPC_FLAGS=0x0
XPC_SERVICE_NAME=com.jetbrains.intellij.39532
ZSH=/Users/xiaosan/.oh-my-zsh
__CF_USER_TEXT_ENCODING=0x1F5:0x19:0x34
awt.toolkit=sun.lwawt.macosx.LWCToolkit
book.author.name=肖伞
book.title=《Grails教程》
catalina.base=/private/var/folders/5p/0lhw6dwj45nfn0zrchplk46m0000gn/T/tomcat.4326420305887272758.8080
catalina.home=/private/var/folders/5p/0lhw6dwj45nfn0zrchplk46m0000gn/T/tomcat.144908067832705976.8080
catalina.useNaming=false
dataSource.dbCreate=create-drop
dataSource.driverClassName=org.h2.Driver
dataSource.jmxExport=true
dataSource.password=
dataSource.pooled=true
dataSource.url=jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
dataSource.username=sa
env=development
environments.development.dataSource.dbCreate=create-drop
environments.development.dataSource.url=jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
environments.production.dataSource.dbCreate=none
environments.production.dataSource.properties.defaultTransactionIsolation=2
environments.production.dataSource.properties.initialSize=5
environments.production.dataSource.properties.jdbcInterceptors=ConnectionState
environments.production.dataSource.properties.jmxEnabled=true
environments.production.dataSource.properties.maxActive=50
environments.production.dataSource.properties.maxAge=600000
environments.production.dataSource.properties.maxIdle=25
environments.production.dataSource.properties.maxWait=10000
environments.production.dataSource.properties.minEvictableIdleTimeMillis=60000
environments.production.dataSource.properties.minIdle=5
environments.production.dataSource.properties.testOnBorrow=true
environments.production.dataSource.properties.testOnReturn=false
environments.production.dataSource.properties.testWhileIdle=true
environments.production.dataSource.properties.timeBetweenEvictionRunsMillis=5000
environments.production.dataSource.properties.validationInterval=15000
environments.production.dataSource.properties.validationQuery=SELECT 1
environments.production.dataSource.properties.validationQueryTimeout=3
environments.production.dataSource.url=jdbc:h2:./prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
environments.test.dataSource.dbCreate=update
environments.test.dataSource.url=jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
file.encoding=UTF-8
file.encoding.pkg=sun.io
file.separator=/
ftp.nonProxyHosts=192.168.0.0/16|*.192.168.0.0/16|10.0.0.0/8|*.10.0.0.0/8|172.16.0.0/12|*.172.16.0.0/12|127.0.0.1|localhost|*.localhost|local|*.local|timestamp.apple.com|*.timestamp.apple.com
full.stacktrace=false
gopherProxySet=false
grails.codegen.defaultPackage=helloworldgrails4
grails.controllers.defaultScope=singleton
grails.converters.encoding=UTF-8
grails.env=development
grails.env.initializing=true
grails.env.standalone=true
grails.full.stacktrace=false
grails.gorm.reactor.events=false
grails.mime.disable.accept.header.userAgents=[Gecko, WebKit, Presto, Trident]
grails.mime.disable.accept.header.userAgents[0]=Gecko
grails.mime.disable.accept.header.userAgents[1]=WebKit
grails.mime.disable.accept.header.userAgents[2]=Presto
grails.mime.disable.accept.header.userAgents[3]=Trident
grails.mime.types.all=*/*
grails.mime.types.atom=application/atom+xml
grails.mime.types.css=text/css
grails.mime.types.csv=text/csv
grails.mime.types.form=application/x-www-form-urlencoded
grails.mime.types.hal=[application/hal+json, application/hal+xml]
grails.mime.types.hal[0]=application/hal+json
grails.mime.types.hal[1]=application/hal+xml
grails.mime.types.html=[text/html, application/xhtml+xml]
grails.mime.types.html[0]=text/html
grails.mime.types.html[1]=application/xhtml+xml
grails.mime.types.js=text/javascript
grails.mime.types.json=[application/json, text/json]
grails.mime.types.json[0]=application/json
grails.mime.types.json[1]=text/json
grails.mime.types.multipartForm=multipart/form-data
grails.mime.types.pdf=application/pdf
grails.mime.types.rss=application/rss+xml
grails.mime.types.text=text/plain
grails.mime.types.xml=[text/xml, application/xml]
grails.mime.types.xml[0]=text/xml
grails.mime.types.xml[1]=application/xml
grails.profile=web
grails.shutdown.hook.installed=true
grails.urlmapping.cache.maxsize=1000
grails.views.default.codec=html
grails.views.gsp.codecs.expression=html
grails.views.gsp.codecs.scriptlet=html
grails.views.gsp.codecs.staticparts=none
grails.views.gsp.codecs.taglib=none
grails.views.gsp.encoding=UTF-8
grails.views.gsp.htmlcodec=xml
hibernate.cache.queries=false
hibernate.cache.use_query_cache=false
hibernate.cache.use_second_level_cache=false
http.nonProxyHosts=192.168.0.0/16|*.192.168.0.0/16|10.0.0.0/8|*.10.0.0.0/8|172.16.0.0/12|*.172.16.0.0/12|127.0.0.1|localhost|*.localhost|local|*.local|timestamp.apple.com|*.timestamp.apple.com
http.proxyHost=127.0.0.1
http.proxyPort=1087
https.proxyHost=127.0.0.1
https.proxyPort=1087
info.app.grailsVersion=4.0.0
info.app.name=helloworldgrails4
info.app.version=0.1
java.awt.graphicsenv=sun.awt.CGraphicsEnvironment
java.awt.headless=true
java.awt.printerjob=sun.lwawt.macosx.CPrinterJob
java.class.path=/Users/xiaosan/Documents/work/helloworldgrails4/src/main/resources:/Users/xiaosan/Documents/work/helloworldgrails4/grails-app/views:/Users/xiaosan/Documents/work/helloworldgrails4/grails-app/i18n:/Users/xiaosan/Documents/work/helloworldgrails4/grails-app/conf:/Users/xiaosan/Documents/work/helloworldgrails4/build/classes/java/main:/Users/xiaosan/Documents/work/helloworldgrails4/build/classes/groovy/main:/Users/xiaosan/Documents/work/helloworldgrails4/gsp-classes:...后面太多省略
java.class.version=52.0
java.endorsed.dirs=/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/endorsed
java.ext.dirs=/Users/xiaosan/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java
java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre
java.io.tmpdir=/var/folders/5p/0lhw6dwj45nfn0zrchplk46m0000gn/T/
java.library.path=/Users/xiaosan/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.
java.runtime.name=Java(TM) SE Runtime Environment
java.runtime.version=1.8.0_171-b11
java.specification.name=Java Platform API Specification
java.specification.vendor=Oracle Corporation
java.specification.version=1.8
java.vendor=Oracle Corporation
java.vendor.url=http://java.oracle.com/
java.vendor.url.bug=http://bugreport.sun.com/bugreport/
java.version=1.8.0_171
java.vm.info=mixed mode
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
java.vm.specification.name=Java Virtual Machine Specification
java.vm.specification.vendor=Oracle Corporation
java.vm.specification.version=1.8
java.vm.vendor=Oracle Corporation
java.vm.version=25.171-b11
line.separator=
management.endpoints.enabled-by-default=false
management.endpoints.jmx.unique-names=true
management.endpoints.shutdown.enabled=true
micronaut.classloader.logging=true
org.grails.MAIN_CLASS_NAME=helloworldgrails4.Application
org.jboss.logging.provider=slf4j
os.arch=x86_64
os.name=Mac OS X
os.version=10.14.6
path.separator=:
run.active=true
server.error.include-stacktrace=ALWAYS
server.servlet.jsp.init-parameters.development=true
server.servlet.session.persistent=true
socksNonProxyHosts=192.168.0.0/16|*.192.168.0.0/16|10.0.0.0/8|*.10.0.0.0/8|172.16.0.0/12|*.172.16.0.0/12|127.0.0.1|localhost|*.localhost|local|*.local|timestamp.apple.com|*.timestamp.apple.com
socksProxyHost=127.0.0.1
socksProxyPort=1087
spring.beaninfo.ignore=true
spring.devtools.restart.additional-exclude=[*.gsp, **/*.gsp, *.gson, **/*.gson, logback.groovy, *.properties]
spring.devtools.restart.additional-exclude[0]=*.gsp
spring.devtools.restart.additional-exclude[1]=**/*.gsp
spring.devtools.restart.additional-exclude[2]=*.gson
spring.devtools.restart.additional-exclude[3]=**/*.gson
spring.devtools.restart.additional-exclude[4]=logback.groovy
spring.devtools.restart.additional-exclude[5]=*.properties
spring.freemarker.cache=false
spring.groovy.template.cache=false
spring.groovy.template.check-template-location=false
spring.h2.console.enabled=true
spring.jmx.unique-names=true
spring.main.banner-mode=off
spring.mustache.cache=false
spring.mvc.log-resolved-exception=true
spring.output.ansi.enabled=always
spring.profiles.active=
spring.reactor.stacktrace-mode.enabled=true
spring.resources.cache.period=0
spring.resources.chain.cache=false
spring.template.provider.cache=false
spring.thymeleaf.cache=false
sun.arch.data.model=64
sun.boot.class.path=/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/sunrsasign.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/classes
sun.boot.library.path=/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib
sun.cpu.endian=little
sun.cpu.isalist=
sun.io.unicode.encoding=UnicodeBig
sun.java.command=helloworldgrails4.Application
sun.java.launcher=SUN_STANDARD
sun.jnu.encoding=UTF-8
sun.management.compiler=HotSpot 64-Bit Tiered Compilers
sun.os.patch.level=unknown
user.country=CN
user.dir=/Users/xiaosan/Documents/work/helloworldgrails4
user.home=/Users/xiaosan
user.language=zh
user.name=xiaosan
user.timezone=Asia/Shanghai
user.variant=
verbose=false
在业务层中使用grailsApplication对象方式一
创建HelloService.groovy
输入Service的名字Hello或者HelloService都可以,会自动判断是否需要添加Service后缀,最后生成HelloService.groovy文件
创建好的HelloService文件
修改HelloService文件
package helloworldgrails4import grails.core.GrailsApplication
import grails.gorm.transactions.Transactional@Transactional
class HelloService {def serviceMethod() {}// grailsApplication 对象通过 Spring 注入进来GrailsApplication grailsApplicationdef useConfigInService() {def bookTitle = grailsApplication.config.getProperty("book.title")return bookTitle}
}
在HelloController中使用HelloService
package helloworldgrails4class HelloController {// 通过 Spring 将HelloService注入进来def helloServicedef index() {render "Hello World!"}def hello() {// 内置grailsApplication变量可以直接使用,使用getProperty(String name)方法获取application.yml中的配置信息def bookTitle = grailsApplication.config.getProperty('book.title')// 获取application.xml中配置的作者姓名def bookAuthorName = grailsApplication.config.getProperty('book.author.name')// 获取application.xml中配置的书籍价格,默认获取值的类型是String类型,通过第二个参数值的类型,值为空时返回第三个参数作为默认值def bookPrice = grailsApplication.config.getProperty('book.price', Integer, 50)// 注意这里没有配置 book.price, 应该返回默认值 50render "bookTitle = ${bookTitle}, bookAuthorName = ${bookAuthorName}, bookPrice = ${bookPrice}"}/*** 获取 grailsApplication.config 中所有配置信息* @return*/def allConfig() {grailsApplication.config?.sort{it.key}?.each {if( it.value.getClass().toString() != "class org.grails.config.NavigableMap"){render it.key + "=" + it.value + "<br/>"}}}/*** 从 Service中读取 grailsApplication.config 对象*/def getConfigFromService() {def result = helloService.useConfigInService()render "从Service中获取的book.title = ${result}"}}
启动项目访问http://localhost:8080/hello/getConfigFromService
成功在Service中通过grailsApplication获取application.yml中的配置信息。
在业务层中使用grailsApplication对象方式二
Service实现 GrailsConfigurationAware 接口,它提供了一个 setConfiguration 方法,该方法在类初始化时接受应用程序配置作为参数。然后通过这个参数获取相关的配置属性,赋值给service实例属性。这种方式比较麻烦,要为service定义属性来接收配置信息。了解一下就好。
实例代码:
import grails.core.support.GrailsConfigurationAwareclass MyService implements GrailsConfigurationAware {// 定义属性变量用于接收获取到的配置信息String recipientString greeting() {//在 service 方法中使用获取到的配置信息return "Hello ${recipient}"}// 该方法接收应用程序配置作为参数void setConfiguration(Config config) {// 通过配置参数获取配置信息recipient = config.getProperty('foo.bar.hello')}}
⎮使用Spring值注解注入配置信息
修改HelloController,在下面添加:
@Value('${book.author.name}')String bookAuthorName/*** 通过 Spring 的 Value 注解来注入配置* @return*/def getAuthorBookBySpringAno() {render "bookAuthorName = ${bookAuthorName}"}
启动项目访问http://localhost:8080/hello/getAuthorBookBySpringAno
注意:
在 Groovy 代码中,Value 注释的值必须使用单引号括起来,否则它会被解释为 GString 而不是 Spring 表达式。
@Value('${book.author.name}')
⎮在application.yml中访问命令行参数或者系统参数
修改conf/application.yml,添加age属性配置
book:title: "《Grails教程》"author:name: "肖伞"# age 属性值通过 ${AUTHOR_AGE} 从外部获取age: ${AUTHOR_AGE}
进入外部属性信息配置界面
进入命令行环境变量配置界面
添加配置名称为AUTHOR_AGE,值为18
保存配置
修改HelloController,添加accessExternalVarFromYml动作获取age
/*** 在YML文件中访问命令行参数或者外部系统信息*/def accessExternalVarFromYml() {render "age = " + grailsApplication.config.getProperty("book.author.age")}
启动项目
访问http://localhost:8080/hello/accessExternalVarFromYml
applicationi.yml成功获取到外部配置的AUTHOR_AGE属性。
⎮使用外部application.yml文件
默认情况下,Grails 将从 ./config 或当前目录读取 application.(properties|yml) .
由于 Grails4 是基于 Spring Boot 2.1.18 ,所以完全能参考Spring Boot的相关配置
这里简单测试一下使用外部application.yml文件更新服务启动端口号。
先进入项目所在目录,打包项目
grails war
➜ /Users/xiaosan/Documents/work/helloworldgrails4 >grails warBUILD SUCCESSFUL in 8s
7 actionable tasks: 4 executed, 3 up-to-date
| Built application to build/libs using environment: production
启动项目,默认运行在8080端口上
➜ /Users/xiaosan/Documents/work/helloworldgrails4 >java -jar build/libs/helloworldgrails4-0.1.war
Grails application running at http://localhost:8080 in environment: production
在build/libs目录创建一个application.yml文件,设置端口号8088
server:port: 8088
停止项目,重新使用一下命令启动项目
java -jar build/libs/helloworldgrails4-0.1.war --spring.config.additional-location=./build/libs/application.yml
➜ /Users/xiaosan/Documents/work/helloworldgrails4 >java -jar build/libs/helloworldgrails4-0.1.war --spring.config.additional-location=./build/libs/application.yml
Grails application running at http://localhost:8088 in environment: production
可以看到在没有改变已打包war文件的前提下,使用外部application.yml文件改变了默认的8080端口。
使用--spring.config.additional-location
添加了外部配置文件的位置,优先级高于默认的配置文件位置。
⎮内置的一些设置,了解一下有好处
Grails 有一组比较重要的核心设置。它们的默认值适用于大多数项目,但我们可能需要修改其中的一个或多个设置。这些设置都在application.yml中配置。
配置 | 默认值 | 描述 |
---|---|---|
grails.enable.native2ascii | true | 如果不需要 Grails i18n 属性文件的 native2ascii 转换,则将此设置为 false |
grails.views.default.codec | none | 设置 GSP 的默认编码机制 - 可以是“none”、“html”或“base64”之一。为了降低 XSS 攻击的风险,请将其设置为 ‘html’。 |
grails.views.gsp.encoding | utf-8 | 用于 GSP 源文件的文件编码 |
grails.mime.file.extensions | true | 是否使用文件扩展名来指定内容协商中的 mime 类型 |
grails.mime.types | all: */* | 用于内容协商的受支持 mime 类型的映射。 |
grails.serverURL | 指定绝对链接的服务器 URL 部分的字符串,包括服务器名称,例如grails.serverURL=“http://my.yourportal.com”。请参阅创建链接。也被重定向使用。 | |
grails.views.gsp.sitemesh.preprocess | 确定是否发生 SiteMesh 预处理。禁用它会减慢页面渲染的速度,但如果您需要 SiteMesh 从 GSP 视图解析生成的 HTML,那么禁用它是正确的选择。如果您不了解此高级属性,请不要担心:将其设置为 true。 | |
grails.reload.excludes 和 grails.reload.includes | 配置这些指令决定了项目特定源文件的重新加载行为。每个指令都采用一个字符串列表,这些字符串是项目源文件的类名,在使用 run-app 命令运行开发中的应用程序时,这些字符串应从重新加载行为中排除或相应地包含在内。如果配置了 grails.reload.includes 指令,则只会重新加载该列表中的类。 |
⎮Logging配置
从 Grails 3.0 开始,日志记录由 Logback 日志记录框架处理,并且可以使用 grails-app/conf/logback.groovy 文件进行配置。
在Grails中不需要我们自己去创建日志对象,Grails会自动把log对象注入到控制器、服务中。
在 Grails 3.3.0 之前,Grails 日志记录器的名称遵循约定
grails.app.<type>.<className>,其中 type 是控制器或者服务, className 是控制器或者服务的完全限定名称。
例如:
grails.app.controllers.com.company.BookController
这里的type是controllers,className是com.company.BookController
grails.app.services.com.company.BookService
这里的type是services,className是com.company.BookService
Grails 3.3.x 简化了记录器名称。下面的例子说明了这些变化:
控制器BookController.groovy 位于 grails-app/controllers/com/company
记录器名称(Grails 3.3.x 或更高版本) | 记录器名称(Grails 3.2.x 或更低版本) | |
---|---|---|
未用 @Slf4j 注解 | com.company.BookController | grails.app.controllers.com.company.BookController |
启用 @Slf4j 注解 | com.company.BookController | com.company.BookController |
BookService.groovy 位于 grails-app/services/com/company
记录器名称(Grails 3.3.x 或更高版本) | 记录器名称(Grails 3.2.x 或更低版本) | |
---|---|---|
未用 @Slf4j 注解 | com.company.BookService | grails.app.services.com.company.BookService |
启用 @Slf4j 注解 | com.company.BookService | com.company.BookService |
BookDetail.groovy 位于 src/main/groovy/com/company
记录器名称(Grails 3.3.x 或更高版本) | 记录器名称(Grails 3.2.x 或更低版本) | |
---|---|---|
启用 @Slf4j 注解 | com.company.BookDetail | com.company.BookDetail |
可见在Grails3.3版本之后就算不使用@Slf4j注解,日志记录器的名称也会比较精简,不会太过复杂,现在已经是Grails4版本了,我们在编写代码的时候可以不写@Slf4j注解。如果项目是Grails3.3之前的版本还是老老实实的加上。
Logging实例演示
修改 helloworldgrails4/HelloController.groovy的index方法,添加日志记录
def index() {// 这里的 log 对象是 grails 内置的对象,可以直接使用log.error("这是一个 error 级别的日志")log.warn("这是一个 warn 级别的日志")log.info("这是一个 info 级别的日志")log.debug("这是一个 debug 级别的日志")render "Hello World!"}
启动项目
访问http://localhost:8080/hello
,查看控制台输出
可以看到只输出了一条 error
级别的日志。
因为grails-app/conf/logback.groovy配置的是ERROR及以上的级别才会显示。
日志级别:DEBUG < INFO < WARN < ERROR < FATAL
logback.groovy 默认的日志配置
查看 grails-app/conf/logback.groovy 默认的日志配置
import grails.util.BuildSettings
import grails.util.Environment
import org.springframework.boot.logging.logback.ColorConverter
import org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverterimport java.nio.charset.StandardCharsets// 彩色日志依赖的渲染类
conversionRule 'clr', ColorConverter
conversionRule 'wex', WhitespaceThrowableProxyConverter// See http://logback.qos.ch/manual/groovy.html for details on configuration
// 配置一个日志输出目的地:控制台(ConsoleAppender),给这个目的地起别名为:STDOUT
appender('STDOUT', ConsoleAppender) {// 配置日志显示方式:自定义规则模式(PatternLayout)encoder(PatternLayoutEncoder) {// 显示日志的编码格式为UTF-8charset = StandardCharsets.UTF_8// 定义日志输出格式pattern =// %d{ } 格式化时间显示,%clr(%d{ }){faint} 将时间显示为淡灰色'%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} ' +// %p 显示日志级别,%5p表示字符串长度不足5个,用空格填充左边位置。%clr() 没有设置颜色默认红色'%clr(%5p) ' +// %t输出产出日志的线程名,%15.15t表示不足15左边填空格,超过15截去后面的。%clr(---){faint} 三个短横线淡灰色'%clr(---){faint} %clr([%15.15t]){faint} ' +// %logger 显示记录器的名称, %-40.40logger{39},名字长度小于40右边空格填充,超过40后面截断,{cyan}青色显示'%clr(%-40.40logger{39}){cyan} %clr(:){faint} ' + // Logger// %m显示输出信息,%n当前平台下的换行符,%wex在堆栈跟踪周围添加一些额外的空白'%m%n%wex' // Message}
}// targetDir 默认为当前项目目录下面的build目录
def targetDir = BuildSettings.TARGET_DIR
// 如果是开发环境,并且存在targetDir目录
if (Environment.isDevelopmentMode() && targetDir != null) {// 配置一个日志输出目的地:文件(FileAppender),给这个目的地起个别名叫:FULL_STACKTRACEappender("FULL_STACKTRACE", FileAppender) {// 配置日志输出到哪个文件file = "${targetDir}/stacktrace.log"// 是否覆盖:true持续添加日志,不覆盖之前添加的。false:覆盖之前添加的。append = true// 配置日志输出格式为:自定义规则模式(PatternLayoutEncoder)encoder(PatternLayoutEncoder) {// 配置日志编码为UTF-8charset = StandardCharsets.UTF_8// 自定义的日志输出格式pattern = "%level %logger - %msg%n"}}// 配置一个日志记录器名字叫StackTrace,记录ERROR及以上的信息,日志输出到别名为 FULL_STACKTRACE 的目的地,additivity:false信息不显示在父日志记录器中。logger("StackTrace", ERROR, ['FULL_STACKTRACE'], false)
}
// 配置根日志记录器,不用配置名字,记录ERROR及以上的日志信息,日志输出到别名为 STDOUT 的目的地
root(ERROR, ['STDOUT'])
彩色日志
logback.groovy 中使用了彩色日志配置,但是在IDEA的控制台中并没有输出彩色的日志。
要显示彩色日志,需要打开一个开关
-Dspring.output.ansi.enabled=always
1. IDEA控制台彩色日志输出方式一
在启动grails项目时,加上这个JVM配置就可以了,而grails4采用gradle来构建项目的,在build.gradle中已经配置好了彩色日志的启动任务,我们直接使用这个任务启动项目就可以了。
启动好之后,再次访问http://localhost:8080/hello
查看控制台输出
可以看到现在已经是彩色日志了。
2. IDEA控制台彩色日志输出方式二
使用helloworldgrails4/Application.groovy
启动项目
配置启动参数
启动项目
访问项目http://localhost:8080/hello
查看控制台输出
3. 打包后的项目默认是彩色日志,不需其他配置
可以看到在终端中启动项目,日志颜色更加的明显。
程序报错时,指定敏感请求参数不写入日志
当 Grails遇到错误, 记录堆栈跟踪时,日志消息可能包含当前请求的所有请求参数的名称和值。
可以在grails-app/conf/application.yml
文件中的grails.exceptionresolver.params.exclude
配置属性中指定要屏蔽参数名称:
grails:exceptionresolver:params:exclude:- password- creditCard
完全关闭请求参数日志记录功能
可以通过将 grails.exceptionresolver.logRequestParameters
配置属性设置为 false 来完全关闭请求参数日志记录。
当应用程序在 DEVELOPMENT 模式下运行时,默认值为 true,对于所有其他环境,默认值为 false。
grails:exceptionresolver:logRequestParameters: false
使用外部日志配置文件
1.使用logging.config指定外部Logback配置文件
修改grails-app/conf/application.yml
文件,添加外部日志配置
logging:config: /opt/logback.groovy
复制conf/logback.groovy
文件到/opt/logback.groovy
修改/opt/logback.groovy
最后一行,将根日志级别为WARN
// 配置根日志记录器,不用配置名字,记录WARN及以上的日志信息,日志输出到别名为 STDOUT 的目的地
root(WARN, ['STDOUT'])
重启启动项目,访问localhost:8080/hello/index
查看控制台输出
输出了ERROR和WARN的日志记录,说明使用了我们刚刚修改的外部日志配置文件。
2.使用JVM启动参数配置外部日志文件
删除grails-app/conf/application.yml
文件中的logging.config
配置。
在JVM配置中添加-Dlogging.config=/opt/logback.groovy
启动项目后查看控制台,同样使用的外部配置文件。
3. 系统环境变量添加LOGGING_CONFIG
删除grails-app/conf/application.yml
文件中的logging.config
配置。
删除JVM中的-Dlogging.config=/opt/logback.groovy
配置
在环境变量中配置LOGGING_CONFIG=/opt/logback.groovy
启动项目后查看控制台,同样使用的外部配置文件。
⎮GORM配置
为所有领域类启用 failOnError
在grails-app/conf/application.yml
文件中将
grails.gorm.failOnError
设置为 true,所有领域类在调用save()方法保存时,如果校验失败就会抛出grails.validation.ValidationException
异常。
grails:gorm:failOnError: true
按包名为领域类启用 failOnError
可以指定哪些包下面的领域类启用failOnError,该值是一个表示包名称的字符串列表。如果该值为字符串列表,则 failOnError 行为将仅限于这些包(包括子包)中的领域类。
grails:gorm:failOnError:- com.companyname.somepackage- com.companyname.someotherpackage
⎮小结
本章主要讲了Grails的基本配置:
- 如何配置,在哪里配置,在代码中如何访问这些配置。
- 如何将配置信息注入到程序中。
- 如何使用外部application.yml配置文件。
- 如何在程序中使用log日志,如何配置,在哪里配置。
- 如何配置保存领域类校验出错的行为。
下一章会讲如何配置外部数据源,数据持久化到数据库中。