728x90

MariaDB(MySQL)에서 데이터로 한글을 입력하였을때 사진과 같이 에러가 발생합니다.

HeidiSQL - 에러화면

 

MySQL Client를 실행 및 로그인하여

아래 명령 코드를 입력해주면 사진과 같이 표시됩니다.

show variables like 'c%'; 

MySQL Client 실행화면

설정들을 uft8로 변경하는 작업을 진행해보겠습니다.

먼저 my.ini를 찾아서 실행해줍니다.

다음 사진과 같이 표시 될텐데,

 

 

uft8에 대한 명령어를 추가해줍니다.

[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4

 

 

이후 설정 적용을 위해서는 MySQL을 재시작해야 합니다.
서비스에서 설치하신 Database를 찾으셔서 다시 시작을 눌러줍니다.

저의 경우, MariaDB를 설치했기에 다음과 같이 표시됩니다.

Windows Service

 

이미 UTF8로 설정된 기존 데이터베이스나 테이블이 있을 경우 
다음 쿼리문을 통해 설정을 변경해주셔야만 합니다.

ALTER DATABASE <데이터베이스 이름> CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
ALTER TABLE <테이블 이름> CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

 

설정이 잘 변경되었는지 확인해보겠습니다.

 

설정이 잘 변경이 되었다면,

위 사진과 같이 데이터가 들어가지게 됩니다.

728x90

'Info > MariaDB(MySQL)' 카테고리의 다른 글

명령어 모음  (0) 2023.08.03
Posted by 게으른거북
:
728x90

참고 페이지 : #삽질 없는 개발은 없다

참고 페이지 : #Angular

 

Input Form에 대한 검증하는 기능을 추가하겠습니다.

총 3개의 Input이 있는데, 입력 값에 따라 Issue를 보여줄 수 있도록 합니다.

Web 실행화면

 

더보기

src/app/app.module.ts 수정

작업에 앞서서 먼저 Module를 추가해줍니다.

...
import { FormsModule, ReactiveFormsModule } from '@angular/forms';  // 코드 수정
...

const appRoutes : Routes = [
  ...
]

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
    ReactiveFormsModule,  // 코드 추가
    ...
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
  ...
}

 

src/app/user/user.component.ts 수정

...
import { FormGroup, FormBuilder, Validators } from '@angular/forms';  // 코드 수정
...

@Component({
  ...
})
export class UserComponent implements OnInit {

  ...

  complexForm : FormGroup;	// 코드 추가

  constructor(
    public service: UserService,
    private toastr: ToastrService,
    private fbuilder : FormBuilder  // 코드 추가
  ) {
      this.service.getUsers()
      .subscribe((data) => {
        ...
      })

    this.service.selectedUser = {
      ...
    };
    
    // 코드 추가
    // 필드 당 여러개의 유효성 검사기 추가. 
    // 두개 이상 검사하려면 Validators.complose 함수로 검사 항목을 맵핑해야함
    this.complexForm = fbuilder.group({
      "name": [
        null, 
        Validators.compose([
          Validators.required,		// 입력 여부 체크
          Validators.minLength(2),	// 최소 글자수 2개
          Validators.maxLength(20),	// 최대 글자수 20개
          Validators.pattern('[ㄱ-ㅎ|가-힣|a-z|A-Z|0-9|\*]+$')	// 한글, 영문(대소문자), 숫자 포함 여부 체크
        ])
      ],
      "email": [
        null, 
        Validators.compose([
          Validators.required,		// 입력 여부 체크
          Validators.email			// 이메일 형식 체크
        ])
      ],
      "password": [
        null, 
        Validators.compose([
          Validators.required,		// 입력 여부 체크
          // 영문(대소문자), 숫자, 특수문자가 각각 1개 이상 포함하여야 하며, 6글자 이상 입력 여부 체크
          Validators.pattern('(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[!@#$%^*+=-]).{6,}$')
        ])
      ]
    })
  }

  ngOnInit(): void {
  }
  
  ...
}

 

Validators 함수 (링크)

class Validators {
  static min(min: number): ValidatorFn
  static max(max: number): ValidatorFn
  static required(control: AbstractControl): ValidationErrors | null
  static requiredTrue(control: AbstractControl): ValidationErrors | null
  static email(control: AbstractControl): ValidationErrors | null
  static minLength(minLength: number): ValidatorFn
  static maxLength(maxLength: number): ValidatorFn
  static pattern(pattern: string | RegExp): ValidatorFn
  static nullValidator(control: AbstractControl): ValidationErrors | null
  static compose(validators: ValidatorFn[]): ValidatorFn | null
  static composeAsync(validators: AsyncValidatorFn[]): AsyncValidatorFn | null
}

 

 

src/app/user/user.component.html 수정

