Alkalmazza a CQRS-t egy Spring REST API-ra

REST felső

Most jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:

>> ELLENŐRIZZE A FOLYAMATOT

1. Áttekintés

Ebben a gyors cikkben valami újat fogunk csinálni. Fejleszteni fogunk egy meglévő REST Spring API-t, és a Command Query Responsibility Segregation - CQRS - használatára késztetjük.

A cél az, hogy világosan válassza el a szolgáltatási és a vezérlő rétegeket külön kezelni a rendszerbe érkező Reads - Queries and Writes - parancsokat.

Ne feledje, hogy ez csak egy korai első lépés az ilyen jellegű építészet felé, nem pedig „érkezési pont”. Ennek ellenére - izgatott vagyok ettől.

Végül - az a példa, amelyet használni fogunk, a közzététel Felhasználó erőforrások, és része a folyamatban lévő Reddit alkalmazás esettanulmányunknak, amely példázza ennek működését - de természetesen minden API megteszi.

2. A szolgáltatási réteg

Kezdjük egyszerű módon - az előző felhasználói szolgáltatásunkban az olvasási és az írási műveletek azonosításával -, és ezt két külön szolgáltatásra bontjuk - UserQueryService és UserCommandService:

nyilvános felület IUserQueryService {getUsersList lista (int oldal, int méret, String sortDir, String sort); String checkPasswordResetToken (hosszú userId, String token); String checkConfirmRegistrationToken (String token); long countAllUsers (); }
nyilvános felület IUserCommandService {void registerNewUser (String felhasználónév, String e-mail, String jelszó, String appUrl); void updateUserPassword (Felhasználó felhasználó, String jelszó, String oldPassword); void changeUserPassword (Felhasználó felhasználó, String jelszó); void resetPassword (Karakterlánc, String appUrl); void createVerificationTokenForUser (Felhasználó felhasználó, String token); void updateUser (Felhasználói felhasználó); }

Az API elolvasásából jól látható, hogy a lekérdező szolgáltatás hogyan végzi az összes olvasást és a parancsszolgáltatás nem olvas semmilyen adatot - minden érvénytelen visszatér.

3. A vezérlő réteg

Következő - a vezérlő réteg.

3.1. A Lekérdezésvezérlő

Itt van a miénk UserQueryRestController:

@Controller @RequestMapping (value = "/ api / users") public class UserQueryRestController {@Autowired private IUserQueryService userService; @Autowired private IScheduledPostQueryService tervezettPostService; @Autowired privát ModelMapper modelMapper; @PreAuthorize ("hasRole ('USER_READ_PRIVILEGE')") @RequestMapping (metódus = RequestMethod.GET) @ResponseBody nyilvános lista getUsersList (...) {PagingInfo pagingInfo = új PagingInfo (oldal, méret, userService.countA); response.addHeader ("PAGING_INFO", pagingInfo.toString ()); List users = userService.getUsersList (oldal, méret, sortDir, rendezés); return users.stream (). map (felhasználó -> convertUserEntityToDto (felhasználó)). gyűjt (Collectors.toList ()); } private UserQueryDto convertUserEntityToDto (Felhasználó felhasználó) {UserQueryDto dto = modelMapper.map (felhasználó, UserQueryDto.class); dto.setScheduledPostsCount (tervezettPostService.countScheduledPostsByUser (felhasználó)); return dto; }}

Ami itt érdekes, hogy a lekérdezésvezérlő csak a lekérdezési szolgáltatásokat injektálja.

Ami még érdekesebb lenne, az az zárja le ennek a vezérlőnek a hozzáférését a parancsnoki szolgáltatásokhoz - ezeket külön modulba helyezve.

3.2. A parancsvezérlő

Itt van a parancsvezérlőnk megvalósítása:

