HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
Content-Length: 143
[ {
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411842",
"siteCd" : "KAC",
"groupCdNm" : "신규그룹001",
"rm" : "비고....",
@@ -626,7 +640,7 @@ Content-Length: 143
[HTTP REQUEST INFO]
-GET /v1/com/code/code?groupCd=NEW_GROUP_1707924397&langDivCd=ko_KR HTTP/1.1
+GET /v1/com/code/code?groupCd=NEW_GROUP_1708411842&langDivCd=ko_KR HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept: application/json
Host: localhost:8080
@@ -664,11 +678,20 @@ Host: localhost:8080
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
Content-Length: 190
[ {
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411842",
"cdId" : "NEW_CODE001",
"cdNm" : "신규코드001",
"upperCd" : null,
@@ -759,11 +782,20 @@ Host: localhost:8080
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
Content-Length: 143
[ {
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411843",
"siteCd" : "KAC",
"groupCdNm" : "신규그룹001",
"rm" : "비고....",
@@ -835,7 +867,7 @@ Content-Length: 118
Host: localhost:8080
{
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411843",
"siteCd" : "KAC",
"groupCdNm" : "신규그룹001",
"rm" : "비고...."
@@ -890,18 +922,27 @@ Host: localhost:8080
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
-Content-Length: 276
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
+Content-Length: 275
{
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411843",
"siteCd" : "KAC",
"groupCdNm" : "신규그룹001",
"rm" : "비고....",
"createUserId" : "CREATE_USER",
- "createDt" : "2024-02-15T00:26:37.902778",
+ "createDt" : "2024-02-20T15:50:43.127816",
"updateUserId" : "CREATE_USER",
- "updateDt" : "2024-02-15T00:26:37.902782"
+ "updateDt" : "2024-02-20T15:50:43.12782"
}
@@ -987,7 +1028,7 @@ Content-Length: 132
Host: localhost:8080
{
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411843",
"cdId" : "NEW_CODE001",
"sortOrdr" : 0,
"addInfoValue" : "추가!!",
@@ -1049,20 +1090,29 @@ Host: localhost:8080
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
Content-Length: 310
{
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411843",
"cdId" : "NEW_CODE001",
"upperCd" : null,
"sortOrdr" : 0,
"addInfoValue" : "추가!!",
"useYn" : "Y",
"createUserId" : "CREATE_USER",
- "createDt" : "2024-02-15T00:26:37.887931",
+ "createDt" : "2024-02-20T15:50:43.107273",
"updateUserId" : "CREATE_USER",
- "updateDt" : "2024-02-15T00:26:37.887936"
+ "updateDt" : "2024-02-20T15:50:43.107277"
}
@@ -1160,7 +1210,7 @@ Content-Length: 144
Host: localhost:8080
{
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411842",
"cdId" : "NEW_CODE001",
"langDivCd" : "ko_KR",
"cdNm" : "신규코드001",
@@ -1222,19 +1272,28 @@ Host: localhost:8080
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
Content-Length: 302
{
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411842",
"cdId" : "NEW_CODE001",
"langDivCd" : "ko_KR",
"cdNm" : "신규코드001",
"rm" : "비고....",
"createUserId" : "CREATE_USER",
- "createDt" : "2024-02-15T00:26:37.826757",
+ "createDt" : "2024-02-20T15:50:43.009038",
"updateUserId" : "CREATE_USER",
- "updateDt" : "2024-02-15T00:26:37.826761"
+ "updateDt" : "2024-02-20T15:50:43.009043"
}
@@ -1326,7 +1385,7 @@ Content-Length: 118
Host: localhost:8080
{
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411843",
"siteCd" : "KAC",
"groupCdNm" : "신규그룹001",
"rm" : "비고...."
@@ -1381,18 +1440,27 @@ Host: localhost:8080
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
-Content-Length: 275
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
+Content-Length: 276
{
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411843",
"siteCd" : "KAC",
"groupCdNm" : "신규그룹001",
"rm" : "비고....",
"createUserId" : "CREATE_USER",
- "createDt" : "2024-02-15T00:26:37.84228",
+ "createDt" : "2024-02-20T15:50:43.031642",
"updateUserId" : "UPDATE_USER",
- "updateDt" : "2024-02-15T00:26:37.844978"
+ "updateDt" : "2024-02-20T15:50:43.035007"
}
@@ -1478,7 +1546,7 @@ Content-Length: 132
Host: localhost:8080
{
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411842",
"cdId" : "NEW_CODE001",
"sortOrdr" : 0,
"addInfoValue" : "수정!!",
@@ -1540,20 +1608,29 @@ Host: localhost:8080
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
Content-Length: 310
{
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411842",
"cdId" : "NEW_CODE001",
"upperCd" : null,
"sortOrdr" : 0,
"addInfoValue" : "수정!!",
"useYn" : "Y",
"createUserId" : "CREATE_USER",
- "createDt" : "2024-02-15T00:26:37.757743",
+ "createDt" : "2024-02-20T15:50:42.915944",
"updateUserId" : "UPDATE_USER",
- "updateDt" : "2024-02-15T00:26:37.770459"
+ "updateDt" : "2024-02-20T15:50:42.938404"
}
@@ -1651,7 +1728,7 @@ Content-Length: 143
Host: localhost:8080
{
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411842",
"cdId" : "NEW_CODE001",
"langDivCd" : "ko_KR",
"cdNm" : "신규코드001",
@@ -1713,19 +1790,28 @@ Host: localhost:8080
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
Content-Length: 301
{
- "groupCd" : "NEW_GROUP_1707924397",
+ "groupCd" : "NEW_GROUP_1708411842",
"cdId" : "NEW_CODE001",
"langDivCd" : "ko_KR",
"cdNm" : "신규코드001",
"rm" : "수정...",
"createUserId" : "CREATE_USER",
- "createDt" : "2024-02-15T00:26:37.798977",
+ "createDt" : "2024-02-20T15:50:42.973527",
"updateUserId" : "UPDATE_USER",
- "updateDt" : "2024-02-15T00:26:37.803818"
+ "updateDt" : "2024-02-20T15:50:42.978852"
}
@@ -1842,7 +1928,16 @@ Host: localhost:8080
[HTTP RESPONSE INFO]
-HTTP/1.1 200 OK
+HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
@@ -1891,7 +1986,16 @@ Host: localhost:8080
[HTTP RESPONSE INFO]
-HTTP/1.1 200 OK
+HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
@@ -1945,8 +2049,181 @@ Host: localhost:8080
[HTTP RESPONSE INFO]
-HTTP/1.1 200 OK
+HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
+
+
+
+
+
+
+
+
+User-Account API
+
+
+[User 회원가입]
+
+[HTTP REQUEST INFO]
+
+
+POST /v1/user/account/register HTTP/1.1
+Content-Type: application/json;charset=UTF-8
+Accept: application/json
+Content-Length: 337
+Host: localhost:8080
+
+{
+ "cstrmDivCd" : "MEMBER",
+ "cstrmStatusCd" : "ACTIVE",
+ "userId" : "TEST_1708411843171",
+ "authId" : "USER",
+ "siteCode" : "DRONE",
+ "userPswd" : "palnet!234",
+ "joinCrtfyCd" : "HP_CRTFD",
+ "memberName" : "이경도",
+ "brthdyDate" : "1999-09-07",
+ "email" : "lkd9125@naver.com",
+ "hpno" : "01083703435",
+ "clncd" : "+82"
+}
+
+
+
+
+
+
+
+
+
+
+
+파라미터
+타입
+설명
+필수
+
+
+
+
+cstrmDivCd
+String
+회원타입 코드
+true
+
+
+cstrmStatusCd
+String
+회원 활성화 코드
+true
+
+
+userId
+String
+아이디
+true
+
+
+authId
+String
+권한 값
+true
+
+
+siteCode
+String
+사이트 코드
+true
+
+
+userPswd
+String
+암호
+true
+
+
+joinCrtfyCd
+String
+가입인증 분류 코드
+true
+
+
+memberName
+String
+이름
+true
+
+
+brthdyDate
+String
+생년월일
+true
+
+
+email
+String
+이메일
+true
+
+
+hpno
+String
+휴대폰 번호
+true
+
+
+clncd
+String
+휴대폰 국가번호
+true
+
+
+terms
+Array
+동의 약관 리스트
+false
+
+
+terms[].termsSno
+Number
+약관 식별번호
+true
+
+
+terms[].agreeYn
+String
+약관 동의여부
+true
+
+
+
+
+
+[HTTP RESPONSE INFO]
+
+
+HTTP/1.1 201 Created
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+X-Content-Type-Options: nosniff
+X-XSS-Protection: 0
+Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+Pragma: no-cache
+Expires: 0
+X-Frame-Options: DENY
+
+
+Unresolved directive in index.adoc - include::./build/generated-snippets/user/account/register/response-fields.adoc[]
@@ -1957,7 +2234,7 @@ Host: localhost:8080
diff --git a/app/kac-app/src/test/java/kr/co/palnet/kac/BaseTest.java b/app/kac-app/src/test/java/kr/co/palnet/kac/BaseTest.java
index 054591a..b96ab51 100644
--- a/app/kac-app/src/test/java/kr/co/palnet/kac/BaseTest.java
+++ b/app/kac-app/src/test/java/kr/co/palnet/kac/BaseTest.java
@@ -1,18 +1,33 @@
package kr.co.palnet.kac;
import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.servlet.ServletException;
+import kr.co.palnet.kac.api.v1.user.account.model.detail.SearchUserRS;
+import kr.co.palnet.kac.api.v1.user.account.model.register.FormRegisterRQ;
+import kr.co.palnet.kac.api.v1.user.account.service.UserAccountService;
import kr.co.palnet.kac.app.KacAppApplication;
+import kr.co.palnet.kac.config.security.model.BaseUserDetails;
+import kr.co.palnet.kac.config.security.service.BaseUserDetailsService;
+import kr.co.palnet.kac.config.security.util.JwtUtil;
+import kr.co.palnet.kac.util.ObjectMapperUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.mock.web.MockFilterConfig;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
+import org.springframework.security.config.BeanIds;
+import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
+import org.springframework.web.filter.DelegatingFilterProxy;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.modifyUris;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
@@ -24,12 +39,24 @@ public class BaseTest {
@Autowired
protected WebApplicationContext webApplicationContext;
+ @Autowired
+ protected UserAccountService userAccountService;
+
+ @Autowired
+ protected BaseUserDetailsService baseUserDetailsService;
+
public MockMvc mockMvc;
+ protected final String CREATE_PASSWORD = "palnet!234";
+
@BeforeEach
- public void setUpAll(RestDocumentationContextProvider restDocumentationContextProvider){
+ public void setUpAll(RestDocumentationContextProvider restDocumentationContextProvider) throws ServletException {
+ DelegatingFilterProxy delegateProxyFilter = new DelegatingFilterProxy();
+ delegateProxyFilter.init(new MockFilterConfig(webApplicationContext.getServletContext(), BeanIds.SPRING_SECURITY_FILTER_CHAIN));
+
+
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) // @Autowired로 빈주입 받은 context
- .addFilter(new CharacterEncodingFilter("UTF-8", true)) // UTF-8 인코딩 필터
+ .addFilters(new CharacterEncodingFilter("UTF-8", true), delegateProxyFilter) // UTF-8 인코딩 필터, SecurityFilter
.apply(
MockMvcRestDocumentation.documentationConfiguration(restDocumentationContextProvider)
.operationPreprocessors()
@@ -42,4 +69,51 @@ public class BaseTest {
)
.build();
}
+
+ protected String getUserToken(){
+
+ String username = "TEST_" + System.currentTimeMillis();
+
+ String jsonRQ = """
+ {
+ "cstrmDivCd" : "MEMBER",
+ "cstrmStatusCd" : "ACTIVE",
+ "userId" : "%s",
+ "authId" : "USER",
+ "siteCode" : "DRONE",
+ "userPswd" : "%s",
+ "joinCrtfyCd" : "HP_CRTFD",
+ "memberName" : "이경도",
+ "brthdyDate" : "1999-09-07",
+ "email" : "lkd9125@naver.com",
+ "hpno" : "01083703435",
+ "clncd" : "+82"
+ }
+ """.formatted(username, this.CREATE_PASSWORD);
+
+ FormRegisterRQ rq = new FormRegisterRQ();
+ rq.setCstrmDivCd("MEMBER");
+ rq.setCstrmStatusCd("ACTIVE");
+ rq.setUserId(username);
+ rq.setAuthId("USER");
+ rq.setSiteCode("DRONE");
+ rq.setUserPswd("palnet!234");
+ rq.setJoinCrtfyCd("HP_CRTFD");
+ rq.setMemberName("이경도");
+ rq.setBrthdyDate(LocalDate.of(1999, 9, 7));
+ rq.setEmail("lkd9125@naver.com");
+ rq.setHpno("01083703435");
+ rq.setClncd("+82");
+
+ try{
+ userAccountService.createUser(rq);
+ } catch (Exception e){
+ e.printStackTrace();
+ }
+
+ BaseUserDetails userDetails = (BaseUserDetails) baseUserDetailsService.loadUserByUsername(username);
+
+ return JwtUtil.makeAuthToken(userDetails);
+ }
+
}
diff --git a/app/kac-app/src/test/java/kr/co/palnet/kac/user/account/UserAccountControllerTest.java b/app/kac-app/src/test/java/kr/co/palnet/kac/user/account/UserAccountControllerTest.java
new file mode 100644
index 0000000..e5f72f1
--- /dev/null
+++ b/app/kac-app/src/test/java/kr/co/palnet/kac/user/account/UserAccountControllerTest.java
@@ -0,0 +1,228 @@
+package kr.co.palnet.kac.user.account;
+
+
+import kr.co.palnet.kac.BaseTest;
+import kr.co.palnet.kac.api.v1.user.account.service.UserAccountService;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.restdocs.headers.HeaderDocumentation;
+import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders;
+import org.springframework.restdocs.payload.JsonFieldType;
+import org.springframework.transaction.annotation.Transactional;
+
+import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
+import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
+import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
+import static org.springframework.restdocs.payload.PayloadDocumentation.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+public class UserAccountControllerTest extends BaseTest {
+
+ @Autowired
+ private UserAccountService userAccountService;
+
+ private final String BASE_URL = "/v1/user/account";
+
+ private final String GRANT_TYPE = "Bearer";
+
+ @DisplayName("회원정보 변경")
+ @Test
+ @Transactional
+ public void updateUser() throws Exception{
+ String jsonRQ = """
+ {
+ "email" : "lkd9125@naver.com",
+ "hpno" : "01083703435"
+ }
+ """;
+
+ String token = this.getUserToken();
+
+ this.mockMvc.perform(
+ put(this.BASE_URL + "/update")
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .content(jsonRQ)
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .header("Authorization", GRANT_TYPE + " " + token)
+ )
+ .andDo(print())
+ .andDo(
+ document(
+ "user/account/update",
+ preprocessResponse(prettyPrint()),
+ HeaderDocumentation.requestHeaders(
+ HeaderDocumentation.headerWithName("Authorization").description("Access토큰 [로그인 발급]")
+ ),
+ requestFields(
+ fieldWithPath("email").type(JsonFieldType.STRING).description("바꿀 이메일").optional(),
+ fieldWithPath("hpno").type(JsonFieldType.STRING).description("바꿀 전화번호").optional()
+ )
+ )
+ )
+ .andExpect(status().isOk());
+ }
+
+ @DisplayName("암호 변경")
+ @Test
+ @Transactional
+ public void updatePassword() throws Exception{
+
+ String jsonRQ = """
+ {
+ "userPswd" : "%s",
+ "newPswd" : "palnet!234",
+ "newPswdConfirm" : "palnet!234"
+ }
+ """.formatted(this.CREATE_PASSWORD);
+
+ String token = this.getUserToken();
+
+ this.mockMvc.perform(
+ put(this.BASE_URL + "/update/pswd")
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .content(jsonRQ)
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .header("Authorization", GRANT_TYPE + " " + token)
+ )
+ .andDo(print())
+ .andDo(
+ document(
+ "user/account/update/pswd",
+ preprocessResponse(prettyPrint()),
+ HeaderDocumentation.requestHeaders(
+ HeaderDocumentation.headerWithName("Authorization").description("Access토큰 [로그인 발급]")
+ ),
+ requestFields(
+ fieldWithPath("userPswd").type(JsonFieldType.STRING).description("현재 암호").optional(),
+ fieldWithPath("newPswd").type(JsonFieldType.STRING).description("바뀔 암호"),
+ fieldWithPath("newPswdConfirm").type(JsonFieldType.STRING).description("바뀔 암호 확인")
+ )
+ )
+ )
+ .andExpect(status().isOk());
+ }
+
+ @DisplayName("회원정보 조회")
+ @Test
+ @Transactional
+ public void getUserInfo() throws Exception{
+ String token = this.getUserToken();
+
+ this.mockMvc.perform(
+ get(this.BASE_URL + "/profile")
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .header("Authorization", GRANT_TYPE + " " + token)
+ )
+ .andDo(print())
+ .andDo(
+ document(
+ "user/account/profile", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
+ preprocessResponse(prettyPrint()),
+ HeaderDocumentation.requestHeaders(
+ HeaderDocumentation.headerWithName("Authorization").description("Access토큰 [로그인 발급]")
+ ),
+ responseFields(
+ fieldWithPath("memberName").type(JsonFieldType.STRING).description("회원 이름"),
+ fieldWithPath("brthdyDate").type(JsonFieldType.STRING).description("생년월일"),
+ fieldWithPath("cntryCd").type(JsonFieldType.STRING).description("국적 구분코드"),
+ fieldWithPath("email").type(JsonFieldType.STRING).description("이메일"),
+ fieldWithPath("hpno").type(JsonFieldType.STRING).description("휴대폰 번호"),
+ fieldWithPath("userId").type(JsonFieldType.STRING).description("아이디"),
+ fieldWithPath("updateDt").type(JsonFieldType.STRING).description("수정일시"),
+ fieldWithPath("updateuserId").type(JsonFieldType.STRING).description("수정자 아이디"),
+ fieldWithPath("cptAuthCode").type(JsonFieldType.STRING).description("각 항청 구분코드")
+ )
+ )
+ )
+ .andExpect(status().isOk());
+ }
+
+ @DisplayName("회원탈퇴")
+ @Test
+ @Transactional
+ public void deleteUser() throws Exception{
+ String token = this.getUserToken();
+
+ this.mockMvc.perform(
+ RestDocumentationRequestBuilders.delete(this.BASE_URL + "/delete")
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ .header("Authorization", GRANT_TYPE + " " + token)
+ )
+ .andDo(print())
+ .andDo(
+ document(
+ "user/account/delete", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
+ preprocessResponse(prettyPrint()),
+ HeaderDocumentation.requestHeaders(
+ HeaderDocumentation.headerWithName("Authorization").description("Access토큰 [로그인 발급]")
+ )
+ )
+ )
+ .andExpect(status().isOk());
+ }
+
+ @DisplayName("회원가입")
+ @Test
+ @Transactional
+ public void register() throws Exception{
+
+ String username = "TEST_" + System.currentTimeMillis();
+
+ String jsonRQ = """
+ {
+ "cstrmDivCd" : "MEMBER",
+ "cstrmStatusCd" : "ACTIVE",
+ "userId" : "%s",
+ "authId" : "USER",
+ "siteCode" : "DRONE",
+ "userPswd" : "palnet!234",
+ "joinCrtfyCd" : "HP_CRTFD",
+ "memberName" : "이경도",
+ "brthdyDate" : "1999-09-07",
+ "email" : "lkd9125@naver.com",
+ "hpno" : "01083703435",
+ "clncd" : "+82"
+ }
+ """.formatted(username);
+
+ this.mockMvc.perform(
+ post(this.BASE_URL + "/register")
+ .contentType(MediaType.APPLICATION_JSON_VALUE)
+ .content(jsonRQ)
+ .accept(MediaType.APPLICATION_JSON_VALUE)
+ )
+ .andDo(print())
+ .andDo(
+ document(
+ "user/account/register", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
+ preprocessResponse(prettyPrint()),
+ requestFields(
+ fieldWithPath("cstrmDivCd").type(JsonFieldType.STRING).description("회원타입 코드"),
+ fieldWithPath("cstrmStatusCd").type(JsonFieldType.STRING).description("회원 활성화 코드"),
+ fieldWithPath("userId").type(JsonFieldType.STRING).description("아이디"),
+ fieldWithPath("authId").type(JsonFieldType.STRING).description("권한 값"),
+ fieldWithPath("siteCode").type(JsonFieldType.STRING).description("사이트 코드"),
+ fieldWithPath("userPswd").type(JsonFieldType.STRING).description("암호"),
+ fieldWithPath("joinCrtfyCd").type(JsonFieldType.STRING).description("가입인증 분류 코드"),
+ fieldWithPath("memberName").type(JsonFieldType.STRING).description("이름"),
+ fieldWithPath("brthdyDate").type(JsonFieldType.STRING).description("생년월일"),
+ fieldWithPath("email").type(JsonFieldType.STRING).description("이메일"),
+ fieldWithPath("hpno").type(JsonFieldType.STRING).description("휴대폰 번호"),
+ fieldWithPath("clncd").type(JsonFieldType.STRING).description("휴대폰 국가번호"),
+ fieldWithPath("terms").type(JsonFieldType.ARRAY).description("동의 약관 리스트").optional(),
+ fieldWithPath("terms[].termsSno").type(JsonFieldType.NUMBER).description("약관 식별번호"),
+ fieldWithPath("terms[].agreeYn").type(JsonFieldType.STRING).description("약관 동의여부")
+ )
+ )
+ )
+ .andExpect(status().isCreated());
+ }
+
+
+}
diff --git a/common/util/src/main/java/kr/co/palnet/kac/util/EncryptUtil.java b/common/util/src/main/java/kr/co/palnet/kac/util/EncryptUtil.java
index 26d4396..f495b77 100644
--- a/common/util/src/main/java/kr/co/palnet/kac/util/EncryptUtil.java
+++ b/common/util/src/main/java/kr/co/palnet/kac/util/EncryptUtil.java
@@ -1,5 +1,6 @@
package kr.co.palnet.kac.util;
+import kr.co.palnet.kac.util.kisa.KISA_SHA256;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.Cipher;
@@ -72,6 +73,18 @@ public class EncryptUtil {
return encrypted;
}
+ public static String sha256Encrypt(String str) {
+
+ byte[] bytes = str.getBytes();
+ byte[] pszDigest = new byte[32];
+ KISA_SHA256.SHA256_Encrpyt(bytes, bytes.length, pszDigest);
+ StringBuffer encrypted = new StringBuffer();
+ for (int i = 0; i < 32; i++) {
+ encrypted.append(String.format("%02x", pszDigest[i]));
+ }
+ return encrypted.toString();
+ }
+
public static void main(String[] args) {
String key = "1234567890123456";
String initVector = "1234567890123456";
diff --git a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/model/PtyCstmrDtl.java b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/model/PtyCstmrDtl.java
index 49acafc..ff288e5 100644
--- a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/model/PtyCstmrDtl.java
+++ b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/model/PtyCstmrDtl.java
@@ -5,6 +5,7 @@ import lombok.*;
import java.time.Instant;
import java.time.LocalDate;
+import java.time.LocalDateTime;
@Data
@@ -74,7 +75,7 @@ public class PtyCstmrDtl {
// 수정일시
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
- private Instant updateDt;
+ private LocalDateTime updateDt;
// 수정사용자ID
@Column(name = "UPDATE_USER_ID", length = 30, nullable = false)
diff --git a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/model/PtyCstmrGroup.java b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/model/PtyCstmrGroup.java
index 8fbc65a..2bdbe8b 100644
--- a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/model/PtyCstmrGroup.java
+++ b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/model/PtyCstmrGroup.java
@@ -4,6 +4,7 @@ import jakarta.persistence.*;
import lombok.*;
import java.time.Instant;
+import java.time.LocalDateTime;
@Data
@@ -17,6 +18,7 @@ public class PtyCstmrGroup {
// 고객그룹일련번호
@Id
@Column(name = "CSTMR_GROUP_SNO") // mysql :: "int unsigned"
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long cstmrGroupSno;
// 고객일련번호
@@ -41,7 +43,7 @@ public class PtyCstmrGroup {
// 승인일자
@Column(name = "APRVL_DT", columnDefinition = "datetime(6)")
- private Instant aprvlDt;
+ private LocalDateTime aprvlDt;
// 참여여부
@Column(name = "JOIN_YN", columnDefinition = "char(1) default 'N'", nullable = false)
@@ -53,7 +55,7 @@ public class PtyCstmrGroup {
// 탈퇴일시
@Column(name = "WTHDRW_DT", columnDefinition = "datetime(6)")
- private Instant wthdrwDt;
+ private LocalDateTime wthdrwDt;
// 터미널ID
@Column(name = "TRMNL_ID", length = 20)
diff --git a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/model/PtyTermsAgreeTxn.java b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/model/PtyTermsAgreeTxn.java
index 3ee413e..3a6a89d 100644
--- a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/model/PtyTermsAgreeTxn.java
+++ b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/model/PtyTermsAgreeTxn.java
@@ -4,6 +4,7 @@ import jakarta.persistence.*;
import lombok.*;
import java.time.Instant;
+import java.time.LocalDateTime;
@Data
@@ -40,7 +41,7 @@ public class PtyTermsAgreeTxn {
// 동의일시
@Column(name = "AGREE_DT", columnDefinition = "datetime")
- private Instant agreeDt;
+ private LocalDateTime agreeDt;
// 처리IP주소
@Column(name = "PROC_IP", length = 39)
@@ -48,7 +49,7 @@ public class PtyTermsAgreeTxn {
// 수정일시
@Column(name = "UPDATE_DT", columnDefinition = "datetime", nullable = false)
- private Instant updateDt;
+ private LocalDateTime updateDt;
// 수정사용자ID
@Column(name = "UPDATE_USER_ID", length = 30, nullable = false)
diff --git a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyCstmrBasRepository.java b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyCstmrBasRepository.java
index dd965dc..58e23d6 100644
--- a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyCstmrBasRepository.java
+++ b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyCstmrBasRepository.java
@@ -5,7 +5,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
-public interface PtyCstmrBasRepository extends JpaRepository {
+public interface PtyCstmrBasRepository extends JpaRepository {
@Query("select b from PtyCstmrBas b left join b.ptyCstmrDtl where b.userId = :userId")
PtyCstmrBas findByUserId(@Param("userId") String userId);
}
diff --git a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyCstmrDtlRepository.java b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyCstmrDtlRepository.java
index 820c96a..d532daf 100644
--- a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyCstmrDtlRepository.java
+++ b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyCstmrDtlRepository.java
@@ -3,6 +3,6 @@ package kr.co.palnet.kac.data.pty.repository;
import kr.co.palnet.kac.data.pty.model.PtyCstmrDtl;
import org.springframework.data.jpa.repository.JpaRepository;
-public interface PtyCstmrDtlRepository extends JpaRepository {
+public interface PtyCstmrDtlRepository extends JpaRepository {
}
diff --git a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyCstmrGroupRepository.java b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyCstmrGroupRepository.java
index 693ab43..ec2b996 100644
--- a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyCstmrGroupRepository.java
+++ b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyCstmrGroupRepository.java
@@ -2,7 +2,19 @@ package kr.co.palnet.kac.data.pty.repository;
import kr.co.palnet.kac.data.pty.model.PtyCstmrGroup;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+import java.util.List;
+import java.util.Optional;
+
+@Repository
public interface PtyCstmrGroupRepository extends JpaRepository {
+ public Optional> findByCstmrSnoAndJoinYn(Long cstmrSno, String joinYn);
+
+ public Optional> findByGroupId(String groupId);
+
+ public Optional> findByCstmrSno(Long cstmrSno);
+
+ public Optional findByGroupIdAndCstmrSno(String groupId, Long cstmrSno);
}
diff --git a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyGroupBasRepository.java b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyGroupBasRepository.java
index 3e8a08c..d21ed3f 100644
--- a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyGroupBasRepository.java
+++ b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/repository/PtyGroupBasRepository.java
@@ -2,7 +2,9 @@ package kr.co.palnet.kac.data.pty.repository;
import kr.co.palnet.kac.data.pty.model.PtyGroupBas;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+@Repository
public interface PtyGroupBasRepository extends JpaRepository {
}
diff --git a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/service/PtyCstmrDomainService.java b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/service/PtyCstmrDomainService.java
index 47e429b..ff935e4 100644
--- a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/service/PtyCstmrDomainService.java
+++ b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/service/PtyCstmrDomainService.java
@@ -1,19 +1,46 @@
package kr.co.palnet.kac.data.pty.service;
import kr.co.palnet.kac.data.pty.model.PtyCstmrBas;
+import kr.co.palnet.kac.data.pty.model.PtyCstmrDtl;
import kr.co.palnet.kac.data.pty.repository.PtyCstmrBasRepository;
+import kr.co.palnet.kac.data.pty.repository.PtyCstmrDtlRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
+import java.util.Optional;
+
@Slf4j
@RequiredArgsConstructor
@Service
public class PtyCstmrDomainService {
private final PtyCstmrBasRepository ptyCstmrBasRepository;
+ private final PtyCstmrDtlRepository ptyCstmrDtlRepository;
+
+
+
public PtyCstmrBas getCstmrInfoByUserId(String userId) {
return ptyCstmrBasRepository.findByUserId(userId);
}
+ public Optional findPtyCstmrBasById(Long cstmrSno){
+ return ptyCstmrBasRepository.findById(cstmrSno);
+ }
+
+ public PtyCstmrBas savePtyCstmrBas(PtyCstmrBas entity) {
+ return ptyCstmrBasRepository.save(entity);
+ }
+
+ public Optional findPtyCstmrDtlById(Long cstmrSno){
+ return ptyCstmrDtlRepository.findById(cstmrSno);
+ }
+ public PtyCstmrDtl savePtyCstmrDtl(PtyCstmrDtl entity){
+ return ptyCstmrDtlRepository.save(entity);
+ }
+
+
+
+
+
}
diff --git a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/service/PtyGroupDomainService.java b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/service/PtyGroupDomainService.java
new file mode 100644
index 0000000..6beada4
--- /dev/null
+++ b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/service/PtyGroupDomainService.java
@@ -0,0 +1,53 @@
+package kr.co.palnet.kac.data.pty.service;
+
+import kr.co.palnet.kac.data.pty.model.PtyCstmrGroup;
+import kr.co.palnet.kac.data.pty.model.PtyGroupBas;
+import kr.co.palnet.kac.data.pty.repository.PtyCstmrGroupRepository;
+import kr.co.palnet.kac.data.pty.repository.PtyGroupBasRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class PtyGroupDomainService {
+
+ private final PtyGroupBasRepository ptyGroupBasRepository;
+
+ private final PtyCstmrGroupRepository ptyCstmrGroupRepository;
+
+ public Optional> findJoinGroupByCstmrSno(Long cstmrSno){
+ return ptyCstmrGroupRepository.findByCstmrSnoAndJoinYn(cstmrSno, "Y");
+ }
+
+ public Optional> findByGroupId(String groupId){
+ return ptyCstmrGroupRepository.findByGroupId(groupId);
+ }
+
+ public Optional> findByCstmrSno(Long cstmrSno){
+ return ptyCstmrGroupRepository.findByCstmrSno(cstmrSno);
+ }
+
+ public Optional findByGroupIdAndCstmrSno(String groupId, Long cstmrSno){
+ return ptyCstmrGroupRepository.findByGroupIdAndCstmrSno(groupId, cstmrSno);
+ }
+
+ public PtyCstmrGroup savePtyCstmrGroup(PtyCstmrGroup entity){
+ return ptyCstmrGroupRepository.save(entity);
+ }
+
+ public PtyGroupBas findById(String id){
+ return ptyGroupBasRepository.findById(id).orElse(null);
+ }
+
+ public PtyGroupBas savePtyGroupBas(PtyGroupBas entity){
+ return ptyGroupBasRepository.save(entity);
+ }
+
+
+
+}
diff --git a/data/pty/src/main/java/kr/co/palnet/kac/data/pty/service/PtyTermsDomainService.java b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/service/PtyTermsDomainService.java
new file mode 100644
index 0000000..c7e6b93
--- /dev/null
+++ b/data/pty/src/main/java/kr/co/palnet/kac/data/pty/service/PtyTermsDomainService.java
@@ -0,0 +1,19 @@
+package kr.co.palnet.kac.data.pty.service;
+
+import kr.co.palnet.kac.data.pty.model.PtyTermsAgreeTxn;
+import kr.co.palnet.kac.data.pty.repository.PtyTermsAgreeTxnRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class PtyTermsDomainService {
+
+ private final PtyTermsAgreeTxnRepository ptyTermsAgreeTxnRepository;
+
+ public PtyTermsAgreeTxn savePtyTermsAgreeTxn(PtyTermsAgreeTxn entity){
+ return ptyTermsAgreeTxnRepository.save(entity);
+ }
+}
diff --git a/web/api-user/build.gradle b/web/api-user/build.gradle
index acc95bc..82be3ba 100644
--- a/web/api-user/build.gradle
+++ b/web/api-user/build.gradle
@@ -3,6 +3,7 @@
dependencies {
implementation "$boot:spring-boot-starter-web"
implementation "$boot:spring-boot-starter-data-jpa"
+ implementation "$boot:spring-boot-starter-security"
// for paging
// implementation("org.springframework.data:spring-data-commons")
@@ -10,6 +11,7 @@ dependencies {
compileOnly 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'
implementation project(":data:pty")
implementation project(":common:core")
+ implementation project(":common:util")
compileOnly project(":web:security")
}
diff --git a/web/api-user/src/main/java/kr/co/palnet/kac/api/v1/user/account/controller/UserAccountController.java b/web/api-user/src/main/java/kr/co/palnet/kac/api/v1/user/account/controller/UserAccountController.java
new file mode 100644
index 0000000..6c37293
--- /dev/null
+++ b/web/api-user/src/main/java/kr/co/palnet/kac/api/v1/user/account/controller/UserAccountController.java
@@ -0,0 +1,74 @@
+package kr.co.palnet.kac.api.v1.user.account.controller;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import kr.co.palnet.kac.api.v1.user.account.model.detail.SearchUserRS;
+import kr.co.palnet.kac.api.v1.user.account.model.register.FormRegisterRQ;
+import kr.co.palnet.kac.api.v1.user.account.model.update.UpdatePasswordRQ;
+import kr.co.palnet.kac.api.v1.user.account.model.update.UpdateUserRQ;
+import kr.co.palnet.kac.api.v1.user.account.service.UserAccountService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@Slf4j
+@RequiredArgsConstructor
+@RequestMapping("/v1/user/account")
+@Tag(name = "유저 - 계정", description = "계정 관련 API")
+public class UserAccountController {
+
+ private final UserAccountService userAccountService;
+
+ @PostMapping("/register")
+ @Operation(summary = "회원가입", description = "유저의 계정을 추가합니다.")
+ public ResponseEntity createUser(@RequestBody FormRegisterRQ rq){
+
+ userAccountService.createUser(rq);
+
+ return ResponseEntity.status(HttpStatus.CREATED).build();
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "회원탈퇴", description = "유저의 계정을 탈퇴시키며 참여한 그룹도 탈퇴시킵니다.")
+ public ResponseEntity deleteUser(){
+
+ userAccountService.deleteUser();
+
+ return ResponseEntity.ok().build();
+ }
+
+ @GetMapping("/profile")
+ @Operation(summary = "회원정보 조회", description = "회원 정보를 조회합니다.")
+ public ResponseEntity getUserInfo(){
+
+ SearchUserRS result = userAccountService.getUserInfo();
+
+ return ResponseEntity.ok().body(result);
+ }
+
+ @PutMapping("/update/pswd")
+ @Operation(summary = "회원암호 변경", description = "회원 암호를 변경합니다.")
+ public ResponseEntity updatePassword(@RequestBody UpdatePasswordRQ rq){
+
+ userAccountService.updatePassword(rq);
+
+ return ResponseEntity.ok().build();
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "회원정보 변경", description = "회원의 정보를 수정합니다.")
+ public ResponseEntity