반응형

javax가 import가 안 될때가 있다.

Cannot resolve symbol ~ 

방법 : 아래처럼 javax 대신 jakarta로 import

 

자바9부터는 javax 대신 jakarta로 쓰면 된다.

 

참고

https://www.samsungsds.com/kr/insights/java_jakarta.html

[자카르타EE에서는 자바 네임스페이스가 Jakarta로, API 패키지명은 javax.* 에서 Jakarta.* 로 변경되었습니다.]

 

Java EE에서 Jakarta EE로의 전환

Java EE에서 Jakarta EE로의 전환

www.samsungsds.com

 

반응형
반응형

* Redis
- 데이터를 디스크에 쓰는 구조가 아니라 메모리에서 데이터를 처리 => 속도 빠름
- 서버 장애등으로 redis 종료 될 시 데이터 유실이 발생할 수 있음
- 한 번에 하나의 명령만 처리할 수 있음
- Redis Cluster를 사용하면 여러개의 redis를 두어 분산처리를 할 수 있음


* String, Lists, Sets, Sorted Sets, Hashes 자료 구조를 지원함
- String : 가장 일반적인 key & value 
- Sets : key & 여러 값이 들어간 value 
- Sorted Sets : 중복된 데이터를 담지 않는 Set 구조
- Lists : Array 형식의 데이터 구조

 

* Redis Cluster
여러 노드간 데이터를 자동으로 분할하는 기능 .
각기 다른 서버를 하나로 묶어 
데이터를 여러대의 장비에서 처리한다.
서버일부분이 장애가 일어나도 다른 서버의 보완을 통해 서비스를 계속 이어 나갈수 있다.

레디스  GUI 툴 

https://redis.com/redis-enterprise/redis-insight/

 

RedisInsight | The Best Redis GUI

RedisInsight provides an intuitive and efficient graphical interface for Redis, allowing you to interact with your databases and manage your data.

redis.com

 

 

Springboot 어플리케이션에서 redis 사용하기

 

1. 의존성 추가 

implementation 'org.springframework.boot:spring-boot-starter-data-redis'

 

2. application.properties 에 redis 서버정보 추가

spring.data.redis.host=localhost
spring.data.redis.port=6379

 

3. RedisConfig.java

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;

@Configuration
public class RedisConfig {

   @Value("${spring.data.redis.host}")
   private String host;

   @Value("${spring.data.redis.port}")
   private int port;

   @Value("${spring.data.redis.password}")
   private int password;

   @Bean
   public RedisConnectionFactory redisConnectionFactory() {
	RedisStandaloneConfiguration redisConfiguration = new RedisStandaloneConfiguration();
	redisConfiguration.setHostName(host);
	redisConfiguration.setPort(port);
	redisConfiguration.setPassword(password);
	LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisConfiguration);

       return new LettuceConnectionFactory;
   }
   
   @Primary
   @Bean
   public RedisTemplate<String, String> redisTemplate() {
       RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
       redisTemplate.setConnectionFactory(redisConnectionFactory());
       redisTemplate.setKeySerializer(new StringRedisSerializer());
       redisTemplate.setValueSerializer(new StringRedisSerializer());
       return redisTemplate;
   }

}

RedisTemplate : 트랜잭션을 지원한다. 트랜잭션으로 묶게 되면 트랜잭션 내부에서 하나의 로직이 실패하여 오류가 나는 경우 수행한 작업을 모두 취소시킨다.

 

4. RedisService.java

import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;


@Service
@RequiredArgsConstructor
public class RedisService {
   private final RedisTemplate redisTemplate;


   public String getValues(String key){
       //opsForValue : Strings를 쉽게 Serialize / Deserialize 해주는 Interface
       ValueOperations<String, String> values = redisTemplate.opsForValue();
       return values.get(key);
   }



   public void setValues(String key, String value){
       ValueOperations<String, String> values = redisTemplate.opsForValue();
       values.set(key,value);
   }

   public void setSets(String key,String... values){
       redisTemplate.opsForSet().add(key,values);
   }

   public Set getSets(String key){
       return redisTemplate.opsForSet().members(key);
   }



}

 

5. RedisController.java

api를 만들어서 데이터를 넣고 요청해보었다.

import com.dominos.pilot_3.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.sql.Timestamp;
import java.util.Set;

@Controller
public class RedisController_ {
//레디스 테스트

    @Autowired
    RedisService redisService;

    @RequestMapping(value = "/redis/test/setString")
    @ResponseBody
    public void setValue(String testkey, String testvalue){
        Timestamp currentTimestamp = new Timestamp(System.currentTimeMillis());
        redisService.setValues(testkey,testvalue);
    }

    @RequestMapping(value = "/redis/test/getString")
    @ResponseBody
    public String getValue(String testkey){
        return redisService.getValues(testkey);
    }


    @RequestMapping(value = "/redis/test/setSets")
    @ResponseBody
    public void setSets(String testkey,String... testvalues){
        redisService.setSets(testkey,testvalues);
    }

    @RequestMapping(value = "/redis/test/getSets")
    @ResponseBody
    public Set getSets(String key){
        return redisService.getSets(key);
    }

}

123123123는 Key와 123123123이라는 Value 쌍을 넣어봤다.

settest라는 Key와 ["settestvalue1","settestvalue2"] 라는 Value 쌍을 넣어봤다.

 

 

Redis Cluster를 사용하는 경우의 설정

1. application.yml

spring:
 data:
  redis:
    cluster:
      nodes:
        - xx.xx.xx.xxx:6379
        - xx.xx.xx.xxx:6380
    password: xxxxxxxxxx

 

2. RedisClusterConfigurationProperties.java

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;

@Component
@ConfigurationProperties(prefix = "spring.data.redis.cluster")
public class RedisClusterConfigurationProperties {
   List<String> nodes;

   public List<String> getNodes() {
       return nodes;
   }

   public void setNodes(List<String> nodes) {
       this.nodes = nodes;
   }

}

 

3. RedisConfig.java

import com.dominos.pilot_3.component.RedisClusterConfigurationProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@EnableRedisRepositories
@RequiredArgsConstructor

public class RedisConfig {

   @Autowired
   RedisClusterConfigurationProperties clusterProperties;

   @Bean
   public RedisConnectionFactory redisConnectionFactory() {
       RedisClusterConfiguration redisConfig = new RedisClusterConfiguration ();
       clusterProperties.getNodes().forEach(s ->{
           String[] url = s.split(":");
           redisConfig.clusterNode(url[0],Integer.parseInt(url[1]));
       });
       redisConfig.setPassword("xxxxxxxx");
       return new LettuceConnectionFactory(redisConfig);
   }

   @Primary
   @Bean
   public RedisTemplate<String, Object> redisTemplate() {
       RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
       redisTemplate.setConnectionFactory(redisConnectionFactory());
       redisTemplate.setKeySerializer(new StringRedisSerializer());
       redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
       return redisTemplate;
   }

}

이하 데이터를 넣고 빼는 service와 controller는 동일함.

반응형
반응형

Intellij 환경변수 등록하기

 

1. 왼쪽 위의 메뉴중 Run > Edit Configurations 

혹은 오른쪽위에서 어플리케이션 이름을 클릭해서 Edit Configurations를 들어가서

 

2. Spring Boot Application 선택  > Environment variables 란이 없는 경우 Modify options 선택

Environment variables를 선택해서 환경변수칸을 추가한다.

 

3. 환경변수 옵션칸에서 오른쪽 아이콘 클릭

 

여기서 추가하면 댐 

아래 체크는 시스템환경변수 포함할건지 말건지 여부 체크 

반응형
반응형

SpringBoot에서 SNS로 메세지 발행하기

SQS로 받은 메시지 Springboot에서 받아보기

개발환경 : Intellij, java17, gradle

 

1. 의존성 설정

    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'


    implementation 'com.google.code.gson:gson:2.9.0'
    implementation platform('software.amazon.awssdk:bom:2.15.0')
    implementation group: 'org.springframework.cloud', name: 'spring-cloud-aws-messaging', version: '2.2.1.RELEASE'
    implementation 'software.amazon.awssdk:sns'
    implementation 'software.amazon.awssdk:sqs'
    implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

 

 

2. application.yml

${AWS_ACCESSKEY} 는 intellij 환경변수에 등록해서 사용함

intellij 환경변수  추가는 https://mchch.tistory.com/282 참고

