Jenkins 심화 - profile 적용(분기 처리)
폴더 구조 변경
backendProject 하위폴더에도 Dockerfile과 nginx.conf를 추가해준다.
FROM nginx:latest
# 기존 설정 제거 (선택적)
RUN rm /etc/nginx/nginx.conf
# 커스텀 nginx.conf 복사
COPY nginx.conf /etc/nginx/nginx.conf
Docker
복사
worker_processes 1;
events {
worker_connections 1024;
}
http {
upstream spring_backend {
server backend1:8080;
server backend2:8080;
server backend3:8080;
}
server {
listen 80;
location / {
proxy_pass http://spring_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /ws-chat {
proxy_pass http://spring_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /ws-gpt {
proxy_pass http://spring_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
Plain Text
복사
•
backendProject > docker-compose.backend.yml 생성
services:
# redis:
# image: redis
# container_name: redis
# ports:
# - "6379:6379"
#
#
# database:
# image: mysql:8
# container_name: database
# ports:
# - "3307:3306"
# environment:
# MYSQL_DATABASE: backendDB
# MYSQL_ROOT_PASSWORD: ${DB_PASS}
# volumes:
# - ./volumes/mysql-data:/var/lib/mysql #내가 지정한 경로
# healthcheck:
# test: ["CMD", "mysqladmin", "ping", "-h", "localhost", '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD']
# timeout: 20s
# retries: 10
backend1: # 서비스 이름은 컨테이너간 통신하기 위한 이름
build: .
container_name: backend1
environment:
PROJECT_NAME: 백앤드 서버1
DB_SERVER: ${DB_SERVER}
DB_PORT: ${DB_PORT}
DB_USER: ${DB_USER}
DB_PASS: ${DB_PASS}
REDIS_HOST: ${REDIS_HOST}
networks:
- prod_server
# depends_on:
# - database
# - redis
backend2: # 서비스 이름은 컨테이너간 통신하기 위한 이름
build: .
container_name: backend2
environment:
PROJECT_NAME: 백앤드 서버2
DB_SERVER: ${DB_SERVER}
DB_PORT: ${DB_PORT}
DB_USER: ${DB_USER}
DB_PASS: ${DB_PASS}
REDIS_HOST: ${REDIS_HOST}
networks:
- prod_server
# depends_on:
# - database
# - redis
backend3: # 서비스 이름은 컨테이너간 통신하기 위한 이름
build: .
container_name: backend3
environment:
PROJECT_NAME: 백앤드 서버3
DB_SERVER: ${DB_SERVER}
DB_PORT: ${DB_PORT}
DB_USER: ${DB_USER}
DB_PASS: ${DB_PASS}
REDIS_HOST: ${REDIS_HOST}
# depends_on:
# - database
# - redis
networks:
- prod_server
nginx:
build: ./nginx/.
container_name: nginx
ports:
- "80:80"
# volumes:
# - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- backend1
- backend2
- backend3
networks:
- prod_server
networks:
prod_server:
external: true
YAML
복사
•
파일 구조 변경으로 인한 각 파일들 내용 수정
◦
Data 폴더 안에 docker-compose.data.yml 작성
◦
.env 파일 추가
services:
# docker network create prod_server 도커 네트워크 만들어야 함! (명령어 실행)
redis:
image: redis
container_name: redis
ports:
- "6379:6379"
networks:
- prod_server
restart: unless-stopped
database:
image: mysql:8
container_name: database
ports:
- "3307:3306"
environment:
MYSQL_DATABASE: backendDB
MYSQL_ROOT_PASSWORD: ${DB_PASS}
volumes:
- ./volumes/mysql-data:/var/lib/mysql #내가 지정한 경로
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD']
timeout: 20s
retries: 10
networks:
- prod_server
restart: unless-stopped
networks:
prod_server:
external: true
YAML
복사
•
Jenkins Script 수정 (localhost:7070 파이프라인 쪽에 적용)
pipeline {
agent any
environment {
PROJECT_DIR = '/var/jenkins_home/workspace/backend5_Test_local/backendProject' // 백앤드 서버 프로젝트 폴더
COMPOSE_FILE = 'docker-compose.backend.yml'
}
stages {
stage('Cleanup Containers') {
steps {
dir("${PROJECT_DIR}") {
sh "docker-compose -f ${COMPOSE_FILE} down"
}
}
}
stage('Build') {
steps {
dir("${PROJECT_DIR}") {
sh 'chmod +x gradlew'
sh './gradlew clean build'
}
}
}
stage('Compose Up') {
steps {
dir("${PROJECT_DIR}") {
sh "docker-compose -f ${COMPOSE_FILE} up -d --build"
}
}
}
stage('Restart Nginx') {
steps {
sh 'docker restart nginx || true'
}
}
}
}
Shell
복사
•
test 관련 파일 설정 모두 해제
plugins {
id 'java'
id 'org.springframework.boot' version '3.5.0'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'org.example'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
// 20250620 - H2 database 추가
// testImplementation 'com.h2database:h2' (주석 처리)
... 중략 ...
}
tasks.named('test') {
useJUnitPlatform()
}
Plain Text
복사
#spring.datasource.url=jdbc:h2:mem:testdb
#spring.datasource.driver-class-name=org.h2.Driver
#spring.datasource.username=sa
#spring.datasource.password=
#spring.jpa.hibernate.ddl-auto=create-drop
#spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
Shell
복사
package org.example.backendproject;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
//@ActiveProfiles("test")
@SpringBootTest
class BackendProjectApplicationTests {
@Test
void contextLoads() {
}
}
Java
복사
package org.example.backendproject.stompwebsocket.redis;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
//@Profile("!test")
@RequiredArgsConstructor
@Configuration
public class RedisConfig {
private final RedisSubscriber redisSubscriber;
@Bean
public RedisMessageListenerContainer container(RedisConnectionFactory redisConnectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
container.addMessageListener(new MessageListenerAdapter(redisSubscriber), new PatternTopic("room.*"));
container.addMessageListener(new MessageListenerAdapter(redisSubscriber), new PatternTopic("private.*")); // 귓속말
return container;
}
}
Java
복사
•
◦
application-properties
spring.application.name=backendProject
# Jenkins
spring.profiles.active=prod
# local
#spring.profiles.active=dev
YAML
복사
◦
application-dev.properties
spring.application.name=backendProject
# 로컬 개발용
db.server=${DB_SERVER:localhost}
db.port=${DB_PORT:3307}
db.username=${DB_USER:root}
db.password=${DB_PASS:1234}
REDIS.HOST=${REDIS_HOST:localhost}
spring.data.redis.host=${REDIS.HOST}
spring.data.redis.port=6379
spring.datasource.url=jdbc:mysql://${db.server}:${db.port}/backendDB?serverTimezone=Asia/Seoul&characterEncoding=UTF-8&rewriteBatchedStatements=true
spring.datasource.username=${db.username}
spring.datasource.password=${db.password}
openai.api.key=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
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=update
YAML
복사
◦
application-prod.properties
spring.application.name=backendProject
# 환경 변수에 값이 있으면 환경변수의 값을 쓰고
# 환경 변수에 값이 없으면 뒤에 있는 default 값을 씀
# 젠킨스 배포용
db.server=${DB_SERVER:database}
db.port=${DB_PORT:3306}
db.username=${DB_USER:root}
db.password=${DB_PASS:1234}
REDIS.HOST=${REDIS_HOST:redis}
spring.data.redis.host=${REDIS.HOST}
spring.data.redis.port=6379
spring.datasource.url=jdbc:mysql://${db.server}:${db.port}/backendDB?serverTimezone=Asia/Seoul&characterEncoding=UTF-8&rewriteBatchedStatements=true
spring.datasource.username=${db.username}
spring.datasource.password=${db.password}
openai.api.key=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
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=update
YAML
복사
•
Jenkins 실행
◦
참고로 Jenkins 실행하기 전에 redis와 mysql 컨테이너를 수동으로 실행 시켜줘야 함
docker-compose -f docker-compose.data.yml up -d
Shell
복사
에러 확인
•
젠킨스 컨테이너 삭제 후 재실행하니 정상적으로 동작됨
BackendProjectApplicationTests > contextLoads() FAILED
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:180
Caused by: org.springframework.beans.factory.BeanCreationException at AbstractAutowireCapableBeanFactory.java:1826
Caused by: jakarta.persistence.PersistenceException at AbstractEntityManagerFactoryBean.java:431
Caused by: org.hibernate.exception.JDBCConnectionException at SQLStateConversionDelegate.java:100
Caused by: com.mysql.cj.jdbc.exceptions.CommunicationsException at SQLError.java:165
Caused by: com.mysql.cj.exceptions.CJCommunicationsException at null:-1
Caused by: java.net.UnknownHostException at null:-1
Shell
복사
JPA
Spring Data JPA
1. Spring에서 사용하는 데이터 접근 방식
•
JPA(Java Persistence API)
◦
JPA는 ORM 기술을 사용한 인터페이스의 집합
◦
JPA는 인터페이스만 있고 직접 동작하는 구현체는 없음
◦
JPA의 대표적인 구현체(실제로 동작하는 코드)
▪
Hibernate
▪
구현체는 JPA의 인터페이스의 명령을 보고 SQL을 만들며 DB와 통신하는 역할을 수행
•
ORM (Object Relational Mapping)
애플리케이션의 객체와 관계형 데이터베이스의 테이블을 자동으로 연결해주는 기술
•
ORM의 주요 기능
◦
객체와 테이블 매핑
▪
객체의 속성을 데이터베이스 테이블의 컬럼과 자동으로 매핑함
◦
SQL 자동 생성
▪
ORM은 객체 지향 코드만 작성하면 자동으로 SQL 쿼리를 생성하여 실행
◦
데이터베이스 연산
▪
객체 지향 방식으로 데이터베이스의 CRUD 연산을 수행할 수 있음
◦
개발 생산성 향상
▪
ORM을 사용하면 데이터베이스 관련 코드를 줄이고 개발 생산성을 높일 수 있음
◦
유지보수 용이
▪
ORM을 사용하면 데이터베이스 구조 변경이 쉽게 반영되고, 유지보수 작업이 용이해짐
•
EntityManager ← DB와 상호작용
◦
JPA의 인터페이스 중 가장 핵심 인터페이스
2. Spring Data JPA
Spring에서 JPA(Java Persistence API)를 더 쉽게, 더 생산적으로 사용할 수 있도록 Spring에서 만든 확장 라이브러리
3. Spring Data JPA의 특징
•
기본 CRUD 메서드 제공
•
SQL 자동 생성
•
Spring Data JPA에서 발생하는 일
•
3계층 구조
◦
Controller → Service → Repository
▪
Controller: 사용자의 요청 처리 및 응답 처리
▪
Service: 비즈니스 로직 처리 (저장, 수정, 삭제, 조회)
▪
Repository: Database 통신 담당
실습 진행 방식
•
회원 가입, 내 정보 수정, 게시판 글쓰기, 댓글 달기, 댓글에 댓글 달기
•
로그인에 Security 적용
•
소셜 로그인 적용 (OAuth2)
•
로그 수집 대시보드
•
서버 성능 모니터링 대시보드
⇒ 6/23(월) 기준 회원 가입과 로그인까지 진행
JPA 심화
•
Spring Data JPA의 엔티티 연관 관계 매핑
◦
연관관계의 방향 (단방향, 양방향)
◦
연관관계의 종류 (1:1, N:1, 1:N, N:N)
◦
연관관계의 주인
◦
Fetch 전략 (즉시 로딩, 지연 로딩)
•
쿼리 메서드 자동 생성
•
Auditing(자동 등록자/수정자, 등록일, 수정일 관리)
•
직접 JPQL, 네이티브 쿼리 작성 (게시글 검색)
•
페이징, 정렬 지원 (게시글 검색 페이징)
•
대용량 데이터 처리 (배치 insert)
•
1:1 (OneToOne) 관계
◦
회원가입 (회원
프로필)
◦
한명의 회원은 하나의 프로필(상세정보, 주소)을 가짐
•
1:N(OneToMany) 관계 - 단방향
Order 클래스에는 member 필드가 없음, Order에서 member를 알 수 없음
Order에서 member를 알 수 없음
단방향에서 생기는 문제
⇒ Order에서 member를 알 수가 없어서 객체 접근 불가능 (order.getMember() ← 불가능)
•
1:N(OneToMany, ManyToOne) 관계 - (양방향)
•
CascadeType 종류
•
Fetch 전략
•
쿼리 메서드 SQL 자동 생성
◦
메서드 이름만 잘 지으면 JPA가 JPQL 쿼리를 자동으로 생성
‘회원가입 + 로그인’ 실습
•
application.properties
spring.application.name=backendProject
# Jenkins
#spring.profiles.active=prod
# local
spring.profiles.active=local
+
# dev
#spring.profiles.active=dev
Shell
복사
•
application-local.properties
spring.application.name=backendProject
db.server=${DB_SERVER:localhost}
db.port=${DB_PORT:3307}
db.username=${DB_USER:root}
db.password=${DB_PASS:1234}
REDIS.HOST=${REDIS_HOST:localhost}
spring.data.redis.host=${REDIS.HOST}
spring.data.redis.port=6379
spring.datasource.url=jdbc:mysql://${db.server}:${db.port}/backendDB?serverTimezone=Asia/Seoul&characterEncoding=UTF-8&rewriteBatchedStatements=true
spring.datasource.username=${db.username}
spring.datasource.password=${db.password}
openai.api.key=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
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=update
YAML
복사
•
User
package org.example.backendproject.user.entity;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToOne;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.example.backendproject.Auth.entity.Auth;
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String userid;
@Column(nullable = false)
private String password;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private UserProfile userProfile;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Auth auth;
}
Java
복사
•
UserProfile
package org.example.backendproject.user.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Entity
public class UserProfile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String username;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false)
private String phone;
@Column(nullable = false)
private String address;
@OneToOne // 1:1 관계
@JoinColumn(name = "user_id")
private User user;
}
Java
복사
•
UserRepository
package org.example.backendproject.user.repository;
import java.util.Optional;
import org.example.backendproject.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUserid(String userid);
}
Java
복사
•
UserDTO
package org.example.backendproject.user.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class UserDTO {
private Long id;
private String userid;
private String username;
private String email;
private String phone;
private String address;
}
Java
복사
•
Auth
package org.example.backendproject.Auth.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.example.backendproject.user.entity.User;
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
public class Auth {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String tokenType;
@Column(nullable = false)
private String accessToken;
@Column(nullable = false)
private String refreshToken;
@OneToOne(fetch = FetchType.LAZY) // 1:1 관계, 지연로딩 적용 -> Auth 엔티티 조회할 때 user 객체는 불러오지 않음
@JoinColumn(name = "user_id") // auth.getUser()에 실제로 접근할 때 User 쿼리 발생!!
private User user;
}
Java
복사
•
SignUpRequestDto
package org.example.backendproject.Auth.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class SignUpRequestDTO {
private String userid;
private String password;
private String username;
private String email;
private String phone;
private String address;
}
Java
복사
•
LoginRequestDTO
package org.example.backendproject.Auth.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class LoginRequestDTO {
private String userid;
private String password;
}
Java
복사
•
AuthRepository
package org.example.backendproject.Auth.repository;
import org.example.backendproject.Auth.entity.Auth;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface AuthRepository extends JpaRepository<Auth, Long> {
}
Java
복사
•
AuthService
package org.example.backendproject.Auth.service;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.example.backendproject.Auth.dto.LoginRequestDTO;
import org.example.backendproject.Auth.dto.SignUpRequestDTO;
import org.example.backendproject.user.dto.UserDTO;
import org.example.backendproject.user.entity.User;
import org.example.backendproject.user.entity.UserProfile;
import org.example.backendproject.user.repository.UserRepository;
import org.springframework.stereotype.Service;
@RequiredArgsConstructor
@Service
public class AuthService {
private final UserRepository userRepository;
@Transactional // 해당 어노테이션 선언해야 저장이 된다.
public void signUp(SignUpRequestDTO dto) {
// 사용자 조회 여부 확인, null값 체크
if (userRepository.findByUserid(dto.getUserid()).isPresent()) {
throw new RuntimeException("사용자가 이미 존재합니다.");
}
User user = new User();
user.setUserid(dto.getUserid());
user.setPassword(dto.getPassword());
UserProfile profile = new UserProfile();
profile.setUsername(dto.getUsername());
profile.setEmail(dto.getEmail());
profile.setPhone(dto.getPhone());
profile.setAddress(dto.getAddress());
/** 연관관계 설정 **/
profile.setUser(user);
user.setUserProfile(profile);
userRepository.save(user);
}
public UserDTO login(LoginRequestDTO loginRequestDTO) {
User user = userRepository.findByUserid(loginRequestDTO.getUserid())
.orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다."));
if (!loginRequestDTO.getPassword().equals(user.getPassword())) {
throw new RuntimeException("비밀번호를 찾을 수 없습니다.");
}
UserDTO userDTO = new UserDTO();
userDTO.setId(user.getId());
userDTO.setUserid(user.getUserid());
userDTO.setUsername(user.getUserProfile().getUsername());
userDTO.setEmail(user.getUserProfile().getEmail());
userDTO.setPhone(user.getUserProfile().getPhone());
userDTO.setAddress(user.getUserProfile().getAddress());
return userDTO;
}
}
Java
복사
•
AuthController
package org.example.backendproject.Auth.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.backendproject.Auth.dto.LoginRequestDTO;
import org.example.backendproject.Auth.dto.SignUpRequestDTO;
import org.example.backendproject.Auth.service.AuthService;
import org.example.backendproject.user.dto.UserDTO;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/auth")
@Slf4j
public class AuthController {
private final AuthService authService;
/** 회원가입 **/
@PostMapping("/signUp")
public ResponseEntity<String> signUp(@RequestBody SignUpRequestDTO signUpRequestDTO) {
try {
authService.signUp(signUpRequestDTO);
return ResponseEntity.ok("회원가입 성공");
} catch (Exception e) {
log.error(e.getMessage());
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage()); // 401
}
}
/** 로그인 **/
@PostMapping("/login")
public ResponseEntity<UserDTO> login(@RequestBody LoginRequestDTO loginRequestDTO) {
try {
UserDTO loginUser = authService.login(loginRequestDTO);
log.info("로그인 성공 = " + new ObjectMapper().writeValueAsString(loginRequestDTO));
return ResponseEntity.ok(loginUser);
} catch (Exception e) {
log.error(e.getMessage());
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); // 401
}
}
}
Java
복사
•
Postman 테스트
•
•
로그인 후 화면
•
DB에서 회원가입된 user 확인
•
로그를 통한 로그인 성공 확인
오늘 푸시한 커밋 리스트
날짜 | 커밋 메시지 |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 | |
2025-06-23 |