activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <!-- WebView 생성 -->
    <WebView
        android:id="@+id/webView"	<!-- MainActivity.java로 보낼 ID -->
        android:layout_width="match_parent"
        android:layout_height="match_parent"></WebView>

</LinearLayout>

 

 

MainActivity.java

package com.example.study_1;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.KeyEvent;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends AppCompatActivity {

    private WebView webView;
    private String url = "https://www.google.com";  // 접속할 URL

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        webView = (WebView) findViewById(R.id.webView);
        webView.getSettings().setJavaScriptEnabled(true); // 스크립트 실행 허용 여부
        webView.loadUrl(url);	// 앱 실행시 접속할 URL
        webView.setWebChromeClient(new WebChromeClient());   // 크롬으로 열기
        webView.setWebViewClient(new WebViewClientClass());  // 웹뷰 열기
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
		// 뒤로가기 버튼 처리
        if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
            webView.goBack();
            return true;
        }

        return super.onKeyDown(keyCode, event);
    }
	
    // 웹뷰 실행하여 URL접속
    private class WebViewClientClass extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            view.loadUrl(String.valueOf(request.getUrl()));
            return true;
        }

//        안드로이드 27버전 이후로 잠겼음
//        @Override
//        public boolean shouldOverrideUrlLoading(WebView view, String url) {
//            view.loadUrl(url);
//            return true;
//        }
    }
}

 

AndriodManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
	
    <!-- 이 부분 추가 -->
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.Study_1"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

 

출처 : 인프런 홍드로이드님 강의 중.

asap

조회할 데이터가 너무 많은 경우 자주 사용하게 되는 Paging 처리.

사실 필요한 경우는 너무 많고 예제도 다른 블로그에 잘 정리되어 있지만,

막상 만들자니 조회할 전체 건수를 불러오고 페이징할 단위별로 계산해주고 과정이 너무 복잡하다.

귀찮은 페이징을 Spring Data JPA에서 지원하는 방법으로 처리해보자.

 

간단한 예시로 이전 포스팅과 동일하게 게임 길드원에 대한 정보를 조회해보자.

 

GuildRepository에 Paging 메소드를 선언한다.

	// 길드원 기여도에 따른 오름차순 Paging 
	public Page<Guild> findByContributionGreaterThan(int contribution, Pageable paging);

test 코드를 작성한다.

	@Test
	public void testFindByUserGreaterThan() {
		Pageable paging = PageRequest.of(1, 10);
		Page<Guild> results = guildRepo.findByContributionGreaterThan(100, paging);
		results.forEach(guild -> System.out.println(guild));
		
	}

코드를 보면 Pageable 객체와 PageRequest.of(1, 10)가 눈에 띈다.

Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where guild0_.contribution>? limit ?, ?
Hibernate: select count(guild0_.index_no) as col_0_0_ from tbml_guild_info guild0_ where guild0_.contribution>?
Guild(indexNo=16, level=16, userName=cookie16, userJob=도적, authority=길드원, contribution=320, guildRegDate=2022-11-05 15:21:47.0)
Guild(indexNo=17, level=17, userName=cookie17, userJob=마법사, authority=길드원, contribution=340, guildRegDate=2022-11-05 15:21:47.0)
Guild(indexNo=18, level=18, userName=cookie18, userJob=기사, authority=길드원, contribution=360, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=19, level=19, userName=cookie19, userJob=기사, authority=길드원, contribution=380, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=20, level=20, userName=cookie20, userJob=기사, authority=길드원, contribution=400, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=21, level=21, userName=cookie21, userJob=마법사, authority=길드원, contribution=420, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=22, level=22, userName=cookie22, userJob=마법사, authority=길드원, contribution=440, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=23, level=23, userName=cookie23, userJob=마법사, authority=길드원, contribution=460, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=24, level=24, userName=cookie24, userJob=도적, authority=길드원, contribution=480, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=25, level=25, userName=cookie25, userJob=기사, authority=길드원, contribution=500, guildRegDate=2022-11-05 15:21:48.0)

실행 결과를 보면 주목할 점이 두 가지 보인다.

1. 테스트는 한번 실행했지만 SELECT 작업은 두 번 실행되었다.

 => 데이터 조회를 위한 SELECT

 => COUNT(*) 를 위한 SELECT

2. 조회 조건이 기여도(contribution)가 100 이상인 유저를 조회

 => DB에 100이상인 길드원은 45명이나 실제 조회된 것은 10명분이다. 즉, 페이징이 잘 처리된 것을 확인할 수 있다.

 

이제 본격적으로 Paging 처리에 대해 살펴보자.

 

1. Pageable 인터페이스와 PageRequest.of( )