cloud:
  aws:
    credentials:
      access-key: ${AWS_ACCESSKEY}
      secret-key: ${AWS_SECRETKEY}
    region:
      static: ap-northeast-1
      auto: false
    stack:
      auto: false

    sns:
      topic:
        arn: arn:aws:sns:ap-northeast-1:34243243247:MyTopic2

    sqs:
      queue:
        name: MyQueue2
        url: https://sqs.ap-northeast-1.amazonaws.com/34243243247/MyQueue2

 

 

3. AWSConfig.java

@Getter
@Configuration
public class AWSConfig {
    @Value("${cloud.aws.credentials.access-key}")
    private String awsAccessKey;

    @Value("${cloud.aws.credentials.secret-key}")
    private String awsSecretKey;

    @Value("${cloud.aws.region.static}")
    private String awsRegion;

    @Value("${cloud.aws.sns.topic.arn}")
    private String snsTopicARN;

    @Bean // SNS Client 세팅
    public SnsClient getSnsClient() {
        return SnsClient.builder()
                .credentialsProvider(
                        getAwsCredentials(this.awsAccessKey, this.awsSecretKey)
                ).region(Region.of(this.awsRegion))
                .build();
    }

	//aws credential 세팅
    public AwsCredentialsProvider getAwsCredentials(String accessKeyID, String secretAccessKey) {
        AwsBasicCredentials awsBasicCredentials = AwsBasicCredentials.create(accessKeyID, secretAccessKey);
        return () -> awsBasicCredentials;
    }

    @Bean // SQS Client 세팅
    public AmazonSQS amazonSQS() {
        AWSCredentials credentials = new BasicAWSCredentials(awsAccessKey, awsSecretKey);
        return AmazonSQSAsyncClientBuilder
                .standard()
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .withRegion(awsRegion)
                .build();
    }
}

 

 

4. SnsService.java

지정한 topic으로 메세지 발행하는 서비스

@Service
@RequiredArgsConstructor
public class SnsService {
    private final AWSSnsConfig awsConfig;

    public PublishResponse awsSnsPublishTest(Map<String,Object> scriptData) {
        PublishRequest publishRequest = PublishRequest.builder()
                .topicArn(awsConfig.getSnsTopicARN())
                .subject("TEST 제목")
                .message(scriptData.toString())
                .build();

        SnsClient snsClient = awsConfig.getSnsClient();
        PublishResponse publishResponse = snsClient.publish(publishRequest);

        snsClient.close();
        return publishResponse;
    }
}

 

 

5. SqsService.java

sns 토픽에서 메세지 가져오는 sqs서비스

@Service
public class SqsService {
    private final QueueMessagingTemplate queueMessagingTemplate;

    @Autowired
    public SqsService(AmazonSQS amazonSqs) {
        this.queueMessagingTemplate = new QueueMessagingTemplate((AmazonSQSAsync) amazonSqs);
    }

    public void getMessage() {
        String rr = queueMessagingTemplate.receiveAndConvert("MyQueue2", String.class);
        System.out.println("queue message :: " + rr );

    }
}

 

 

6. SqsListener.java

@Component
public class SqlListener {
    @SqsListener(value = "MyQueue2", deletionPolicy = SqsMessageDeletionPolicy.NEVER)
    public void listen(@Payload String sst, Acknowledgment ack) {
        log.info("{}", sst);
        ack.acknowledge();
    }
}

 

 

7. Controller.java 

서비스 호출 controller.

@RestController
@RequiredArgsConstructor
@RequestMapping("api")
public class SnsController {
    private final SnsService snsService;
    private final SqsService sqsService;

	//메세지 발행 메소드
    @PostMapping("/publish")
    public void publish(@RequestBody Map<String, Object> scriptData) {
        PublishResponse pr = snsService.awsSnsPublishTest(scriptData);
        System.out.println(pr);
        //PublishResponse(MessageId=80da361c-4ec9-55f5-9aa8-6a49037995af)

    }

	//메세지 가져오는 메소드
    @GetMapping("/subscribe")
    public void getMessage() {
        sqsService.getMessage();
    }
}

 

가져온 메세지 콘솔출력

반응형
반응형

software.amazon.awssdk.services.sns.model.InvalidParameterException: Invalid parameter: TopicArn

 

