1. 구글 클라우드 api 개발자 콘솔에서 새 프로젝트 생성 & OAuth2 ID만들기2. 의존성 추가
2021-05-31
0531 OAuth2 적용하기
0531 Spring Security 객체 화면/컨트롤러에서 확인하기
@AuthenticatedPrincipal 어노테이션으로 간단하게 UserDetails타입의 객체를 Authentication에서 뽑아올 수 있다.
스프링 시큐리티는 loadByUsername 메소드 이후 return받은 UserDetails타입을 Authentication이라는 이름의 세션에 Principal이라는 변수명으로 저장해두기 때문에 개발자가 따로 할 일이 없다!!! 후하하!!!
화면에서는 sec:authentication 이라는 태그로 UserDetails타입의 객체를 뽑아올 수 있다.
0531 Spring Security 커스텀하기
1. 먼저 멤버테이블에서 email(식별자) 을 기반으로 멤버 엔티티를 가져오는 repository에 메소드를 작성한다. 로그인할 때 사용할 것이다.
1) @EntityGraph 속성 : 일대 다 , 혹은 컬렉션객체를 멤버변수로 가지고 있을 경우, 그 멤버변수의 갯수만큼 jpa는 select를 날린다. 비효율적이기 때문에 이러한 어노테이션을 이용하면 join으로 한번에 가져올 수 있다.
2) 소셜로그인 유저에 대해서는 따로 처리할 것이기 때문에 boolean fromSocial이라는 파라메터도 추가로 넣어준다.
3) 위에서는 빠뜨렸지만 @Param어노테이션으로 파라메터를 확실히 명시해주는게 좋다. jpa는 똑똑해서 잘 받아오긴 하지만서두~
2. ClubMemberDTO를 추가한다. 이것은 화면에 보여줄그릇(dto)역할이자, UserDetails 역할을 하게된다. UserDetails를 구현한 클래스를 이미 스프링이 준비해두고 있으므로 , 이 중 하나인 User라는 클래스를 extends해서 생성자 오버라이딩 해주자.
entity 와 DTO의 영역을 따로 구분하기 위해 이러한 클래스를 만들었다.
만약 마이바티스같은 맵퍼를 이용한다면 has a로 구현할 수도 있을것이다. ( User를 extends하는 DTO클래스를 만들고, 실제 ClubMember 타입을 멤버변수로 가져서 -> clubmember의 생성자를 만들어준다던지... 중간역할? 이건 나중에 필요할 때 더 생각하자. )
3. UserDetailsService를 구현하는 클래스를 작성한다.
이 클래스를 구현하려면 loadByUsername이라는 메소드를 작성해야한다.
repository에서 유저 정보를 찾아오고 -> 찾아온 유저정보를 기반으로 로그인을 시도하는 유저가 존재하는지 아닌지 검사 ( 없으면 exception을 날린다)
4. 유저가 존재하는 경우 해당 유저의 정보를 entity클래스에서 뽑아내서 UserDetails타입을 구현한 User타입의 ClubMemberDTO로 변환한다. 이 클래스는 화면에 보여줄 그릇이자 - UserDetails타입을 충성히 수행한다! 얏호.
특히 SimpleGrantedAuthority 라는, GrantedAuthority를 구현한 클래스로 Role을 변환해서 넣어준다. (람다식의 map이용해서 role이 여러개인경우에도 대비)
/sample/member페이지 접속 시도시 스프링시큐리티에서 자동으로 설정해 둔 로그인 창이 뜨며 성공적으로 로그인하면 위와같이 멤버 페이지를 확인할 수 있다.
0531 @Builder오류
현재 생성자가 단 1개이므로 - 그 생성자에 맞는 빌더가 형성된다?
부모클래스에서 extends한 멤버변수까지 포함하는 생성자와 충돌
----------------------------
빌더 오류 수정
0531 Spring Security 적용하기
2021-05-30
0530 mybatis, jpa함께 사용하기
jpa의 경우 - 연관관계가 복잡해지거나 통계쿼리등에서 한계를 보인다.
orm.xml을 활용하는 방법도 있는듯....하지만 더 복잡해진다(?) 이부분은 어설프게 썼다가는 큰코다칠듯.
jpa+ mybatis를 함께 사용해본다.
0530 댓글 수정 에러 해결
update 안되고 그냥 save로 새로 insert되던 에러 해결
알고보니 내가 rno(PK)를 getter안해서 그냥 새로운 PK가 자동으로 generated되고 있었다.
putMapping : 그냥 있던거에 밀어넣어줌.
구현할때는 repository로 save하면, 해당 pk값에있는 것과 대조해서 밀어넣는다.
0530 스프링 부트 스터디
좀더 알아보고 싶은 것 - 노란색
1. build 디렉토리 란?
2. gradle의 역할: 빌드 & 라이브러리를 자동으로 가져와준다.
1) 컴파일: 컴퓨터가 이해할 수 있는 언어(바이너리코드) 로 변환하는것
2) 빌드: 어플리케이션을 실행 가능한 단위로 만들어주는 것.
3) 그레이들은 이러한 컴파일+빌드를 자동으로 해준다.
3. dependency란? : 의존성. 잘 만들어진 기능을 재사용할 수 있게 해준다. 내가 만들지 않은 기능들을 이용하여 어플리케이션을 만든다.
4. annotation의 문제점? : 컴파일될때 클래스에 포함이 된다. 메타데이터. 요구사항이 변경되면 -> 자바코드를 뜯어고쳐야 하는가?
http://wiki.gurubee.net/display/DEVSTUDY/Annotation <<출처!!
Annotation의 단점
- 어노테이션 처리시 리플렉션을 통해 해당 클래스를 분석해야 하는 오버헤드가 있다.
- XML 파일을 이용하는 방법도 오버헤드가 있으므로, 경우에 따라서 어노테이션이 더 빠를 수도 있음.
- 어노테이션은 모듈이나 어플리케이션 전반적인 메타데이터를 설정할 수 없다.
- 어노테이션의 범위는 클래스나 패키지 레벨로 한정되기 때문에 여러 클래스에 걸친 공통적인 설정이나 모듈레벨 설정이 어렵다.
- 웹 어플리케이션 개발시 서블릿 필터나, 인터셉터를 이용해서 문제 해결이 가능함.
XML과 어노테이션같이 쓰기
- 대부분의 일반적인 웹 어플리케이션에 적합한 방법 이다.
- 어플리케이션 상에서 디자인 타임에 결정되는 부분에 대해서는 어노테이션을 사용하는 것이 좋고,
실제 디플로이 환경에 따라 바뀔 수 있는 부분의 경우 XML을 사용하여 표기하는 것이 좋다.
5. def querydslDir = "$buildDir/generated/querydsl"
$buildDir : 로컬서버/개발서버/운영서버는 다르다. 따라서 이러한 환경변수를 배포시점에 따로 설정한다.
6. 로컬서버 -> 테스트서버 ( 메이븐, 젠킨스는 여기까지만 역할을 수행한다. ) -> 실제서버
실제서버에서는 최종 산출물만 올라가고, 따라서 빌드툴을 사용해서는 안된다. 맘대로 변경하면 안된다! ( devtools는 정말로 'dev'tools인 것. ) 자원의 복사만 이루어진다.
7. 빌드란? : 컴파일 + 자원의 복사.
8.gradle : wrapper 란?
9. 빌드디렉토리와 out디렉토리
https://goateedev.tistory.com/173 <<그런것이었군!!
10. 인터페이스의 default메소드가 충돌하면 어떻게 되는가?
: https://frontierdev.tistory.com/67 << 충돌시 컴파일 오류, super.~~로 명시해주거나 상속하는 쪽에서 명확히 해주어야한다.
11. DTO클래스의 의문점 :
1) 굳이 builder를 써야하는가? 화면단에만 보이는 클래스이기 때문에, @builder를 만들어서 명시적으로 길게길게 코드로 작성할 필요가 있는가?
2) @Data어노테이션 : 코드가독성을 향상시켜주는 것은 맞다. 그렇지만 DTO이기 때문에- 그다지 코드를 열어서 뜯어볼일이 없다.
3) 아예 DTO를 안쓰고 Collection클래스를 이용하는 방법은? -> null문제가 발생한다. 이것을 해결하려면 직접 뭔가 메소드를 만들어주거나.. 하면서 보충할수있다. 장점은 훨씬 유연하다는 것이다. 그때그때 필요할때 필요한 것만 만들어서 넘겨주면된다. 반면 DTO클래스는 좀더 명시적으로 넘겨주는 데이터를 표현할수있다.
12. 데이터의 영속성이란 ? : 어플리케이션이 중단되더라도 저장된 데이터는 유지된다. 즉, 어플리케이션이 중단되더라도 데이터를 회복해서 가져올 수 있다.
13. Date Type을 사용해야 하는가?
1) DB에서는 Date타입으로 하되
2) 자바 객체에서는 전부 String타입으로 하고, 필요한 날짜계산 메소드 등은 utility로 만들어서 활용하는 방법도 있다. 좀더 유연한 설계가 가능해짐. LocalDateTime 과 같은 클래스를 굳이 이용하지 않아도 된다. java진영에서 이러한 클래스를 계속 업데이트하는데 힘쓰는 이유는 날짜계산 시간계산등이 복잡하기 때문에 기능으로서 제공하기 위해서이다.
3) 즉, 기능으로서 사용한다/ 데이터로서 사용한다 를 명확히하는 방법도 있다는 것.
14. 객체 지향이란? 실행시점에 기능과 데이터가 결정된다는 것이다. (인터페이스 구현)
0530 AWS인스턴스 생성 및 ssh접속
1. 배포 실습을 위한 AWS서버 이용.
1) AWS계정을 만듭니다. 카드번호가 필요합니다. 12개월동안 무료로 서버를 이용할 수 있습니다.
2) 새 인스턴스생성 - > ubuntu18.04선택
2. 새 키페어 생성 -> 다운로드 -> 적절한 폴더에 파일 이동시킨후 파일 권한 설정하기( 윈도우의 경우 속성-보안-고급에서 설정가능. 리눅스의 경우 chmod 명령어 사용)
동빈나님의 도커관련 동영상에서 윈도우GUI화면에서 권한설정관련하여 확인가능.
3. 관리자 권한으로 cmd창을 연후 키페어가 존재하는 디렉토리로 이동한다.
ssh명령어 ( AWS-ec2-연결- 보안 에서 확인가능)를 통해 서버로 원격접속할수있다!!!!!
Are you want connecting? 질문에 yes입력하면 연결성공!!
이렇게 우분투계정으로 바뀌고. 리눅스 명령어를 사용할수있게 된다!!!!매직...
2021-05-29
0529 댓글 기능 구현
1.
리스트에 있는 특정 댓글을 클릭 하면( replyList 의 요소중에서 해당 card-body 를, on click)
그 특정댓글의 내용을 모달에 출력해줄것이다.
input이 아니므로 val()를 쓸수없고, 내용을 가져오려면 html()또는 text() 함수를 써야한다.
단, text()의 경우 html태그를 단순한 String 문자열로 읽기 때문에, html()을 사용한다.
0529 소스코드 배포 과정
1. local => git ( 버전관리 시스템) => 개발서버/실서버.
- 바로 개발서버로 올리는 것이 아니라, git 혹은 svn등의 버전관리시스템에 먼저 commit , push 한 후 실서버에 배포하는 식으로 한다.
2. 소스코드 중에서 굳이 github에 올릴필요가 없는 파일들은 .gitignore에 작성한다. 예를 들면, 빌드도구를 통해 자동적으로 생성되는 파일. 버전관리가 필요없는 파일들.
- .project, .settings, bin, target과 같은 디렉토리는 굳이 git에 올릴 필요가 없다.
관리해야 하는 코드/ 버전관리가 필요없는 코드를 명확히 분리한다.
3. todo: aws계정 및 인스턴스 생성
0529 가독성이 좋은 commit메시지를 쓰자
나의 평소 커밋 메시지를 반성하게 되었다.
https://blog.weirdx.io/post/33832
평소에 그다지 고민하지 않고 커밋메시지를 적곤 했는데.. 그렇다.
유지보수하기 좋고 한눈에 알아보기 편한, 가독성이 좋은 커밋 메시지를 작성해야 한다.
이렇게...단순히 그날그날 업데이트한 내용을 적고있었다. 대/소문자 구별도 하고 있지 않다.
다음부터는
동사(대문자 시작) " (공백) " 상세내용~
순으로 작성하자.
2021-05-28
0528 ajax댓글처리
1. 새로알게된것
HTML 태그의 data -* 속성 : 사용자 커스텀 value를 넣어둘수있다.
key:value로 저장되며 ajax를 이용하면 .data(); 함수를 이용해서 쉽게 값을 뽑아낼수있다. 단 , 클라이언트 브라우저에 전부 값이 노출되므로 보안상 중요한 값은 넣지 않는다.
참고) MDN페이지
https://developer.mozilla.org/ko/docs/Learn/HTML/Howto/Use_data_attributes
2. ReplyController를 생성한다.
특이사항은 RestController로 처리한다는 것.
댓글은 bno를 FK로 물고있기때문에( 다대일관계) 이것을 활용하여 해당 게시글의 댓글을 불러올 것이다. bno는 이미 read페이지에 model객체 안에 담겨있다. 따라서 불러올때는 이 값을 활용하고, document가 로딩되는 시점에서 찾아오도록 비동기처리를 한다.
HttpResponse를 이용해서 데이터 & 200staus를 리턴해줄 것이다.
사실 로직자체는 그다지 복잡하지 않다. 화면구현이 핵심이라고 할수있다.
bno로 조회하면 HttpResponse안의 json데이터를 확인할수있다. (GET맵핑이기때문에 브라우저로도 확인가능하다)
3. 페이지 구현의 흐름은 대강 이러하다.
addReply button 과
ReplyList 가 화면에 존재.
1)
$(document).ready()~~를 활용해서 ReplyList를 클릭하면 ajax로 해당 게시글의 댓글리스트를 찾아온다. 이것은 넘길 데이터 없이 단순 get이기 때문에. jQuery의 $.getJSON 함수를 활용하면 더욱 간단하게 작성할 수 있다.
받아온 데이터는 array이기 때문에, $.each()함수를 활용하여 하나씩 댓글을 붙여준다.
2)
addReply 버튼을 누르면 댓글을 쓰기위한 모달창이 나타난다.
remove,modify,save,clear버튼이 있지만, 이때는 remove와 modify버튼은 hide처리해서 숨긴다.
save버튼을 누르면
모달창안의 input [name = '~~'] 태그를 활용해서 jQuery로 값을 받아오고, 받아온 값을 JSON데이터 형식으로 담는다. $.ajax를 활용해서 post로 데이터를 전송하고, 결과값을 받아온다. (success뒤의 콜백함수) 받아온 결과값을 바탕으로 다시 applyList를 만든다.
댓글이 등록된 후에는 alert로 댓글이 등록되었음을 알리고,
다시 modal창을 hide해주도록 하자.
0528 새로 알게 된 점
1. 파일 다운로드하기
1) 웹 브라우저에 의해서 해석이 불가능한 파일: ppt, xls, hwp등... -> 자원 링크(a 태그) 만 걸어주면 다운로드가 가능
2) 웹 브라우저에 의해서 해석이 가능한 파일: jsp, php, html, jpg등 .. -> 헤더에 추가정보 넣고, 데이터 보내서 다운로드 가능하도록 만들어야 함.
안그러면 그냥 해당 자원페이지로 이동해버림. (다운로드가 아니라)
2021-05-27
0527 QuerydslRepositorySupport 를 이용한 페이징 & Sort
1. sort조건 생성.
sort조건이 여러개 있는 경우를 대비하여 forEach로 처리한다.
Order로 ASC인지 DESC인지를 받고 ,
sort조건을 질의할 테이블을 PathBuilder로 생성한다.
getProperty 는 질의할 컬럼명을 생성한다. ( 이것은 sort할때 넣은 String값일 것이다)
마지막으로, tuple.orderBy메소드안에 OrderSpecifier를 통해 넣어준다.
이런식으로 Sort를 넣어주는 것은... QuerydslRepositorySupport가 Sort타입을 지원하지 않아서이다. 따라서 OrderSpecifier객체를 생성해서 넘겨주어야한다.
다만 이 PathBuilder타입에 대해서는 좀더 연구가 필요할 것같다... 큐도메인 객체를 만들어주는 역할인것같음.
2. return해줄 Page<Object[]>타입을 만드는 과정이다.
Page타입은 interface이기때문에, 이것을 구현한 PageImpl타입을 리턴해줄것이다.
tuple.fetch()를 하면 리턴타입은 List<Tuple>타입이다.
즉 현재, List안에 List(=tuple, 여러개의 열을 가진 레코드) 가 있는 구조.
Tuple을 Arrays로 맵핑하고,
그것을 다시 Collections.toList로 만든다.
테스트 결과 order by 와 limit 쿼리가 형성되는 것을 확인할 수 있다!!
0527 QuerydslRepositorySupport 를 이용한 검색조건 처리
1. 우선 목표로 하는 쿼리를 생각한다.
bno>0 은 항상 들어가야 하는 where조건이고,
검색조건은 있을때도 있고 없을때도 있는 동적 조건이다.
2. BooleanBuilder는 이러한 동적조건을 처리하기 편하게 해준다.
해당 조건이 없으면 and (혹은 or) 문의 쿼리를 만들어주지 않기 때문이다.
type으로 제목, 내용, 제목+내용, 제목+내용+작성자
keyword로 검색어를 받는다.
타입과 키워드가 null이 아닌경우 = 검색 조건이 있는 경우
를 처리하기 위한 BooleanBuilder 타입의 conditionBuilder를 만들고-
앞서 만들어두었던 BooleanBuilder에 이어붙여준다. 이를 통해 검색조건이 있다면 where조건절에 and로 연결될 것이다.
3. 확인하기 위한 간단한 테스트를 작성한다.
(but, 아직 페이징을 위한 코드를 작성하지 않았기 때문에 페이지와 Sort조건은 무시될 것이다)
4. and로 조건문이 처리되고있음을 확인할 수 있다.
5. 조건문이 없는 경우- (즉, 검색하지 않는 경우 ) 이렇게 and가 만들어지지 않고 쿼리가 날라간다!!! 원더풀!!
0527 Tuple을 활용한 다중 컬럼 리턴하기
1. 질의할 테이블이 하나일 경우(Entity가 하나일경우) QuerydslPredicateExecutor를 활용해서 비교적 간단하게 작성할수있으나, FK등 연관관계가 복잡할경우 QuerydslRepositorySupport를 이용하여 쿼리를 작성할 수 있다.
2. 다중 컬럼을 리턴하고 싶은 경우, 결과값을 Tuple이라는 타입을 활용해서 확인할 수 있다.
3. 핵심은, 질의에 필요한 테이블을 조인한 후 ->
select할 컬럼들만 파라메터로 넣고, 그 결과값을 tuple로 받기위한 질의를 한다.
tuple.fetch를 통해 해당 컬럼들의 리스트 ( 즉, 테이블을 통째로 가져온셈)을 확인할 수 있다.
이와같이 추출한 컬럼리스트를 확인할 수 있다.
0527 QuerydslRepositorySupport
1. DomainRepository 인터페이스 생성
2. DomainRepositoryImpl 클래스 생성 + DomainRepository 를 구현 & QuerydslRepositorySupport를 extends한다.
3. 생성자 오버로딩 -> 원하는 Entity 타입을 넣어준다.
4. 해당 DomainRepository를 EntityRepository(JpaRepository를 implements하는) 가 또 implements한다.
5. join활용해서 쿼리를 날린다.
QuerydslRepositorySupport는 복잡한 동적쿼리를 날릴수있게 도와준다.
학습곡선이 높지만. 그만큼 강력하고 확장가능성이 높다!! 한번알아두면 활용굿!
쿼리를 날릴 대상 엔티티(테이블)을 Qdomain객체로 가져온다.
from - 어디 테이블?
join - 어디 테이블? on 조건
where - 조건
fetch() -> 쿼리를 날린다.
2021-05-26
0526 JPQL join 리턴타입 고찰
왜 여러 열을 받는데 교재에서는 리턴타입을 Object로 했을까?에 대한 고민이 있었다.
그래서 테스트로 Object[]배열로 받아보았다.
그러나 실제로는 받아올때 모든 열을 한꺼번에 Object하나로 받아오고있음을 알수있다.
따라서 Object로 일단 받고 -> Object[]배열로 강제타입캐스팅 해주어야 한다.
0526 일한다는 것이 무얼까
https://news.naver.com/main/read.nhn?mode=LPOD&mid=sec&oid=001&aid=0012417366&isYeonhapFlash=Y&rc=N
댓글읽다가 눈물이 순간 울컥했다.
일한다는게 뭘까싶다.
너무너무 일하고 싶어.
정말 맡겨만 주시면 뭐든 할수있는데
0526 튜플을 PageResultDTO로 변환
계속 코드를 짜다보니까 이해가 간다.
행 안에 열이 들어있는 테이블구조 --> Page<Object[]> 타입
Object[]안에는 세 열이 있다.
차례대로 인덱스 0,1,2 로 뽑아낸다. (entity로 만들어주기 위한 강제형변환 필요)
각각의 entity 로 넣고 -> 변환해주는 작업을 PageResultDTO가 맡는다.
어떻게? 람다를 이용한 함수식을 넣는 생성자가! 변환역할을 해주니까.
나는 그 함수식만 던져 넣어주면된다.
결과 화면에 필요한 모든 리스트와 페이지 등을 멤버변수로 가지고 있는 PageResultDTO가 생성된다!
0328 fdisk, mkfs, mount, fstab
1. 하드디스크를 붙인다. 2. fdisk -l로 하드디스크를 확인한다. - interactiive한 커맨드모드 사용하여 (m) 붙인 하드디스크의 파티셔닝을 한다. - 마지막에 w를 해야 실제로 반영이 된다. 3. mkfs를 하여 어떤 파일시스...
-
1. NX : 키가 존재하지 않는다면 실행 2. XX : 존재한다면 실행 3. exists키워드 4. incr, decr키워드 ->조회수같은거에 유용할듯!! 5. 레디스의 데이터 타입 : string, list (큐 혹은 덱으로 이용가능), ...
-
cat : 파일 내용을 출력해줌 -n:번호 붙여서 출력 ( number) -b:번호 붙여서 출력하되 공백에는 번호 붙이지 않음 tac : 거꾸로 출력해줌 > : 해당 내용을 옆으로 재지향(?) . 만약 이미 존재하는 파일일 경우 덮어쓰기 한다...
-
1. 마이바티스의 insertSelectkey 를 이용해서 FK를 transactional로 insert하는 처리를 할것이다. 일반적인 insert와 달리 insertSelectkey를 쓰면, 직후 getRNo를 했을때 해당 식별자 값이 nul...