Skip to content

Commit

Permalink
Merge pull request #6 from 2E1I/dev
Browse files Browse the repository at this point in the history
카카오 로그인 추가
  • Loading branch information
CEO-Nick authored Apr 18, 2024
2 parents dfb7739 + 47687ac commit 2e9be72
Show file tree
Hide file tree
Showing 39 changed files with 916 additions and 30 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@ out/
### VS Code ###
.vscode/
src/main/resources/db-application.properties
src/main/resources/application.properties
src/main/resources/application.properties
src/main/resources/application-oauth.properties
src/main/java/com/e2i1/linkeepserver/domain/oauth
src/main/java/com/e2i1/linkeepserver/config/oauth
7 changes: 6 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
//developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'org.postgresql:postgresql'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
Expand All @@ -41,6 +41,11 @@ dependencies {
//swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'

//jwt
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'

}

tasks.named('bootBuildImage') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.e2i1.linkeepserver.common.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserSession {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.e2i1.linkeepserver.common.entity;

import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Converter
public class StringListToStringConverter implements AttributeConverter<List<String>, String> {

@Override
public String convertToDatabaseColumn(List<String> attribute) {
if (attribute == null || attribute.isEmpty()) {
return "{}"; // PostgreSQL 에서 빈 배열을 표현
}

// List를 PostgreSQL 배열 문자열로 변환
return "{" + attribute.stream()
.map(s -> "\"" + s.replace("\"", "\\\"") + "\"") // 쌍따옴표 이스케이프
.collect(Collectors.joining(",")) + "}";
}

@Override
public List<String> convertToEntityAttribute(String dbData) {
if (dbData == null || dbData.equals("{}")) {
return null;
}

// PostgreSQL 배열 문자열을 List로 변환
dbData = dbData.substring(1, dbData.length() - 1); // 양쪽 중괄호 제거

return Arrays.stream(dbData.split(","))
.map(s -> s.replace("\"", "")) // 쌍따옴표 제거
.collect(Collectors.toList());
}
}
35 changes: 35 additions & 0 deletions src/main/java/com/e2i1/linkeepserver/common/error/ErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.e2i1.linkeepserver.common.error;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@AllArgsConstructor
@Getter
public enum ErrorCode{
OK(HttpStatus.OK, "성공"),
BAD_REQUEST(HttpStatus.BAD_REQUEST, "잘못된 요청"),
SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 에러"),
NULL_POINT(HttpStatus.INTERNAL_SERVER_ERROR, "Null point"),
NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않습니다."),

// 소셜 로그인 관련 에러 코드
UNKNOWN_OAUTH_LOGIN(HttpStatus.BAD_REQUEST, "알 수 없는 소셜 로그인 형식"),

// 토큰 관련 에러 코드
INVALID_TOKEN(HttpStatus.BAD_REQUEST, "유효하지 않은 토큰"),
EXPIRED_TOKEN(HttpStatus.BAD_REQUEST, "만료된 토큰"),
TOKEN_EXCEPTION(HttpStatus.BAD_REQUEST, "토큰 알 수 없는 에러"),
AUTHORIZATION_TOKEN_NOT_FOUND(HttpStatus.BAD_REQUEST, "인증 헤더 토큰 없음"),

// 유저 관련 에러 코드
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "사용자를 찾을 수 없음"),

// 모음집 관련 에러 코드
COLLECTION_NOT_FOUND(HttpStatus.NOT_FOUND, "모음집을 찾을 수 없음"),
;

private final HttpStatus httpStatusCode;
private final String description;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.e2i1.linkeepserver.common.error;


import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@AllArgsConstructor
@Getter @Setter
@Builder
public class ErrorResponse {
private String errorMessage;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.e2i1.linkeepserver.common.exception;

import com.e2i1.linkeepserver.common.error.ErrorCode;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class ApiException extends RuntimeException{

private final ErrorCode errorCode;
private final String errorDescription;

public ApiException(ErrorCode errorCode) {
this.errorCode = errorCode;
this.errorDescription = errorCode.getDescription();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.e2i1.linkeepserver.config;

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;

@Configuration
public class RestTemplateConfig {

//HTTP get,post 요청을 날릴때 일정한 형식에 맞춰주는 template
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.requestFactory(() -> new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()))
.additionalMessageConverters(new StringHttpMessageConverter(StandardCharsets.UTF_8))
.build();
}
}
47 changes: 46 additions & 1 deletion src/main/java/com/e2i1/linkeepserver/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,49 @@
package com.e2i1.linkeepserver.config;

public class WebConfig {
import com.e2i1.linkeepserver.interceptor.AuthorizationInterceptor;
import com.e2i1.linkeepserver.resolver.UserSessionResolver;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {

private final AuthorizationInterceptor authorizationInterceptor;
private final UserSessionResolver userSessionResolver;

private final List<String> DEFAULT_EXCLUDE = List.of(
"/",
"favicon.ico",
"/error",
"/api/users/login"
);

private final List<String> SWAGGER = List.of(
"/swagger-ui.html",
"/swagger-ui/**",
"/v3/api-docs/**"
);

/**
* DEFAULT_EXCLUDE, SWAGGER에 저장된 uri 제외하고는 전부 검증할 것
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authorizationInterceptor)
.excludePathPatterns(DEFAULT_EXCLUDE)
.excludePathPatterns(SWAGGER);
}

/**
* UserSessionResolver 등록
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(userSessionResolver);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.e2i1.linkeepserver.domain.collections.entity;

import com.e2i1.linkeepserver.common.entity.DateEntity;
import com.e2i1.linkeepserver.common.entity.StringListToStringConverter;
import com.e2i1.linkeepserver.domain.collaborators.entity.CollaboratorsEntity;
import com.e2i1.linkeepserver.domain.links.entity.LinksEntity;
import com.e2i1.linkeepserver.domain.tags.entity.TagsEntity;
Expand Down Expand Up @@ -42,7 +43,8 @@ public class CollectionsEntity extends DateEntity {
@Enumerated(EnumType.STRING)
private Access access;

private String color;
@Convert(converter = StringListToStringConverter.class)
private List<String> color;

private Boolean favorite;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.e2i1.linkeepserver.domain.collections.repository;

import com.e2i1.linkeepserver.domain.collections.entity.CollectionsEntity;
import org.springframework.data.repository.Repository;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CollectionsRepository extends Repository<CollectionsEntity,Long>{
public interface CollectionsRepository extends JpaRepository<CollectionsEntity,Long> {
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
package com.e2i1.linkeepserver.domain.collections.service;

import com.e2i1.linkeepserver.common.error.ErrorCode;
import com.e2i1.linkeepserver.common.exception.ApiException;
import com.e2i1.linkeepserver.domain.collaborators.repository.CollaboratorsRepository;
import com.e2i1.linkeepserver.domain.collections.entity.CollectionsEntity;
import com.e2i1.linkeepserver.domain.collections.repository.CollectionsRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@RequiredArgsConstructor
public class CollectionsService {
private final CollaboratorsRepository collaboratorsRepository;
private final CollectionsRepository collectionsRepository;

public CollectionsEntity findById(Long collectionId) {
return collectionsRepository.findById(collectionId)
.orElseThrow(() -> {
log.error("Collection Not Found!! collectionId = {}", collectionId);
return new ApiException(ErrorCode.COLLECTION_NOT_FOUND);
});
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
package com.e2i1.linkeepserver.domain.links.business;

import com.e2i1.linkeepserver.common.annotation.Business;
import com.e2i1.linkeepserver.domain.collections.entity.CollectionsEntity;
import com.e2i1.linkeepserver.domain.collections.service.CollectionsService;
import com.e2i1.linkeepserver.domain.links.converter.LinksConverter;
import com.e2i1.linkeepserver.domain.links.dto.LinkReqDTO;
import com.e2i1.linkeepserver.domain.links.entity.LinksEntity;
import com.e2i1.linkeepserver.domain.links.service.LinksService;
import lombok.RequiredArgsConstructor;

@Business
@RequiredArgsConstructor
public class LinksBusiness {

private final LinksService linksService;
private final LinksConverter linksConverter;
private final CollectionsService collectionsService;


/**
* link 저장하기
*/
public LinksEntity save(LinkReqDTO req) {
CollectionsEntity collection = collectionsService.findById(req.getCollectionId());
LinksEntity linkEntity = linksConverter.toEntity(req, collection);
return linksService.save(linkEntity);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
import com.e2i1.linkeepserver.domain.links.dto.LinkReqDTO;
import com.e2i1.linkeepserver.domain.links.dto.LinkResDTO;
import com.e2i1.linkeepserver.domain.links.dto.SearchLinkResDTO;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;

@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/links")
Expand All @@ -22,7 +25,9 @@ public ResponseEntity<SearchLinkResDTO> searchLink(@RequestParam("search")String
return ResponseEntity.ok(null);
}
@PostMapping()
public ResponseEntity<String> searchLink(@RequestBody LinkReqDTO linkReqDTO){
public ResponseEntity<String> saveLink(@RequestBody @Valid LinkReqDTO linkReqDTO){
log.info("{}", linkReqDTO);
linksBusiness.save(linkReqDTO);
return ResponseEntity.ok("success");
}
@GetMapping("/{linkId}")
Expand All @@ -31,8 +36,8 @@ public ResponseEntity<LinkResDTO> getLink(@PathVariable String linkId){
return ResponseEntity.ok(null);
}

@PostMapping("/view")
public ResponseEntity<HashMap<String,Long>> countView(@RequestBody Long linkId){
@PatchMapping("/views")
public ResponseEntity<HashMap<String,Long>> plusView(@RequestBody Long linkId){
HashMap<String,Long> result = new HashMap<>();
result.put("numOfViews", 22L);
return ResponseEntity.ok(result);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
package com.e2i1.linkeepserver.domain.links.converter;

import com.e2i1.linkeepserver.common.annotation.Converter;
import com.e2i1.linkeepserver.domain.collections.entity.CollectionsEntity;
import com.e2i1.linkeepserver.domain.links.dto.LinkReqDTO;
import com.e2i1.linkeepserver.domain.links.entity.LinksEntity;
import lombok.RequiredArgsConstructor;

@Converter
@RequiredArgsConstructor
public class LinksConverter {

public LinksEntity toEntity(LinkReqDTO req, CollectionsEntity collection) {

return LinksEntity.builder()
.title(req.getDescription())
.url(req.getUrl())
.description(req.getDescription())
.collection(collection)
.build();
}

// public LinkResDTO toResponse(LinksEntity link) {
//
// }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.e2i1.linkeepserver.domain.links.dto;

import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
Expand All @@ -11,7 +12,11 @@
@AllArgsConstructor
public class LinkReqDTO {
private String title;

@NotBlank(message = "URL은 필수 입력입니다.")
private String url;
private String description;

@NotBlank(message = "저장할 모음집을 선택하세요.")
private Long collectionId;
}
Loading

0 comments on commit 2e9be72

Please sign in to comment.