springcloud微服務(wù)架構(gòu)實戰(zhàn):商家管理微服務(wù)設(shè)計
商家管理微服務(wù)設(shè)計
商家管理微服務(wù)是一個獨立的RESTAPI應(yīng)用,這個應(yīng)用通過接口服務(wù)對外提供商家信息管理、商家權(quán)限管理和菜單資源管理等方面的功能。
商家管理微服務(wù)開發(fā)在merchant-restapi模塊中實現(xiàn),有關(guān)這一類型模塊的依賴引用、配置、啟動程序的設(shè)計等,可以參考前面章節(jié)中有關(guān)RESTAPI微服務(wù)開發(fā)中的相關(guān)說明,不再重復(fù)。
商家管理微服務(wù)將直接調(diào)用權(quán)限管理模型的領(lǐng)域服務(wù),在調(diào)用之前,我們可以對領(lǐng)域服務(wù)層進行一個單元測試,以驗證領(lǐng)域服務(wù)層的程序正確性。同時,也可以通過單元測試生成一個管理員用戶,以方便后面的操作體驗。

商家管理服務(wù)層單元測試
首先,在merchant-restapi模塊中,對10.1節(jié)開發(fā)的各個領(lǐng)域服務(wù)進行測試,從而對整個商家業(yè)務(wù)領(lǐng)域的開發(fā)進行全面的驗證。這些測試包括各個實體的創(chuàng)建、數(shù)據(jù)獲取、對象更新、刪除和分頁查詢等內(nèi)容。
創(chuàng)建商家及其用戶實體的測試用例如下所示:
@RunWith (Spr ingRunner.class)
@ContextConfiguration(classes = {JpaConfiguration.class,
MerchantRestApiAppl ication.class})
@SpringBootTes t
public class UserTest {
private static Logger logger = LoggerFactory. getLogger (UserTest.class) ;
@Autowi red
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private ResourceService resourceService;
CAutowired
private ModelService modelService;
CAutowired
private KindService kindService;
@Autowired
private MerchantService merchantService;
@Test
public void insertData() {
Kind kind = new Kind() ;
kind.setName("商家系統(tǒng)");
kind. setLink ("merchantweb") ;
kindService. save (kind) ;
Assert .notNull (kind.getId(), "create kind error") ;
Model model = new Model () ;
model . setName("用戶管理") ;
model. setHost ("/user/ index") ;
model. setKind(kind) ;
modelService.save (model) ;
Assert. notNull (model.getId(),"create model error") ;
Resource resource = new Resource() ;
resource.setName("用戶修改");
resource.setUrl ("/user/edit/**") ;
resource . setModel (model) ;
resourceService. save (resource) ;
Assert. notNull (resource.getId(), "create resource error") ;
Role role = new Role() ;
role.setName("商家管理員");
List resources = new ArrayList<>() ;
resources. add (resource) ;
role. setResources (resources) ;
roleService.save (role) ;
Assert. notNull (role.getId(),"create role error") ;
Merchant merchant = new Merchant() ;
merchant . setName ("測試商家") ;
merchantService. save (merchant) ;
Assert .notNull (merchant.getId(), "create merchant error") ;
User user = new User() ;
user. setName ("admin") ;
BCryptPasswordEncoder bpe = new BCryptPasswordEncoder() ;
user. setPassword (bpe. encode ("123456")) ;
user . setEmail ("[email protected]") ;
List roles = new ArrayList<>() ;
roles.add(role) ;
user . setRoles (roles) ;
user . setMerchant (merchant) ;
userService. save (user) ;
Assert .notNull (user.getId(), "create user error");
}
} 在這個測試用例中,包含了商家業(yè)務(wù)模型中所有實體的創(chuàng)建,這些實體包括分類、模塊、資源、角色、商家、用戶等。如果測試通過,則可以生成一個由分類、模塊和資源組成的三級菜單,同時創(chuàng)建一個具有所屬商家、 具有一個角色和相關(guān)訪問資源權(quán)限的用戶實體。這個用戶實體的用戶名和密碼為“admin/123456”。在后面的開發(fā)中,我們可以使用這個用戶來登錄系統(tǒng)。

