Командный объект Grails: как загрузить в него request.JSON?

Вопрос: есть ли способ сделать автоматическую привязку объекта команды к данным request.JSON?

Учитывая этот простой объект Command в моем контроллере Grails:

class ProfileCommand{

int id
String companyName

static constraints = {
    companyName blank: false
    id nullable: false
}

@Override
public String toString() {
    return "ProfileCommand{id=$id, companyName='$companyName'}";
}
}

и моя подпись метода контроллера:

def update(ProfileCommand command) {...}

Как я могу получить данные request.JSON в свой командный объект?

До сих пор единственный способ сделать это — создать объект команды вручную в методе update(), передав request.JSON в качестве аргумента конструктора:

    def command = new ProfileCommand(request.JSON)

    log.debug "Command object contents: $command"

Приведенная выше команда отладки производит:

Command object contents: ProfileCommand{id=1, companyName='Blub Muckers'}

Это именно то, что я хочу (большой привет Оливеру Тайнсу за вышеупомянутое решение). К сожалению, вызов command.validate() после создания команды приводит к следующему исключению:

Class org.codehaus.groovy.grails.web.taglib.exceptions.GrailsTagException
Message Tag [validate] is missing required attribute [form]

Я использую v2.0.3, uris произвел такое же исключение с v2.0.4.

ОБНОВЛЕНИЕ Согласно Иэну Робертсу из списка рассылки Grails, вам нужно добавить аннотацию @Validateable к классу команд, чтобы заставить validate() работать. Спасибо, Ян!


person John Gordon    schedule 31.05.2012    source источник


Ответы (3)


Я не уверен, есть ли что-нибудь с точки зрения конфигурации для автоматической привязки данных параметра JSON; одна вещь, которую вы можете сделать, это написать фильтр для ваших действий, которые принимают входные данные запроса JSON, который в основном переназначает request.JSON непосредственно на карту корневых параметров, что теоретически должно позволять выполнять автоматическую привязку данных.

что-то типа:

class JSONParamMapFilters {
  def filters = {
     before = {
        remapFilter(controller:'yourController', action:'update') {
           request.JSON.each { k,v ->
               params[k] = v
           }
        }
     }
  }
}

Затем вы можете расширить этот фильтр с помощью регулярных выражений/соглашений об именах для любых применимых действий контроллера.

person Aquatoad    schedule 31.05.2012
comment
Это сработает. Я отмечу это как ответ, если у кого-то еще нет другого предложения. Спасибо, Акватод! - person John Gordon; 31.05.2012
comment
Рад помочь. Я также удалю бит, исправленный аннотацией @Validateable. - person Aquatoad; 31.05.2012

Вы должны использовать parseRequest=true в UrlMappings.groovy. Например.:

"/user/$id/$action?"(controller: "userProfile", parseRequest: true) {
    constraints {
        id matches: /^[0-9]+$/
    }
}

Затем вы можете использовать переменную params или привязать json к объекту команды в аргументах метода:

def index(MyCommand command){...}

Оба должны работать. Но в некоторых случаях теряет часть информации из json (привязка к картам).

person Dmitry Kurinskiy    schedule 28.01.2013
comment
Просто к вашему сведению для читателей на grails 2.3, parseRequest теперь ничего не делает, вам нужно обрабатывать JSON вручную. - person Oliver Tynes; 05.06.2014

Если вы не используете объект команды в качестве параметра каких-либо действий контроллера, Grails не будет автоматически улучшать его с помощью метода проверки. Вам нужно аннотировать класс с помощью @Validateable, чтобы указать Grails, что его следует улучшить.

http://grails.org/doc/latest/guide/validation.html#validationNonDomainAndCommandObjectClasses

person Ian Roberts    schedule 31.05.2012