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();
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
package.json
파일에 "script" 윗 부분에"proxy": "http://localhost:8080",
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"
}
server.port=8080
우리는 백엔드 과정이니 그럴 수 있긴 한데…. 프로젝트 때 알려주면 좋을 텐데 나도 큰 틀을 못잡아서… 고민해보고 서치해봤다…
HTTP 요청
를 통해 통신하면 됨REST API
또는 GraphQL
을 사용하여 데이터를 주고받을 수 있다./users
엔드포인트로 GET 요청을 보내면 모든 사용자 목록을 가져올 수 있다.**프론트엔드와 백엔드 간의 통신 예제 (React 및 Spring Boot를 사용한 회원가입)**
이 코드 예제에서 React 애플리케이션은 회원가입을 위해
/api/signup
엔드포인트로 POST 요청을 보내며, Spring Boot 백엔드는 해당 요청을 처리합니다. 이렇게하여 프론트엔드와 백엔드 간의 통신
- 백엔드 (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("회원가입이 성공적으로 완료되었습니다.");
}
}
```
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;
이 코드 예제에서 React 애플리케이션은 Apollo Client를 사용하여 GraphQL을 호출하고, Spring Boot 백엔드는 GraphQL 쿼리를 처리합니다. 이를 통해 프론트엔드와 백엔드 간의 효율적인 데이터 통신이 가능합니다. GraphQL을 사용하면 클라이언트가 필요한 데이터를 정확하게 요청하고 반환받을 수 있으므로 데이터 관리 및 효율성이 향상됩니다.
✍️ 백엔드 (Spring Boot) - GraphQL 설정
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>
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 클라이언트 설정
bashCopy code
npm install @apollo/client graphql
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')
);
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 계정 생성 및 로그인:
AWS 계정이 없는 경우 AWS 웹 사이트에서 계정을 생성하고 로그인합니다.
2. AWS 콘솔에 로그인:
AWS 계정으로 로그인한 후 AWS 관리 콘솔에 액세스합니다.
3. RDS 대시보드로 이동:
AWS 콘솔에서 "RDS"를 검색하거나, "데이터베이스" 항목을 클릭하여 RDS 대시보드로 이동합니다.
4. 데이터베이스 인스턴스 생성:
5. 인스턴스 설정 구성:
6. 데이터베이스 설정 구성:
7. 보안 그룹 및 VPC 설정:
8. 추가 구성 및 옵션 설정:
9. 인스턴스 생성 및 대기:
10. 연결 정보 확인:
11. 데이터베이스에 연결:
12. 데이터베이스 사용:
위 단계를 따라 AWS RDS를 사용하여 MySQL 또는 다른 관계형 데이터베이스를 생성하고 관리할 수 있습니다. 보안 및 성능 관리를 위해 AWS RDS의 다양한 설정 및 옵션을 활용할 수 있습니다. 필요에 따라 데이터베이스 백업 및 복원을 설정하여 데이터의 안전성을 유지할 수도 있습니다.
1. 데이터베이스 시스템 선택:
로컬 환경에서 사용할 데이터베이스 시스템을 선택합니다. 아래는 몇 가지 인기있는 옵션입니다.
2. 데이터베이스 설치:
선택한 데이터베이스 시스템을 로컬 컴퓨터에 설치합니다. 데이터베이스 공식 웹 사이트에서 설치 파일과 설치 가이드를 다운로드할 수 있습니다.
3. 데이터베이스 설정:
데이터베이스를 설치한 후에는 초기 설정을 수행해야 합니다. 설정에는 다음이 포함됩니다.
4. 데이터베이스 클라이언트 도구 설치:
데이터베이스를 관리하고 쿼리를 실행하기 위한 데이터베이스 클라이언트 도구를 설치합니다. 이 도구는 데이터베이스와 상호 작용할 때 사용됩니다.
5. 애플리케이션과 연동:
로컬 데이터베이스를 사용하려면 애플리케이션 코드에서 데이터베이스에 연결하고 데이터를 읽고 쓸 수 있어야 합니다. 데이터베이스 연결을 설정하고 SQL 또는 NoSQL 쿼리를 실행하여 데이터를 조작합니다.
예를 들어, Java 프로젝트에서 MySQL 데이터베이스를 사용하려면 JDBC(Java Database Connectivity) 드라이버를 사용하여 데이터베이스에 연결하고 SQL 쿼리를 실행합니다.
다른 프로그래밍 언어와 데이터베이스 시스템을 사용하는 경우 해당 언어 또는 데이터베이스에 맞는 라이브러리 또는 드라이버를 설치하고 연동하는 방법을 학습해야 합니다.
로컬 데이터베이스 설정은 프로젝트의 규모와 요구 사항에 따라 달라질 수 있으며, 데이터베이스 종류 및 개발 환경에 따라 다양한 설정이 가능합니다.
// 스프링 데이터 베이스 JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
compileOnly 'org.projectlombok:lombok' // 롬북
runtimeOnly 'com.h2database:h2' //인메모리 데이터베이스
annotationProcessor 'org.projectlombok:lombok'
application.yml
을 만들어서 jpa 및 데이터 베이스 설정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. 꼭… 자바 파일은 패키지 안에 넣어주자
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;
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);
}
}
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(); //빌더패턴 적용*/
}
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();
}
}
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> {
}
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());
}
}
application.yml
에 설정해둔 것으로주말에 아르바이트 끝나고 생각보다 다운그레이드로 인해 문제생기기도 하고 이래서ㅠㅠㅠㅠ 좀 걸렸지만 완성해서 팀원들한테도 카톡보냈다 ㅠㅠㅠㅠㅠ