일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Remix
- NextJS
- node
- Ai
- polygon
- miniconda
- Setting
- 라라벨
- 발행
- 배포
- 블록체인
- Laravel
- nft
- React
- git
- exceljs
- jquery
- Kaikas
- threejs
- PM2
- metamask
- 회고
- Python
- nodejs
- nginx
- chatGPT
- 공연티켓
- netfunnel
- CSS
- pagination
- Today
- Total
박주니 개발 정리
register 진행시 주의사항 본문
cava 프로젝트를 진행하면서 node+javascript 위주로 하다가 laravel로 만들다보니 validation보다 jquery를 많이 의존해서 유효성검사를 진행했습니다. 하지만 laravel로 작업할 때 코드가 클린하기 위해서는 validation 기반으로 진행을 해야했고 유지보수를 하거나 협업을 할 때에도 모든 것을 jquery로 진행하게 되면 코드가 복잡해지는 것을 보면서 핵심이 되는 부분만 새로 간단하게 만들어서 만들어봤습니다.
1. 회원가입 버튼은 type submit으로 해서 validation을 거칠 수 있게 만듭니다.
- 이유) ajax을 사용해서 click event을 진행할시에 validation에 대한 메시지를 제대로 받지 못할 뿐더러 controller에서 response()->json()에 값을 담아서 그것을 또 프론트에서 append 보이게 해야 하기 때문에 최대한 form tag를 활용합니다.
2. 조건 성립시 localStorage를 활용해서 회원가입 버튼 조건 부합시 진행할 수 있게 만듭니다.
- 이유) 아이디 중복확인을 할 때에도 버튼을 안눌르고 클릭할 수도 있고 비밀번호 확인 성립되는 지 여부 확인도 안하고 누를 수도 있고 클라이언트가 요구하는 다양한 조건에 성립되지 않을 때 회원가입 버튼을 클릭시 다 controller을 거치게 하면 그건 프론트엔드 기능을 제대로 하지 않는 것이기 때문에 서버 과부하를 방지합니다.
3. ajax 사용시 controller에서 return response()->json()을 활용해서 구분해서 진행할 수 있게 만듭니다.
- 이유) 예전에 javascript로 작업을 하다보니 php 기반을 잘몰라서 ajax을 사용할 때 controller을 활용하는 방법이 잘안나와있었습니다. 보니깐 ajax을 사용하면 crud 작성하고 return response()->json()으로 내보내서 그것을 success:function(response){} 에서 response로 받아서 진행하시면 됩니다. ajax으로 진행할 때 controller에서 dd 활용할 수가 없어서 Log::info를 자주 사용했습니다.
지금 올리는 코드는 위에 세가지를 기반으로 blade, controller을 만들어봤습니다. 이 부분에 대한 코드 이해는 laravel crud를 이해하시고 오신다면 왜 이렇게 작성했는 지 확인할 수 있습니다. 포인트는 validation 활용편과 laravel crud 블로그에 올린거 봐주세요.
- register.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Register') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('register') }}" onsubmit="return checkRegister()">
@csrf
<div class="row mb-3">
<label for="name" class="col-md-4 col-form-label text-md-end">{{ __('Name') }}</label>
<div class="col-md-6">
<input id="name" type="text" class="form-control @error('name') is-invalid @enderror"
name="name" value="{{ old('name') }}" required autofocus>
@error('name')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
<input type="button" id="checkId" value="중복확인">
</div>
</div>
<div class="row mb-3">
<label for="email"
class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror"
name="email" value="{{ old('email') }}" required>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="password"
class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" id="password"
class="form-control @error('password') is-invalid @enderror" name="password"
required>
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="password-confirm"
class="col-md-4 col-form-label text-md-end">{{ __('Confirm Password') }}</label>
<div class="col-md-6">
<input id="password-confirm" type="password" id="password-confirm"
class="form-control" name="password_confirmation" required>
</div>
</div>
<button type="button" id="authBtn">인증</button>
<div class="row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Register') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
@section('javascript')
<script>
$(document).ready(function() {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
localStorage.removeItem('name');
localStorage.removeItem('confirmPwd');
localStorage.removeItem('auth')
})
$("#checkId").on("click", function() {
let name = $("#name").val();
$.ajax({
type: "GET",
url: `/checkId/${name}`,
success: function(response) {
if (response.message == 'success') {
localStorage.setItem('name', 1)
alert("사용 가능한 아이디입니다.")
} else {
localStorage.setItem('name', 2)
alert("중복된 아이디가 있습니다.")
}
},
error: function(request, status, error) {
console.log("code:" + request.status + "\n" + "message:" + request.responseText +
"\n" + "error:" + error);
}
})
})
// password, cofinrmpassword 비교
$("#password, #password-confirm").on("change", function() {
var password = $("#password").val();
var confirmPassword = $("#password-confirm").val();
var num = password.search(/[0-9]/g);
var eng = password.search(/[a-z]/ig);
var spe = password.search(/[`~!@@#$%^&*|₩₩₩'₩";:₩/?]/gi);
// console.log(password.length)
// console.log(num, eng, spe)
// password 8자리이상 20자리 이하일경우에만 비교
if (password.length > 7 || password.length < 20) {
if (password.search(/\s/) != -1) {
alert("비밀번호는 공백 없이 입력해주세요.");
return false;
}
else {
if (num >= 0 && eng >= 0 && spe >= 0) {
if (password == confirmPassword) {
localStorage.setItem('confirmPwd', 1)
alert("비밀번호가 일치합니다.")
} else {
localStorage.setItem('confirmPwd', 2)
alert("비밀번호가 일치하지 않습니다.")
}
} else {
alert("영문,숫자, 특수문자를 혼합하여 입력해주세요.");
}
}
}
})
$("#authBtn").on("click", function(){
let name = localStorage.getItem('name')
let password = localStorage.getItem('confirmPwd')
console.log(name, password);
if(name == 1 && password == 1){
alert("인증이 완료되었습니다.")
localStorage.setItem('auth', 1)
}
else{
alert("인증 실패했습니다.")
localStorage.setItem('auth', 2)
}
})
function checkRegister(){
let auth = localStorage.getItem('auth')
if(auth == 1){
alert('회원가입 진행중입니다.')
}
else{
alert("회원가입 실패하셨습니다.")
return false
}
}
</script>
@endsection
- 참고) script에서 정규식표현은 해당 코드는 제한을 하기 위함입니다. 좀 더 자세한 코드를 작성할 수 있었으나 우선 이건 프로젝트를 하다가 그저 회고하기 위해 만든 form임으로 나중에 만드실 때에는 input마다 제한을 주시길 바랍니다.
- CheckIdController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Log;
class CheckIdController extends Controller
{
public function index($user){
$userFirst = User::where('name', $user)->first();
if(true == empty($userFirst)){
return response()->json(['message'=>'success']);
}
else{
return response()->json(['message' => 'fail']);
}
}
}
- 참고) 아이디 중복확인 버튼 클릭시 이동해서 구분하는 controller입니다. 경로는 따로 설명하지 않겠습니다. 클릭시 이동해서 ajax으로 이용하시면 됩니다.
- RegisterController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\Models\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
'role' => 'user',
'status' => '2'
]);
}
}
- 참고) 이 controller은 laraval에서 제공하는 기본 controller입니다. column 추가 되거나 하시면 변경만 해서 활용하시면 됩니다. 새로 만들어서 작업하면 기본 제공하는 기능을 활용하지 못할 수 있으니 최대한 있는 register controller을 활용해주시면 됩니다.
그리고 이건 jquery 및 각 blade script을 사용하기 위해서는 @extends()에 연결된 blade를 확인해서 header에 jquery script 추가하고 @yield('content') 하단에 @yield('javascript')를 추가하시면 됩니다.
- app.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}" defer></script>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous">
</script>
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
{{ config('app.name', 'Laravel') }}
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav me-auto">
</ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ms-auto">
<!-- Authentication Links -->
@guest
@if (Route::has('login'))
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
</li>
@endif
@if (Route::has('register'))
<li class="nav-item">
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
</li>
@endif
@else
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ Auth::user()->name }}
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('Logout') }}
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
@csrf
</form>
</div>
</li>
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4">
@yield('content')
@yield('javascript')
</main>
</div>
</body>
</html>
- 참고) 이건 어디까지나 기본적으로 제공하는 @extends() 안에 있는 blade에서 해결한 것이고 나중에 협업에 일을 하시면 다른 blade로 작업할 수 있으니 꼭 그때는 extends 어디에 연결되어있는 지 확인하시고 진행하시길 바랍니다.
- jquery script 경로
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous">
</script>
- 참고) 다른 경로들을 사용을 해봤지만 저는 이 경로를 연결하고 사용할 때가 가장 편하게 잘돼서 추천을 합니다. 다만 더 간단한 방법이 있다면 알려주시면 감사하겠습니다.
laravel로 프로젝트를 진행하면서 특히 회원가입을 진행할 때 validation 유효성 검사를 중점으로 두고 해야한다는 것을 다시 한번 느끼게 되었다. 로마의 가면 로마의 법을 따르는 것처럼 node javascript 기반으로 했을 때 문제가 없어서 프론트에서 제한만 잘하면 되겠지라는 안일한 생각이 이렇게 유지보수할 때나 협업할 때 불편함을 줄 수 있다는 것을 알게 되었고 이제는 그런 실수를 저지르지 말아야겠다.