원인 : 프로젝트에 topic region설정을 잘못함

내 토픽 region은 ap-northeast-1인데

프로젝트 설정은 2로 해놓음 ㅎㅎ;;

 

반응형
반응형

SNS와 SQS 정리
SNS : Publisher가 Subscriber에게 메시지를 전송하는 서비스
SQS : 메세지 대기열 서비스

SNS 역할
특정 서비스에서 SNS로 지정한 주제(topic)에 대한 메시지를 발행한다. 예)회원가입정보
그럼 이 SNS는 이 topic에 대한 메시지를 받아보기로 한 (subscribe한) 서비스들에게 메시지를 전달해준다.
subscribe를 하는 주체는 SQS, Lambda, HTTP, SMS, 이메일, 모바일 애플리케이션 엔드포인트가 될 수 있다.

SQS 역할
SQS는 Simple Queue Service로, 메세지 대기열 서비스라고 함.
SNS로부터 특정 주제의 메세지를 구독하여 받아볼 수 있다.
그럼 특정 서비스나 시스템에서 SQS로 받은 메시지를 사용하면 되는거임

흐름은 이렇게 됨
서비스 -> SNS -> SQS -> 다른 서비스

즉 SNS와 SQS를 활용하면 엔드포인트에서 엔드포인트로 데이터를 직접 때려박지 않아도 되므로 데이터 안전성과 관리 오버헤드 제거에 있어서 용이하겠다. . . 

1. SNS 주제 생성하기


https://ap-northeast-1.console.aws.amazon.com/sns/v3/

주제 이름 적고 다음단계로 ㄱㄱ

표준으로 ㄱㄱ 하고 다른 옵션들은 모두 주어진대로 ㄱㄱ

생성되었다.

 


2. SQS 대기열 생성하기


https://ap-northeast-1.console.aws.amazon.com/sqs/v2/

 

대기열 생성 ㄱㄱ

표준으로 하고 다른 옵션들은 기본으로 ㄱㄱ

생성되었다.

 

 


3. SNS 구독하기

생성한 대기열(MyQueue)이 만들었던 SNS의 주제를 바라보도록 설정해야한다. (publish)

'Amazon SNS 주체 구독' 선택

내가 만들었던 Topic을 선택해줌.

SQS에서 설정된것 확인

SNS에서도 설정된것 확인

 


4. SNS 메시지발행

구독 설정이 잘 되었나 확인해볼것.

SNS에서 메시지 게시

제목과 메시지 본문을 적고 기본 옵션으로 전송

 

5. 메시지 수신

MyQueue에서 메시지를 받아보자

메시지 폴링을 누릅니다.

 

SNS 에서 발행한 메시지가 보입니다.

메시지 아이디를 눌러보면 아래와 같은 메시지가 표시됨.  성공~ 

{
  "Type" : "Notification",
  "MessageId" : "d118fffff-dddd-cccc-bbbbb-aaaaaaaa",
  "TopicArn" : ":MyTopic",
  "Subject" : "TEST~~TITLE~~",
  "Message" : "TEST~~PAYLOAD~~~",
  "Timestamp" : "2023-02-02T00:11:52.300Z",
  "SignatureVersion" : "1",
  "Signature" : "==",
  "SigningCertURL" : "",
  "UnsubscribeURL" : ""
}

 

다음은 SNS 와 SQS 를 Spring Boot에 연동해서 메세지 보내고 받아보기~

https://mchch.tistory.com/281

 

SpringBoot에서 SNS SQS 연동하기

SpringBoot에서 SNS로 메세지 발행하기 SQS로 받은 메시지 Springboot에서 받아보기 개발환경 : Intellij, java17, gradle 1. 의존성 설정 implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.sp

mchch.tistory.com

 

반응형
반응형

the request was rejected because no multipart boundary was found 에러가 났다.

 

 

Content-Type 지정한걸 빼버리면 된다 

Content-Type: multipart/form-data
반응형
반응형

Windows 에서 설치 및 테스트 하였음

 

1. H2 다운로드

https://www.h2database.com/html/main.html

windows Installer 다운로드하여 설치하였음.

 

 

2. 설치 확인

C:\Program Files (x86)\H2\bin 경로에서 설치파일들 확인하고 bin밑의 h2.bat을 클릭

 

