RequestMapping으로 url이 http://localhost:8282/myweb/ 이면 index.jsp 연결
NoticeController
package com.coding404.myweb.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/trip")
public class NoticeController {
@Autowired
@Qualifier("tripService")
private TripService tripService;
//화면 구현 - 컨트롤러 연결
@RequestMapping("/notice_list")
public String notice_list() {
return "trip/notice_list";
}
//상세화면
@RequestMapping("/notice_view")
public String notice_view() {
return "trip/notice_view";
}
//글 작성
@RequestMapping("/notice_write")
public String notice_write() {
return "trip/notice_write";
}
//수정화면
@RequestMapping("/notice_modify")
public String notice_modify() {
return "trip/notice_modify";
}
}
service와 같은 이름으로 멤버변수 생성 후 @Autowired(의존성 주입), @Qualifier (사용할 의존 객체를 선택) 넣기 controller Qualifier - serviceImpl Service 와 연결 (이름 같게 정의)
NoticeController 생성 후 기본 화면 구현
@Controller 달아주고, @RequestMapping("/trip") 설정 - trip 폴더에 있는 파일들 (list, view, write, modify)
UserController
package com.coding404.myweb.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
//이 페이지는 템플릿을 적용하지 않고 사용하려면 타일즈 설정에 직접 추가
@RequestMapping("/login")
public String login() {
return "user/login";
}
@RequestMapping("/join")
public String join() {
return "user/join";
}
}
UserController 생성 후 기본 화면 구현
MyBatis Mapper 파일 위치 분리 기본 생성
root-context.xml
위에서 TripMapper.xml 을 같은 패키지에 담지 않고 분리했기 때문에 그에 맞게 파일 위치 변경
setter 주입으로 name="mapperLocations", value="classpath:/위치맞게 변경" mapperLocations: 설정 속성 classpath: 패키지 계층구조의 '최상위 경로', src/main/resources 파일 아래의 파일의 경로를 참조하는 방법
TripMapper 인터페이스
package com.coding404.myweb.trip.service;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface TripMapper {
}
post 방식으로 action = registForm으로 넘겨서 내용들을 처리 ▶ NoticeController로 넘김
화면에서 적지 않고 넘기면 공백으로 들어가니까 not null 이어도 의미없어짐 - 처리해줘야함
notice_write.jsp required="required" 넣어주기 - 여기서는 tripdate, writer, title
NoticeController.jsp 넘어온 내용 처리
[ post 방식 ] 등록, 수정, 삭제
컨트롤러에서 registForm만들기 - 등록하고 리다이렉트로 목록화면으로 넘김
TripService 인터페이스에서 public int noticeRegist(TripVO vo); insert니까 리턴값은 없고, 0, 1로 성공 실패 확인 매개변수로 TripVO을 넣음
TripServiceImpl에서는 Mapper인터페이스를 부름
그대로 Mapper인터페이스 넣고, Mapper.xml에 insert 쿼리문 넣기
//글 등록
@RequestMapping(value="/registForm", method=RequestMethod.POST)
public String registForm(TripVO vo, RedirectAttributes ra) {
System.out.println(vo.toString());
int result = tripService.noticeRegist(vo);
String msg = result == 1 ? "문의사항이 정상 등록되었습니다" : "문의 등록에 실패했습니다";
ra.addFlashAttribute("msg", msg);
return "redirect:/trip/notice_list"; //데이터 받으면 목록화면으로 그냥 넘기기
}
list할 때 format(형식변환) / parse(형변환) - 보통 비즈니스 로직은 서비스 계층에서 이뤄짐
cri 제외하고 보기
TripVO 객체를 ArrayList에 담아서 list라는 이름으로 가져옴
화면에서는 list를 board라는 이름으로 맵핑 후, 필요한 데이터만 사용하여 반복문으로 처리
게시글 확인
선택한 게시글 확인
a링크 클릭 → 컨트롤러로 notice_view 연결
특정 글만 보여야 하기 때문에 @RequestParam으로 tno를 가지고 TripVO 객체 가져오기
<select id="getContent" resultType="TripVO">
select * from trip where tno=#{tno}
</select>
하나의 컨텐츠에 대한 select 만들기
TripVO를 model에 담아서 뿌림
이전글, 다음글
컨트롤러에서 tno를 가지고, 이전글, 다음글을 나타내는 list를 가져옴 (list 길이 최소 1개, 최대 2개)
<!-- 이전글, 다음글 -->
<!-- xml or html에서 부등호는 태그로 인식이 되는데, ADATA는 순수한 문자열의 형태로 인식 시킴 -->
<select id="getPrevNext" resultType="TripVO" parameterType="int">
<![CDATA[
select * from trip
where tno in ( (select tno from trip where tno < #{tno} order by tno desc limit 1),
(select tno from trip where tno > #{tno} limit 1) )
order by tno desc
]]>
</select>
현재 글의 바로 이전 글의 tno를 가져옴: 현재 글보다 작은 tno 값을 가진 이전 글 중에서 가장 큰 값
현재 글의 바로 다음 글의 tno를 가져옴: 현재 글보다 큰 tno 값을 가진 다음글 중에서 가장 작은 값
서브 쿼리 결과를 합쳐서 처리하고, tno 기준으로 내림차순 정렬하면 이전글 - 다음글이 정렬된 상태로 조회
<![CDATA[ 쿼리 ]]> : 순수한 문자열의 형태로 인식, '<'를 태그로 인식X
select * from # where = 스칼라(연산자, 하나의 행과 컬럼), 서브쿼리(EXISTS, IN, ALL, ANY, SOME 여러 행과 컬럼)
select * from trip where tno in (서브쿼리, 서브쿼리) 예시로 (1, 3)
<ul class="near_list mt20">
<!-- ${list } 잘 넘어오는지 확인 -->
<!--
리스트 길이 확인
1. 글이 2개인 경우 - 이전글 < 현재글인 경우 이전글
2. 글이 1개인 경우 - 리스트 길이가 1이고, 글 < 현재글인 경우 다음글이 없음
3. 글이 0개인 경우 - list길이가 없으면 돌지도 않을거임, 따로 안해도 됨
-->
<c:forEach var="data" items="${list }"> <!-- list길이가 없으면 돌지도 않을거임, data에는 이전글 다음글이 들어있음 -->
<c:if test="${fn:length(list) == 1 and data.tno < vo.tno}">
<li><h4 class="prev">다음글</h4>은 없습니다</li>
</c:if>
<c:if test="${data.tno > vo.tno}">
<li><h4 class="prev">다음글</h4><a href="notice_view?tno=${data.tno }">${data.title }</a></li>
</c:if>
<c:if test="${data.tno < vo.tno }">
<li><h4 class="next">이전글</h4><a href="notice_view?tno=${data.tno }">${data.title }</a></li>
</c:if>
<c:if test="${fn:length(list) == 1 and data.tno > vo.tno}">
<li><h4 class="next">이전글</h4>은 없습니다</li>
</c:if>
</c:forEach>
<!--
<li><h4 class="prev">다음글</h4><a href="javascript:;">추석 연휴 티켓/투어 배송 및 직접 수령 안내</a></li>
<li><h4 class="next">이전글</h4><a href="javascript:;">이번 여름 휴가 제주 갈까? 미션 투어 (여행경비 50만원 지원)</a></li>
-->
</ul>
${data.tno < vo.tno}: 현재의 글(vo.tno)보다 data.tno가 작으므로 이전글
${data.tno > vo.tno}: 현재의 글(vo.tno)보다 data.tno가 크므로 다음글
<form action="deleteForm" method="post" name="deleteForm">
<input type="hidden" name="tno" value="${vo.tno}"/>
...
<p class="btn_line txt_right">
<!-- 수정 버튼 -->
<a href="javascript:;" class="btn_bbs" onclick="submitForm('notice_modify', 'POST')">글수정</a>
<!-- 삭제 버튼 -->
<a href="javascript:;" class="btn_bbs" onclick="submitForm('deleteForm', 'POST')">글삭제</a>
<a href="notice_list" class="btn_bbs">목록</a>
</p>
</form>
<!-- JavaScript 함수 추가 -->
<script>
// JavaScript로 폼을 전송하는 함수
function submitForm(action, method) {
// 새로운 폼 엘리먼트 생성
var form = document.createElement('form');
form.action = action;
form.method = method;
form.style.display = 'none'; // 폼이 화면에 보이지 않도록 함
// 히든 필드 추가
var tnoField = document.createElement('input');
tnoField.type = 'hidden';
tnoField.name = 'tno';
tnoField.value = '${vo.tno}';
// 폼에 필드 추가
form.appendChild(tnoField);
// document.body에 폼 추가
document.body.appendChild(form);
// 폼 전송
form.submit();
// 사용이 끝난 폼 제거
document.body.removeChild(form);
}
</script>
수정화면 클릭시 ?tno={vo.tno}로 단순히 화면 이동 (수정도 post 방식 써야함)
placeholder는 힌트, 값X, 값은 value에
controller에서 처리하고 modify에서 뿌리기
notice_modify.jsp 수정버튼 누를 때 tno같이 넘어가게 해주기, hidden 이용 → 화면 x, 데이터 보내기
수정이나 삭제는 postO, getX(수정은 수정파일로 들어가니까 get해도 무난하지만 post써라, 삭제는 누르면 어디로 가는게 아니라 바로 실행이니까 무조건 post 써야 함)
///////////////////////////////////////참고////////////////////////////////////////
//수정, 상세 화면이 완전 동일하다면
//void형은 들어오는 경로가 나가는 경로라서 modify경로로 들어오면 modify로, view로 들어오면 view로 나감
@RequestMapping({"notice_modify", "notice_view"})
public void notice_view(@RequestParam("tno") int tno,
Model model) {
TripVO vo = tripService.getContent(tno);
model.addAttribute("vo",vo);
}
수정, 상세 화면이 같을 때 참고 → 버튼 누르면 바로 가는게 아니라 확인하고 submit 보냄