Spring Data JPA 許可權記錄轉許可權樹形結構
阿新 • • 發佈:2020-12-16
技術標籤: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;
}
}
效果戰術: