Skip to content
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
Binary file added .DS_Store
Binary file not shown.
18 changes: 13 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.1'
id 'io.spring.dependency-management' version '1.1.0'
id 'org.springframework.boot' version '2.7.8'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'com.dku'
group = 'com.project'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
sourceCompatibility = '11'

configurations {
compileOnly {
Expand All @@ -22,11 +22,19 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
implementation 'org.jetbrains:annotations:23.0.0'
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'

// jwt
implementation 'io.jsonwebtoken:jjwt:0.9.1'

//validation
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.slf4j:slf4j-api:1.7.31'
}

tasks.named('test') {
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1 +1 @@
rootProject.name = 'springstudy'
rootProject.name = 'carrot'
13 changes: 0 additions & 13 deletions src/main/java/com/dku/springstudy/SpringStudyApplication.java

This file was deleted.

15 changes: 15 additions & 0 deletions src/main/java/com/project/carrot/CarrotApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.project.carrot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing //JpaAuditing을 활성화 해주는 기능
@SpringBootApplication
public class CarrotApplication {

public static void main(String[] args) {
SpringApplication.run(CarrotApplication.class, args);
}

}
11 changes: 11 additions & 0 deletions src/main/java/com/project/carrot/CustomException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.project.carrot;

import com.project.carrot.domain.ErrorCode;
import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public class CustomException extends RuntimeException{
ErrorCode errorCode;
}
57 changes: 57 additions & 0 deletions src/main/java/com/project/carrot/MyInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.project.carrot;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.project.carrot.domain.PostSaveDTO;
import com.project.carrot.domain.SuccessResponseDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j //로깅에 사용하는 어노테이션
@RequiredArgsConstructor
@Component
public class MyInterceptor implements HandlerInterceptor {
private final ObjectMapper objectMapper;
@Override
public void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object object,
Exception ex
) throws Exception {
//wrapping 된 Response 가 넘어 올 것이다.
final ContentCachingResponseWrapper cachingResponse = (ContentCachingResponseWrapper) response;
//200번대 응답이 아닌 경우 Interceptor 를 거치지 않는다.
if (!String.valueOf(response.getStatus()).startsWith("2")) {
return;
}
//Json 형식의 응답값만 수정 - @ResponseBody를 통해 Object 반환은 JSON으로 넘어옴.
if (cachingResponse.getContentType() != null && (cachingResponse.getContentType().contains("application/json"))) {
if (cachingResponse.getContentAsByteArray().length != 0) {
//String 변환 ex){"key":"value"}
String body = new String(cachingResponse.getContentAsByteArray());

//Object형식으로 변환 -> Response에 꽂아주기 위함.
Object data = objectMapper.readValue(body, Object.class);

//ResponseEntity 생성
SuccessResponseDTO<Object> objectResponseDTO = new SuccessResponseDTO<>(data);

//String 변환 -> Byte로 쓰기 위함.
String wrappedBody = objectMapper.writeValueAsString(objectResponseDTO);

//flush 버퍼에 있는 데이터를 처리함.
cachingResponse.resetBuffer();

//덮어쓰기
cachingResponse.getOutputStream().write(wrappedBody.getBytes(), 0, wrappedBody.getBytes().length);
log.info("Response Body : {}", wrappedBody);
}
}
}
}
32 changes: 32 additions & 0 deletions src/main/java/com/project/carrot/Service/MemberItemService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.project.carrot.Service;

import com.project.carrot.domain.ItemDTO;
import com.project.carrot.domain.MemberItem;
import com.project.carrot.repository.MemberItemRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
public class MemberItemService {
/*
* 상품 등록 페이지 구현
* */

public final MemberItemRepository memberItemRepository;

@Transactional
public MemberItem append(MemberItem memberItem){
return memberItemRepository.save(memberItem);
}

@Transactional
public MemberItem saled(Long itemId, Long userId){
MemberItem memberItem=memberItemRepository.findByItemId(itemId)
.orElseThrow(()->new RuntimeException("존재하지 않는 유저입니다."));
//memberItem=memberItem.toBuilder().ItemForSale(false).build();
memberItem.update(false,userId);

System.out.println(memberItem.toString());
return memberItem;
}
}
47 changes: 47 additions & 0 deletions src/main/java/com/project/carrot/Service/MemberService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.project.carrot.Service;

import com.project.carrot.domain.Member;
import com.project.carrot.domain.PostSaveDTO;
import com.project.carrot.repository.MemberRepository;
import lombok.NoArgsConstructor;
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;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;


@RequiredArgsConstructor
@Transactional//JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행되어야만 한다.
public class MemberService implements UserDetailsService {
/*
회원가입, 로그인 기능 개발
*/
private final MemberRepository memberRepository;

public Member join(Member member){
memberRepository.findByEmail(member.getUserEmail())
.ifPresent(m->{throw new IllegalStateException("이미 존재하는 이메일입니다.");});

return memberRepository.save(member);
}

//컨트롤러에서 역할 수행하게 되어 주석처리
/*public Member Login(String email, String password){
Member findMember = memberRepository.findByEmail(email)
.orElseThrow(() -> new IllegalStateException("이메일이 일치하지 않습니다."));

if(findMember.getUserPass() != password) throw new IllegalStateException("패스워드가 일치하지 않습니다.");

return findMember;
}*/

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return memberRepository.findByEmail(username)
.orElseThrow(()->new UsernameNotFoundException("사용자를 찾을 수 없습니다."));
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/project/carrot/config/InterceptorConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.project.carrot.config;

import com.project.carrot.MyInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration //설정 파일이고 Bean을 등록할 것이다.
@RequiredArgsConstructor
public class InterceptorConfig implements WebMvcConfigurer {
private final MyInterceptor myInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(myInterceptor)
.addPathPatterns("/**"); //localhost:8080 의 이하 경로
}
}
47 changes: 47 additions & 0 deletions src/main/java/com/project/carrot/config/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.project.carrot.config;

import com.project.carrot.security.JwtAuthenticationFilter;
import com.project.carrot.security.JwtTokenProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

private final JwtTokenProvider jwtTokenProvider;

// authenticationManager를 Bean 등록합니다.
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}

@Override
protected void configure(HttpSecurity http) throws Exception {

http.csrf().disable();
//http.httpBasic().disable(); // 일반적인 루트가 아닌 다른 방식으로 요청시 거절, header에 id, pw가 아닌 token(jwt)을 달고 간다. 그래서 basic이 아닌 bearer를 사용한다.
http.httpBasic().disable()
.authorizeRequests()// 요청에 대한 사용권한 체크
.antMatchers("/test").authenticated()
//.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/**").permitAll()
.and()
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
UsernamePasswordAuthenticationFilter.class); // JwtAuthenticationFilter를 UsernamePasswordAuthenticationFilter 전에 넣는다
// + 토큰에 저장된 유저정보를 활용하여야 하기 때문에 CustomUserDetailService 클래스를 생성합니다.
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);


}
}

42 changes: 42 additions & 0 deletions src/main/java/com/project/carrot/config/SpringConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.project.carrot.config;

import com.project.carrot.Service.MemberItemService;
import com.project.carrot.Service.MemberService;
import com.project.carrot.repository.JPAMemberItemRepository;
import com.project.carrot.repository.JPAMemberRepository;
import com.project.carrot.repository.MemberItemRepository;
import com.project.carrot.repository.MemberRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.persistence.EntityManager;
import javax.sql.DataSource;

@Configuration
public class SpringConfig {

private final DataSource dataSource;
private final EntityManager em;

public SpringConfig(DataSource dataSource, EntityManager em) {
this.dataSource = dataSource;
this.em = em;
}


@Bean
public MemberService memberService(){
return new MemberService(memberRepository());
}

@Bean
public MemberRepository memberRepository(){
return new JPAMemberRepository(em);
}

@Bean
public MemberItemService memberItemService(){return new MemberItemService(memberItemRepository());}

@Bean
public MemberItemRepository memberItemRepository(){return new JPAMemberItemRepository(em);}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.project.carrot.controller;

import com.project.carrot.CustomException;
import com.project.carrot.domain.ExceptionDTO;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice //@ControllerAdvice + @ResponseBody
//@ControllerAdvice는 컨트롤러에서 발생하는 에러를 처리 //SecurityFilter에서 발생하는 예외는 스프링의 것이 아니므로 처리하지 못함
//@ResponseBody: 응답값 String->Stirng, Object->Json 형식으로 반환해준다.
//@ExceptionHandler: 특정 예외처리를 지정하여 관리
public class ControllerAdvisor {
@ExceptionHandler(value = {CustomException.class})
protected ResponseEntity exceptionHandler(CustomException e){
return ResponseEntity.status(e.getErrorCode().getStatus())
.body(new ExceptionDTO(e));
}
}
Loading