【发布时间】:2013-02-07 19:26:19
【问题描述】:
我们有一个庞大的数据库应用程序,必须对其进行重构(原因有很多。最大的一个原因:安全性)。
我们已经拥有的:
- MySQL 数据库
- 超过 100 个表的 JPA2 (Eclipselink) 类
- 直接访问数据库的客户端应用程序
需要具备的条件:
- REST 接口
- 通过数据库使用角色登录/注销
到目前为止我做了什么:
- 使用 Spring Security 3.1.1 设置 Spring MVC 3.2.1
- 使用自定义
UserDetailsService(仅包含用于测试 atm 的静态数据) - 创建了几个控制器用于测试(只是接收/提供数据)
设计问题:
- 我们的数据库中有 maaaaany @OneToMany 和 @ManyToMany 关系
1.:(重要)
如果我发送包含所有子对象的整个对象树作为响应,我可能会一次发送整个数据库。
所以我需要一种方法来请求例如“所有文章”。但它应该省略所有子对象。我昨天试过了,我收到的对象有很多兆字节:
@PersistenceContext
private EntityManager em;
@RequestMapping(method=RequestMethod.GET)
public @ResponseBody List<Article> index() {
List<Article> a = em.createQuery("SELECT a FROM Article a", Article.class).getResultList();
return a;
}
2.:(重要)
如果客户收到一篇文章,目前我们可以简单地调用article.getAuthor(),JPA 会调用SELECT a FROM Author a JOIN Article ar WHERE ar.author_id = ?。
使用 REST,我们可以向 /authors/{id} 发出请求。 但是:这样我们就不能在客户端使用我们旧的 JPA 模型,因为该模型包含 Author author 而不是 Long author_id。
我们必须重写每个模型还是有更简单的方法?
3.:(不太重要)
身份验证:是否使其无状态?到目前为止,我从未使用过无状态身份验证,但 Spring 似乎对它有某种支持。当我查看网络上的一些示例实现时,我会担心安全问题:每次请求时,他们都会发送用户名和密码。这不可能是正确的方法。
如果有人知道一个很好的解决方案,请告诉我。否则我只会使用标准 HTTP 会话。
4.:
设计客户端模型的最佳方式是什么?
public class Book {
int id;
List<Author> authors; //option1
List<Integer> authorIds; //option2
Map<Integer, Author> idAuthorMap; //option3
}
(这是一本有多个作者的书)。这三个选项各有优缺点:
- 我可以直接访问对应的
Author模型,但是如果我通过 REST 请求一个Book模型,我现在可能不想要该模型,但稍后。所以选项 2 会更好: - 我可以直接通过 REST 请求
Book模型。然后使用authorIds获取相应的作者。但现在我不能简单地使用myBook.getAuthors()。 - 这是 1. 和 2. 的混合体:如果我只请求
Books 并且只包含Authorid,我可以执行以下操作:idAuthorMap.put(authorId, null)。
但也许有一个 Java 库可以为我处理所有事情?!
现在就是这样。谢谢各位:)
可能的解决方案:
问题:只选择我需要的数据。这意味着或多或少地忽略每个@ManyToMany、@OneToMany、@ManyToOne 关系。
解决方案:使用@JsonIgnore 和/或@JsonIgnoreProperties。
问题:每个被忽略的关系都应该在不修改数据模型的情况下轻松获取。
解决方案:示例模型:
class Book {
int bId;
Author author; // has @ManyToOne
}
class Author {
int aId;
List<Book> books; // has @OneToMany
}
现在我可以通过 REST 获取一本书:GET /books/4,结果将如下所示(因为我通过 @JsonIgnore 忽略所有关系):{"bId":4}
然后我必须创建另一个路由来接收相关作者:GET /books/4/author。将返回:{"aId":6}。
向后:GET /authors/6/books -> [{"bId":4},{"bId":42}]。
每个@ManyToMany、@OneToMany、@ManyToOne 都会有一条路线,但仅此而已。所以这个不会存在:GET /authors/6/books/42。客户端应使用GET /books/42。
【问题讨论】:
标签: rest jpa spring-mvc jpa-2.0 eclipselink