팀 프로젝트 공통 템플릿 만들기 프론트엔드와 백엔드 환경 설정(인텔리제이에 리액트와 스프링부트 연결하기)

GoldenDusk·2023년 9월 17일
2
post-thumbnail

1. 인텔리제이에 기본 설정

🧐 프론트앤드(리액트), 백엔드(스프링 부트) 설정방법

  1. 일단 스프링 부트로 하나 만들어주기

  1. 스프링 부트 안에 리액트 설치 하기

  1. 버전 다운그레이드 리액트 16.14 버전으로 맞추기

  1. 그 후 문제 해결

🔗 https://homubee.tistory.com/36

  • index.js 바꿔주기
import React from 'react';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import ReactDOM from 'react-dom';

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

// 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();
  • 안된다면 2안
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

ReactDOM.render(<App />, document.getElementById("root"));
  1. 리액트에 프록시 설정
  • package.json 파일에 "script" 윗 부분에
"proxy": "http://localhost:8080",
  1. 스프링 부트 build.gradle 하단에 코드 작성
  • 꼭 plugins 아래에 넣기
def reactDir = "$projectDir/src/main/frontend";

sourceSets{
    main{
        resources{
            srcDirs = ["$projectDir/src/main/resources"]
        }
    }
}

processResources{
    dependsOn "copyReactBuildFiles"
}

task installReact(type:Exec){
    workingDir "$reactDir"
    inputs.dir "$reactDir"
    group = BasePlugin.BUILD_GROUP

    if(System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')){
        commandLine "npm.cmd", "audit", "fix"
        commandLine 'npm.cmd', 'install'
    }else{
        commandLine "npm", "audit", "fix"
        commandLine 'npm', 'install'
    }
}

task buildReact(type:Exec){
    dependsOn "installReact"
    workingDir "$reactDir"
    inputs.dir "$reactDir"
    group = BasePlugin.BUILD_GROUP

    if(System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')){
        commandLine "npm.cmd", "run-script", "build"
    }else{
        commandLine "npm", "run-script", "build"
    }
}

task copyReactBuildFiles(type:Copy){
    dependsOn "buildReact"
    from "$reactDir/build"
    into "$projectDir/src/main/resources/static"
}
  1. application.properties
server.port=8080

2. 그렇다면 어떻게 쓰는데..? 어떻게 통신해?

🧐 부트캠프는 왜 따로 따로 알려주는 것인가…

우리는 백엔드 과정이니 그럴 수 있긴 한데…. 프로젝트 때 알려주면 좋을 텐데 나도 큰 틀을 못잡아서… 고민해보고 서치해봤다…

🧐 분리하는 이유가 뭔데…?

  • 팀 프로젝트에서 백엔드와 프론트엔드를 분리하는 것은 일반적인 방법
  • 스프링 부트 자체에는 리액트 환경을 설정하는 기능은 없으며, 두 개의 서버를 분리해서 실행하게 된다.
  • 프론트엔드와 백엔드 간에 HTTP 요청 를 통해 통신하면 됨

🧐 프론트엔드와 백엔드 통합

  • 백엔드와 프론트엔드는 서로 통신해야 한다. REST API또는 GraphQL을 사용하여 데이터를 주고받을 수 있다.
  • 프론트엔드에서는 백엔드 서버의 API 엔드포인트를 호출하여 데이터를 가져올 수 있다.

🍇 REST API (Representational State Transfer API)란?

  • REST는 HTTP를 기반으로 한 아키텍처 스타일로, 클라이언트와 서버 간의 통신을 위한 규칙을 정의
  • RESTful API는 자원(리소스)을 URL로 표현하고 HTTP 동사(GET, POST, PUT, DELETE 등)를 사용하여 해당 자원을 조작
  • 예를 들어, /users 엔드포인트로 GET 요청을 보내면 모든 사용자 목록을 가져올 수 있다.

**프론트엔드와 백엔드 간의 통신 예제 (React 및 Spring Boot를 사용한 회원가입)**