<div class="container">
  <header>
    ...
  </header>

  <hr>

  <div class="row">
    <div class="col-md-12">
      <h3>Insert User Data</h3>
      <!-- 코드 수정 -->
      <form method="post" #form="ngForm" [formGroup]="complexForm"  (ngSubmit)="onSubmit(form)">
        <input type="hidden" name="id" [(ngModel)]="service.selectedUser.id">
        <div class="form-group">
          <label for="name">Name : </label>
          <!-- 코드 수정 -->
          <input type="text" name="name" id="name" class="form-control" placeholder="insert your name"
            [(ngModel)]="service.selectedUser.name" [formControl]="complexForm.controls['name']">
          <!-- 코드 추가 -->
          <div *ngIf="complexForm.controls['name'].touched && !complexForm.controls['name'].valid" class="alert alert-danger">

            <div *ngIf="complexForm.controls['name'].hasError('required')" >필수 입력사항입니다.</div>

            <div *ngIf="complexForm.controls['name'].hasError('pattern')" >특수문자 및 숫자를 입력하실 수 없습니다.</div>

            <div *ngIf="complexForm.controls['name'].hasError('minlength') || complexForm.controls['name'].hasError('maxlength')" >2~20자 이내로 입력해주세요.</div>

          </div>
        </div>
        <div class="form-group">
          <label for="email">Email : </label>
          <!-- 코드 수정 -->
          <input type="text" name="email" id="email" class="form-control" placeholder="insert your email"
            [(ngModel)]="service.selectedUser.email" [formControl]="complexForm.controls['email']">
          <!-- 코드 추가 -->
          <div *ngIf="complexForm.controls['email'].touched && !complexForm.controls['email'].valid" class="alert alert-danger">
            
            <div *ngIf="complexForm.controls['email'].hasError('required')" >필수 입력사항입니다.</div>

            <div *ngIf="complexForm.controls['email'].hasError('email')" >이메일 형식으로 입력해 주세요.</div>

          </div>

        </div>
        <div class="form-group">
          <label for="password">Password : </label>
          <!-- 코드 수정 -->
          <input type="text" name="password" id="password" class="form-control" placeholder="insert your password"
            [(ngModel)]="service.selectedUser.password" [formControl]="complexForm.controls['password']">
          <!-- 코드 추가 -->
          <div *ngIf="complexForm.controls['password'].touched && !complexForm.controls['password'].valid" class="alert alert-danger">
            
            <div *ngIf="complexForm.controls['password'].hasError('required')" >필수 입력사항입니다.</div>

            <div *ngIf="complexForm.controls['password'].hasError('pattern')" >영문(대소문자), 숫자, 특수문자(!@#$%^*+=-)를 조합하여 8자리 이상 입력해주세요.</div>

          </div>

        </div>

        <div class="form-row">
          <div class="d-grid gap-2 d-md-flex justify-content-md-end">
          	<!-- 코드 수정 -->
            <button class="btn btn-sm btn-block btn-primary col-lg-2" [disabled]="!complexForm.valid">
              submit &nbsp; <fa-icon icon="user-plus"></fa-icon>
            </button>

            <button class="btn btn-sm btn-block btn-secondary col-lg-2" (click)="clearForm()">
              clear &nbsp; <fa-icon icon="undo"></fa-icon>
            </button>
          </div>
        </div>
      </form>
    </div>
  </div>

  <div class="row">
    ...
  </div>


  <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
    ...
  </div>

  <br>
  <footer>
    ...
  </footer>
</div>

 

실행화면

Web 실행화면 - 초기화면

초기 실행화면에서는 입력값에 대해 Required Error가 발생되었있기에,

submit 버튼이 비활성화 상태로 되어있습니다.

 

Web 실행화면 - 에러화면

입력폼을 가볍게(?) 터치하고 넘어가면, Required Error로 인해,

문구가 표시되는 것을 볼 수 있습니다.

 

Web 실행화면 - 에러화면

각각의 입력폼에 대한 Error로 표시되는 문구가 다르게 표시되는 이유는,

user.component.html에서 <div> 태그 내 *ngIf를 다르게 지정했기 때문입니다.

 

Web 실행화면 - 성공 화면

입력에 대한 검증에 맞추어 잘 입력해주시면,

Issue 문구도 사라지고, submit 버튼도 활성화 되어집니다.

 

728x90
Posted by 게으른거북
:
728x90

참고페이지 : Using Go with MariaDB (링크

 

Using Go with MariaDB | MariaDB

2019 Webinar: Building Modern Applications with MariaDB Hybrid Transactional/Analytical Processing (HTAP) Watch Now _________________________ I have been using Google’s Go programming language for a…

mariadb.com

이전 Database 연동 작업 이후,

생성(Create-POST), 읽기(Read-GET), 수정(Update-PUT), 삭제(Delete-DELETE)

작업을 추가로 진행하겠습니다.

 

더보기

main.go 수정

...

func main() {
	...
}

func connetDatabase() *sql.DB { ... }

func checkErr(err error) { ... }

func getUsers(w http.ResponseWriter, r *http.Request) { ... }

// 특정 user 정보 전달
func getUser(w http.ResponseWriter, r *http.Request) {
	setJsonHeader(w)
	HttpInfo(r)

	// 파라미터값 체크
	params := mux.Vars(r)

	// 파라미터값 중 id값 추출
	id, _ := strconv.Atoi(params["id"])

	// 주석 처리 or 제거
	// 일치하는 user id를 확인
	/*for _, user := range users {
		if user.Id == id {
			// 일치하는 user의 데이터 표시 및 함수 종료
			json.NewEncoder(w).Encode(user)
			return
		}
	}*/

	// 코드 추가
	// sql.DB 객체 생성
	db := connetDatabase()

	// 지연하여 닫는다(필수)
	defer db.Close()

	// 하나의 Row를 갖는 SQL 쿼리
	user = User{}

	err := db.QueryRow("SELECT * FROM users WHERE id = ?", id).Scan(&user.Id, &user.Name, &user.Email, &user.Password)
	checkErr(err)
	fmt.Println(user)

	if user.Id != 0 {
		// 일치하는 user의 데이터 표시 및 함수 종료
		json.NewEncoder(w).Encode(user)
		return
	} else {
		json.NewEncoder(w).Encode(NewResponse(r.Method, "failed", 400))
	}
}

// user 정보 추가
func postUser(w http.ResponseWriter, r *http.Request) {
	setJsonHeader(w)
	HttpInfo(r)

	body, _ := ioutil.ReadAll(r.Body)

	var user User
	err := json.Unmarshal(body, &user)
	defer r.Body.Close()

	if err != nil {
		json.NewEncoder(w).Encode(NewResponse(r.Method, "failed", 400))
		return
	}

	// 주석 처리 or 제거
	//users = append(users, user)

	// 코드 추가
	// sql.DB 객체 생성
	db := connetDatabase()
	defer db.Close()

	// INSERT 문 실행
	result, err := db.Exec("INSERT INTO users VALUES (?, ?, ?, ?)", user.Id, user.Name, user.Email, user.Password)
	checkErr(err)

	// sql.Result.RowsAffected() 체크
	n, err := result.RowsAffected()
	if n == 1 {
		fmt.Println("1 row inserted.")
	} else {
		json.NewEncoder(w).Encode(NewResponse(r.Method, "failed", 400))
		return
	}

	json.NewEncoder(w).Encode(NewResponse(r.Method, "success", 201))
}

// user 정보 수정
func putUser(w http.ResponseWriter, r *http.Request) {
	setJsonHeader(w)
	HttpInfo(r)

	params := mux.Vars(r)

	id, _ := strconv.Atoi(params["id"])

	body, _ := ioutil.ReadAll(r.Body)

	var user User

	err := json.Unmarshal(body, &user)

	checkErr(err)

	// 주석 처리 or 제거
	/*for index, _ := range users {
		if users[index].Id == id {
			users[index] = user

			json.NewEncoder(w).Encode(NewResponse(r.Method, "success", 200))
			return
		}
	}

	json.NewEncoder(w).Encode(NewResponse(r.Method, "failed", 400))*/

	// 코드 추가
	// sql.DB 객체 생성
	db := connetDatabase()
	defer db.Close()

	// UPDATE 문 실행
	result, err := db.Exec("UPDATE users SET id=?, name=?, email=?, password=? WHERE id=?", user.Id, user.Name, user.Email, user.Password, id)
	checkErr(err)

	// sql.Result.RowsAffected() 체크
	n, err := result.RowsAffected()
	if n == 1 {
		fmt.Println("1 row updated.")
	} else {
		json.NewEncoder(w).Encode(NewResponse(r.Method, "failed", 400))
		return
	}

	json.NewEncoder(w).Encode(NewResponse(r.Method, "success", 201))
}

// user 정보 삭제
func deleteUser(w http.ResponseWriter, r *http.Request) {

	setJsonHeader(w)

	HttpInfo(r)

	params := mux.Vars(r)

	id, _ := strconv.Atoi(params["id"])

	// 주석 처리 or 제거
	/*for index, _ := range users {
		if users[index].Id == id {
			users = append(users[:index], users[index+1:]...)

			json.NewEncoder(w).Encode(NewResponse(r.Method, "success", 200))

			return
		}
	}

	json.NewEncoder(w).Encode(NewResponse(r.Method, "failed", 400))*/

	// 코드 추가
	// sql.DB 객체 생성
	db := connetDatabase()
	defer db.Close()

	// Delete 문 실행
	result, err := db.Exec("DELETE FROM users WHERE id = ?", id)
	checkErr(err)

	// sql.Result.RowsAffected() 체크
	n, err := result.RowsAffected()
	if n == 1 {
		fmt.Println("1 row deleted.")
	} else {
		json.NewEncoder(w).Encode(NewResponse(r.Method, "failed", 400))
		return
	}

	json.NewEncoder(w).Encode(NewResponse(r.Method, "success", 200))
}

 

728x90
Posted by 게으른거북
: