๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ป ํ”„๋กœ์ ํŠธ/๐Ÿ‘‘ VIP ์ดˆ๋Œ€์žฅ ๐Ÿ’Œ

[Spring, React] ๊ฐ์ฒด ์ค‘์‹ฌ์ธ JPA์— ๋งž์ถฐ์„œ ์ฝ”๋“œ ์ˆ˜์ •ํ•˜๊ธฐ.

by hyeong._.ing 2026. 6. 4.

 

 

์ดˆ๋ฐ˜์— DB ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ,
ํ…Œ์ด๋ธ” ์ค‘์‹ฌ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ JPA๋Š” ๊ฐ์ฒด ์ค‘์‹ฌ์ด๊ธฐ ๋•Œ๋ฌธ์—
์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์•ผํ•  ํ•„์š”์„ฑ์„ ๋А๊ผˆ๋‹ค.

 

 

 

 

1. ์ƒํ™ฉ์„ค๋ช…

  • ์ดˆ๋ฐ˜ ํ”„๋กœ์ ํŠธ๋Š” ๊ด€๋ฆฌ์ž ์˜์—ญ์—์„œ ์ด 3๊ฐœ์˜ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
  • AdminRepository : ๊ด€๋ฆฌ์ž ์ •๋ณด๋ฅผ ์ €์žฅํ•œ๋‹ค.
  • PemissionRepository : ๊ถŒํ•œ ์ •๋ณด๋ฅผ ์ €์žฅํ•œ๋‹ค. ์ง€๊ธˆ ํ”„๋กœ์ ํŠธ์—์„  ์ด 5๊ฐ€์ง€ ๊ถŒํ•œ์ด ์žˆ๋‹ค. ์กฐํšŒ | ์ถ”๊ฐ€ | ์ˆ˜์ • | ์‚ญ์ œ | ๊ฒ€์ƒ‰์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ๊ฐ๊ฐ 1๋ฒˆ, 2๋ฒˆ, 3๋ฒˆ... ์ด๋Ÿฐ์‹์œผ๋กœ ๋ฒˆํ˜ธ๋ฅผ ๋ถ€์—ฌํ–ˆ๋‹ค.
  • AdminPermissionRepository : ์–ด๋–ค ๊ด€๋ฆฌ์ž๊ฐ€ ์–ด๋–ค ๊ถŒํ•œ์„ ๊ฐ–๊ณ  ์žˆ๋Š”์ง€ ์ €์žฅํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด id๊ฐ€ 1๋ฒˆ์ธ ๊ด€๋ฆฌ์ž๊ฐ€ ์กฐํšŒ, ์ˆ˜์ • ๊ถŒํ•œ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด '1-1', '1-3' ๋Œ€์ถฉ ์ด๋Ÿฐ์‹์œผ๋กœ ์ •๋ณด๊ฐ€ ์ €์žฅ๋œ๋‹ค.
  • ์ฒ˜์Œ ๋กœ์ง์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ๊ด€๋ฆฌ์ž ์ˆ˜์ •์ด ์š”์ฒญ๋˜๋ฉด ๋‚ด๋ถ€์—์„œ ์›๋ž˜ ์žˆ๋˜ ๊ด€๋ฆฌ์ž id๋ฅผ ์ฐพ์•„ ์—ฐ๊ฒฐ๋œ ๊ถŒํ•œ์„ ๋ชจ๋‘ ์‚ญ์ œํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ ์ƒˆ๋กญ๊ฒŒ ์š”์ฒญ ๋ฐ›์€ ๊ถŒํ•œ์„ ์ถ”๊ฐ€ ํ•œ๋‹ค. => ์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. flush( )๋ฅผ ํ†ตํ•ด ๊ฐ•์ œ๋กœ ์‚ญ์ œ ์š”์ฒญ์„ ํ•ด์•ผ๋งŒ ์ˆ˜์ •์ด ์ด๋ค„์ง„๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
  • flush( )๋Š” ์›๋ž˜ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์•Œ์•„์„œ ํ•ด์ค˜์•ผํ•œ๋‹ค. ๋‚ด๊ฐ€ ์ƒ๊ฐํ–ˆ๋˜ ๋กœ์ง์€ ์‚ญ์ œ ์š”์ฒญ์ด ์ผ์–ด๋‚˜๋ฉด ์•Œ์•„์„œ flush( )๊ฐ€ ์ด๋ค„์ง„ ๋’ค ์ƒˆ๋กœ์šด ์ •๋ณด๋ฅผ insertํ•˜๋Š”๊ฑฐ์˜€๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ง€๊ธˆ ์ฝ”๋“œ๋Š” ์ง์ ‘ flush( )๋ฅผ ์ž‘์„ฑํ•ด์•ผ๋งŒ ์ˆ˜์ •์ด ์™„๋ฃŒ๋œ๋‹ค. ์ด๊ฑธ ๋ณด๊ณ  ์ง€๊ธˆ ์ฝ”๋“œ๋Š” JPA๋ฅผ ์ œ๋Œ€๋กœ ๋‹ค๋ฃจ์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๋‹ค.

 

 

 


 

 

 

 