이 코드 예제에서 React 애플리케이션은 회원가입을 위해 /api/signup 엔드포인트로 POST 요청을 보내며, Spring Boot 백엔드는 해당 요청을 처리합니다. 이렇게하여 프론트엔드와 백엔드 간의 통신

  1. 백엔드 (Spring Boot) - REST API 설정:
    • Spring Boot를 사용하여 회원가입을 처리하는 RESTful API를 만듭니다. 예를 들어, /api/signup 엔드포인트를 만들어 새로운 사용자를 등록합니다.
```java
javaCopy code
@RestController
@RequestMapping("/api")
public class UserController {
    @Autowired
    private UserService userService;

    @PostMapping("/signup")
    public ResponseEntity<?> signUp(@RequestBody UserDto userDto) {
        userService.registerUser(userDto); // 사용자 등록 로직
        return ResponseEntity.ok("회원가입이 성공적으로 완료되었습니다.");
    }
}

```
  1. 프론트엔드 (React) - REST API 호출

  • React 애플리케이션에서 회원가입을 위한 REST API를 호출합니다. Axios 또는 fetch와 같은 HTTP 클라이언트를 사용하여 백엔드에 POST 요청을 보냅니다.
import React, { useState } from 'react';
import axios from 'axios';

function SignUp() {
    const [formData, setFormData] = useState({
        username: '',
        email: '',
        password: ''
    });

    const handleInputChange = (e) => {
        const { name, value } = e.target;
        setFormData({ ...formData, [name]: value });
    };

    const handleSubmit = async (e) => {
        e.preventDefault();
        try {
            await axios.post('/api/signup', formData); // 백엔드 API 호출
            console.log('회원가입 성공');
        } catch (error) {
            console.error('회원가입 실패:', error);
        }
    };

    return (
        <div>
            <h2>회원가입</h2>
            <form onSubmit={handleSubmit}>
                <input
                    type="text"
                    name="username"
                    value={formData.username}
                    onChange={handleInputChange}
                    placeholder="사용자 이름"
                />
                <input
                    type="email"
                    name="email"
                    value={formData.email}
                    onChange={handleInputChange}
                    placeholder="이메일 주소"
                />
                <input
                    type="password"
                    name="password"
                    value={formData.password}
                    onChange={handleInputChange}
                    placeholder="비밀번호"
                />
                <button type="submit">가입하기</button>
            </form>
        </div>
    );
}

export default SignUp;

🍇 GraphQL

  • GraphQL은 클라이언트가 필요한 데이터를 정확하게 요청할 수 있는 쿼리 언어
  • 클라이언트가 쿼리를 작성하여 서버에 전송하면 서버는 해당 쿼리에 대한 데이터만 응답
  • 이러한 특징으로 인해 과도한 데이터 요청을 방지하고 클라이언트와 서버 간의 효율적인 통신을 가능하게 한다.

이 코드 예제에서 React 애플리케이션은 Apollo Client를 사용하여 GraphQL을 호출하고, Spring Boot 백엔드는 GraphQL 쿼리를 처리합니다. 이를 통해 프론트엔드와 백엔드 간의 효율적인 데이터 통신이 가능합니다. GraphQL을 사용하면 클라이언트가 필요한 데이터를 정확하게 요청하고 반환받을 수 있으므로 데이터 관리 및 효율성이 향상됩니다.

✍️ 백엔드 (Spring Boot) - GraphQL 설정

  1. Spring Boot 프로젝트에 GraphQL 관련 의존성을 추가합니다. Maven을 사용하는 경우 pom.xml에 다음 의존성을 추가하세요:
xmlCopy code
<dependencies>
    <!-- Spring Boot GraphQL Starter -->
    <dependency>
        <groupId>com.graphql-java-kickstart</groupId>
        <artifactId>graphql-spring-boot-starter</artifactId>
    </dependency>
    <!-- GraphQL Java Tools (Schema 정의 및 리졸버) -->
    <dependency>
        <groupId>com.graphql-java</groupId>
        <artifactId>graphql-java-tools</artifactId>
    </dependency>
</dependencies>
  1. GraphQL 스키마와 리졸버를 정의합니다. 스키마는 graphqls 파일로 정의하고, 리졸버는 Java 클래스로 작성합니다.
graphqlCopy code
# src/main/resources/graphql/schema.graphqls

type User {
    id: ID!
    username: String!
    email: String!
    # 다른 필드 추가
}

