Grails 3.2.11 Bugs

  • Functional Testing setup无法回滚
1
2
3
4
5
6
7
8
9
10
class BaseFunctionalTest extends GebSpec {
def setup() {
Dog dog = new Dog(name:'xxxx')
}

//需要手动删除
def cleanup() {
Dog.findByName('xxxx')?.delete()
}
}
  • JSON Views循环渲染bug

如果多个GORM实体存在循环引用,则会产生stackover flow异常,如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
Class A {
static hasMany = [children: B]
}

Class B {
A parent
}

def a = new A()
def b = new B(parent:a)
a.addToChildren(b)

json g.render(a, [deep: true])

Spring RestTemplate 打印Request及Response内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import org.apache.commons.io.IOUtils
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.http.HttpRequest
import org.springframework.http.client.ClientHttpRequestExecution
import org.springframework.http.client.ClientHttpRequestInterceptor
import org.springframework.http.client.ClientHttpResponse


class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {

static final String DEFAULT_ENCODING = 'UTF-8'
static final Logger LOGGER = LoggerFactory.getLogger(LoggingRequestInterceptor)

@Override
ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
traceRequest(request, body)
ClientHttpResponse response = execution.execute(request, body)
traceResponse(response)
return response
}

private void traceRequest(HttpRequest request, byte[] body) throws IOException {
LOGGER.info('===========================request begin================================================')
LOGGER.info('URI : {}', request.URI)
LOGGER.info('Method : {}', request.method)
LOGGER.info('Headers : {}', request.headers)
LOGGER.info('Request body: {}', new String(body, 'UTF-8'))
LOGGER.info('==========================request end================================================')
}

private void traceResponse(ClientHttpResponse response) throws IOException {
LOGGER.info('============================response begin==========================================')
LOGGER.info('Status code : {}', response.statusCode)
LOGGER.info('Status text : {}', response.statusText)
LOGGER.info('Headers : {}', response.headers)
LOGGER.info('Response body: {}', IOUtils.toString(response.body, DEFAULT_ENCODING))
LOGGER.info('=======================response end=================================================')
}

}
  • 配置RestTemplate
1
2
3
RestTemplate restTemplate = new RestTemplate()
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()))
restTemplate.setInterceptors([new LoggingRequestInterceptor()])

由于会多次读取request及response body,所以我们这里会使用BufferingClientHttpRequestFactory类来保证能够读取多次。

Groovy正则表达式用法

Matcher example:

1
2
3
4
5
6
7
8
9
10
11
//Matcher example
String regexStr = /gr.*/
String str = 'groovy'

Matcher matcher0 = (str =~ regexStr)
boolean result0 = (str ==~ regexStr)
assert matcher0.matches() == result0

Matcher matcher1 = (str =~ /$regexStr/)
boolean result1 = (str ==~ /$regexStr/)
assert matcher1.matches() == result1

Find example:

1
2
3
4
5
6
def cool = /gr\w{4}/  // Start with gr followed by 4 characters.
Matcher matcher2 = ('groovy, java and grails rock!' =~ /$cool/)
assert 2 == matcher2.count
assert 2 == matcher2.size() // Groovy adds size() method.
assert 'groovy' == matcher2[0] // Array-like access to match results.
assert 'grails' == matcher2.getAt(1)

Sl4j+Logback依赖配置

1
2
3
4
5
6
7
8
9
def sl4jVersion = '1.7.25'
def logbackVersion = '1.2.3'

compile group: 'ch.qos.logback', name: 'logback-core', version: logbackVersion
compile group: 'ch.qos.logback', name: 'logback-classic', version: logbackVersion
compile group: 'ch.qos.logback', name: 'logback-access', version: logbackVersion
compile group: 'org.slf4j', name: 'slf4j-api', version: sl4jVersion
compile group: 'org.slf4j', name: 'jcl-over-slf4j', version: sl4jVersion
compile group: 'org.slf4j', name: 'log4j-over-slf4j', version: sl4jVersion