반응형

1. kafka client 다운로드 

https://kafka.apache.org/downloads

Binary 다운로드
tgz파일 압축 풀어서 C에 갖다놓기
(실행시 path가 길면 "입력 줄이 너무 깁니다." 가 뜨기 때문)

 

2. 클러스터에 연결하기 위해 IAM 인증을 사용할 것이므로 IAM 인증용 jar 다운로드

https://github.com/aws/aws-msk-iam-auth/releases
jar 파일을 libs 폴더 밑에 넣는다.(C에 위치한 경우 C:\kafka_2.13-3.6.1\libs 의 밑 ) 

 

 

3. config 폴더 밑에 client.properties 파일 생성하여 아래 내용 입력

security.protocol=SASL_SSL
sasl.mechanism=AWS_MSK_IAM
sasl.jaas.config=software.amazon.msk.auth.iam.IAMLoginModule required;
sasl.client.callback.handler.class=software.amazon.msk.auth.iam.IAMClientCallbackHandler

 

cmd에서 bin\windows로 가서 명령어 입력하면 됨

 

토픽 리스트 조회
kafka-topics.bat --list --bootstrap-server [브로커엔드포인주소]:[포트] --command-config C:\kafka_2.13-3.6.1\config\client.properties

토픽 삭제
kafka-topics.bat --bootstrap-server [브로커엔드포인주소]:[포트] --delete --topic [토픽이름] --command-config C:\kafka_2.13-3.6.1\config\client.properties

토픽 생성
kafka-topics.bat --bootstrap-server [브로커엔드포인주소]:[포트] --create --topic [토픽이름] --partitions [개수] --replication-factor [개수] --command-config C:\kafka_2.13-3.6.1\config\client.properties

토픽 구성정보 조회
kafka-topics.bat --topic [토픽이름] --describe --bootstrap-server [브로커엔드포인주소]:[포트] --command-config C:\kafka_2.13-3.6.1\config\client.properties

토픽의 record 조회
kafka-console-consumer.bat --bootstrap-server [브로커엔드포인주소]:[포트] --topic [토픽이름] --from-beginning --consumer.config C:\kafka_2.13-3.6.1\config\client.properties --property print.offset=true --property print.timestamp=true --property print.key=true

토픽에 메세지 발행
kafka-console-producer.bat --topic order-status --bootstrap-server b-2.mskdominos.ormjxv.c2.kafka.ap-northeast-2.amazonaws.com:9098 --producer.config C:\kafka_2.13-3.6.1\config\client.properties

클러스터에 연결된 컨슈머 그룹 리스트 조회
kafka-consumer-groups.bat --bootstrap-server [브로커엔드포인주소]:[포트] --command-config C:\kafka_2.13-3.6.1\config\client.properties --list
amazon.msk.canary.group.broker-1

컨슈머 그룹 오프셋 정보 조회
kafka-consumer-groups.bat --bootstrap-server [브로커엔드포인주소]:[포트] --command-config C:\kafka_2.13-3.6.1\config\client.properties --describe --group [그룹이름] --offsets

반응형
반응형

스프링부트에서 STOMP를 이용한 메세지 pub/sub 예시

build.gradle에서 라이브러리를 추가해주십쇼 

implementation 'org.springframework.boot:spring-boot-starter-websocket'

 

웹소켓 설정파일 WebsocketConfig.java 을 아래와 같은 내용으로 생성

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import lombok.RequiredArgsConstructor;

@Configuration
@EnableWebSocketMessageBroker
@RequiredArgsConstructor
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {

@Override
    public void configureMessageBroker(MessageBrokerRegistry registry){
        // /pub으로 시작하는 요청은 @Controller의 @MessageMapping 메소드로 라우트됨
        // 클라이언트가 서버로 메세지를 보낼 때 붙여야하는 prefix
        registry.setApplicationDestinationPrefixes("/pub"); 

         //해당 문자열로 시작하는 message 주소값을 받아서 처리하는 Broker를 활성화한다.
        registry.enableSimpleBroker("/sub"); //메세지 구독 주소값
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry){
        registry.addEndpoint("/websocket")  //클라이언트가 연결할 url
        .setAllowedOriginPatterns("*")
        .withSockJS(); 
        //withSockJS : 웹소켓을 지원하지 않는 환경에서도 웹소켓 사용을 가능하게 해주는 옵션
        //이 옵션을 달면 클라이언트에서 SockJS 라이브러리를 사용해야 함
        //http 아니면 https 로 연결가능(sockJS가 http를 ws로 변환해줌)
    }
}

 