type Mutation {
    signUp(username: String!, email: String!, password: String!): User
}
javaCopy code
// GraphQL 리졸버 (예시)
@Component
public class UserResolver implements GraphQLMutationResolver {
    public User signUp(String username, String email, String password) {
        // 사용자 등록 로직
        // 실제 로직에 따라 사용자를 등록하고 반환합니다.
        User user = new User();
        user.setId(UUID.randomUUID().toString());
        user.setUsername(username);
        user.setEmail(email);
        // 비밀번호 등 추가 필드 설정

        return user;
    }
}

✍️ 프론트엔드 (React) - GraphQL 클라이언트 설정

  1. React 프로젝트에 GraphQL 클라이언트 라이브러리를 추가합니다. 가장 널리 사용되는 Apollo Client를 예로 들겠습니다.
bashCopy code
npm install @apollo/client graphql
  1. GraphQL API 엔드포인트와 스키마를 설정합니다. Apollo Client를 사용하는 경우 ApolloProvider를 사용하여 클라이언트를 초기화합니다.
jsxCopy code
// src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client';
import App from './App';

const client = new ApolloClient({
    uri: '/graphql', // 백엔드 GraphQL API 엔드포인트
    cache: new InMemoryCache(),
});

ReactDOM.render(
    <ApolloProvider client={client}>
        <App />
    </ApolloProvider>,
    document.getElementById('root')
);
  1. GraphQL 쿼리를 작성하여 백엔드에서 데이터를 요청합니다.
jsxCopy code
// src/components/SignUp.js

import React, { useState } from 'react';
import { useMutation, gql } from '@apollo/client';

const SIGN_UP = gql`
    mutation SignUp($username: String!, $email: String!, $password: String!) {
        signUp(username: $username, email: $email, password: $password) {
            id
            username
            email
            # 다른 필드 추가
        }
    }
`;

function SignUp() {
    const [formData, setFormData] = useState({
        username: '',
        email: '',
        password: '',
    });

    const [signUp] = useMutation(SIGN_UP);

    const handleInputChange = (e) => {
        const { name, value } = e.target;
        setFormData({ ...formData, [name]: value });
    };

    const handleSubmit = async (e) => {
        e.preventDefault();
        try {
            const { data } = await signUp({
                variables: formData,
            });
            console.log('회원가입 성공:', data.signUp);
        } catch (error) {
            console.error('회원가입 실패:', error);
        }
    };

    return (
        <div>
            <h2>회원가입</h2>
            <form onSubmit={handleSubmit}>
                <input
                    type="text"
                    name="username"
                    value={formData.username}
                    onChange={handleInputChange}
                    placeholder="사용자 이름"
                />
                <input
                    type="email"
                    name="email"
                    value={formData.email}
                    onChange={handleInputChange}
                    placeholder="이메일 주소"
                />
                <input
                    type="password"
                    name="password"
                    value={formData.password}
                    onChange={handleInputChange}
                    placeholder="비밀번호"
                />
                <button type="submit">가입하기</button>
            </form>
        </div>
    );
}

export default SignUp;

🧐 배포

  • 백엔드와 프론트엔드는 독립적으로 배포됩니다. 백엔드는 스프링 부트 애플리케이션으로, 프론트엔드는 정적 파일로 호스팅할 수 있습니다.

🧐 그렇다면 백엔드를 서버로 올린다는 것은 뭘까?

백엔드를 서버로 올린다는 것은 백엔드 애플리케이션을 실행하고, 외부에서 접근할 수 있도록 인터넷에 연결된 컴퓨터 또는 서버에 배포(deploy)하는 과정을 의미합니다. 이것은 실제로 사용자와 상호작용하고 데이터를 처리하는 서비스를 제공하기 위해 필요한 단계입니다.