2. ์ˆ˜์ • ์ „ AdminService ์ฝ”๋“œ ๋ถ„์„

  • ๊ถŒํ•œ ์ „๋ถ€ ์‚ญ์ œ
adminPermissionRepository.deleteByAdminId(id);
adminPermissionRepository.flush();
savePermissions(id, request.getPermissions());
์ด ์ฝ”๋“œ๋Š” AdminPermissionRepository๋ฅผ ์ง์ ‘ ์ฃผ์ž…๋ฐ›์•„์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ๊ด€๋ฆฌ์ž์˜ ๊ถŒํ•œ์„ ์ „๋ถ€ ์ง€์šฐ๊ธฐ ์œ„ํ•ด repository๊นŒ์ง€ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ๊ธฐ์กด ๊ถŒํ•œ์ด๋ž‘ ๋˜‘๊ฐ™์€ ์ˆ˜์ • ์š”์ฒญ์ด ๋“ค์–ด์™€๋„ ์ด ์ฝ”๋“œ๋Š” ๊ธฐ์กด ๊ฑธ ์น˜์šฐ๊ณ  ๋‹ค์‹œ ๋„ฃ๋Š”๋‹ค.  - ์ˆ˜์ •๋ฐฉํ–ฅ → ์ด์ œ ์ด ๋ถ€๋ถ„์„ ์ˆ˜์ •ํ•ด์•ผํ•œ๋‹ค. ํ…Œ์ด๋ธ” ์ค‘์‹ฌ ๋ฐฉ์‹์ด ์•„๋‹Œ ๊ฐ์ฒด ์ค‘์‹ฌ ๋ฐฉ์‹์œผ๋กœ ๋ฐ”๊ฟ”์•ผํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ถŒํ•œ์„ ๋ชจ๋‘ ์‚ญ์ œํ•˜์ง€ ์•Š๊ณ  Admin ์—”ํ‹ฐํ‹ฐ ์•ˆ์˜ adminPermission ์ปฌ๋ ‰์…˜์„ ๊ธฐ์ค€์œผ๋กœ ์ง์ ‘ ๋น„๊ตํ•˜์—ฌ ์ฒ˜๋ฆฌํ•ด์•ผํ•œ๋‹ค.

 

 

  • permissions๊ฐ€ null์ด ์•„๋‹Œ ๊ฒฝ์šฐ๋งŒ
