복붙노트

[SPRING] 엔티티를 json으로 최대 절전 모드로 전환

SPRING

엔티티를 json으로 최대 절전 모드로 전환

나는 Hibernate 4와 Spring 3를 사용한다.

나는 두 개의 실체를 가지고있다.

책 엔티티

@Entity
@Table(name = "book")
public class Book implements Serializable {

    public Book() {
    }

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY)
    private int id;

    @ManyToOne()
    @JoinColumn( name = "author_id" )
    private Author author;

    private String name;
    private int pages;

    @Version
    @Column( name = "VERSION")
    private int version;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Author getAuthor() {
        return author;
    }

    public void setAuthor(Author author) {
        this.author = author;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPages() {
        return pages;
    }

    public void setPages(int pages) {
        this.pages = pages;
    }

    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }


}

및 작성자 엔티티

@Entity
@Table(name = "author")
public class Author implements Serializable {

    public Author() {
    }

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY)
    private int id;
    private String name;

    @OneToMany( mappedBy = "author", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Book> books = new HashSet<Book>();


    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public Set<Book> getBooks() {
        return books;
    }
    public void setBooks(Set<Book> books) {
        this.books = books;
    }

    public void addBook(Book book) {
        book.setAuthor(this);
        getBooks().add(book);
    }

    public void removeBook(Book book) {
        getBooks().remove(book);        
    }

}

및 JSON은 pom.xml에 종속됩니다.

<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.1.2</version>
        </dependency>


        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-hibernate4</artifactId>
            <version>2.1.2</version>
        </dependency>

내 루트 컨텍스트가 여기 있습니다 -

    <!-- Root Context: defines shared resources visible to all other web components -->
    <context:annotation-config/>

    <context:component-scan base-package="org.jar.libs.dao" />
    <context:component-scan base-package="org.jar.libs.service" />

    <tx:annotation-driven transaction-manager="transactionManager" />

     <bean id="jspViewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource"
        p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/hibernate"
        p:username="root" p:password="root" />

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                <value>org.jar.libs.domain.Book</value>
                <value>org.jar.libs.domain.Author</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

</beans>

... servlet-context.xml

<!-- Enables the Spring MVC @Controller programming model -->
    <annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

    <context:component-scan base-package="org.jar.libs.controller" />

제어 장치.

@Controller
@RequestMapping (value = "books/rest")
public class BookController {

    @Autowired
    private BookService bookService;

    // logger
    private static final Logger logger = LoggerFactory.getLogger(BookController.class);


    @SuppressWarnings("unchecked")
    @RequestMapping( method = RequestMethod.GET )
    public @ResponseBody List<Book> getBook() {


        List<Book> res = bookService.findAll();
        return res;


    }

}

내 DAO에서 findAll :

public List<Book> findAll() {
        Session session = sessionFactory.getCurrentSession();
        List<Book> result = (List<Book>) session.createQuery("select c from Book c").list();
        return result;
    }

디버그에서 그 방법은 2 레코드를 반환하지만, 봄은 JSON 결과를 변환하고 406 HTTP 오류를 반환 할 수 없습니다 참조하십시오. 뭐가 문제 야?

나는 디버그에서 볼 수있는 이미지를 첨부한다. - http://tinypic.com/view.php?pic=35kvi9i&s=6

