select * from travel;
-- 기존 컬럼 no에 pk, auto_increment 배정
alter table travel
modify no int auto_increment primary key;
제대로 변경됨
테이블 준비 끝
**여행 페이지 만들기 시작 순서**
0) DB에서 테이블 정의
1) VO 객체 정의 (테이블에 대응하는) => TravelVO 2) Mapper 인터페이스 정의 3) Mapper xml 정의 -> 테스트 4)Service 인터페이스 정의 + 구현 -> 구현한 걸로 테스트 5) Controller 정의 6) jsp (화면 정의)
VO 객체 정의 ➡️ Mapper 인터페이스 정의 ▶ Mapper xml 정의 ▶ 테스트 ➡️Service 인터페이스 정의 + 구현 ➡️구현한 걸로 테스트 ➡️Controller 정의 ➡️jsp (화면 정의)
[domain] 패키지에 TravelVO 클래스 만들기
@Data 주고 만들기
DDL 에서 봤던 순서대로 정의하기
package org.galapagos.domain;
import lombok.Data;
@Data
public class TravelVO {
private Long no;
private String region;
private String title;
private String description;
private String address;
private String phone;
}
VO 객체 정의 ➡️ Mapper 인터페이스 정의 ▶ Mapper xml 정의 ▶ 테스트 ➡️Service 인터페이스 정의 + 구현 ➡️구현한 걸로 테스트 ➡️Controller 정의 ➡️jsp (화면 정의)
[Mapper] 패키지에서 인터페이스 추가
TravelMapper
*<TravelVO> : TimeMapper🐲
package org.galapagos.mapper;
import java.util.List;
import org.galapagos.domain.Criteria;
import org.galapagos.domain.TravelVO;
public interface TravelMapper {
public int getTotalCount(Criteria cri); // 갖다쓸 수 있음. int로 바꿔주기
// 페이지 목록 추출 (bno 수정필요)
public List<TravelVO> getList(Criteria cri);
// pk 추출 포함
public void insert(TravelVO travel); // insertselectkey 만들 필요 x 한 벌로 운영
public TravelVO read(Long no);
public int delete(Long no);
public int update(TravelVO travel);
}
VO 객체 정의 ➡️ Mapper 인터페이스 정의 ▶ Mapper xml 정의 ▶ 테스트 ➡️Service 인터페이스 정의 + 구현 ➡️구현한 걸로 테스트 ➡️Controller 정의 ➡️jsp (화면 정의)
❗Mapper xml을 만들 때 주의점 Mapper 인터페이스와 같은 패키지 경로에 맞춰서 해야 한다.
❗작업 전에 mybatis-config.xml에서 같은 패키지에 TravelVO가 속해있는지 확인해야 한다.🐲
TravelMapper.xml 로 복사해오는 요소들
<?xml version="1.0" encoding="UTF-8"?>
<!-- 이 xml은 mapper 정의이다. -->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 나랑 짝이 되는 인터페이스가 누구냐 -->
<mapper namespace="org.galapagos.mapper.TravelMapper">
</mapper>
검색 기능 > 검색 조건 조정
검색조건 가져와서 수정하기
BoardMapper.xml => TravelMapper.xml 로 복사하기(앞으로 계속 나올 일) title(T), description(D), region(R) 을 검색필터로 할 것임
조정할 부분이 사이에 넣어서 고쳐줄 것이다.
<sql id="criteria">
<trim prefixOverrides="OR">
<foreach item="type" collection="typeArr">
<trim prefix="OR">
<choose>
<when test="type == 'T'.toString()">
title like CONCAT('%', #{keyword}, '%')
</when>
<when test="type == 'D'.toString()">
description like CONCAT('%', #{keyword}, '%')
</when>
<when test="type == 'R'.toString()">
region like CONCAT('%', #{keyword}, '%')
</when>
</choose>
</trim>
</foreach>
</trim>
</sql>
<sql> 태그 밑에 총 건수 보여주는 <select> 태그 추가
<select id="getTotalCount" resultType="int">
select count(*) from travel //tbl_ 빼야함
</select>
VO 객체 정의 ➡️ Mapper 인터페이스 정의 ▶ Mapper xml 정의 ▶ 테스트 ➡️Service 인터페이스 정의 + 구현 ➡️구현한 걸로 테스트 ➡️Controller 정의 ➡️jsp (화면 정의)
TravelMapperTest (JUnit Test Case) 만들기
메서드 전체 체크
가져올 어노테이션 추가하고 @Autowired
좌 TravelMapperTest / 우 BoardMapperTest
Criteria 추가
getTotalCount 총 검색 건수
*현재 검색어 따로 없는 상황
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import lombok.extern.log4j.Log4j;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { RootConfig.class })
@Log4j
public class TravelMapperTest {
@Autowired
private TravelMapper mapper;
@Test
public void testGetTotalCount() {
Criteria cri = new Criteria(); //검색어 없는 상황
}
}
테스트 실행하면 잘 된다. xml 에도 criteria 추가
@Test
public void testGetTotalCount() {
Criteria cri = new Criteria(); //검색어 없는 상황
int total = mapper.getTotalCount(cri);
log.info("total: " + total);
cri.setType("RTD");
cri.setKeyword("해수욕장");
total = mapper.getTotalCount(cri);
log.info("total: " + total);
}
testgetList() 첫 페이지 10개를 리턴하는 테스트
<select id="getList" resultType="TravelVO">
select * from travel
<where>
<include refid="criteria"></include>
</where>
order by region, title
limit #{offset} , #{amount}
</select>
@Test
public void testGetList() {
Criteria cri = new Criteria();
List<TravelVO> list = mapper.getList(cri); //리턴:첫페이지 10개
}
TravelMapper.xml read 가져오기... 이후 계속 반복 * 첫 번째 박스 : xml, 두 번째 박스 : TravelMapperTest 코드
read
<select id="read" resultType="TravelVO">
select * from travel
where no = #{no}
</select>
@Test
public void testRead() {
TravelVO travel = mapper.read(10L); //long 타입 L
log.info(travel);
}
@Test
public void testInsert() { //insert이므로 no는 지정할 필요 없음
TravelVO travel = new TravelVO();
travel.setRegion("수도권");
travel.setTitle("강남 에코파크");
travel.setDescription("강남에 위치한 에너지 파크");
travel.setAddress("서울시 강남구");
travel.setPhone("1111-2222-3333");
mapper.insert(travel);
log.info(travel);
}
INFO : org.galapagos.mapper.TravelMapperTest - TravelVO(no=113, region=수도권, title=강남 에코파크, description=강남에 위치한 에너지 파크, address=서울시 강남구, phone=1111-2222-3333)
update
권역빼고 title, description, address, phone 부분 바꾸기
<update id="update">
update travel set
title = #{title},
description = #{description},
address = #{address},
phone = #{phone}
where no = #{no}
<!-- update_date = now() -->
</update>
no=113 이었던 거 기억하고 수정해야 한다!
@Test
public void testUpdate() {
TravelVO travel = mapper.read(113L);
travel.setTitle("강남 에너지 파크");
travel.setDescription("강남의 떠오르는 명소");
travel.setAddress("서울시 강남구 1");
travel.setPhone("010-1234-5678");
mapper.update(travel);
}
전후
delete
<delete id="delete">
DELETE FROM travel where no = #{no}
</delete>
@Test
public void testDelete() {
mapper.delete(113L); //강남 어쩌구 지우기
}
사라짐
VO 객체 정의 ➡️ Mapper 인터페이스 정의 ▶ Mapper xml 정의 ▶ 테스트 ➡️Service 인터페이스 정의 + 구현 ➡️구현한 걸로 테스트 ➡️Controller 정의 ➡️jsp (화면 정의)
[service 패키지]
인터페이스 TravelService 만들기
package org.galapagos.service;
import java.util.List;
import org.galapagos.domain.Criteria;
import org.galapagos.domain.TravelVO;
public interface TravelService {
// CRUD 기본골격, 리턴타입 true, false
public int getTotal(Criteria cri);
public List<TravelVO> getList(Criteria cri);
public TravelVO get(Long no);
public void register(TravelVO travel);
public boolean modify(TravelVO travel);
public boolean remove(Long no);
}
TravelServiceImpl 만들어서 implement로 TravleService 사용하기
@Service 추가 꼭 하기 (애매하면 @Component)
package org.galapagos.service;
import java.util.List;
import org.galapagos.domain.Criteria;
import org.galapagos.domain.TravelVO;
import org.galapagos.mapper.TravelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;
@Log4j
@Service // bean 등록
//@AllArgsConstructor // auto wired 대신 생성자 매개변수로 주입해서 쓸 수 있는 방법 -> 가독성 상승
public class TravelServiceImpl implements TravelService {
@Autowired
private TravelMapper mapper;
@Override
public int getTotal(Criteria cri) {
return mapper.getTotalCount(cri);
}
@Override
public List<TravelVO> getList(Criteria cri) {
return mapper.getList(cri);
}
@Override
public TravelVO get(Long no) {
//조회수 처리
return mapper.read(no);
}
@Override
public void register(TravelVO travel) {
mapper.insert(travel);
//첨부파일 업로드
}
@Override
public boolean modify(TravelVO travel) {
//영향받은 행의 개수 리턴, 1이면 성공한 것
return mapper.update(travel) == 1;
}
@Override
public boolean remove(Long no) {
return mapper.delete(no) == 1;
}
}
@GetMapping({ "/get", "/modify" })
public void get(
@RequestParam("no") Long no,
@ModelAttribute("cri") Criteria cri,
Model model) {
model.addAttribute("travel", service.get(no));
}
4. 이제 내 어플리케이션에서 뜨면 클릭 5. 삼단바 눌러서 [플랫폼] - [Web플랫폼 등록] 서버주소랑 포트번호, 본인 실제 ip 주소 3가지 등록 후 저장 *실제 프로젝트 시, 클라우드 서버 주소를 ip주소 위치에 넣어줘야 한다. ip: 172.30.1.39 6. [요약정보] - JavaScript키를 복사해 두자. ⭐⭐⭐ Kakao 지도 API https://apis.map.kakao.com/
스크립트 작업 get.jsp 젤 하단 부분에서 작업
<script src="//dapi.kakao.com/v2/maps/sdk.js?appkey=<APP KEY>">
</script>
<script>
let mapContainer = document.getElementById('map');
// 지도 제어 코딩
</script>
여기서 APP KEY 부분에 아까 발급받은 JavaScript 키를 넣어야 한다. 꺽쇠 <> 없애줘야한다❗
javascript 키 삽입
순수 자바스크립트로 DOM 처리할 것이다.
let mapContainer = document.getElementById('map');
만들어둔 id가 map인 해당 div 태그에 대한 참조를 달라는 뜻
앞에 type이랑 app key 뒤에 &libraries=services(=>Geocoder인식용) 추가해서 최종 코드 type은 굳이 안 넣어도 동작하는 것 같다.
Map 생성자, 첫 번째 인자:getElementByID / 두 번째 인자 : 지도를 어떻게 만들지 옵션 속성명 : center(중심좌표), level(확대레벨) *LatLng : 위도, 경도를 나타내는 객체
지도 객체 Map (오타 *LanLng이다.)LatLng 객체
travel에 있던 곳 하나 주소 구글맵에 검색해서 [여기를 출발지로 설정]주소창에 나오는 위도, 경도
위에서 잡았던 위도와 경도를 코드 안에 함께 넣어서 옵션 지정
<script>
// 지도 제어 코딩
let mapContainer = document.getElementById('map');
let mapOption = {
center: new kakao.maps.LatLng(37.8103437,128.8815612), // 중심좌표
level: 3 // 지도의 확대 레벨
};
let map = new kakao.maps.Map(mapContainer, mapOption);
</script>
마커 넣기📍
Marker 클래스 사용법
<script> 태그 안에 중심좌표랑 같이 넣어주기. (아까 위도, 경도 똑같이) ⭐원래는 DB에 해당 중심좌표 위치를 같이 넣어주는 게 좋다.
// 마커가 표시될 위치
var markerPosition = new kakao.maps.LatLng(37.8103437, 128.8815612);
// 마커 생성
var marker = new kakao.maps.Marker({
position: markerPosition
});
// 마커가 지도 위에 표시되도록 설정
marker.setMap(map);
보통 전처리를 통해서 DB에 중심좌표를 넣어두지만 우리는 안 그랬으니 GeoCode를 사용해 보자
디폴트 생성자로 생성을 시켜서 addressSearch(주소문자열, 콜백함수) 메서드를 쓰는 것 콜백함수 매개변수 : result, status(찾기 성공 여부 - 처리결과상 성공하면 result에 위도, 경도 객체가 리턴) ⭐result는 배열에 담겨서 리턴되기 때문에 배열처리가 필요하다!!(한 개의 주소가 여러 군데에 있을 수 있다.)
지도 <script> 안에서 앞부분에 넣기 ❤️${travel.address} : 주소로 직접 쳐야할 부분을 대신한 el
<script>
//Geocode
let geocoder = new kakao.maps.services.Geocoder();
let address ='${travel.address}'; //주소 직접 치지말고 el로 가져오기
❗주의사항 자바스크립트의 모든 함수는 비동기 함수이다. 동기:함수실행이 끝날 때까지 기다려줌 비동기는 기다려주지 않아 ! => 콜백 함수가 항상 등록된다. addressSearch 하고 바로 리턴된다는 뜻
첫 번째 좌표로 위도, 경도를 만들고 그 마커를 맵의 중심에 위치시킬 것.
//Geocode
let geocoder = new kakao.maps.services.Geocoder();
let address ='${travel.address}'; //주소 직접 치지말고 el로 가져오기
//콜백함수 매개변수:result, status
geocoder.addressSearch(address, function(result, status) {
if (status === kakao.maps.services.Status.OK) {
// 배열의 첫번째 위치로 이동
var coords = new kakao.maps.LatLng(result[0].y, result[0].x);
var marker = new kakao.maps.Marker({
map: map,
position: coords //*coords : 이미지 맵에서 영역의 좌표를 지정하는 속성
});
// 지도의 중심을 결과값으로 받은 위치로 이동시킵니다
map.setCenter(coords);
}
});
🧙 중복코드 및 하드코딩 고치기
1. 마커 중복코드 주석처리
2. 중심좌표 이동 중복코드 지우고 하드코딩 부분 coords 로 바꾸기
위에서 let으로 coords가 설정됨
3. else 처리
Status가 OK가 아닌 경우도 있을 수 있으므로 해야 한다. (잘못된 주소, 서버 이상 등)