interface
로 생성
package com.example.entity;
public interface Member1Projection {
//get + 변수()
String getId();
String getName();
int getAge();
}
// 일부 컬럼만 출력
// JPQL => SELECT id, name, age FROM member1 ORDER BY id ASC;
public List<Member1Projection> findAllByOrderByIdAsc();
@GetMapping(value = "/selectlistprojection.do")
public String selectListProjectionGET(Model model){
try {
List<Member1Projection> list = m1Repository.findAllByOrderByIdAsc();
log.info(format, list.toString());
for(Member1Projection obj : list) { // list형태로 왔기 때문에 확인하기 위해서는 반복문을 사용!
log.info(format, obj.getId() + "," + obj.getName() + "," + obj.getAge());
}
model.addAttribute("list", list);
return "/member1/selectlistprojection";
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h3>회원조회(Member1Projection)</h3>
<hr />
<table border="1">
<thead>
<tr style="text-align: center;">
<td>id</td>
<td>name</td>
<td>age</td>
</tr>
</thead>
<tbody>
<tr th:each="obj : ${list}">
<td th:text="${obj.id}"></td>
<td th:text="${obj.name}"></td>
<td th:text="${obj.age}"></td>
</tr>
</tbody>
</table>
</body>
</html>
package com.example.entity;
public interface Address1Projection {
long getNo(); // 주소번호
String getAddress(); // 주소
Member1 getMember1(); // 회원정보
interface Member1 { // 외래키 항목
String getId(); // 아이디
String getName(); // 이름
}
// 조합 (주소번호 + 주소정보 합치기)
default String getNoAddress() {
return getNo() + "," + getAddress();
}
}
// SELECT a.no, a.address, m.id, m.name FROM address1 a, member1 m ORDER BY no DESC;
List<Address1Projection> findAllByOrderByNoDesc();
@GetMapping(value = "/selectlistprojection.do")
public String selectlistprojectGET(Model model){
try {
List<Address1Projection> list = a1Repository.findAllByOrderByNoDesc();
model.addAttribute("list", list);
return "/address1/selectlistprojection"; // html 위치
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>회원정보 + 주소정보 (Address1Projection)</h1>
<hr />
<table border="1">
<thead>
<tr style="text-align: center;">
<td>주소번호</td>
<td>주소</td>
<td>회원아이디</td>
<td>회원이름</td>
<td>조합 ('주소번호' , '주소정보')</td>
</tr>
</thead>
<tbody>
<tr th:each="obj : ${list}">
<td th:text="${obj.no}"></td>
<td th:text="${obj.address}"></td>
<td th:text="${obj.member1.id}"></td>
<td th:text="${obj.member1.name}"></td>
<td th:text="${obj.noAddress}"></td>
</tr>
</tbody>
</table>
</body>
</html>
-- Create Seq
CREATE SEQUENCE seq_restaurant1_no
INCREMENT BY 1
START WITH 1;
-- Create Table
CREATE TABLE restaurant1
( no NUMBER(19) DEFAULT SEQ_RESTAURANT1_NO.nextval,
phone VARCHAR2(20) PRIMARY KEY,
name varchar2,
address varchar2,
type varchar2(30),
regdate TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
일반적인 방법으로 entity를 추가하게 되면 시퀀스가 null값이 대입되는 오류가 발생한다.
여기서 해결 방법이 두가지로 나뉜다.
package com.example.entity;
import java.math.BigInteger;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.hibernate.annotations.CreationTimestamp;
import org.springframework.format.annotation.DateTimeFormat;
import lombok.Data;
@Entity
@Data
@Table(name = "RESTAURANT1")
@SequenceGenerator(name = "SEQ_RESTAURANT1_NO", sequenceName = "SEQ_RESTAURANT1_NO", initialValue = 1, allocationSize = 1)
@IdClass(Restaurant1ID.class) // 복합키 사용
public class Restaurant1 {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_RESTAURANT1_NO")
private BigInteger no;
@Id
private String phone;
private String name;
private String address;
private String type;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
@CreationTimestamp
@Column(updatable = false)
private Date regdate;
}
ID를 두개 지정해 준 뒤,
Restaurant1ID
라는 새로운 entity 생성.
package com.example.entity;
import java.io.Serializable;
import java.math.BigInteger;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Restaurant1ID implements Serializable{
private BigInteger no;
private String phone;
}
기존 entity를 상속하여 키 값을 두개 지정.
이후 처음의 Restaurant1 entity에
@IdClass(Restaurant1ID.class)
어노테이션을 추가해준다.
package com.example.entity;
import java.math.BigInteger;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.Generated;
import org.hibernate.annotations.GenerationTime;
import org.springframework.format.annotation.DateTimeFormat;
import lombok.Data;
@Data
@Entity
@Table(name = "RESTAURANT1")
@SequenceGenerator(name = "SEQ_RESTAURANT1_NO", sequenceName = "SEQ_RESTAURANT1_NO", initialValue = 1, allocationSize = 1)
public class Restaurant1 {
@Generated(GenerationTime.INSERT)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_RESTAURANT1_NO")
private BigInteger no;
@Id
private String phone;
private String name;
private String address;
private String type;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
@CreationTimestamp
@Column(updatable = false)
private Date regdate;
}
no 컬럼에서
@Generated(GenerationTime.INSERT)
어노테이션을 추가한다. 자동으로 시퀀스가 추가되게 하는 기능이다.
package com.example.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.entity.Restaurant1;
@Repository
public interface Restaurant1Repository extends JpaRepository<Restaurant1, String>{
}
package com.example.controller.jpa;
import java.math.BigInteger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.example.entity.Restaurant1;
import com.example.repository.Restaurant1Repository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping(value = "/restaurant1")
@RequiredArgsConstructor
public class Restaurant1Controller {
final Restaurant1Repository r1Repository;
@GetMapping(value = "/insert.food" )
public String insertGET() {
try {
return "/restaurant1/insert";
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
@PostMapping(value = "/insert.food")
public String insertPOST(
@RequestParam(name = "phone") String phone ,
@RequestParam(name = "name") String name,
@RequestParam(name = "address") String address,
@RequestParam(name = "type") String type) {
try {
Restaurant1 obj = new Restaurant1();
// 식당 등록하기 기능
obj.setPhone(type);
obj.setName(name);
obj.setAddress(address);
obj.setType(type);
r1Repository.save(obj);
return "redirect:/restaurant1/selectlist.food";
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
}
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>식당등록</h1>
<hr />
<form th:action="@{/restaurant1/insert.food}" method="post">
<input type="text" name="phone" value="051-111-" placeholder="전화번호" /><br />
<input type="text" name="name" value="OO반점" placeholder="가게명" /><br />
<input type="text" name="address" value="부산시" placeholder="주소" /><br />
<select name="type" class="form-select" id="inputGroupSelect1">
<option value="한식">한식</option>
<option value="중식">중식</option>
<option value="양식">양식</option>
<option value="일식">일식</option>
<option value="인스턴트">인스턴트</option>
<option value="채식">채식</option>
</select>
<input type="submit" value="등록하기" />
</form>
</body>
</html>
이번엔 등록된 식당들을 조회해보도록 하겠다.
package com.example.repository;
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.entity.Restaurant1;
@Repository
public interface Restaurant1Repository extends JpaRepository<Restaurant1, String>{
// SELECT * FROM restaurant1 WHERE phone LIKE '% || ? || %' ORDER BY no DESC;
List<Restaurant1> findByPhoneContainingOrderByNoDesc(String phone, Pageable pageable);
// SELECT COUNT(*) FROM restaurant1 WHERE phone LIKE '% || ? || %'
long countByPhoneContaining(String phone);
//--------------------------------------------------------------------------------------//
// SELECT * FROM restaurant1 WHERE name LIKE '% || ? || %' ORDER BY no DESC;
List<Restaurant1> findByNameContainingOrderByNoDesc(String name, Pageable pageable);
// SELECT COUNT(*) FROM restaurant1 WHERE name LIKE '% || ? || %'
long countByNameContaining(String name);
//--------------------------------------------------------------------------------------//
// SELECT * FROM restaurant1 WHERE type LIKE '% || ? || %' ORDER BY no DESC;
List<Restaurant1> findByTypeContainingOrderByNoDesc(String type, Pageable pageable);
// SELECT COUNT(*) FROM restaurant1 WHERE TYPE=?
long countByType(String type);
//--------------------------------------------------------------------------------------//
// SELECT * FROM restaurant1 WHERE address LIKE '% || ? || %' ORDER BY no DESC;
List<Restaurant1> findByAddressContainingOrderByNoDesc(String address, Pageable pageable);
// SELECT COUNT(*) FROM restaurant1 WHERE address LIKE '% || ? || %'
long countByAddressContaining(String address);
//--------------------------------------------------------------------------------------//
}
package com.example.controller.jpa;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.example.dto.Search;
import com.example.entity.Restaurant1;
import com.example.repository.Restaurant1Repository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping(value = "/restaurant1")
@RequiredArgsConstructor
public class Restaurant1Controller {
final Restaurant1Repository r1Repository;
final HttpSession httpSession;// 세션객체
// 127.0.0.1:9090/ROOT/restaurant1/selectlist.food?page=1&type=phone&text=
// 식당 전체목록 표시(페이지네이션, 연락처, 이름별, 종류별, 주소별 검색)
@GetMapping(value = "/selectlist.food")
public String selectlistGET(
Model model, @ModelAttribute Search obj) {
try {
log.info("Restaurant1Controller => {}", obj.toString());
// 페이지네이션
PageRequest pageRequest = PageRequest.of(obj.getPage()-1,10);
// 연락처 검색
List<Restaurant1> list = r1Repository.findByPhoneContainingOrderByNoDesc(obj.getText(), pageRequest);
long total = r1Repository.countByPhoneContaining(obj.getText());
if (obj.getType().equals("name")){
list = r1Repository.findByNameContainingOrderByNoDesc(obj.getText(), pageRequest);
total = r1Repository.countByNameContaining(obj.getText());
}
else if(obj.getType().equals("address")){
list = r1Repository.findByAddressContainingOrderByNoDesc(obj.getText(), pageRequest);
total = r1Repository.countByAddressContaining(obj.getText());
}
else if(obj.getType().equals("type")) {
list = r1Repository.findByTypeContainingOrderByNoDesc(obj.getText(), pageRequest);
total = r1Repository.countByType(obj.getText());
}
model.addAttribute("list", list);
model.addAttribute("pages", (total-1) + 1 / 10);
model.addAttribute("search", obj);
return "/restaurant1/selectlist";
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
@GetMapping(value = "/insert.food" )
public String insertGET() {
try {
return "/restaurant1/insert";
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
@PostMapping(value = "/insert.food")
public String insertPOST(
@RequestParam(name = "phone") String phone,
@RequestParam(name = "name") String name,
@RequestParam(name = "address") String address,
@RequestParam(name = "type") String type) {
try {
Restaurant1 obj = new Restaurant1();
// 식당 등록하기 기능
obj.setPhone(phone);
obj.setName(name);
obj.setAddress(address);
obj.setType(type);
r1Repository.save(obj);
return "redirect:/restaurant1/selectlist.food";
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
}
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>식당목록</h1>
<a th:href="@{/restaurant1/insert.food}"><button>매장등록</button></a>
<hr />
<form th:action="@{/restaurant1/selectlist.food}" method="get" th:object="${search}">
<input type="hidden" name="page" value="1" />
<select th:field="${search.type}">
<option th:each="tmp, idx : ${search.typeCode}" th:value="${tmp}" th:text="${search.typeName[idx.index]}">
</option>
</select>
<input type="text" th:field="${search.text}" placeholder="검색어" />
<input type="submit" value="검색">
</form>
<hr />
<table border="1">
<thead>
<tr>
<th>번호</th>
<th>연락처</th>
<th>상호명</th>
<th>주소</th>
<th>종류</th>
<th>등록일</th>
<th>버튼</th>
</tr>
</thead>
<tbody>
<tr th:each="obj: ${list}">
<td th:text="${obj.no}"></td>
<td th:text="${obj.phone}" name="phone"></td>
<td th:text="${obj.name}" name="name"></td>
<td th:text="${obj.address}" name="address"></td>
<td th:text="${obj.type}" name="type"></td>
<td th:text="${obj.regdate}"></td>
<td><a th:href="@{/menu1/insert.food(rno=${obj.no}, rphone=${obj.phone})}"><button>메뉴등록</button></a></td>
</tr>
</tbody>
</table>
<th:block th:each="num : ${#numbers.sequence( 1, pages )}">
<a th:href="@{/restaurant1/selectlist.food(page=${num}, type=${search.type}, text=${search.text})}"
th:text="${num}"></a>
</th:block>
</body>
</html>
Select
박스를 이용한 검색기능과 페이지네이션 기능도 추가하였다.
추가로 각 식당마다 메뉴를 등록하고 조회를 할 수 있도록 기능도 넣었으며, 각각의 메뉴를 수정하거나 삭제할 수 있도록 버튼을 주가 할 예정이다.
아직 DB에 메뉴 데이터가 입력이 되지 않아 이부분에 대해서는 내일 추가로 정리해보도록 하겠다.