You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Grails 5继承RestfulController时出现默认构造函数缺失问题

问题

正在将应用从Grails 2.5.2迁移至Grails 5.2.5,原Grails 2中有一个RestVehicleTrackingController继承自RestfulController,该控制器无需指定关联Domain,直接返回Map对象的JSON格式响应。但在Grails 5中,继承RestfulController时必须指定Domain,而我需要保留原有逻辑:查询任意Domain生成Map后返回JSON响应,尝试的代码如下:

URL映射

"/api/vehicleList/$gatepassNo?(.$format)?"(controller: 'restVehicleTracking', action: 'getVehicleList')

控制器代码

class RestVehicleTrackingController extends RestfulController {
    static allowedMethods = [search: 'GET', getVehicleList: 'GET']
    def restCommonService
    def vehicleTrackingService


    def getVehicleList(String gatepassNo) {
        def ipAddress = restCommonService.getClientIpAddress(request)
        def url = '/api/ws/vt/gatePass/vehicleList'
        String requestParams = params.toString()
        if (gatepassNo) {
            def retVal = vehicleTrackingService.getVehicleInformation(gatepassNo)
            if (retVal) {
                restCommonService.storeRequestInformation(url, requestParams, retVal.toString(), true, ipAddress, 'DOWN',)
                respond retVal, formats: ['json', 'xml']
            }
        }
        restCommonService.storeRequestInformation(url, requestParams, null, false, ipAddress, 'DOWN',)
        respond null, status: 404
    }
    
}

在Grails 2.5.2中代码运行正常,但在Grails 5.2.5中出现错误:

There is no default constructor available in class 'grails.rest.RestfulController'

解决方案

方案1:直接继承基础Controller类(推荐)

既然你的控制器不需要绑定特定Domain,也不需要RestfulController提供的默认CRUD方法,直接继承Grails基础的Controller类即可,完全保留原有业务逻辑:

class RestVehicleTrackingController extends Controller {
    static allowedMethods = [search: 'GET', getVehicleList: 'GET']
    def restCommonService
    def vehicleTrackingService

    def getVehicleList(String gatepassNo) {
        def ipAddress = restCommonService.getClientIpAddress(request)
        def url = '/api/ws/vt/gatePass/vehicleList'
        String requestParams = params.toString()
        if (gatepassNo) {
            def retVal = vehicleTrackingService.getVehicleInformation(gatepassNo)
            if (retVal) {
                restCommonService.storeRequestInformation(url, requestParams, retVal.toString(), true, ipAddress, 'DOWN')
                respond retVal, formats: ['json', 'xml']
                return // 提前返回,避免执行后续404逻辑
            }
        }
        restCommonService.storeRequestInformation(url, requestParams, null, false, ipAddress, 'DOWN')
        respond null, status: 404
    }
}

注:添加return是为了和原Grails 2行为保持一致,确保找到数据后不会触发后续的404响应。

方案2:显式指定泛型并提供构造函数(仅当需要RestfulController功能时使用)

如果一定要继承RestfulController,需要显式指定泛型类型并提供构造函数。由于不需要绑定特定Domain,可以用Object作为泛型参数:

class RestVehicleTrackingController extends RestfulController<Object> {
    // 提供符合RestfulController要求的构造函数
    RestVehicleTrackingController() {
        super(Object)
    }

    static allowedMethods = [search: 'GET', getVehicleList: 'GET']
    def restCommonService
    def vehicleTrackingService

    def getVehicleList(String gatepassNo) {
        // 原有业务逻辑不变
        def ipAddress = restCommonService.getClientIpAddress(request)
        def url = '/api/ws/vt/gatePass/vehicleList'
        String requestParams = params.toString()
        if (gatepassNo) {
            def retVal = vehicleTrackingService.getVehicleInformation(gatepassNo)
            if (retVal) {
                restCommonService.storeRequestInformation(url, requestParams, retVal.toString(), true, ipAddress, 'DOWN')
                respond retVal, formats: ['json', 'xml']
                return
            }
        }
        restCommonService.storeRequestInformation(url, requestParams, null, false, ipAddress, 'DOWN')
        respond null, status: 404
    }
}

注:此方案会引入RestfulController的默认CRUD方法(如index、show等),如果不需要这些方法,需要额外配置禁用,因此优先推荐方案1。

内容的提问来源于stack exchange,提问作者Sumon Bappi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 13:51:12