Skip to content

Commit

Permalink
Merge pull request #47 from ssu-student-union/feat/26-csv
Browse files Browse the repository at this point in the history
[feat] : #26 CSV Batch 처리 및 온보딩 수정
  • Loading branch information
chahyunsoo authored Aug 2, 2024
2 parents 1acece6 + 26cda0e commit 2f86968
Show file tree
Hide file tree
Showing 38 changed files with 707 additions and 46 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ out/

### Yml ###
**/src/main/resources/application.yml
**/src/main/resources/**


.DS_Store
Expand Down
8 changes: 4 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,17 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
implementation 'com.auth0:jwks-rsa:0.21.1'

//csv
// implementation 'com.opencsv:opencsv:5.5'
//s3
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

//spring-batch
// implementation 'org.springframework.boot:spring-boot-starter-batch'
implementation 'org.springframework.boot:spring-boot-starter-batch'

//webClient
implementation 'org.springframework.boot:spring-boot-starter-webflux'

//redis, 2.3.1.RELEASE'
// implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

//lombok
compileOnly 'org.projectlombok:lombok'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package ussum.homepage.infra.jpa.csv_user.entity;

import static com.querydsl.core.types.PathMetadataFactory.*;

import com.querydsl.core.types.dsl.*;

import com.querydsl.core.types.PathMetadata;
import javax.annotation.processing.Generated;
import com.querydsl.core.types.Path;


/**
* QStudentCsvEntity is a Querydsl query type for StudentCsvEntity
*/
@Generated("com.querydsl.codegen.DefaultEntitySerializer")
public class QStudentCsvEntity extends EntityPathBase<StudentCsvEntity> {

private static final long serialVersionUID = 1910442335L;

public static final QStudentCsvEntity studentCsvEntity = new QStudentCsvEntity("studentCsvEntity");

public final StringPath groupName = createString("groupName");

public final StringPath major = createString("major");

public final NumberPath<Long> STID = createNumber("STID", Long.class);

public final StringPath studentEmail = createString("studentEmail");

public final StringPath studentGroup = createString("studentGroup");

public final NumberPath<Long> studentId = createNumber("studentId", Long.class);

public final StringPath studentName = createString("studentName");

public final StringPath studentStatus = createString("studentStatus");

public QStudentCsvEntity(String variable) {
super(StudentCsvEntity.class, forVariable(variable));
}

public QStudentCsvEntity(Path<? extends StudentCsvEntity> path) {
super(path.getType(), path.getMetadata());
}

public QStudentCsvEntity(PathMetadata metadata) {
super(StudentCsvEntity.class, metadata);
}

}

2 changes: 2 additions & 0 deletions src/main/java/ussum/homepage/HomepageApplication.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package ussum.homepage;

