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

전남대 BE_조설빈 5주차 과제 (1단계) #261

Open
wants to merge 13 commits into
base: seolbin96
Choose a base branch
from
Open
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ out/

### Mac OS ###
.DS_Store

# 환경 변수 설정 파일
application-secret.properties
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
# spring-gift-order
# spring-gift-order

### 기능 구현 목록
1. 카카오 로그인 화면 구현
2. 인가 코드 받기
3. 인가 코드를 사용해 액세스 토큰 받기
4. 액세스 토큰을 사용해 사용자 정보 가져오기
5. 사용자 정보로 JWT 토큰 생성

### 추가로 할 일
- api 키 하드코딩한 부분 수정하기 (숨기도록 수정)
15 changes: 13 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,25 @@ repositories {
}

dependencies {
runtimeOnly 'com.h2database:h2'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springframework.boot:spring-boot-starter-validation'

compileOnly 'io.jsonwebtoken:jjwt-api:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.1'
testImplementation 'org.mockito:mockito-core:3.6.28'
testImplementation 'org.mockito:mockito-junit-jupiter:3.6.28'
}

tasks.named('test') {
useJUnitPlatform()
}
}
23 changes: 23 additions & 0 deletions src/main/java/gift/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package gift.config;

import gift.security.LoginMemberArgumentResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {

private final LoginMemberArgumentResolver loginMemberArgumentResolver;

public WebConfig(LoginMemberArgumentResolver loginMemberArgumentResolver) {
this.loginMemberArgumentResolver = loginMemberArgumentResolver;
}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(loginMemberArgumentResolver);
}
}
42 changes: 42 additions & 0 deletions src/main/java/gift/controller/CategoryController.java
Copy link

Choose a reason for hiding this comment

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

과제 요구사항 밖일 수 있으나, 생각해보면 카테고리를 누구나 수정, 삭제할 수 있는 건 조금 이상한 것 같습니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package gift.controller;

import gift.dto.CategoryDTO;
import gift.service.CategoryService;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/categories")
public class CategoryController {
private final CategoryService categoryService;

public CategoryController(CategoryService categoryService) {
this.categoryService = categoryService;
}

@GetMapping
public ResponseEntity<Page<CategoryDTO>> readCategory(@RequestParam int page, @RequestParam int size) {
Page<CategoryDTO> categories = categoryService.findAll(page, size);
return new ResponseEntity<>(categories, HttpStatus.OK);
}

@PostMapping
public ResponseEntity<Void> createCategory(@RequestBody CategoryDTO categoryDTO) {
categoryService.save(categoryDTO);
return new ResponseEntity<>(HttpStatus.CREATED);
}

@PutMapping("/{category_id}")
public ResponseEntity<Void> updateCategory(@PathVariable("category_id") Long id, @RequestBody CategoryDTO categoryDTO) {
categoryService.update(id, categoryDTO);
return new ResponseEntity<>(HttpStatus.OK);
}

@DeleteMapping("/{category_id}")
public ResponseEntity<Void> deleteCategory(@PathVariable("category_id") Long id) {
categoryService.delete(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
48 changes: 48 additions & 0 deletions src/main/java/gift/controller/KakaoLoginController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package gift.controller;

import gift.service.KakaoService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.view.RedirectView;

@Controller
public class KakaoLoginController {

@Value("${kakao.client-id}")
private String clientId;

@Value("${kakao.redirect-uri}")
private String redirectUri;

private final KakaoService kakaoService;

public KakaoLoginController(KakaoService kakaoService) {
this.kakaoService = kakaoService;
}

@GetMapping("/kakaoLogin")
public String oauthLogin() {
String url = "https://kauth.kakao.com/oauth/authorize?";
url += "scope=talk_message&";
url += "response_type=code&";
url += "redirect_uri=" + redirectUri + "&";
url += "client_id=" + clientId;
return "redirect:" + url;
}

@GetMapping("/")
public RedirectView callback(@RequestParam(name = "code") String code, RedirectAttributes redirectAttributes) throws Exception {
String token = kakaoService.login(code);
redirectAttributes.addFlashAttribute("token", token);
Copy link

Choose a reason for hiding this comment

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

이렇게 되면 로그인이 잘 유지되는건지 궁금합니다.

return new RedirectView("/home");
}

@GetMapping("/home")
public String home(Model model) {
return "home";
}
}
31 changes: 31 additions & 0 deletions src/main/java/gift/controller/OptionController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package gift.controller;

import gift.dto.OptionDTO;
import gift.service.OptionService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/products/{productId}/options")
public class OptionController {
private final OptionService optionService;

public OptionController(OptionService optionService) {
this.optionService = optionService;
}

@GetMapping
public ResponseEntity<List<OptionDTO>> getOptionsByProductId(@PathVariable Long productId) {
List<OptionDTO> options = optionService.getOptionsByProductId(productId);
return new ResponseEntity<>(options, HttpStatus.OK);
}

@PostMapping
public ResponseEntity<OptionDTO> addOptionToProduct(@PathVariable Long productId, @RequestBody OptionDTO optionDTO) {
OptionDTO createdOption = optionService.addOptionToProduct(productId, optionDTO);
return new ResponseEntity<>(createdOption, HttpStatus.CREATED);
}
}
57 changes: 57 additions & 0 deletions src/main/java/gift/controller/ProductAdminController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package gift.controller;

import gift.dto.ProductDTO;
import gift.service.ProductService;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("/admin/products")
public class ProductAdminController {

private final ProductService productService;

public ProductAdminController(ProductService productService) {
this.productService = productService;
}

@GetMapping
public String listProducts(Model model, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "5") int size) {
Page<ProductDTO> productsPage = productService.getAllProducts(page, size);
model.addAttribute("productsPage", productsPage);
return "productList";
}

@GetMapping("/add")
public String addProductForm(Model model) {
model.addAttribute("product", new ProductDTO());
return "productForm";
}

@PostMapping("/add")
public String addProduct(@ModelAttribute ProductDTO productDTO) {
productService.saveProduct(productDTO);
return "redirect:/admin/products";
}

@GetMapping("/edit/{id}")
public String editProductForm(@PathVariable Long id, Model model) {
ProductDTO productDTO = productService.getProductById(id);
model.addAttribute("product", productDTO);
return "productForm";
}

@PostMapping("/edit/{id}")
public String updateProduct(@PathVariable Long id, @ModelAttribute ProductDTO productDTO) {
productService.updateProduct(id, productDTO);
return "redirect:/admin/products";
}

@GetMapping("/delete/{id}")
public String deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
return "redirect:/admin/products";
}
}
58 changes: 58 additions & 0 deletions src/main/java/gift/controller/ProductController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package gift.controller;

import gift.dto.ProductDTO;
import gift.service.ProductService;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;

@RestController
@RequestMapping("/api/products")
public class ProductController {

private final ProductService productService;

public ProductController(ProductService productService) {
this.productService = productService;
}

@GetMapping
public ResponseEntity<Page<ProductDTO>> getAllProducts(@RequestParam int page, @RequestParam int size) {
Page<ProductDTO> products = productService.getAllProducts(page, size);
return new ResponseEntity<>(products, HttpStatus.OK);
}

@GetMapping("/{id}")
public ResponseEntity<ProductDTO> getProductById(@PathVariable Long id) {
ProductDTO product = productService.getProductById(id);
return new ResponseEntity<>(product, HttpStatus.OK);
}

@PostMapping
public ResponseEntity<Void> addProduct(@RequestBody @Valid ProductDTO productDTO, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
productService.saveProduct(productDTO);
return new ResponseEntity<>(HttpStatus.CREATED);
}

@PutMapping("/{id}")
public ResponseEntity<Void> updateProduct(@PathVariable Long id, @RequestBody @Valid ProductDTO productDTO, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
productService.updateProduct(id, productDTO);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
45 changes: 45 additions & 0 deletions src/main/java/gift/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package gift.controller;

import gift.model.User;
import gift.service.UserService;
import gift.dto.TokenResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/members")
public class UserController {
private final UserService userService;

@Autowired
public UserController(UserService userService) {
this.userService = userService;
}

@PostMapping("/register")
public ResponseEntity<TokenResponse> register(@RequestBody User user) {
try {
userService.createUser(user);
TokenResponse tokenResponse = userService.createTokenResponse(user);
return new ResponseEntity<>(tokenResponse, HttpStatus.CREATED);
} catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}

@PostMapping("/login")
public ResponseEntity<TokenResponse> login(@RequestBody User user) {
try {
User savedUser = userService.loadOneUser(user.getEmail());
if (savedUser != null && savedUser.getPassword().equals(user.getPassword())) {
TokenResponse tokenResponse = userService.createTokenResponse(savedUser);
return new ResponseEntity<>(tokenResponse, HttpStatus.OK);
}
return new ResponseEntity<>(null, HttpStatus.UNAUTHORIZED);
} catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
Loading