Business management background and SSO design

In the example of e-commerce platform in this paper, the merchant is the protagonist of this platform, and the merchant management background is a safe and reliable operation platform specially provided for this protagonist. In the business management background, businesses can carry out commodity management, order management, logistics management, membership management, evaluation management and other aspects of management. These management functions and their service functions are implemented by different microservice projects and deployed by different applications. All we need to do now is combine these administrative functions, which are distributed across different applications, into an administrative background with the same access control design.

Single sign-on (SSO) integrates such scattered applications into an organic whole through unified access control and permission management, providing unified login control and authorization management for different applications in the distributed environment. A merchant administrator only needs to log in once in any application to gain access to other applications. Therefore, no matter how many micro service applications constitute the function of the merchant management background, it is always just a complete platform for a merchant administrator.

The design and development of business management background mainly consists of business management development and SSO development. Among them, business management development mainly includes business information management and its authority system design two parts.

These designs are developed in merchant management microservice project Merchant-MicroService. The complete source code can be downloaded from the source code of this book. The examples in this chapter correspond to branch V2.1.

Merchant and its permission system design is composed of merchant-Object, merchant-Domain, merchant-restAPI, merchant-Client and merchant-Web modules. SSO design consists of merchant-SSO module and merchant-Security module. SSO client access can be experienced through the merchant-Web module.

Business authority system design and development

The business authority system is composed of two functional models: authority management model and menu management model. Among them, the authority management model contains business, user, role and other entity design, menu management model contains resources, modules, classification and other entity design. The two models form a complete permission menu architecture by associating roles with resources, as shown in Figure 10-1.

In Figure 10-1, the association relationship between entities is designed by one-way association, as shown below:

  • The user is subordinate to the merchant, which is a many-to-one relation.
  • Users have roles in a many-to-many relationship.
  • Roles own resources in a many-to-many relationship.
  • Resources are subordinate to modules in a many-to-one relationship.
  • Module is subordinate to classification and is a many-to-one relation.

In the relationship shown in Figure 10-1, the arrow indicates that one party is the primary key of the relationship and the other party is the foreign key. An intermediate table is used to store associations between users and roles and between roles and resources.

After the physical models corresponding to these objects are designed by PowerDesigner, the table definitions and their associations are finally completed, as shown in Figure 10-2.

In Figure 10-2, the tables of merchant, user, role, resource, module and category are t_merchant, T_USERt_role-t_resource-T_model and t_kind respectively. User_role and ROLE_RESOURCE lists the association between users and roles and between roles and resources. In addition, the form Persistent_logins is used to store temporary data while the user is logged in.

Permission management model design

The authority management model is mainly composed of entities such as merchants, users, roles, resources, modules and categories. Each of these entities is briefly described below.

The business entity is mainly composed of ID, name, email, phone, address, contact and creation date and other attributes, and the implementation code is as follows:

@Entity @Table(name = "t merchant") public class Merchant implements java.io.Serializable{ @Id @GeneratedValue(strategy =GenerationType.IDENTITY)private Long id; private String name; private String email; private String phone; private String address; private String linkman; @DateTimeFormat(pattern = "yyyY-MM-dd HH:mm:ss") @column (name = "created",columnDefinition = "timestamp defaultCurrent timestamp") @Temporal (TemporalType.TIMESTAMP)private Date created; // 0neToMany (cascade ={ },mappedBy ="merchant")// private List<User> users; public Merchant() { } ... }Copy the code

The user entity is mainly composed of ID, name, password, email, gender, creation date and other attributes, and the implementation code is as follows:

@Entity @Table(name = "tuser") public class User implements java.io.Serializable{ @Id @GeneratedValue (strategy = GenerationType.IDENTITY)private Long id; private String name; private String password; private String email; eColumn (name = "sex",length= 1,columnDefinition = "tinyint")private Integer sex; @DateTimeFormat (pattern= "YyyY-MM-dd HH:mm: ss") eColumn (name = "created", columnDefinition = "timestamp defaultcurrent timestamp ") @Temporal (TemporalType.TIMESTAMP)private Date created; @ManyToMany (cascade = {,fetch = FetchType.EAGER)@JoinTable(name = "user role", joinColumns ={@JoinColumn (name = "user id")], inverseJoinColumns -{GJoinColumn (name = "role_id")}) private List<Role> roles; @ManyTo0ne CJoinColumn(name = "merchant_id")@JsonIgnore private Merchant merchant; public User() { } ... }Copy the code

Where @manytomany is a many-to-many forward association, where an intermediate table user_Role is used to hold the data of the association.

@manytoone is a reverse association design, that is to use mercnant_1A TFAh wide oPIl Mo body to establish association relations.

The role entity consists of attributes such as ID, name, and creation date, and is implemented as follows:

@Entity
@Table(name ="t role")
public class Role implements java.io.Serializable{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;
private String name;
@DateTimeFormat (pattern = "yyyy-MM-dd HH:mm:ss")
eColumn(name = "created",columnDefinition = "timestamp defaultcurrent timestamp ")
@Temporal (TemporalType.TIMESTAMP)private Date created;
@ManyToMany(cascade = {}, fetch = FetchType.EAGER)
@JoinTable(name = "role resource",
joinColumns = {@JoinColumn (name - "role_id")},
inverseJoinColumns = {@JoinColumn (name = "resource_id")))
private List<Resource> resources;
public Role() {
}
...
}
Copy the code

Role entities have a many-to-many association with resource entities, so use @manytomany to set them. Through this relation, the authority management model and menu management model can form a complete business authority system.

The resource entity consists of attributes such as ID, name, uniform resource location, and creation date. The implementation code is as follows:

@Entity @Table(name ="t resource") public class Resource implements java.io.Serializable { @Id @GeneratedValue (strategy  =GenerationType.IDENTITY)private Long id; private string name; private string url; @DateTimeFormat (pattern = "yyyy-MM-dd HH:mm:ss") @Column (name = "created", columnDefinition = "timestamp defaultcurrent timestamp") @Temporal(TemporalType.TIMESTAMP)private Date created; @ManyToOne @JoinColumn(name = "mid")@JsonManagedReference private Model model; public Resource() { } ... }Copy the code

The association between resource entities and modules also uses @manytoone for reverse association design, which is the same as the design principle of association between users and merchants.

The module entity consists of attributes such as ID, name, host, icon and creation date. The implementation code is as follows:

@Entity @Table(name ="tmodel") public class Model implements java.io.Serializable{ @Id @Generatedvalue(strategy -GenerationType.IDENTITY)private Long id; private String name; private String host; private String icon; @DateTimeFormat (pattern = "yyyy-MM-dd HH:mm:ss") eColumn (name = "created", columnDefinition = "timestamp defaultcurrent timestamp") @Temporal (TemporalType.TIMESTAMP)private Date created; @ManyTo0ne @JoinColumn (name = "kid")@JsonIgnore private Kind kind; public Model() {} ... }Copy the code

The association design of module entities, like the association design of resource entities, also uses @manytoone for reverse association design.

The classified entity consists of attributes such as ID, name, link service and creation date, and the implementation code is shown as follows:

@Entity @Table(name = "t kind") public class Kind implements java.io. Serializable{ @Id @Generatedvalue (strategy =GenerationType.IDENTITY)private Long id; private String name; private String link; @DateTimeFormat (pattern= "yyyy-MM-dd HH:mm:ss") cColumn (name = "created", columnDefinition = "timestamp defaultcurrent timestamp") @Temporal (TemporalType.TIMESTAMP)private Date created; public Kind() {} ... }Copy the code

The classified entity is a top-level menu in the menu model structure, so no association design is required.

The one-way association design can improve the data access performance, but it also has some disadvantages. For example, in the role entity, the one-way association between the role entity and the resource entity is already implemented, so it is very easy to query the resource list from the role entity. On the other hand, querying the list of roles from the resource entity is a bit laborious. To compensate for this deficiency, you can use SQIL query statements, as described later in the persistence design.

Persistent design of the permission management model

After the permission management model is designed, creating a repository interface for each entity and binding it with JPA’s repository interface can give the entity operation behavior and realize the persistent design of the entity. This process, in fact, is the repository interface design work.

For example, you could create a repository interface like this to implement persistent design for a merchant entity:

@Repository public interface MerchantRepository extends JpaRepository<Merchant,Long>,JpaSpecificationExecutor<Merchant> {}Copy the code

In this interface design, by inheriting JpaRepository, the interface can be added, deleted, changed, and searched. Through inheritance. JpaSpecificationExecutor, paging query design can be complicated. If you don’t do any special query design, you’re done with the persistence design of the merchant entity.

If you also need to implement some complex query design for an entity, such as persistent design for a user entity, use the code shown below:

@Repository
public interface UserRepository extends JpaRepository<User, Long>,JpaSpecificationExecutor<User> {
cQuery ("select distinct u from User u where u.name= :name")User findByName (@Param ("name") String name) ;
@Query("select u from User u"+
" left join u.roles r"+
"where r.name= :name")
User findByRoleName (@Param ("name") String name) ;
@Query ("select distinct u from User u where u.id= :id")User findById(@Param( "id") Long id);
@Query ( "select u from User u"+
"left join u.roles r "+"where r.id = :id")
List<User> findByRoleId(@Param("id") Long id);
}
Copy the code

There are a few more declarative methods for custom Query design using the annotation “@query”.

FindByName and findByld mainly use distinct to perform deduplication query to avoid data duplication in many-to-many associated query.

In addition, findByRoleName and findByRoleld are the aforementioned queries designed to compensate for the lack of a one-way correlation design. FindByRoleName enables you to query a user list from the role name, and findByRoleld enables you to query a user list from the role ID.

In the role entity repository interface design, we also need to add a query design as follows:

@Repository
public interface RoleRepository extends JpaRepository<Role,Long>,JpaSpecificationExecutor<Role>{
CQuery("select o from Role o"+
"left join o.resources r"+"where r.id = :id")
List<Role> findByResourceId(@Param("id") Long id);
}
Copy the code

In this design, findByResourceld is a reverse association query that uses the resource ID to query the role list.

The persistence design of other entities is similar to that of merchant entities, simply by creating a repository interface for them.

Service encapsulation of the permission management model

In domain service development, the implementation of the service layer is an encapsulation design for the invocation of the repository interface, so that unified transaction management can be achieved in the invocation of the repository interface, and other functions can be added.

Let’s take the development of the user service layer as an example. The development of other business service layers is similar and will not be repeated.

In the design of user Service layer, the implementation code of add, delete, modify and check each operation is as follows: @service

@Transactional public class UserService { CAutowired private UserRepository userRepository; public String insert (User user){ try { User old = findByName(user.getName()); if(old == null) { userRepository.save(user); return user.getId() .toString(); }else{return "username "+ old.getName()+ "' already exists!" ; }catch(Exception e){ e.printStackTrace(); return e.getMessage(); public String update (User user){ try { userRepository.save(user); return user.getId() .toString(); }catch(Exception e){ e.printStackTrace(); return e.getMessage (); } } public String delete (Long id){ try { userRepository.deleteById(id); return id.toString (); }catch (Exception e){ e.printStackTrace(); return e.getMessage(); } } public User find0ne (Long id){ return userRepository.findByUserId(id); } public List<User> findA11(){ return userRepository.findAl1(); }}Copy the code

In this design, the annotation @Transactional implements implicit transaction management capabilities. The login user must be based on the user name. Therefore, the same name check is performed when the new user name is added.

The code for implementing the paging query function of the user domain service is as follows:

@service @Transactional public class UserService { CAutowired private UserRepository userRepository; public Page<User> findAl1 (UserQo userQo){ Sort sort = Sort.by(Sort.Direction. DESC, "created"); Pageable pageable = PageRequest.of (userQo.getPage(), userQo.getSize(. sort); return userRepository.findAll(new Specification<User>(){ @override public Predicate toPredicate(Root<User> root, CriteriaQuery<? >qu CriteriaBuilder criteriaBuilder) { List<Predicate> predicatesList =new ArrayList<Predicate>(); If (commonUtils.isnotnull (userqo.getName ())){predicatesList.add (criteriaBuilder. Like (root.get ("name")), "G" + userQo. GetName () + "%")); } if(CommonUtils.isNotNull (userQo.getMerchant ())){ predicatesList.add (criteriaBuilder.equal (root. get ("merchant"),userQo.getMerchant().getId())); } if (CommonUtils.isNotNull(userQo.getCreated())){ predicatesList.add(criteriaBuilder.greaterThan(root.get ("created"),userQo.getCreated())); query.where (predicatesList.toArray(new Predicate[predicatesList. size()])); return guery.getRestriction(); } }, pageable); }}Copy the code

The findAll method is used to implement the paging query function, and the query object userQo is used to pass query parameters, including the user name, merchant object, and creation date.

In the domain service design, we use some query objects, which are unified in merchant-Object module. The properties of the query object correspond essentially to those of the entity object, and several paging query properties have been added.

The implementation code of the query object is as follows:

public class User0o extends PageQo implements java.io.Serializable{ private Long id; private String name; private String password; private String email; private Integer sex; @DateTimeFormat (pattern = "Yyyy-MM-dd HH:mm:ss")private Date created; private List<RoleQo>roles = new ArrayList<>(); private MerchantQo merchant; public UserQ0() { } ... }Copy the code

After completing the development of the service layer, the design of the business authority system basically comes to an end. In the next chapter, we design micro services for business management.

Three things to watch ❤️

If you find this article helpful, I’d like to invite you to do three small favors for me:

  1. Like, forward, have your “like and comment”, is the motivation of my creation.

  2. Follow the public account “Java rotten pigskin” and share original knowledge from time to time.

  3. Also look forward to the follow-up article ing🚀

  4. [666] Scan the code to obtain the learning materials package

Article is not original, and all of us feel while reading the article good remember thumb up forward + attention oh ~ this article source: www.toutiao.com/i6903438931…