해결법

  1. ==============================

    1.일반적으로, 트랜잭션 (transaction) 중에 관계 오브젝트를 돌려주는 엔티티 클래스의 getter 메소드를 호출하면 (자), LazyInitializationExceptions가 취득됩니다.

    일반적으로, 트랜잭션 (transaction) 중에 관계 오브젝트를 돌려주는 엔티티 클래스의 getter 메소드를 호출하면 (자), LazyInitializationExceptions가 취득됩니다.

    그것은 트랜잭션에서 json으로 엔티티 클래스 객체 (질의에서 검색)를 변환하는 경우에 발생할 수 있습니다.

    나는 동일한 문제를 가지고 있었고, 최대 절전 모드로 검색된 엔티티 객체를 컨트롤러의 json으로 변환했다. 컨트롤러가 트랜잭션 (서비스 계층의 트랜잭션)에서 json으로 변환하는 동안 엔티티 클래스 객체의 getter 메소드가 호출되고 LazyInitializationException이 발생합니다. json으로의 객체 변환을 방해 한 응답이 반환되지 않았습니다.

    내 솔루션, 시도해보십시오 :

    @SuppressWarnings("unchecked")
    @RequestMapping( method = RequestMethod.GET )
    public @ResponseBody List<Book> getBook() {
        List<Book> res = bookService.findAll();
        for(Book book : res) {
           book.getAuthor().setBooks(null);
        }
        return res;
    }
    
  2. ==============================

    2.다른 사람들이 제안한 것처럼, 절대로 JSON으로 동면체를 직렬화 (또는 실제로 직렬화를 수행)하려고 시도하지 말라. 가져온 엔티티가 실제로 "프록시 화 된"객체라는 것을 명심해야한다 (Hibernate는 ASM, CGLIB 및 다른 "동적 프록시"프레임 워크를 사용한다). 예를 들어, 콜렉션은 [lazily]로 초기화 될 수있는 [PersistenceBags]로 대체되어 예외를 최대 절전 모드로 만듭니다. 하지만 문제는 거기서 멈추지 않는다. Hibernate 사용자 정의 유형을 직렬화하려고 할 때 문제가 발생할 수있다. 나는 이것이 여러분이 "보일러 플레이트"코드를 작성하는 것처럼 들리 겠지만, DAL에서 반환 된 엔티티를 취할 데이터 전송 객체 인 DTO를 코딩하고 직렬화 할 수있는 객체로 변환 할 수 있습니다.

    다른 사람들이 제안한 것처럼, 절대로 JSON으로 동면체를 직렬화 (또는 실제로 직렬화를 수행)하려고 시도하지 말라. 가져온 엔티티가 실제로 "프록시 화 된"객체라는 것을 명심해야한다 (Hibernate는 ASM, CGLIB 및 다른 "동적 프록시"프레임 워크를 사용한다). 예를 들어, 콜렉션은 [lazily]로 초기화 될 수있는 [PersistenceBags]로 대체되어 예외를 최대 절전 모드로 만듭니다. 하지만 문제는 거기서 멈추지 않는다. Hibernate 사용자 정의 유형을 직렬화하려고 할 때 문제가 발생할 수있다. 나는 이것이 여러분이 "보일러 플레이트"코드를 작성하는 것처럼 들리 겠지만, DAL에서 반환 된 엔티티를 취할 데이터 전송 객체 인 DTO를 코딩하고 직렬화 할 수있는 객체로 변환 할 수 있습니다.

    엔티티와 DTO 간의 직렬화 개발을 쉽게하기 위해 dozer와 같은 프레임 워크를 사용할 수 있습니다.

  3. ==============================

    3.이 두 가지 Jackson 유물을 대신 사용해보십시오.

    이 두 가지 Jackson 유물을 대신 사용해보십시오.

    <dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.9</version>
    </dependency>
    
    <dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-core-asl</artifactId>
    <version>1.9.9</version>
    </dependency>
    

    또한 컨트롤러에서 컨트롤러를 다음과 같이 변경하십시오.

     @SuppressWarnings("unchecked")
    @RequestMapping( method = RequestMethod.GET,  produces = MediaType.APPLICATION_JSON_VALUE )
    public @ResponseBody List<Book> getBook() {
    

    마지막으로,보기가 json 요청을하고 있는지 확인하십시오.

  4. ==============================

    4.필드를 serialize하지 않으려면 @ com.fasterxml.jackson.annotation.JsonIgnore 주석을 사용할 수 있습니다. 따라서 해당 필드의 getter는 호출되지 않습니다.

    필드를 serialize하지 않으려면 @ com.fasterxml.jackson.annotation.JsonIgnore 주석을 사용할 수 있습니다. 따라서 해당 필드의 getter는 호출되지 않습니다.

    @JsonIgnore
    @OneToMany( mappedBy = "author", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Book> books = new HashSet<Book>();
    
  5. from https://stackoverflow.com/questions/14141718/hibernate-entity-to-json by cc-by-sa and MIT license