if (request.getPermissions() != null) {
    assignPermissions(admin, request.getPermissions());
}
List.of("CUSTOMER_READ", "CUSTOMER_READ", " ", null)
permissons๊ฐ€ null์ด ์•„๋‹ ๋•Œ๋งŒ ๊ถŒํ•œ์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ๋‘๋ฒˆ์งธ ์ฝ”๋“œ์ฒ˜๋Ÿผ ๋“ค์–ด์˜ค๋ฉด ํ˜„์žฌ ์ฝ”๋“œ๋Š” null๋งŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์‚ฌ์‹ค null๋งŒ ์ฒ˜๋ฆฌํ•œ ์ด์œ ๋Š” ์ด ํ”„๋กœ์ ํŠธ๊ฐ€ ์‹ค์ œ ์šด์˜๋  ์„œ๋น„์Šค๋„ ์•„๋‹ ๋ฟ๋”๋Ÿฌ, ๊ถŒํ•œ์€ ์ฒดํฌ๋ฐ•์Šค๋กœ ํ‘œ์‹œํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ๊ฒƒ ๊ฐ™์•„์„œ ๊ทธ๋ ‡๊ฒŒ ์ž‘์„ฑํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฐ ๋ถ€๋ถ„๋„ ์ด์ค‘๋ณด์•ˆ์ฒ˜๋Ÿผ ๊ผผ๊ผผํ•˜๊ฒŒ ์ž‘์„ฑํ•˜๋Š” ๊ฒŒ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.  - ์ˆ˜์ •๋ฐฉํ–ฅ →  ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด์•ผํ•  ๊ฒƒ ๊ฐ™๋‹ค. null, ๊ณต๋ฐฑ, ์ค‘๋ณต ๊ถŒํ•œ ์ฝ”๋“œ๋ฅผ ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ์—์„œ ์ •๋ฆฌํ•œ ๋’ค ๋” ๊ผผ๊ผผํ•˜๊ฒŒ ๋กœ์ง์„ ์ž‘์„ฑํ•ด์•ผํ•  ๊ฒƒ ๊ฐ™๋‹ค.

 

 

 

 


 

 

 

 

3. ์ˆ˜์ • ํ›„ AdminService ์ฝ”๋“œ ๋ถ„์„

  • ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ replacePermission ์ž‘์„ฑ
["CUSTOMER_READ", "CUSTOMER_ADD"]
๊ด€๋ฆฌ์ž๊ฐ€ ๊ฐ€์ง„ ๊ถŒํ•œ ๋ชฉ๋ก์„ ํ™”๋ฉด์—์„œ ์ƒˆ๋กœ ๋„˜์–ด์˜จ permissionCodes ๋ชฉ๋ก๊ณผ ๋˜‘๊ฐ™์ด ๊ต์ฒดํ•˜๋Š” ์ฝ”๋“œ๋‹ค. ์œ„์™€ ๊ฐ™์ด ๋„˜์–ด์˜ค๋ฉด admin์˜ ๊ธฐ์กด ๊ถŒํ•œ ์ค‘ ์ด ๋ชฉ๋ก์— ์—†๋Š” ๊ฒƒ์€ ์‚ญ์ œํ•˜๊ณ , ์—†๋Š” ๊ถŒํ•œ์€ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค.

 

// 1.
 Set<String> requestedCodes = permissionCodes == null
                // 2.
                ? Set.of() 
                // 3.
                : permissionCodes.stream()
                // 4.
                .filter(Objects::nonNull)
                // 5.
                .map(String::trim)
                // 6.
                .filter(code -> !code.isBlank())
                // 7.
                .collect(Collectors.toCollection(LinkedHashSet::new));
