728x90

axios에서는 api 호출시에 중복되는 코드나 기능을 생략할 수 있는 axiosinstance라는 기능이 있습니다.
이를 활용하면 코드의 유지보수성과 확장성을 얻을 수 있습니다.

axios 공식 홈페이지가 설명이 굉장히 친절하게 되어 있어서 직접 확인 하는 것도 좋습니다.
https://axios-http.com/kr/docs/intro

 

import axios, { InternalAxiosRequestConfig } from 'axios';

const axiosInstance = axios.create({
  baseURL: 'http://localhost:3000/',
  timeout: 100000,
  headers: {
    'content-type': 'application/json;charset=UTF-8',
    accept: 'application/json,',
  },
});

axiosInstance.interceptors.request.use(
  (config: InternalAxiosRequestConfig<{ headers: string }>) => {
    const access_token = sessionStorage.getItem('authorization');

    // config.headers 초기화
    config.headers = config.headers || {};
    if (access_token !== null) {
      config.headers['Authorization'] = `${access_token}`;
    }
    return config;
  }
);

export default axiosInstance;

위 코드는  서버에 api호출시에 로그인을 했다면 저장된 토큰을 자동으로 전송하기 위해서 작성한 코드입니다.
이는 api호출시 request단계에서 매번 토큰을 불러오는 과정을 직접 입력할 필요가 없어지죠.

사실 axios 자체가 타입 추론이 잘되어서 별다른 코드를 작성하지 않고 타입가드 정도만 해도 정상적으로 작동합니다. 
하지만 이럴 경우 any 타입으로 선언이 되기 때문에 타입스크립트의 장점이 드러나지 않습니다.

따라서 저는 제가 사용하는 토큰 전송시에만 간단하게 타입 처리를 하였습니다.

초기 config는 InternalAxiosRequestConfig 타입에 any값이 제네릭에 들어오는 것을 알 수 있습니다.

저는 이때 config 안에 있는 header를 사용하기 때문에 

axiosInstance.interceptors.request.use(
  (config: InternalAxiosRequestConfig<{ headers: string }>) => {
    const access_token = sessionStorage.getItem('authorization');

    // config.headers 초기화
    config.headers = config.headers || {};
    if (access_token !== null) {
      config.headers['Authorization'] = `${access_token}`;
    }
    return config;
  }
);

로 수정했습니다.

이처럼 타입 추론이 굉장히 잘 되기 때문에, 원하시는 혹은 추가하고 싶은 타입이 있다면  해당 부분에 마우스를 올려서 어떤 값이 any로 들어오고 있는지 확인하고 이를 수정하시면 됩니다.

 


https://velog.io/@bang9dev/axios-interceptor-with-ts 에서 타입을 굉장히 꼼꼼히 쓰신 예시를 볼 수 있는데, 참고하시는 것도 좋을 것 같습니다!

 

Axios 인터셉터 타입스크립트에서 제대로 쓰기

Axios 에는 interceptors 라는 기능이 있다. 이를 통해서 request/response 에 선행, 후행 처리를 커스텀하게 할 수 있다. 하지만 interceptor 를 통해서 변경된 값이 타입에 적용되지는 않는데, 이를 멋지게

velog.io

 

728x90

 

아래는 바이트 공식 홈페이지에 가면 볼 수 있는 vite의 장점들이다. 바이트란 무엇일까?

https://vitejs.dev/

 

이전까지 npx create-react-app을  통해서 리액트 앱을 만들었는데 ,  vite는 이를 대신해서 사용할 수 있는 것이다.
물론 리액트 뿐만 아니라 뷰 같은 다른 프로젝트도 생성이 가능하다.


그렇다면 왜 바이트를 사용할까?

공식 문서내용은 아래와 같고 요약하자면
기존에 ES모듈(import)이 사용하술 있기 전에는 번들링을 통해서 , 소스 모듈을 브라우저에서 실행할 수 있는 파일로 크롤링, 처리 및 연결했다. 그런데 이러한 방식이  점점 자바스크립트 코드가 많아지면서 병목현상이 생겼다. 그 당시엔 좋았떤 것이 점차 속더 및 성능 저하가 생긴 것이다.

 

이를 ES모듈을 적용하여서 속도 및 성능을 개선한 게  바이트다.

 

바이트는 느린 서버시작과 업데이트를 개선함

 

서버시작 개선방법 

