Grails集成测试调用RestfulController父类方法致请求异常问题
解决RestfulController子类POST请求调用父类save方法的问题
嘿,我来帮你捋捋这个问题——你在做Grails集成测试的时候,发POST请求居然触发了父类RestfulController的save方法,而不是子类MyController的实现,最后因为方法签名不匹配返回了422错误,对吧?
为啥会出现这情况?
核心原因是Grails的请求映射和方法匹配规则:如果你的子类save方法签名和父类不一致,框架可能找不到对应的子类方法,就会 fallback 到父类的默认实现。
举个例子,父类RestfulController的save是无参的:
def save() { // 父类默认逻辑 }
要是你子类的save写成带参数的,比如:
def save(MyDomain myDomain) { // 你的自定义逻辑 }
这种情况下,Grails的参数绑定机制没法把请求正确匹配到子类方法,就会去调用父类的无参save,自然就出现签名不匹配的问题了。
怎么解决?给你三个可行方案:
1. 对齐子类和父类的方法签名
最简单的办法就是让子类的save保持无参,在方法内部自己获取绑定的域对象,重写父类逻辑:
class MyController extends RestfulController<MyDomain> { static responseFormats = ['json', 'xml', 'hal'] MyController() { super(MyDomain) } @Override def save() { // 手动绑定请求参数到域对象 MyDomain myDomain = new MyDomain(params) // 你的自定义保存逻辑 if (myDomain.save(flush: true)) { respond myDomain, [status: CREATED] } else { respond myDomain.errors, [status: UNPROCESSIBLE_ENTITY] } } }
这样因为方法签名和父类完全一致,就能覆盖父类的实现,请求也会正确路由到子类的save。
2. 显式配置URL映射
如果你非得保留子类的方法签名,可以在UrlMappings.groovy里手动指定POST请求的路由,让它直接指向子类的save方法:
// grails-app/controllers/UrlMappings.groovy class UrlMappings { static mappings = { // 针对你的控制器配置路由 "/my"(controller: "my") { action = [POST: "save"] } // 或者API风格的路由 "/api/my"(controller: "my") { action = [POST: "save"] } // 保留默认路由 "/$controller/$action?/$id?(.$format)?"{ constraints { // apply constraints here } } } }
手动配置的路由优先级更高,框架会优先用这个映射,直接把POST请求打到子类的方法上。
3. 检查@Resource注解配置(如果用了的话)
要是你是用@Resource注解快速生成的REST控制器,得确保注解的配置没问题,重写方法时也保持签名一致:
@Resource(uri='/my', formats=['json', 'xml', 'hal']) class MyController extends RestfulController<MyDomain> { MyController() { super(MyDomain) } @Override def save() { // 你的自定义逻辑 } }
最后别忘了测试验证
写集成测试的时候,要确保请求格式正确,比如用Spock测试的话:
void "测试POST请求调用子类save方法"() { when: request.contentType = JSON_CONTENT_TYPE request.method = 'POST' request.content = '{"name": "测试数据"}'.bytes controller.save() then: response.status == HttpStatus.CREATED.value() }
这样就能验证请求确实触发了子类的save方法,返回正确的状态码啦。
内容的提问来源于stack exchange,提问作者Pila
相关产品推荐
相关产品推荐