Pageable 인터페이스는 페이징에 대한 많은 메소드가 존재하여 PageRequest 클래스를 통해 사용하는 것이 편하다.

모든 쿼리 메소드는 마지막 파라미터를 Pageable 인터페이스를 사용할 수 있다.

 

public Page<Guild> findByContributionGreaterThan(int contribution, Pageable paging);

 

당연히 PageRequest에는 페이징 처리에 대해 필요한 것들이 들어있다. 

그 중 가장 편리하고 자주 사용하는 것이 PageRequest.of() 이다.

 

Pageable paging = PageRequest.of(0, 10);

 

 # SpringBoot 2.0 아래의 버전에서는 new PageRequest()로 생성하지만 2.0에 들어서는 PageRequest.of()를 사용한다. 

 

 

2. Sort

페이징된 데이터를 정렬할 때는 Sort 클래스를 이용한다.

Order By를 통한 처리도 가능하지만 PageRequest와 Sort를 사용하면 Order By와 달리 추가적인 기능을 쓸 수 있다.

아래는 실제 PageRequest.class 에 정의된 of 메소드이다.

	// 페이지 번호와 페이지당 로우 수를 지정 ( page+1 번 페이지, 10개 로우 )
    public static PageRequest of(int page, int size) {
		return of(page, size, Sort.unsorted());
	}
    
    // 페이지 번호, 로우 수, 정렬방향
    public static PageRequest of(int page, int size, Sort sort) {
		return new PageRequest(page, size, sort);
	}
    
    // 페이지 번호, 로우 수, 정렬방향, 속성
    public static PageRequest of(int page, int size, Direction direction, String... properties) {
		return of(page, size, Sort.by(direction, properties));
	}

Order By와 Sort의 가장 큰 차이는 세 번째 of 메소드의 [String... properties] 파라미터이다.

Order By를 사용하기 위해서는 쿼리 메소드에 OrderByLevelDesc() 처럼 사용하여 메소드명이 길어지지만

Sort를 통해 정렬하게 되면 속성 파라미터를 이용하여 정렬 방향을 지정할 수 있다.

@Test
	public void testFindByUserGreaterThanPageSort() {
		Pageable paging = PageRequest.of(1, 10, Sort.Direction.DESC, "level");
		Page<Guild> results = guildRepo.findByContributionGreaterThan(100, paging);
		results.forEach(guild -> System.out.println(guild));
		
	}
Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where guild0_.contribution>? order by guild0_.level desc limit ?, ?
Hibernate: select count(guild0_.index_no) as col_0_0_ from tbml_guild_info guild0_ where guild0_.contribution>?
Guild(indexNo=40, level=40, userName=cookie40, userJob=마법사, authority=길드원, contribution=800, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=39, level=39, userName=cookie39, userJob=도적, authority=길드원, contribution=780, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=38, level=38, userName=cookie38, userJob=도적, authority=길드원, contribution=760, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=37, level=37, userName=cookie37, userJob=도적, authority=길드원, contribution=740, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=36, level=36, userName=cookie36, userJob=마법사, authority=길드원, contribution=720, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=35, level=35, userName=cookie35, userJob=기사, authority=길드원, contribution=700, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=34, level=34, userName=cookie34, userJob=기사, authority=길드원, contribution=680, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=33, level=33, userName=cookie33, userJob=기사, authority=길드원, contribution=660, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=32, level=32, userName=cookie32, userJob=도적, authority=길드원, contribution=640, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=31, level=31, userName=cookie31, userJob=기사, authority=길드원, contribution=620, guildRegDate=2022-11-05 15:21:48.0)

예제의 코드와 위의 코드와의 차이점은 PageRequest.of( ... ) 의 파라미터에 Sort 관련 파라미터가 추가된 것이다.

그리고 조회결과에서도 예제와 동일한 쿼리메소드를 사용했음에도 전혀 다른 결과가 나오는 것을 볼 수 있다.

 

 

3. Page<T>

보통 JPA를 통해 조회한 결과를 List<T>를 사용하여 관리하지만, Page<T> 타입을 이용하면 

SpringMVC와 연동할 때 많은 이점을 제공해 준다. 즉, 웹페이지와 관련된 작업에 유용한 기능을 제공해준다.

	@Test
	public void testFindByUserGreaterThanPageSort() {
		Pageable paging = PageRequest.of(1, 10, Sort.Direction.DESC, "level");
		Page<Guild> results = guildRepo.findByContributionGreaterThan(100, paging);
		
		// Page<T> 부과기능 : 내용과 건수를 한번에 조회 가능
		System.out.println("PAGE SIZE: " + results.getSize());
		System.out.println("TOTAL PAGES: " + results.getTotalPages());
		System.out.println("TOTAL COUNT: " + results.getTotalElements());
		System.out.println("NEXT: " + results.nextPageable());
				
		List<Guild> list = results.getContent();
				
		results.forEach(guild -> System.out.println(list));
		
	}

Page<T> 객체인 results를 통해 페이징에 대한 정보를 출력하는 것을 확인할 수 있다.

Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where guild0_.contribution>? order by guild0_.level desc limit ?, ?
Hibernate: select count(guild0_.index_no) as col_0_0_ from tbml_guild_info guild0_ where guild0_.contribution>?
PAGE SIZE: 10
TOTAL PAGES: 5
TOTAL COUNT: 45
NEXT: Page request [number: 2, size 10, sort: level: DESC]
[Guild(indexNo=40, level=40, userName=cookie40, userJob=마법사, authority=길드원, contribution=800, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=39, level=39, userName=cookie39, userJob=도적, authority=길드원, contribution=780, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=38, level=38, userName=cookie38, userJob=도적, authority=길드원, contribution=760, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=37, level=37, userName=cookie37, userJob=도적, authority=길드원, contribution=740, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=36, level=36, userName=cookie36, userJob=마법사, authority=길드원, contribution=720, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=35, level=35, userName=cookie35, userJob=기사, authority=길드원, contribution=700, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=34, level=34, userName=cookie34, userJob=기사, authority=길드원, contribution=680, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=33, level=33, userName=cookie33, userJob=기사, authority=길드원, contribution=660, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=32, level=32, userName=cookie32, userJob=도적, authority=길드원, contribution=640, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=31, level=31, userName=cookie31, userJob=기사, authority=길드원, contribution=620, guildRegDate=2022-11-05 15:21:48.0)]
[Guild(indexNo=40, level=40, userName=cookie40, userJob=마법사, authority=길드원, contribution=800, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=39, level=39, userName=cookie39, userJob=도적, authority=길드원, contribution=780, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=38, level=38, userName=cookie38, userJob=도적, authority=길드원, contribution=760, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=37, level=37, userName=cookie37, userJob=도적, authority=길드원, contribution=740, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=36, level=36, userName=cookie36, userJob=마법사, authority=길드원, contribution=720, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=35, level=35, userName=cookie35, userJob=기사, authority=길드원, contribution=700, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=34, level=34, userName=cookie34, userJob=기사, authority=길드원, contribution=680, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=33, level=33, userName=cookie33, userJob=기사, authority=길드원, contribution=660, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=32, level=32, userName=cookie32, userJob=도적, authority=길드원, contribution=640, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=31, level=31, userName=cookie31, userJob=기사, authority=길드원, contribution=620, guildRegDate=2022-11-05 15:21:48.0)]
[Guild(indexNo=40, level=40, userName=cookie40, userJob=마법사, authority=길드원, contribution=800, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=39, level=39, userName=cookie39, userJob=도적, authority=길드원, contribution=780, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=38, level=38, userName=cookie38, userJob=도적, authority=길드원, contribution=760, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=37, level=37, userName=cookie37, userJob=도적, authority=길드원, contribution=740, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=36, level=36, userName=cookie36, userJob=마법사, authority=길드원, contribution=720, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=35, level=35, userName=cookie35, userJob=기사, authority=길드원, contribution=700, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=34, level=34, userName=cookie34, userJob=기사, authority=길드원, contribution=680, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=33, level=33, userName=cookie33, userJob=기사, authority=길드원, contribution=660, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=32, level=32, userName=cookie32, userJob=도적, authority=길드원, contribution=640, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=31, level=31, userName=cookie31, userJob=기사, authority=길드원, contribution=620, guildRegDate=2022-11-05 15:21:48.0)]
[Guild(indexNo=40, level=40, userName=cookie40, userJob=마법사, authority=길드원, contribution=800, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=39, level=39, userName=cookie39, userJob=도적, authority=길드원, contribution=780, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=38, level=38, userName=cookie38, userJob=도적, authority=길드원, contribution=760, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=37, level=37, userName=cookie37, userJob=도적, authority=길드원, contribution=740, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=36, level=36, userName=cookie36, userJob=마법사, authority=길드원, contribution=720, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=35, level=35, userName=cookie35, userJob=기사, authority=길드원, contribution=700, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=34, level=34, userName=cookie34, userJob=기사, authority=길드원, contribution=680, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=33, level=33, userName=cookie33, userJob=기사, authority=길드원, contribution=660, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=32, level=32, userName=cookie32, userJob=도적, authority=길드원, contribution=640, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=31, level=31, userName=cookie31, userJob=기사, authority=길드원, contribution=620, guildRegDate=2022-11-05 15:21:48.0)]
[Guild(indexNo=40, level=40, userName=cookie40, userJob=마법사, authority=길드원, contribution=800, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=39, level=39, userName=cookie39, userJob=도적, authority=길드원, contribution=780, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=38, level=38, userName=cookie38, userJob=도적, authority=길드원, contribution=760, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=37, level=37, userName=cookie37, userJob=도적, authority=길드원, contribution=740, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=36, level=36, userName=cookie36, userJob=마법사, authority=길드원, contribution=720, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=35, level=35, userName=cookie35, userJob=기사, authority=길드원, contribution=700, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=34, level=34, userName=cookie34, userJob=기사, authority=길드원, contribution=680, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=33, level=33, userName=cookie33, userJob=기사, authority=길드원, contribution=660, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=32, level=32, userName=cookie32, userJob=도적, authority=길드원, contribution=640, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=31, level=31, userName=cookie31, userJob=기사, authority=길드원, contribution=620, guildRegDate=2022-11-05 15:21:48.0)]
[Guild(indexNo=40, level=40, userName=cookie40, userJob=마법사, authority=길드원, contribution=800, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=39, level=39, userName=cookie39, userJob=도적, authority=길드원, contribution=780, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=38, level=38, userName=cookie38, userJob=도적, authority=길드원, contribution=760, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=37, level=37, userName=cookie37, userJob=도적, authority=길드원, contribution=740, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=36, level=36, userName=cookie36, userJob=마법사, authority=길드원, contribution=720, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=35, level=35, userName=cookie35, userJob=기사, authority=길드원, contribution=700, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=34, level=34, userName=cookie34, userJob=기사, authority=길드원, contribution=680, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=33, level=33, userName=cookie33, userJob=기사, authority=길드원, contribution=660, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=32, level=32, userName=cookie32, userJob=도적, authority=길드원, contribution=640, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=31, level=31, userName=cookie31, userJob=기사, authority=길드원, contribution=620, guildRegDate=2022-11-05 15:21:48.0)]
[Guild(indexNo=40, level=40, userName=cookie40, userJob=마법사, authority=길드원, contribution=800, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=39, level=39, userName=cookie39, userJob=도적, authority=길드원, contribution=780, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=38, level=38, userName=cookie38, userJob=도적, authority=길드원, contribution=760, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=37, level=37, userName=cookie37, userJob=도적, authority=길드원, contribution=740, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=36, level=36, userName=cookie36, userJob=마법사, authority=길드원, contribution=720, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=35, level=35, userName=cookie35, userJob=기사, authority=길드원, contribution=700, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=34, level=34, userName=cookie34, userJob=기사, authority=길드원, contribution=680, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=33, level=33, userName=cookie33, userJob=기사, authority=길드원, contribution=660, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=32, level=32, userName=cookie32, userJob=도적, authority=길드원, contribution=640, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=31, level=31, userName=cookie31, userJob=기사, authority=길드원, contribution=620, guildRegDate=2022-11-05 15:21:48.0)]
[Guild(indexNo=40, level=40, userName=cookie40, userJob=마법사, authority=길드원, contribution=800, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=39, level=39, userName=cookie39, userJob=도적, authority=길드원, contribution=780, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=38, level=38, userName=cookie38, userJob=도적, authority=길드원, contribution=760, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=37, level=37, userName=cookie37, userJob=도적, authority=길드원, contribution=740, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=36, level=36, userName=cookie36, userJob=마법사, authority=길드원, contribution=720, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=35, level=35, userName=cookie35, userJob=기사, authority=길드원, contribution=700, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=34, level=34, userName=cookie34, userJob=기사, authority=길드원, contribution=680, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=33, level=33, userName=cookie33, userJob=기사, authority=길드원, contribution=660, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=32, level=32, userName=cookie32, userJob=도적, authority=길드원, contribution=640, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=31, level=31, userName=cookie31, userJob=기사, authority=길드원, contribution=620, guildRegDate=2022-11-05 15:21:48.0)]
[Guild(indexNo=40, level=40, userName=cookie40, userJob=마법사, authority=길드원, contribution=800, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=39, level=39, userName=cookie39, userJob=도적, authority=길드원, contribution=780, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=38, level=38, userName=cookie38, userJob=도적, authority=길드원, contribution=760, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=37, level=37, userName=cookie37, userJob=도적, authority=길드원, contribution=740, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=36, level=36, userName=cookie36, userJob=마법사, authority=길드원, contribution=720, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=35, level=35, userName=cookie35, userJob=기사, authority=길드원, contribution=700, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=34, level=34, userName=cookie34, userJob=기사, authority=길드원, contribution=680, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=33, level=33, userName=cookie33, userJob=기사, authority=길드원, contribution=660, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=32, level=32, userName=cookie32, userJob=도적, authority=길드원, contribution=640, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=31, level=31, userName=cookie31, userJob=기사, authority=길드원, contribution=620, guildRegDate=2022-11-05 15:21:48.0)]
[Guild(indexNo=40, level=40, userName=cookie40, userJob=마법사, authority=길드원, contribution=800, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=39, level=39, userName=cookie39, userJob=도적, authority=길드원, contribution=780, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=38, level=38, userName=cookie38, userJob=도적, authority=길드원, contribution=760, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=37, level=37, userName=cookie37, userJob=도적, authority=길드원, contribution=740, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=36, level=36, userName=cookie36, userJob=마법사, authority=길드원, contribution=720, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=35, level=35, userName=cookie35, userJob=기사, authority=길드원, contribution=700, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=34, level=34, userName=cookie34, userJob=기사, authority=길드원, contribution=680, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=33, level=33, userName=cookie33, userJob=기사, authority=길드원, contribution=660, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=32, level=32, userName=cookie32, userJob=도적, authority=길드원, contribution=640, guildRegDate=2022-11-05 15:21:48.0), Guild(indexNo=31, level=31, userName=cookie31, userJob=기사, authority=길드원, contribution=620, guildRegDate=2022-11-05 15:21:48.0)]

Page에 대한 사이즈와 ROW의 수 등 페이지에 대한 정보를 한번에 확인이 가능하며,

Web에 페이지 정보를 전달하여 더욱 유용하게 사용할 수 있다.

 

Page<T> 가 제공해주는 유용한 메소드는 다음과 같다.

int getNumber() 현재 페이지이 정보
int getSize() 한 페이지의 크기
int getTotalPages() 전체 페이지의 수
int getNumberOfElements() 결과 데이터 수
boolean hasPreviousPage() 이전 페이지의 존재 여부
boolean hasNextPage() 다음 페이지의 존재 여부
boolean isLastPage() 마지막 페이지인가 여부
Pageable nextPageable() 다음 페이지 객체
Pageable previousPageable() 이전 페이지 객체
List<T> getCount() 조회된 데이터
boolean hasContent() 결과 존재 여부
Sort getSrot() 검색에 사용된 Sort 정보

 

 

 

※ Spring Data JPA는 구멍가게코딩단의 [초급 개발자들을 위한 가볍고 넓은 스프링부트 스타트 스프링 부트2.0] 책을 참고하였습니다.

 

지난 글에서 만든 Guild 테이블과 길드 구성원의 데이터를 통해 

Spring Data JPA에서 데이터를 조회(SELECT) 하는 방법을 정리한다.

 

1. 쿼리메소드

Spring Data JPA는 메소드의 이름을 통해 쿼리를 실행하도록 지원한다.

이때 메소드 이름은 몇 가지의 규칙을 가지게 된다. 이 규칙이 곧 쿼리 문법이라 봐도 무방할 것 같다.

 

List<T> find[EntityName]By[Colunm]( String str ) ; 

 

Return의 경우 Collection<T> 를 사용하며 그 중 List<T> , Page<T> 를 자주 사용한다.

 

- 장점

 JPA의 특징인 "특정 DB에 종속되지 않는다"는 방식을 그대로 따르기에 

설정된 DB에 대한 SQL 자동 처리를 지원해준다. 즉, 생산성이 향상된다.

 

- 단점

쿼리메소드는 간단한 쿼리를 수행할 수 있는 기능을 제공하지만 실제로 실무의 쿼리는

단순한 [SELECT * FROM TBL WHERE COL1 = 'A'] 처럼 간단하지 않고 훨씬 복잡하다.

이때 쿼리메소드를 통한 조회는 한계가 있기에 QueryDsl , JPQL에 대해 공부해야 한다. 

 

* spring 공식 docs 참고

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.core-concepts

 

2. 쿼리메소드 조회 예제

가장 많이 쓰는 기능들에 대해 코드를 정리하며, 그 외의 조회 조건은 하단의 표를 참고하자.

Repository Interface 를 통해 이번에 정리할 내용을 대략적으로 볼 수 있다.

중요하게 봐야하는 부분은 다음과 같다.

 - 각 예제코드에서 guildRepo 객체를 통해 호출하는 메소드

 - 각 예제의 로그에서 볼 수 있는 생성된 쿼리문 (Hibernate)

public interface GuildRepository extends CrudRepository<Guild, Long>{

	// SELECT 조회
	public List<Guild> findGuildByUserName(String userName);
	