1. ์š”์ฒญ์œผ๋กœ ๋“ค์–ด์˜จ ๊ถŒํ•œ ์ฝ”๋“œ๋“ค์„ Set์œผ๋กœ ์ •๋ฆฌํ•œ๋‹ค. Set์€ ์•Œ์•„์„œ ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๋Š” ํŠน์ง•์ด ์žˆ๊ณ  contains( )๋กœ ํฌํ•จ ์—ฌ๋ถ€๋ฅผ ๋น ๋ฅด๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 
2. permissionCodes๊ฐ€ null์ด๋ฉด ๋นˆ Set์„ ๋งŒ๋“ ๋‹ค. ๊ทธ๋‹ˆ๊นŒ ์š”์ฒญ ๊ถŒํ•œ์ด ์•„๋ฌด๊ฒƒ๋„ ์—†๋‹ค๊ณ  ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
3. permissionCodes๊ฐ€ null์ด ์•„๋‹ˆ๋ฉด Stream์œผ๋กœ ํ•˜๋‚˜์”ฉ ์ฒ˜๋ฆฌํ•œ๋‹ค.
4. null์ธ ๊ถŒํ•œ ์ฝ”๋“œ๋Š” ์ œ๊ฑฐํ•œ๋‹ค. ["CUSTOMER_READ", null, "CUSTOMER_ADD"]์œผ๋กœ ๋“ค์–ด์™”๋‹ค๋ฉด ์—ฌ๊ธฐ์„œ null์„ ์ œ๊ฑฐํ•œ๋‹ค.
5. ๊ฐ ๊ถŒํ•œ์˜ ์•ž๋’ค ๊ณต๋ฐฑ์„ ์ œ๊ฑฐํ•œ๋‹ค. " CUSTOMER_READ " -> "CUSTOMER_READ"
6. ๋นˆ ๋ฌธ์ž์—ด์„ ์ œ๊ฑฐํ•œ๋‹ค. ["CUSTOMER_READ","  ", "CUSTOMER_ADD"]์œผ๋กœ ๋“ค์–ด์™”๋‹ค๋ฉด ์—ฌ๊ธฐ์„œ "  "์„ ์ œ๊ฑฐํ•œ๋‹ค.
7. ์ตœ์ข…์ ์œผ๋กœ LinkedHashSet์œผ๋กœ ๋ชจ์€๋‹ค. ๊ทธ ์ด์œ ๋Š” ์ค‘๋ณต ์ œ๊ฑฐ๋ฅผ ํ•˜๋ฉด์„œ ์ž…๋ ฅ๋œ ์ˆœ์„œ๋ฅผ ์œ ์ง€์‹œํ‚ค๊ธฐ ์œ„ํ•จ์ด๋‹ค.

 

 

Q. Set์ด contains( )๋กœ ํฌํ•จ ์—ฌ๋ถ€๋ฅผ ๋น ๋ฅด๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š”?

A. ํ•ด์‹œ ํ…Œ์ด๋ธ” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ArrayList๋Š” ํŠน์ • ๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ๋ชจ๋‘ ํ™•์ธํ•œ๋‹ค. ๋งŒ์•ฝ N๊ฐœ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์„ ๋•Œ, ์ตœ์•…์˜ ๊ฒฝ์šฐ N๋ฒˆ์„ ๋‹ค ์ฐพ์•„๋ด์•ผ ํ•˜๋ฏ€๋กœ O(N)์ด ๊ฑธ๋ฆฌ๊ฒŒ ๋œ๋‹ค. HashSet์€ ์ฃผ์†Œ๋ฅผ ๊ณ„์‚ฐํ•ด์„œ ํ•œ ๋ฒˆ์— ์ฐพ์•„๋‚ธ๋‹ค. HashSet์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋•Œ ๋‚ด๋ถ€์ ์œผ๋กœ ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋  ์ธ๋ฑ์Šค๋ฅผ ๋ฏธ๋ฆฌ ๊ณ„์‚ฐํ•œ๋‹ค. 

์˜ˆ๋ฅผ ๋“ค์–ด, ROLE_ADMIN ์ด๋ผ๋Š” ๊ถŒํ•œ ์ฝ”๋“œ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ๋‚ด๋ถ€๋Š” "ROLE_ADMIN".hashCode( )๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ณ ์œ ํ•œ ์ˆซ์ž(์˜ˆ: 12345)๋ฅผ ๋ฝ‘์•„๋‚ด ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด ์ˆซ์ž๋ฅผ ํ•ด์‹œ ํ…Œ์ด๋ธ”์˜ ํฌ๊ธฐ๋กœ ๋‚˜๋ˆ„์–ด ์ธ๋ฑ์Šค๋ฅผ ์•Œ์•„๋‚ธ๋‹ค. ๊ทธ๋ž˜์„œ ์ €์žฅํ•  ๋•Œ 5๋ฒˆ์ด๋ฉด, 5๋ฒˆ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ง‘์–ด๋„ฃ๋Š”๋‹ค. ํ˜ธ์ถœํ•  ๋•Œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค. contains("ROLE_ADMIN")์„ ํ˜ธ์ถœํ•˜๋ฉด, ๋˜‘๊ฐ™์ด ๊ณ„์‚ฐํ•ด์„œ ๋ฐ”๋กœ 5๋ฒˆ์œผ๋กœ ์งํ–‰ํ•œ ๋’ค, ๊ฑฐ๊ธฐ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

