레이블이 spring인 게시물을 표시합니다. 모든 게시물 표시
레이블이 spring인 게시물을 표시합니다. 모든 게시물 표시

2022-01-15

1/15 char array -> string


 해쉬함수를 사용하여 byte array 로 반환하니 음수값이 많이 나온다.

이것을 단순히 for문 돌려서 char로 바꾸어보니 값이 많이 깨졌다 (아스키코드값은 다 양수이니까)

해결하기 위하여 Base64Util을 사용하여 String 으로 반환하도록 한다. 

2021-11-17

1117 implements 한 클래스가 많은경우 어떻게 빈으로 등록할지

  프록시 빈을 받을 때 이 문제가 발생 

-> 인터페이스 기반의 프록시

구현한 객체가 많아서. @Autowired로 해서는 충돌하게 된다

-> 해결방법

1. @Configuration 파일을 직접작성 

2. 이름으로 받을 수 있다. @Qualifier 혹은 변수명에 직접 해당 @Autowired 할 객체의 이름을 쓴다 (클래스명의 소문자)

3. 아예 그냥 List 등의 자료구조로 전부 받아버린 다음에 - 조건에 따라서 분기한 뒤 돌려준다



// 아니면  extends클래스 해서 상속으로 해결한다는 방법도 있다..얘는 아예 다른 방식. 좋은지는~? 잘 모르겠다. 왜냐면 - 자식타입이 어떤식으로 동작할지 클라이언트 쪽에서 다 알아야 대자나. ㅜㅜ extends 에 대한.. 이 불안함~~~

2021-11-09

1109 thread 실습하기!




대기큐 사이즈를 0로, 스레드풀사이즈를 100으로 한정해놓고 스레드 1000개를 동시에 보냈다.!!

그랬더니 - 더이상 요청을 받아들일수없다는 에러 메시지 출력!!오오오.



2021-11-07

1107 JUnit 테스트시의 의문점 해결

 JUnit으로 스레드풀테스트를 돌렸을때. join()을 걸어주지않았더니 바로 테스트가 종료되는 점 이 이상하다고 생각했다.

메인스레드가 종료되어도 다른작업스레드가 남아있으면 JVM이 종료되지 않는것이 보통아닌가? 그런데 왜 메인스레드가 이걸 기다려줘야 하지? 하고 의문이 들었다.

->실험1) 스프링이 만들어주는 생명주기와 관련이있다?

이를테면스프링빈에 의존하고있어서?? HelloService의 생명주기와 관련한것인가?

하지만 그렇다면 스레드 자체가 종료되는게 아니고 에러가 떴을거다. 

applicationRunner클래스를 이용하여 즉시실행으로 확인해본결과 역시 스프링 빈 문제는 아니었다.
join()메소드를 걸지 않아도 메소드는 잘 동작했고 예상했던 바와 같이 동시성문제도 발생하는 것을 확인할 수 있었다.


-> 실험2) JUnit프레임워크의 생명주기와 관련이있다?


마찬가지로 일반 main메소드로 돌렸을때도 join()걸지않아도 예상했던대로 출력되었다.


메인 스택이 종료되어도 남은 스레드가 있기때문에 jvm이 종료되지않고 출력되고있음을 확인할수있다.

이로서 JUnit의 생명주기와 join()메소드가 관련있음을 알게되었다!!

아마 JUnit은 테스트종료후에도 남은 스레드로 인해 메모리 누수가 생기는 것을 방지하기 위해 하위스레드들을 자동으로 데몬으로 셋팅하는.. 그런 작업이 있지않나 싶다.

2021-10-25

1025 톰캣, 스레드, 스프링, 커넥션객체

[스프링]

- 메타 정보 파일 + 클래스 => 스프링 어플리케이션

1. 메타정보파일 : xml, 자바 config , db데이터 등등 다양. resourceLoader만 필요적절하게 있다면뭐든 형식오케이

- 스프링 빈 등록방법

1. 형식 : xml또는 java config

2. 방법 : 

1) 직접 bean id일일이 등록

2) component scan해서 베이스 패키지 등록 - 아래에 있는 애들 다 등록하기 . 빈스캐너 등록

3) 스테레오 타입 어노테이션 이용 (위에랑 합쳐서,할수있음)