서버에서 STOMP 메세지 보내기

- convertAndSend 메소드를 호출하면 클라이언트가 구독하고 있는 주소로 메세지가 발행됨.

- /sub/** 주소를 구독하고 있는 클라이언트에게 메세지를 전달하는 예시 

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;


@Component
@RequiredArgsConstructor
public class sendService{
    private final SimpMessagingTemplate messagingTemplate;

    public void sendMessageToSubOrderTopic(String message,String id) {
        messagingTemplate.convertAndSend("/sub/"+id, message);
    }
}

 

 

 

서버에서 STOMP 메세지 받아서 전달하기

- 서버가 메세지 브로커 역할 수행

- 특정 클라이언트가 /sub/test 주소로 메세지를 보내면 @MessageMapping에서 받아 @SendTo에 설정된 쪽으로 전달

- /sub/** 을 구독하는 클라이언트가 메세지를 받아볼 수 있는 예시

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Controller
public class StompMessageController {
/* 클라이언트에서 웹소켓을 연결한 뒤 /pub/test 로 메세지를 보내면
 여기서 받아 SendTo에 명시된 구독 링크로 메세지를 발행
 prefix는 생략
*/
    @MessageMapping("/test")
    @SendTo("/sub")
    public String processMessage(String message){
        System.out.println("message : " + message);
        return message;

    }

    //STOMP를 쓰면 좋은점
   	/* @Controller 적용된 객체를 이용해 조직적으로 관리할 수 있다.
    	STOMP의 Destination 경로를 기반으로 Spring Security를 적용할 수 있다
    	외부 브로커를 이용해 여러 서버를 관리할 수 있다.
    */


}

 


그럼 메세지를 구독하고 보내는 클라이언트 페이지를 띄워 테스트를 해보자..

검색해보면 전부 다 APIC으로 테스트를 하던데 APIC자체를 못찾아서 javascript로 짜서 했음. 

html 페이지에 javascript 소스를 넣는다.

 

메세지 구독하는 클라이언트 페이지 소스 예시 (javascript)

서버에 withSockJS() 설정이 되어있다면 SockJS 를 이용하여 연결해야 하며 이 경우엔 http나 https 로 접속을 해야함.

서버에서 /sub 주소로 구독하고 있는 클라이언트에 메세지를 전달해주므로 

/sub/aaa이나  /sub/bbb 를 구독하는 쪽은 메세지를 다 받을 수 있음. 

<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.6.1/sockjs.min.js" integrity="sha512-1QvjE7BtotQjkq8PxLeF6P46gEpBRXuskzIVgjFpekzFVF4yjRgrQvTG1MTOJ3yQgvTteKAcO7DSZI92+u/yZw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>

<script type="text/javascript">
var socket = new SockJS("http://localhost:8081/websocket");
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
    console.log("연결 완료");
    stompClient.subscribe("/sub/aaa",function(response){
        console.log(response.body);
  });	
});
</script>

 

메세지를 발행하는 클라이언트 페이지 소스 예시(javascript)

<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.6.1/sockjs.min.js" integrity="sha512-1QvjE7BtotQjkq8PxLeF6P46gEpBRXuskzIVgjFpekzFVF4yjRgrQvTG1MTOJ3yQgvTteKAcO7DSZI92+u/yZw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>

<script type="text/javascript">
var socket = new SockJS("http://localhost:8081/websocket");
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
    console.log("연결 완료");
    stompClient.send("/pub/test",{},"test메시지입니다.");
});
</script>

 

SockJS를 안 쓰고 싶다면

서버에서 해당 설정을 없애주고

클라이언트에서는 stomp 라이브러리로 바로 연결하면 댐

