On the design of permission management system and the implementation of springbootjpa

Keywords: MySQL JSON

In a project, it is usually necessary to restrict and distinguish the access rights of users, that is, the classic user role menu role management architecture. In this architecture, the relationship between the user and the role is basically determined, that is, the relationship of many to one. Before the role and the menu, the operation authority such as "menu operation" has been added. For example, the menu operation authority owned by a role is shown in the following figure:

Menu and operation permission are one to many relationships. The entity classes using springbootjpa are

Menu:

@Entity
@Table(name = "menu", uniqueConstraints = { @UniqueConstraint(name = "idx_menuname", columnNames = { "menuName" }) })
@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" })
public class Menu implements Serializable {
    private static final long serialVersionUID = -6499256046633708586L;

    @Id
    @Column(columnDefinition = "varchar(64) comment 'menu id'")
    private String menuId; // Menu ID

    @Column(nullable = false, columnDefinition = "varchar(255) comment 'Menu name'")
    private String menuName; // Menu name

    @OneToMany(mappedBy = "menu", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<MenuHandle> menuHandles;//Menu operation permission
}

Menu operation permission:

@Entity
@Table(name = "menu_handle")
@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" })
public class MenuHandle implements Serializable {
    private static final long serialVersionUID = -5909986386327673973L;

    @Id
    @Column(columnDefinition = "varchar(64) comment 'Operation authority id'")
    private String handleId; // Operation permission id

    @Column(nullable = false, columnDefinition = "varchar(255) comment 'Permission name'")
    private String name; // Permission name

    @ManyToOne(targetEntity = Menu.class)
    @JoinColumn(name = "menu_id", updatable = false)
    private Menu menu;//Permission corresponding menu
}

Roles and menus are many to many relationships, and roles and operations are also many to many relationships

Role:

@Entity
@Table(name = "role", uniqueConstraints = { @UniqueConstraint(name = "idx_rolename", columnNames = { "roleName" }) })
@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" })
public class Role implements Serializable {
    private static final long serialVersionUID = -5553646385121286353L;

    @Id
    @Column(columnDefinition = "varchar(64) comment 'role id'")
    private String roleId;

    @Column(nullable = false, columnDefinition = "varchar(255) comment 'Role name'")
    private String roleName;

    @ManyToMany
    private List<Menu> menus;//Menus for roles

    @ManyToMany
    private List<MenuHandle> roleMenuHandles;//Operation permission of role
}

In this design, when I query a role through the springbootjpa api, the roles' menus and rolemenuehandles will be cascaded and queried in infinite cycles, resulting in the incorrect json generated by the queried object.
My current practice is: Rewrite toString method in permission entity:

    @Override
    public String toString() {
        JSONObject jso = new JSONObject();
        jso.put("handleId", handleId);
        jso.put("name", name);
        jso.put("menuId", menu.getMenuId());
        return jso.toJSONString();
    }

If there is a better way, welcome to add.

Posted by R0CKY on Thu, 14 Nov 2019 12:15:05 -0800