diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..85e7c1d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/.idea/
diff --git a/.idea/Backend.iml b/.idea/Backend.iml
deleted file mode 100644
index d6ebd48..0000000
--- a/.idea/Backend.iml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index 3f04895..0000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index e3a6f1d..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index f43d862..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
deleted file mode 100644
index e4623b0..0000000
--- a/.idea/workspace.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1704176766234
-
-
- 1704176766234
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index aee2944..a782736 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,14 @@
# Backend
TEAM2 백엔드 레포지토리입니다.
+
+## 사용기술
+- SpringBoot
+- Spring Data JPA
+- Spring Security
+- MySQL
+- JWT + OAuth2.0
+- NCP Server
+- NCP Object Storage
+
+## 아키텍처
+
diff --git a/ping/.gitignore b/ping/.gitignore
index ba9d2be..b3fd7d3 100644
--- a/ping/.gitignore
+++ b/ping/.gitignore
@@ -16,7 +16,6 @@ build/
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
-
### IntelliJ IDEA ###
.idea
*.iws
@@ -26,6 +25,9 @@ out/
!**/src/main/**/out/
!**/src/test/**/out/
application.yml
+JwtProperties.java
+OAuthProperties.java
+NcpObjectStorageConfig.java
### NetBeans ###
/nbproject/private/
@@ -33,6 +35,6 @@ application.yml
/dist/
/nbdist/
/.nb-gradle/
-
+frontend/
### VS Code ###
.vscode/
diff --git a/ping/build.gradle b/ping/build.gradle
index 31c81af..82c7868 100644
--- a/ping/build.gradle
+++ b/ping/build.gradle
@@ -26,13 +26,24 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
+ implementation group: 'com.auth0', name: 'java-jwt', version: '4.3.0'
+ implementation 'org.springframework.boot:spring-boot-devtools'
+ implementation 'org.springframework.boot:spring-boot-starter-validation'
+ implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6'
+ implementation 'org.apache.httpcomponents:httpclient:4.5.13'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
+ implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
+ implementation 'com.fasterxml.jackson.core:jackson-databind'
}
tasks.named('test') {
useJUnitPlatform()
}
+
+bootJar {
+ duplicatesStrategy = DuplicatesStrategy.EXCLUDE
+}
\ No newline at end of file
diff --git a/ping/src/main/java/com/b6122/ping/ImgPathProperties.java b/ping/src/main/java/com/b6122/ping/ImgPathProperties.java
new file mode 100644
index 0000000..d587404
--- /dev/null
+++ b/ping/src/main/java/com/b6122/ping/ImgPathProperties.java
@@ -0,0 +1,6 @@
+package com.b6122.ping;
+
+public interface ImgPathProperties {
+
+ String postImgPath = "C:\\ping\\post\\image";
+}
diff --git a/ping/src/main/java/com/b6122/ping/PingApplication.java b/ping/src/main/java/com/b6122/ping/PingApplication.java
index 1cc78e3..e7b4b62 100644
--- a/ping/src/main/java/com/b6122/ping/PingApplication.java
+++ b/ping/src/main/java/com/b6122/ping/PingApplication.java
@@ -2,10 +2,19 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@SpringBootApplication
+@EnableJpaAuditing
public class PingApplication {
+ @Bean
+ public BCryptPasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
public static void main(String[] args) {
SpringApplication.run(PingApplication.class, args);
}
diff --git a/ping/src/main/java/com/b6122/ping/auth/PrincipalDetails.java b/ping/src/main/java/com/b6122/ping/auth/PrincipalDetails.java
new file mode 100644
index 0000000..04cda93
--- /dev/null
+++ b/ping/src/main/java/com/b6122/ping/auth/PrincipalDetails.java
@@ -0,0 +1,57 @@
+package com.b6122.ping.auth;
+
+import com.b6122.ping.domain.User;
+import lombok.Data;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+@Data
+public class PrincipalDetails implements UserDetails {
+
+ private User user;
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ Collection authorities = new ArrayList<>();
+ authorities.add(new SimpleGrantedAuthority(user.getRole().toString())); // Enum을 문자열로 변환하여 SimpleGrantedAuthority 생성
+ return authorities;
+ }
+
+ @Override
+ public String getPassword() {
+ return null;
+ }
+
+ @Override
+ public String getUsername() {
+ return null;
+ }
+
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
+ public PrincipalDetails(User user) {
+ this.user = user;
+ }
+}
diff --git a/ping/src/main/java/com/b6122/ping/auth/PrincipalDetailsService.java b/ping/src/main/java/com/b6122/ping/auth/PrincipalDetailsService.java
new file mode 100644
index 0000000..7fd4d19
--- /dev/null
+++ b/ping/src/main/java/com/b6122/ping/auth/PrincipalDetailsService.java
@@ -0,0 +1,26 @@
+package com.b6122.ping.auth;
+
+import com.b6122.ping.domain.User;
+import com.b6122.ping.repository.datajpa.UserDataRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+// http://localhost:8080/login을 통해 로그인을 안함(disable 해놔서) 따라서 아래 서비스가 동작하기 위한
+// 필터를 하나 만들어야 된다(JwtAuthenticationFilter)
+// 근데 우리 서비스는 ~/login을 통해 요청할 일이 없기 때문에, JwtAuthenticationFilter도 사실상 필요가 없다
+// jwt 토큰 발급 후 JwtAuthorizationFilter에서 시큐리티 세션에 Authentication 객체를 저장하여 권한 관리를 하고 있다.
+@Service
+@RequiredArgsConstructor
+public class PrincipalDetailsService implements UserDetailsService {
+
+ private final UserDataRepository userDataRepository;
+
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ User userEntity = userDataRepository.findByUsername(username).orElseThrow();
+ return new PrincipalDetails(userEntity);
+ }
+}
diff --git a/ping/src/main/java/com/b6122/ping/config/CorsConfig.java b/ping/src/main/java/com/b6122/ping/config/CorsConfig.java
new file mode 100644
index 0000000..c6f9c38
--- /dev/null
+++ b/ping/src/main/java/com/b6122/ping/config/CorsConfig.java
@@ -0,0 +1,25 @@
+package com.b6122.ping.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+@Configuration
+public class CorsConfig {
+
+ @Bean
+ public CorsFilter corsFilter() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ CorsConfiguration config = new CorsConfiguration();
+ config.setAllowCredentials(true); // 내 서버가 응답을 할 때 json을 자바스크립트에서 처리할 수 있게 할지를 설정
+// config.addAllowedOriginPattern("http://61.97.185.12");
+ config.addAllowedOriginPattern("http://localhost:3000");
+ config.addAllowedHeader("*"); // 모든 header에 응답을 허용
+ config.addAllowedMethod("*"); // 모든 http method를 허용
+ source.registerCorsConfiguration("/**", config);
+ return new CorsFilter(source);
+
+ }
+}
diff --git a/ping/src/main/java/com/b6122/ping/config/SecurityConfig.java b/ping/src/main/java/com/b6122/ping/config/SecurityConfig.java
new file mode 100644
index 0000000..b99ea0b
--- /dev/null
+++ b/ping/src/main/java/com/b6122/ping/config/SecurityConfig.java
@@ -0,0 +1,54 @@
+package com.b6122.ping.config;
+
+import com.b6122.ping.config.jwt.JwtAuthorizationFilter;
+import com.b6122.ping.repository.datajpa.UserDataRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.web.SecurityFilterChain;
+
+
+@Configuration
+@EnableWebSecurity
+@RequiredArgsConstructor
+public class SecurityConfig {
+
+ private final CorsConfig corsConfig;
+ private final UserDetailsService userDetailsService;
+ private final UserDataRepository userDataRepository;
+
+ @Bean
+ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+
+ //AuthenticaionManager 생성
+ AuthenticationManagerBuilder sharedObject = http.getSharedObject(AuthenticationManagerBuilder.class);
+ sharedObject.userDetailsService(this.userDetailsService); //이 userDetailsService와 PrincipalDetailsService에서 상속받는 인터페이스는 서로 같음.
+ AuthenticationManager authenticationManager = sharedObject.build();
+ http.authenticationManager(authenticationManager);
+ //세션 만들지 않기.
+ http
+ .addFilter(corsConfig.corsFilter())
+ .csrf(AbstractHttpConfigurer::disable)
+ .sessionManagement((sessionManagement) -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+ .formLogin((formLogin) -> formLogin.disable())
+// .addFilter(new JwtAuthenticationFilter((authenticationManager)))
+ .addFilter((new JwtAuthorizationFilter(authenticationManager, userDataRepository)))
+ .httpBasic((httpBasic) -> httpBasic.disable()) //Bearer 방식을 사용하기 위해 basic 인증 비활성화
+ .authorizeHttpRequests((authorize) ->
+ authorize
+ .requestMatchers("/api/oauth/jwt/**").permitAll()
+ .requestMatchers("/admin/**").hasAnyRole("ADMIN")
+ .requestMatchers("/**").hasAnyRole("ADMIN", "USER")
+ .anyRequest().authenticated());
+
+
+ return http.build();
+ }
+}
diff --git a/ping/src/main/java/com/b6122/ping/config/jwt/JwtAuthenticationFilter.java b/ping/src/main/java/com/b6122/ping/config/jwt/JwtAuthenticationFilter.java
new file mode 100644
index 0000000..76fb3d9
--- /dev/null
+++ b/ping/src/main/java/com/b6122/ping/config/jwt/JwtAuthenticationFilter.java
@@ -0,0 +1,67 @@
+//package com.b6122.ping.config.jwt;
+//
+//import com.auth0.jwt.JWT;
+//import com.auth0.jwt.algorithms.Algorithm;
+//import com.b6122.ping.auth.PrincipalDetails;
+//import com.b6122.ping.domain.User;
+//import com.fasterxml.jackson.databind.ObjectMapper;
+//import jakarta.servlet.FilterChain;
+//import jakarta.servlet.ServletException;
+//import jakarta.servlet.http.HttpServletRequest;
+//import jakarta.servlet.http.HttpServletResponse;
+//import lombok.RequiredArgsConstructor;
+//import org.springframework.security.authentication.AuthenticationManager;
+//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+//import org.springframework.security.core.Authentication;
+//import org.springframework.security.core.AuthenticationException;
+//import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+//
+//import java.io.IOException;
+//import java.util.Date;
+//
+//@RequiredArgsConstructor
+//public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
+//
+// private final AuthenticationManager authenticationManager;
+//
+// //로그인 요청을 하면, 로그인 시도를 위해 실행되는 메소드
+// @Override
+// public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
+// System.out.println("로그인 시도중");
+//
+// //넘어온 username과 pw를 받아서
+// ObjectMapper objectMapper = new ObjectMapper();
+// try {
+// //json 데이터를 가정
+// User user = objectMapper.readValue(request.getInputStream(), User.class);
+// //authenticationManager에 넘겨주기 위해 토큰 생성
+// UsernamePasswordAuthenticationToken authenticationToken =
+// new UsernamePasswordAuthenticationToken(user.getUsername(), "1234");
+// //토큰을 authenticate()에 넘겨주면, PrincipalDetailsService의 loadByUsername() 실행
+// //service에서 인증이 완료되면 로그인 완료(DB의 데이터와 들어온 데이터가 일치)
+// Authentication authentication = authenticationManager.authenticate(authenticationToken);
+//
+// return authentication; //세션에 저장
+// //세션에 저장하는 이유는, security가 권한 관리를 해주기 때문에
+// //자세한 이유 --> https://www.inflearn.com/questions/714149/jwt-token-%EA%B5%AC%ED%98%84%EC%97%90%EC%84%9C-session-%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C%EB%8B%A4
+// } catch (IOException e) {
+// throw new RuntimeException(e);
+// }
+// }
+//
+// // attemptAuthentication이 성공적으로 실행 이후 successfulAuthentication 메소드 실행.
+// // 아래 메소드에서 JWT 토큰 생성 후 사용자에게 response 해준다.
+// @Override
+// protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
+// PrincipalDetails principalDetails = (PrincipalDetails) authResult.getPrincipal();
+//
+// //HMAC512 방식 암호화
+// String jwtToken = JWT.create()
+// .withSubject("jwt토큰")
+// .withExpiresAt(new Date(System.currentTimeMillis() + (60000 * 10))) //10분
+// .withClaim("id", principalDetails.getUser().getId())
+// .withClaim("username",principalDetails.getUser().getUsername())
+// .sign(Algorithm.HMAC512("secretKeyByServer"));
+// response.addHeader("Authorization", "Bearer " + jwtToken);
+// }
+//}
diff --git a/ping/src/main/java/com/b6122/ping/config/jwt/JwtAuthorizationFilter.java b/ping/src/main/java/com/b6122/ping/config/jwt/JwtAuthorizationFilter.java
new file mode 100644
index 0000000..e42356f
--- /dev/null
+++ b/ping/src/main/java/com/b6122/ping/config/jwt/JwtAuthorizationFilter.java
@@ -0,0 +1,97 @@
+package com.b6122.ping.config.jwt;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTVerificationException;
+import com.b6122.ping.auth.PrincipalDetails;
+import com.b6122.ping.domain.User;
+import com.b6122.ping.dto.UserDto;
+import com.b6122.ping.repository.datajpa.UserDataRepository;
+import com.b6122.ping.service.JwtService;
+import jakarta.persistence.EntityNotFoundException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
+
+import java.io.IOException;
+import java.util.Map;
+
+public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
+
+ private UserDataRepository userDataRepository;
+ private JwtService jwtService;
+
+ public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserDataRepository userDataRepository) {
+ super(authenticationManager);
+ this.userDataRepository = userDataRepository;
+ }
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+
+ String header = request.getHeader(JwtProperties.HEADER_STRING);
+
+ if (header == null || !header.startsWith(JwtProperties.TOKEN_PREFIX)) {
+ chain.doFilter(request, response);
+ return;
+ }
+
+ //토큰 검증(동일한 토큰인지, 만료시간은 안지났는지 com.auth0.jwt 라이브러리가 확인해줌)
+ //access token과 refresh token을 검증
+ String username = null;
+ String token = request.getHeader(JwtProperties.HEADER_STRING).replace(JwtProperties.TOKEN_PREFIX, "");
+ String tokenType = JWT.decode(token).getClaim("token_type").asString();
+
+ if (tokenType.equals("access")) {
+ try {
+ username = JWT.require(Algorithm.HMAC512(JwtProperties.SECRET)).build().verify(token).getClaim("username").asString();
+ } catch(JWTVerificationException e) {
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.getWriter().write("Access token is not valid. Please send refersh token.");
+ return;
+ }
+ } else if (tokenType.equals("refresh")) {
+
+ try {
+ username = JWT.require(Algorithm.HMAC512(JwtProperties.SECRET)).build().verify(token).getClaim("username").asString();
+ User user = userDataRepository.findByUsername(username).orElseThrow(EntityNotFoundException::new);
+ UserDto userDto = new UserDto(user.getId(), user.getUsername());
+ Map jwtAccessToken = jwtService.createJwtAccessToken(userDto);
+
+ //refersh token이 유효하면 access token 새로 발급
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.getWriter().write("{\"access-token\": \"" + jwtAccessToken.get("access-token") + "\"}");
+ return;
+
+ } catch (JWTVerificationException e) {
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.getWriter().write("Refresh token is not valid. Please login again.");
+ return;
+ }
+ }
+
+ if (username != null) {
+ User user = userDataRepository.findByUsername(username).orElseThrow(EntityNotFoundException::new);
+
+ // 인증은 토큰 검증시 끝. 인증을 하기 위해서가 아닌 스프링 시큐리티가 수행해주는 권한 처리를 위해
+ // 아래와 같이 토큰을 만들어서 Authentication 객체를 강제로 만들고 그걸 세션에 저장
+ PrincipalDetails principalDetails = new PrincipalDetails(user);
+ Authentication authentication = new UsernamePasswordAuthenticationToken(principalDetails,
+ null,
+ principalDetails.getAuthorities());
+ // 강제로 시큐리티의 세션에 접근하여 값 저장
+ // -> 컨트롤러에서 Authentication 객체를 받아서(DI) 권한 처리를 할 수 있음.
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ }
+
+ chain.doFilter(request, response);
+ }
+
+}
diff --git a/ping/src/main/java/com/b6122/ping/controller/PostController.java b/ping/src/main/java/com/b6122/ping/controller/PostController.java
new file mode 100644
index 0000000..a835420
--- /dev/null
+++ b/ping/src/main/java/com/b6122/ping/controller/PostController.java
@@ -0,0 +1,186 @@
+package com.b6122.ping.controller;
+
+import com.b6122.ping.auth.PrincipalDetails;
+import com.b6122.ping.domain.PostScope;
+import com.b6122.ping.dto.PostDto;
+import com.b6122.ping.service.PostService;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+
+import org.apache.catalina.filters.AddDefaultCharsetFilter;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+@Getter@Setter
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api")
+public class PostController {
+ private final PostService postService;
+
+ //글 작성 후 디비 저장
+ @PostMapping("/posts/home/store")
+ public ResponseEntity getPost(@RequestParam("title") String title,
+ @RequestParam("content") String content,
+ @RequestParam("latitude") float latitude,
+ @RequestParam("longitude") float longitude,
+ @RequestParam("scope") String scope,
+ @RequestParam(value = "img", required = false) List img,
+ Authentication authentication){
+ PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
+
+ PostDto postDto = new PostDto();
+ postDto.setTitle(title);
+ postDto.setContent(content);
+ postDto.setLatitude(latitude);
+ postDto.setLongitude(longitude);
+ postDto.setImgs(img);
+ postDto.setUid(principalDetails.getUser().getId());
+ if("private".equals(scope)){
+ postDto.setScope(PostScope.PRIVATE);
+ } else if("public".equals(scope)) {
+ postDto.setScope(PostScope.PUBLIC);
+ } else {
+ postDto.setScope(PostScope.FRIENDS);
+ }
+ Long pid = postService.createPost(postDto);
+ return ResponseEntity.status(HttpStatus.CREATED).body(pid);
+ }
+
+ //글 수정 후 디비 저장
+ @PutMapping("/posts/home/edit/{postId}")
+ public ResponseEntity modifyPost(@RequestParam("title") String title,
+ @RequestParam("content") String content,
+ @RequestParam("latitude") float latitude,
+ @RequestParam("longitude") float longitude,
+ @RequestParam("scope") String scope,
+ @RequestParam(value = "img", required = false) List img,
+ @PathVariable("postId") Long postId,
+ Authentication authentication){
+
+ PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
+
+ PostDto postDto = new PostDto();
+ postDto.setTitle(title);
+ postDto.setContent(content);
+ postDto.setLatitude(latitude);
+ postDto.setLongitude(longitude);
+ postDto.setImgs(img);
+ postDto.setUid(principalDetails.getUser().getId());
+ postDto.setId(postId);
+ if("private".equals(scope)){
+ postDto.setScope(PostScope.PRIVATE);
+ } else if("public".equals(scope)) {
+ postDto.setScope(PostScope.PUBLIC);
+ } else {
+ postDto.setScope(PostScope.FRIENDS);
+ }
+ Long pid = postService.modifyPost(postDto);
+ return ResponseEntity.status(HttpStatus.CREATED).body(pid);
+ }
+
+ //글 삭제
+ @PostMapping("/post/delete")
+ public ResponseEntity deletepost(@RequestParam("pid") Long pid){
+ postService.deletePost(pid);
+ return ResponseEntity.ok(pid);
+ }
+
+ //글 정보 반환, 조회수 ++
+ @GetMapping("/postInfo")
+ public ResponseEntity postInfo(@RequestParam("pid") Long pid,Authentication authentication ) {
+ PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
+ Long uid = principalDetails.getUser().getId();
+ PostDto pd = postService.getPostInfo(pid, uid);
+ System.out.println("PostDto = " + pd);
+ return ResponseEntity.ok(pd);
+ }
+
+ //좋아요 update
+ @PostMapping("/likeToggle")
+
+ public ResponseEntity toggleLike(@RequestParam List pids, @RequestParam List myLikes,Authentication authentication ) {
+ PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
+ Long uid = principalDetails.getUser().getId();
+ postService.toggleLike(pids, myLikes, uid);
+
+ return ResponseEntity.ok("Like toggled successfully");
+ }
+
+
+ //pin클릭 시 글 목록 반환, pid 리스트를 받아 반환, home friends public 동일
+ @GetMapping("/posts/clickPin")//map -> clickPin 변경
+ public ResponseEntity> postsPreviewPin(@RequestParam List pids){
+ List posts = postService.getPostsPreviewPin(pids);
+ return ResponseEntity.ok(posts);
+ }
+
+ //Home
+
+ //Home-Map, 내 모든 글의 pin 반환
+ @GetMapping("/posts/home/pins")
+ public ResponseEntity> showPinsHome(Authentication authentication) {
+ PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
+ Long uid = principalDetails.getUser().getId();
+ List posts = postService.getPinsHomeMap(uid);
+ return ResponseEntity.ok(posts);
+ }
+
+ //Home-List 토글, postList 반환
+ @GetMapping("/posts/home/list")
+ public ResponseEntity> showPostsHomeList(Authentication authentication) {
+ PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
+ Long uid = principalDetails.getUser().getId();
+ List posts = postService.getPostsHomeList(uid);
+ return ResponseEntity.ok().body(posts);
+ }
+
+
+
+
+ //Friend
+
+ //pins 반환, 친구 id 를 리스트로 받아 공개범위가 private이 아닌 것만 pid, 위도 경도 반환
+ @GetMapping("/posts/friends/pins")
+ public ResponseEntity> showPinsFriends(@RequestParam("uids") List uids) {
+ List posts = postService.getPinsFriendsMap(uids);
+ return ResponseEntity.ok(posts);
+ }
+
+
+ //친구 글 목록 preview 반환, 친구 id를 리스트로 받아 scope가 friend, public 인 것만 최신순으로 반환
+ @GetMapping("/posts/friends/list")
+ public ResponseEntity> showPostsFriendsList(@RequestParam("uids") List uids) {
+ List posts = postService.getPostsFriendsList(uids);
+ return ResponseEntity.ok().body(posts);
+ }
+
+
+
+
+ //public
+
+ //public pin반환, 반경 2km 내에 있는 글 반환
+ @GetMapping("/posts/public/pins")
+ public ResponseEntity> showPinsPubic(@RequestParam("longitude") float longitude, @RequestParam("latitude") float latitude) {
+ List posts = postService.getPinsPublicMap(longitude,latitude);
+ return ResponseEntity.ok(posts);
+ }
+
+
+ //public list 반환,반경 2km 내에 있는 글 반환
+
+ @GetMapping("/posts/public/list")
+ public ResponseEntity> showPostsPubicList(@RequestParam("longitude") float longitude, @RequestParam("latitude") float latitude) {
+ List posts = postService.getPostsPublicList(longitude,latitude);
+ return ResponseEntity.ok(posts);
+ }
+}
+
diff --git a/ping/src/main/java/com/b6122/ping/controller/RestApiController.java b/ping/src/main/java/com/b6122/ping/controller/RestApiController.java
new file mode 100644
index 0000000..9d92438
--- /dev/null
+++ b/ping/src/main/java/com/b6122/ping/controller/RestApiController.java
@@ -0,0 +1,177 @@
+package com.b6122.ping.controller;
+
+import com.b6122.ping.auth.PrincipalDetails;
+import com.b6122.ping.dto.*;
+import com.b6122.ping.service.*;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+import java.util.Map;
+
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api")
+public class RestApiController {
+
+ private final JwtService jwtService;
+ private final UserService userService;
+ private final FriendshipService friendshipService;
+ private final OauthService oauthService;
+
+ //프론트엔드로부터 authorization code 받고 -> 그 code로 카카오에 accesstoken 요청
+ // 받아 온 access token으로 카카오 리소스 서버로부터 카카오 유저 정보 가져오기
+ // 가져온 정보를 기반으로 회원가입
+ // jwt accessToken을 리액트 서버에 return
+// @PostMapping("/oauth/jwt")
+// public ResponseEntity