Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#5] DB연동 및 docker-compose 적용 #6

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
MYSQL_ROOT_PASSWORD=market
MYSQL_DATABASE=RefurbMarket
MYSQL_USER=refurb
MYSQL_PASSWORD=market
3 changes: 3 additions & 0 deletions api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'

runtimeOnly 'com.mysql:mysql-connector-j'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,28 @@
import com.refurbmarket.dto.user.LoginRequestDto;
import com.refurbmarket.dto.user.LoginResponseDto;
import com.refurbmarket.dto.user.SignUpRequestDto;
import com.refurbmarket.service.UserService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;

@Tag(name = "User", description = "User API")
@RestController
@RequiredArgsConstructor
@RequestMapping("/users")
public class UserController {
private final UserService userService;

@Operation(summary = "회원 등록", description = "사용자는 회원가입을 할 수 있다.")
@ApiResponse(
responseCode = "201", description = "회원 등록 성공"
)
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public LoginResponseDto signUp(@RequestBody final SignUpRequestDto request) {
return new LoginResponseDto("김테스트", "test@test.com", "abcdefg");
return userService.createUser(request);
}

@Operation(summary = "로그인", description = "회원은 로그인을 할 수 있다.")
Expand All @@ -35,6 +40,6 @@ public LoginResponseDto signUp(@RequestBody final SignUpRequestDto request) {
)
@PostMapping("/login")
public LoginResponseDto login(@RequestBody final LoginRequestDto request) {
return new LoginResponseDto("김테스트", "test@test.com", "abcdefg");
return userService.login(request);
}
}
13 changes: 13 additions & 0 deletions api/src/main/java/com/refurbmarket/domain/User.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.refurbmarket.domain;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class User {
private Long id;
private String name;
private String email;
private String password;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.refurbmarket.dto.user;

import com.refurbmarket.domain.User;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
Expand All @@ -12,4 +14,8 @@ public class LoginRequestDto {
private String email;
@Schema(description = "회원 비밀번호")
private String password;

public User toDomain() {
return new User(null, null, email, password);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.refurbmarket.dto.user;

import com.refurbmarket.domain.User;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
Expand All @@ -14,4 +16,8 @@ public class LoginResponseDto {
private String email;
@Schema(description = "토큰")
private String token;

public static LoginResponseDto of(User user, String token) {
return new LoginResponseDto(user.getName(), user.getEmail(), token);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.refurbmarket.dto.user;

import com.refurbmarket.domain.User;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
Expand All @@ -14,4 +16,8 @@ public class SignUpRequestDto {
private String email;
@Schema(description = "사용자 비밀번호")
private String password;

public User toDomain() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DTO안에 비지니스 로직이 들어가는 것이 좋은 것인가요?

return new User(null, name, email, password);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.refurbmarket.repository.implementation;

import java.util.Optional;

import org.springframework.stereotype.Repository;

import com.refurbmarket.domain.User;
import com.refurbmarket.repository.interfaces.UserRepository;
import com.refurbmarket.repository.mapper.UserMapper;

import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor
public class MyBatisUserRepositoryImpl implements UserRepository {
private final UserMapper userMapper;

@Override
public User insertUser(User user) {
userMapper.insertUser(user);
return user;
}

@Override
public Optional<User> findByEmail(String email) {
return userMapper.findByEmail(email);
}

@Override
public Optional<User> findByEmailAndPassword(String email, String password) {
return userMapper.findByEmailAndPassword(email, password);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.refurbmarket.repository.interfaces;

import java.util.Optional;

import com.refurbmarket.domain.User;

public interface UserRepository {
User insertUser(User user);

Optional<User> findByEmail(String email);

Optional<User> findByEmailAndPassword(String email, String password);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.refurbmarket.repository.mapper;

import java.util.Optional;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import com.refurbmarket.domain.User;

@Mapper
public interface UserMapper {
void insertUser(@Param("user") User user);

Optional<User> findByEmail(String email);

Optional<User> findByEmailAndPassword(String email, String password);
}
34 changes: 34 additions & 0 deletions api/src/main/java/com/refurbmarket/service/UserService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.refurbmarket.service;

import org.springframework.stereotype.Service;

import com.refurbmarket.domain.User;
import com.refurbmarket.dto.user.LoginRequestDto;
import com.refurbmarket.dto.user.LoginResponseDto;
import com.refurbmarket.dto.user.SignUpRequestDto;
import com.refurbmarket.repository.interfaces.UserRepository;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;

public LoginResponseDto createUser(SignUpRequestDto request) {
User user = request.toDomain();
if (userRepository.findByEmail(user.getEmail()).isPresent()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (userRepository.findByEmail(user.getEmail()).isPresent()) {
if (userRepository.findByEmail(user.getEmail()) == null) {

throw new IllegalArgumentException("이메일 중복");
}
Comment on lines +20 to +22
Copy link
Collaborator

@f-lab-lyan f-lab-lyan Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (userRepository.findByEmail(user.getEmail()).isPresent()) {
throw new IllegalArgumentException("이메일 중복");
}
Stream.of(user.getEmail())
.map(userRepository::findByEmail)
.getOrElse(() => throw new IllegalArgumentException("이메일 중복"))
.collect();
Suggested change
if (userRepository.findByEmail(user.getEmail()).isPresent()) {
throw new IllegalArgumentException("이메일 중복");
}
userRepository
.findByEmail(user.getEmail())
.getOrElse(() => throw new IllegalArgumentException("이메일 중복"));

user = userRepository.insertUser(user);
return LoginResponseDto.of(user, "asdf");
}

public LoginResponseDto login(LoginRequestDto request) {
User user = request.toDomain();
if (userRepository.findByEmailAndPassword(user.getEmail(), user.getPassword()).isEmpty()) {
throw new IllegalArgumentException("로그인 정보가 올바르지 않습니다.");
}
return LoginResponseDto.of(user, "asdf");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Service에서 DTO를 알고 있는 것이 좋은 것인가요?

}
}
8 changes: 8 additions & 0 deletions api/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
spring:
application:
name: RefurbMarket
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:13306/${MYSQL_DATABASE}?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
username: ${MYSQL_USERNAME}
password: ${MYSQL_PASSWORD}

mybatis:
mapper-locations: mybatis/mapper/*.xml

springdoc:
api-docs:
Expand Down
20 changes: 20 additions & 0 deletions api/src/main/resources/mybatis/mapper/UserMapper.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.refurbmarket.repository.mapper.UserMapper">
<select id="findByEmail" resultType="com.refurbmarket.domain.User">
SELECT id, name, email, password
FROM User
WHERE email = #{email}
</select>
<select id="findByEmailAndPassword" resultType="com.refurbmarket.domain.User">
SELECT id, name, email, password
FROM User
WHERE email = #{email}
AND password = #{password}
</select>
<insert id="insertUser">
INSERT INTO User (email, password, name)
VALUES (#{user.email}, #{user.password}, #{user.name})
</insert>
</mapper>
13 changes: 13 additions & 0 deletions api/src/main/resources/sql/init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
grant all privileges on RefurbMarket.* to refurb@'%';
drop table if exists member CASCADE;
create table User
(
id bigint AUTO_INCREMENT,
name VARCHAR(255),
email VARCHAR(255),
password VARCHAR(255),
created_at TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6),
primary key (id)
) comment = "회원";

insert into User (name, email, password) values ("김테스트", "test@email.com", "testtest12!");
13 changes: 13 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: '3.8'
services:
database:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
ports:
- "13306:3306"
volumes:
- ./api/src/main/resources/sql/init.sql:/docker-entrypoint-initdb.d/init.sql