Cập nhật: 10/4/2015. Tôi thường không làm bất kỳ việc lập bản đồ hàng tuần nào nữa. Bạn có thể thực hiện biểu diễn JSON có chọn lọc thanh lịch hơn thông qua chú thích. Xem này gist.
Tôi đã dành phần tốt hơn cả ngày cố gắng tìm ra trường hợp này của đối tượng lồng nhau 3 lớp và cuối cùng cũng đóng đinh nó. Dưới đây là tình hình của tôi:
Accounts (tức là người dùng) --1tomany -> Vai trò --1tomany -> views (dùng được phép nhìn thấy)
(. Những lớp POJO được dán ở phía dưới rất)
Và tôi muốn bộ điều khiển để trả về một đối tượng như thế này:
[ {
"id" : 3,
"email" : "[email protected]",
"password" : "sdclpass",
"org" : "Super-duper Candy Lab",
"role" : {
"id" : 2,
"name" : "ADMIN",
"views" : [ "viewPublicReports", "viewAllOrders", "viewProducts", "orderProducts", "viewOfferings", "viewMyData", "viewAllData", "home", "viewMyOrders", "manageUsers" ]
}
}, {
"id" : 5,
"email" : "[email protected]",
"password" : "stereopass",
"org" : "Stereolab",
"role" : {
"id" : 1,
"name" : "USER",
"views" : [ "viewPublicReports", "viewProducts", "orderProducts", "viewOfferings", "viewMyData", "home", "viewMyOrders" ]
}
}, {
"id" : 6,
"email" : "[email protected]",
"password" : "ukmedpass",
"org" : "University of Kentucky College of Medicine",
"role" : {
"id" : 2,
"name" : "ADMIN",
"views" : [ "viewPublicReports", "viewAllOrders", "viewProducts", "orderProducts", "viewOfferings", "viewMyData", "viewAllData", "home", "viewMyOrders", "manageUsers" ]
}
} ]
một điểm quan trọng là nhận ra rằng mùa xuân không chỉ làm tất cả điều này tự động cho bạn. Nếu bạn chỉ cần hỏi nó để trở về một mục tài khoản mà không làm công việc của các đối tượng lồng nhau, bạn sẽ chỉ nhận được:
{
"id" : 6,
"email" : "[email protected]",
"password" : "ukmedpass",
"org" : "University of Kentucky College of Medicine",
"role" : null
}
Vì vậy, đầu tiên, tạo SQL 3 bảng của bạn THAM GIA truy vấn và chắc chắn rằng bạn đang nhận được tất cả dữ liệu bạn cần. Đây là của tôi, như nó xuất hiện trong Bộ điều khiển của tôi:
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
@RequestMapping("/accounts")
public List<Account> getAllAccounts3()
{
List<Account> accounts = jdbcTemplate.query("SELECT Account.id, Account.password, Account.org, Account.email, Account.role_for_this_account, Role.id AS roleid, Role.name AS rolename, role_views.role_id, role_views.views FROM Account JOIN Role on Account.role_for_this_account=Role.id JOIN role_views on Role.id=role_views.role_id", new AccountExtractor() {});
return accounts;
}
Lưu ý rằng tôi đang tham gia 3 bảng. Bây giờ tạo một lớp RowSetExtractor để đặt các đối tượng lồng nhau với nhau. Các ví dụ trên cho thấy làm tổ 2 lớp ... cái này đi thêm một bước nữa và làm 3 cấp độ. Lưu ý rằng tôi cũng phải duy trì đối tượng lớp thứ hai trong bản đồ.
public class AccountExtractor implements ResultSetExtractor<List<Account>>{
@Override
public List<Account> extractData(ResultSet rs) throws SQLException, DataAccessException {
Map<Long, Account> accountmap = new HashMap<Long, Account>();
Map<Long, Role> rolemap = new HashMap<Long, Role>();
// loop through the JOINed resultset. If the account ID hasn't been seen before, create a new Account object.
// In either case, add the role to the account. Also maintain a map of Roles and add view (strings) to them when encountered.
Set<String> views = null;
while (rs.next())
{
Long id = rs.getLong("id");
Account account = accountmap.get(id);
if(account == null)
{
account = new Account();
account.setId(id);
account.setPassword(rs.getString("password"));
account.setEmail(rs.getString("email"));
account.setOrg(rs.getString("org"));
accountmap.put(id, account);
}
Long roleid = rs.getLong("roleid");
Role role = rolemap.get(roleid);
if(role == null)
{
role = new Role();
role.setId(rs.getLong("roleid"));
role.setName(rs.getString("rolename"));
views = new HashSet<String>();
rolemap.put(roleid, role);
}
else
{
views = role.getViews();
views.add(rs.getString("views"));
}
views.add(rs.getString("views"));
role.setViews(views);
account.setRole(role);
}
return new ArrayList<Account>(accountmap.values());
}
}
Và điều này mang lại kết quả mong muốn. POJO dưới đây để tham khảo. Lưu ý các khung nhìn @ElementCollection Set trong lớp Role. Đây là những gì tự động tạo bảng role_views như được tham chiếu trong truy vấn SQL. Biết rằng bảng đó tồn tại, tên của nó và tên trường của nó là rất quan trọng để nhận được truy vấn SQL ngay. Cảm thấy sai lầm khi phải biết rằng ... có vẻ như điều này sẽ tự động hơn - không phải là mùa xuân là gì? ... nhưng tôi không thể tìm ra cách tốt hơn. Bạn phải làm công việc thủ công trong trường hợp này, theo như tôi có thể nói.
@Entity
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
@Column(unique=true, nullable=false)
private String email;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String org;
private String phone;
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "roleForThisAccount") // @JoinColumn means this side is the *owner* of the relationship. In general, the "many" side should be the owner, or so I read.
private Role role;
public Account() {}
public Account(String email, String password, Role role, String org)
{
this.email = email;
this.password = password;
this.org = org;
this.role = role;
}
// getters and setters omitted
}
@Entity
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id; // required
@Column(nullable = false)
@Pattern(regexp="(ADMIN|USER)")
private String name; // required
@Column
@ElementCollection(targetClass=String.class)
private Set<String> views;
@OneToMany(mappedBy="role")
private List<Account> accountsWithThisRole;
public Role() {}
// constructor with required fields
public Role(String name)
{
this.name = name;
views = new HashSet<String>();
// both USER and ADMIN
views.add("home");
views.add("viewOfferings");
views.add("viewPublicReports");
views.add("viewProducts");
views.add("orderProducts");
views.add("viewMyOrders");
views.add("viewMyData");
// ADMIN ONLY
if(name.equals("ADMIN"))
{
views.add("viewAllOrders");
views.add("viewAllData");
views.add("manageUsers");
}
}
public long getId() { return this.id;}
public void setId(long id) { this.id = id; };
public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
public Set<String> getViews() { return this.views; }
public void setViews(Set<String> views) { this.views = views; };
}
Đoạn mã trên bị hỏng. Có nhiều niềng răng đóng hơn là mở các niềng răng. (4 vs 3) – fivedogit
@fivedogit - updated - TY- hy vọng bạn thấy nó hữu ích – nclord