Skip to content

Commit

Permalink
Merge pull request #98 from Dallili/develop
Browse files Browse the repository at this point in the history
최종 제출물 머지
  • Loading branch information
crHwang0822 authored Jun 18, 2024
2 parents ba68fd6 + ceab4d5 commit 7c56e7f
Show file tree
Hide file tree
Showing 109 changed files with 4,750 additions and 39 deletions.
43 changes: 40 additions & 3 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle

name: Java CI with Gradle
name: Java CI&CD with Gradle

on:
push:
Expand Down Expand Up @@ -46,14 +46,51 @@ jobs:
spring.datasource.url: ${{secrets.AWS_RDS_HOST}}
spring.datasource.username: ${{secrets.AWS_RDS_USERNAME}}
spring.datasource.password: ${{secrets.AWS_RDS_PASSWORD}}
jwt.secret: ${{secrets.JWT_SECRET_KEY}}
JWT_SECRET_KEY: ${{secrets.JWT_SECRET_KEY}}
openai.organization.id: ${{secrets.OPENAI_ORGANIZATION_ID}}
openai.project.id: ${{secrets.OPENAI_PROJECT_ID}}
openai.api.key: ${{secrets.OPENAI_API_KEY}}
openai.api.url: ${{secrets.OPENAI_API_URL}}
openai.model: ${{secrets.OPENAI_MODEL}}
mail.username: ${{secrets.MAIL_USERNAME}}
mail.password: ${{secrets.MAIL_PASSWORD}}
mail.templates.path: ${{secrets.MAIL_TEMPLATE_PATH}}
mail.templates.img.logo: ${{secrets.MAIL_LOGO_PATH}}
mail.templates.img.title: ${{secrets.MAIL_TITLE_PATH}}
mail.templates.img.text: ${{secrets.MAIL_TEXT_PATH}}

# Configure Gradle for optimal use in GiHub Actions, including caching of downloaded dependencies.
# See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
- name: Setup Gradle
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0

- name: Build with Gradle Wrapper
run: ./gradlew build
- name: Build with Gradle
run: ./gradlew build -x test

# docker build & push
- name: Docker Build & Push
if: contains(github.ref, 'develop')
run: |
docker login -u ${{secrets.DOCKER_USERNAME}} -p ${{secrets.DOCKER_PASSWORD}}
docker build -f Dockerfile -t ${{secrets.DOCKER_USERNAME}}/${{secrets.DOCKER_REPOSITORY}}:dev .
docker push ${{secrets.DOCKER_USERNAME}}/${{secrets.DOCKER_REPOSITORY}}:dev
# deploy to EC2
- name: Deploy to EC2
uses: appleboy/ssh-action@master
with:
host: ${{secrets.AWS_EC2_HOST}}
username: ec2-user
key: ${{secrets.AWS_EC2_KEY}}
script: |
CONTAINER_ID=$(sudo docker ps -q --filter "publish=80-8080")
if [ ! -z "$CONTAINER_ID" ]; then
sudo docker stop $CONTAINER_ID
sudo docker rm $CONTAINER_ID
fi
sudo docker pull ${{secrets.DOCKER_USERNAME}}/${{secrets.DOCKER_REPOSITORY}}:dev
sudo docker run -d -p 80:8080 -e TZ=Asia/Seoul ${{secrets.DOCKER_USERNAME}}/${{secrets.DOCKER_REPOSITORY}}:dev
# NOTE: The Gradle Wrapper is the default and recommended way to run Gradle (https://docs.gradle.org/current/userguide/gradle_wrapper.html).
# If your project does not have the Gradle Wrapper configured, you can use the following configuration to run Gradle with a specified version.
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ bin/
!**/src/test/**/bin/