	// SELECT LIKE String% 구문 조회
	public Collection<Guild> findByUserJobStartingWith(String userJob);
		
	// SELECT LIKE %String 구문 조회
	public Collection<Guild> findByUserJobEndingWith(String userJob);
	
	// SELECT LIKE %String% 구문 조회
	public Collection<Guild> findByUserJobContaining(String userJob);
	
	// OR 조건 처리
	public Collection<Guild> findByUserJobContainingOrUserJobContaining(String userJob1, String userJob2);
	
	// AND 조건 처리
	public Collection<Guild> findByUserJobContainingAndUserJobContaining(String userJob1, String userJob2);
	
	// 부등호 처리 ( level > ? :: GreaterThan)
	public Collection<Guild> findByLevelGreaterThan(int level);
	
	// 부등호 처리 ( level < ? :: LessThan)
	public Collection<Guild> findByLevelLessThan(int level);
	
	// 부등호 처리 ( level <= ? :: LessThanEqual)
	public Collection<Guild> findByLevelLessThanEqual(int level);
	
	// userJob% AND Level > 40 Order by 처리
	public Collection<Guild> findByUserJobStartingWithAndLevelGreaterThanOrderByLevelDesc(String userJob, int level);
	
}

 

2-1 단순한 SELECT - WHERE

길드 유저의 이름을 통해 길드원을 조회

@Test
	public void testByTitle() {
		System.out.println(":::: find - By ::::");
		guildRepo.findGuildByUserName("cookie27").forEach(guild -> System.out.println(guild));
	}
:::: find - By ::::
Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where guild0_.user_name=?
Guild(indexNo=27, level=27, userName=cookie27, userJob=도적, authority=길드원, contribution=540, guildRegDate=2022-11-05 15:21:48.0)

 

2-2 LIKE 조회

LIKE 검색은 와일드카드(%)의 위치에 따라 별도의 메소드를 사용한다. (String%, %String , %String%)

String% :: StartingWith

%String :: EndingWith

%String% :: Contatining

@Test
	public void testByUserJobStartingWith() {
		System.out.println(":::: Like String% ::::");
		Collection<Guild> results = guildRepo.findByUserJobStartingWith("기");
		
		results.forEach(guild -> System.out.println(guild));
	}
	
	@Test
	public void testByUserJobEndingWith() {
		System.out.println(":::: Like %String ::::");
		Collection<Guild> results = guildRepo.findByUserJobEndingWith("적");
		
		results.forEach(guild -> System.out.println(guild));
	}
	
	@Test
	public void testByUserJobContaining() {
		System.out.println(":::: Like %String% ::::");
		Collection<Guild> results = guildRepo.findByUserJobContaining("법");
		
		results.forEach(guild -> System.out.println(guild));
	}
:::: Like String% ::::
Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where guild0_.user_job like ? escape ?
Guild(indexNo=3, level=3, userName=cookie3, userJob=기사, authority=길드원, contribution=60, guildRegDate=2022-11-05 15:21:47.0)
Guild(indexNo=4, level=4, userName=cookie4, userJob=기사, authority=길드원, contribution=80, guildRegDate=2022-11-05 15:21:47.0)


:::: Like %String ::::
Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where guild0_.user_job like ? escape ?
Guild(indexNo=5, level=5, userName=cookie5, userJob=도적, authority=길드원, contribution=100, guildRegDate=2022-11-05 15:21:47.0)
Guild(indexNo=8, level=8, userName=cookie8, userJob=도적, authority=길드원, contribution=160, guildRegDate=2022-11-05 15:21:47.0)


:::: Like %String% ::::
Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where guild0_.user_job like ? escape ?
Guild(indexNo=1, level=1, userName=cookie1, userJob=마법사, authority=길드원, contribution=20, guildRegDate=2022-11-05 15:21:47.0)
Guild(indexNo=2, level=2, userName=cookie2, userJob=마법사, authority=길드원, contribution=40, guildRegDate=2022-11-05 15:21:47.0)

 

2-3 OR / AND 연산

OR와 AND는 조건이 여러개인 경우를 나타내므로 [Colunm1] Or [Colunm2] 와 같이 메소드이름을 정한다.

@Test
	public void testByTitleContainingOrContentContaining() {
		System.out.println(":::: OR ::::");
		Collection<Guild> results = guildRepo.findByUserJobContainingOrUserJobContaining("도", "법사");
		results.forEach(guild -> System.out.println(guild));
	}
	
	@Test
	public void testFindByUserJobContainingAndUserJobContaining() {
		System.out.println(":::: AND ::::");
		Collection<Guild> results = guildRepo.findByUserJobContainingAndUserJobContaining("마", "법사");
		results.forEach(guild -> System.out.println(guild));
	}