Depencies 부분 

자바스크립트는 ES번들을 사용하여 종속성을 사전 번들로 제공하고, ES번들GO로 작성되었는데 이는 자바스크립트 기반 번들보다 10~100이상 속도가 빠르다.

 

Sourcecode 부분

Native ESM을 통해서 소스코드 제공 + 브라우저가 일부 번들링 작업을 인계받고, 브라우저가 요청시에만 제공

 

서버업데이트 개선방법 

기존 번들러 기반 빌드 설정에서는 파일 편집 시 전체 번들을 다시 빌드하는 경우가 있는데 , vite가 사용하는
HMR방식은 페이지의 나머지 부분에 영향을 주지않고 변경된 모듈 자체를 교체해서 빠르게 화면에 반영되게 함

또한 ESM을 통해서 실행하여서 기존 HMR방식과는 다르게 앱의 크기에도 덜 영향을 받는다.

 

소스코드를 작성하여 변경하더라도 state가 초기화 되지않음.

설치방법

npm init vite
(처음 사용하는 경우 y를 누르면  create vite가 설치됨)

이후 원하는 프로젝트 (react ) -> typescript를 선택한 후
npm install로 모듈 설치
이후 npm run dev로 실행 (npm start 대신 사용)

패캠 강사님이 비교한 것에 의하면
                          바이트      vs        CRA              의 차이는 
설치 시간               30초                  1분40초
FIle Size                45MB                  221MB
Build File Size       150KB                553KB

728x90

패스트 캠퍼스에서   swiper 라이브러리 사용에 대해서 배우게 되었다. (패캠 프론트엔드 초격차 강의)

공식 문서는 

https://swiperjs.com/react

 

Swiper - The Most Modern Mobile Touch Slider

Swiper is the most modern free mobile touch slider with hardware accelerated transitions and amazing native behavior.

swiperjs.com

사용한 예시 코드는 다음과 같다.

 <Container>
      <h2>{title}</h2>
      <Swiper
        // install Swiper modules
        modules={[Navigation, Pagination, Scrollbar, A11y]}
        loop={true} //loop 기능을 사용할 것인지
        navigation // arrow 버튼 사용 유무
        pagination={{ clickable: true }} //페이지 버튼 보이게 할지
        breakpoints={{
          1378: {
            slidesPerView: 6, //한번에 보이는 슬라이드 개수
            slidesPerGroup: 6,
          },
          998: {
            slidesPerView: 5, //한번에 보이는 슬라이드 개수
            slidesPerGroup: 5,
          },
          625: {
            slidesPerView: 4, //한번에 보이는 슬라이드 개수
            slidesPerGroup: 4,
          },
          0: {
            slidesPerView: 3, //한번에 보이는 슬라이드 개수
            slidesPerGroup: 3,
          },
        }}
      >
        <Content id={id}>
          {movies?.map((movie) => (
            <SwiperSlide key={movie.id}>
              <Wrap>
                <img
                  key={movie.id}
                  src={`https://image.tmdb.org/t/p/original${movie.backdrop_path}`}
                  alt={movie.name}
                  onClick={() => handleClick(movie)}
                />
              </Wrap>
            </SwiperSlide>
          ))}
        </Content>
      </Swiper>

      {modalOpen && (
        <MovieModal {...movieSelected} setModalOpen={setModalOpen} />
      )}
    </Container>

이중에서 Container와 Content Wrap태그는 styled-components 라이브러리를 사용해서 만든 스타일드 컴퍼넌트입니다.

 

 

 

좌측 Usage 탭에서 모듈들을 확인할 수 있다. (강의랑 import 주소가 다릅니다 'swiper/modules'로 수정) --> 매번 달라질 수 있어서 공식문서 확인하는게 좋아요

 

내가 적용한 모듈은 

 modules={[Navigation, Pagination, Scrollbar, A11y]}

각각의 모듈은

  • Navigation - Navigation module
  • Pagination - Pagination module
  • Scrollbar - Scrollbar module
  • A11y - Accessibility module

공식 사이트 예시 코드에서도 그렇고 기분적으로 사용하는 친구들입니다.

이후 style 탭을 통해서 확인하고 자기가 사용하고 싶은 css를 임포트 하면 됩니다

// import swiper style
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/scrollbar';
import 'swiper/css/pagination';
import styled from 'styled-components';

