한참 헤매다.. app script 의 설정에 문제가 있는것을 알았다.
웹앱 배포 시 엑세스 권한이 나에게만 되어 있는지 확인 후 "모든사용자" 엑세스 권한으로 변경 후 배포 한다.
반나절을 날렸다..
'기타 > 기타' 카테고리의 다른 글
mac m1(Apple Silicon) 호환 JDK 설치 (1) | 2021.07.05 |
---|---|
'outlook 닫는중' 강제 종료 방법 (0) | 2021.01.07 |
한참 헤매다.. app script 의 설정에 문제가 있는것을 알았다.
웹앱 배포 시 엑세스 권한이 나에게만 되어 있는지 확인 후 "모든사용자" 엑세스 권한으로 변경 후 배포 한다.
반나절을 날렸다..
mac m1(Apple Silicon) 호환 JDK 설치 (1) | 2021.07.05 |
---|---|
'outlook 닫는중' 강제 종료 방법 (0) | 2021.01.07 |
http 통신 에러 D NetworkSecurityConfig: Using Network Security Config from resource network_security_config debugBuild: false
NetworkSecurityConfig: No Network Security Config specified, using platform default
Flutter apk 빌드 후 http 통신 불가 로그 확인
logcat 확인 시 아래와 같은 로그 확인 함
"D NetworkSecurityConfig: Using Network Security Config from resource network_security_config debugBuild: false"
검색 결과 Android 설정 문제로 확인 되어 아래 처럼 내용 수정 후 빌드 시 정상 확인
1. main -> AndroidManifest.xml 수정
<manifest
(...)
<uses-permission android:name="android.permission.INTERNET" /> <= 추가
<application
android:usesCleartextTraffic="true" <= 추가
android:networkSecurityConfig="@xml/network_security_config" <= 추가
(...)
>
<activity
</activity>
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
2. main/res/xml 디렉토리 파일 생성 -> network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
플러터에서 웹 빌드 (Missing index.html. 에러처리) (0) | 2020.10.14 |
---|
so 별 별도 로직이 존재하므로 반복과 중복 if 문을 써서 코드가 복잡해 지는 구조가 있다.
java reflect 를 이용하여 동적으로 class 및 method 호출 과정에 대해 기록한다.
전체 코드는 다음 링크에서 확인 (https://github.com/pari0130/reflection)
service 별 버전이 상이하여 별도 클래스로 분리 할 경우 호출하는 로직에서 if 문 중첩이 발생 될 수 있으므로 동적 호출 방안에 대해 기록 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/**
* 설명
*
* Retention RunTime : compile time 과 binary 에도 포함되고, reflection 을 통해 접근 가능
*
* Target CLASS : class, interface, object, annotation class 에 사용 가능하도록 제한
*
* values : 서비스 버전 정보 입력을 위해 사용
*
* */
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS)
annotation class ServiceVersion(
val values: Array<String> = []
)
|
interface TestService {
fun getTestItems(item: String): Map<String, Any>
fun insertCharge(param: Map<String, Any>)
}
// v1 로 사용 될 class
@Service("TestServiceV1Impl")
@ServiceVersion(values = ["v1"])
class TestServiceV1Impl(val testDiService: TestDiService) : TestService { }
// v1.1 로 사용 될 class
@Service("TestServiceV11Impl")
@ServiceVersion(values = ["v1.1"])
class TestServiceV11Impl(val testDiService: TestDiService) : TestService { }
// v1.2 로 사용 될 class
@Service("TestServiceV12Impl")
@ServiceVersion(values = ["v1.2"])
class TestServiceV12Impl(val testDiService: TestDiService) : TestService { }
|
override fun getTestService(version: String): TestService {
return applicationContext.getBeanProvider(TestService::class.java).stream() // TestService interface 를 상속한 Bean 조회
.filter { b -> !ObjectUtils.isEmpty(b.javaClass.getDeclaredAnnotation(ServiceVersion::class.java)) }
.filter { b ->
Arrays.stream(b.javaClass.getDeclaredAnnotation(ServiceVersion::class.java).values) // version annotation 을 사용하는 method 중 일치하는 값 조회
.anyMatch { v -> v.equals(version) }
}
.findAny()
.orElse(applicationContext.getBean("TestServiceV1Impl", TestService::class.java))
}
|
@Test
fun getTestService() {
var version = "v1"
val itemV1 = testDiService.getTestService(version).getTestItems("v1 item test")
version = "v1.1"
val itemV11 = testDiService.getTestService(version).getTestItems("v1.1 item test")
version = "v1.2"
val itemV12 = testDiService.getTestService(version).getTestItems("v1.2 item test")
logger.info("[TEST] item -> { $itemV1, $itemV11, $itemV12 }") // [TEST] item -> { {item=v1 item test}, {item=v1.1 item test}, {item=v1.2 item test} }
assertAll(
{ Assertions.assertEquals(itemV1["item"], "v1 item test") },
{ Assertions.assertEquals(itemV11["item"], "v1.1 item test") },
{ Assertions.assertEquals(itemV12["item"], "v1.2 item test") }
)
}
|
so 별 특정 함수를 호출하는 로직에 대해 중첩된 if 문이 발생 될 수 있으므로 보완 방안으로 Reflection 을 이용한 동적 method 호출에 대해 기록한다.
/**
* 설명
*
* Retention RunTime : compile time 과 binary 에도 포함되고, reflection 을 통해 접근 가능합니다.
*
* Target FUNCTION : 생성자를 제외한 함수들에 사용 가능하도록 제한
*
* soIds : so 별 특정 함수 실행 시 so 입력을 위해 사용
* actionItem : action item 이 다를 수 있으므로 item 입력을 위해 사용
*
* */
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION) // method 에 선언 될 경우 FUNCTION 으로 지정
annotation class SpecificActionItem(
val soIds: Array<String> = [],
val actionItem: Array<String> = []
)
|
interface TestSpecificFunService {
fun insertChargeByCarplat(param: Map<String, Any>)
fun insertChargeByPeopleCar(param: Map<String, Any>)
fun insertChargeByWay(param: Map<String, Any>)
}
@SpecificActionItem(soIds = ["carplat"], actionItem = ["insert_charge"])
override fun insertChargeByCarplat(param: Map<String, Any>) {
logger.info("insertCharge -> { so : carplat, item : insert_charge, param : $param }")
}
@SpecificActionItem(soIds = ["peopleCar"], actionItem = ["insert_charge"])
override fun insertChargeByPeopleCar(param: Map<String, Any>) {
logger.info("insertCharge -> { so : peopleCar, item : insert_charge, param : $param }")
}
@SpecificActionItem(soIds = ["way"], actionItem = ["insert_charge"])
override fun insertChargeByWay(param: Map<String, Any>) {
logger.info("insertCharge -> { so : way, item : insert_charge, param : $param }")
}
|
override fun invokeServiceFun(so: String, actionItem: String, param: Map<*, *>): Any? {
if (so.isNullOrEmpty() || actionItem.isNullOrEmpty()) {
logger.info("[DI LOG] invoke func so or actionItem is Empty -> { so : $so, actionItem : $actionItem }")
return null
}
var invokeResult: Any? = null
applicationContext.getBeanProvider(TestSpecificFunService::class.java).stream()
.forEach extraClass@{ clazz ->
clazz.javaClass.declaredMethods.forEach extraMethod@{ method ->
val extraMethod = method.getAnnotation(SpecificActionItem::class.java) // Annotation method 조회
if (!ObjectUtils.isEmpty(extraMethod)) {
if (extraMethod.soIds.contains(so) && extraMethod.actionItem.contains(actionItem)) { // soid, actionItem
invokeResult = clazz.javaClass.getMethod(method.name, Map::class.java).invoke(clazz, param)
return@extraClass // 일치하는 값이 있을 경우 조회 중인 interface loop 를 종료
}
} else {
return@extraClass
}
}
}
return invokeResult
}
|
@Test
fun invokeServiceFun() {
var so = "carplat"
val actionItem = "insert_charge"
val param = mapOf("param1" to 1, "param2" to 2)
testDiService.invokeServiceFun(so, actionItem, param) // insertCharge -> { so : carplat, item : insert_charge, param : {param1=1, param2=2} }
so = "peopleCar"
testDiService.invokeServiceFun(so, actionItem, param) // insertCharge -> { so : peopleCar, item : insert_charge, param : {param1=1, param2=2} }
so = "way"
testDiService.invokeServiceFun(so, actionItem, param) // insertCharge -> { so : way, item : insert_charge, param : {param1=1, param2=2} }
}
|
초기 호출을 제외하고는 Reflection API를 사용하는 것이 성능에 대한 별 차이가 없는 것에 대한 테스트 블로그 내용 (https://lob-dev.tistory.com/entry/Java%EC%9D%98-Reflection-API)
Kotlin 고차함수에 대한 Callback param 전달 (0) | 2022.05.03 |
---|
@Test
fun callbackTest(){
listLoop(callBack = {
logger.info("callBack index -> ${it["index"]}")
Thread.sleep(500)
})
}
fun listLoop(callBack:(Map<String, Any>) -> Unit){
var index = 0
while (index < 10) {
logger.info("loop -> $index")
callBack.invoke(mapOf("index" to index))
index++
}
}
Kotlin(java) Reflect 를 활용한 중첩 if 문 제거 (0) | 2022.06.13 |
---|
gradle build 에러 "CreateProcess error=206, 파일 이름이나 확장명이 너무 깁니다"
bootRun 을 통해 서비스 실행 후 gradle build 중 아래와 같은 에러가 발생함
검색 시 경로가 길어서 문제가 될수 있다고 하여 해당 서비스 경로도 변경 해봤으나 증상이 동일
다른 케이스를 확인 중 build version 에 대한 문제가 발생 할 수 있다 하여 gradle version 을 update
Slack command 로 google sheet 요청 시 failed with the error "dispatch_failed" error (0) | 2023.03.30 |
---|---|
'outlook 닫는중' 강제 종료 방법 (0) | 2021.01.07 |
QueryDsl 사용 시 date 시작/종료 구간 검색
JPAQuery 부분
query.where(qOrder.createdDate.between(dto.getSearchStartDate(), dto.getSearchEndDate()));
dto 부분
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime searchStartDate;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime searchEndDate;
LocalDateTime 을 사용할때에는 DateTimeFormat 을 입력해줘야 param 에 2021-02-01 09:52:53 같은 date time을 변환하여 받을 수 있다
Springboot @Transactional Rollback 이 안되는 현상 정리 (0) | 2021.03.24 |
---|---|
JSONException 에러 관련 (0) | 2020.08.18 |
Xss custom filter (lucy 적용 안되어 임시방편 코드) (0) | 2020.07.28 |
springboot 에서 jsp-config include 사용 (2) | 2020.07.02 |
@Slf4j 사용시 log cannot be resolved 에러 처리 (4) | 2019.09.18 |
개발 중 insert, update 쿼리 중 Exception 이 발생 하였지만 쿼리 요청이 rollback 되지않는 현상 정리
1. 액션
- insert 혹은 update 문이 false 로 떨어질 경우 throw new Exception 을 처리 함
if(!dao.updateBl("updateQuery", dto)){
throw new BaseException(SystemException.DB_NOT_UPDATE_ACTION);
}
2. 기대동작
- RuntimeException 을 상속 받은 Exception 처리를 했으니 @Transactional 에 의해 rollback 처리를 기대함
3. 증상
- DB update 가 rollback 되지 않고 정상적으로 업데이트가 됨
4. 원인 정리
- update 문을 감싸는 try-catch 문을 신경쓰지 않았으며, catch 문에 처리되는 Exception 이 throw new Exception(e.getMessage()) 만 타고 있었음
- Exception() 의 경우 checked exception 이므로 rollback 처리가 안됨
5. 해결방안
- 첫번째 방법 : try-catch 문의 Exception을 다음과 같이 변경 (RuntimeException 상속받은 클래스)
} catch (Exception e) {
throw new BaseException(e.getMessage());
}
- 두번째 방법 : throw new Exception() 으로 처리하고 @Transactional 의 옵션값을 보완함
@Transactional(rollbackFor = {RuntimeException.class, Exception.class})
현재 첫번째 방법으로 처리 했습니다.
QueryDsl date between 사용 (0) | 2021.04.03 |
---|---|
JSONException 에러 관련 (0) | 2020.08.18 |
Xss custom filter (lucy 적용 안되어 임시방편 코드) (0) | 2020.07.28 |
springboot 에서 jsp-config include 사용 (2) | 2020.07.02 |
@Slf4j 사용시 log cannot be resolved 에러 처리 (4) | 2019.09.18 |
outlook 사용 중 비정상 종료 후 윈도우 우측하단에 'outlook 닫는중' 으로 회색만 표시되고 닫히지 않는 증상시 강제 종료 방법
1. window + r 키로 윈도우 cmd 창을 실행
2. 윈도우 cmd 창에서 'tasklist' 를 입력하여 현재 실행중인 프로세스 호출
3. 프로세스 중 'OUTLOOK.EXE' 를 찾아서 PID 항목을 기록
4. 'OUTLOOK.EXE' 프로그램에 대해 강제로 종료
Slack command 로 google sheet 요청 시 failed with the error "dispatch_failed" error (0) | 2023.03.30 |
---|---|
mac m1(Apple Silicon) 호환 JDK 설치 (1) | 2021.07.05 |
플러터에서 웹 빌드 (Missing index.html. 에러처리)
flutter에서 flutter build web 수행 시 Missing index.html. 에러가 발생하는 경우는 flutter create가 수행되지 않은 문제
아래 순서대로 수행시 문제없습니다.