<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.6.1/sockjs.min.js" integrity="sha512-1QvjE7BtotQjkq8PxLeF6P46gEpBRXuskzIVgjFpekzFVF4yjRgrQvTG1MTOJ3yQgvTteKAcO7DSZI92+u/yZw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
<script type="text/javascript">
var client = Stomp.client("ws://localhost:8081/websocket");
client.connect({},function(){
    console.log("연결 완료");
    client.subscribe("/sub/aaa",function(message){
        console.log("받은 메세지 : " + mesasge);
    });
})
	
</script>
반응형
반응형

1. websocket 연결설정

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import lombok.RequiredArgsConstructor;

@Configuration
@EnableWebSocket
@RequiredArgsConstructor
public class WebSocketConfig implements WebSocketConfigurer{

    //밑에서 만들 WebSocketHandler 클래스
    private final WebSocketHandler webSocketHandler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry){
        registry.addHandler(webSocketHandler,"/websocket").setAllowedOrigins("*");
        // /websocket : 연결url
        //setAllowedOrigins : 웹소켓 cors정책으로, 허용 도메인 지정
        
    }

}

 

2. websocket 핸들러 생성. web socket 연결 및 종료의 수행에 대한 내용

import java.util.concurrent.ConcurrentHashMap;

import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

@Component
//TextWebSocketHandler 상속 시 3개의 메소드 오버라이딩
public class WebSocketHandler extends TextWebSocketHandler{
    
    //ConcurrentHashMap : 멀티 스레드 환경에서 사용. entry 아이템별로 락을 건다.
    private static final ConcurrentHashMap<String, WebSocketSession> CLIENTS = new ConcurrentHashMap<String, WebSocketSession>();
    
    public void afterConnectionEstablished(WebSocketSession session)throws Exception{
        CLIENTS.put(session.getId(), session);
        System.out.println("session Id(" + session.getId() + ") 연결");
        //출력예시 : session Id(84693265-e147-0b2c-5505-b2d3c62e62b4) 연결
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception{
        CLIENTS.remove(session.getId());
        System.out.println("session Id(" + session.getId() + ") 연결해제");
        //출력예시 : session Id(03017781-abf2-bc66-855e-f217bb99b275) 연결해제
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception{
        String id = session.getId();
        System.out.println(CLIENTS.toString());
        //출력예시 : {03017781-abf2-bc66-855e-f217bb99b275=StandardWebSocketSession[id=03017781-abf2-bc66-855e-f217bb99b275, uri=ws://localhost:8081/websocket]}
        CLIENTS.entrySet().forEach(arg ->{
            if(!arg.getKey().equals(id)){
                try{
                    arg.getValue().sendMessage(message);
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        });
    }
}

 

 

 

테스트 방법

1. chrome에서 제공하는 확장 프로그램 이용

https://chromewebstore.google.com/detail/websocket-test-client/fgponpodhbmadfljofbimhhlengambbn?pli=1

 

2. postman에서 제공하는 웹소켓 연결 기능 이용

반응형
반응형

Spring boot 기반의 웹 어플리케이션에서 Amazon MSK 을 IAM 인증방식으로 연동하려고 함

MSK 클러스터 접속에 사용할 IAM 계정 : test-user ( MSK 관련 권한이 부여되어 있어야 함)

 

사용한 라이브러리

implementation 'org.springframework.kafka:spring-kafka:3.0.12'
implementation 'software.amazon.msk:aws-msk-iam-auth:2.0.3'

 

메세지 전송용 ProducerFactory 생성

KafkaAdmin 클라이언트는 생성하지 않았음
 * ProducerFactory : Kafka Producer 인스턴스를 생성하는 팩토리 빈
* Kafka Producer : Kafaka 브로커에 메시지를 전송하는 역할을 담당

@Bean
public ProducerFactory<String, String> producerFactory() {
     
        Map<String, Object> configProps = new HashMap<>();
        
        //연결할 kafka 브로커설정(MSK 서버)
        configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaBootstrapServers);
        
        //보내는 메시지 타입 설정     
        configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);  

        //IAM인증 설정
        configProps.put(AdminClientConfig.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
        configProps.put(SaslConfigs.SASL_MECHANISM, "AWS_MSK_IAM");
        //awsProfileName 으로 계정명 명시
        configProps.put(SaslConfigs.SASL_JAAS_CONFIG,"software.amazon.msk.auth.iam.IAMLoginModule required awsProfileName=\"test-user\";");
        configProps.put(SaslConfigs.SASL_CLIENT_CALLBACK_HANDLER_CLASS, "software.amazon.msk.auth.iam.IAMClientCallbackHandler");
                
        return new DefaultKafkaProducerFactory<>(configProps);
}

//위에서 생성한 ProducerFactory로 KafkaTemplate 생성
@Bean
 public KafkaTemplate<String, String> kafkaTemplate() {
        return new KafkaTemplate<>(producerFactory());
}

토픽 생성은 하지 않았음. 특정 토픽으로 메세지를 보낼 때 해당토픽이 존재하지 않으면 자동으로 토픽이 생성됨
auto.create.topics.enable 설정이 디폴트로 true 값을 가짐 

 

메세지 전송용 Service 생성

@Service
public class KafkaProduceService {
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

	//이 메소드를 호출해서 메세지를 보내면 됨
    public void sendMessage(String topic, String message) {
        kafkaTemplate.send(topic, message);
    }  

}

 

 

 

반응형

 

 

메세지 수신용 ConsumerFactory 생성

 * ConsumerFactory : Kafka Consumer 인스턴스를 생성하기 위한 팩토리 빈

 @Bean
 public ConsumerFactory<String, String> consumerFactory() {

        Map<String, Object> configProps = new HashMap<>();
        //consumer Group Id 부여해주기
        configProps.put(ConsumerConfig.GROUP_ID_CONFIG, "testGroup1");
        
        //MSK 브로커 설정(MSK서버)
        configProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaBootstrapServers);

	//IAM 인증 
        configProps.put(AdminClientConfig.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
        configProps.put(SaslConfigs.SASL_MECHANISM, "AWS_MSK_IAM");
        configProps.put(SaslConfigs.SASL_JAAS_CONFIG,"software.amazon.msk.auth.iam.IAMLoginModule required awsProfileName=\"test-user\";");
        configProps.put(SaslConfigs.SASL_CLIENT_CALLBACK_HANDLER_CLASS, "software.amazon.msk.auth.iam.IAMClientCallbackHandler");

        configProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
        configProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
        
        return new DefaultKafkaConsumerFactory<>(configProps);
 }

   
//kafka 메시지를 수신하는 리스너 컨테이너를 생성하는데 사용되는 인터페이스
@Bean
public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<String, String> factory =
                new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory());
        return factory;
}

 

 

메세지 수신용 Service 생성

@Service
public class KafkaConsumeService {
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;
    
