지난번에 했었던 nil값 체크에 이어서 업그레이드 시켜본 함수입니다.
지난번과 차이가 있다면
1. 필수 입력 필드 중 입력 받지 못한 필드만 출력 됩니다.
한 줄 한 줄 입력 받은 데이터를 가져와서 빈 값이 생길 때 빈 값인 필드 이름만 출력이 되는것이 아니라 필수로 입력해야하는 필드 이름 전체가 출력이 되었다는 점입니다. (nil값 체크 참조)
만약 필수 값을 채우지 못한 에러가 생겨 났을 시, 제대로 데이터가 들어갔는지 체크 해줄 시에 복잡했던 부분이
방대한 데이터들이 끊임없이(또는 쉴새없이) 내려오는 상황에서 필수 값 필드 전체가 한 줄로 출력이 되어 한 눈에 보고 파악하기 힘들었고, 조금은 불편했습니다. (물론 코드는 간단했지만요..)
2. reflect 함수 사용으로 입력 하는 struct에 다이렉트로 접근합니다.
기존에 사용했던 방법은 타 함수에서 여러번 거쳐 거쳐 들어온 데이터들을 체크했다면 지금 사용한 방법은 거기에 거쳐 오는게 아니라 다이렉트로 체크한다는 점입니다.
대략 차이점은 이쯤 해두고, 코드 설명 부터 들어가도록 하겠습니다.
코드 설명
func ExamFunc(examstruct *ExamStruct) error {
var str string = "aaa,bbb,ccc" // 체크하려는 필수값들. (추가로 넣어도 됨.)
err := Checking(examstruct, str)
if err != nil {
panic(err)
}
return err
}
func Checking(examstruct *ExamStruct, str string) error {
var err error
compare := strings.Split(str, ",")
elements := reflect.ValueOf(examstruct).Elem()
errorstring := "CHECK "
cnt := 0
for i := 0; i < len(str); i++ {
for j := 0; j < elements.NumField(); j++ {
valName := elements.Type().Field(j)
valValue := elements.Field(j)
if compare[i] == valName.Name {
if len(valValue.String()) == 0 {
errorstring += compare[i] + ", "
cnt++
}
}
}
}
if cnt > 0 {
err = errors.New(es)
return err
}
return nil
}
ExamFunc도 JSON데이터의 값을 체크해주는 함수이기 때문에 error를 return하는 함수입니다. Checking과의 차이라면
ExamFunc은 JSON데이터의 값 체크해주는 부분의 집합들이고, Checking은 그 중 한 부분을 떼어내어 함수로 만든 것이니 사용 할 때 이 부분을 참고하여 쓰길 바랍니다.
var err error
compare := strings.Split(str, ",")
elements := reflect.ValueOf(examstruct).Elem()
errorstring := "CHECK "
먼저 error를 return 시켜주기 위해 error 타입의 변수를 선언 해줍니다.
그리고 compare변수는 ExamFunc에서 필수 Struct 필드명을 String형식으로 넣어준 부분을 str에 넣고,
이 부분을 Checking함수 인자값으로 보내주는데 이 부분을 ","단위로 자른 값이 들어있는 변수입니다.
참고로 이 때 str에 들어가는 값들은 실제 Struct에서 선언한 필드값을 써주어야 합니다.
elements변수는 reflect.ValueOf().Elem()을 써서 주어진 구조체를 reflect.Value 타입으로 변형시킨 것인데,
주어진 구조체의 입력받은 JSON 데이터들이 전부 가지고 있게 됩니다.
errorstring은 말그대로 에러 문구를 위한 변수이다. 끝에 빈 공간을 넣어준 이유는 보기 편하기 위함입니다.
elements변수의 데이터들을 뽑아오기 위해서는 for문을 돌려주면 되는데
cnt := 0
for i := 0; i < len(str); i++ {
for j := 0; j < elements.NumField(); j++ {
valName := elements.Type().Field(j)
valValue := elements.Field(j)
if compare[i] == valName.Name {
if len(valValue.String()) == 0 {
errorstring += compare[i] + ", "
cnt++
}
}
}
}
cnt는 빈 값이 들어있는 수를 체크하기 위한 변수입니다.
그 후에 for문을 돌리는데 먼저 지정된 필수 값 수 만큼 돌아갑니다. 저의 경우 "aaa,bbb,ccc"를 넣었기 때문에 3번이 돌죠.
그 다음 elements에서 지정한 Struct의 전체 필드 값 만큼 돌아가게 되는데 valName의 경우 그 Struct의 필드 이름과 필드 속성 값이 들어가게 되고, valValue의 경우 해당 valName의 입력값이 들어가게 됩니다.
그런 다음 compare[i]에 들어있는 필수 입력 필드값과 전체 Struct 값중에 같은 필드 값이 있는지 비교를 합니다.
같은 필드 값이 있으면 해당 필드가 빈 값인지 체크를 하여 빈 값이면 errorstring에 compare[i]을 집어 넣고, cnt를 1증가 시켜 줍니다.
위 코드의 실행 순서는 위 그림과 같다 보면 됩니다.
코드를 이해하는데 도움이 될 것 같아 그림으로 다시 설명을 해보자면 먼저 필수 필드값 'A'가 valName.Name의
'A' 필드와 같은지 조회를 하고, 같은 값이 있다면 'A'필드의 JSON값들을 전부 조회하여 'A'필드에 빈 값이 있는지 확인합니다.
그 후 'B'필드, 'C'필드가 같은 일을 한다 보면 됩니다.
if cnt > 0 {
err = errors.New(es)
return err
}
return nil
그렇게 해서 cnt가 0보다 클 경우(또는 빈 값을 찾았을 경우) 해당 에러 문구와 함께 빈 값이 있는 필드를 출력시켜 error를 보내주고, 없다면 nil 값을 보내주는데
만약 error가 있을 경우 err가 return되어 ExamFunc에서 panic처리가 될 것인데 저는 panic함수를 따로 만들어서 Panic이 되었을 시 log에 남기도록 처리하였습니다.
이상으로 코드 설명을 마쳤고, 유용하게 쓰시길 바랍니다.
혹시나 설명에서 잘못된 부분이 있다면 (특히 reflect 부분에서) 댓글로 알려주시기 바랍니다.
'프로그래밍(Web) > 업무관련' 카테고리의 다른 글
[바미] 개발 하면서 사용해 본 협업 툴들 (0) | 2021.06.04 |
---|---|
[바미] JMeter 설치부터 사용기 (Windows) (0) | 2021.05.17 |
[바미] Golang JSON에 입력된 UTC 시간 값 비교하기 (0) | 2021.05.04 |
[바미] Golang JSON nil값 Check 함수 만들다 생긴 일. (0) | 2021.05.04 |
[바미] Golang 같은 변수의 값 체크 시 “suspect or ” warnning 해결 방법 (0) | 2021.05.03 |