이후
Swiper 안에서 map 메서드를 통해서 각각의 SwiperSlide를 생성하면 된다.

 

좌우의 흰 버튼이 Swiper의 navigation 이고 , 우측 하단의 점들이 pagination이다.

 

Swiper 에 들어가는 어트리뷰트는 아래 링크에서 확인할 수 있다.

https://swiperjs.com/swiper-api#parameters

 

Swiper - The Most Modern Mobile Touch Slider

Swiper is the most modern free mobile touch slider with hardware accelerated transitions and amazing native behavior.

swiperjs.com

 

breakpoints 는 화면 크기에 따라 보여주는 것을 어떻게 다르게 할 지 설정하는 것이다.

loop는 슬라이더가 끝에 갔을 떄 루프를  통해 다시 처음으로 이동가능하게 하는 것이다.

 

728x90

이런 모양의  달력을 라이브러리를 통해서 간단하게 만들 수 있다.

 

해당 라이브러리의 깃헙주소는 https://www.npmjs.com/package/fullcalendar 이다.

설치 

해당 라이브러리를 시작하기 위해서는 우선 세 가지를 인스톨 해야한다.

npm install --save  @fullcalendar/core @fullcalendar/react @fullcalendar/daygrid @fullcalendar/timegrid @fullcalendar/list

npm install --save @fullcalendar/interaction

npm install --save-dev css-loader

  

이후 프로젝트에서 사용하면 된다.

 

저는 프로젝트를 만든 이후 , component 폴더에 달력과 관련 css파일만 추가해서 실행하였습니다.

 

 

이제 코드를 보겠습니다. 

import React, { useRef } from "react";
import FullCalendar from "@fullcalendar/react";
import dayGridPlugin from "@fullcalendar/daygrid";
import timeGridPlugin from "@fullcalendar/timegrid";
import listMonth from "@fullcalendar/list";
import interactionPlugin from "@fullcalendar/interaction";

import "./Calendar.css";

const Calendar = () => {
  const calendarRef = useRef();
  // event 추가
  const onEventAdd = (e) => {
    const api = calendarRef.current.getApi();
    api.addEvent({
      title: "이사장님과의 약속",
      date: "2023-08-24 12:30",
      constraint: "약속",
    });
  };
  // 이벤트 클릭시
  const eventCLick = (info) => {
    // alert("eventClick");
    // alert(JSON.stringify(info.event.start));

    let date = new Date(info.event.start);
    let year = date.getFullYear();
    let month = date.getMonth();
    let day = date.getDate();
    let hour = date.getHours();
    let minute = date.getMinutes();
    let promise = `날짜 : ${year}년 ${month + 1}월 ${day}일 ${hour}시 ${minute}분
`;
    promise += "제목 : " + info.event.title + "\n";
    promise += "내용 : " + info.event.constraint;
    alert(promise);
  };

  // 날짜를 클릭시
  const handleDateClick = (args) => {
    let date = new Date(args.dateStr);
    let year = date.getFullYear();
    let month = date.getMonth() + 1 + "";
    if (month.length < 2) {
      month = "0" + month;
    }
    let day = date.getDate() + "";
    if (day.length < 2) {
      day = "0" + day;
    }
    let selectDate = year + "-" + month + "-" + day;
    alert(selectDate);
  };

  return (
    <div className="calendar">
      <FullCalendar
        headerToolbar={{
          left: "prev next today", // 좌측버튼
          center: "title",
          end: "dayGridMonth timeGridWeek timeGridDay listMonth",
        }}
        locale={"ko"} // 한국어
        navLinks={true} // 오른쪽 상단의 day 클릭 대신 날짜를 클릭
        businessHours={true} // 주말을 다른 색으로
        plugins={[dayGridPlugin, timeGridPlugin, listMonth, interactionPlugin]}
        initialView="dayGridMonth"
        eventClick={eventCLick}
        ref={calendarRef}
        dateClick={handleDateClick}
        events={[
          {
            title: "점심약속",
            date: new Date(), //'2023-08-16
          },
          {
            title: "미팅",
            start: "2023-08-14", //'2023-08-16 까지 적으면 줄이 김
          },
          {
            title: "미팅2",
            start: "2023-08-14 12:30", //'2023-08-16 까지 적으면 줄이 김
          },

          {
            title: "비지니스",
            start: "2023-08-18 12:30:00",
            constraint: "김사장과 복싱",
            end: "2023-08-20 12:30",
          },
          {
            title: "워크샵",
            start: "2023-08-17 12:30:00",
            constraint: "팔협지 또 일등이야",
            end: "2023-08-22 12:30",
          },
          {
            title: "데이트",
            start: "2023-08-27 12:30:00",
            constraint: "영화관람",
            backgroundColor: "#ff0000",
          },
        ]}
      />

      <br />
      <button onClick={onEventAdd} className="btn btn-primary">
        일정추가
      </button>
    </div>
  );
};