4) 빈스캐너 : 직접 등록하기 or 해당 빈스캐너를 이미 디폴트로 들고있는 applicationcontext사용하기(우리는 보통 이쪾을 사용하니까 걍 스테레오 타입어노테이션 막붙여버리고 ㅇㅇ 아무렇지않게 쓰고있었다)


3. 반드시 필요한것 : id , class 보통 어노테이션 방식쓰면 - id는 class명에서 앞에만 소문자로 따서 ㅇㅇ만들어짐 

4. 빈 스코프설정  : 디폴트 싱글톤. 특별한 경우 prototype으로 계속 생성도 가능

5. @configuration : 이거 이용해서 여러빈을 한번에 등록. 얘 자체도 하나의 빈이기때문에 싱글톤. 설령 얘의 메소드를 직접부른다고 하더라도1!! 반환된 객체는 싱글톤이다 (오묘~~~@!)

6. 같은 타입의빈이 여러개 있을떄 ? -.> @qualified같이 이름으로 구분하거나 / 아니면 배열로 주고 파라메터 받아서 적절하게 반환한다는 전략도 있음. HashMap으로 해서 이름/ 객체로 받을수도 있음!!! 개쩐당


- DI하기

1. 전략 : setter / 생성자 / 필드 / 일반 메소드 주입

2 . 만약에 테스트 환경같이 갈아끼울필요있으면 setter주입고려해보고.

3. 생성자주입쓰면 한번에 할수있으니까 편하다-

-스테레오타입어노테이션 

: 해당 어노테이션으로 빈등록하면 - aop쓸때 걸러낸다던지. 좀더 명확하게 클래스에 이런애입니다!! 라고 정보를 모아서 볼수있으니 편함. 이용하자. @Repository, @Controller, @Service 그외에 애매한 애들은 @Component라고 등록. 

- @Configuration에 등록하는 애들 : 개발자가 작성한 클래스가 아니라 기술적으로 필요한 애들등록할때도 사용@Bean으로. 


- 다양한 종류의 ApplicationContext가 있다. 여기는 빈들이 생성(초기화) 되고 . 한번 호출해준다!! 그러면- 이제 타고타고 유저요청에따라 main메소드가 실행되고. 







2021-10-02

1002 토비의 스프링 학습

 


- 관심사의 분리. 

- 클라이언트는 내가 어떤 오브젝트를 사용하는지에 관심이없다. 

- 생성및 관계설정의 책임을 DaoFactory에게 위임한다.

- 원래는 각각의 클래스가 가지고 있던 의존성 책임을 -> DaoFactory에게 위임하고. 각각의 클래스는 본연의 비지니스 역할(콘택스트) 에만 집중할 수 있게된다.

- 결국 이 DaoFactory가 일종의 applicationContext로서 Ioc를 담당

- 프레임워크와 라이브러리의 차이는 제어의 흐름이 누구에게 있는가이다.

- 스프링은 '시간'을 '관계'를 담당해준다.

- 각종 오브젝트들을 적절한 시간에 만들고, 그 오브젝트들의 관계를 넣어준다.

- 우리는 비지니스 로직을 공개하지 않고 코드를 짤수있게 된다. 


- 위코드 확인 : 먼저 빈들을 싱글톤으로 등록해두고 -> 클라이언트가 해당 빈을 요청하면 -> getBean으로 찾아서 리턴한다. 


<용어 정리>

- bean:

스프링이 관리하는 오브젝트. 모든 객체가 빈이 아니라, 스프링이 직접 생명주기를 관리해야만 빈이라고 부른다. 

- bean factory

: 빈의 생명주기와 관계설정을 관리하는 클래스. 보통은 빈 팩토리 클래스를 막바로 사용하기보다 어플리케이션 콘텍스트 클래스를 불러서 사용한다. 

- applicationContext :

빈 팩토리를 상속한다. 빈생명주기 + 스프링이 제공하는 부가적인 기능 .




- 직접 제작한 DaoFactory 에서 만들어낸 userDao클래스는 각각 다른 메모리값이 할당된 별개의 인스턴스이다.

반면 @Configuration어노테이션을 통해 ApplicationContext를 생성하고,

이를 통해 Bean Factory 에서 불러낸 UserDao클래스는 동일하다. 테스트 케이스 초록불을 확인할 수 있다.

즉 스프링은 기본적으로 빈을 생성할때 싱글톤 전략을 사용한다. 하지만 왜일까?

- 번외) 동일성과 동등성

동일성 : 물리적 동일성. 같은 메모리상에 위치한다. 기본적으로 Object의 equals메소드는 동일성비교를 한다. (==)

동등성 : 논리적으로 같은가. 특정기준에 의해서 같은 인스턴스임을 보장한다. 단 이때 물리적 메모리 할당값은 다를 수 있다.  (equals)


- 스프링이 싱글톤으로 빈을 생성하는 이유

: 일단 기본적인 자바 싱글톤 전략을 직접 사용한다고 했을때 발생하는 문제점이 여럿있다.

private생성자이므로 상속불가하고 , 확장불가하고, 테스트 하기 어려워진다. 밖에서 생성할수가 없으니..

그리고 서버환경에서는 반드시 한개만 만들어진다고 보장할 수도 없다. 

-> 그렇지만, 싱글톤으로 생성하는 것 적극지지 - 왜냐하면, 유저의 요청에 따라 계속해서 클래스를 생성하면 메모리가 절대로 못버텨난다. 

- 스프링은 자바의 전통적인 싱글톤 전략 대신 Ioc를 이용하여 빈을 싱글톤으로 생성하고 관리한다. 


- 싱글톤사용시 주의점

: 멀티스레드 환경에서는 객체가 공유되기 때문에 주의한다 . 

따라서 -> 상태stateless해야한다. 변경되는 상태값을 가지고 있으면 안된다.

- 변경될수있는 값은 파라메터로 혹은 지역변수로 전달한다. 이건 스택에 쌓이는 정보이므로 공유되지 않으므로 괜찮다.

- 혹은 읽기전용 변수 / 혹은 다른 싱글톤객체를 인스턴스 변수로 가지고 있는 것은 괜찮다.

2021-09-30

0930 tomcat max thread 실험!

 

1. 톰캣 max thread를 1개로 제한하고 100개 클라이언트를 받도록 한경우.( 하나의 클라이언트 요청 약 2초) => 100초 이상걸렸음!! 당연하다. 하나의 톰캣스레드가 혼자 작업을 수행하고, 작업이 끝날때까지 블로킹이 일어난다. blocking이 일어나면 다른 스레드로 교체해줘야 되는데 교체할 스레드가 없다. ㅋㅋ



2. 100개 max thread 톰캣에게 약 2초걸리는 작업을 할당 -> 3초 조금 넘게 걸림. context 스위칭 하는 시간 이 걸려서?


3. Async한 서버로 만든경우:

2초 조금 넘게걸렸다!!!! (세상에) 똑같이 톰캣스레드는 1개인데!!! 대신 작업스레드가 늘어난다. 어떤기준인지는 몰겠으나. 이경우 8개의 워커스레드가 뒤에서 동작하였다. 아마 내가 지금 4코어 컴퓨터라서 4*2= 8 개 만든것인가??




요청을 1000개 로 늘렸더니. 서버는 작업 다 끝냈다고 하는데 클라이언트 쪽은 무한대기에 빠졌다?? 왜지?

2021-09-29

0929 CyclicBarrier 사용하기

 


1.CyclicBarrier 클래스

await()이 불린만큼 생성자안의 넘버가 한개씩 줄어들고.

넘버==0 이되면 메소드를 수행한다. 

2. 나의 경우

메인메서드에서 일단 한번 await() 걸어서. 얘 혼자 스택 못끝내게 만들어놓고.

100개의 스레드 다 만들어져서 await()이 총 101번 걸리면 그때 한꺼번에 호출!

그렇게 함으로써 total elapsed time을 구할 수 있도록 한다!


lock걸어서 동기화한다음에

await() 이 불릴때마다 카운트가 -1 씩 줄어들고

0이 되면 runnable 의 run()호출함을 확인할 수 있음. 


번외) AtomicInteger , AtomicLong클래스

Synchronized 키워드는 기본적으로 비관적 잠금이다. 

동기화 이슈는 확률적으로 매우 작게 일어나긴 하지만 , 일단 잠가놓고 본다.

그렇지만 Atomic~~클래스는 낙관적잠금을 한다.

일단 공유되어질수있고, 해당 공유되어진 값에 차이가 날경우 롤백?보완?잠금?하는 방식이라고한다. 따라서 성능면에서 더 좋다. 

아토믹하다, 원자적이라는 것은 더이상 쪼갤수없다는 것.

이를 테면 원자적 연산이란 = 더이상 쪼갤수없는 연산, 한번에 처리될 수 있는 연산을 의미한다. 

int a = 0은 원자적 연산이다.

하지만 a++ 은 원자적 연산이 아니다.

int a = 0 을 살펴보면

a 를 로드한다(4바이트) & 0을 로드한다(4바이트) & a에 0을 대입한다 => 컴퓨터가 원자적으로 처리할수있다.

하지만 a ++은어떨까?

a = a+ 1 이므로

더하는 과정에서 연산이 쪼개진다.(?) 

그리고 a가 int 가 아니라. long일경우에도! 8바이트가 되어서 연산이 쪼개진다고 함.

더 공부해야징~~


0929 톰캣 스레드 개수를 제한했을 경우

 

톰캣 max 스레드 개수를 10개로 제한


서버의 스레드가 10개로 제한되어 계속 돌려쓰기된다. 매우 느리게 된다!!



클라이언트 측에서는 스레드가 계속 만들어지는데. 서버측에서 이걸 못받아주니까 처리속도가 무지 느려진다! 

0929 inner class 재미있는 오류발생

 

해당 restController클래스에 static을 붙이지 않았을때 생기는 오류

Inner 클래스를 static 메인에서 참조하기 때문에 생긴다.

SpringbootRunner로 run()을 올리면. restController가 인스턴스로 뜨는 건가? 어떤식으로 참조하고 있는 거지. 

메인메서드 에서 static하게 클래스를 올려야 하는데

스태틱하지 않은 inner클래스가 있어서 에러.


해결방법 1) inner클래스를 바깥으로 빼낸다. public 키워드는 제외한다. 하나의 java파일안에 public 클래스는 단 하나밖에 있을수없으며 파일명과 동일해야 한다.


해결방법 2) static inner클래스로 만든다.

2021-07-12

0712 이미지 수정시 NPE!!!


서버에 띄우고 게시글 수정시 이미지를 수정하지 않은 경우 null에러가 뜬다!! 

삼중에 걸쳐서 null 입력값을 검증하고, 로그를 찍어보았더니 
마지막의 equals부분만 false뜬다(와 진짜 숨막힌다. 간신히 막네..)
결국 위 에러는 if문 을 통과해서 null인데 변수를 set하려고했기때문에 발생하는 에러.
NPE가 제일 무섭다 흑흑. 

그런데 서버에 띄우기 전 로컬에서는 이 상태로 잘 돌아갔기 때문에... 대체 어떤식으로 돌아가고 있었는지가 의문이다. STS의 자체적인 서비스인가...

2021-07-07

0707 중복 메시지 오류해결

 

addIngre버튼 안에- searchBtn버튼이 눌리는 식으로 메서드 안에 메서드를 작성했더니

str이 중복해서 나타나는 문제가 있었다.

addIngre를 부를때마다 str이 계속 쌓이는 것이었다.

메서드를 분리해서. addIngre는 얘대로. searchBtn은 얘대로 따로따로 on클릭 메서드를 적어야한다! onclick안에 onclick을 하면. str이 초기화되지않고 계속 쌓인다!


+ foodmy로 insert한 뒤, foodMy로 이동할수있도록 링크를 추가했다!! ㅎㅎ 쇼핑몰은 이런식으로 장바구니 담기 -> 장바구니 담기로 이동하기 라는 박스를 보여주니까. 그걸 따라해보았다. 지속적인 개선!! 페이지들이 잘 연결되는 흐름을 만들수있도록!!

0707 java 메서드를 jsp안에서 사용하기

 1. dto클래스 안에 메서드를 만들기 . static으로 해서 바로 메서드에 접근할 수 있도록 할 것이다.


2. 사용법은 간단하다! 페이지 import를 선언해주고, static이므로 클래스명으로 부르고- 메서드를 사용하면된다!! 변수도 그냥 일반 jstl쓰듯 넣어주면 됨. ㅎㅎ




2021-06-25

0625 스프링 시큐리티 jsp, controller에서 사용하기

<JSP 부분> 

1.  로그인 하지 않은 사용자에게 보여주고 싶을때 

<sec:authorize access="isAnonymous()"> </sec:authorize>

2. 로그인 한 사용자에게 보여주고 싶을때

<sec:authorize access="isAuthenticated()"> </sec:authorize>

3. 로그인 한 사용자의 정보를 뽑아내고자 할때

<sec:authentication property="principal.memberDTO.mName" />

이런식으로 사용할 수 있습니다.

principal은 스프링이 User를 spring security context(스프링이 관리해주는 세션)에 등록하는 변수명입니다.


인터페이스 타입의 UserDetails를

User클래스가 구현하고

User 클래스를 extends하는 CustomUser 클래스를 만들었고

CustomUser 클래스는 멤버변수로 우리의 MemberDTO를 가지고 있습니다. (헥헥..)


즉 getPrincipal(=UserDetails => User =>CustomUser)  -> getMemberDTO -> getMName 의 순서로 변수를 가져오게 되는 것입니다. 동일한 방식으로 MemberDTO의 다른 변수들도 뽑아낼 수 있습니다. @Data어노테이션으로 getter setter를 미리 만들어 두었으니까요! (이메일, 권한 등등.)


4. 로그인한 사용자의 이메일 정보를 뽑아내어 input값을 박아놓기



이런식으로 활용할 수 있습니다.

글을 등록할때 유저가 임의로 본인의 이메일을 조작하지 않도록 readonly를 걸어줍니다.


5. 현재 로그인 한 유저 = 해당 글을 쓴 유저일때만 modify버튼을 보여주기

                                  +

    ADMIN유저는 모든 항목에 접근가능하도록 보여주기




var 로 해당 로그인한 유저의 이메일을 변수로 만든뒤

해당 로그인한 유저(loginUser) = 해당 글을 쓴 유저( dto.mEmail) 일때만 버튼이 보이도록 if문으로 검사 합니다.

혹은 

mGrade를 변수로 받아서 ADMIN일때도 수정,삭제가 가능하도록 합니다.


동일한 작업을 read, modify페이지 둘다 해줍시다.



6. ajax의 하드코딩한 mEmail변수를 수정하기





<Controller 부분>

1. 유저정보를 확인하고 싶을때

Authentication 이라는 타입을 이용하여 뽑아낼 수 있습니다.


이런식으로... 확인할 수 있습니다.

로그 찍어가면서 원하는 변수를 겹겹이 빼내면 됩니다!


2. @GetMapping 접근제어하기

jsp에서 버튼을 숨기더라도 url을 이미 알고있다면 유저는 해당 페이지에 접근할 수 있습니다. 따라서 백엔드에서도 이것을 막아주어야합니다.

@PreAuthorize("isAuthenticated()")

어노테이션을 활용하여 로그인 한 유저만 글을 등록할 수 있게 합니다.



동일하게, RestController에도 접근제어를 걸어줍니다.


3. @PostMapping 접근제어하기

로그인한 유저==해당 글을 등록한 유저

or

권한 ==ADMIN

일 경우에만 글을 수정, 삭제 할 수 있도록 @PostMapping부분을 접근제어해줍니다.

툴을 사용하면 GetMapping을 막아둔 경우에도 @PostMapping으로 접근하여 글을 수정,삭제할수있기 때문입니다.




0625 member통합 및 수정

 

반환값 수정

int로 반환하면 js에서는 <integer>1</integer>이런식으로 document string으로 받기때문에.. 반환값의 타입을 수정하고 관련 js메소드도 수정함



2021-06-24

0624 @RequestBody로 json 못받는 에러 해결!

 사실 정확한 원리는 잘 모르겠다.. 부트는 알아서 척척 객체바인딩 해주던데... 뭔가 그런 auto - config가 스프링에서는 빠져있는 듯함?


원래는 그냥 바로 RecipeGradeDTO로 받았는데, 이상하게 int타입 제외하고는 바인딩이 안되더라. 그래서 아예 그냥 map타입으로 받았더니 받아진다....왜냐! 이자식@!