如果測試不能通過,則可以根據(jù)斷言中提示的錯誤信息,在相關(guān)的服務(wù)組件中查找出錯的原因。
獲取實體的測試用例如下所示:
@Test
public void getData() {
User user = userService. findOne (1L) ;
Assert.notNull (user, "not find") ;
logger . info("====user==={}", new Gson() . toJson (user));
}這個測試用例通過用戶ID獲取用戶信息,如果測試通過,則輸出用戶實體的完整信息,包括用戶、用戶擁有的角色和角色包含的資源等。
分頁查詢的測試如下所示:
@Test
public void findAll() throws Exception{
SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse ("2017-01-0100:00:00") ;
UserQo userQo = new UserQo() ;
userQo. setCreated(date) ;
Merchant merchant
merchantService. findOne (1L) ;
MerchantQo merchantQo = CopyUtil.copy (merchant, MerchantQo .class);
userQo. setMerchant (merchantQo) ;
Page page = userService. findA1l (userQo) ;
Assert.notEmpty (page .getContent(), "list is empty");
List list = page. getContent() ;
for(User user : list) {
logger. info("====user===={},", new Gson() .toJson(user));
}
} 這個測試用例使用查詢對象UserQo配置了分頁查詢的參數(shù),來執(zhí)行用戶信息的分頁查詢。
在查詢參數(shù)中設(shè)定了創(chuàng)建日期和所屬商家等屬性。在查詢成功后,將輸出每條記錄的信息,這些信息有用戶對象、用戶擁有的角色、角色關(guān)聯(lián)的資源和資源所屬的模塊等。
其他有關(guān)更新和刪除等測試,可以參照上面的方法進行設(shè)計。
單元測試在進行工程打包時,可以作為程序正確性的一一個驗證手段。如果測試不通過,則不能成功打包。當使用Maven進行項目管理時,這項功能默認是打開的。如果想要在關(guān)閉打包時執(zhí)行測試,可以在工程中使用下面所示的配置:
<plugin>
<group Id>org. apache . maven.pluginsgroupId>
<artifactId>maven-surefire-pluginartifactId>
<version>2.20version>
<configuration>
<skipTests>trueskipTests>
configuration>
plugin>商家服務(wù)的接口開發(fā)
在商家管理的REST API應(yīng)用中,包含了商家信息管理、商家用戶權(quán)限管理和菜單資源管理等接口的開發(fā)。每一個接口的設(shè)計我們分別使用一個RestController來實現(xiàn)。這些接口的設(shè)計基本上大同小異,下面我們以用戶接口的設(shè)計為例進行說明。
用戶的查詢接口是使用GET方法實現(xiàn)的,幾種查詢接口的實現(xiàn)方法如下所示:
@RestController
@RequestMapping("/user")
public class UserController
private static Logger logger 二LoggerFactory .getLogger (UserController.
class) ;
@Autowi red
private UserService userService;
@RequestMapping("/{id}")
public String findById (EPathVariable Long id) {
return new Gson() . toJson (userService. findOne(id));
@RequestMapping ("/names/ {name}")
public String findByName (@PathVariable String name) {
return new Gson() . toJson (userService. findByName (name)) ;
@RequestMapping("/list")
public String findList() {
return new Gson() . toJson (userService. findAll());
@RequestMapping (value = "/page")
public String findPage (Integer index, Integer size, String name, Long
merchantId) {
try {
UserQo userQo = new UserQo() ;
if (Commonutils. isNotNull (index)) {
userQo. setPage (index) ;
if (CommonUtils. isNotNull (size)) {
userQo.setSize (size) ;
}
if (CommonUtils. isNotNull (name)) {
userQo. setName (name) ;
if (CommonUtils. isNotNull (merchantId)) {
MerchantQo merchantQo = new MerchantQo();
merchantQo . setId (merchantId) ;
userQo. setMerchant (merchantQo) ;
Page users = userService. findAll (userQo) ;
Map<String, object> page = new HashMap<>() ;
page.put ("content", users .getContent());
page .put ("totalPages", users . getTotalPages();
page.put ("totalelements", users . getTotalElements());
return new Gson() . toJson(page) ;
} catch (Exception e) {
e. printStackTrace() ;
return null ;
}
} 這些查詢接口有單個對象查詢、列表查詢和分頁查詢等。因為是接口調(diào)用,所以查詢的結(jié)果最終都是以JSON結(jié)構(gòu)的方式返回文本數(shù)據(jù)。
如果要新建-一個商家用戶,則可以使用POST方法實現(xiàn),代碼如下所示:
@RestController
ERequestMapping ("/user")
public class UserController
private static Logger logger =
LoggerFactory . getLogger (UserController.class) ;
@Autowired
private UserService userService;
CRequestMapping (value=" /save", method = RequestMethod. POST)
public String save (@RequestBody UserQo userQo) throws Exception{
User user = CopyUtil. copy (userQo, User.class);
List roleList = CopyUtil. copyList (userQo . getRoles(), Role.class);
user.setRoles (roleList) ;
user.setMerchant (CopyUtil. copy (userQo. getMerchant (),Merchant.class));
String ret = userService. insert (user) ;
logger. info("新增=" + ret) ;
return ret;
}
} 當創(chuàng)建實體提交給數(shù)據(jù)服務(wù)進行處理時,必須將輸入?yún)?shù)中的查詢對象轉(zhuǎn)化為實體,使用實體調(diào)用領(lǐng)域服務(wù)進行數(shù)據(jù)保存。并且在創(chuàng)建-一個商家用戶實體時,為了保證商家用戶的合法性,還必須指定用戶的所屬商家,并且給其分配一個角色,這樣,這個商家用戶才可以用來登錄商家系統(tǒng)。
商家用戶的更新設(shè)計可以使用PUT方法實現(xiàn),代碼如下所示:
@RestController
@RequestMapping ("/user")
public class UserController
private static Logger logger =
LoggerFactory.getLogger (UserController.class) ;
@Autowi red
private UserService userService;
@RequestMapping (value=" /update", method
RequestMethod. PUT)
public String update (@RequestBody UserQo userQo) throws Exception{
User user = CopyUtil.copy (userQo, User. class);
List roleList = CopyUtil.copyList (userQo.getRoles(), Role.class);
user .setRoles (roleList) ;
user . setMerchant (CopyUtil.copy (userQo. getMerchant (), Merchant.class));
String ret = userService. update (user);
logger. info("修改="+ ret) ;
return ret;
}
} 商家用戶的更新設(shè)計與創(chuàng)建一個商 家用戶的實現(xiàn)方法相差不多,不同之處在于請求方法及傳輸?shù)膮?shù)。
刪除一個商家用戶的設(shè)計可以使用DELETE方法實現(xiàn),代碼如下所示:
@RestController
@RequestMapping (" /user")
public class UserController
private static Logger logger = LoggerFactory. getLogger (UserController .
class) ;
@Autowired
private UserService userService;
@Reques tMapping (value="/delete/{id}",method = RequestMethod . DELETE)
public String delete(@Pathvariable Long id) throws Exception {
String ret = userService .delete(id) ;
logger. info("刪除=" + ret) ;
return ret;
}
}當要刪除的實體具有關(guān)聯(lián)關(guān)系時,則必須先刪除它們之間的關(guān)聯(lián)關(guān)系,然后才能執(zhí)行刪除操作。例如,在角色刪除的設(shè)計中,使用了如下所示的設(shè)計: .
@RequestMapping (value="/delete/ {id}", method = RequestMethod. DELETE)
public String delete (@PathVariable Long id) throws Exception {
//讓具有此角色的用戶脫離關(guān)系
List userList = userService. findByRoleId(id) ;
if (userList != null && userList.size() > 0) {
for(User user : userList) {
for (Role role : user.getRoles()) {
if(role.getId() .equals(id)) {
user .getRoles() . remove (role) ;
userService. update (user) ;
break;
}
}
}
}
//安全刪除角色
String ret = roleService.delete(id) ;
logger. info("刪除=" + ret) ;
return ret;
} 即在刪除角色之前,要保證角色沒有被用戶關(guān)聯(lián)。如果已經(jīng)存在關(guān)聯(lián)關(guān)系,則必須將這些關(guān)聯(lián)關(guān)系刪除之后,才能成功刪除角色。
在完成接口開發(fā)之后,可以啟動REST API應(yīng)用,對一些查詢接口可以使用瀏覽器進行-一個簡單的測試。例如,對于用戶信息的分頁查詢,可以使用如下所示的鏈接進行測試:
http://localhost: 9081/user/page如果數(shù)據(jù)庫中存在商家用戶數(shù)據(jù),則打開鏈接之后,可以看到如圖10-3所示的JSON結(jié)構(gòu)的數(shù)據(jù)。

對于上面設(shè)計的這些接口調(diào)用方法,我們都以FeignClient的方式進行了封裝。更詳細的信息可以參照前面章節(jié)中相關(guān)內(nèi)容的說明。商家服務(wù)的接口調(diào)用設(shè)計,在模塊merchant-client 中實現(xiàn)。在后面的開發(fā)中,我們只需在項目管理中配置模塊merchant-client的依賴引用,就可以使用這些接口調(diào)用方法實現(xiàn)商家管理的各項功能設(shè)計了。
本文給大家講解的內(nèi)容商家管理后臺與sso設(shè)計:商家管理微服務(wù)設(shè)計
下篇文章給大家講解的是商家管理后臺與sso設(shè)計:SSO設(shè)計;
覺得文章不錯的朋友可以轉(zhuǎn)發(fā)此文關(guān)注小編;
感謝大家的支持!
本文就是愿天堂沒有BUG給大家分享的內(nèi)容,大家有收獲的話可以分享下,想學習更多的話可以到微信公眾號里找我,我等你哦。
