小型 facelet 应用程序中的 javax.persistence.TransactionRequiredException [英] javax.persistence.TransactionRequiredException in small facelet application

查看:20
本文介绍了小型 facelet 应用程序中的 javax.persistence.TransactionRequiredException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将一些值从小型 facelet 应用程序保存到 MySql 数据库,但不断收到此错误.我有一个带有 JPS 页面和 servlet 的相同应用程序,它在大致相同的逻辑下运行良好,这是我第一次尝试使用 facelets,所以它可能只是一些愚蠢的事情,但我会感谢帮助.

谢谢

错误

javax.faces.el.E​​valuationException: javax.persistence.TransactionRequiredException在 javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)在 com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)在 javax.faces.component.UICommand.broadcast(UICommand.java:315)在 javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)在 javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)在 com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)在 com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)在 com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)在 javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)在 org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)在 org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)在 org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)在 org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)在 com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)在 com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)在 com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)在 com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)在 com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)在 com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)在 com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)在 com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)在 com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)在 com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)在 com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)在 com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)在 com.sun.grizzly.ContextTask.run(ContextTask.java:71)在 com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)在 com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)在 java.lang.Thread.run(Thread.java:722)引起:javax.persistence.TransactionRequiredException在 com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTxRequiredCheck(EntityManagerWrapper.java:163)在 com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTransactionScopedTxCheck(EntityManagerWrapper.java:145)在 com.sun.enterprise.container.common.impl.EntityManagerWrapper.persist(EntityManagerWrapper.java:263)在 vecka19.controller.BookController.addBook(BookController.java:28)在 vecka19.controller.BookController$Proxy$_$$_WeldClientProxy.addBook(BookController$Proxy$_$$_WeldClientProxy.java)在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)在 java.lang.reflect.Method.invoke(Method.java:601)在 javax.el.BeanELResolver.invokeMethod(BeanELResolver.java:779)在 javax.el.BeanELResolver.invoke(BeanELResolver.java:528)在 javax.el.CompositeELResolver.invoke(CompositeELResolver.java:257)在 com.sun.el.parser.AstValue.invoke(AstValue.java:248)在 com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:302)在 org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:39)在 org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)在 com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)在 javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)... 32 更多

index.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"xmlns:h="http://java.sun.com/jsf/html"xmlns:c="http://java.sun.com/jsp/jstl/core"><h:头><title>Vecka19</title></h:head><h:body><section id="bookForm"><div><h:form id="bookForm"><表格><tr><td><h:outputLabel value="ID:" for="id"/></td><td><h:inputText id="id" value="#{book.bookId}"/></td></tr><tr><td><h:outputLabel value="TITLE:" for="title"/></td><td><h:inputText id="title" value="#{book.title}"/></td></tr><tr><td><h:outputLabel value="AUTHOR:" for="author"/></td><td><h:inputText id="author" value="#{book.author}"/></td></tr><tr><td><h:outputLabel value="PRICE:" for="price"/></td><td><h:inputText id="price" value="#{book.price}"/></td></tr><tr><td><h:commandButton value="Add" action="#{bookController.addBook()}"/><h:commandButton value="Get" action="#{bookController.book}"/><h:commandButton value="Edit" action="#{bookController.editBook()}"/><h:commandButton value="Delete" action="#{bookController.deleteBook()}"/></td></tr></h:form>

</节><br/><section id="dbTable"><div><表格><th>ID</th><th>TITLE</th><th>作者</th><th>价格</th><c:forEach items="${bookController.books}" var="book"><tr><td>${book.bookId}</td><td>${book.title}</td><td>${book.author}</td><td>${book.price}</td></tr></c:forEach>

</节></h:body>

BookController.java

package vecka19.controller;导入 java.util.List;导入 javax.enterprise.context.RequestScoped;导入 javax.inject.Inject;导入 javax.inject.Named;导入 javax.persistence.EntityManager;导入 javax.persistence.PersistenceContext;进口 vecka19.model.Book;@命名@RequestScoped公共类 BookController {@Inject Book book;@PersistenceContext私有 EntityManager em;公共列表 getBooks() {返回 em.createNamedQuery("Book.findAll").getResultList();}公共书 getBook() {返回 em.find(Book.class, book.getBookId());}公共无效 addBook() {em.persist(书);}公共无效编辑书(){em.merge(书);}公共无效删除书(){em.remove(getBook());}}

Book.java

package vecka19.model;导入 java.io.Serializable;导入 javax.enterprise.context.RequestScoped;导入 javax.inject.Named;导入 javax.persistence.Column;导入 javax.persistence.Entity;导入 javax.persistence.Id;导入 javax.persistence.NamedQueries;导入 javax.persistence.NamedQuery;导入 javax.persistence.Table;导入 javax.validation.constraints.NotNull;@实体@命名@RequestScoped@Table(name = "书籍")@NamedQueries({@NamedQuery(name = "Book.findAll", query = "SELECT b FROM Book b")})公共类 Book 实现了 Serializable {private static final long serialVersionUID = 1L;@ID@NotNull@Column(name = "BOOK_ID")私人整数书号;@Column(name = "TITLE")私人字符串标题;@Column(name = "作者")私人字符串作者;@Column(name = "价格")私人整数价格;公共书(){}公共书(整数书号){this.bookId = bookId;}公共整数 getBookId() {返回书号;}public void setBookId(Integer bookId) {this.bookId = bookId;}公共字符串 getTitle() {返回标题;}公共无效设置标题(字符串标题){this.title = 标题;}公共字符串 getAuthor() {返回作者;}公共无效setAuthor(字符串作者){this.author = 作者;}公共整数 getPrice() {退货价格;}public void setPrice(整数价格){this.price = 价格;}}

percistence.xml

<persistence-unit name="vecka19PU" transaction-type="JTA"><jta-data-source>jdbc/MySQLDataSource</jta-data-source><exclude-unlisted-classes>false</exclude-unlisted-classes><属性/></persistence-unit></持久性>

解决方案

您正在滥用 CDI 托管 bean 作为业务服务.它没有事务管理的线索.您需要手动管理事务.由于这通常很痛苦,而且您显然在使用 Glassfish,它是一个支持 EJB 的完整 Java EE 容器,因此您更愿意为此使用完整的 EJB.在 EJB 中使用 EntityManager 时,容器将完全透明地管理 DB 事务.一个 EJB 方法调用算作单个事务(即,当您触发多个数据库查询并且其中一个失败时,所有内容都将自动回滚).

总的来说,您似乎混合了模型、控制器和服务的职责.不要让您的实体也成为托管 bean.您也绝对不要在 Javabean getter 方法(例如 getBooks())中执行业务逻辑.当在迭代组件中被引用时,它会在每个迭代轮中被调用.因此,假设您有 100 条记录,那么 DB 将被命中 100 次.这显然是低效的.

它应该是这样的:

模型(实体):

@Entity@Table(name = "BOOKS")公共类 Book 实现了 Serializable {//...}

控制器(支持 bean):

@Named@RequestScoped公共类 BookController {私人书本;私人列表<Book>图书;@EJB私人订书服务服务;@PostConstruct公共无效初始化(){书=新书();书籍 = service.list();}公共无效添加(){service.save(book);在里面();}公共书 getBook() {还书;}公共列表<Book>获取书籍(){还书;}}

服务(EJB):

@Stateless公共类图书服务{@PersistenceContext私有 EntityManager em;公共列表<Book>列表() {返回 em.createQuery(FROM Book", Book.class).getResultList();}公共图书查找(整数 ID){返回 em.find(Book.class, id);}公共整数保存(书本){em.persist(书);返回 book.getId();}公共无效更新(书本){em.merge(书);}公共无效删除(书本){em.remove(em.contains(book) ? book : em.merge(book));}}

视图(Facelet;简化):

<h:inputText id="作者"值=#{bookController.book.author}"/><h:inputText id="price";值=#{bookController.book.price}"/><h:commandButton value=添加"动作=#{bookController.add}";/>...<h:dataTable value="#{bookController.books}";var=书"><h:column><f:facet name=header">ID</f:facet>#{book.id}</h:column><h:column><f:facet name="header">Title</f:facet>#{book.title}</h:column><h:column><f:facet name="header">作者</f:facet>#{book.author}</h:column><h:column><f:facet name="header">Price</f:facet>#{book.price}</h:column></h:dataTable>

(你的编辑和删除按钮没有任何意义,所以我删除了它们,你可能想把它们放在数据表中)

另见:

I'm trying to persist some values to a MySql database from a small facelet application but keep getting this error. I had this same application with a JPS page and a servlet and it worked fine with roughly the same logic, this is my first time trying to work with facelets so it might just be something silly but i'd appriciate the help.

Thanks

error

javax.faces.el.EvaluationException: javax.persistence.TransactionRequiredException
    at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
    at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
    at javax.faces.component.UICommand.broadcast(UICommand.java:315)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
    at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:722)
Caused by: javax.persistence.TransactionRequiredException
    at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTxRequiredCheck(EntityManagerWrapper.java:163)
    at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTransactionScopedTxCheck(EntityManagerWrapper.java:145)
    at com.sun.enterprise.container.common.impl.EntityManagerWrapper.persist(EntityManagerWrapper.java:263)
    at vecka19.controller.BookController.addBook(BookController.java:28)
    at vecka19.controller.BookController$Proxy$_$$_WeldClientProxy.addBook(BookController$Proxy$_$$_WeldClientProxy.java)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at javax.el.BeanELResolver.invokeMethod(BeanELResolver.java:779)
    at javax.el.BeanELResolver.invoke(BeanELResolver.java:528)
    at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:257)
    at com.sun.el.parser.AstValue.invoke(AstValue.java:248)
    at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:302)
    at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:39)
    at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
    at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
    ... 32 more

index.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
    <title>Vecka19</title>
</h:head>
<h:body>
    <section id="bookForm">
        <div>
            <h:form id="bookForm">
                <table>
                    <tr>
                        <td><h:outputLabel value="ID: " for="id"/></td>
                        <td><h:inputText id="id" value="#{book.bookId}"/></td>
                    </tr>
                    <tr>
                        <td><h:outputLabel value="TITLE: " for="title"/></td>
                        <td><h:inputText id="title" value="#{book.title}"/></td>
                    </tr>
                    <tr>
                        <td><h:outputLabel value="AUTHOR: " for="author"/></td>
                        <td><h:inputText id="author" value="#{book.author}"/></td>
                    </tr>
                    <tr>
                        <td><h:outputLabel value="PRICE: " for="price"/></td>
                        <td><h:inputText id="price" value="#{book.price}"/></td>
                    </tr>
                    <tr>
                        <td>
                            <h:commandButton value="Add" action="#{bookController.addBook()}" />
                            <h:commandButton value="Get" action="#{bookController.book}" />
                            <h:commandButton value="Edit" action="#{bookController.editBook()}" />
                            <h:commandButton value="Delete" action="#{bookController.deleteBook()}" />
                        </td>
                    </tr>
                </table>
            </h:form>
        </div>
    </section>
    <br />
    <section id="dbTable">
        <div>
            <table>
                <th>ID</th>
                <th>TITLE</th>
                <th>AUTHOR</th>
                <th>PRICE</th>
                <c:forEach items="${bookController.books}" var="book">
                    <tr>
                        <td>${book.bookId}</td>
                        <td>${book.title}</td>
                        <td>${book.author}</td>
                        <td>${book.price}</td>
                    </tr>
                </c:forEach>
            </table>
        </div>
    </section>
</h:body>

BookController.java

package vecka19.controller;

import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import vecka19.model.Book;

@Named
@RequestScoped
public class BookController {
    @Inject Book book;

    @PersistenceContext
    private EntityManager em;

    public List getBooks() {
        return em.createNamedQuery("Book.findAll").getResultList();
    }

