1. 程式人生 > 其它 >Spring Data JPA 許可權記錄轉許可權樹形結構

Spring Data JPA 許可權記錄轉許可權樹形結構

技術標籤:spring Data JPA

第一步:許可權表permission

DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission`  (
  `permission_id` int(11) NOT NULL COMMENT '主鍵id',
  `permission_zh` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '選單中文名稱',
  `permission_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '選單英文名稱',
  `permission_path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '選單路徑',
  `permision_icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '選單圖示',
  `permision_component` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '前端路由所在的元件位置',
  `permision_parent_id` int(11) NULL DEFAULT NULL COMMENT '父選單',
  PRIMARY KEY (`permission_id`) USING BTREE,
  INDEX `permission_zh`(`permission_zh`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

第二步:spring data jpa 對應實體對映表

package com.zzg.entity;

import javax.persistence.Entity;
import javax.persistence.Id;

import lombok.Getter;
import lombok.Setter;

/**
 * 
 * @author zzg
 *
 */
@Getter
@Setter
@Entity
public class Permission {

    @Id
    private Integer permissionId;
    private String permissionName;
    private String permissionZh;
    private String permissionPath;
    private String permisionIcon;
    private String permisionComponent;
    private Integer permisionParentId;
    
//    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)   
//    @JoinColumn(name="permision_parent_id")  
//    private Permission parent;
//    // 子選單項
//    @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent", fetch = FetchType.EAGER)  
//    private Set<Permission> child  = new HashSet<Permission>() ;
}

問題描述:在許可權表中(permission),存在父子關係(樹形結構關係),為了標識這種關係我最初開始採用的方式是使用spring data jpa 提供的關係註解標籤:@ManyToOne、@JoinColumn、@OneToMany。採用這種方式可以很快在父子關係(樹形結構)關係的表述,但是在實際情況驗證中,由於採用關係註解標籤,導致查詢資料關係混亂(簡單來說:就是資料之間巢狀嚴重)。我這裡採用的方法是放棄註解標籤,通過自定義封裝實體物件,包含父子關係(樹形結構關係)。

第三步:Permission 實體封裝包裝物件。

package com.zzg.vo;

import java.util.List;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class PermissionVo {
	private Integer permissionId;
	private String permissionName;
	private String permissionZh;
	private String permissionPath;
	private String permisionIcon;
	private String permisionComponent;
	private Integer permisionParentId;
	private List<PermissionVo> child;
}

第四步:Controller 查詢指定使用者所擁有的許可權資訊(permission ),方法:@RequestMapping(value = "/permission/{uid}", method = RequestMethod.GET)

package com.zzg.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.zzg.common.AbstractController;
import com.zzg.dao.PermissionRepository;
import com.zzg.dao.RoleRepository;
import com.zzg.dao.UserRepository;
import com.zzg.entity.Permission;
import com.zzg.entity.Role;
import com.zzg.entity.User;
import com.zzg.vo.PermissionVo;

@RestController
public class PermissionController extends AbstractController{
	@Autowired
	private PermissionRepository permissionRepository;
	@Autowired
	private UserRepository userRepository;
	@Autowired
	private RoleRepository roleRepository;
	
	
	@RequestMapping(value = "/permission/save", method = RequestMethod.POST)
	@ResponseBody
	public Map insert(@RequestBody Permission permission) {
		permissionRepository.save(permission);
		Map<String,Object> map = new HashMap<String, Object>();
		map.put("code", 200);
		map.put("message", "新增成功");
		return map;
	}
	
	/**
	 * 動態更新:僅限於更新單表字段
	 * @param house
	 * @return
	 */
	@RequestMapping(value = "/permission/update", method = RequestMethod.POST)
	@ResponseBody
	public Map update(@RequestBody Permission permission) {
		Optional<Permission> old = permissionRepository.findById(permission.getPermissionId());
		if(old.isPresent()){
			Permission oldPermission = old.get();
            //將傳過來的 house 中的非NULL屬性值複製到 oldHouse 中
            copyPropertiesIgnoreNull(permission, oldPermission);
            //將得到的新的 oldHouse 物件重新儲存到資料庫,因為資料庫中已經存在該記錄
            //所以JPA會很智慧的 改為更新操作,更新資料庫
            permissionRepository.save(oldPermission);
        }
		Map<String,Object> map = new HashMap<String, Object>();
		map.put("code", 200);
		map.put("message", "更新成功");
		return map;
	}
	
	@RequestMapping(value = "/permission/findPage", method = RequestMethod.POST)
	@ResponseBody
	public Map findPage(@RequestBody Map<String, Object> paramter) {
		//顯示第1頁每頁顯示3條
		PageRequest pr = super.initPageBounds(paramter);
		
		Page<Permission> stus = permissionRepository.findAll(new Specification<Permission>(){
			@Override
			public Predicate toPredicate(Root<Permission> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
				// TODO Auto-generated method stub
				List<Predicate> predicateList = new ArrayList<>();
				
				return criteriaBuilder.and(predicateList.toArray(new Predicate[predicateList.size()]));
			}
		}, pr);
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("code", 200);
		map.put("message", "查詢成功");
		map.put("date", stus);
		return map;
	}
	
	/**
	 * 查詢使用者指定許可權
	 * @param uid
	 * @return
	 */
	@RequestMapping(value = "/permission/{uid}", method = RequestMethod.GET)
	@ResponseBody
	public Map findPermission(@PathVariable Integer uid) {
		List<PermissionVo> permissionsVos = new ArrayList<PermissionVo>();
		
		List<Permission> permissions = new ArrayList<Permission>();
		//顯示第1頁每頁顯示3條
		User user = userRepository.findByUserId(uid);
		
		user.getRoles().stream().forEach(item->{
        	Role role = roleRepository.findByRoleId(item.getRoleId());
        	if(!CollectionUtils.isEmpty(role.getPermissions())){
        		for(Permission permission : role.getPermissions()){
        			if(permission.getPermisionParentId() == null){
        				permissions.add(permission);
        			}
        			
        		}
        	}
        });
		
	
		
		
		permissions.stream().forEach(item ->{
			 
			 /**
			  * Spring Data JPA 動態查詢條件
			  */
			 Specification<Permission> specification = new Specification<Permission>() {
	             @Override
	            public Predicate toPredicate(Root<Permission> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
	                List<Predicate> predicates = new ArrayList<Predicate>();
	                if(null != item.getPermissionId()) {
	                    predicates.add(cb.equal(root.<Integer>get("permisionParentId"), item.getPermissionId()));
	                }
	                return cq.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
	            }
	        };
	        List<Permission> childPermission = permissionRepository.findAll(specification);
	        List<PermissionVo> childPermissionVO = new ArrayList<PermissionVo>();
	        for(Permission permission : childPermission){
	        	 PermissionVo vo = new PermissionVo();
	        	 BeanUtils.copyProperties(permission, vo);
	        	 childPermissionVO.add(vo);
	        }
	        
	        PermissionVo vo = new PermissionVo();
	        BeanUtils.copyProperties(item, vo);
	        vo.setChild(childPermissionVO);
	        
	        permissionsVos.add(vo);
	        
		});
		 
		
		// 資料清理
//		Iterator<Permission> iterator = permissions.iterator();
//		while(iterator.hasNext()){
//			Permission permission = iterator.next();
//			if(permission.getPermisionParentId() != null){
//				iterator.remove();
//			}
//		}
		
		

//		for(Permission permission : permissions){
//			if(permission.getParent() != null){
//				permissions.remove(permission);
//			}
//		}
				
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("code", 200);
		map.put("message", "查詢成功");
		map.put("date", permissionsVos);
		return map;
	}
	
	@RequestMapping(value = "/permission/delete/{id}", method = RequestMethod.GET)
	@ResponseBody
	public Map delete(@PathVariable("id") Integer id) {
		permissionRepository.deleteById(id);
		Map<String,Object> map = new HashMap<String, Object>();
		map.put("code", 200);
		map.put("message", "刪除成功");
		return map;
	}

}

效果戰術: