補充說明:繼續(xù)我們的用戶系統開發(fā)。前面有了基本的用戶信息,還有登錄賬號,還完成了單點登錄。賬號必須綁定用戶,用戶不一定擁有可登錄賬號。這是對于管理系統而言還是有必要的。有些用戶是業(yè)務的參與者,但并不需要有操作。恩,也可以說這里的用戶并不是常說的那種包含用戶名密碼的用于登錄的賬號,而只是一個用戶信息的資源。這系統里用于登錄的賬號的對象叫Account(賬號),而User(用戶)是業(yè)務中的參與者,業(yè)務中的關聯都是關聯到User的。把前面代碼的Safety對象的名稱已經改成了Account。這個可以參與源碼。
用戶登錄先告一段落,在后續(xù)業(yè)務中,不夠用時再補充功能,或者發(fā)現不足時再加強。如:客戶端管理,本來客戶端是要放在數據庫中管理的,token是要保存到數據庫中的。這些都是要做的,只是先往后放一放。
什么是組織
組織是對資源進行分組的一種方式。如:XX集團、XX醫(yī)院、XX科室、XX病區(qū)…… 那么組織類型就是:集團、醫(yī)院、科室、部門……
組織的作用在這里是非常大的??梢哉f是這一號主角。這么定義的原因是:用戶會屬于某些組織,辦公用品是某組織的,這臺設備是某組織的資產等等,在管理中,人、事、物都是需要分組管理的。
在這里,科室指的是醫(yī)院下面的組織類型,為了區(qū)別于常說的“內科”、“兒科”等。我們約定:像“內科”、“兒科”這種人們常說的分科我們定義為“學科”,而科室是對組織的一種類型的定義??剖腋袷遣块T,學科更像專業(yè)。
上面這些定義也沒什么可以爭議的,我們只是在這里有這么個約定。在跟某院長討論這個問題的時候,我們認為這樣的定義更容易描述區(qū)分。
在這節(jié)我們先完成組織類型的業(yè)務實現,組織的業(yè)務會稍稍復雜些。就把組織類型和組織分成兩節(jié)來寫。
創(chuàng)建數據模型
組織類型:
package com.biboheart.huip.user.domain;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
@Data
@Entity
@Table(name = "bh_user_org_type")
public class OrgType implements Serializable {
private static final long serialVersionUID = -7469448447123762569L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name; // 名稱
private String sn; // 類型的序號
}
組織類型規(guī)則:這是為了對組織類型進行上下級規(guī)則的提前設置,比如:集團下面只允許添加醫(yī)院類型的組織,設置了這樣的規(guī)則后,在組織管理時就會有更好的用戶體驗。
package com.biboheart.huip.user.domain;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
@Data
@Entity
@Table(name = "bh_user_org_type_rule")
public class OrgTypeRule implements Serializable {
private static final long serialVersionUID = -6713717729763625987L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer pid; // 規(guī)則的父id
private Integer cid; // 規(guī)則的子id
}
創(chuàng)建數據連接
OrgTypeRepository:
package com.biboheart.huip.user.repository;
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import com.biboheart.huip.user.basejpa.CustomRepository;
import com.biboheart.huip.user.domain.OrgType;
public interface OrgTypeRepository extends CustomRepository<OrgType, Integer> {
OrgType findBySnAndIdNot(String sn, Integer id);
OrgType findByNameAndIdNot(String name, Integer id);
@Query("select id from OrgType where sn in ?1")
List<Integer> findIdsBySnIn(List<String> inSnList);
@Query("select id from OrgType")
public List<Integer> findAllIds();
}
OrgTypeRuleRepository:
package com.biboheart.huip.user.repository;
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import com.biboheart.huip.user.basejpa.CustomRepository;
import com.biboheart.huip.user.domain.OrgTypeRule;
public interface OrgTypeRuleRepository extends CustomRepository<OrgTypeRule, Integer> {
OrgTypeRule findByPidAndCid(Integer pid, Integer cid);
@Query("select cid from OrgTypeRule where pid in ?1")
public List<Integer> findCidsByPidIn(List<Integer> pids);
@Query("select pid from OrgTypeRule where cid in ?1")
public List<Integer> findPidsByCidIn(List<Integer> cids);
}
創(chuàng)建服務
兩個數據模型只是為了對應兩張數據表。服務我們只需要一個。
OrgTypeService
package com.biboheart.huip.user.service;
import java.util.List;
import com.biboheart.brick.exception.BhException;
import com.biboheart.huip.user.domain.OrgType;
import com.biboheart.huip.user.domain.OrgTypeRule;
public interface OrgTypeService {
/**
* 添加組織類型
* @param orgType 組織類型對象
* @return
*/
public OrgType save(OrgType orgType) throws BhException;
/**
* 刪除組織類型
* @param id 組織類型ID
* @return
*/
public OrgType delete(Integer id, String sn);
/**
* 查詢組織類型
* @param id
* @param sn
* @return
*/
public OrgType load(Integer id, String sn);
/**
* 取所有類型
* @return
*/
public List<OrgType> list(List<Integer> ids, List<String> sns, List<Integer> pidList, Integer descendant, Integer self);
public List<Integer> listId(List<String> sns, List<Integer> pidList, Integer descendant, Integer self);
/**
* 添加組織類型規(guī)則
* @param pid 父類型ID
* @param cid 子類型ID
* @throws EberException
*/
public OrgTypeRule addOrgTypeRule(Integer pid, Integer cid) throws BhException;
public OrgTypeRule deleteOrgTypeRule(Integer pid, Integer cid) throws BhException;
}
實現它
package com.biboheart.huip.user.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.biboheart.brick.exception.BhException;
import com.biboheart.brick.utils.CheckUtils;
import com.biboheart.brick.utils.ListUtils;
import com.biboheart.huip.user.domain.OrgType;
import com.biboheart.huip.user.domain.OrgTypeRule;
import com.biboheart.huip.user.repository.OrgTypeRepository;
import com.biboheart.huip.user.repository.OrgTypeRuleRepository;
import com.biboheart.huip.user.service.OrgTypeService;
@Service
public class OrgTypeServiceImpl implements OrgTypeService {
@Autowired
private OrgTypeRepository orgTypeRepository;
@Autowired
private OrgTypeRuleRepository orgTypeRuleRepository;
@Override
public OrgType save(OrgType orgType) throws BhException {
if(CheckUtils.isEmpty(orgType.getId())) {
orgType.setId(0);
}
if (CheckUtils.isEmpty(orgType.getSn())) {
throw new BhException("類型編號不能為空");
}
if(CheckUtils.isEmpty(orgType.getName())) {
throw new BhException("類型名稱不能為空");
}
if(null != orgTypeRepository.findBySnAndIdNot(orgType.getSn(), orgType.getId())) {
throw new BhException("編號已經存在");
}
if(null != orgTypeRepository.findByNameAndIdNot(orgType.getName(), orgType.getId())) {
throw new BhException("名稱已經存在");
}
orgType = orgTypeRepository.save(orgType);
return orgType;
}
@Override
public OrgType delete(Integer id, String sn) {
OrgType ot = null;
if (null == ot && !CheckUtils.isEmpty(sn)) {
ot = orgTypeRepository.findBySnAndIdNot(sn, 0);
}
if (null == ot && !CheckUtils.isEmpty(id)) {
ot = orgTypeRepository.findById(id).get();
}
if (null != ot) {
orgTypeRepository.delete(ot);
}
return ot;
}
@Override
public OrgType load(Integer id, String sn) {
OrgType ot = null;
if (null == ot && !CheckUtils.isEmpty(sn)) {
ot = orgTypeRepository.findBySnAndIdNot(sn, 0);
}
if (null == ot && !CheckUtils.isEmpty(id)) {
ot = orgTypeRepository.findById(id).get();
}
return ot;
}
@Override
public List<OrgType> list(List<Integer> ids, List<String> sns, List<Integer> pidList, Integer descendant,
Integer self) {
if(CheckUtils.isEmpty(ids) && CheckUtils.isEmpty(sns) && CheckUtils.isEmpty(pidList)) {
return orgTypeRepository.findAll();
}
if(!CheckUtils.isEmpty(sns)) {
List<Integer> idList = orgTypeRepository.findIdsBySnIn(sns);
if(CheckUtils.isEmpty(ids)) {
ids = idList;
} else {
ids = ListUtils.intersectionList(ids, idList);
}
}
if(!CheckUtils.isEmpty(pidList)) {
if(CheckUtils.isEmpty(descendant)) {
List<Integer> cidList = orgTypeRuleRepository.findCidsByPidIn(pidList);
if(!CheckUtils.isEmpty(self)) {
ListUtils.mergeList(cidList, pidList);
}
if(CheckUtils.isEmpty(ids)) {
ids = cidList;
} else {
ids = ListUtils.intersectionList(ids, cidList);
}
} else {
List<Integer> cidList = new ArrayList<>();
listCid(pidList, cidList);
if(!CheckUtils.isEmpty(self)) {
ListUtils.mergeList(cidList, pidList);
}
if(CheckUtils.isEmpty(ids)) {
ids = cidList;
} else {
ids = ListUtils.intersectionList(ids, cidList);
}
}
}
if(CheckUtils.isEmpty(ids)) {
return null;
}
return orgTypeRepository.findAllById(ids);
}
@Override
public List<Integer> listId(List<String> sns, List<Integer> pidList, Integer descendant, Integer self) {
List<Integer> idList = new ArrayList<>();
if(CheckUtils.isEmpty(sns) && CheckUtils.isEmpty(pidList)) {
return orgTypeRepository.findAllIds();
}
if(!CheckUtils.isEmpty(sns)) {
idList = orgTypeRepository.findIdsBySnIn(sns);
}
if(!CheckUtils.isEmpty(pidList)) {
if(CheckUtils.isEmpty(descendant)) {
List<Integer> cidList = orgTypeRuleRepository.findCidsByPidIn(pidList);
if(!CheckUtils.isEmpty(self)) {
ListUtils.mergeList(cidList, pidList);
}
if(CheckUtils.isEmpty(idList)) {
idList = cidList;
} else {
idList = ListUtils.intersectionList(idList, cidList);
}
} else {
List<Integer> cidList = new ArrayList<>();
listCid(pidList, cidList);
if(!CheckUtils.isEmpty(self)) {
ListUtils.mergeList(cidList, pidList);
}
if(CheckUtils.isEmpty(idList)) {
idList = cidList;
} else {
idList = ListUtils.intersectionList(idList, cidList);
}
}
}
return idList;
}
@Override
public OrgTypeRule addOrgTypeRule(Integer pid, Integer cid) throws BhException {
if(CheckUtils.isEmpty(pid) || CheckUtils.isEmpty(cid)) {
throw new BhException("提供的參數有誤");
}
OrgTypeRule otr = orgTypeRuleRepository.findByPidAndCid(pid, cid);
if(null != otr) {
return otr;
}
otr = new OrgTypeRule();
otr.setPid(pid);
otr.setCid(cid);
return orgTypeRuleRepository.save(otr);
}
@Override
public OrgTypeRule deleteOrgTypeRule(Integer pid, Integer cid) throws BhException {
if(CheckUtils.isEmpty(pid) || CheckUtils.isEmpty(cid)) {
throw new BhException("提供的參數有誤");
}
OrgTypeRule otr = orgTypeRuleRepository.findByPidAndCid(pid, cid);
if(null == otr) {
return null;
}
orgTypeRuleRepository.delete(otr);
return otr;
}
private void listCid(List<Integer> pidList, List<Integer> cidList) {
if(CheckUtils.isEmpty(pidList)) {
return;
}
if(null == cidList) {
cidList = new ArrayList<>();
}
List<Integer> tcids = orgTypeRuleRepository.findCidsByPidIn(pidList);
if(CheckUtils.isEmpty(tcids)) {
return;
}
ListUtils.mergeList(cidList, tcids);
listCid(tcids, cidList);
}
}
開放接口
OrgTypeController
package com.biboheart.huip.user.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.biboheart.brick.exception.BhException;
import com.biboheart.brick.model.BhResponseResult;
import com.biboheart.brick.utils.CheckUtils;
import com.biboheart.brick.utils.PrimaryTransverter;
import com.biboheart.huip.user.domain.OrgType;
import com.biboheart.huip.user.domain.OrgTypeRule;
import com.biboheart.huip.user.service.OrgTypeService;
@RestController
public class OrgTypeController {
@Autowired
private OrgTypeService orgTypeService;
/**
* 添加/修改組織類型
* @param ot
* @return
* @throws EberException
*/
@RequestMapping(value = "/userapi/user/orgType/save", method = {RequestMethod.POST})
public BhResponseResult<?> save(OrgType ot) throws BhException {
ot = orgTypeService.save(ot);
return new BhResponseResult<>(0, "success", ot);
}
/**
* 刪除組織類型
* @param id
* @return
* @throws EberException
*/
@RequestMapping(value = "/userapi/user/orgType/delete", method = {RequestMethod.POST, RequestMethod.GET})
public BhResponseResult<?> delete(Integer id, String sn) {
OrgType ot = orgTypeService.delete(id, sn);
return new BhResponseResult<>(0, "success", ot);
}
/**
* 取組織類型
* @param id
* @param sn
* @return
* @throws EberException
*/
@RequestMapping(value = "/userapi/user/orgType/load", method = {RequestMethod.POST, RequestMethod.GET})
public BhResponseResult<?> load(Integer id, String sn) {
OrgType ot = orgTypeService.load(id, sn);
return new BhResponseResult<>(0, "success", ot);
}
/**
* 組織類型列表
* @param ids
* @param pid
* @return
* @throws EberException
*/
@RequestMapping(value = "/userapi/user/orgType/list", method = {RequestMethod.POST, RequestMethod.GET})
public BhResponseResult<?> list(String ids, Integer pid, String sns, Integer descendant, Integer self) {
List<OrgType> ots = null;
List<Integer> idList = PrimaryTransverter.idsStr2List(ids);
List<Integer> pidList = new ArrayList<>();
if (!CheckUtils.isEmpty(pid)) {
pidList.add(pid);
}
List<String> snList = new ArrayList<>();
if(!CheckUtils.isEmpty(sns)) {
String[] snArr = sns.split(",");
for(String sn : snArr) {
snList.add(sn);
}
}
ots = orgTypeService.list(idList, snList, pidList, descendant, self);
return new BhResponseResult<>(0, "success", ots);
}
/**
* 添加規(guī)則
* @param id
* @param cid
* @return
* @throws EberException
*/
@RequestMapping(value = "/userapi/user/orgTypeRule/save", method = {RequestMethod.POST, RequestMethod.GET})
public BhResponseResult<?> saveRule(Integer id, Integer cid) throws BhException {
OrgTypeRule otr = orgTypeService.addOrgTypeRule(id, cid);
return new BhResponseResult<>(0, "success", otr);
}
/**
* 刪除規(guī)則
* @param id
* @param cid
* @return
* @throws BhException
* @throws EberException
*/
@RequestMapping(value = "/userapi/user/orgTypeRule/delete", method = {RequestMethod.POST, RequestMethod.GET})
public BhResponseResult<?> deleteRule(Integer id, Integer cid) throws BhException {
OrgTypeRule otr = orgTypeService.deleteOrgTypeRule(id, cid);
return new BhResponseResult<>(0, "success", otr);
}
}
組織類型的數量不會很多,而且是低頻業(yè)務。如果規(guī)則的添加和刪除就不做批量了。
測試接口
測試保存

點擊“send”后出錯,返回的登錄頁面的代碼。

這個看問題現象可以想到它是因為security造成的。我們先改下資源配置
com.biboheart.huip.user.security.ResourceConfiguration
package com.biboheart.huip.user.security;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
@Configuration
@EnableResourceServer
public class ResourceConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.requestMatchers()
.antMatchers("/user/**", "/userapi/**")
.and()
.authorizeRequests()
.antMatchers("/user/**", "/userapi/**").authenticated();
}
}
/user/**是security中的controller中,獲取用戶信息、權限等的API的首部。我們約定用戶系統中的API的定義都以"/userapi/"開頭,這樣的約定,以便resource服務的配置。以后在這個系統中的接口增加就不用改變配置文件。
修改后再來試下訪問情況。

這下告訴我們的是無權限訪問。那我們來取個token再訪問。



使用password的grant_type獲取token。用access_token去請求接口。



保存成功了。
其實我們在用戶登錄中就可以進行這段測試。當時沒測,現在放到這里來走個流程。也說明了接口已經受到了用戶權限的控制。到目前為止,只是控制用戶是否登錄,并沒有做更細致的權限管理。這個要放在后面進行。




我添加了4個規(guī)則

有了規(guī)則后再訪問列表就可以加些規(guī)則的參數

列表參數的含義是:列出ID為2的組織類型下面的所有后輩(子孫)組織類型,結果中包含自己。如果去掉self的參數,結果就會只有3個項。
目錄結構

git地址:https://gitee.com/biboheart/huip.git