    public Book getBook() {
        return em.find(Book.class, book.getBookId());
    }

    public void addBook() {
        em.persist(book);
    }

    public void editBook() {
        em.merge(book);
    }

    public void deleteBook() {
        em.remove(getBook());
    }

}

Book.java

package vecka19.model;

import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;

@Entity
@Named
@RequestScoped
@Table(name = "BOOKS")
@NamedQueries({@NamedQuery(name = "Book.findAll", query = "SELECT b FROM Book b")})
public class Book implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @NotNull
    @Column(name = "BOOK_ID")
    private Integer bookId;
    @Column(name = "TITLE")
    private String title;
    @Column(name = "AUTHOR")
    private String author;
    @Column(name = "PRICE")
    private Integer price;

    public Book() {
    }

    public Book(Integer bookId) {
        this.bookId = bookId;
    }

    public Integer getBookId() {
        return bookId;
    }

    public void setBookId(Integer bookId) {
        this.bookId = bookId;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

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

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }
}

percistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="vecka19PU" transaction-type="JTA">
    <jta-data-source>jdbc/MySQLDataSource</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties/>
  </persistence-unit>
</persistence>

解决方案

You're abusing a CDI managed bean as a business service. It has no clues of transaction management. You'd need to manually manage transactions. As this is usually a pain and you're apparently using Glassfish, which is a fullworthy Java EE container supporting EJBs, you'd rather like to use a fullworthy EJB for this. When using EntityManager inside an EJB, the container will fully transparently manage DB transactions. One EJB method call counts as a single transaction (i.e. when you fire multiple DB queries and one of them fails, then everything will be automatically rolled back).

Overall, you seem to be mixing the responsibilities of the model, controller and service. Do not make your entity a managed bean as well. You should further absolutely also not perform business logic in a Javabean getter method (e.g. getBooks()). When referenced in an iterating component, it's invoked during every iteration round. So imagine that you've 100 records, then the DB will be hit 100 times. This is plain inefficient.

Here's how it should all look like:

Model (the entity):

@Entity
@Table(name = "BOOKS")
public class Book implements Serializable {
    // ...
}

Controller (the backing bean):

@Named
@RequestScoped
public class BookController {

    private Book book;
    private List<Book> books;

    @EJB
    private BookService service;

    @PostConstruct
    public void init() {
        book = new Book();
        books = service.list();
    }

    public void add() {
        service.save(book);
        init();
    }

    public Book getBook() { 
        return book;
    }

    public List<Book> getBooks() {
        return books;
    }

}

Service (the EJB):

@Stateless
public class BookService {

    @PersistenceContext
    private EntityManager em;

    public List<Book> list() {
        return em.createQuery("FROM Book", Book.class).getResultList();
    }

    public Book find(Integer id) {
        return em.find(Book.class, id);
    }

    public Integer save(Book book) {
        em.persist(book);
        return book.getId();
    }

    public void update(Book book) {
        em.merge(book);
    }

    public void delete(Book book) {
        em.remove(em.contains(book) ? book : em.merge(book));
    }

}

View (the Facelet; simplified):

<h:inputText id="title" value="#{bookController.book.title}"/>
<h:inputText id="author" value="#{bookController.book.author}"/>
<h:inputText id="price" value="#{bookController.book.price}"/>
<h:commandButton value="Add" action="#{bookController.add}" />
...
<h:dataTable value="#{bookController.books}" var="book">
    <h:column><f:facet name="header">ID</f:facet>#{book.id}</h:column>
    <h:column><f:facet name="header">Title</f:facet>#{book.title}</h:column>
    <h:column><f:facet name="header">Author</f:facet>#{book.author}</h:column>
    <h:column><f:facet name="header">Price</f:facet>#{book.price}</h:column>
</h:dataTable>

(your edit and delete buttons didn't make any sense, so I removed them, you might want to put them inside the data table)

See also:

这篇关于小型 facelet 应用程序中的 javax.persistence.TransactionRequiredException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
Java开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