2021-06-20

0620 javascript 에러 해결!

 card창이 계속해서 증식하는 에러

1개-> 그다음 append 1개 ->그다음 append 1개 ->..

이런식으로 card창이 붙어야 하는데

1개 -> 원래것 1개+ 새로운 것 1개(총 2개) ->1+1+1 = 3개 ->...

이런식으로 캐시(?) 가 쌓이듯이 card창이 계속 증식....

포인트는 함수 안에서 함수를부르지 않고 따로쓰는것.

이거 해결할라고 비동기를 동기로 바꾸는 법.. 까지 찾아보고... 하지만 결국 함수로 해결했다!!


 버튼을 클릭하는 이벤트를 따로따로 함수 작성해서 var값만 넘겨준다.

근데 뭔가 해결한 후에도 좀 찝찝한 감이 있다. 알고리즘을 더 공부하자. 반복문도 못써서야. ㅜㅜ

함수와 함수를 분리하는 그 요령도 아직 감이 안잡힌다. 이런건 어디서 배우는 거지..

원래는 클릭이벤트 안에 또 클릭이벤트 함수를 작성하는 식으로 계속 나열했었는데. 이걸 바꾸었더니 에러가 해결됨. 왤까~~ 왜냐~~ 그래서 해결되어서 기쁘다!! 이제 다음장으로 넘어갈 수 있다!! 


--------------------------------------------------------------




실제로 DB에 insert하는 것은 register 버튼이 눌러질때- 필요한 data항목을 다 긁어서. recipe글과 함께 날라간다!!


인서트 되는 것까지 확인!!! 아싸!!!! 아~~ 속시원하다!! 

후후 이제 다음단계로 가볼까요!!


2021-06-18

0618 모달 보여주기, getJSON으로 값 찾아오기

 

1. 포인트: 필요한 값만 보여주기

    현재 저 모달안에는 다른 input (검색한 음식의 양을 입력받을수있다) 과, 다른 버튼 (addAmount) 가 존재하지만 유저에게는 보이지 않는다. 같은 페이지 안에 있지만 필요한 값만 보여주고 숨기고 하는 것이다.  

2. 버튼을 클릭하면 -> searchInput안의 val을 긁어서 getJSON으로 보내고, 결과 값을 받는다.

결과는 내가 만들어둔 RestController에서 List<FoodDTO>라는 타입으로 보냈다. 그래서 배열로 받아온다. 이제 이것을 li로 감싸서 each로 하나하나 뿌려줄 것이다. 

0618 restcontroller만들고 테스트하기

 

1. 검색어를 입력하면 결과를 반환해주는 restController작성



2. Postman으로 테스트. status 200과 함께 잘 반환되고 있다. 

getMapping이기 때문에 쿼리스트링으로 파라메터가 날아간다.

0618 FK관계의 데이터를 insert하기

 

1. 

마이바티스의 insertSelectkey 를 이용해서 FK를 transactional로 insert하는 처리를 할것이다.

일반적인 insert와 달리  insertSelectkey를 쓰면, 직후 getRNo를 했을때 해당 식별자 값이 null이 아니라 nextval로 불러온 값을 반환받을 수 있다.




2. DTO클래스에 FK관계의 list를 추가해둔다. 
new해야만 배열의 공간을 메모리에 확보할 수 있으니 주의하자. (call by reference)


3. null 체크와 size체크를 반드시 해서, 원하지 않는 결과를 방지한다. list가 있을 경우에만 insert할 것이다. 
list가 존재할경우 리스트에서 하나씩 뽑아서 맵퍼에게 넘기면, 맵퍼안의 insert구문이 실행된다.


4. 테스트 결과 잘 insert됨을 확인해볼 수 있다. 
list가 없을때는 recipe에만 새로운 데이터가 추가된다.


0328 fdisk, mkfs, mount, fstab

 1. 하드디스크를 붙인다. 2. fdisk -l로 하드디스크를 확인한다.  - interactiive한 커맨드모드 사용하여 (m) 붙인 하드디스크의 파티셔닝을 한다.  - 마지막에 w를 해야 실제로 반영이 된다.  3. mkfs를 하여 어떤 파일시스...