    @KafkaListener(topics = "testTopic", groupId = "testGroup1")
    public void listen(ConsumerRecord<String, String> record) {
        System.out.println(record.value());
        System.out.println(record.toString());
    }

}

 


MSK 에 IAM 인증 시도시 오류 정리

1. IAM 계정의 access key와 secret key를 찾지 못하는 경우

com.amazonaws.SdkClientException: Unable to load AWS credentials from any provider in the chain: [software.amazon.msk.auth.iam.internals.EnhancedProfileCredentialsProvider@3bf917a2: Profile file contained no credentials for profile 'testUser': ProfileFile(profilesAndSectionsMap=[]), cohttp://m.amazonaws.auth.AWSCredentialsProviderChain@2dadd688: Unable to load AWS credentials from any provider in the chain: [EnvironmentVariableCredentialsProvider: Unable to load AWS credentials from environment variables (AWS_ACCESS_KEY_ID (or AWS_ACCESS_KEY) and AWS_SECRET_KEY (or AWS_SECRET_ACCESS_KEY)), SystemPropertiesCredentialsProvider: Unable to load AWS credentials from Java system properties (aws.accessKeyId and aws.secretKey), WebIdentityTokenCredentialsProvider: You must specify a value for roleArn and roleSessionName, software.amazon.msk.auth.iam.internals.EnhancedProfileCredentialsProvider@68aac71d: Profile file contained no credentials for profile 'default': ProfileFile(profilesAndSectionsMap=[]), cohttp://m.amazonaws.auth.EC2ContainerCredentialsProviderWrapper@69883287: Failed to connect to service endpoint: ]]

시스템 환경변수에 AWS_ACCESS_KEY_ID(혹은 AWS_ACCESS_KEY ) 와 AWS_SECRET_KEY (혹은 AWS_SECRET_ACCESS_KEY) 이름으로 access key와 secret key를 세팅해준다. 

혹은 producerFactory와 consumerFactory 내에 System.setProperty로 키 세팅해주면 됨.

System.setProperty("aws.accessKeyId", awsAccessKey);
System.setProperty("aws.secretKey", awsSecretKey);

 

 

2. IAM인증 설정이 바르지 않을때 난 에러 

Node -1 disconnected.
2024-01-31 10:16:24,725 [INFO  ] NetworkClient.cancelInFlightRequests(NetworkClient.java:344) - [Producer clientId=producer-1] Cancelled in-flight API_VERSIONS request with correlation id 1 due to node -1 being disconnected (elapsed time since creation: 98ms, elapsed time since send: 98ms, request timeout: 30000ms)
2024-01-31 10:16:24,726 [WARN  ] NetworkClient$DefaultMetadataUpdater.handleServerDisconnect(NetworkClient.java:1105) - [Producer clientId=producer-1] Bootstrap broker sdfssdfdf.kafka.ap-northeast-2.amazonaws.com:9098 (id: -1 rack: null) disconnected

Factory 생성 시에 sasl_jaas_config 값에 IAM로그인모듈 설정과 IAM계정의 이름을 적어주자.

configs.put(SaslConfigs.SASL_JAAS_CONFIG,"software.amazon.msk.auth.iam.IAMLoginModule required awsProfileName=\"testUser\";");

 

반응형
반응형

32인치 게이밍모니터 알파스캔 콘퀘스트 32U90G 구매 후기

1. 그래픽카드 GTX1050 사용중, DP 연결 

3840x2160, 2560x1600 은 98Hz 까지밖에 안나오고 

2560x1440 으로 144Hz 까지 나옴. 글카를 바꿀때가 됐다.

2. FHD 144hz 27인치 모니터 사용할때보다 pc 켜지는게 늦다. 왠지는 나도 모름. pc를 바꿀때가 됐다.

3. 모니터 높이 조절이 간편함.  그냥 위아래로 밀면 알아서 고정되는것이 신기함.

4. 옵션 등의 메뉴 버튼은 우측에 달려있어 왼손잡이는 불편함. 

5. 플스와 PC 둘다 연결해놨는데 입력을 DP->HDMI1로 사용하다가 HDMI의 전원을 끌 경우 자동으로 DP로 안넘어가는게 아쉽. HDMI1로 입력을 변경하고 나서 다시 자동으로 해놔야함.

6. 내장 스피커가 아주 만족스럽다. 저가 스피커보다 훨 낫다.

 

굉장히 만족중 

반응형
반응형

버전 : 자바17

내 컨트롤러 메소드..

@GetMapping(value = "/info/{a1}")
    public void getInfo(@PathVariable String a1) throws Exception {
}

이 api를 호출하면 아래와 같은 에러가 나는 것이었다

java.lang.IllegalArgumentException: Name for argument of type [java.lang.String] not specified, and parameter name information not found in class file either.

 

path parameter와 변수명이 같으면 name을 명시 안 해줘도 되는걸로 알고있었는데

컴파일 모드가 debug 모드가 아닌 경우 컴파일 시 로컬 지역변수가 포함이 안 되어 변수 맵핑을 못 한다고 함.

 

컨트롤러 메소드에 name옵션 추가해줌.. 

@GetMapping(value = "/info/{a1}")
    public void getInfo(@PathVariable(name="a1") String a1) throws Exception {
}

 

아니면 컴파일 시 지역변수 포함하도록 build.gradle 파일을 손봐준다.

셋중에 하나 추가 

java {
    options.compilerArgs << "-g"
}


tasks.withType(JavaCompile) {
   options.compilerArgs.add("-parameters")
}


compileJava {
    options.compilerArgs <<  '-parameters'
}

 

반응형
반응형

HTTP 422 / 422 에러 / 422 Unprocessable Entity

요청을 잘 받았으나 문법 오류로 인하여 무언가를 응답할 수 없을때 발생한다고 함

 

원인)

HttpsURLConnection  사용시에 GET 으로 보내면서 데이터를 같이 보내서..

 

[원래 코드]

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setDoOutput(true);

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
bw.write("abc");
bw.flush();
bw.close();

 

[수정 후]

setDoOutput을 지워주고
출력 스트림을 없앴음.

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("GET");



setDoOutput 
URLConnection에 대한 doOutput 필드값 설정
URL 연결을 출력용으로 사용하려는 경우 DoOutput 플래그를 true로 설정하고,
그렇지 않은 경우는 false로 설정해야 한다. 기본값은 false이므로 안쓰면 false 임

반응형
반응형

1. 구글 월 캘린더에 포인터를 올리면 자동 스크롤이 돼서 계속 월이 이동하는 현상 발생
2. 윈도우 설정을 켜면 몇몇 옵션들이 자동 스크롤 되어 변경되는 현상 발생

마우스, 키보드 다 꺼보고 재부팅 해봐도 똑같았음.

아래 글들은 내가 시도해본 것들. 되지 않음.

https://support.google.com/calendar/thread/602889/calendar-jumps-months-ahead-when-i-move-my-mouse-from-one-day-to-another-during-a-month?hl=en

 

Calendar jumps months ahead when I move my mouse from one day to another during a month. - Google Calendar Community

 

support.google.com

https://kin.naver.com/qna/detail.naver?d1id=1&dirId=1060304&docId=448835574&qb=6rWs6riAIOy6mOumsOuNlCDsiqTtgazroaQ=&enc=utf8&section=kin.ext&rank=1&search_sort=0&spq=0

 

구글 캘린더에 마우스포인터를 놓으면 다음달로 자동으로 넘어가요

구글 캘린더에 마우스포인터를 놓으면 다음달로 계속 넘어가요 손을 떼지 않으면 2026년 2028년까지 쭉 계속 자동으로 넘어가는데이 문제 해결방법 아시는 분 계실까요?!

kin.naver.com

 

해결방법

제어판 > 하드웨어 및 소리 > 장치관리자 . 마우스 및 기타 포인팅 장치

HID 규격 마우스 우클릭 > 속성 > 드라이버 > 디바이스 사용 안 함

 

반응형
반응형

server was unable to start within 45 seconds

eclipse tomcat 올라오는게 너무 느린 현상 발생

 

해결

debug모드의 BreakPoints가 너무 많아서 그랬다. 삭제해주니 빨라졌다.

반응형
반응형

프론트페이지(jsp) => controller 에 폼데이터를 전송할때

데이터를 받아보니 문자가 자동 escape 처리가 되어있었다.

'  는  &#39;

"  는 &quot;

<&lt;

>&gt; 로 바뀌어 전달되었다.

근데 어떤 페이지에서 보낸건 escape 처리가 안 되고 어떤 페이지에서 보낸 건 escape 처리가 되어있었다.

ajax로 보낸건 자동 이스케이프가 안 되는데 form을 만들어서 submit한건 자동 이스케이프 처리가 되는거임..

확인해보니 전송하는 데이터의 Content-Typetext/html인 경우 escape 처리가 되는 듯 함.

 

자세한 설명 ..

text/html 콘텐츠에서는 특수 문자(예: `<`, `>`, `&` 등)가 올바르게 표시되고 HTML 문서의 구조를 방해하지 않도록 하기 위해 문자 이스케이프가 사용됩니다. 예를 들어, `<` 문자는 `&lt;`로, `>` 문자는 `&gt;`로, `&` 문자는 `&amp;`로 이스케이프됩니다. 이는 이러한 문자가 HTML 태그나 엔터티로 해석되는 것을 방지하기 위해 수행됩니다.

반면 application/json 콘텐츠에서 문자 이스케이프는 주로 JSON 형식 자체로 표현되는 데이터와 관련이 있습니다. JSON에는 JSON 파서에서 데이터가 올바르게 구문 분석되고 해석되도록 하기 위해 문자열 내의 문자를 이스케이프하는 자체 규칙이 있습니다. 예를 들어 JSON 문자열 내의 큰따옴표(`"`)와 같은 특수 문자는 `\"`로 이스케이프되고 개행 문자는 `\n`으로 표시됩니다.

 

반응형

+ Recent posts