【问题标题】:grails.converters.JSON except few propertiesgrails.converters.JSON 除了少数属性
【发布时间】:2023-12-13 23:14:01
【问题描述】:

我正在使用 grails-1.3.2 和 hbase-0.2.4。

我有以下域类:

class MyClass{
  String val1
  String val2
  String val3

   //----

 }

class MyClassController{
    def someAction = {
        def myClass = new MyClass()
        //----

        String valAsJson = (myClass as JSON)

        render valAsJson 
     }
}

我的问题是,是否有任何捷径只渲染部分属性(例如渲染除 val3 属性之外的所有属性)?

【问题讨论】:

    标签: json grails groovy render converter


    【解决方案1】:

    JSON 排除 Marshaller 插件

    我最近需要解决这个问题。我继续将解决方案打包到一个插件中,使您可以轻松地从 JSON 转换器的输出中排除类属性。它在 Grails 插件门户上可用。

    在您install the plugin 之后,您将可以访问 grails.converters.JSON 类中称为 excludeFor*() 的方法。

    可以在此处找到更广泛的文档:How to use the JSON Exclusion Marshaller

    但基本上可以这样使用:

    import grails.converters.JSON
    
    def json, resultTeachersWillSee, resultOtherStudentsWillSee
    
    // Given a TestStudent Domain Class
    def student = new TestStudent([
        firstName: "Tobias",
        lastName: "Funke",
        gradePointAverage: 3.6,
        studentID: "FS-210-7312",
        socialSecurityNumber: "555-55-5555"
    ])
    student.save(flush: true)
    
    // When
    JSON.excludeForTeachers(TestStudent, ['socialSecurityNumber', 'id', 'class'])
    
    JSON.use('excludeForTeachers') {
        json = new JSON(student)
    }
    resultTeachersWillSee = json.toString()
    
    // Then
    assert resultTeachersWillSee == '{"firstName":"Tobias",
           "gradePointAverage":3.6, "lastName":"Funke", 
           "studentID":"FS-210-7312"}'
    
    
    
    // And When
    JSON.excludeForOtherStudents(TestStudent, ['gradePointAverage', 'studentID', 
         'socialSecurityNumber', 'id', 'class'])
    
    JSON.use('excludeForOtherStudents') {
        json = new JSON(student)
    }
    resultOtherStudentsWillSee = json.toString()
    
    // Then
    assert resultOtherStudentsWillSee == '{"firstName":"Tobias",
           "lastName":"Funke"}'
    

    JSON.excludeForTeachers(...) 创建一个名为“excludeForTeachers”的命名对象编组器。编组器从结果 JSON 输出中排除学生对象的三个属性。 'socialSecurityNumber' 属性在类中明确定义,而 'id' 属性是由 GORM 在幕后添加的。在任何情况下,教师都不需要查看任何这些属性。

    该插件对我很有帮助...我希望其他人也觉得它有帮助。

    【讨论】:

      【解决方案2】:

      或者,您可以创建所需属性的映射,然后将它们编码为 JSON

      Map m = [ 'val1', 'val2' ].inject( [:] ) { map, val -> map."$val" = a."$val" ; map }
      render m as JSON
      

      要排除属性,您需要执行以下操作(未测试)

      def exclude = [ 'val3' ]
      Map m = new DefaultGrailsDomainClass( MyClass.class ).properties.findAll {
        !( it.name in exclude )
      }.inject( [:] ) { map, val ->
        map."$val.name" = a."$val.name" ; map
      }
      render m as JSON
      

      【讨论】:

      • 添加了我认为应该可以工作的内容...虽然没有测试过...如果您尝试过并且有效,您能告诉我吗?
      【解决方案3】:

      如果您只是想将MyClass 的实例呈现为JSON,不包括某些属性,这里有一个使用Grails 提供的JSONBuilder 类的解决方案

      import grails.web.JSONBuilder
      
      class MyClassController{
      
          def someAction = {
      
              def myClass = new MyClass()
      
              def builder = new JSONBuilder.build {
                  myClass.properties.each {propName, propValue ->
      
                  // Properties excluded from the JSON
                  def excludes = ['class', 'metaClass', 'val3']
      
                  if (!excludes.contains(propName)) {
      
                      setProperty(propName, propValue)
                  }
              }
              render(text: builder.toString(), contentType: 'application/json')
           }
      }
      

      【讨论】:

        【解决方案4】:

        如果您只想始终包含特定属性,那么您真的需要使用 ObjectMarshaller 接口。详情请见this article

        【讨论】:

        • Gregg 它有效,但我想排除属性,因为我的域类很少,可能需要 20 个或更多属性,我只想除一两个。如果我没有找到其他除了我会使用它的解决方案...谢谢
        • @Gregg 在实施编组器时您是否认为或遇到过性能问题。我们已经在我们的 2 个项目中使用过它们并且我们体验过。有没有其他方法可以解决这个问题?
        【解决方案5】:

        你可以这样做:

        def myClass = MyClass.get(1)
        
         //include
         render myClass.part(include:['val1', 'val2']) as JSON
        
         //except
         render job.part(except:['val2','val3']) as JSON
        

        Bootstrap.groovy:

        import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor as Events
        
        class BootStrap {
         def grailsApplication
        
         def excludedProps = [Events.ONLOAD_EVENT,
            Events.BEFORE_DELETE_EVENT, Events.AFTER_DELETE_EVENT,
            Events.BEFORE_INSERT_EVENT, Events.AFTER_INSERT_EVENT,
            Events.BEFORE_UPDATE_EVENT, Events.AFTER_UPDATE_EVENT]
        
          def init = { servletContext ->
             grailsApplication.domainClasses.each{ domainClass ->
                 domainClass.metaClass.part= { m ->
                     def map= [:]
                     if(m.'include'){
                         m.'include'.each{
                             map[it]= delegate."${it}"
                         }
                     }else if(m.'except'){
                         m.'except'.addAll excludedProps
                         def props= domainClass.persistentProperties.findAll {
                             !(it.name in m.'except')
                         }
                         props.each{
                             map[it.name]= delegate."${it.name}"
                         }
                     }
                     return map
                 }
             }
          }
          def destroy = {
          }
        }
        

        如果您知道如何创建我们自己的插件,那么只需为此创建一个插件,这样您就可以在所有 grails 应用程序中使用它。

        【讨论】: