Spring Starter Project
Chapter04JPA
src/main/java
com.example.demo
Chapter04JpaApplication.java (main 메서드)
main.controller
MainController.java
member.controller
MemberController.java
member.service
MemberService.java(인터페이스)
MemberServiceImpl.java
member.dao
MemberRepository.java(인터페이스)
member.bean
MemberDTO.java
member.entity
MemberEntity.java
src/main/resources
templates
index.html
member
writeForm.html
static
js
writeForm.js
아이디 중복 검사
writeForm.js
$(function () {
// 아이디 중복 검사
$('#id').on('focusout', function(){
$('#idDiv').empty();
let id = $('#id').val();
if (id === '') {
$('#idDiv').html('아이디를 입력하세요.').css('color', 'red');
} else {
$.ajax({
type: 'post',
url: '/member/getExistId',
data: {'id': id},
dataType: 'text',
success: function(data){
if (data == 'exist') {
$('#idDiv').html('이미 사용 중인 아이디입니다.').css('color', 'red');
} else if(data == 'non_exist') {
$('#idDiv').html('사용가능한 아이디입니다.').css('color', 'green');
}
},
error: function(e){
console.log(e);
}
});
}
});
Chapter04JpaApplication.java ★ ★ ★ ★ ★
@ComponentScan(basePackages = {"main.controller",
"member.controller",
"member.bean",
"member.dao",
"member.entity",
"member.service"})
@EntityScan("member.entity")
@EnableJpaRepositories("member.dao")
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@ComponentScan(basePackages = {"main.controller",
"member.controller",
"member.bean",
"member.dao",
"member.entity",
"member.service"})
@EntityScan("member.entity")
@EnableJpaRepositories("member.dao")
@SpringBootApplication
public class Chapter04JpaApplication {
public static void main(String[] args) {
SpringApplication.run(Chapter04JpaApplication.class, args);
}
}
@EntityScan
- 어노테이션으로 엔티티 클래스를 스캔할 곳을 지정하는데 사용한다.
- 메인 어플리케이션 패키지 내에 엔티티 클래스가 없는 경우 어노테이션을 사용해서
패키지밖에 존재하는 엔티티를 지정할 수 있다.
- 기본적으로 @EnableAutoConfiguration 어노테이션에 의해서 지정한 곳에서 엔티티를 스캔한다.
@EnableJpaRepositories
- JpaRepository에 대한 설정정보를 자동적으로 로딩하고
이 정보를 토대로 Repository 빈을 등록하는 역할을 한다
MemberDTO.java
package member.bean;
import lombok.Data;
@Data
public class MemberDTO {
private String id;
private String pwd;
private String name;
}
MemberEntity.java
package member.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
@Entity
@Table(name = "membertbl")
@Data
public class MemberEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int seq;
@Column(name = "id", nullable = false, unique = true, length = 30)
private String id;
@Column(name = "pwd", nullable = false, length = 300)
private String pwd;
@Column(name = "name", nullable = false, length = 30)
private String name;
}
MemberController.java
@PostMapping(value="isExistId")
@ResponseBody
public String isExistId(@RequestParam String id) {
return memberService.isExistId(id);
}
MemberService.java
package member.service;
public interface MemberService {
public String isExistId(String id);
}
기존의 findById(int)가 와야한다. 밑에 findById는 우리가 만든 쿼리메서드이다.
MemberServiceImpl.java
package member.serviceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import member.dao.MemberRepository;
import member.entity.MemberEntity;
import member.service.MemberService;
@Service
public class MemberServiceImpl implements MemberService {
@Autowired
private MemberRepository memberRepository;
@Override
public String isExistId(String id) {
//기존의 findById(int)가 와야한다. 밑에 findById는 우리가 만든 쿼리메서드이다.
MemberEntity memberEntity = memberRepository.findById(id); //select * from membertbl where id = ?
System.out.println(memberEntity);
if(memberEntity == null)
return "non_exist"; //사용 가능
else
return "exist"; //사용 불가능
}
}
MemberRepository.java
package member.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import member.entity.MemberEntity;
@Repository
public interface MemberRepository extends JpaRepository<MemberEntity, Integer>{
public void findById(String id);
}
회원가입
writeForm.js
// 회원가입 등록
$('#writeBtn').on('click', function(event){
event.preventDefault();
$('#nameDiv').empty();
$('#idDiv').empty();
$('#pwdDiv').empty();
let isValid = true;
// 이름 검증
if($('#name').val().trim() == ''){
$('#nameDiv').html('이름을 입력하세요.').css('color', 'red');
$('#name').focus();
isValid = false;
}
// 아이디 검증
if($('#id').val().trim() == ''){
$('#idDiv').html('아이디를 입력하세요.').css('color', 'red');
$('#id').focus();
isValid = false;
}
// 비밀번호 검증
if($('#pwd').val().trim() == ''){
$('#pwdDiv').html('비밀번호를 입력하세요.').css('color', 'red');
$('#pwd').focus();
isValid = false;
}
if(isValid){
$.ajax({
type: 'post',
url: '/member/write',
data: $('#memberWriteForm').serialize(),
success: function(){
alert('회원가입이 완료되었습니다.');
//location.href='member/list';
},
error: function(e){
console.log(e);
}
});
}
});
});
MemberController.java
@PostMapping(value = "write")
@ResponseBody
public void write(@ModelAttribute MemberEntity memberEntity) {
memberService.write(memberEntity);
}
MemberService.java
public void write(MemberEntity memberEntity);
package member.service;
import member.entity.MemberEntity;
public interface MemberService {
public String isExistId(String id);
public void write(MemberEntity memberEntity);
}
MemberServiceImpl.java
@Override
public void write(MemberEntity memeberEntity) {
memberRepository.save(memeberEntity);
}
회원목록
writeForm.js
location.href='member/list';
if(isValid){
$.ajax({
type: 'post',
url: '/member/write',
data: $('#memberWriteForm').serialize(),
success: function(){
alert('회원가입이 완료되었습니다.');
location.href='member/list';
},
error: function(e){
console.log(e);
}
});
}
MemberController.java
@GetMapping(value = "list")
public String list(Model model) {
List<MemberEntity> list = memberService.getMemberList();
model.addAttribute("list", list);
return "member/list";
}
MemberService.java
public List<MemberEntity> getMemberList();
package member.service;
import java.util.List;
import member.entity.MemberEntity;
public interface MemberService {
public String isExistId(String id);
public void write(MemberEntity memberEntity);
public List<MemberEntity> getMemberList();
}
MemberServiceImpl.java
@Override
public List<MemberEntity> getMemberList() {
return memberRepository.findAll();
}
list.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>회원 목록</title>
<link rel="stylesheet" href="../css/list.css">
</head>
<body>
<div class="list-container">
<a href="/">
<img src="../image/free-icon-love-4096198.png" width="80px" height="80px" alt="heart"/>
</a>
<h2 class="list-title">회원 목록</h2>
<table class="list-table">
<thead>
<tr>
<th>번호</th>
<th>아이디</th>
<th>비밀번호</th>
<th>이름</th>
</tr>
</thead>
<tbody>
<tr th:each="dto : ${list}">
<td th:text="${dto.name}">name</td>
<td>
<a th:href="@{/user/detail/{id}(id=${dto.id})}" th:text="${dto.id}">id</a>
</td>
<td th:text="${dto.pwd}">pwd</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
페이징처리
/member/list?pg=1 => 만약 1페이지라면 숫자 1 생략하게 한다.
index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>메인화면</title>
<link rel="stylesheet" href="../css/main.css">
</head>
<body>
<div class="main-container">
<a href="/">
<img src="../image/free-icon-love-4096198.png" width="80px" height="80px" alt="heart"/>
</a>
<h3 class="main-title"> 메인화면 </h3>
<hr class="divider"/>
<div class="link-container">
<a href="/member/writeForm" class="main-link">가입</a>
<a href="/member/list?page=0" class="main-link">목록</a>
</div>
</div>
</body>
</html>
MemberController.java
@GetMapping(value = "list")
public String list(@RequestParam(value = "page", required = false, defaultValue = "0") String pg,
//0부터 시작, 0이면 1페이지, 1이면 2페이지...
@PageableDefault(page=0, size = 3, sort = "name", direction = Sort.Direction.DESC) Pageable pageable,
Model model) {
Page<MemberEntity> list = memberService.getMemberList(pageable);
model.addAttribute("list", list);
return "member/list";
}
MemberService.java
public Page<MemberEntity> getMemberList(Pageable pageable);
package member.service;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import member.entity.MemberEntity;
public interface MemberService {
public String isExistId(String id);
public void write(MemberEntity memberEntity);
public Page<MemberEntity> getMemberList(Pageable pageable);
}
MemberServiceImpl.java
@Override
public Page<MemberEntity> getMemberList(Pageable pageable) {
return memberRepository.findAll(pageable);
}
페이징 처리2
Spring Starter Project
Chapter04JPA
src/main/java
com.example.demo
Chapter04JpaApplication.java (main 메서드)
main.controller
MainController.java
member.controller
MemberController.java
member.service
MemberService.java(인터페이스)
MemberServiceImpl.java
member.dao
MemberRepository.java(인터페이스)
member.bean
MemberDTO.java
MemberPaging.java
member.entity
MemberEntity.java
src/main/resources
templates
index.html
member
writeForm.html
static
js
writeForm.js
MemberPaging.java
package member.bean;
import org.springframework.stereotype.Component;
import lombok.Data;
@Component
@Data
public class MemberPaging {
private int currentPage; // 현재 페이지
private int pageBlock; // [이전][1][2][3][다음] 블록 크기
private int pageSize; // 페이지당 표시할 게시글 수
private int totalA; // 총 게시글 수
private StringBuffer pagingHTML; // 페이징 HTML을 저장할 StringBuffer
public void makePagingHTML() {
pagingHTML = new StringBuffer();
int totalP = (totalA + pageSize - 1) / pageSize; // 총 페이지 수 계산
int startPage = (currentPage - 1) / pageBlock * pageBlock + 1;
int endPage = startPage + pageBlock - 1;
if (endPage > totalP) endPage = totalP;
if (startPage != 1) {
pagingHTML.append("<span id='paging' onclick='memberPaging(" + (startPage - 1) + ")'>이전</span>");
}
for (int i = startPage; i <= endPage; i++) {
if ( i == currentPage) {
pagingHTML.append("<span id='currentPaging' onclick='memberPaging(" + i + ")'>" + i + "</span>");
} else {
pagingHTML.append("<span id='paging' onclick='memberPaging(" + i + ")'>" + i + "</span>");
}
}
if (endPage < totalP) {
pagingHTML.append("<span id='paging' onclick='memberPaging(" + (endPage + 1) + ")'>다음</span>");
}
}
public StringBuffer getPagingHTML() {
return pagingHTML;
}
}
MemberServiceImpl.java
@Autowired
private MemberPaging memberPaging;
@Override
public Map<String, Object> getMemberList(Pageable pageable) {
Page<MemberEntity> list = memberRepository.findAll(pageable);
//총글수
int totalA = memberRepository.findAll().size();
System.out.println("totalA = " + totalA);
memberPaging.setCurrentPage(pageable.getPageNumber() + 1); //page=0이면 1페이지, page=1이면 2페이지
memberPaging.setPageBlock(3);
memberPaging.setPageSize(3);
memberPaging.setTotalA(totalA);
memberPaging.makePagingHTML();
Map<String, Object> map = new HashMap<>();
map.put("list", list);
map.put("memberPaging", memberPaging);
return map;
}
MemberService
public Map<String, Object> getMemberList(Pageable pageable);
package member.service;
import java.util.Map;
import org.springframework.data.domain.Pageable;
import member.entity.MemberEntity;
public interface MemberService {
public String isExistId(String id);
public void write(MemberEntity memberEntity);
public Map<String, Object> getMemberList(Pageable pageable);
}
MemberController.java
@GetMapping(value = "list")
public String list(@RequestParam(value = "page", required = false, defaultValue = "0") String page,
//0부터 시작, 0이면 1페이지, 1이면 2페이지...
@PageableDefault(page=0, size = 3, sort = "name", direction = Sort.Direction.DESC) Pageable pageable,
Model model) {
Map<String, Object> map = memberService.getMemberList(pageable);
model.addAttribute("map", map);
return "member/list";
}
list.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>회원 목록</title>
<link rel="stylesheet" href="../css/list.css">
</head>
<body>
<div class="list-container">
<a href="/">
<img src="../image/free-icon-love-4096198.png" width="80px" height="80px" alt="heart"/>
</a>
<h2 class="list-title">회원 목록</h2>
<table class="list-table">
<thead>
<tr>
<th>번호</th>
<th>아이디</th>
<th>비밀번호</th>
<th>이름</th>
</tr>
</thead>
<tbody>
<tr th:each="dto : ${map.list}">
<td th:text="${dto.seq}">seq</td>
<td>
<a th:href="@{/member/detail/{id}(id=${dto.id})}" th:text="${dto.id}">id</a>
</td>
<td th:text="${dto.pwd}">pwd</td>
<td th:text="${dto.name}">name</td>
</tr>
</tbody>
</table>
</div>
<div id="memberPagingDiv" th:utext="${map.memberPaging.pagingHTML}"></div>
<script type="text/javascript">
function memberPaging(page) {
location.href="/member/list?page=" + (page-1);
}
</script>
</body>
</html>
검색하기
list.html
<div>
<form id="searchListForm">
<select id="columnName" style="width: 100px;">
<option value="name">이름</option>
<option value="id">아이디</option>
</select>
<input type="text" id="value">
<input type="button" id="searchListBtn" value="검색">
</form>
</div>
list.js
$(function(){
//검색
$('#searchListBtn').click(function(){
if($('#value').val() == '')
alert('검색어를 입력하시오.');
else
$.ajax({
type: 'get',
url: '/member/getSearchList',
data: {'columnName': $('#columnName').val(),
'value': $('#value').val()
},
dataType: 'json',
success: function(data){
console.log(data);
},
error: function(e) {
console.log(e);
}
}); //$.ajax({})
});
});
MemberController.java
@GetMapping(value = "getSearchList")
@ResponseBody
public List<MemberEntity> getSearchList(@RequestParam(value = "columnName") String columnName,
@RequestParam(value = "value") String value){
return memberService.getSearchList(columnName, value);
}
MemberService.java
public List<MemberEntity> getSearchList(String columnName, String value);
package member.service;
import java.util.List;
import java.util.Map;
import org.springframework.data.domain.Pageable;
import member.entity.MemberEntity;
public interface MemberService {
public String isExistId(String id);
public void write(MemberEntity memberEntity);
public Map<String, Object> getMemberList(Pageable pageable);
public List<MemberEntity> getSearchList(String columnName, String value);
}
MemberServiceImpl.java
select * from membertbl where name like '%홍%' -- 이름 검색
근데 MySQL에서는 위에처럼 쓰면 안된다.
select * from membertbl where name like concat('%', '홍'. '%')
이렇게 써야한다.
@Override
public List<MemberEntity> getSearchList(String columnName, String value) {
//쿼리 메서드
if(columnName.equals("name")) {
//select * from membertbl where name like concat('%', '홍'. '%')
return memberRepository.findByNameContaining(value);
}else {
//select * from membertbl where id like concat('%', '홍'. '%')
return memberRepository.findByIdContaining(value);
}
}
MemberRepository.java
//이름 검색
public List<MemberEntity> findByNameContaining(String value);
//아이디 검색
public List<MemberEntity> findByIdContaining(String value);
package member.dao;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import member.entity.MemberEntity;
@Repository
public interface MemberRepository extends JpaRepository<MemberEntity, Integer>{
public MemberEntity findById(String id);
//이름 검색
public List<MemberEntity> findByNameContaining(String value);
//아이디 검색
public List<MemberEntity> findByIdContaining(String value);
}
검색했을 때 이런식으로 json형태로 찍히는 것을 알 수 있다.
json형태로 받아온 데이터 값 뿌리기 !!
list.js
$(function(){
// 검색
$('#searchListBtn').click(function(){
if ($('#value').val() == '') {
alert('검색어를 입력하시오.');
} else {
$.ajax({
type: 'get',
url: '/member/getSearchList',
data: {
'columnName': $('#columnName').val(),
'value': $('#value').val()
},
dataType: 'json',
success: function(data) {
console.log(data);
$('.list-table tbody').empty();
$.each(data, function(index, item) {
let result = `<tr>` +
`<td>` + item.seq + `</td>` +
`<td>` + item.id + `</td>` +
`<td>` + item.pwd + `</td>` +
`<td>` + item.name + `</td>` +
`</tr>`;
$('.list-table tbody').append(result);
}); // $.each
},
error: function(e) {
console.log(e);
}
}); // $.ajax({})
}
});
});
*** Optional
스프링 데이터 JPA를 사용하며 CrudRepository의 findById 메서드 리턴 타입인 Optional 클래스에 처음 접하게 되었다.
Optional은 Java 8에 추가된 새로운 API로 이전에 하던 '고통스러운 null 처리'를
'잘' 다룰 수 있게 도와주는 클래스라고 한다.
Optional 클래스란?
- Optional이란 'null일 수도 있는 객체'를 감싸는 일종의 Wrapper 클래스이다.
*** 쿼리 메소드
JPA에서 제공하는 CrudRepository, 또는 JpaRepository를 이용해서 기본적인 CRUD 기능을 수행했다.
일반적으로 JPA를 이용해서 목록 기능을 구현할 때는 JPQL(Java Persistence Query Language)을 이용하면 된다.
JPQL은 검색 대상이 테이블이 아닌 엔티티 라는 것만 제외하고는 기본 구조와 문법이 기존의 SQL과 유사하다.
스프링 JPA에서는 복잡한 JPQL을 대신해서 처리할 수 있는 쿼리 메소드라는 기능을 제공한다.
쿼리 메소드는 메소드의 이름으로 필요한 쿼리를 만들어주는 기능이다.
쿼리 메소드를 작성할 때 엔티티 이름은 생략할 수 있다.
현재 사용하는 Repository 인터페이스에서 선언된 타입 정보를 기준으로 자동 엔티티 이름이 적용된다.
쿼리 메소드의 리턴 타입은 Page<T>, Slice<T>, List<T> 이며 모두 Collection<T> 타입이다.
이 중에서 가장 많이 사용하는 것은 Page<T>, List<T>로서, 단순히 목록을 검색하려면 List<T>를 사용하고
페이징 처리를 하려면 Page<T>를 사용하면 된다.
*** @Query 어노테이션
일반적인 쿼리는 지금까지 학습한 스프링 데이터 JPA의 쿼리 메소드만으로도 충분하다.
하지만 복잡한 쿼리를 사용하거나 연관관계에 기반한 조인 검색을 처리하기 위해서는
JPQL(Java Persistence Query Language)을 사용해야 한다.
또는 성능상 어쩔 수 없이 특정 데이터베이스에 종속적인 네이티브 쿼리를 사용해야하는 경우도 있다.
JPQL은 일반적인 SQL과 유사한 문법을 가지고 있지만
검색 대상이 테이블이 아니라 영속성 컨텍스트에 등록된 엔티티이다.
따라서 FROM 절에 엔티티 이름과 컬럼 대신 엔티티가 가지고 있는 변수를 조회하기 때문에
SELECT나 WHERE 절에서 사용하는 변수 이름은 대소문자를 구분하여 정확하게 지정해야 한다.
MemberServiceImpl.java
@Override
public List<MemberEntity> getSearchList(String columnName, String value) {
//쿼리 메서드
/*
if(columnName.equals("name")) {
//select * from membertbl where name like concat('%', '홍'. '%')
return memberRepository.findByNameContaining(value);
}else {
//select * from membertbl where id like concat('%', '홍'. '%')
return memberRepository.findByIdContaining(value);
}
*/
//@Query 어노테이션
if(columnName.equals("name")) {
return memberRepository.getSearchMember(value);
}else {
return memberRepository.getSearchId(value);
}
}
MemberRepository.java
//@Query 어노테이션
//검색 대상이 테이블이 아니라 영속성 컨텍스트에 등록된 엔티티이다.
//?1은 첫 번째 파라메터를 의미한다.
@Query("select entity from MemberEntity entity where entity.name like concat('%', ?1, '%')")
public List<MemberEntity> getSearchMember(String value);
@Query("select entity from MemberEntity entity where entity.id like concat('%', ?1, '%')")
public List<MemberEntity> getSearchId(String value);
?1, ?2, ?3 이렇게 하면 어떤 값이 매칭되는지 잘모른다.
@Query("select entity from MemberEntity entity where entity.name like concat('%', :value, '%')")
public List<MemberEntity> getSearchMember(@Param("value") String value);
그러므로 이런식으로 @Param("value")로 쓰는게 무슨 값인지 한 눈에 보인다 !!
검색 후 페이징처리1
MemberController.java
@GetMapping(value = "getSearchList")
@ResponseBody
public Map<String, Object> getSearchList(
@RequestParam(value = "columnName") String columnName,
@RequestParam(value = "value") String value,
@RequestParam(value = "page", required = false, defaultValue = "0") String page,
@PageableDefault(page=0, size = 3, sort = "seq", direction = Sort.Direction.DESC) Pageable pageable){
return memberService.getSearchList(columnName, value, pageable);
}
MemberService.java
public Map<String, Object> getSearchList(String columnName, String value, Pageable pageable);
package member.service;
import java.util.List;
import java.util.Map;
import org.springframework.data.domain.Pageable;
import member.entity.MemberEntity;
public interface MemberService {
public String isExistId(String id);
public void write(MemberEntity memberEntity);
public Map<String, Object> getMemberList(Pageable pageable);
public Map<String, Object> getSearchList(String columnName, String value, Pageable pageable);
}
MemberServiceImpl.java
@Override
public Map<String, Object> getSearchList(String columnName, String value, Pageable pageable) {
//쿼리 메서드
/*
if(columnName.equals("name")) {
//select * from membertbl where name like concat('%', '홍'. '%')
return memberRepository.findByNameContaining(value);
}else {
//select * from membertbl where id like concat('%', '홍'. '%')
return memberRepository.findByIdContaining(value);
}
*/
/*
//@Query 어노테이션
if(columnName.equals("name")) {
return memberRepository.getSearchMember(value);
}else {
return memberRepository.getSearchId(value);
}
*/
Page<MemberEntity> list;
if(columnName.equals("name")) {
list = memberRepository.getSearchMember(value, pageable);
}else {
list = memberRepository.getSearchId(value, pageable);
}
Map<String, Object> map = new HashMap<>();
map.put("list", list);
return map;
}
MemberRepository.java
package member.dao;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import member.entity.MemberEntity;
@Repository
public interface MemberRepository extends JpaRepository<MemberEntity, Integer>{
public MemberEntity findById(String id);
//쿼리 메서드
//이름 검색
public List<MemberEntity> findByNameContaining(String value);
//아이디 검색
public List<MemberEntity> findByIdContaining(String value);
//@Query 어노테이션
//검색 대상이 테이블이 아니라 영속성 컨텍스트에 등록된 엔티티이다.
//?1은 첫 번째 파라메터를 의미한다.
@Query("select entity from MemberEntity entity where entity.name like concat('%', :value, '%')")
public Page<MemberEntity> getSearchMember(@Param("value") String value, Pageable pageable);
@Query("select entity from MemberEntity entity where entity.id like concat('%', :value, '%')")
public Page<MemberEntity> getSearchId(@Param("value") String value, Pageable pageable);
}
데이터를 content가 쥐고있으므로
list.js
$.each(data.list.content, function(index, item) {
$(function(){
// 검색
$('#searchListBtn').click(function(){
if ($('#value').val() == '') {
alert('검색어를 입력하시오.');
} else {
$.ajax({
type: 'get',
url: '/member/getSearchList',
data: {
'columnName': $('#columnName').val(),
'value': $('#value').val()
},
dataType: 'json',
success: function(data) {
console.log(data);
$('.list-table tbody').empty();
$.each(data.list.content, function(index, item) {
let result = `<tr>` +
`<td>` + item.seq + `</td>` +
`<td>` + item.id + `</td>` +
`<td>` + item.pwd + `</td>` +
`<td>` + item.name + `</td>` +
`</tr>`;
$('.list-table tbody').append(result);
}); // $.each
},
error: function(e) {
console.log(e);
}
}); // $.ajax({})
}
});
});
검색 후 페이징 처리2 (추가 설명 필요함 !!!)
list.html
<input type="text" id="page" value="0" />
<script type="text/javascript">
function memberPaging(page){
if($('#value').val() == '')
location.href = "/member/list?page=" + (page-1);
else { // 검색 버튼을 눌렀을 때
$('#page').val(page-1);
$('#searchListBtn').trigger('click');
}
}
</script>
검색 버튼을 눌렀을 때 강제이벤트를 발생시켜야 한다.
list.js
$(function(){
// 검색
$('#searchListBtn').click(function(){
alert($('#columnName').val() + ", " + $('#value').val() + ", " + $('#page').val());
if ($('#value').val() == '') {
alert('검색어를 입력하시오.');
} else {
$.ajax({
type: 'get',
url: '/member/getSearchList',
data: {
'columnName': $('#columnName').val(),
'value': $('#value').val(),
'page': $('#page').val()
},
dataType: 'json',
success: function(data) {
console.log(data);
$('.list-table tbody').empty();
$.each(data.list.content, function(index, item) {
let result = `<tr>` +
`<td>` + item.seq + `</td>` +
`<td>` + item.id + `</td>` +
`<td>` + item.pwd + `</td>` +
`<td>` + item.name + `</td>` +
`</tr>`;
$('.list-table tbody').append(result);
$('#memberPagingDiv').html(data.memberPaging.pagingHTML);
}); // $.each
},
error: function(e) {
console.log(e);
}
}); // $.ajax({})
}
});
});
MemberController.java
@GetMapping(value = "getSearchList")
@ResponseBody
public Map<String, Object> getSearchList(
@RequestParam(value = "columnName") String columnName,
@RequestParam(value = "value") String value,
@RequestParam(value = "page", required = false, defaultValue = "0") String page,
@PageableDefault(page=0, size = 3, sort = "seq", direction = Sort.Direction.DESC) Pageable pageable){
return memberService.getSearchList(columnName, value, pageable);
}
MemberServiceImpl.java
@Override
public Map<String, Object> getSearchList(String columnName, String value, Pageable pageable) {
//쿼리 메서드
/*
if(columnName.equals("name")) {
//select * from membertbl where name like concat('%', '홍'. '%')
return memberRepository.findByNameContaining(value);
}else {
//select * from membertbl where id like concat('%', '홍'. '%')
return memberRepository.findByIdContaining(value);
}
*/
/*
//@Query 어노테이션
if(columnName.equals("name")) {
return memberRepository.getSearchMember(value);
}else {
return memberRepository.getSearchId(value);
}
*/
//페이징 처리
Page<MemberEntity> list;
int totalA = 0;
if(columnName.equals("name")) {
list = memberRepository.getSearchMember(value, pageable);
totalA = memberRepository.findByNameContaining(value).size();
}else {
list = memberRepository.getSearchId(value, pageable);
totalA = memberRepository.findByIdContaining(value).size();
}
memberPaging.setCurrentPage(pageable.getPageNumber() + 1); //page=0이면 1페이지, page=1이면 2페이지
memberPaging.setPageBlock(3);
memberPaging.setPageSize(3);
memberPaging.setTotalA(totalA);
memberPaging.makePagingHTML();
Map<String, Object> map = new HashMap<>();
map.put("list", list);
map.put("memberPaging", memberPaging);
return map;
}
}
MemberRepository.java
//검색 - 총글수
public Map<String, Object> findAllByColumnNameContaining(String value);
package member.dao;
import java.util.List;
import java.util.Map;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import member.entity.MemberEntity;
@Repository
public interface MemberRepository extends JpaRepository<MemberEntity, Integer>{
public MemberEntity findById(String id);
//쿼리 메서드
//이름 검색
public List<MemberEntity> findByNameContaining(String value);
//아이디 검색
public List<MemberEntity> findByIdContaining(String value);
//@Query 어노테이션
//검색 대상이 테이블이 아니라 영속성 컨텍스트에 등록된 엔티티이다.
//?1은 첫 번째 파라메터를 의미한다.
@Query("select entity from MemberEntity entity where entity.name like concat('%', :value, '%')")
public Page<MemberEntity> getSearchMember(@Param("value") String value, Pageable pageable);
@Query("select entity from MemberEntity entity where entity.id like concat('%', :value, '%')")
public Page<MemberEntity> getSearchId(@Param("value") String value, Pageable pageable);
//검색 - 총글수
public Map<String, Object> findAllByColumnNameContaining(String value);
}
'Spring Boot' 카테고리의 다른 글
DAY 96 - (2024.11.21) (0) | 2024.11.25 |
---|---|
DAY94 - (2024.11.19) (0) | 2024.11.20 |
DAY 90 - JPA (2024.11.13) - 쿼리메서드 / 메인화면, 회원가입폼 (2024.11.13) (0) | 2024.11.14 |
DAY 89 - JPA (2024.11.12) (1) | 2024.11.12 |
DAY 88 - JPA (2024.11.11) (0) | 2024.11.12 |