我有以下设置。
使用的技术:
我使用NetBeans工具“从数据库中获取RESTful Web服务来生成我的实体和休息服务。现在我在我的数据库中有一个视图,其中一行由两列组成的compits唯一标识(我知道它没有意义说到关于视图的主键,但是为了简单起见,让我们把它称为主键。我将视图建模为具有嵌入式复合主键的实体,如下所示:
@Entity
@Table(name = "UserAmountView")
@XmlRootElement
public class UserAmountView implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
protected UserAmountPK userAmountPK;
// fields, constructors, getters, setters etc.
}
@Embeddable
public class UserAmountPK implements Serializable {
@Basic(optional = false)
@NotNull
@Column(name = "UserID")
private int userID;
@Basic(optional = false)
@NotNull
@Column(name = "BalanceID")
private Integer balanceID;
public UserAmountPK() {
}
public UserAmountPK(int userID, Integer balanceID) {
this.userID = userID;
this.balanceID = balanceID;
}
// getters and setters etc...
}
现在我的问题是,如何最好地RESTful地解决这样一个实体的实例?对于具有复合主键的普通表,NetBeans使用矩阵参数(复合键的每个部分/列一个)生成一个过程,因此我将此方法用于我的视图。我希望,我可以在 ... / wgm.rest.useramountview; userID = 7; balanceID = 3 下获取由主键(7,3)组成的实体,但当然这不是因为矩阵参数与wgm.rest.useramountview在同一路径段中,所以请求将返回所有现有实体。接下来我尝试了 ... / wgm.rest.useramountview /; userID = 7; balanceID = 3 这给了我相同的结果(为什么?)。只有当我在'/'和';'之间插入一些内容时,它才会按预期工作并返回由(7,3)标识的实体,例如的 ... / wgm.rest.useramountview /富;用户ID = 7; balanceID = 3 即可。 显然,我想避免总是在URL中插入'foo'。有哪些替代方案?
我的服务类目前看起来如下:
@Stateless
@Path("wgm.rest.useramountview")
public class UserAmountViewFacadeREST extends AbstractFacade<UserAmountView> {
@PersistenceContext(unitName = "WGManagerPU")
private EntityManager em;
private UserAmountPK getPrimaryKey(PathSegment pathSegment) {
wgm.rest.UserAmountPK key = new wgm.rest.UserAmountPK();
javax.ws.rs.core.MultivaluedMap<String, String> map = pathSegment.getMatrixParameters();
java.util.List<String> userID = map.get("userID");
if (userID != null && !userID.isEmpty()) {
key.setUserID(new java.lang.Integer(userID.get(0)));
}
java.util.List<String> balanceID = map.get("balanceID");
if (balanceID != null && !balanceID.isEmpty()) {
key.setBalanceID(new java.lang.Integer(balanceID.get(0)));
}
return key;
}
@GET
@Path("{id}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public UserAmountView find(@PathParam("id") PathSegment id) {
wgm.rest.UserAmountPK key = getPrimaryKey(id);
return super.find(key);
}
@GET
@Override
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public List<UserAmountView> findAll() {
return super.findAll();
}
// ...
}
另一种可能性是将复合键的单列作为路径参数包括在内,如下所示:
@GET
@Path("{userID}/{balanceID}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public UserAmountView find(
@PathParam("userID") String userID,
@PathParam("balanceID") String balanceID) {
wgm.rest.UserAmountPK key =
new UserAmountPK(new Integer(userID), new Integer(balanceID));
return super.find(key);
}
但是,这仍然不能让我满意,因为那看起来像是一个子资源。实际上,两个路径参数都在同一层级上,用于识别一个资源。
我终于提出了罗曼沃特纳答案的改编版本(见下文):直接在基础资源路径上使用矩阵参数,并直接在方法内区分这两种情况。我必须将结果包装在Response对象中,因为返回类型不匹配(UserAmountView
find
与List<UserAmountView>
findAll
匹配。结果如下:
@Stateless
@Path("wgm.rest.useramountview")
public class UserAmountViewFacadeREST extends AbstractFacade<UserAmountView> {
@PersistenceContext(unitName = "WGManagerPU")
private EntityManager em;
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response findAll(
@MatrixParam("userID") String userID,
@MatrixParam("balanceID") String balanceID) {
if (userID != null && balanceID != null) {
wgm.rest.UserAmountPK key = new UserAmountPK(Parser.asIntOrNull(userID), Parser.asIntOrNull(
balanceID));
return Response.ok(super.find(key)).build();
} else {
return Response.ok(super.findAll()).build();
}
}
}
答案 0 :(得分:1)
您将复合键作为矩阵参数.../wgm.rest.useramountview;userID=7;balanceID=3
传递,但您已将定义的路径结构设置为.../wgm.rest.useramountview
或.../wgm.rest.useramountview/{id}
,其中id
也定义为路径参数。
由于矩阵参数属于它们所定义的资源,JAX-RS将使用类似findAll
的URI调用最接近的可能资源.../wgm.rest.useramountview;userID=7;balanceID=3
方法,尽管此处您不提取矩阵参数。这就是为什么返回所有条目而不是调用该URI的特定条目的原因。
第二次调用.../wgm.rest.useramountview/foo;userID=7;balanceID=3
成功,因为您现在向服务提供ID foo;userID=7;balanceID=3
,JAX-RS现在将解析为find(...)
方法。在此处使用PathSegment对象时,您只需忽略实际的ID
值,而只是收集在其上定义的矩阵参数。
要处理矩阵参数而不必使用其他一些当前未使用的ID路径参数,您应该将find
和findAll
方法重构为:
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public UserAmountView find(@MatrixParam("userID") Integer userID,
@MatrixParam("balanceID") Integer balanceID) {
if (null != userID && null != balanceID) {
return findOne(userID, balanceID);
} else {
return findAll();
}
}
与PathParam
或QueryParam
一样,您也可以直接注入MatrixParam
,如上例所示。你也可以直接在PathSegment
方法上重复使用findAll
并像你一样检索矩阵参数,但我想使用@MatrixParam
注释会更直观一些。
答案 1 :(得分:0)
我认为这是 MatrixParam,PathSegment 值的副作用,第一个标记实际上是一个正常的路径参数,后跟; key1 = val1; key2 = val2 值。
您是否考虑过使用普通的&amp; key1 = val1&amp; key2 = val2 查询参数?