Open eunja511005 opened 9 months ago
안드로이드 클라이언트
// stomp
implementation 'com.github.NaikSoftware:StompProtocolAndroid:1.6.6'
// rx
implementation 'io.reactivex.rxjava2:rxjava:2.2.5'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
// gson
implementation 'com.google.code.gson:gson:2.8.8'
package com.example.chat;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.Gson;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import ua.naiksoftware.stomp.Stomp;
import ua.naiksoftware.stomp.StompClient;
import io.reactivex.disposables.Disposable;
public class MainActivity extends AppCompatActivity {
private static final String SERVER_URL = "ws://192.168.219.106:8080/ws-chat/websocket";
private TextView textViewStatus;
private Button buttonSubscribe;
private TextView textViewMessage;
private StompClient mStompClient;
private Disposable stompLifecycleDisposable;
private final String TAG = this.getClass().getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textViewStatus = findViewById(R.id.textViewStatus);
buttonSubscribe = findViewById(R.id.buttonSubscribe);
textViewMessage = findViewById(R.id.textViewMessage);
try {
URI serverUri = new URI(SERVER_URL);
mStompClient = Stomp.over(Stomp.ConnectionProvider.OKHTTP, SERVER_URL);
// 연결 설정 및 연결
mStompClient.connect();
// 연결이 성공한 경우
stompLifecycleDisposable = mStompClient.lifecycle().subscribe(lifecycleEvent -> {
switch (lifecycleEvent.getType()) {
case OPENED:
Log.d(TAG, "STOMP connection opened");
// 연결 성공 후 구독
mStompClient.topic("/topic/chat").subscribe(topicMessage -> {
String message = topicMessage.getPayload();
// 메시지를 UI에 표시하거나 처리
runOnUiThread(() -> textViewMessage.setText(message));
});
// 메시지 전송
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm", Locale.getDefault());
String currentTime = sdf.format(new Date());
Message socketMessage = new Message();
socketMessage.setSender("YW");
socketMessage.setTimestamp(currentTime);
socketMessage.setMessage("My first STOMP message!");
// ChatMessage 객체를 JSON 문자열로 변환
String jsonMessage = new Gson().toJson(socketMessage);
mStompClient.send("/app/chat/send", jsonMessage).subscribe();
break;
case CLOSED:
Log.d(TAG, "STOMP connection closed");
break;
case ERROR:
Log.e(TAG, "Error in STOMP connection", lifecycleEvent.getException());
break;
}
});
} catch (URISyntaxException e) {
e.printStackTrace();
Log.e(TAG, "WebSocket connection error", e);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 액티비티가 종료될 때 STOMP 클라이언트 연결 해제
if (stompLifecycleDisposable != null) {
stompLifecycleDisposable.dispose();
}
// STOMP 클라이언트 연결 해제
if (mStompClient != null) {
mStompClient.disconnect();
}
}
}
JWT 얻기 위한 소스
안드로이드 클라이언트에서 STOMP 호출시 Header 추가 방법
Map<String, String> headerMap = new HashMap<>();
headerMap.put("Authorization", "Bearer " + jwtToken);
mStompClient = Stomp.over(Stomp.ConnectionProvider.OKHTTP, SERVER_URL, headerMap);
// 연결 설정 및 연결
mStompClient.connect();
스프링 서버에서 STOMP Header 필터를 이용해 꺼내는 방법
MyFilterConfiguration.java에 아래 내용 추가
@Bean
public FilterRegistrationBean<WebSocketFilter> webSocketFilter() {
FilterRegistrationBean<WebSocketFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new WebSocketFilter());
registration.addUrlPatterns("/ws-service/*"); // Set the URL patterns for the filter
registration.setName("WebSocketFilter");
registration.setOrder(3); // Set the order in which the filter should be applied
return registration;
}
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.owasp.validator.html.AntiSamy;
import org.owasp.validator.html.Policy;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import com.eun.tutorial.dto.ZthhErrorDTO;
import com.eun.tutorial.dto.main.MenuControlDTO;
import com.eun.tutorial.dto.main.UserRequestHistoryDTO;
import com.eun.tutorial.service.ZthhErrorService;
import com.eun.tutorial.service.main.MenuControlService;
import com.eun.tutorial.service.main.UserRequestHistoryService;
import com.eun.tutorial.util.AuthUtils;
import com.eun.tutorial.util.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class WebSocketFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = ((HttpServletRequest) servletRequest);
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
log.info("Header Name: " + headerName + ", Header Value: " + headerValue);
}
String header = request.getHeader("Authorization");
if (header == null || !header.startsWith("Bearer ")) {
return;
}
String authToken = header.substring(7); // "Bearer " 이후의 토큰 부분 추출
if (JwtTokenUtil.validateToken(authToken)) {
// 토큰이 유효한 경우 데이터 반환
String username = JwtTokenUtil.extractUsername(authToken);
filterChain.doFilter(servletRequest, servletResponse);
} else {
// 토큰이 유효하지 않은 경우 연결 거부
throw new IllegalStateException("Invalid JWT token");
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Do nothing
}
@Override
public void destroy() {
// Do nothing
}
}
ConstraintLayou 정렬 자바에서 동적으로 변경
![]()
[중요] 제일 마지막에 꼭 아래 코드 필요
constraintSet.applyTo(constraintLayout);
접근 허용 추가
서버 소스