import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableBatchProcessing // 배치 사용을 위한 선언
@SpringBootApplication
public class HomepageApplication {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ussum.homepage.application.admin.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import ussum.homepage.application.admin.service.AdminService;
import ussum.homepage.global.ApiResponse;

@RequiredArgsConstructor
@RequestMapping("/admin")
@RestController
public class AdminController {
private final AdminService adminService;

@PostMapping("/s3-csv")
public ResponseEntity<ApiResponse<?>> csvToS3(@RequestParam MultipartFile file) {
adminService.uploadCsvToS3(file);
return ApiResponse.success(null);
}

@PostMapping("csv-project")
public ResponseEntity<ApiResponse<?>> s3ToProject(@RequestParam("file") String fileName) {
adminService.uploadCsvFromS3ToProject(fileName);
return ApiResponse.success(null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package ussum.homepage.application.admin.service;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import ussum.homepage.infra.csvBatch.JobLauncherRunner;
import ussum.homepage.infra.utils.S3utils;

@Service
@RequiredArgsConstructor
@Transactional
public class AdminService {
private final S3utils s3utils;
private final JobLauncherRunner runner;

public void uploadCsvToS3(MultipartFile file) {
s3utils.uploadFile(file);
}

public void uploadCsvFromS3ToProject(String fileName) {
s3utils.getFileToProject(fileName);
runner.runJob(); // batch job 실행

// runJob이후 resources/csv 경로에 학생목록.csv파일이 생성됨, 코드로 삭제해야하나?
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
Expand All @@ -22,8 +23,8 @@ public void LoginPage(HttpServletResponse response) throws Exception{
}

@GetMapping("/callback")
public ApiResponse<UserOAuthResponse> callback(@RequestParam("code") String code){
return ApiResponse.onSuccess(oAuthService.signIn(code));
public ResponseEntity<ApiResponse<?>> callback(@RequestParam("code") String code){
return ApiResponse.success(oAuthService.signIn(code));
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package ussum.homepage.application.user.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import ussum.homepage.application.user.service.OnBoardingService;
import ussum.homepage.application.user.service.dto.request.OnBoardingRequest;
import ussum.homepage.application.user.service.dto.request.UserRequest;
Expand All @@ -16,9 +18,10 @@ public class OnBoardingController {
private final OnBoardingService onBoardingService;

@PostMapping("/academy-information")
public ApiResponse<?> createUserOnBoarding(@UserId Long userId,
@RequestBody OnBoardingRequest request){
onBoardingService.getUserOnBoarding(userId, request);
return ApiResponse.onSuccess(null);
public ResponseEntity<ApiResponse<?>> createUserOnBoarding(@UserId Long userId,
@RequestBody OnBoardingRequest request){
onBoardingService.saveUserOnBoarding(userId, request);
return ApiResponse.success(null);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import ussum.homepage.application.user.service.UserService;
import ussum.homepage.global.ApiResponse;

@RequiredArgsConstructor
@RequestMapping("/users")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,41 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import ussum.homepage.application.user.service.dto.request.OnBoardingRequest;
import ussum.homepage.application.user.service.dto.response.OnBoardingResponse;
import ussum.homepage.domain.csv_user.StudentCsv;
import ussum.homepage.domain.csv_user.StudentCsvRepository;
import ussum.homepage.domain.csv_user.service.StudentCsvModifier;
import ussum.homepage.domain.csv_user.service.StudentCsvReader;
import ussum.homepage.domain.user.User;
import ussum.homepage.domain.user.service.UserFormatter;
import ussum.homepage.domain.user.service.UserAppender;
import ussum.homepage.domain.user.service.UserModifier;
import ussum.homepage.domain.user.service.UserReader;
import ussum.homepage.global.jwt.JwtTokenProvider;
import ussum.homepage.global.error.exception.GeneralException;
import ussum.homepage.infra.jpa.csv_user.StudentCsvMapper;

import java.util.Optional;

import static ussum.homepage.global.error.status.ErrorStatus.USER_NOT_FOUND;

@Service
@RequiredArgsConstructor
@Transactional
@Transactional(readOnly = true)
public class OnBoardingService {
private final JwtTokenProvider provider;
private final UserAppender userAppender;
private final UserFormatter userFormatter;
private final UserModifier userModifier;
private final UserReader userReader;
private final StudentCsvReader studentCsvReader;
private final StudentCsvModifier studentCsvModifier;

@Transactional
public void getUserOnBoarding(Long userId, OnBoardingRequest request){
public void saveUserOnBoarding(Long userId, OnBoardingRequest request){
User user = userReader.getUserWithId(userId);
String studentId = request.getStudentId();
StudentCsv studentCsv = studentCsvReader.getStudentWithStudentId(Long.valueOf(studentId),request)
.orElseThrow(() -> new GeneralException(USER_NOT_FOUND));

/*
TO DO // MemberEntity, GroupEntity 연결
*/
user.updateOnBoardingUser(request);
userModifier.save(user);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import ussum.homepage.domain.user.service.UserReader;

@Service
@RequiredArgsConstructor
@Transactional
public class UserService {
private final UserReader userReader;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@
public class OnBoardingRequest {
private String name;
private String studentId;
private String groupName;
private String major;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ussum.homepage.application.user.service.dto.response;

import lombok.Builder;

@Builder
public record CsvOnBoardingResponse(
boolean name,
boolean groupName,
boolean major
) {
public static CsvOnBoardingResponse of(boolean name, boolean groupName, boolean major) {
return CsvOnBoardingResponse.builder()
.name(name)
.groupName(groupName)
.major(major)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ussum.homepage.application.user.service.dto.response;

import lombok.Builder;
import ussum.homepage.application.user.service.dto.request.OnBoardingRequest;

@Builder
public record OnBoardingResponse(
boolean name,
boolean studentId,
boolean groupName,
boolean major
) {
public static OnBoardingResponse of(boolean name, boolean studentId, boolean groupName, boolean major) {
return OnBoardingResponse.builder()
.name(name)
.studentId(studentId)
.groupName(groupName)
.major(major)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public record UserOAuthResponse(
String studentId,
Boolean isFirst,
String accessToken,
String refreshToken,
String refreshToken, // refreshToken을 돌려 줄 이유가 있을까?
String profileImage,
String createdAt
) {
Expand All @@ -23,6 +23,7 @@ public static UserOAuthResponse of(User user, JwtTokenInfo tokenInfo, Boolean is
.isFirst(isFirst)
.accessToken(tokenInfo.getAccessToken())
.refreshToken(tokenInfo.getRefreshToken())
.profileImage(user.getProfileImage())
.createdAt(null)
.build();
}
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/ussum/homepage/domain/csv_user/StudentCsv.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ussum.homepage.domain.csv_user;

import lombok.*;

/*
원래는 record로 dto를 관리하지만,
기본 생성자에서 문제가 발생하여 class 사용
*/
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class StudentCsv {
private Long STID;
private Long studentId;
private String studentName;
private String groupName;
private String major;
private String studentStatus;
private String studentGroup; // 학생그룹의 의미
// 전화번호?
private String studentEmail;

public static StudentCsv of(Long STID, Long studentId, String studentName, String groupName,
String major, String studentStatus, String studentGroup, String studentEmail) {
return new StudentCsv(STID, studentId, studentName, groupName,
major, studentStatus, studentGroup, studentEmail);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ussum.homepage.domain.csv_user;

import org.springframework.batch.item.Chunk;
import ussum.homepage.infra.jpa.csv_user.entity.StudentCsvEntity;

import java.util.Optional;

public interface StudentCsvRepository {
void saveAll(Chunk<StudentCsvEntity> students);
Optional<StudentCsv> findByStudentId(Long studentId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package ussum.homepage.domain.csv_user.service;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import ussum.homepage.domain.csv_user.StudentCsvRepository;

@Service
@RequiredArgsConstructor
public class StudentCsvModifier {
private final StudentCsvRepository studentCsvRepository;

}
Loading

0 comments on commit 2f86968

Please sign in to comment.