🍇 백엔드를 서버로 올리는 과정

  1. 서버 선택: 백엔드 애플리케이션을 호스팅할 서버를 선택합니다. 이 서버는 온라인으로 항상 실행 중인 컴퓨터 또는 클라우드 서비스(예: AWS, Azure, Google Cloud)일 수 있습니다.
  2. 서버 환경 설정: 선택한 서버에 운영체제(OS)를 설치하고 필요한 소프트웨어(Java, Node.js, 스프링 부트 등)를 설치하여 백엔드 애플리케이션을 실행할 환경을 설정합니다.
  3. 애플리케이션 배포: 백엔드 애플리케이션 코드와 모든 종속성을 서버로 복사합니다. 이를 통해 서버에서 애플리케이션을 실행할 수 있게 됩니다.
  4. 웹 서버 구성: 백엔드 애플리케이션을 외부에서 접근 가능하게 하기 위해 웹 서버(예: Apache, Nginx)를 구성합니다. 이 웹 서버는 클라이언트(웹 브라우저)와 백엔드 애플리케이션 간의 트래픽을 관리합니다.
  5. 도메인 구성: 도메인 네임을 구입하거나 기존 도메인을 연결하여 사용자가 애플리케이션에 쉽게 접근할 수 있도록 설정합니다.
  6. 보안 구성: 백엔드 서버와 데이터베이스에 보안을 적용하여 무단 액세스를 방지하고 사용자 데이터를 안전하게 보호합니다.
  7. 서비스 시작: 백엔드 애플리케이션을 서버에서 시작하고, 클라이언트(프론트엔드) 애플리케이션과 통신 가능하게 만듭니다.
  8. 모니터링 및 유지보수: 서버와 애플리케이션의 상태를 모니터링하고 필요한 경우 유지보수 및 업데이트 작업을 수행하여 서비스의 원할한 운영을 보장합니다.

🧐 흠… 우리는 팀프로젝트 작업을 해야하는데 돌아가는 코드는 로컬(내 컴퓨터에서) 톰캣으로 한다고 해도 데이터베이스는 공유해야 하는데 이걸 어떻게 해야할까..?

팀 프로젝트를 진행할 때 데이터베이스를 어떻게 공유하고 사용하는지에 대한 몇 가지 옵션이 있습니다. 데이터베이스를 공유하려면 팀원들 간에 데이터베이스 접근 권한 및 연결 정보를 공유해야 합니다. 일반적으로 다음과 같은 방법을 사용합니다:

  1. 공용 데이터베이스 서버 사용 (온프레미스 또는 클라우드):
    • AWS RDS (Amazon Relational Database Service): AWS RDS를 사용하여 공용 데이터베이스를 호스팅할 수 있습니다. 팀원들은 AWS RDS 인스턴스에 액세스 권한을 부여받아 데이터베이스에 접근할 수 있습니다.
    • 로컬 데이터베이스: 팀원 중 하나가 로컬 데이터베이스를 호스팅하고 다른 팀원들에게 접근 권한을 부여할 수 있습니다. 이 경우, 데이터베이스 호스트 및 포트 정보를 공유해야 합니다.
  2. 데이터베이스 백업 및 동기화:
    • 데이터베이스의 백업과 동기화를 통해 팀원 간에 데이터 일관성을 유지할 수 있습니다. 주기적으로 데이터베이스를 백업하고 백업 파일을 팀원들에게 전달하여 데이터 손실을 방지합니다.
  3. 환경 변수 및 보안 설정:
    • 데이터베이스 연결 정보와 비밀번호와 같은 민감한 정보는 환경 변수나 비밀 관리 도구를 사용하여 안전하게 관리해야 합니다. 이를 통해 보안을 유지하고 데이터베이스 액세스를 보호할 수 있습니다.
  4. API 및 데이터베이스 엔드포인트 정의:
    • 백엔드 개발자는 데이터베이스와 상호 작용하기 위한 API 엔드포인트를 정의해야 합니다. 이 엔드포인트를 사용하여 프론트엔드에서 데이터베이스에 액세스할 수 있습니다.

🍇 AWS RDS (Amazon Relational Database Service) 사용하는 방법

1. AWS 계정 생성 및 로그인:

AWS 계정이 없는 경우 AWS 웹 사이트에서 계정을 생성하고 로그인합니다.

2. AWS 콘솔에 로그인:

AWS 계정으로 로그인한 후 AWS 관리 콘솔에 액세스합니다.

3. RDS 대시보드로 이동:

AWS 콘솔에서 "RDS"를 검색하거나, "데이터베이스" 항목을 클릭하여 RDS 대시보드로 이동합니다.

