4

我使用休眠 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;


    }

}

findAll 在我的 DAO 中:

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

在调试中,我看到该方法返回 2 条记录,但 Spring 无法将结果转换为 JSON 并返回 406 HTTP 错误。怎么了?

我附上我在调试中看到的图像。- http://tinypic.com/view.php?pic=35kvi9i&s=6

4

3 回答 3

4

通常,当您在事务之外调用实体类(返回关系对象)的 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;
}
于 2013-01-03T15:40:39.917 回答
1


正如其他人所建议的那样,我真的不建议您尝试对休眠实体进行 JSON 序列化(或实际执行任何序列化)。
您必须记住,获取的实体实际上是“代理”对象(Hibernate 使用 ASM、CGLIB 和其他“动态代理”框架)。
结果,例如,集合被替换为 [PersistenceBags] 可能被初始化为 "lazily" ,并导致您休眠异常1

但问题并不止于此,您可能会在尝试序列化 Hibernate自定义类型时看到问题
我知道这听起来您可能喜欢编写“样板”代码,但您最终可能会编写 DTO - 数据传输对象,它将获取从 DAL 返回的实体,并将它们转换为可以序列化的对象。

您可以使用 dozer 之类的框架来简化实体与 DTO 之间的序列化开发。

于 2015-05-29T01:03:05.370 回答
0

尝试改用这两个 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 请求。

于 2013-01-03T15:25:26.270 回答