### IntelliJ IDEA ###
application.properties
application.yml
application-prod.yml
application-local.yml
.idea
*.iws
*.iml
Expand Down
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM amazoncorretto:17
COPY build/libs/*.jar spring-base.jar
ENTRYPOINT ["java", "-jar", "/spring-base.jar"]
23 changes: 23 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,36 @@ dependencies {
//swagger ui
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'

//Gson 라이브러리
implementation 'com.google.code.gson:gson:2.8.9'

//스프링 시큐리티 관련 라이브러리
implementation 'org.springframework.boot:spring-boot-starter-security'

//jjwt
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5',
'io.jsonwebtoken:jjwt-jackson:0.11.5'

//욕설 필터링 라이브러리
implementation 'io.github.vaneproject:badwordfiltering:1.0.0'

//회원가입 이메일 인증
implementation 'org.springframework.boot:spring-boot-starter-mail:3.2.2'

//thymeleaf
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.1.2'

}

tasks.named('test') {
useJUnitPlatform()
}

jar {
enabled = false
}

sourceSets {
main{
java{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

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

@SpringBootApplication
@EnableJpaAuditing
public class SecretFriendsApplication {

public static void main(String[] args) {
Expand Down
34 changes: 34 additions & 0 deletions src/main/java/org/dallili/secretfriends/config/GptConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.dallili.secretfriends.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class GptConfig {
@Value("${openai.api.key}")
private String apiKey;
@Value("${openai.project.id}")
private String projectId;
@Value("${openai.organization.id}")
private String organizationId;

@Bean
public RestTemplate restTemplate(){
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add((request, body, execution)->{
request.getHeaders().add(
"Authorization"
,"Bearer "+apiKey);
request.getHeaders().add(
"OpenAI-Organization"
, organizationId);
request.getHeaders().add(
"OpenAI-Project"
, projectId);
return execution.execute(request,body);
});
return restTemplate;
}
}
63 changes: 63 additions & 0 deletions src/main/java/org/dallili/secretfriends/config/MailConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.dallili.secretfriends.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.thymeleaf.templateresolver.ITemplateResolver;

import javax.swing.*;
import java.util.Properties;

@Configuration
public class MailConfig {
@Value("${mail.host}")
private String mailServerHost;
@Value("${mail.port}")
private int mailServerPort;
@Value("${mail.username}")
private String mailServerUsername;
@Value("${mail.password}")
private String mailServerPassword;
@Value("${mail.templates.path}")
private String mailTemplatesPath;


//이메일 발송에 사용되는 JavaMailSender 빈으로 등록
@Bean
public JavaMailSender javaMailSender(){
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setHost(mailServerHost);
javaMailSender.setPort(mailServerPort);
javaMailSender.setUsername(mailServerUsername);
javaMailSender.setPassword(mailServerPassword);

Properties properties = javaMailSender.getJavaMailProperties();
properties.put("mail.transport.protocol","smtp");
properties.put("mail.smtp.auth","true");
properties.put("mail.smtp.starttls.enable","true");

return javaMailSender;
}

@Bean
public ITemplateResolver thymeleafTemplateResolver(){
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix(mailTemplatesPath);
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML");
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}

@Bean
public SpringTemplateEngine thymeleafTemplateEngine(){
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(thymeleafTemplateResolver());
return templateEngine;
}

}
110 changes: 110 additions & 0 deletions src/main/java/org/dallili/secretfriends/config/MySecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package org.dallili.secretfriends.config;

import lombok.RequiredArgsConstructor;
import org.dallili.secretfriends.security.*;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@RequiredArgsConstructor
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class MySecurityConfig{

private final CustomUserDetailsService customUserDetailsService;
private final JwtUtil jwtUtil;
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;

private static final String[] AUTH_WHITELIST = {
"/swagger-ui/**", "/swagger-ui.html", "/members/signup/**", "/members/login",
"/v3/api-docs","/api-docs/**","/swagger-resources/**","api-docs/",
"/v3/api-docs/**"
};

//비밀번호 암호화를 위한 PasswordEncoder 빈 등록
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}

@Bean
public WebSecurityCustomizer webSecurityCustomizer(){
return (web)-> web.ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations());
} //정적 자원들을 스프링 시큐리티 적용에서 제외

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{

http
.httpBasic(AbstractHttpConfigurer::disable)
//.formLogin(form->form.disable())
.csrf(csrf-> csrf.disable())
.cors(Customizer.withDefaults())
.sessionManagement(config -> config.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.headers(header -> header
.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin))
//JwtFilter를 UsernamePasswordAuthenticationFilter 앞에 추가
.addFilterBefore(new JwtFilter(customUserDetailsService,jwtUtil), UsernamePasswordAuthenticationFilter.class)
//exception handling 할 때 만들었던 클래스를 추가
.exceptionHandling(authenticationManager->authenticationManager
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.accessDeniedHandler(jwtAccessDeniedHandler))
.authorizeHttpRequests(auth->auth
.requestMatchers(AUTH_WHITELIST).permitAll()
.anyRequest().authenticated());



return http.build();
}


// cors 오류 해결
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
// 리액트 오리진
config.addAllowedOrigin("http://localhost:3000"); // 로컬 환경
config.addAllowedOrigin("https://localhost:3000");
config.addAllowedOrigin("secret-friends.link");
config.addAllowedOrigin("http://secret-friends.link");
config.addAllowedOrigin("https://secret-friends.link");
// 스프링부트 오리진
config.addAllowedOrigin("http://localhost:8080"); // 로컬 환경
config.addAllowedOrigin("https://localhost:8080");
config.addAllowedOrigin("http://localhost:9090"); // 도커랑 8080 포트 겹칠 때 9090 포트 사용
config.addAllowedOrigin("https://localhost:9090");
config.addAllowedOrigin("http://ec2-3-17-227-166.us-east-2.compute.amazonaws.com");
config.addAllowedOrigin("api.secretfriends.shop");
config.addAllowedOrigin("http://api.secretfriends.shop");
config.addAllowedOrigin("https://api.secretfriends.shop");

config.addAllowedMethod("*"); // 모든 메소드 허용.
config.addAllowedHeader("*");
config.setAllowCredentials(true);

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}



}
30 changes: 29 additions & 1 deletion src/main/java/org/dallili/secretfriends/config/RootConfig.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package org.dallili.secretfriends.config;

import org.dallili.secretfriends.domain.Diary;
import org.dallili.secretfriends.dto.DiaryDTO;
import org.dallili.secretfriends.notify.domain.Notify;
import org.dallili.secretfriends.notify.dto.NotifyDTO;
import org.modelmapper.ModelMapper;
import org.modelmapper.PropertyMap;
import org.modelmapper.convention.MatchingStrategies;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -16,7 +21,30 @@ public ModelMapper getMapper(){
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(org.modelmapper.config.Configuration.AccessLevel.PRIVATE)
.setMatchingStrategy(MatchingStrategies.LOOSE);

modelMapper.addMappings(diaryMapping);
modelMapper.addMappings(diaryFieldMapping);
return modelMapper;
}

PropertyMap<DiaryDTO, Diary> diaryMapping = new PropertyMap<DiaryDTO, Diary>() {
@Override
protected void configure() {
map().getMember().setMemberID(source.getMemberID());
map().getPartner().setMemberID(source.getPartnerID());
map().getMember().setNickname(source.getMemberName());
map().getPartner().setNickname(source.getPartnerName());
}
};

PropertyMap<Diary,DiaryDTO> diaryFieldMapping = new PropertyMap<Diary, DiaryDTO>() {
@Override
protected void configure() {
map().setMemberID(source.getMember().getMemberID());
map().setPartnerID(source.getPartner().getMemberID());
map().setMemberName(source.getMember().getNickname());
map().setPartnerName(source.getPartner().getNickname());
}
};


}
Loading

0 comments on commit 7c56e7f

Please sign in to comment.