์ด๋Ÿฐ ๊ณ„์‚ฐ์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์—„์ฒญ๋‚˜๊ฒŒ ๋งŽ์•„๋„ ๋ฐฉ ๋ฒˆํ˜ธ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋‹จ ํ•œ ๋ฒˆ์˜ ๊ณผ์ •๋งŒ ๊ฑฐ์น˜๋ฏ€๋กœ ํ‰๊ท ์ ์œผ๋กœ O(1)์ด ๊ฑธ๋ฆฐ๋‹ค.

 

 

        if (requestedCodes.isEmpty()) {
            admin.getAdminPermissions().clear();
            return;
        }
์ •๋ฆฌ๋œ ์š”์ฒญ ๊ถŒํ•œ ์ฝ”๋“œ๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋Š” ๊ฒฝ์šฐ admin์ด ๊ฐ€์ง€๊ณ  ์žˆ๋˜ ๊ถŒํ•œ ๋ชฉ๋ก์„ ์ „๋ถ€ ๋น„์šด๋‹ค. ์ด์ œ ์ด ๊ด€๋ฆฌ์ž๋Š” ์•„๋ฌด ๊ถŒํ•œ๋„ ๊ฐ€์ง€์ง€ ์•Š๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ๋”์ด์ƒ ์ฒ˜๋ฆฌํ•  ๊ถŒํ™˜์ด ์—†์œผ๋‹ˆ return์œผ๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ์ข…๋ฃŒํ•œ๋‹ค.

 

List<Permission> permissions = permissionRepository.findByCodeIn(List.copyOf(requestedCodes));
requestCodes์— ์žˆ๋Š” ๊ถŒํ•œ ์ฝ”๋“œ๋“ค์ด ์‹ค์ œ permission ํ…Œ์ด๋ธ”์— ์กด์žฌํ•˜๋Š”์ง€ ์กฐํšŒํ•œ๋‹ค. findByCodeIn์ด DB์—์„œ ํ•ด๋‹น code๋ฅผ ๊ฐ€์ง„ Permission๋“ค์„ ์ฐพ์•„์˜จ๋‹ค.

List.copyOf๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์„ ๋งž์ถ”๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋๋‹ค. CodeIn์€ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด SQL์˜ IN์ ˆ์„ ์ƒ์„ฑํ•œ๋‹ค.(์˜ˆ์‹œ: WHERE code IN (?, ?, ...)) JPA์—์„œ IN ์ฟผ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•  ๋•Œ, ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์„ List<String>์œผ๋กœ ์„ ์–ธํ•ด ๋‘๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ํ•˜์ง€๋งŒ ํ˜„์žฌ requestedCode์˜ ํƒ€์ž…์€ Set<String>์ด๋‹ค. ๊ทธ๋ž˜์„œ Set ํƒ€์ž…์„ List ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด List.copyOf๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

์‚ฌ์‹ค new ArrayList<>(requestedCodes)๋กœ ์จ๋„๋œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ List.copyOf๋ฅผ ์‚ฌ์šฉํ•œ ์ด์œ ๋Š” ์ˆ˜์ • ๋ถˆ๊ฐ€๋Šฅํ•œ List๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•จ์ด๋‹ค. ์•„๋‹ˆ๋ฉด Collection<String>์œผ๋กœ ๋ฐ”๊ฟ”๋„ ๋œ๋‹ค.

 

Set<String> foundCodes = permissions.stream()
                // Permission ๊ฐ์ฒด์—์„œ code๋งŒ ๊บผ๋‚ธ๋‹ค.
                // Permission(code="CUSTOMER_READ") -> "CUSTOMER_READ"
                .map(Permission::getCode)
                // ๊บผ๋‚ธ code ๊ฐ’๋“ค์„ Set์œผ๋กœ ๋ชจ์€๋‹ค.
                .collect(Collectors.toSet());
DB์—์„œ ์‹ค์ œ๋กœ ์ฐพ์€ ๊ถŒํ•œ ์ฝ”๋“œ๋ฅผ Set์œผ๋กœ ๋ชจ์œผ๋Š” ์ฝ”๋“œ์ด๋‹ค. 

 

   List<String> missingCodes = requestedCodes.stream()
                // requestCodes ์ค‘ foundCodes์— ์—†๋Š” code๋งŒ ๋‚จ๊ธด๋‹ค.
                .filter(code -> !foundCodes.contains(code))
                // ๊ทธ ๊ฒฐ๊ณผ๋ฅผ List๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
                .toList();
์š”์ฒญ์œผ๋กœ ๋“ค์–ด์˜จ ๊ถŒํ•œ ์ฝ”๋“œ ์ค‘์—์„œ DB์—์„œ ์ฐพ์ง€ ๋ชปํ•œ ๊ถŒํ•œ ์ฝ”๋“œ๋“ค์„ missingCodes์— ๋‹ด๋Š”๋‹ค.

 

    if (!missingCodes.isEmpty()) {
            throw new IllegalArgumentException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ถŒํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค: " + String.join(", ", missingCodes));
        }
DB์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ถŒํ•œ ์ฝ”๋“œ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ๋‹ค๋ฉด ์ž˜๋ชป๋œ ๊ถŒํ•œ ์ฝ”๋“œ๊ฐ€ ์š”์ฒญ๋˜์—ˆ์œผ๋ฏ€๋กœ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

 

admin.getAdminPermissions().removeIf(adminPermission -> {
            // 1.
            Permission permission = adminPermission.getPermission();
            // 2.
            return permission == null
                    // 3.
                    || permission.getCode() == null
                    // 4.
                    || !requestedCodes.contains(permission.getCode());
        });
ํ˜„์žฌ admin์ด ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ถŒํ•œ ์ค‘์—์„œ ์š”์ฒญ ๊ถŒํ•œ ๋ชฉ๋ก์— ์—†๋Š” ๊ถŒํ•œ์„ ์ œ๊ฑฐํ•œ๋‹ค. removeIf๊ฐ€ ์ปฌ๋ ‰์…˜ ์•ˆ์˜ ์š”์†Œ๋ฅผ ํ•˜๋‚˜์”ฉ ๋ณด๋ฉด์„œ, ์กฐ๊ฑด์ด true์ธ ์š”์†Œ๋ฅผ ์‚ญ์ œํ•œ๋‹ค. ์•„๋ž˜ ๋” ๊ตฌ์ฒด์ ์œผ๋กœ ์„ค๋ช…์„ ์ ์–ด๋ณด๊ฒ ๋‹ค.

 

// ๊ตฌ์กฐ๊ฐ€ ์ด๋ ‡๊ฒŒ ์žˆ์œผ๋ฉด removeIf๊ฐ€ AdminPermission์„ ํ•˜๋‚˜์”ฉ ๊บผ๋‚ด์„œ ๊ฒ€์‚ฌํ•œ๋‹ค.
// removeIf๋Š” ์ง์ ‘ ๋ฐ˜๋ณตํ•˜๋ฉด์„œ ์‚ญ์ œ๊นŒ์ง€ ํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

Admin
 โ””โ”€โ”€ adminPermissions
      โ”œโ”€โ”€ AdminPermission(admin=admin, permission=CUSTOMER_READ)
      โ”œโ”€โ”€ AdminPermission(admin=admin, permission=CUSTOMER_ADD)
      โ””โ”€โ”€ AdminPermission(admin=admin, permission=CUSTOMER_DELETE)

 