:::: OR ::::
Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where guild0_.user_job like ? escape ? or guild0_.user_job like ? escape ?
Guild(indexNo=1, level=1, userName=cookie1, userJob=마법사, authority=길드원, contribution=20, guildRegDate=2022-11-05 15:21:47.0)
Guild(indexNo=2, level=2, userName=cookie2, userJob=마법사, authority=길드원, contribution=40, guildRegDate=2022-11-05 15:21:47.0)
Guild(indexNo=5, level=5, userName=cookie5, userJob=도적, authority=길드원, contribution=100, guildRegDate=2022-11-05 15:21:47.0)
Guild(indexNo=7, level=7, userName=cookie7, userJob=마법사, authority=길드원, contribution=140, guildRegDate=2022-11-05 15:21:47.0)
Guild(indexNo=8, level=8, userName=cookie8, userJob=도적, authority=길드원, contribution=160, guildRegDate=2022-11-05 15:21:47.0)

:::: AND ::::
Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where (guild0_.user_job like ? escape ?) and (guild0_.user_job like ? escape ?)
Guild(indexNo=1, level=1, userName=cookie1, userJob=마법사, authority=길드원, contribution=20, guildRegDate=2022-11-05 15:21:47.0)
Guild(indexNo=2, level=2, userName=cookie2, userJob=마법사, authority=길드원, contribution=40, guildRegDate=2022-11-05 15:21:47.0)

 

2-4 부등호 연산

부등호 연산자를 처리하기 위해 아래와 같은 메소드를 지원한다.

 

초과 : num > 10  → GreaterThan

미만 : num < 10 → LessThan

이상 : num >= 10 → GreaterThanEquals

이하 : num <= 10 → LessThanEquals

	@Test
	public void testFindByLevelGreaterThan() {
		System.out.println(":::: Greater ::::");
		Collection<Guild> results = guildRepo.findByLevelGreaterThan(20);
		results.forEach(guild -> System.out.println(guild));

	}
	
	@Test
	public void testFindByLevelLessThan() {
		System.out.println(":::: Less ::::");
		Collection<Guild> results = guildRepo.findByLevelLessThan(20);
		results.forEach(guild -> System.out.println(guild));
	}
	
	@Test
	public void testFindByLevelLessThanEqual() {
		System.out.println(":::: LessThanEqual ::::");
		Collection<Guild> results = guildRepo.findByLevelLessThanEqual(20);
		results.forEach(guild -> System.out.println(guild));
	}
:::: Greater ::::
Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where guild0_.level>?
Guild(indexNo=21, level=21, userName=cookie21, userJob=마법사, authority=길드원, contribution=420, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=22, level=22, userName=cookie22, userJob=마법사, authority=길드원, contribution=440, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=23, level=23, userName=cookie23, userJob=마법사, authority=길드원, contribution=460, guildRegDate=2022-11-05 15:21:48.0)


:::: Less ::::
Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where guild0_.level<?
Guild(indexNo=1, level=1, userName=cookie1, userJob=마법사, authority=길드원, contribution=20, guildRegDate=2022-11-05 15:21:47.0)
Guild(indexNo=2, level=2, userName=cookie2, userJob=마법사, authority=길드원, contribution=40, guildRegDate=2022-11-05 15:21:47.0)


:::: LessThanEqual ::::
Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where guild0_.level<=?
Guild(indexNo=19, level=19, userName=cookie19, userJob=기사, authority=길드원, contribution=380, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=20, level=20, userName=cookie20, userJob=기사, authority=길드원, contribution=400, guildRegDate=2022-11-05 15:21:48.0)

 

2-5 ORDER BY (정렬)

정렬 기준이 되는 컬럼을 통해 메소드 명을 작성한다

find...By...OrderBy[Colunm][Asc/Desc] ();

 

이번 예는 조금 더 복잡하게 

"직업이 '도' 로 시작하며 레벨이 40 보다 높은 유저정보를 오름(내림)차순으로 정렬" 한 예이다. 

	@Test
	public void testFindByUserJobStartingWithAndLevelGreaterThanOrderByLevelDesc() {
		System.out.println(":::: LIKE + GREATER + ORDER BY(DESC) ::::");
		Collection<Guild> results = guildRepo.findByUserJobStartingWithAndLevelGreaterThanOrderByLevelDesc("도", 40);
		results.forEach(guild -> System.out.println(guild));
	}
	
	@Test
	public void testFindByUserJobStartingWithAndLevelGreaterThanOrderByLevelAsc() {
		System.out.println(":::: LIKE + GREATER + ORDER BY(ASC) ::::");
		Collection<Guild> results = guildRepo.findByUserJobStartingWithAndLevelGreaterThanOrderByLevelAsc("도", 40);
		results.forEach(guild -> System.out.println(guild));
	}