@Controller @RequestMapping (value = "/ api / users") public class UserCommandRestController {@Autowired private IUserCommandService userService; @Autowired privát ModelMapper modelMapper; @RequestMapping (érték = "/ registration", metódus = RequestMethod.POST) @ResponseStatus (HttpStatus.OK) nyilvános érvénytelen nyilvántartás (HttpServletRequest kérés, @RequestBody UserRegisterCommandDto userDto) {String appUrl = request.getRequestURL (). (request.getRequestURI (), ""); userService.registerNewUser (userDto.getUsername (), userDto.getEmail (), userDto.getPassword (), appUrl); } @PreAuthorize ("isAuthenticated ()") @RequestMapping (value = "/ password", method = RequestMethod.PUT) @ResponseStatus (HttpStatus.OK) public void updateUserPassword (@RequestBody UserUpdatePasswordCommandDto userDto) (userServer) (userServer , userDto.getPassword (), userDto.getOldPassword ()); } @RequestMapping (value = "/ passwordReset", metódus = RequestMethod.POST) @ResponseStatus (HttpStatus.OK) public void createAResetPassword (HttpServletRequest kérés, @RequestBody UserTriggerResetPasswordCommandDto userDr) = String.getl (URL). csere (request.getRequestURI (), ""); userService.resetPassword (userDto.getEmail (), appUrl); } @RequestMapping (value = "/ password", method = RequestMethod.POST) @ResponseStatus (HttpStatus.OK) public void changeUserPassword (@RequestBody UserchangePasswordCommandDto userDto) {userService.changeUserPassword (getCurrentUser (), userDto.get; } @PreAuthorize ("hasRole ('USER_WRITE_PRIVILEGE')") @RequestMapping (érték = "/ {id}", módszer = RequestMethod.PUT) @ResponseStatus (HttpStatus.OK) public void updateUser (@RequestBody UserUpdateCommandDto. updateUser (convertToEntity (userDto)); } privát Felhasználó convertToEntity (UserUpdateCommandDto userDto) {return modelMapper.map (userDto, User.class); }}

Néhány érdekes dolog történik itt. Először - vegye észre, hogy ezek az API-implementációk hogyan használnak egy másik parancsot. Ennek főként az a célja, hogy jó alapot nyújtsunk az API tervezésének további javításához és a különböző erőforrások kibontakozásához.

Egy másik ok az, hogy amikor megtesszük a következő lépést, az Események beszerzése felé - tiszta parancssorunk van, amelyekkel dolgozunk.

3.3. Külön erőforrás-ábrázolások

Nézzük át gyorsan a felhasználói erőforrásunk különböző ábrázolásait, miután ezt parancsokra és lekérdezésekre bontottuk:

public class UserQueryDto {private Long id; privát String felhasználónév; privát boolean engedélyezve; privát Set szerepek; privát hosszú tervezettPostsCount; }

Itt vannak a Command DTO-k:

  • UserRegisterCommandDto a felhasználói regisztrációs adatok ábrázolására szolgál:
public class UserRegisterCommandDto {private String felhasználónév; privát karakterlánc e-mail; privát karakterlánc jelszó; }
  • UserUpdatePasswordCommandDto adatok felhasználására szolgál a felhasználói jelszó frissítéséhez:
public class UserUpdatePasswordCommandDto {private String oldPassword; privát karakterlánc jelszó; }
  • UserTriggerResetPasswordCommandDto a felhasználói e-mail képviseletére szolgál a jelszó alaphelyzetbe állításához egy e-mail elküldésével a jelszó visszaállításával:
public class UserTriggerResetPasswordCommandDto {private String email; }
  • UserChangePasswordCommandDto az új felhasználói jelszó képviseletére szolgál - ez a parancs a felhasználói jelszó-visszaállító token után kerül meghívásra.
public class UserChangePasswordCommandDto {private String jelszó; }
  • UserUpdateCommandDto az új felhasználó adatainak megjelenítése módosítások után:
public class UserUpdateCommandDto {private Long id; privát boolean engedélyezve; privát Set szerepek; }

4. Következtetés

Ebben az oktatóanyagban megalapoztuk a CQRS tiszta implementációját egy Spring REST API számára.

A következő lépés az API továbbfejlesztése lesz azáltal, hogy különálló felelősségeket (és erőforrásokat) határoz meg a saját szolgáltatásaikban, hogy szorosabban illeszkedjünk egy erőforrás-központú architektúrához.

REST alsó

Most jelentettem be az újat Tanulj tavaszt tanfolyam, amelynek középpontjában az 5. tavasz és a tavaszi bakancs 2 alapjai állnak:

>> ELLENŐRIZZE A FOLYAMATOT

$config[zx-auto] not found$config[zx-overlay] not found