W poprzednim wpisie przedstawiłem sposób na redukcję kodu w encjach przy pomocy dziedziczenia i adnotacji @MappedSuperclass. Rozwiązanie to możemy również stosować aby tworzyć kod bardziej przenośny, który niewielkim kosztem można użyć w innych projektach.
Większość aplikacji webowych stosuje autoryzację opartą o role (ang. Role Based Access Control), w takich wypadkach mamy zazwyczaj encję User oraz Role, pierwszą odpowiedzialną za przetrzymywanie informacji o użytkowniku a druga nazwy ról. O ile role są obszarem stałym - zawsze mają nazwę - o tyle użytkownicy często mają różne wariacje i relacje. Ot choćby powiązanie konta użytkownika z firmą. [sourcecode lang=“java”] // Copyright (C) 2009 Code-House // All rights reserved package org.code_house.security.domain;
import java.util.Calendar; import java.util.HashSet; import java.util.Set;
import javax.persistence.Column; import javax.persistence.ManyToMany; import javax.persistence.MappedSuperclass; import javax.persistence.Temporal; import javax.persistence.TemporalType;
import org.code_house.domain.BaseEntity;
/\\ \* Klasa reprezentująca użytkownika. Powinna ona zostać nadpisana w docelowym \* systemie poprzez plik orm.xml. \* \* @author Łukasz Dywicki. */ @MappedSuperclass public class SecurityUser extends BaseEntity {
/\\ \* Hasło użytkownika. */ @Column private String password;
/\\ \* Login użytkownika. */ @Column private String username;
/\\ \* Konto wygasło. */ @Column @Temporal(TemporalType.TIMESTAMP) private Calendar expire;
/\\
\* Grupy do których przynależy użytkownik.
*/
@ManyToMany(mappedBy = “users”)
private Set
/\\ \* Konto zablokowane np. po 3 nieudanych próbach logowania. */ @Column private boolean locked;
/\\ \* Konto wyłączone np. przez administratora. */ @Column private boolean enabled;
// Dalej gettery i settery } [/sourcecode] Rola ma niekompletną definicję relacji do klasy SecurityUser, którą należy uzupełnić o informacje na temat encji docelowej i definicji tabeli pośredniczącej. [sourcecode lang=“java”] // Copyright (C) 2009 Code-House // All rights reserved package org.code_house.security.domain;
import javax.persistence.Entity; import javax.persistence.ManyToMany; import javax.persistence.Table;
import org.code_house.domain.NamedEntity;
/\\ \* Klasa reprezentująca rolę. Może to być np ADMIN, USER bądź cokolwiek innego. \* \* @author Łukasz Dywicki luke@code-house.org */ @Entity @Table(name = “roles”) public class Role extends NamedEntity {
@ManyToMany
@JoinTable(name = “users_roles”,
joinColumns = @JoinColumn(name = “role_id”, referencedColumnName = “id”)
)
private Set
// gettery i settery } [/sourcecode] Oto kawałek konfiguracji XML, która uzupełni metadane i pozwoli na uruchomienie kodu. Atrybut target-entity pozwala na określenie tabeli docelowej relacji podczas gdy element inverse-join-column uzupełnia definicję tabeli pośredniczącej. [sourcecode lang=“xml” classname=“xml”]
Przykład ten można wykorzystać by uzupełniać relacje, których nie sposób odzwierciedlić w kodzie.