Translate

2020년 10월 20일 화요일

[Leaflet] Using GeoJSON

 


GeoJSON 정보

GeoJSON 스펙(RFC 7946) 링크

 GeoJSON은 다양한 지리 데이터 구조를 인코딩하기위한 형식이다.

 GeoJSON 객체는 공간영역(Geometry), 공간경계(Feature), 기능리스트(FeattureCollection)을 나타낼 수 있다.

 GeoJSON은 Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection에 대한 geometry 타입을 지원한다.

 GeoJSON의 Feature에는 Geometry객체, 추가속성이 포함되고, FeatureCollection 에는 기능 리스트들이 포함되어 있다.

 * Leaflet은 위의 모든 GeoJSON 타입을 지원하며, properties를 셋팅하고 features를 기술할 시 Features/FeatureCollection를 가장 잘 작동한다.


* 추가 GeoJSON 참고 URL: https://ko.wikipedia.org/wiki/GeoJSON



GeoJSON 레이어


옵션


스타일



pointToLayer


onEachFeature


Filter


종합


참고: https://leafletjs.com/examples/geojson/


[Leaflet] Markers with Custom Icons




마커와 커스텀 아이콘



출처: https://leafletjs.com/examples/custom-icons/


[Leaflet] On Mobile

 


모바일 및 Geolocation

참고: https://leafletjs.com/examples/mobile/

2020년 10월 18일 일요일

[Leaflet] Quick Start Guide

 

Leaflet 튜토리얼


설명은 코드에 주석으로 추가함.


1004lucifer

1. 페이지 준비 및 지도설정




2. 마커, 원 및 다각형



3. 팝업



4. 이벤트



참고: https://leafletjs.com/examples/quick-start/


2020년 7월 1일 수요일

[Vue.js][Axios] Request/Response Console Log






개발 시 Ajax에 대한 Request/Response 콘솔로그를 쉽게 볼 수 있다면 디버깅하기에 편할 것으로 예상이 되어 아래와 같이 axios 를 통해 Ajax 요청 시 응답에 대한 콘솔로그를 제작했다.


/**
 * Axios 응답
 * @param res Response||error 객체
 * @private
 */
function _responseLog(res) {
  var response = res.response ? res.response : res;
  var color = response.status === 200 ? '#58FA58' : '#FA5858';
  var status = response.status ? response.status : res.message;
  console.groupCollapsed(`[Axios] %c[${status}]`, `background-color:${color}; color:black`, `- ${res.config.url}`);
  console.info(`url: ${res.config.url}\nmethod: ${res.config.method}\n`);
  console.info('[Request]\n',
    '\theaders: ', res.config.headers || '', '\n',
    '\tparams: ', res.config.params || '', '\n',
    '\tdata: ', res.config.data || '');
  console.info('[Response]\n',
    '\theaders: ', response.headers || '', '\n',
    '\tdata: ', response.data || '');
  console.groupEnd();
}

const service = axios.create({
  baseURL: baseUrl,
  timeout: request.timeout
});

/**
 * Axios의 Response 인터셉터
 */
service.interceptors.response.use(
  response => {
    _responseLog(response);
    return res;
  },
  error => {
    _responseLog(error);
    return Promise.reject(error);
  }
);


아래와 같이 콘솔로그가 보여지며 꽤  편하게 쓰고 있다.
1004lucifer
1004lucifer


2020년 6월 27일 토요일

[Vue.js] methods 함수 안에서의 this에 대한 고찰 (this를 찾을 수 없는경우)






methods의 함수 내에서 this가 없어서 수행이 안되거나,
프로그램 실행은 되는데 개발자 도구에서 디버깅모드로 this를 참조하려고 할 시 this가 undefied로 나오는 경우가 있다.



Vue.js methods 함수내에서 this를 사용하기위해 주의할 점에 대해서 알아봤다.






이슈

1004lucifer
async 키워드가 들어간 함수에서 console.log 를 이용하여 this 객체를 로그로 남겼는데, 로그는 정상적으로 찍히지만 디버깅모드에서 this 객체가 'undefied' 로 나오는것 있었다.

실제로는 this 객체가 없지만 브라우저에서 버그가 있거나 문제없게 수정을 해주는걸까 싶어서 원인을 알아보기 시작했다.







소스

1004lucifer

export default {
  name: 'App',
  components: {
    HelloWorld
  },
  data: function() {
    return {
      testData1: 'testData1',
      testData2: 'testData2'
    }
  },
  created() {
    console.log('created');
  },
  mounted: function() {
    this.test1();
    this.test2();
    this.test3();
    this.test4();
    this.test5();
    this.test6();
    this.test7();
  },
  methods: {
    // 일반적인 함수 생성
    test1: function() {
      // eslint-disable-next-line no-debugger
      debugger;
      console.log('test1: ', this);
    },

    // 함수에 async 키워드 추가
    test2: async function() {
      // eslint-disable-next-line no-debugger
      debugger;
      console.log('test2: ', this);
    },

    // ECMAScript2015 - 단축 구문 함수 생성
    test3() {
      // eslint-disable-next-line no-debugger
      debugger;
      console.log('test3: ', this);
    },

    // ECMAScript2015 - 단축 구문 함수 생성 (async 키워드 추가)
    async test4() {
      // eslint-disable-next-line no-debugger
      debugger;
      console.log('test4: ', this);
    },

    // Arrow Function 지정
    test5: () => {
      // eslint-disable-next-line no-debugger
      debugger;
      console.log('test5: ', this);
    },


    callbackTest: function(obj) {
      // eslint-disable-next-line no-debugger
      debugger;
      obj.callback(obj.data);
    },
    test6: function() {
      this.callbackTest({
        data: this.testData1,
        // 콜백함수 정상적으로 생성
        callback: function(res) {
          // eslint-disable-next-line no-debugger
          debugger;
          console.log(res, this);
        }
      });
    },
    test7: function() {
      this.callbackTest({
        data: this.testData2,
        // 콜백함수 Arrow Function 으로 생성
        callback: (res) => {
          // eslint-disable-next-line no-debugger
          debugger;
          console.log(res, this);
        }
      });
    },
    test8: function() {
      // this 객체를 복사
      var context = this;
      this.callbackTest({
        data: this.testData2,
        callback: function(res) {
          // eslint-disable-next-line no-debugger
          debugger;
          console.log(res, context);
        }
      });
    },
  }
}




분석


1. Vue 프로젝트 빌드


프로젝트 빌드 시 아래와 같이 dist 디렉토리 하위에 빌드된 파일이 생성이 된다.
1004lucifer



2. 각 함수별 빌드파일과 비교




test1 함수

- 내용이 동일하다.
// ====== 원래 소스 ======
test1: function() {
  console.log('test1: ', this);
}

// ===== 빌드된 소스 =====
test1: function() {
	console.log("test1: ", this)
}



test2
1004lucifer
- async 키워드로 인해 기존의 내용이 wrapping 되었으며, 해당 객체에 this 객체를 똑같이 맞춰준 후 돌려준다.
그렇기 때문에 수행 시 Local 영역에 this 객체가 들어있다.
// ====== 원래 소스 ======
test2: async function() {
  console.log('test2: ', this);
}

// ===== 빌드된 소스 =====
test2: function() {
	var t = Object(a["a"])(regeneratorRuntime.mark((function t() {
		return regeneratorRuntime.wrap((function(t) {
			while (1)
				switch (t.prev = t.next) {
				case 0:
					console.log("test2: ", this);
				case 2:
				case "end":
					return t.stop()
				}
		}
		), t, this)
	}
	)));
	function e() {
		return t.apply(this, arguments)
	}
	return e
}()



test3

- 내용이 동일하다.
// ====== 원래 소스 ======
test3() {
  console.log('test3: ', this);
}

// ===== 빌드된 소스 =====
test3: function() {
	console.log("test3: ", this)
}



test4
1004lucifer
- this 객체를 t 라는 변수에 담아서 내부에서 t 객체를 사용하고 있다.
개발자도구에서는 Closure(test4) 에서 this를 사용하는 것으로 보여진다.
// ====== 원래 소스 ======
async test4() {
  console.log('test4: ', this);
}

// ===== 빌드된 소스 =====
test4: function() {
	var t = this;
	return Object(a["a"])(regeneratorRuntime.mark((function e() {
		return regeneratorRuntime.wrap((function(e) {
			while (1)
				switch (e.prev = e.next) {
				case 0:
					console.log("test4: ", t);
				case 2:
				case "end":
					return e.stop()
				}
		}), e)
	})))()
}



test5

- 빌드되면서 this 자리에 엉뚱한게 들어가 버렸다.

* Vue 공식홈페이지에서 화살표 함수를 사용 시 부모 컨텍스트를 바인딩한다고 사용하지 말라고 기술되어 있다.

* 여기서 상위객체의 h가 어떤 것인지 확인이 가능하다.
// ====== 원래 소스 ======
test5: () => {
  console.log('test5: ', this);
}

// ===== 빌드된 소스 =====
test5: function() {
	console.log("test5: ", h)
}



test6

- 내용이 동일하며, callback 함수에서 수행하는 this는 test6 함수의 this와 다른것을 확인 할 수 있다.
// ====== 원래 소스 ======
test6: function() {
  this.callbackTest({
	data: this.testData1,
	callback: function(res) {
	  console.log(res, this);
	}
  });
}

// ===== 빌드된 소스 =====
callbackTest: function(t) {
	t.callback(t.data)
},
test6: function() {
	this.callbackTest({
		data: this.testData1,
		callback: function(t) {
			console.log(t, this)
		}
	})
}



test7

- callback 함수에 화살표 함수를 사용했더니 부모 컨텍스트(test7)에 바인딩되어 this를 사용 할 수 있게 되었다.
// ====== 원래 소스 ======
test7: function() {
  this.callbackTest({
	data: this.testData2,
	callback: (res) => {
	  console.log(res, this);
	}
  });
}

// ===== 빌드된 소스 =====
callbackTest: function(t) {
	t.callback(t.data)
},
test7: function() {
	var t = this;
	this.callbackTest({
		data: this.testData2,
		callback: function(e) {
			console.log(e, t)
		}
	})
}



test8

- 화살표 함수를 사용하지 않고 test7과 같은 효과를 줄 수 있다.
// ====== 원래 소스 ======
test8: function() {
  var context = this;
  this.callbackTest({
	data: this.testData2,
	callback: function(res) {
	  console.log(res, context);
	}
  });
}

// ===== 빌드된 소스 =====
callbackTest: function(t) {
	t.callback(t.data)
},
test8: function () {
	var t = this;
	this.callbackTest({
		data: this.testData2, callback: function (e) {
			console.log(e, t)
		}
	})
}





결론


어떤 방식으로 함수를 작성하느냐에 따라 Vue객체의 this를 사용할수도 있고 사용하지 못할 수도 있다는걸 알게 되었다.

우선 Vue 공식홈페이지에 있는 예제 코드는 모두 function 키워드가 붙은 정석적인 방법으로 사용이 되어있었다.

Babel이 트랜스컴파일링 하게될 때 상황에 따라 의도치 않게 코드가 나와버려서 Vue 공식홈페이지에 있는 방식대로 코딩을 권장하고 싶긴하지만, 많은 IDE 툴에서 ES6 단축 함수 형식으로 자동완성을 해주고 있기에 그렇게 하기도 좀 애매하기도 하다.

주위 개발자에겐 this 문제가 발생한경우 function 키워드를 넣는 방식으로 코드를 수정해 보라고 가이드를 할 예정이다.




PS.
얼핏 알고있는 내용을 정리하면서 확실하게 개념을 확립한것도 그렇고, 크롬 개발자도구의 Scope 항목에 Closure가 나오는 의미에 대해서 알게될 수 있어서 좋은 포스팅이 되었다.



익명함수 및 클로저 개념


2020년 4월 27일 월요일

[Spring Boot][OAuth2][Facebook] Cannot deserialize instance of `java.lang.String` out of START_OBJECT token 오류 원인





Framework: Spring Boot 2.x


증상

다른 SNS 에서는 문제가 없는데 Facebook 에서만 아래와 같은 오류가 발생하면서 정상적으로 로그인이 되지 않는다.

1004lucifer


org.springframework.http.converter.HttpMessageNotReadableException: An error occurred reading the OAuth 2.0 Error: JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
 at [Source: (sun.net.www.protocol.http.HttpURLConnection$HttpInputStream); line: 1, column: 10] (through reference chain: java.util.LinkedHashMap["error"]); nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
 at [Source: (sun.net.www.protocol.http.HttpURLConnection$HttpInputStream); line: 1, column: 10] (through reference chain: java.util.LinkedHashMap["error"])
at org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter.readInternal(OAuth2ErrorHttpMessageConverter.java:79) ~[spring-security-oauth2-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter.readInternal(OAuth2ErrorHttpMessageConverter.java:47) ~[spring-security-oauth2-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:199) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler.handleError(OAuth2ErrorResponseErrorHandler.java:59) ~[spring-security-oauth2-client-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:776) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:734) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:645) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService.loadUser(DefaultOAuth2UserService.java:108) ~[spring-security-oauth2-client-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at com.project.security.oauth2.CustomOAuth2UserService.loadUser(CustomOAuth2UserService.java:26) ~[classes/:na]
at org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider.authenticate(OAuth2LoginAuthenticationProvider.java:116) ~[spring-security-oauth2-client-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175) ~[spring-security-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter.attemptAuthentication(OAuth2LoginAuthenticationFilter.java:186) ~[spring-security-oauth2-client-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:160) ~[spring-security-oauth2-client-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:94) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:114) ~[spring-boot-actuator-2.1.13.RELEASE.jar:2.1.13.RELEASE]
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:104) ~[spring-boot-actuator-2.1.13.RELEASE.jar:2.1.13.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:747) [tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367) [tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1639) [tomcat-embed-core-9.0.31.jar:9.0.31]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.31.jar:9.0.31]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_241]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_241]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.31.jar:9.0.31]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_241]
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
 at [Source: (sun.net.www.protocol.http.HttpURLConnection$HttpInputStream); line: 1, column: 10] (through reference chain: java.util.LinkedHashMap["error"])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:245) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:227) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
at org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter.readInternal(OAuth2ErrorHttpMessageConverter.java:74) ~[spring-security-oauth2-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
... 71 common frames omitted
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
 at [Source: (sun.net.www.protocol.http.HttpURLConnection$HttpInputStream); line: 1, column: 10] (through reference chain: java.util.LinkedHashMap["error"])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63) ~[jackson-databind-2.9.10.3.jar:2.9.10.3]
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1343) ~[jackson-databind-2.9.10.3.jar:2.9.10.3]
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1139) ~[jackson-databind-2.9.10.3.jar:2.9.10.3]
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1093) ~[jackson-databind-2.9.10.3.jar:2.9.10.3]
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:63) ~[jackson-databind-2.9.10.3.jar:2.9.10.3]
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:10) ~[jackson-databind-2.9.10.3.jar:2.9.10.3]
at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:527) ~[jackson-databind-2.9.10.3.jar:2.9.10.3]
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:364) ~[jackson-databind-2.9.10.3.jar:2.9.10.3]
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:29) ~[jackson-databind-2.9.10.3.jar:2.9.10.3]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4014) ~[jackson-databind-2.9.10.3.jar:2.9.10.3]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3085) ~[jackson-databind-2.9.10.3.jar:2.9.10.3]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:239) ~[spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
... 73 common frames omitted

1004lucifer
  ...


2020-04-27 18:58:41.687 DEBUG 16420 --- [nio-8080-exec-7] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@72982a80, returned: -1
2020-04-27 18:58:41.688 DEBUG 16420 --- [nio-8080-exec-7] o.s.s.w.a.ExceptionTranslationFilter     : Access is denied (user is anonymous); redirecting to authentication entry point

org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) ~[spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) [spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) [spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) [spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) [spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.8.RELEASE.jar:5.1.8.RELEASE]

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103) [spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]






원인 및 해결방법


아래의 부분을 '아니오' 로 변경 후 다시 테스트해보니 정상적으로 동작했다.