4. 데이터베이스 인스턴스 생성:

  • "데이터베이스 인스턴스 생성" 버튼을 클릭하여 새로운 데이터베이스 인스턴스를 생성합니다.
  • "엔진 옵션"에서 MySQL 또는 원하는 관계형 데이터베이스 엔진을 선택합니다.
  • "프리 티어 사용" 옵션을 선택하면 무료 티어에서 데이터베이스 인스턴스를 생성할 수 있습니다.

5. 인스턴스 설정 구성:

  • "인스턴스 식별자" 및 "마스터 사용자 이름"을 설정합니다. 이것은 데이터베이스 인스턴스에 대한 고유한 이름과 마스터 사용자의 이름입니다.
  • "마스터 암호"를 생성하고 안전하게 보관하세요.

6. 데이터베이스 설정 구성:

  • "데이터베이스 이름"을 지정하고 필요한 설정을 구성합니다.
  • "퍼블릭 액세스 가능성"을 제어하고 필요한 경우 VPC(Virtual Private Cloud) 설정을 구성합니다.

7. 보안 그룹 및 VPC 설정:

  • 데이터베이스 인스턴스에 대한 보안 그룹 및 VPC 설정을 구성하여 액세스 제어를 설정합니다. 보안 그룹을 통해 특정 IP 주소나 범위에서만 데이터베이스에 액세스할 수 있도록 할 수 있습니다.

8. 추가 구성 및 옵션 설정:

  • 필요한 경우 데이터베이스 인스턴스의 추가 구성 및 옵션을 설정합니다. 이 단계에서는 데이터베이스 인스턴스의 성능 및 백업 설정 등을 구성할 수 있습니다.

9. 인스턴스 생성 및 대기:

  • 설정을 완료하면 "인스턴스 생성" 또는 "시작" 버튼을 클릭하여 데이터베이스 인스턴스를 생성하고 대기합니다. 이 과정은 몇 분 정도 걸릴 수 있습니다.

10. 연결 정보 확인:

  • 데이터베이스 인스턴스가 생성되면 해당 인스턴스의 연결 정보를 확인할 수 있습니다. 이 정보에는 엔드포인트 주소, 포트 번호, 마스터 사용자 이름 등이 포함됩니다.

11. 데이터베이스에 연결:

  • 데이터베이스 클라이언트 도구 또는 프로그래밍 언어를 사용하여 데이터베이스에 연결합니다. 연결 정보를 사용하여 데이터베이스에 접속할 수 있습니다.

12. 데이터베이스 사용:

  • 이제 데이터베이스에 연결되었으므로 테이블을 생성하고 데이터를 삽입, 조회, 수정, 삭제 등의 작업을 수행할 수 있습니다.

위 단계를 따라 AWS RDS를 사용하여 MySQL 또는 다른 관계형 데이터베이스를 생성하고 관리할 수 있습니다. 보안 및 성능 관리를 위해 AWS RDS의 다양한 설정 및 옵션을 활용할 수 있습니다. 필요에 따라 데이터베이스 백업 및 복원을 설정하여 데이터의 안전성을 유지할 수도 있습니다.

🍇 로컬 데이터베이스 사용 방법

1. 데이터베이스 시스템 선택:

로컬 환경에서 사용할 데이터베이스 시스템을 선택합니다. 아래는 몇 가지 인기있는 옵션입니다.

  • SQLite: 가벼운 파일 기반 데이터베이스로, 설치 및 설정이 간단하며 작은 프로젝트에 적합합니다.
  • MySQL 또는 PostgreSQL: 무료로 사용할 수 있는 오픈 소스 관계형 데이터베이스 시스템입니다. 프로젝트의 규모와 요구 사항에 따라 선택합니다.
  • MongoDB: NoSQL 데이터베이스로, 비정형 데이터 및 대량 데이터를 다루는 데 적합합니다.

2. 데이터베이스 설치:

선택한 데이터베이스 시스템을 로컬 컴퓨터에 설치합니다. 데이터베이스 공식 웹 사이트에서 설치 파일과 설치 가이드를 다운로드할 수 있습니다.

3. 데이터베이스 설정:

데이터베이스를 설치한 후에는 초기 설정을 수행해야 합니다. 설정에는 다음이 포함됩니다.

  • 데이터베이스 서버 시작: 데이터베이스 서버를 시작하여 데이터베이스에 액세스할 수 있도록 합니다.
  • 관리자 계정 설정: 관리자 계정(예: root 또는 postgres)을 설정하고 암호를 지정합니다.
  • 데이터베이스 생성: 필요한 데이터베이스를 생성합니다.
  • 사용자 및 권한 설정: 데이터베이스에 액세스할 수 있는 사용자를 만들고 액세스 권한을 부여합니다.

4. 데이터베이스 클라이언트 도구 설치:

데이터베이스를 관리하고 쿼리를 실행하기 위한 데이터베이스 클라이언트 도구를 설치합니다. 이 도구는 데이터베이스와 상호 작용할 때 사용됩니다.

5. 애플리케이션과 연동:

로컬 데이터베이스를 사용하려면 애플리케이션 코드에서 데이터베이스에 연결하고 데이터를 읽고 쓸 수 있어야 합니다. 데이터베이스 연결을 설정하고 SQL 또는 NoSQL 쿼리를 실행하여 데이터를 조작합니다.

예를 들어, Java 프로젝트에서 MySQL 데이터베이스를 사용하려면 JDBC(Java Database Connectivity) 드라이버를 사용하여 데이터베이스에 연결하고 SQL 쿼리를 실행합니다.

다른 프로그래밍 언어와 데이터베이스 시스템을 사용하는 경우 해당 언어 또는 데이터베이스에 맞는 라이브러리 또는 드라이버를 설치하고 연동하는 방법을 학습해야 합니다.

로컬 데이터베이스 설정은 프로젝트의 규모와 요구 사항에 따라 달라질 수 있으며, 데이터베이스 종류 및 개발 환경에 따라 다양한 설정이 가능합니다.

3. 테스트 중

🍇 JPA H2 설정

  1. build.gradle 설정 해주기 dependencies에 넣어주기
// 스프링 데이터 베이스 JPA
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    compileOnly 'org.projectlombok:lombok' // 롬북
    runtimeOnly 'com.h2database:h2' //인메모리 데이터베이스
    annotationProcessor 'org.projectlombok:lombok'
  1. main > resources > application.yml을 만들어서 jpa 및 데이터 베이스 설정
  • h2 console도 해주면 localhost 돌아갈 때 데이터베이스 잘 저장되었는지 확인가능
  • 하지만 이건 영구 저장이 아니라는 점 알아두자

spring:
  jpa:
    show-sql: true
    open-in-view: false
    properties:
      hibernate:
        format_sql: true
    defer-datasource-initialization: true

  datasource:
    url: jdbc:h2:mem:testdb
  h2:
    console:
      enabled: true

3. 꼭… 자바 파일은 패키지 안에 넣어주자

  • 하루종일 걸린 에러가!!!!! 데이터베이스 안만들어지는게!!!! 패키지를 안에 안 집어넣어서 였다니
  • 수정전

  • 수정후

  • 통신도 됨(postman)

🍇 리액트와 서버 통신용 테스트 코드

  1. 테스트 용 코드들 리액트 : ArticleForm.js
import React, { useState } from 'react';
import axios from 'axios';

function ArticleForm() {
    const [title, setTitle] = useState('');
    const [content, setContent] = useState('');

    const handleSubmit = async (e) => {
        e.preventDefault();

        try {
            const response = await axios.post('http://localhost:8080/api/articles', {
                title: title,
                content: content
            });

            if (response.status === 201) {
                console.log('Article added successfully', response.data);
                // 기타 로직 (예: 폼 초기화, 알림 표시 등)
                setTitle('');
                setContent('');
            }
        } catch (error) {
            console.error('Error adding article', error);
        }
    };

    return (
        <div>
            <form onSubmit={handleSubmit}>
                <div>
                    <label>Title:</label>
                    <input
                        type="text"
                        value={title}
                        onChange={(e) => setTitle(e.target.value)}
                    />
                </div>
                <div>
                    <label>Content:</label>
                    <textarea
                        value={content}
                        onChange={(e) => setContent(e.target.value)}
                    />
                </div>
                <button type="submit">Submit</button>
            </form>
        </div>
    );
}