export default Calendar;

약식으로 만든 파일이기 때문에 위와 같이 작성을 하였습니다.
FullCalendar를 제외한 플러그인은 컴퍼넌트가 아니기에 소문자로 import 했고
FullCalendar는 대문자로 import해야합니다

 

그리고 현재는 서버와의 통신없이 코드를 작성하였기에 , 

 const onEventAdd = (e) => {
    const api = calendarRef.current.getApi();
    api.addEvent({
      title: "이사장님과의 약속",
      date: "2023-08-24 12:30",
      constraint: "약속",
    });
  };

에서 임의의 더미데이터를 넣어 작성하였지만, 서버와 연결을 할 거면 axios를 통해서 데이터를 전송하시면 됩니다.

 

이제 라이브러리에 대해 설명하겠습니다.

<FullCalendar
        headerToolbar={{
          left: "prev next today", // 좌측버튼
          center: "title",
          end: "dayGridMonth timeGridWeek timeGridDay listMonth",
        }}
        locale={"ko"} // 한국어
        navLinks={true} // 오른쪽 상단의 day 클릭 대신 날짜를 클릭
        businessHours={true} // 주말을 다른 색으로
        plugins={[dayGridPlugin, timeGridPlugin, listMonth, interactionPlugin]}
        initialView="dayGridMonth"
        eventClick={eventCLick}
        ref={calendarRef}
        dateClick={handleDateClick}
        events={[
          {
            title: "점심약속",
            date: new Date(), //'2023-08-16
          },
          {
            title: "미팅",
            start: "2023-08-14", //'2023-08-16 까지 적으면 줄이 김
          },
          {
            title: "미팅2",
            start: "2023-08-14 12:30", //'2023-08-16 까지 적으면 줄이 김
          },

          {
            title: "비지니스",
            start: "2023-08-18 12:30:00",
            constraint: "김사장과 복싱",
            end: "2023-08-20 12:30",
          },
          {
            title: "워크샵",
            start: "2023-08-17 12:30:00",
            constraint: "팔협지 또 일등이야",
            end: "2023-08-22 12:30",
          },
          {
            title: "데이트",
            start: "2023-08-27 12:30:00",
            constraint: "영화관람",
            backgroundColor: "#ff0000",
          },
        ]}
      />

headerToolbar 의 경우 헤더에 있는 버튼들을 정의해줍니다. 이때 prev 와 next 는 화살표 모양으로 달력이동, today는 현재 날짜로 돌아오게 합니다.  left title right는 해당 버튼들의 위치를 정의하고,  dayGridMonth timeGridWeek timeGridDay listMonth 는 각각 월 주 일 일정리스트별 정렬을 해줍니다.

week을 클릭할 경우

 

locale은 언어 설정,

navlinks는 day대신 날짜 클릭 (false하는게 좋다고 생각합니다), 

businessHours는 주말은 다른색,

plugins에 위에 import한 plugin들을 연결하고,

initial view는 시작시 보여줄 달력의 모양,
dateClick은 달력의 날짜 클릭시 효과,

eventClick은 일정 클릭시 효과입니다.

 

728x90

리엑트로 위와 같은 페이지네이션을 구현했습니다. 이때 사용한 라이브러리와 코드를 공유하려고 합니다.

우선 라이브러리이기에 프로젝트에 해당 라이브러리를 먼저 설치해야합니다.

npm i react-js-pagination

 

라이브리러의 자세한 정보는 https://mui.com/material-ui/react-pagination/ 에서 확인하면 됩니다!

 

이후 사용하고자 하는 페이지에서 import 합니다.

import Pagination from "react-js-pagination";

Pagination 이 컴퍼넌트 이기에 소문자로 import하면 제대로 작동하지 않습니다.

 

 <Pagination
		// 내가 선언한 상태 : page, totalCnt    함수 : handlePageChange
        activePage={page} 
        itemsCountPerPage={10}
        totalItemsCount={totalCnt}
        pageRangeDisplayed={5}
        prevPageText={"이전"}
        nextPageText={"다음"}
        onChange={handlePageChange}
      />