// Permission permission = adminPermission.getPermission();
// AdminPermission์€ admin๊ณผ permission์„ ์—ฐ๊ฒฐํ•˜๋Š” ์ค‘๊ฐ„ ๊ฐ์ฒด์ธ๋ฐ
// ์—ฌ๊ธฐ์„œ ๊ทธ ์•ˆ์— ๋“ค์–ด์žˆ๋Š” ์‹ค์ œ ๊ถŒํ•œ Permission์„ ๊บผ๋‚ธ๋‹ค.

AdminPermission
 โ”œโ”€โ”€ admin = adminA
 โ””โ”€โ”€ permission = CUSTOMER_READ
 
 // adminPermission.getPermission()์„ ํ•˜๋ฉด CUSTOMER_READ์— ํ•ด๋‹นํ•˜๋Š” Permission ๊ฐ์ฒด๊ฐ€ ๋‚˜์˜จ๋‹ค.

 

// ์—ฌ๊ธฐ์„œ true๊ฐ€ ๋‚˜์˜ค๋ฉด ์‚ญ์ œ๋œ๋‹ค.

// ์ •์ƒ์ ์ธ ๋ฐ์ดํ„ฐ๋Š” AdminPermission(admin=admin, permission=CUSTOMER_READ) ์ด๋Ÿฐ ํ˜•ํƒœ์ธ๋ฐ
// AdminPermission(admin=admin, permission=null) ์ด๋Ÿฐ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ค๋ฉด ์‚ญ์ œํ•œ๋‹ค.
return permission == null
    
        // ์ •์ƒ์ ์ธ ๋ฐ์ดํ„ฐ๋Š” Permission(code="CUSTOMER_READ") ์ด๋Ÿฐ ํ˜•ํƒœ์ธ๋ฐ
        // Permission(code=null) ์ด๋Ÿฐ ์ƒํƒœ๋ฉด ์‚ญ์ œํ•œ๋‹ค.
        || permission.getCode() == null
        
        // ์‹ค์ œ๋กœ ๊ถŒํ•œ์ด ๊ต์ฒด๋˜๋Š” ์ฝ”๋“œ์ด๋‹ค.
        // ํ˜„์žฌ admin์ด ๊ฐ€์ง„ ๊ถŒํ•œ ์ฝ”๋“œ๊ฐ€, ์ƒˆ๋กœ ์š”์ฒญ๋œ ๊ถŒํ•œ ๋ชฉ๋ก์— ์—†์œผ๋ฉด ์‚ญ์ œํ•œ๋‹ค.
        // ๊ธฐ์กด ๊ถŒํ•œ: CUSTOMER_READ, CUSTOMER_ADD, CUSTOMER_DELETE
        // ์ˆ˜์ • ์š”์ฒญ: requestedCodes: CUSTOMER_READ, CUSTOMER_ADD
        // ํ•˜๋‚˜์”ฉ ๊ฒ€์‚ฌํ•˜๋ฉด CUSTOMER_READ, CUSTOMER_ADD๋Š” ture๊ฐ€ ๋˜๋Š”๋ฐ !๊ฐ€ ๋ถ™์–ด์„œ False๊ฐ€ ๋œ๋‹ค.
        // ๊ทธ๋ž˜์„œ ์‚ญ์ œ๊ฐ€ ์•ˆ๋˜๊ณ  CUSTOMER_DELETE๋Š” FAlSE๋กœ !๊ฐ€ ๋ถ™์–ด true๊ฐ€ ๋˜์–ด ์‚ญ์ œ๋œ๋‹ค.
        || !requestedCodes.contains(permission.getCode());

 

        Set<String> existingCodes = admin.getAdminPermissions().stream()
                // 1.
                .map(AdminPermission::getPermission)
                // 2.
                .filter(Objects::nonNull)
                // 3.
                .map(Permission::getCode)
                // 4.
                .filter(Objects::nonNull)
                // 5.
                .collect(Collectors.toSet());
