크롬 드라이버의 find_element_by_css_selector 를 통해서 element를 python으로 가져와서 사용할 수 있다.

 

카카오맵 엘레먼트 찾기

  1. 원하는 엘레먼트를 찾은 후 우클릭하여 검사한다.
  2. 해당 엘레먼트를 검사 창에서 다시 우클릭한 후 Copy > Copy selector 를 선택한다.
  3. 해당 값을 find_element_by_css_selector 의 매게변수로 전달한다.

 

외래 키를 설정하려면 Collation 값이 일치해야 한다.

 

Collation 값 확인하는 방법

show full columns from article ;

 

아래와 같은 방법으로 Collation 값을 변경한다.

alter table category convert to character set utf8 collate utf8mb3_general_ci;

 

 

SQL Error [1452] [23000]: (conn=3205) Cannot add or update a child row: a foreign key constraint fails 

 

Collation 값을 일치시켜준 후 외래 키를 생성하려고 하니 위와같은 오류를 만나게 되었다.

위 오류는 외래키를 생성하려는 테이블에서 외래키를 만들려는 값에 참조 테이블에 없는 값을 가지고 있기 때문이다.

 

travis-ci를 더이상 무료로 사용할 수 없기에 수동으로 제배포 하기로 했다.

우선 프로젝트가 8080포트를 사용하기에 8080포트를 사용중인 프로젝트를 죽인다.

 

8080포트 사용중인 프로세스 종료 시키기

lsof -i tcp:8080
kill $(lsof -t -i:8080)

 

8080포트를 사용중인 프로젝트를 죽였다면 

프로젝트 경로로 이동후 프로젝트 제거

프로젝트 폴더와 해당 내부의 파일을 동시에 제거하기 위한 명령어는 아래와 같다

rm -rf 폴더이름

일반적으로 rm만으로는 폴더에 프로젝트가 존재하면 제거할 수 없다.

빈 폴더면 rmdir로 제거하면 된다.

깃 클론을 이용해서 다시 프로젝트를 받는다.

 

gradlew를 사용하기 위해서 권한 설정을 한다.

chmod +x ./gradlew

 

다음으로 테스트를 수행한다.

./gradlew test

 

다 되었으면 작성해둔 deploy.sh를 실행시킨다.

./deploy.sh

<맞는 코드>

List<Article> findTop4ByCategoryNotOrderByViewCountDesc(String category);

 

<틀린 코드>

List<Article> findTop4ByCategoryNotAndOrderByViewCountDesc(String category);

ORDERBY중간에 AND를 사용하면 안 된다.

ORDERBY의 경우 WHERE 절의 조건이 아님으로 AND를 사용할 필요 없다.

나의 경우 ORDERBY 앞에 AND로 연결하고 조금 헤매게 되었다.

오늘 게시글이나 버튼을 중앙에 배치하고 싶어서 여러 가지 찾아보게 되었다.

우선 버튼을 중앙에 배치하는 방법이다. 이 방법은 div 같은 태그 안의 요소들을 중앙에 배치할 때 유용하다.

style="justify-content:center; display:flex;

bootstrap을 사용한 중앙에 게시글 수정 요소를 나타낼 때 사용했던 방법이다.

<div class="row">
	<div class="col"></div>
	<div class="col-md-6"></div>
	<div class="col"></div>
</div>

위와 같이 html을 작성하면 부트스트랩이 중앙에 정렬을 원하는 요소를 정렬해준다.

 

이번에는 JPA 페이지 사용법을 정리하겠다.

 

Repository

 List<Article> findByCategory(String category, Pageable pageable);

Service

    @Transactional(readOnly = true)
    public List<ArticleListResponseDto> findByCategory(String category, Pageable pageable) {
        return articleRepository.findByCategory(category, pageable).stream()
                .map(ArticleListResponseDto::new)
                .collect(Collectors.toList());
    }

Controller

    @GetMapping("/majorBoard")
    public String majorBoard(Model model, @LoginUser SessionUser user, @AuthenticationPrincipal User user_s,
                            @PageableDefault(sort="id", direction=Sort.Direction.ASC) Pageable pageable)
    {
        List<ArticleListResponseDto> lst = articleService.findByCategory("major", pageable);

        return "article-select";
    }

기본적으로 위와 같이 Repository와 Service 그리고 Controller에 Pageable을 매개변수로 주고받으면 된다.

Controller에서 처음에 Pageable 객체를 받을 때는 @PageableDefault 어노테이션을 사용한다.

어떤 컬럼을 기준으로 정렬을 할지 정렬은 어떤 방식으로 할지 정할 수 있다. 

기본적으로 page 몇 개를 나타낼지 설정하지 않았다면 10개의 행만 나타낸다.

'Today I Learned' 카테고리의 다른 글

수동으로 프로젝트 제배포하기  (0) 2022.03.06
JPA를 사용하며 ORDERBY 주의점  (0) 2022.03.06
mustache로 권한 체크하기  (0) 2022.02.20
MockMvc  (0) 2022.02.03
orm, ibatis, Spring Data JPA  (0) 2022.01.31

 

https://www.acmicpc.net/problem/10825

 

10825번: 국영수

첫째 줄에 도현이네 반의 학생의 수 N (1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 한 줄에 하나씩 각 학생의 이름, 국어, 영어, 수학 점수가 공백으로 구분해 주어진다. 점수는 1보다 크거나 같고, 1

www.acmicpc.net

나의 풀이 by python

n = int(input())
data = []

for i in range(n):
    name, a, b, c = input().split()
    a, b, c = int(a), int(b), int(c)
    data.append([a, b, c, name])

data = sorted(data, key = lambda x : (-x[0], x[1], -x[2], x[3]))

for i in range(n):
    print(data[i][3])

해당 문제는 여러가지 값을 정렬로 이용해야 할 때 유용하게 사용할 수 있는 예제이다. 

이것이 코딩 테스트이다 답안

n = int(input())
students = [] # 학생 정보를 담을 리스트

# 모든 학생 정보를 입력받기
for _ in range(n):
    students.append(input().split())


students.sort(key=lambda x: (-int(x[1]), int(x[2]), -int(x[3]), x[0]))

# 정렬된 학생 정보에서 이름만 출력
for student in students:
    print(student[0])

오늘 관리자 화면 버튼을 유저가 관리자 권한을 가졌을 때만 나타나게끔 만들기로 했다.

하지만 mustache에는 Thymeleaf처럼 아래와 같은 로직을 구현하는 사용할 수 있는 방도를 찾진 못했다.

                        <a
                                class="nav-link active"
                                sec:authorize="hasAnyRole('ROLE_USER')"
                                th:href="@{/note}"
                        >

github에 mustache로 spring security 관련 코드를 찾아봤다.

해당 정보는 찾았지만 해당 코드를 사용하기 위해서는 maven 기반 프로젝트여야 했다. 나의 경우 gradle 기반이기 때문에 임포트 하는 방법에서 방법을 찾기 힘들었다.

그래서 다른 방식으로 권한을 체크하게 되었다.

 

    @GetMapping("/")
    public String main(Model model, @LoginUser SessionUser user, @AuthenticationPrincipal User user_s) {
        checkUser(model, user, user_s);
        return "main";
    }

 

    static public void checkUser(Model model, SessionUser user, User user_s){
        if (user != null) {
            model.addAttribute("nickname", user.getName());
            if(user.getRole().getKey().equals("ROLE_ADMIN"))
                model.addAttribute("isAdmin", user.getRole().getKey());
        }
        if (user_s != null) {
            model.addAttribute("nickname", user_s.getName());
            if(user.getRole().getKey().equals("ROLE_ADMIN"))
                model.addAttribute("isAdmin", user_s.getRole().getKey());
        }
    }

나의 경우 위와같은 방식으로 문제를 해결하였다. 

컨트롤러가 호출될때 유저 권한을 받아서 만약 ADMIN 권한을 가졌다면 isAdmin이라는 값을 model에 넣는 것이다. 

그렇게 하여 mustahce에서는 아래와 같이 구현하였다.

        {{#isAdmin}}
        <!-- Nav Item - Tables -->
        <li class="nav-item" sec:authorize="hasRole('ROLE_ADMIN')">
            <a class="nav-link" href="tables.html">
                <i class="fas fa-fw fa-table"></i>
                <span>관리자 화면</span></a>
        </li>
        {{/isAdmin}}

관리자의 권한을 가졌다면 자연스럽게 관리자 화면 버튼 클릭 버튼이 생성될 것이고 아니라면 생성되지 않을 것이다.

MockMvc

 

perform

요청을 전송하는 역할을 합니다. 결과로 ResultActions 를 반환합니다.

get, post, put, delete

perform() 안에 넣어서 요철할 http method를 정합니다. 

ex)perform(get("/hello"))

params

Key value 파라미터를 전달할수 있습니다.

여러 개일 때는 params, 한개면 param을 사용합니다.

 

andExpect

응답을 검증합니다.

ex) andExpect(status().isBadRequest())

satatus() 상태를 검증합니다. isOk(200), isNotFound(404)

view() 응답으로 받은 뷰 이름을 검증합니다.

redirect() 응답으로 받은 redirect를 검증합니다.

content() 응답 body를 검증합니다.

 

andDo

일반적으로 해야할 일을 표현합니다.

andDO(print()) 하면 결과를 print합니다.

 

스프링 시큐리티의 테스트는 일반적인 컨트롤러 테스트와 약간 다릅니다.

그 이유는 유저가 로그인을 한 상태로 서비스를 이용했다는 가정하에

테스트를 진행할 수 있어야 하기 때문입니다.

시큐리티 테스트를 사용하면 테스트를 시행 전에 원하는 유저를 마치 로그인한 것 처럼 설정할 수 있습니다.

 

가짜 유저를 세팅하는 방법중 3가지 방법을 소개합니다.

@WithMockUser

특정 사용자가 존재하는 것처럼 테스트 진행할 수 있습니다.

@WithUserDetails

사용자 가짜 로그인 가능

~.with

직접 사용자를 mockMvc에 지정하는 방식입니다. 

@Entity

엔티티 클래스 애노테이션

데이터베이스에 저장(persist)할 자바 객체를 정의

- 다양한 애노테이션을 이용해 보다 자세한 테이블 스키마 정보를 표현

- 애노테이션으로 표현한 스키마 정보와 실제 테이블 스키마가 완벽히 일치해야 할 필요는 없음

- 하나의 도메인(domain)으로 간주

 

@Entity 클래스 안에서 사용되는 주요 JPA 애노테이션

- @Table, @Index, @UniqueConstraint: 테이블 기본 정보와 인덱스, unique 키를 설정

- @Id, @GeneratedValue: primary key 설정

- @Column: 각 컬럼 설정

- @Enumerated: enum 을 처리하는 방법을 설정

- @Transient: 특정 필드를 DB 영속 대상에서 제외

- @OneToOne, @OneToMany, @ManyToOne, @ManyToMany: 연관 관계 설정

- @MappedSuperClass: 상속을 이용한 공통 필드 정의

- @Embedded, @Embeddable: 클래스 멤버를 이용한 공통 필드 정의

- @DataTimeFormat: 스프링에서 제공하는 애노테이션, 날짜 입력의 포맷을 지정

 

 

@Entity: JPA엔티티의 lifecycle event를 활용한 Auditing(생성자, 생성일자, 수정자, 수정일자) 테크닉

JPA엔티티에 생성일시, 수정일시 같이 일정하게 작성하는 메타데이터를 처리 가능

- @PrePersist

- @PostPersist

- @PreRemove

- @PostRemove

- @PreUpdate

- @PostUpdate

- @PostLoad

 

@Entity: Spring JPA Auditing 애노테이션

엔티티의 생성일시, 수정일시, 생성자, 수정자를 자동으로 관리해주는 애노테이션

설정

- @EnableJpaAuditing

- @EntityListeners(AuditingEntityListener.class)

활용

- @CreatedBy

- @CreatedDate

- @LastModifiedBy

- @LastModifiedDate

 

ORM(Object Relational Mapping)

객체지향 언어를 이용하여, 서로 호환되지 않는 타입 간의 데이터를 변환하는 기술

 

Apache iBatis

SQL 데이터 베이스와 객체 간 매핑을 지원해주는 persistence framework

 

Spring Data JPA 인터페이스

단계별로 필요한 기능까지만 사용 가능

- Repository: 기본 repository 인터페이스, 어떤 메소드도 제공하지 않음 

- CrudRepository: Repository + CRUD 기능 제공

- PagingAndSortingRepository: CrudRepository + 페이징, 정렬 기능 제공

- JpaRepository: PagingAndSortingRepository + Spring Data JPA repository 전체 기능

 

 

인터페이스에 작성한 메소드 이름이 곧 쿼리 표현이 됨

ex: List<Event>findByEventStatusAndEventNameOrCapacity(String eventStatus, String eventName, Integer capacity);

- 다이나믹 쿼리를 만들 수는 없음

- 사용 가능한 키워드

  - distinct, and, or, is, not, between, lessThan, lessThanEqual, greaterThen, greaterThenEqual

  - null, isNotNull, like, startingWith, endingWith, containing, orderBy, in true, false, ignoreCase

  - join 등 복잡한 표현은 불가

 

 

@Param: 쿼리 메소드 입력 파라미터에 사용하여 애노테이션 기반 파라미터 바인딩할 때 사용

@QUERY: 직접 JPQL을 작성하고 싶을 때 사용

@ NoReositoryBean: 빈으로 등록하고 싶지 않은 인터페이스를 지정할 수 있음

 - 특정 쿼리 메소드를 기본 메소드로 지정하는 방식으로 운영 가능

 - 특정 메소드를 선택적으로 사용하거나 api에 노출하고자 할 때도 사용하는 테크닉

+ Recent posts