태그에 대한 자세한 설명은 https://mui.com/material-ui/api/pagination/ 에서 확인하시면 됩니다.

제가 사용한 것은 

 

activePage : 현재 페이지

itemsCountPerPage : 한 페이지에 보여줄 글 수

totleItemsCount = 총 게시글 수

pageRangeDisplayed = 한 번에 보여줄 page 버튼 수 (저는 게시글이 적어서 2개만 나왔습니다)

?? +PageText : 다음 혹인 이전 버튼에 들어갈 글자

onChange : page가 선택됐을 때 실행할 함수 

 

 위치는 본인 프로젝트에 맞게 넣으면 됩니다.  저는 글 쓰기 버튼 위 게시판 아래에 배치하였습니다.

 

// 페이징
  const [page, setPage] = useState(1);
  const [totalCnt, setTotalCnt] = useState(0);

useState를 통해서 현재 페이지와, 총 글 수를 변수 선언했고

const getBbslist = (c, s, pn) => {
    axios
      .get("http://localhost:3000/bbslist", { params: { choice: c, search: s, pageNumber: pn } })
      .then((resp) => {
        console.log(resp.data);
        setBbslist(resp.data.bbslist);
        setTotalCnt(resp.data.cnt); // 글의 총수
      })
      .catch((err) => {
        alert(err);
      });
  };

게시글을 불러오는 함수를 통해서 게시글 데이터를 get요청했습니다.

이때 resp로 bbslist(게시글 리스트) 와 cnt(총 게시글 수) 를 리턴 받습니다.
controller에서는 서비스에 있는 bbslist 함수를 통해서 게시글들을 반환하고, getallbbs 함수를 통해서 총 게시글 수를 반환합니다.

@GetMapping("bbslist")
	public Map<String,Object> bbslist(BbsParam param){
		System.out.println("BbsController bbslist " + new Date());
		//글목록
		List<BbsDto> list = service.bbslist(param);
		
		//글의 총수
		int count = service.getallbbs(param);

		// 현재 페이지
		Map<String,Object> map = new HashMap<String,Object>();
		map.put("bbslist", list);

		
		//react용
		map.put("cnt", count);
		return map;
	}

 

728x90

npx create-react-app  react-test 
                                   ( 프로젝트 명) 을 통해서 리액트 프로젝트를 생성하면 아래와 같은 구성이 생긴다.

이때 리엑트는  노란색 칠해진 3부분에 의해서 작동한다.

기본적으로 웹페이지는 index.html에서 시작을 하는데 리엑트에서도 마찬가지이다.

하지만 리엑트의 특징은 컴퍼넌트를 통해서 하나의 index.html 페이지에서 컴퍼넌트 교체를 통해서 다른 페이지를 보여주는 거 처럼 작동한다.

<body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>

index.html에 보면 다음과 같이 적혀있다.

이때 npm start(혹은 yarn)대신 직접 열면, root 하위의 파일들이 불러와지지 않아서, 빈 페이지가 보인다.

 

index.html에 하위 컴퍼넌트를 연결하는 역할을 index.js가 한다.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

이떄 StrictMode는 좀 더 엄격하게 프로젝트를 사용하기 위해 설정하는 것으로, 굳이 없어도 된다.

코드를 보면 html에 있던 id가 root인 곳(body)에 <App/> 을 랜더링한다고 적혀 있다.

그리고 App이 무엇인지는 App.js 파일을 보면 알 수 있다.

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

현재 우리가 봤던 화면은 위 코드를 통해 구성되어있다.

그리고 이를 App.css와 저장된 이미지에 애니메이션 효과를 주어서 우리가 봤던 아래 이미지를 구현한다.

컴퍼넌트는 이때 대문자로 이름이 시작해야하고, export default를 통해서 외부 파일에서 사용할 수 있게 한다.

 

// index.js의 임포트 부분

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

index.js 에서 ./App 을 통해서 export한 App을 사용하고 있다. 이때 뒤에 './App'; 은 경로인데, .js의 경우는 생략이 가능하다.

728x90
<form action="regiAf.do" method="post">