removeIf ์ดํ›„์—๋„ admin์—๊ฒŒ ๋‚จ์•„ ์žˆ๋Š” ๊ถŒํ•œ ์ฝ”๋“œ๋“ค์„ ๋ชจ์€๋‹ค. ๋‚˜์ค‘์— ์ค‘๋ณต ์ถ”๊ฐ€๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค. 

1. AdminPermission์—์„œ Permission ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ธ๋‹ค.
2. Permission์ด null์ธ ๊ฒฝ์šฐ ์ œ์™ธํ•œ๋‹ค.
3. Permission ๊ฐ์ฒด์—์„œ code๋งŒ ๊บผ๋‚ธ๋‹ค.
4. code๊ฐ€ null์ธ ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•œ๋‹ค.
5. ์ตœ์ข…์ ์œผ๋กœ ํ˜„์žฌ admin์ด ์ด๋ฏธ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ถŒํ•œ ์ฝ”๋“œ๋“ค์„ Set์œผ๋กœ ๋ชจ์€๋‹ค.

 

       for (Permission permission : permissions) {
       
            // 1.
            if (existingCodes.contains(permission.getCode())) {
                continue;
            }

            // 2.
            AdminPermission adminPermission = new AdminPermission();
            // 3.
            adminPermission.setAdmin(admin);
            // 4.
            adminPermission.setPermission(permission);
            // 5.
            admin.getAdminPermissions().add(adminPermission);
        }
    }
removeIf๋กœ ๊ธฐ์กด ๊ถŒํ•œ์€ ์‚ญ์ œํ–ˆ๋‹ค. ์ด์ œ ์ƒˆ๋กœ์šด ๊ถŒํ•œ์„ ์ง‘์–ด๋„ฃ์–ด์•ผํ•œ๋‹ค. DB์—์„œ ์กฐํšŒํ•œ ์‹ค์ œ Permission ๋ชฉ๋ก์„ ํ•˜๋‚˜์”ฉ ๋ฐ˜๋ณตํ•œ๋‹ค. 

1. ํ˜„์žฌ admin์ด ์ด ๊ถŒํ•œ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฏ€๋กœ ๋‹ค์Œ permission์œผ๋กœ ๋„˜์–ด๊ฐ„๋‹ค.
2. admin์—๊ฒŒ ์—†๋Š” ๊ถŒํ•œ์ด๋ผ๋ฉด ์ƒˆ AdminPermission ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ ๋‹ค.
3. ์ƒˆ AdminPermission์— ํ˜„์žฌ admin์„ ์—ฐ๊ฒฐํ•œ๋‹ค. 
4. ์ƒˆ AdminPermission์— ์ถ”๊ฐ€ํ•  Pemission์„ ์—ฐ๊ฒฐํ•œ๋‹ค. 
5. admin์˜ ๊ถŒํ•œ ๋ชฉ๋ก์— ์ƒˆ AdminPemission์„ ์ถ”๊ฐ€ํ•œ๋‹ค. 

์ฒ˜์Œ ์ฝ”๋“œ๋Š” ์ˆ˜์ • ์ž์ฒด๊ฐ€ ์š”์ฒญ๋˜๋ฉด ๊ด€๋ฆฌ์ž์˜ ๊ถŒํ•œ์„ ๋ชจ๋‘ ์‚ญ์ œํ•˜๊ณ  ๋‹ค์‹œ ์ €์žฅํ–ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด์ œ๋Š” ์ฝ”๋“œ๋ฅผ ๋ฐ”๊ฟ”์„œ ๋ฐ”๋€ ๊ถŒํ•œ์„ ํ™•์ธํ•˜๊ณ  ๊ทธ ๊ถŒํ•œ๋งŒ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ–ˆ๋‹ค. AdminPermissionRepository๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ–ˆ๋˜ ์ด์ „ ์ฝ”๋“œ์™€ ๋‹ฌ๋ฆฌ ์˜์กด์„ฑ์ด ํ™• ์ค„์–ด๋“  ์ฝ”๋“œ์ด๋‹ค.