我有一个包含以下内容的挂毯5项目:
实体包中的一个抽象实体,由所有其他具体实体继承
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
@MappedSuperclass
public class AbstractEntity implements Serializable, Comparable<AbstractEntity> {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "ID")
protected Integer id;
@Override
public int compareTo(AbstractEntity o) {
return this.toString().compareTo(o.toString());
}
}
继承AbstractEntity的几个具体实体(我会省略它们的大部分内容,因为我认为与这个问题完全无关,它们是简单的实体数据类)。一种此类实体类的示例:
//Imports go here
@Entity
@Table(name = "room")
@NamedQueries({
@NamedQuery(name = "Room.findAll", query = "SELECT r FROM Room r")})
public class Room extends AbstractEntity {
private static final long serialVersionUID = 1L;
@Basic(optional = false)
@Column(name = "ROOM_TYPE")
@Validate("required")
@Enumerated(EnumType.STRING)
private RoomType roomType;
//rest of the attributes and their annotations go here, as well as setter/getter methods
通用DAO接口
import com.mycompany.myproject.entities.AbstractEntity;
import java.util.List;
public interface GenericDAO <T extends AbstractEntity>{
public abstract List<T> getListOfObjects(Class myclass);
public abstract T getObjectById(Integer id, Class myclass);
public abstract T addOrUpdate(T obj);
public abstract T delete(Integer id, Class myclass);
}
通用DAO接口的实现,使用Binder.bind在服务包的AppModule中将其绑定到该接口
import com.mycompany.myproject.entities.AbstractEntity;
import java.util.Collections;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
public class GenericDAOImpl<T extends AbstractEntity> implements GenericDAO<T> {
private Session session;
@Override
public List getListOfObjects(Class myclass) {
List<T> list = session.createCriteria(myclass).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
Collections.sort(list);
return list;
}
@Override
public T getObjectById(Integer id, Class myclass) {
AbstractEntity ae = (AbstractEntity) session.createCriteria(myclass)
.add(Restrictions.eq("id", id)).list().get(0);
return (T) ae;
}
@Override
public AbstractEntity addOrUpdate(AbstractEntity obj) {
return (T) session.merge(obj);
}
@Override
public T delete(Integer id, Class myclass) {
AbstractEntity ae = (AbstractEntity) session.createCriteria(myclass)
.add(Restrictions.eq("id", id)).list().get(0);
session.delete((T) ae);
session.flush();
return (T) ae;
}
}
组件包中的通用编辑器Java类
import com.mycompany.myproject.entities.AbstractEntity;
import com.mycompany.myproject.services.GenericDAO;
import java.util.List;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.PropertyConduit;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.beaneditor.BeanModel;
import org.apache.tapestry5.hibernate.annotations.CommitAfter;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.BeanModelSource;
import org.apache.tapestry5.services.PropertyConduitSource;
public class GenericEditor<T extends AbstractEntity> {
@Inject
private PropertyConduitSource conduit;
@Inject
private GenericDAO genericDAO;
@Property
@Persist
private T bean;
@Property
private T row;
@Inject
private BeanModelSource bms;
@Inject
private ComponentResources cr;
private Class myclass;
{
PropertyConduit conduit1 = conduit.create(getClass(), "bean");
myclass = conduit1.getPropertyType();
}
public List<T> getGrid(){
List<T> temp = genericDAO.getListOfObjects(myclass);
return temp;
}
public BeanModel<T> getFormModel(){
return bms.createEditModel(myclass, cr.getMessages()).exclude("id");
}
public BeanModel<T> getGridModel(){
return bms.createDisplayModel(myclass, cr.getMessages()).exclude("id");
}
@CommitAfter
Object onActionFromDelete(int id){
genericDAO.delete(id, myclass);
return this;
}
@CommitAfter
Object onActionFromEdit(int row){
bean = (T)genericDAO.getObjectById(row, myclass);
return this;
}
@CommitAfter
Object onSuccess(){
genericDAO.addOrUpdate(bean);
try {
bean = (T) myclass.newInstance();
} catch(Exception ex){
}
return this;
}
GenericEditor Java类的关联的.tml文件
<!--GenericEditor.tml-->
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd" xmlns:p="tapestry:parameter">
<t:beaneditform object="bean" t:model="formModel" >
</t:beaneditform>
<t:grid t:source="grid" t:model="gridModel" add="edit,delete" row="row">
<p:editCell>
<t:actionlink t:id="edit" context="row">Edit</t:actionlink>
</p:editCell>
<p:deleteCell>
<t:actionlink t:id="delete" context="row">Delete</t:actionlink>
</p:deleteCell>
</t:grid>
</html>
此外,页面包中还有几个Java类及其关联的.tml文件,这些类最初是在不使用genericDAO的情况下制作的,但是使用了具体的DAO,因此它们看起来像这样(其中一个示例):
import com.mycompany.myproject.entities.Room;
import com.mycompany.myproject.services.RoomDAO;
import java.util.ArrayList;
import java.util.List;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.hibernate.annotations.CommitAfter;
import org.apache.tapestry5.ioc.annotations.Inject;
public class RoomPage {
@Property
private Room room;
@Property
private Room roomrow;
@Inject
private RoomDAO roomDAO;
@Property
private List<Room> rooms;
void onActivate(){
if(rooms==null){
rooms = new ArrayList<Room>();
}
rooms = roomDAO.getListOfRooms();
}
@CommitAfter
Object onSuccess(){
roomDAO.addOrUpdateRoom(room);
room = new Room();
return this;
}
@CommitAfter
Object onActionFromEdit(Room room2){
room = room2;
return this;
}
@CommitAfter
Object onActionFromDelete(int id){
roomDAO.deleteRoom(id);
return this;
}
}
以及相关的.tml文件:
<!--RoomPage.tml-->
<html t:type="layout" title="RoomPage"
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"
xmlns:p="tapestry:parameter">
<div class="row">
<div class="col-sm-4 col-md-4 col-lg-3">
<t:beaneditform object="room" exclude="id" reorder="roomtype, floor,
tv, internet"
submitlabel="message:submit-label"/>
</div>
<div class="col-sm-8 col-md-8 col-lg-9">
<t:grid t:source="rooms" exclude="id"
add="edit,delete" row="roomrow"
include="roomtype, floor, tv, internet">
<p:editCell>
<t:actionlink t:id="edit" context="roomrow">Edit</t:actionlink>
</p:editCell>
<p:deleteCell>
<t:actionlink t:id="delete" context="roomrow.id">Delete</t:actionlink>
</p:deleteCell>
</t:grid>
</div>
</div>
</html>
上面使用具体DAO的代码可以正常工作,在数据库中按预期显示用于在数据库中输入新行的表单,以及带有数据库表中行的网格。
因此,基本思想是将GenericEditor与genericDAO一起使用,以减少所需的代码量并处理任何数据库表,使用BeanEditForm在表中输入新行,并使用Grid来显示表中的所有行,删除或编辑它们。从理论上讲,这应该对继承AbstractEntity类的任何实体都适用,因此不需要为每个实体创建单独的DAO接口/实现对。
问题是,我似乎无法按预期工作,因为我不确定如何实际使用上面显示的GenericEditor。我尝试了以下操作:
修改后的RoomPage.java:
import com.mycompany.myproject.components.GenericEditor;
import com.mycompany.myproject.entities.Room;
public class RoomPage{
@Component
private GenericEditor<Room> ge;
}
修改后的RoomPage.tml:
<!--RoomPage.tml-->
<html t:type="layout" title="RoomPage"
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"
xmlns:p="tapestry:parameter">
<t:GenericEditor t:id="ge" />
</html>
但这显然不起作用,因为它产生的只是一个空指针异常以及此错误:
Blockquote [ERROR]页面。RoomPageSetupRender [RoomPage:ge.grid]中的呈现队列错误:无法读取组件RoomPage:ge.grid的参数“源”:org.apache.tapestry5.ioc.internal.util.TapestryException
org.apache.tapestry5.ioc.internal.util.TapestryException:读取组件RoomPage:ge.grid的参数“源”失败:org.apache.tapestry5.ioc.internal.util.TapestryException [at classpath:com / mycompany / myproject /components/GenericEditor.tml,第5行]
然后,我尝试完全删除grid元素,并仅使用BeanEditForm运行GenericEditor。这实际上导致了页面的加载,但是并未在页面上显示预期的表单,而是在页面末尾显示了Room实体和“创建/更新”按钮的字段,而出现的只是“创建/更新”按钮,没有任何字段,就好像BeanEditForm是在没有任何属性的对象上创建的。按下创建/更新按钮会创建另一个空指针异常。
出于调试目的,我将GenericEditor.java更改为以非通用方式工作,方法是在其中创建通用类型T的另一个属性,然后将其初始化为Room类型的新对象,强制转换为(T),并然后声明属性类与room属性的类型相同,如下所示
private T room;
{
//PropertyConduit conduit1 = conduit.create(getClass(), "bean");
//class = conduit1.getPropertyType();
room = (T) new Room();
class = room.getClass();
}
通过这些更改运行应用程序(仍禁用网格并仅启用beaneditform),页面现在可以正确呈现所有输入字段。这使我得出结论,问题在于GenericEditor无法通过泛型接收正确的类型,但是我不知道我的逻辑是否正确,即使是正确的,也不知道如何解决此问题。问题的另一个可能原因可能是PropertyConduit,我不确定它的工作方式是否正确,以及是否正确使用了它,因此我不排除问题是否也源于此。
无论哪种方式,我的主要猜测是我以某种方式滥用了GenericEditor,因此如该问题的标题所述,我应该如何使用GenericEditor来正确访问数据库?
我已经在stackoverflow上搜索了与自己类似的问题,但是无论在这里还是在其他地方,我都找不到类似的问题。我希望这里的某人能够帮助我确定问题所在并帮助我解决问题,因为我真的不知道如何独自解决。提前致谢。
更新:
通过尝试检查将哪种类型的类转发给GenericEditor的myclass,我进行了一些进一步的调试。我修改了GenericEditor.java的以下位:
{
PropertyConduit conduit1 = conduit.create(getClass(), "bean");
myclass = conduit1.getPropertyType();
}
以下:
{
PropertyConduit conduit1 = conduit.create(getClass(), "bean");
System.out.println("conduit1.toString(): "+conduit1.toString());
System.out.println("conduit1.getPropertyType().toString(): "+conduit1.getPropertyType().toString());
System.out.println("conduit1.getPropertyType().getName(): "+conduit1.getPropertyType().getName());
myclass = conduit1.getPropertyType();
System.out.println("myclass.getName(): "+myclass.getName());
}
这导致了以下输出:
pipe1.toString():PropertyConduit [com.mycompany.myproject.components.GenericEditor bean]
pipe1.getPropertyType()。toString():类com.mycompany.myproject.entities.AbstractEntity
pipe1.getPropertyType()。getName():com.mycompany.myproject.entities.AbstractEntity
myclass.getName():com.mycompany.myproject.entities.AbstractEntity
我认为这几乎意味着转发给GenericEditor的T类型是AbstractEntity,而不是预期的Room。如果我的假设是正确的,那么我会滥用GenericEditor,因为我没有通过泛型将适当的类转发给它,那么我应该如何将适当的类转发给它呢?还是我的假设是错误的,这里还有其他问题吗?
最佳答案
我已经设法找到了这个问题的答案,所以我把它张贴在这里,以防万一有人需要它:
应用程序无法按预期运行的原因有两个:
1)在GenericDAOImpl类中,我忘了在“私有会话会话”行上方添加@Inject批注,该批注首先产生了错误,因此该段代码应如下所示:
//imports
public class GenericDAOImpl<T extends AbstractEntity> implements GenericDAO<T> {
@Inject
private Session session;
//rest of code unchanged
2)首先我不确定的是如何使用GenericEditor组件,而我试图通过将组件添加到类文件和关联的tml文件中来以错误的方式使用它。相反,应该做的只是简单地扩展GenericEditor,并删除关联的tml文件,因此使用GenericEditor tml,如下所示:
public class RoomPage extends GenericEditor<Room>{
}
进行这两项更改后,该应用程序将按预期工作