<table border="1">
<tr>
	<th>아이디</th>
	<td>
		<input type="text" name="id" id="id" size="20" placeholder="아이디">
		<input id="id_chk_btn" value="id확인"><br>
		<p id="idcheck" style="font-size: 8px"></p>		
	</td>
</tr>
<tr>
	<th>패스워드</th>
	<td>
		<input type="text" name="pwd" id="pwd" size="20">
	</td>
</tr>
<tr>
	<th>이름</th>
	<td>
		<input type="text" name="name" size="20">
	</td>
</tr>
<tr>
	<th>이메일</th>
	<td>
		<input type="text" name="email" size="20">
	</td>
</tr>
<tr>
	<td colspan="2" align="center">
		<input type="submit" value="회원가입">
	</td>
</tr>
</table>

</form>

위와 같이 간단한 회원가입 폼을 구현하였다.

이때 회원가입과 아이디중복확인 2가지 버튼이 있는데, 위와 같이 코드를 작성하면 아이디 체크일 때도 자동으로 제출이 된다(submit)
이때 간단하게 아이디 체크 버튼의 타입을 button으로 지정하면 submit이 자동으로 되는것을 막을 수 있다.

		<input type="button" id="id_chk_btn" value="id확인"><br>




728x90

 

코드 : https://github.com/suhong99/jspLecture/tree/master/SampleModelOne

 

GitHub - suhong99/jspLecture

Contribute to suhong99/jspLecture development by creating an account on GitHub.

github.com

1. eclipse에서  Dynamic Web Project로 파일을 만든다.

이후 \주소\내프로젝트 이름\src\main\webapp\WEB-INF\lib에  mysql-connector-j-8.0.33.jar파일 넣으면 초기세팅이 끝난다.

 

2. 신세계에서 배우는 프로젝트에선 db, jsp , bootstrap, jquery를 이용해서 만들었다.

 

3. db는 MYSQL을 사용했는데, 

create table member(
	id varchar(50) primary key,
	pwd varchar(50) not null,
	name varchar(50) not null,
	email varchar(50) unique,
	auth int
);

select count(*)
from member
where id='abc';

select * from member;

delete from member
where id='abc';

회원가입은 다음과 같다.  아이디와 비밀번호  email name을 입력받는다.
auth는 추후 관리자 관련 값이다. 관리자는 1 회원은 3
이를 eclipse에서 만든 java코드를 통해서 db에 값을 추가해준다.

프론트쪽에서 값을 입력하기 전에 db와 연결할 java코드를 먼저 작성한다.


3. 데이터에 접근할 때는 dto와 dao를 사용한다.
dto 는 Data Transfer Object로 데이터로 주로 db와 주고 받은 값을 담는데 사용한ㄷ.
 dao는 데이터 베이스에 접근하기 위한 객체 Data Access Object이다.


4. dao에는instance생성, 생성자 , 아이디 확인, 로그인 , 회원가입이 있다. 

 

public boolean addMember(MemberDto dto) {		
		String sql = " 	insert into member(id, pwd, name, email, auth) "
				+ "		values(?, ?, ?, ?, 3) ";
		
		Connection conn = null;
		PreparedStatement psmt = null;
		
		int count = 0;
		
		try {
			conn = DBConnection.getConnection();
			System.out.println("addMember 1/3 success");
				
			psmt = conn.prepareStatement(sql);
			psmt.setString(1, dto.getId());
			psmt.setString(2, dto.getPwd());
			psmt.setString(3, dto.getName());
			psmt.setString(4, dto.getEmail());
			System.out.println("addMember 2/3 success");
			
			count = psmt.executeUpdate();
			System.out.println("addMember 3/3 success");
			
		} catch (SQLException e) {
			System.out.println("addMember fail");
			e.printStackTrace();
		} finally {
			DBClose.close(psmt, conn, null);
		}
		
		return count>0?true:false;
	}

 

위의 코드는 구중에 회원가입에 관련된 코드다. 

위와 같이 db와 dao dto가 준비가 끝나면 이제 프론트쪽 코드를 작성하면 된다.

회원가입 코드는 아래와 같다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>

<style type="text/css">
.center{
	margin: auto;
	width: 60%;
	border: 3px solid #0000ff;
	padding: 10px;
}
</style>

</head>
<body>

<h2>회원가입</h2>
<p>환영합니다</p>

<div class="center">

<form action="regiAf.jsp" method="post">