cmd 창이 켜지며 실행됨. 인터넷 브라우저로 콘솔창이 켜짐.

cmd창을 끄면 db실행이 중단되는 것 같다.

 

 

3. 접속하기

브라우저 콘솔창에서 접속해서 H2 Server 이나 H2 Embedded 중 선택하면 됨. 

>> Embedded 모드
시스템의 메인 메모리에서 구동시키는 방식
application이 종료된다면 저장, 수정된 Data가 사라짐.

>> Server모드
하나의 시스템에서 별도의 프로세스(JVM)를 통해 DB를 동작시켜 데이터베이스를 영속적으로 사용하는 방법

이때 연결을  누르면 데이터베이스 파일이 없어서 에러가 뜨는데, 에러에 표시된 경로에 들어가서 내용 없는 파일을 하나 만든다.

새로만들기 > 텍스트파일 (내용은 적지 않고 저장) > 파일 이름은 파일이름.mv.db 

생성 후 다시 연결을 해보면 연결이 된다. 

 

 

 

4. springboot와 연동하기 - 의존성 

h2와 jpa 의존성을 추가하였으며 전체 dependencies 내용은 아래와 같다.

dependencies {
    implementation 'com.h2database:h2'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-web-services'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

 

 

5. springboot와 연동하기 - 프로퍼티 설정

application.properties 파일에 아래 내용 추가 

spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:tcp://localhost/~/springtest1
spring.datasource.username=sa

##JPA 실행시 sql문 출력
spring.jpa.show-sql=true

##테이블 생성여부.. create로 해두면 어플리케이션 실행 시 덮어쓰기로 테이블이 새로 생성됨. 
##데이터도 모두 지워진다는 거~~
##안 할 경우 none
spring.jpa.hibernate.ddl-auto=create

 

 

6. Entity 또는 domain 만들기 

테이블과 맵핑할 객체를 만들었다. (Member.java)

- @Entity 어노테이션 추가

- 키 컬럼에 @Id 추가

- 값의 자동생성과 자동증가를 위해 @GeneratedValue 추가

@Entity //객체와 테이블 매핑
public class Member {

    @Id //기본 키 매핑
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private String name;

    private String address;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress(){
        return address;
    }

    public void setAddress(String address){
        this.address = address;
    }
}

 

 

7. Repository 만들기

DB에 접근하여 쿼리를 수행할 Repository를 인터페이스로 만들었다. (MemberRepository.java)

- @Repository 어노테이션  추가하고

- JpaRepository를 상속

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
    Member save(Member member);
    Optional<Member> findById(Long id);
    Optional<Member> findByName(String name);
    List<Member> findAll();
}

 

 

8. 테스트 해보기

테스트용 코드 작성~

@SpringBootTest
class Spring2ApplicationTests {

    private final MemberRepository memberRepository;

    // 의존성 주입
    @Autowired
    public Spring2ApplicationTests(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Test
    void memberTest() {
        // 멤버 저장
        Member member = new Member();
        member.setName("nameTestAAAAAA");
        member.setAddress("seoulAAAAAA");
        memberRepository.save(member);

        // 저장한 멤버 아이디로 검색
        Member findMember = memberRepository.findById(member.getId()).get();
        System.out.println(findMember.getAddress());
        Assertions.assertThat(member.getName()).isEqualTo(findMember.getName());

    }
}

 

실행해보면 아래와같이 쿼리와 프린트 결과가 찍힌다~

 

DB 콘솔에서도 확인

반응형
반응형

홈택스에서 근로소득원천징수 영수증 발급받는방법

 

1. 홈택스 로그인  >  검색  >  "지급명세서 등 제출내역" 통합검색

 

 

2. 검색결과 중 "지급명세서 등 제출내역" 선택

 

3. 알아서 뜬다 

 

없는 경우는 사업장에서 아직 안 올린것. 거의 2월 3월에나 올리는듯...

반응형
반응형
Gradle could not start your build.  
> Could not create service of type ChecksumService using BuildSessionScopeServices.createChecksumService().

gradle daemon이 중복으로 실행되려 해서 그런 것 같다.

작업관리자에서 java 싹죽이고 IDE 다시 시작하니까 된다

반응형

+ Recent posts