export default ArticleForm;
  1. 패키지 설정

  1. controller ⇒ 여기 주소와 리액트 주소가 일치해야 한다는 것
package com.example.teamproject_test_1.controller;

import com.example.teamproject_test_1.domain.Article;
import com.example.teamproject_test_1.dto.AddArticleRequest;
import com.example.teamproject_test_1.service.BlogService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController //HTTP Response Body에 객체 데이터를 json형식을 반환하는 컨트롤러
public class BlogApiController {
    private final BlogService blogService;

    @PostMapping("/api/articles")
    public ResponseEntity<Article> addArticle(@RequestBody AddArticleRequest request){
        Article saveAritcle = blogService.save(request);

        return ResponseEntity.status(HttpStatus.CREATED).body(saveAritcle);
    }
}
  1. domain ⇒ 데이터 베이스 엔터티
package com.example.teamproject_test_1.domain;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity // JPA 엔터티 클래스임을 나타내는 어노테이션
@Getter // Lombok 어노테이션으로, 모든 필드에 대한 Getter 메서드를 자동으로 생성
@NoArgsConstructor(access = AccessLevel.PROTECTED) // Lombok으로 생성된 기본 생성자를 protected 접근 지정자로 생성
public class Article {
    @Id // 엔터티의 주요 키(primary key)를 나타내는 어노테이션
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 자동으로 값을 생성하도록 지정하는 어노테이션, 기본 설정대로 자동 생성
    @Column(name="id", updatable = false) // 엔터티의 필드와 데이터베이스 컬럼 간의 매핑을 지정하는 어노테이션
    private Long id;

    @Column(name="title", nullable=false)
    private String title;

    @Column(name="content", nullable = false)
    private String content;

    @Builder //Lombok으로 생성자를 자동으로 생성하는데, 빌더 패턴을 활용하여 객체를 생성
    public Article(String title, String content){
        this.title = title;
        this.content=content;
    }

    /*new Article("abc", "aaaaaa"); //빌더 패턴을 적용하지 않고 객체 생성*/

    /*Article.builder().title("abc").content("def").build(); //빌더패턴 적용*/
}
  1. dto
package com.example.teamproject_test_1.dto;

import com.example.teamproject_test_1.domain.Article;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor //기본 생성자를 자동으로 생성
@AllArgsConstructor //모든 필드를 파라미터로 받는 생성자를 자동으로 생성
@Getter
public class AddArticleRequest {
    private String title;

    private String content;

    public Article toEntity(){ //DTO(데이터 전송 객체)에서 엔터티로 변환하기 위한 메서드를 제공
        return Article.builder().title(title).content(content).build();
    }
}
  1. repository
package com.example.teamproject_test_1.repository;

import com.example.teamproject_test_1.domain.Article;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BlogRepository extends JpaRepository<Article, Long> {
}
  1. service
package com.example.teamproject_test_1.service;

import com.example.teamproject_test_1.domain.Article;
import com.example.teamproject_test_1.dto.AddArticleRequest;
import com.example.teamproject_test_1.repository.BlogRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor //final 붙거나 @NotNull이 붙은 필드의 생성자 추가
@Service // 해당 빈을 서블릿 컨테이너에 등록
public class BlogService {

    private final BlogRepository blogRepository;

    public Article save(AddArticleRequest request){
        return blogRepository.save(request.toEntity());
    }

}

🍇 결과

  1. 데이터베이스 테이블 자동 생성
  1. 글쓰면 통신됨

  1. localhost:8080/h2-consol에 들어가 잘 데이터베이스가 들어갔는지 확인
  • url은 application.yml에 설정해둔 것으로

  • 두 번째 테스트

회고

주말에 아르바이트 끝나고 생각보다 다운그레이드로 인해 문제생기기도 하고 이래서ㅠㅠㅠㅠ 좀 걸렸지만 완성해서 팀원들한테도 카톡보냈다 ㅠㅠㅠㅠㅠ

팀원들한테 공유

완성샷

  • 크기가 줄어들면
profile
내 지식을 기록하여, 다른 사람들과 공유하여 함께 발전하는 사람이 되고 싶다. gitbook에도 정리중 ~

0개의 댓글