<table border="1">
<tr>
	<th>아이디</th>
	<td>
		<input type="text" name="id" id="id" size="20" placeholder="아이디">
		<input type="button" id="id_chk_btn" value="id확인"><br>
		<p id="idcheck" style="font-size: 8px"></p>		
	</td>
</tr>
<tr>
	<th>패스워드</th>
	<td>
		<input type="text" name="pwd" id="pwd" size="20">
	</td>
</tr>
<tr>
	<th>이름</th>
	<td>
		<input type="text" name="name" size="20">
	</td>
</tr>
<tr>
	<th>이메일</th>
	<td>
		<input type="text" name="email" size="20">
	</td>
</tr>
<tr>
	<td colspan="2" align="center">
		<input type="submit" value="회원가입">
	</td>
</tr>
</table>

</form>
</div>

<script type="text/javascript">
$(document).ready(function(){
	
	$("#id_chk_btn").click(function(){
		
		// id의 규칙: 대소문자 + 특수문자 포함
		
		// id 글자의 갯수
		
		// id가 사용할 수있는지 없는지 -ajax
		$.ajax({
			url:"idcheck.jsp",
			type:"post",
			data:{ "id":$("#id").val() },
			success:function( answer ){
				// alert("success");
				// alert(answer);
				
				if(answer.trim() == "YES"){
					$("#idcheck").css("color", "#0000ff");
					$("#idcheck").text("사용할 수 있는 아이디입니다");
				}else{
					$("#idcheck").css("color", "#ff0000");
					$("#idcheck").text("사용중인 아이디입니다");
					$("#id").val("");
				}
				
			},
			error:function(){
				alert('error');
			}
		});
	});
	
});
</script>




</body>
</html>

간단하게 id가 이미 존재하는지 확인하고,  만약 존재하지 않는다면 회원가입을 진행하면 된다.

이때 idcheck.jsp에서 아이디를 확인하고 있는데 

<%@page import="dao.MemberDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	String id = request.getParameter("id");

	MemberDao dao = MemberDao.getInstance();
	boolean b = dao.getId(id);
	if(b == true){	// id가 있음
		out.println("NO");
	}else{	// id가 없음(사용할 수 있음)
		out.println("YES");
	}	
%>

jsp에서는 <% %> 사이에 자바코를 작성하고, dao 인스턴스를 생성한 후, dao에 있는 id 확인 함수를 실행한다.

	public boolean getId(String id) {
		String sql = " 	select count(*) "
				+ "		from member "
				+ "		where id=? ";
		
		Connection conn = null;
		PreparedStatement psmt = null;
		ResultSet rs = null;
		
		int count = 0;
		
		try {
			conn = DBConnection.getConnection();
			System.out.println("getId 1/4 success");
		
			psmt = conn.prepareStatement(sql);
			psmt.setString(1, id);
			System.out.println("getId 2/4 success");
			
			rs = psmt.executeQuery();
			System.out.println("getId 3/4 success");
			
			if(rs.next()) {
				count = rs.getInt(1);				
			}	
			System.out.println("getId 4/4 success");
			
		} catch (SQLException e) {		
			System.out.println("getId fail");
			e.printStackTrace();
		} finally {
			DBClose.close(psmt, conn, rs);
		}
		
		return count>0?true:false;
	}

sql의 where문을 통해 아이디를 확인하고 있따면 count를 올려서 true값이 반환되게 한다.

그리고 따라서 위의 regi.jsp에서 true일 때 아이디가 중복됩니다라고 알려준다.

이후 중복되지 않는다면

<%@page import="dto.MemberDto"%>
<%@page import="dao.MemberDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%
	request.setCharacterEncoding("utf-8");

	String id = request.getParameter("id");
	String pwd = request.getParameter("pwd");
	String name = request.getParameter("name");
	String email = request.getParameter("email");
	
	MemberDao dao = MemberDao.getInstance();
	
	MemberDto dto = new MemberDto(id, pwd, name, email, 0);
	boolean isS = dao.addMember(dto);
	if(isS == true){	// 가입성공!	
		%>
		<script type="text/javascript">
		alert("가입에 성공하셨습니다!");
		location.href = "login.jsp";
		</script>
		<%
	}else{				// 가입실패
		%>
		<script type="text/javascript">
		alert("다시 가입해 주십시오");
		location.href = "regi.jsp";
		</script>
		<%
	}
%>

가입 성공을 시키면 된다.

+ Recent posts