Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Team-A-I/otoo_java

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ“– ๊ฐˆ๋“ฑ ํŒ๊ฒฐ ์„œ๋น„์Šค '๋ช‡๋Œ€๋ช‡' (RestAPI)

์ด ํ”„๋กœ์ ํŠธ๋Š” ๋‹ค์–‘ํ•œ RESTful API๋ฅผ ์ œ๊ณตํ•˜๋Š” ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ž…๋‹ˆ๋‹ค.
์ฃผ์š” ๊ธฐ๋Šฅ์œผ๋กœ๋Š” STT API, Redis, JWT ์ธ์ฆ, JPA(ORM)๋ฅผ ์‚ฌ์šฉํ•œ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ ๋“ฑ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

๊ตฌ ์กฐ

Group 2245

ํ”„๋กœ์ ํŠธ ์„ค์น˜ ๋ฐ ์‹คํ–‰

  • ์ „์ œ ์กฐ๊ฑด
    • Java 17 ์ด์ƒ
    • Spring Boot 3.0

ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • (application.yml)


  jwt:
    secretKey: ${JWT_SECRET_KEY}

    access:
      expiration: 3600000
      header: Authorization

    refresh:
      expiration: 1209600000
      header: Authorization-refresh

  oauth:
    kakao:
      client_id: ${OAUTH_KAKAO_CLIENT_ID}
      url:
        auth: https://kauth.kakao.com
        api: https://kapi.kakao.com
    naver:
      client_id: ${OAUTH_NAVER_CLIENT_ID}
      client_secret: ${OAUTH_NAVER_CLIENT_SECRET}
      redirect_uri: 
    google:
      client_id: ${OAUTH_GOOGLE_CLIENT_ID}
      client_secret: ${OAUTH_GOOGLE_CLIENT_SECRET}
      redirect_uri: 


  spring:
    application:
      name: otoo_java
    datasource:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: ${SPRING_DATASOURCE_URL}
      username: ${SPRING_DATASOURCE_USERNAME}
      password: ${SPRING_DATASOURCE_PASSWORD}
    jpa:
      show-sql: true
      hibernate:
        ddl-auto: update
        properties:
          hibernate:
            format_sql: true
            dialect: org.hibernate.dialect.MySQLDialect
    mail:
      host: ${SPRING_MAIL_HOST}
      port: ${SPRING_MAIL_PORT}
      username: ${SPRING_MAIL_USERNAME}
      password: ${SPRING_MAIL_PASSWORD}
      properties:
        mail:
          smtp:
            auth: true
            starttls:
              enable: true
              required: true
            ssl:
              trust: ${SPRING_MAIL_HOST}


  fastapi:
    url: ${FASTAPI_URL}

  react:
    url: ${REACT_URL}

  rest:
    url: ${REST_URL}

  data:
    redis:
      port: 6379
      host: localhost

  server:
    port: 8080



  management:
    endpoints:
      web:
        exposure:
          include: health,info
    endpoint:
      health:
        show-details: always

Redis ์„ค์น˜ ๋ฐ ์‹คํ–‰

https://github.com/microsoftarchive/redis/releases ์„ค์น˜ -> redis-server ์‹คํ–‰

์ฃผ์š”๊ธฐ๋Šฅ ๋ฐ ์˜ˆ์ œ์ฝ”๋“œ

JWT ์ธ์ฆ

์„ค๋ช…

  • JWT(JSON Web Token)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์€ ์‚ฌ์šฉ์ž์˜ ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ณ ,
    ๊ถŒํ•œ ์žˆ๋Š” ์‚ฌ์šฉ์ž๋งŒ์ด ํŠน์ • API์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ์ฝ”๋“œ

// JwtUtil.java

@Slf4j
@Component
@RequiredArgsConstructor
public class JwtUtil {
    private final PrincipalDetailsService principalDetailsService;
    private static final long ACCESS_TIME = 24 * 60 * 60 * 1000L; // 1์ผ
    private static final long REFRESH_TIME = 7 * 24 * 60 * 60 * 1000L; // 7์ผ
    private static final String BEARER_PREFIX = "Bearer ";
    
    @Value("${JWT_SECRET_KEY}")
    private String secretKey;

    private Key key;
    private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

    @PostConstruct
    public void init() {
        key = Keys.hmacShaKeyFor(secretKey.getBytes());
    }

    public String createToken(String email, String type) {
        Date date = new Date();
        long time = type.equals("Access") ? ACCESS_TIME : REFRESH_TIME;
        Claims claims = Jwts.claims().setSubject(email).setIssuedAt(date).setExpiration(new Date(date.getTime() + time));
        return Jwts.builder().setClaims(claims).signWith(key, signatureAlgorithm).compact();
    }

    public boolean tokenValidation(String token) {
        try {
            Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            log.error("Invalid JWT token: {}", e.getMessage());
            return false;
        }
    }
}

Redis ์บ์‹ฑ

์„ค๋ช…

  • Redis๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์บ์‹ฑ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
    ์ด๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ์†๋„๋ฅผ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์ œ์ฝ”๋“œ

// RedisRefreshToken.java

@NoArgsConstructor
@Getter
@RedisHash("refreshToken")
public class RedisRefreshToken {
    @Id
    private String id;
    private String refreshToken;

    @TimeToLive(unit = TimeUnit.SECONDS)
    private Long expiration;

    public RedisRefreshToken(String email, String refreshToken, Long expiration) {
        this.id = email;
        this.refreshToken = refreshToken;
        this.expiration = expiration;
    }
}

STT API

์„ค๋ช…

  • ์Œ์„ฑ ํ…์ŠคํŠธ ๋ณ€ํ™˜(STT) API๋ฅผ ์ œ๊ณตํ•˜์—ฌ ์Œ์„ฑ ๋ฐ์ดํ„ฐ๋ฅผ ํ…์ŠคํŠธ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    VITO API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์Œ์„ฑ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ์ฝ”๋“œ

// SttService.java

@Slf4j
@Service
@RequiredArgsConstructor
public class SttService {
    @Value("${vito.client_id}")
    String client_id;

    @Value("${vito.client_secret}")
    String client_secret;

    @Value("${FASTAPI_URL}")
    String fastApiUrl;

    public String getAccessToken() {
        WebClient webClient = WebClient.builder()
                .baseUrl("https://openapi.vito.ai")
                .build();

        return webClient.post()
                .uri("/v1/authenticate")
                .retrieve()
                .bodyToMono(String.class)
                .block();
    }

    public ResponseEntity<String> transcribeFile(MultipartFile multipartFile, String usercode) {
        String accessToken = getAccessToken();
        WebClient webClient = WebClient.builder()
                .baseUrl("https://openapi.vito.ai/v1")
                .build();

        String response = webClient.post()
                .uri("/transcribe")
                .bodyValue(multipartFile.getBytes())
                .retrieve()
                .bodyToMono(String.class)
                .block();

        log.info("STT Response: {}", response);
        return ResponseEntity.ok(response);
    }
}

๋ณด์•ˆ ์„ค์ •

์„ค๋ช…

  • Spring Security์™€ JWT๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณด์•ˆ ๊ธฐ๋Šฅ์„ ์„ค์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
    ์ด๋ฅผ ํ†ตํ•ด API ์š”์ฒญ์— ๋Œ€ํ•œ ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ์ฝ”๋“œ

// JwtAuthFilter.java

@Slf4j
@Component
@RequiredArgsConstructor
public class JwtAuthFilter extends OncePerRequestFilter {
    private final JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String accessToken = jwtUtil.getHeaderToken(request, "Access");
        if (accessToken != null && jwtUtil.tokenValidation(accessToken)) {
            Authentication authentication = jwtUtil.createAuthentication(jwtUtil.getEmailFromToken(accessToken));
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        filterChain.doFilter(request, response);
    }
}

JPA (ORM)

์„ค๋ช…

  • JPA๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ORM(Object-Relational Mapping)์„ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
    ์ด๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ฒด๋กœ ๋‹ค๋ฃจ๊ณ , ๋‹ค์–‘ํ•œ ์ฟผ๋ฆฌ๋ฅผ ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์ œ์ฝ”๋“œ

// Repository.java

@Repository
public interface SttTalksRepository extends JpaRepository<SttTalks, Long> {
}

About

No description or website provided.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •