HCD 랩스 12월 1주차 - mqtt 연결, 백엔드 흐름, 람다식, stream, DB데이터를 조회해서 리액트에 리스트로 출력, 조회, 검색, 스프링 시큐리티

우영·2025년 12월 2일

HDC 랩스 풀스택 1기

목록 보기
15/20

이번주 할것

  1. guage 차트연결
  2. mqtt 통신 코드를 컴포넌트에서 분리
  3. 컴포넌트로 분리 - 화요일 4시반까지 한 작업 - 라즈베리 끔
  4. 리액트의 데이터를 스프링백엔드로 디비에 insert - 12/3 복습하긴 했음
  5. 디비데이터를 조회해서 리액트에 리스트로 출력 - 12/4 너무 어려움
  6. 스프링 시큐리티
  7. 토큰을 이용해서 로그인/로그아웃
  8. 백엔드에서 mqtt통신하기

12/1 월 - AI 특강


12/2 화 - mqtt통신 컴포넌트 분리

assignment

review


  • 노드 모듈 지웠으면 락.json도 삭제

mqtt 연결하는 방법(중요)

    1. putty 접속 후 vscode에서 가상환경 work - mini - test 실행
    1. 다른 vscode 실행 후 reactwork - 터미널에서 cd mqtt-test
    1. 브로커는 명령 프롬프트 가서
      mosquitto -c "C:\Program Files\mosquitto\mosquitto.conf" -v
    1. 브로커 먼저 키고 2번 가서 npm run dev

구글차트

-- 게이지 쓰기
https://developers.google.com/chart/interactive/docs/gallery/gauge?hl=ko

export const options = {
  width: 400,
  height: 120,
  redFrom: 90,
  redTo: 100,
  yellowFrom: 75,
  yellowTo: 90,
  minorTicks: 5,
};
//센서데이터용 state
  const [sensorData, setSensorData] = useState([
    ["Label", "Value"],
    ["온도", 0],
    ["습도", 0],
  ]);
  
  • 변경 - 위에 sersorData는 지움,

  • import

  • sensorData 연결 작업 - 게이지 사이트에서 복붙


shop
다운받고

다시 복습 해야 할듯
4시반까지 이번주할것의 3번까지 함.


4번 차례 백엔드 흐름

  • 강사님께 들은 거 받아적기만 함. 정리 필요 내부까지
    front-end 가입을 누르면 spring framework로 Dispatcher가 요청을 받고 haddlermapping이 /write를 분석해서 Dispatcher로 컨트롤러 정보를 넘겨줌 그리고 handlerAdaptor에게 넘어가서 controller로 넘어감 그리고 서비스를 요청함 - DAO를 요청 - repository를 요청 그리고 돌면서 JPA 내부에서 entity 매니저를 통해서 JDBC 드라이버를 통해서 DBMS를 동작할 수 있게 함. 결과를 받아서 넘겨주면 handlerAdaptor에게 넘겨주면 화면을 만들어내는게 아니라 데이터만 json으로 프론트엔드로 넘어감 화면에 주는거라면 viewResearcher?로 넘어감.

눈에 보이는 것들만
프론트엔드(리액트) - 컨트롤러 - 서비스 - DAO - JPA면 레포지토리 마이바티스면 mapper - DBMS 테이블 하나를 모델링한 엔티티가 있어야하고 엔티티를 가지고 조회작업을 하거나 반환해야함. - 규모가 작으면 DAO를 없앰. - 엔티티는 왔다갔다하면서 DAO단까지만 있어야 함. 레이어간의 데이터를 주고받는 것은 DTO로 함. 편하게 하기 위한 for문 돌리지 않고 자바의 Stream API를 씀. (자료구조 제어등등)


  • 롬복 사용


    복습 필수 6

12/3 수 - 람다식, stream,

assignment

review


  • 오전에 한 것 프로젝트 만들고 설정

  • 야물파일 수정


시작

  • 이게 있어야 됨 만들어짐
  • 리액트, 컨트롤러 처럼 서버가 분리되있을때
    리액트에서 회원가입하기를 누르면 데이터를 한번에 json으로 보내고 받을 수 있음, controller까지 감

백엔드에서 포스트맨으로 작업하고 단계단계 수정
`

  • http://127.0.0.1:9500/customer/create?userId=bts1&password=1234&name=제이홉&addr=광주&tel=010&info=멋있다.해도 되지만 플랫폼이 다른 경우엔 Json으로 처리됨
    옛날엔 fetch를 썼는데 지금은 엑시오스를 사용해서 자동으로 JSOn으로 변환해줌

  • 컨트롤러에서 DTO 출력하기까진 함 포스트맨으로

  • 그래서 body를 누르고 x-www 파라미터를 넘겨서 처리하세요 (네임은 밸류 네임은 밸류)란 문제가 있었음. 하지만 우린 Json이기 때문에 4번째인 raw선택

  1. 컨트롤러가 service의 메소드를 호출하고 2. 서비스에서 DAO 메소드가 호출되도록
  2. 메소드호출시 타입이 맞지 않으면 null넘기고 메시지만 출력
  • 이제 리액트에서 데이터를 받아와야 함.
    리액트에서 요청 - -컨트롤러 - (DTo) - service - dao - (entity) - repository - insert - DBMS
  1. 서비스에서 시작 @Service
    컨트롤러에서 서비스를 불러와야 함

무조건 리뷰

리액트에서 연결 복습할거

import React, { useState } from "react";
import "./JoinPage.css";
import axios from "axios";
const CustomerInsert = () => {
  const [formData, setFormData] = useState({
    userId: "",
    password: "",
    name: "",
    addr: "",
    tel: "",
    info: "",
  });

  const handleChange = (e) => {
    // console.log(e.target);
    const { name, value } = e.target;
    setFormData({
      ...formData, //기존값 유지 스프레드 연산자
      [name]: value, // value변수 안에 있는 값, [name]은 name변수안에 저장된 값을 꺼내서 키로 사용할 수 있도록 정의
    });
    // console.log(formData);
  };

  //async가 추가된 함수는 비동기로 진행되는 함수이므로 이 함수가 끝날때까지 대기하지 않고 자바스크립트 엔진
  // 다른 작업을 할 수 있도록 정의
  const handleSubmit = async (e) => {
    // asyn추가 Axios 깔고 npm install axios 비동기함수라는 의미
    e.preventDefault();
    console.log("전송할 데이터:", formData);
    // fetch 코드 생략 (이전과 동일)
    //fetch대신 Axios를 사용해서 post로 서버에 요청
    //Axios는 fetch와 동일한 역할을 하지만 자동을 처리되는 기능이 많고, 웹브라우저에 서버에 http요청(서버와 통신)을 위해
    // 사용하는 라이브러리
    //spring boot : http://127.0.0.1:9500/customer/create
    //axios.post메소드는 post방식으로 요청을 하겠다는 의미
    //path와 post로 전달할 데이터를 명시
    //데이터는 자바스크립트객체로 전달하면 axios가 자동으로 json객체로 변환해준다.
    //서버에 요청을 하는 경우 작업이 완료될때까지 다음 단계로 넘어가지 않도록 await를 추가해서 작업한다. 대기하는 앞에 붙여주면 다음으로 넘어가지 않음
    //데이터를 보내지 않고 검증 한 후에 전송
    try {
      const response = await axios.post("http://127.0.0.1:9500/customer/create", formData);
      alert("전송 버튼 클릭됨! (콘솔 확인)");
      //성공적으로 응답을 받으면 처리
      if (response.status === 200) {
        console.log("서버응답:", response.data);
        alert("회원가입이 완료됐습니다.");
      }
    } catch (error) {
      console.error("에러발생:", error);
      alert("회원가입 중 오류가 발생했습니다.");
    }
  };

  return (
    <div className="join-container">
      <h2>회원가입</h2>
      <form onSubmit={handleSubmit}>
        <div className="form-group">
          <label>아이디</label>
          <input
            type="text"
            name="userId"
            value={formData.username}
            onChange={handleChange}
            placeholder="아이디를 입력하세요"
          />
        </div>
        <div className="form-group">
          <label>비밀번호</label>
          <input
            type="password"
            name="password"
            value={formData.password}
            onChange={handleChange}
            placeholder="비밀번호를 입력하세요"
          />
        </div>
        <div className="form-group">
          <label>이름</label>
          <input
            type="text"
            name="name"
            value={formData.name}
            onChange={handleChange}
            placeholder="홍길동"
          />
        </div>
        <div className="form-group">
          <label>주소</label>
          <input
            type="text"
            name="addr"
            value={formData.addr}
            onChange={handleChange}
            placeholder="서울시 강남구..."
          />
        </div>
        <div className="form-group">
          <label>전화번호</label>
          <input
            type="text"
            name="tel"
            value={formData.tel}
            onChange={handleChange}
            placeholder="010-0000-0000"
          />
        </div>
        <div className="form-group">
          <label>기타정보</label>
          <textarea
            name="info"
            value={formData.info}
            onChange={handleChange}
            placeholder="추가로 남길 말을 적어주세요."
          />
        </div>

        <button type="submit" className="submit-btn">
          가입하기
        </button>
      </form>
    </div>
  );
};

export default CustomerInsert;

과제 카테고리 등록 만들어서 dB에 넣는 작업까지

  1. 객체를 생성하고 호출하는 작업을 처리하기

    • CategoryController, CategoryServiceImpl, CategoryDAOImpl을 만들기
    • Controller -> Service -> DAO가 호출되는지 메시지만 출력해서 확인하기
  2. Controller 에 JSON객체를 받을 수 있도록 메소드를 추가하고 포스트맨으로 요청이되는지 확인하기(CustomerController)

  3. 요청이 완료되면 포스트맨으로 입력한 데이터가 디비에 insert되도록 코드 수정하기

  4. 리액트에서 입력한 값이 디비에 insert되도록 컨트롤러를 요청하기

12/4 목 - DB데이터를 조회해서 리액트에 리스트로 출력, 조회, 검색

assignment

review


디비데이터를 조회해서 리액트에 리스트로 출력
 [step1]
    1. 컨트롤러, 서비스 DAO를 구성한다.
             컨트롤러 -> 서비스 -> DAO요청시 요청이 되는지 확인(단순 메시지 출력)
    2. DBMS의 데이터가 조회되도록 처리
     - DAO에서 조회된 List<Product>  를 서비스로 넘겨줄때(리턴할때) List<ProductResponse>로 변환하는 작업     
                                   --------------
                                 엔티티
     ModelMapper를 이용해서 변환, Stream API를 이용해서 작업
     - 서비스메소드 :     public List<ProductResponse> findAll() {
     - DAO : public List<Product> findAll();
         컨트롤러: 메소드추가
     3. 컨트롤러에서 List<ProductResponse>를 리턴하도록
     4. 포스트맨에서 확인 

  • 오후에 진행할 내용

    • 순서대로
    1. 전체상품목록
    2. 상품번호로 상품상세조회
    3. 검색까지 함.
  • hook을 쓰는 경우 내부에서 hook을 쓰는경우(use붙어있는것들), 컨포넌트 상단에 정의하고 사용함

  • client.js 만듦. 이름을 아무거나 만듦.

검색 기능에서
JPA 메소드 웹페이지

  • parameter를 포함하는 것을 가져오는 것

  • 오후에 한것
  • 상품 카테고리를 눌렀을때
  • 상품을 누르면 상세 설명이 나옴 (미션1)
  • 정보에 검색어를 치면 검색어가 들어가 있는 정보만 나옴 (미션2)
디비데이터를 조회해서 리액트에 리스트로 출력
 [step1]
    1. 컨트롤러, 서비스 DAO를 구성한다.
             컨트롤러 -> 서비스 -> DAO요청시 요청이 되는지 확인(단순 메시지 출력)
    2. DBMS의 데이터가 조회되도록 처리
     - DAO에서 조회된 List<Product>  를 서비스로 넘겨줄때(리턴할때) List<ProductResponse>로 변환하는 작업     
                                   --------------
                                     엔티티
     ModelMapper를 이용해서 변환, Stream API를 이용해서 작업
     - 서비스메소드 : public List<ProductResponse> findAll() {
     - DAO : public List<Product> findAll();
         컨트롤러: 메소드추가
     3. 컨트롤러에서 List<ProductResponse>를 리턴하도록
     4. 포스트맨에서 확인 

     [오류 발생시!!]
     product 테이블을 삭제하고 schema.sqll에 컬럼명 변경한 후 다시 실행되도록 작업
	insert_time DATETIME DEFAULT CURRENT_TIMESTAMP

[step2]
1. 서버와 통신할 수 있도록 productAPI.js 만들고 requests.js에 /product/list추가
2. 조회된 결과를 출력할  수 있도록 ProductList와 Product를 수정
=> 결과화면 캡쳐 후 제출

3. 완료되면 어제 미션으로 해결한 카테고리등록 부분도 API로 빼기
   productAPI.js에 추가하기

상품상세보기
 1. 매개변수로 전달되는 productNo와 일치하는 데이터를 조회
 2. Controller -> Service -> DAO로 호출될 수 있도록 작업
 3. DBMS에서 조회하기
 4. 서비스에서
   DAO 호출결과로 받은 Entity를 ProductResponse로 변환
 5. 컨트롤러에 메소드 추가
   path : /product/read
   파라미터: productNo 
 6. 포스트맨으로 테스트

프론트작업 - 항상 부모에서 자식을 전달
  - requests.js에서 path추가
  - XXXXAPI.j에서 서버통신
  - 컴포넌트에서 통신호출
  - 결과로 뷰 만들기 

검색하기
 - /product/search로 작업하기
 - 검색어를 입력하고 서버와 통신
  - DAO에서 List <Product> findBySearch(String search); 가 실행되도록
    => info컬럼에서 like연산자로 동작하도록
	select*from product where info like '%여성%'
    DAO에서는 Repository의 List <Product> findBySearch(String search);를 호출
- Service에서 DAO의 메소드 호출결과를 변경
- 컨트롤러에서 메소드 추가
  List<ProductResponse> 리턴, 매개변수로 검색키워드 받기

- 리액트에서 통신 결과를 ProductList에서 출력되도록 처리
결과는 블로그에서 확인 

백엔드작업 - 포스트맨확인 - 통신 - 통신결과 console로 출력 - 통신결과 화면에 출력

리액트에서 요청해서 백엔드에서 통신하는 과정 CLR까지 함.

Review

  • 상품을 누르면 상세 설명이 나옴 (미션1)
    백엔드작업 - 포스트맨확인 - 통신 - 통신결과 console로 출력 - 통신결과 화면에 출력

  • 정보에 검색어를 치면 검색어가 들어가 있는 정보만 나옴 (미션2)

    • 순서
      = 백엔드작업 - 포스트맨확인 - 통신 - 통신결과 console로 출력 - 통신결과 화면에 출력

      • 백엔드
      1. ProductRepository
        = DB product 테이블에서 info 컬럼에 search가 포함된 레코드들을 조회하는 SQL을 자동 생성해주는 JPA 메소드

      2. ProductDAOImpl
        = DAO는 Repository에게 DB 조회를 요청하고, 조회된 엔티티(List<Product>)를 그 상태 그대로 Service에게 넘긴다.

      3. ProductServiceImpl
        = Service는 DAO가 준 엔티티(Product)를 화면에 전달 가능한 JSON 형태(ProductResponse DTO)로 변환해서 Controller에게 전달한다.(modelMapper 사용)

      4. ProductController
        = Controller는 Service에서 받은 DTO 리스트를 그대로 JSON으로 변환해 프론트엔드(React)에 응답으로 보낸다.

  • 리액트


12/5 금 - 스프링 시큐리티

assignment

review


  • 4ro qodna

  • 강사님이 프로젝트 파일을 줌

뷰 -(필터가 추가됨)- 서블릿 - 컨트롤러

필터체인 - 실행해야 하는 필터의 목록들 (객체로 표현)

  • 포트번호가 이미 있다고 뜸 이럴땐 작업관리자에서 오픈jdk바이너리를 종료

  • 시큐리티를 등록함으로써 내부에 인증 시스템이 돌아감 나중엔 토큰으로 넘어감

  • 기본 SecurityFillerChain
  • 체인을 따로 만들어서 실행

    • 로그인은 했지만 접근권한이 없을때 403
  • 설정 파일 disable 걸어놓고 하면 기본과 달라진 걸 확인

  • 미션 springshop에서 작업하기

    • /customer/create는 관리자권한을 갖고 있는 사용자가 접근할 수 있도록
    • /product는 user권한을 갖고 있는 사용자가 접근할 수 있도록
    • 메모리유저로 로그인처리
      (springsecurity)프로젝트와 동일한 유저와 관리자로 작업
    1. 먼저 gradle 들어가서 spring security 추가
    2. config 폴더에 securityConfig 파일 생
    3. 전에 했던 거 보면서 작성

- 흐름 이해 중요! 복기!!!!!!!!!!!!!!!!!!!!!!!!!!!

  • 이번 프로젝트는 액세스 토큰만 다음프로젝트때는 리프레쉬 토큰 까지 쓸 수 있어야 한다

  • 이 구조도 복습, sampleentity는 주신 파일


순서 암호화하는 순서




  • Spring security랑 똑같이 하는 건데
    • pk(generate_id)로 조회하는 작업을 하고 폼로그인 이용해서 로그인 패스워드 입력 내 DB에서 비교해서 로그인이 되야 함 userdetail 커스터마이징
    • 클래스 커스터머, 커스터머디테일 2개 만들어야 함. 커스터머는 서비스에다가 넣고 커스터머디테일 DTO에다가 만들지말고 넣으면 됨.

초기설정

  1. 프로젝트 체크
    - gradle build tool에서 Intellij IDEA 선택
    - JDK버전체크(17)
    - utf-8인코딩체크
    - devtool
    setting에서 체크
    - 롬복체크
    라이브러리추가
    셋팅 - annotationProcessor 체크
    rebuild
    => build.gradle에 annotationProcessor 'org.projectlombok:lombok' 추가 확인

0개의 댓글