:::: LIKE + GREATER + ORDER BY(ASC) ::::
Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where (guild0_.user_job like ? escape ?) and guild0_.level>? order by guild0_.level asc
Guild(indexNo=43, level=43, userName=cookie43, userJob=도적, authority=길드원, contribution=860, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=44, level=44, userName=cookie44, userJob=도적, authority=길드원, contribution=880, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=46, level=46, userName=cookie46, userJob=도적, authority=길드원, contribution=920, guildRegDate=2022-11-05 15:21:48.0)


:::: LIKE + GREATER + ORDER BY(DESC) ::::
Hibernate: select guild0_.index_no as index_no1_0_, guild0_.authority as authorit2_0_, guild0_.contribution as contribu3_0_, guild0_.guild_reg_date as guild_re4_0_, guild0_.level as level5_0_, guild0_.user_job as user_job6_0_, guild0_.user_name as user_nam7_0_ from tbml_guild_info guild0_ where (guild0_.user_job like ? escape ?) and guild0_.level>? order by guild0_.level desc
Guild(indexNo=46, level=46, userName=cookie46, userJob=도적, authority=길드원, contribution=920, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=44, level=44, userName=cookie44, userJob=도적, authority=길드원, contribution=880, guildRegDate=2022-11-05 15:21:48.0)
Guild(indexNo=43, level=43, userName=cookie43, userJob=도적, authority=길드원, contribution=860, guildRegDate=2022-11-05 15:21:48.0)

 

# 더 많은 쿼리메소드 표현방식은 Spring 공식 docs에 정리되어 있다. (Qeury Creation 항목)

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods

 

Spring Data JPA - Reference Documentation

Example 109. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del

docs.spring.io

 

 

Table 3. Supported keywords inside method namesKeywordSampleJPQL snippet

Distinct findDistinctByLastnameAndFirstname select distinct …​ where x.lastname = ?1 and x.firstname = ?2
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is, Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull, Null findByAge(Is)Null … where x.age is null
IsNotNull, NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> ages) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstname) = UPPER(?1)

 

 

 

※ Spring Data JPA는 구멍가게코딩단의 [초급 개발자들을 위한 가볍고 넓은 스프링부트 스타트 스프링 부트2.0] 책을 참고하였습니다.


class ClassName {
    private int a;    
// 클래스 초기화 블록
    static {
        a = 10;
    }
     // 인스턴스 초기화 블록
    {
        a = 10;
     }

}

* 장점
1. 맴버변수 초기화는 보통 생성자에서 하므로 생성자 오버로딩하여 사용하는 경우 생성자마다 초기화 코드가 들어가야한다.
    static block으로 묶어주는 경우 컴파일 시점에 한번 초기화되어 중복코드를 방지할 수 있다.

2. 하나의 클래스로 여러개의 인스턴스가 동시에 실행되는 경우 유용하다.
    공통적으로 사용하는 변수를 static영역에 넣으므로 1회만 초기화되어도 여러 인스턴스에서 사용이 가능하다.
    
공통적으로 사용하는 변수의 초기화는 static { } 으로 묶어주는 것이 좋다.

'JAVA' 카테고리의 다른 글

HttpURLConnection으로 POST / GET 연습  (0) 2022.10.11
JAVA / JSON 연습  (0) 2022.09.18
AES 암호화 & BASE64 인코딩  (0) 2022.09.04
BufferedInputStream  (0) 2022.08.28
BigDecimal  (0) 2022.08.28

https://triest.tistory.com/14

 

HttpURLConnection 설정 및 옵션

HttpURLConnection Request Header 설정하는 방법 // HttpURLConnection 객체 생성. HttpURLConnection conn = null; // URL 연결 (웹페이지 URL 연결.) conn = (HttpURLConnection)url.openConnection(); // Time..

triest.tistory.com

HttpURLConnection 설정정보

 

 

https://limdevbasic.tistory.com/14

 

[Java] Java로 HTTP GET, POST 통신하기

최근에 프로젝트를 진행하면서 Java로 외부 API를 활용하여 데이터를 얻어와야 하는 일이 생겼습니다. 그래서 Java로 HTTP 통신을 하는 방법에 대해 공부해보았습니다. Oracle JDK 11 버전을 사용했으며

limdevbasic.tistory.com

HttpURLConnection 사용해보기

'개발맛집블로그' 카테고리의 다른 글

장가네  (0) 2022.10.01
SPRING, JPA, 컴퓨터 이론  (0) 2022.09.03

+ Recent posts