@ResponseBody
-
[Spring] annotations 정리2019.10.16
[Spring] 프로젝트 커뮤니티,블로그 만들기(#4)-게시판 작성,수정,삭제(CRUD) 만들기
안녕하세요 무작정 일단 따라 해 보는 Spring 커뮤니티 만들기 4탄 시작합니다.
환경
Eclipse 2019-9 Jee
JDK 1.8_231
Apache Tomcat 8.5.47
MariaDB 10.4.10
MyBatis 3.2.2
+ JSTL 1.2
+ jackson 2.9.4
오늘의 할 일
1.URL 8080,프로젝트 명 제거
2.JSTL,EL 설정
3.게시판 CRUD 기능 만들기
시작하기에 앞서 지금 상태에서 Run on Server를 하시면
http://localhost:8080/springEx01/ 이렇게 8080이랑 springEx01이라는 프로젝트명이 붙는걸 보시게 되는데요
이걸 안보이게 하려면 설정을 조금 해줘야합니다.
8080 포트와 프로젝트명 URL에서 없애기
이클립스 하단 Servers 탭 클릭 -> Tomcat v8.5 Server at localhost 더블 클릭 -> Overview 탭 클릭 -> HTTP/1.1 PortNumber 8080에서 80으로 변경
그리고 저장 후 바로 Modules 탭 클릭 -> 해당 프로젝트 클릭 후 Edit… 버튼 클릭 -> Path에 프로젝트명 지우고 "/" 만 남기고 저장 "/"는 남겨야 합니다.
짜잔! URL이 깔끔해진 모습
index.jsp에 a 태그 href도 <a href="/view/dashboard">대시보드 보러가기</a> 이렇게 변경해줍니다.
현재 인덱스 페이지와 대시보드 페이지만 존재하고 있는데요.
일단 대시보드 페이지에 게시판 리스트를 보여주고 작성,수정,삭제는 다른 페이지에서 진행하겠습니다.
로그인은 다음 5장에서 다룹니다.
먼저 JSP에서 Java 코드<%= %>를 쓴다면 가독성이 매우 떨어지므로 저희는 JSTL & EL ${} 이라는걸 사용하겠습니다.
새로운 라이브러리를 추가할 땐? 정답! pom.xml
pom.xml 디펜던시<dependency> 추가
<!-- jstl dependecy -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency> 추가 후
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 이 문구를 JSTL & EL 태그를 사용 할 때
JSP 파일 최상단에 넣어주면 되는데요. Prefix="c"말고도 여러 개가 있으므로
include 전용 JSP를 만들어줍니다.
views -> jstlHeader.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
이제 JSTL,EL 태그를 사용할 JSP 페이지 <!DOCTYPE html> 위에 넣어주시면 됩니다.
<%@ include file="/WEB-INF/views/jstlHeader.jsp" %>
자 그럼 준비가 끝났으니 본격적으로 게시판 만들기 CRUD를 시작합니다.
먼저 CRUD 중 R(read)부터 만들겠습니다.
대시보드에 들어가면 제일 먼저 게시판 리스트가 보이도록 만들 예정입니다.
리스트를 보여주려면 먼저 DB에서 데이터를 Select 해와야겠죠
ViewController.java
@RequestMapping("view/dashboard")
public ModelAndView dashboard() {
List result = boardService.getBoardList();
ModelAndView mav = new ModelAndView();
mav.addObject("result",result);
return mav;
}
BoardService.java
List getBoardList();
BoardServiceImpl.java
public List<Board> getBoardList() {
return boardDAO.getBoardList(); }
BoardDAO.java
public List<Board> getBoardList() {
return sqlSession.selectList("getBoardList"); }
board-Mapper.xml
<select id="getBoardList" resultType="board">
SELECT * FROM board order BY id DESC;
</select>
원래 작성 순서는 Mapper -> DAO -> Service -> Controller 순이지만 일단 익숙지 않은 분들을 위해 Controller부터 작성하였습니다.
dashboard.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/jstlHeader.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>dashboard</title>
<style>
table {
width: 100%;
border: 1px solid #444444;
}
th, td {
border: 1px solid #444444;
}
</style>
</head>
<body>
<p>dashboard</p>
<div>게시글 리스트</div>
<table>
<thead><tr>
<td>제목</td>
<td>조회수</td>
<td>좋아요</td>
<td>첨부파일</td>
<td>글 작성 날짜</td>
</tr></thead>
<c:forEach var="b" items="${result }">
<fmt:formatDate value="${b.create_time}" pattern="yyyy-MM-dd HH:MM:ss" var="dateFormat_cr"/>
<tr>
<td>${b.subject }</td>
<td>${b.views }</td>
<td>${b.likes }</td>
<td>${b.attachments }</td>
<td>${dateFormat_cr }</td>
</tr>
</c:forEach>
</table>
<div> <a href="/view/boardwrite">글 작성하기</a></div>
</body>
</html>
UI는 아직 허접하지만 일단 게시판 리스트가 잘 출력되는 모습입니다.
이제 글 작성하기 링크를 누르면 글을 작성할 수 있게 C(Create)를 만들어봅시다.
먼저 작성을 다 한 후 jQuery ajax를 이용한 POST 방식을 사용할 겁니다.
views -> view -> boardwrite.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<meta charset="UTF-8">
<title>글 작성</title>
<script type="text/javascript">
function boardValidation(){
var subject = $("#subject").val();
var content = $("#content").val();
if(!subject){
alert("제목 입력은 필수입니다.");
$("#subject").focus();
return false;
}else if(!content){
alert("내용 입력은 필수 입니다.");
$("#content").focus();
return false;
}else {
boardWrite(subject,content);
}
}
function boardWrite(sub,con){
$.ajax({
url : "/jquery/boardwrite",
type:'POST',
data : {
subject : sub,
context : con
},
success:function(data){
if(data == 1){
alert("글 등록이 완료되었습니다.");
location.href="/view/dashboard";
}else {
alert("글 등록 실패");
}
},error:function(){
console.log("error");
}
})
}
</script>
</head>
<body>
<form>
<table>
<caption>게시판 글쓰기 </caption>
<tbody>
<tr>
<th>제목: </th>
<td><input type="text" placeholder="제목을 입력하세요. " id="subject"/></td>
</tr>
<tr>
<th>내용: </th>
<td><textarea cols="30" rows="10" placeholder="내용을 입력하세요. " id="content"></textarea></td>
</tr>
<!-- <tr>
<th>첨부파일: </th>
<td><input type="text" placeholder="파일을 선택하세요. " name="filename"/></td>
</tr> -->
<tr>
<td colspan="2">
<input type="button" value="등록" onclick="boardValidation()"/>
<input type="button" value="뒤로" onclick="javascript:location.href='dashboard'"/>
</td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
jQuery 플러그인이 필요하겠죠 저희는 *CDN 방식으로 받겠습니다.
boardwrite.jsp <head></head>안에 넣어줍니다.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
*CDN :콘텐츠 전송 네트워크(Content delivery network)는 콘텐츠를 효율적으로 전달하기 위해 여러 노드를 가진 네트워크에 데이터를 저장하여 제공하는 시스템을 말한다. 인터넷 서비스 제공자에 직접 연결되어 데이터를 전송하므로, 콘텐츠 병목을 피할 수 있는 장점이 있다
하지만 Spring 입장에선 boardwrite.jsp를 못 찾겠죠?
무조건 jsp를 view로 등록할 땐 Controller에서 받아줘야 합니다.
ViewController.java
@RequestMapping(value="view/boardwrite",method = RequestMethod.GET)
public ModelAndView boardwrite() {
ModelAndView mav = new ModelAndView();
return mav; }
그리고 위에 boardWrite() 메서드를 보시면 URL를 /jquery/boardwrite로 보내고 있죠
저희는 Controller의 용도를 나눠서 가독성이 좋도록 할 겁니다.
ViewController.java : View를 보여주는(연결해주는) Controller
JqueryController.java : jquery + ajax를 이용한 메서드들
자 그럼 JqueryController.java를 만들어야겠죠
src/main/java -> controller -> JqueryController.java 생성
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.company01.springEx01.logic.Board;
import com.company01.springEx01.service.BoardService;
@Controller
@RequestMapping("jquery/*")
public class JqueryController {
@Autowired
BoardService boardService;
@RequestMapping(value="jquery/boardwrite",method = RequestMethod.POST)
@ResponseBody
public int boardwrite(Board board) {
int result = 0;
result = boardService.boardwrite(board);
return result;
}
}
@ResponseBody : json으로 응답해주는 어노테이션
여기서 보면 boardwrite 메서드의 리턴 타입이 int라고 돼있는데
어라? 저는 int로 리턴하면 String or Object로 리턴하라고 에러가 나던데요? 네 맞습니다.
원래 스프링은 Model 객체를 리턴해 "view"를 보여주려고 하는 성질이 존재하는데,
갑자기 int를 리턴해버리면 처음부터 형태가 맞지 않다며 예외를 뱉습니다.
그럼 아예 값을 리턴해주는 JSON 형태로 던져주면 어떨까요? 네 바로 그 작업을 하는 것입니다.
pom.xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.4</version>
</dependency>
BoardService.java
int boardwrite(Board board);
BoardServiceImpl.java
@Override
public int boardwrite(Board board) {
return boardDAO.boardwrite(board);}
BoardDAO.java
public int boardwrite(Board board) {
return sqlSession.insert("boardwrite",board);
}
board-Mapper.xml
<insert id="boardwrite">
insert into board (id,subject,context,attachments,likes,views,create_time,update_time)
values(#{id},#{subject},#{context},#{attachments},#{likes},#{views},now(),null);
</insert>
만들었으니 한번 해볼까요?
대시보드에 있는 글 작성하기 버튼(링크)을 클릭합니다.
글 작성 UI
일단 첨부파일은 로직이 조금 필요하므로 나중에 하고 제목, 내용만 입력하도록 하였습니다.
글 작성 후 등록
대시보드
짠! 잘 들어왔죠 이제 저 글 제목을 클릭하면 내용을 볼 수 있고, 조회수가 1씩 증가하도록 해보겠습니다.
dashboard.jsp
제목 부분에 a 태그 링크 추가
<td><a href="/view/boardDetail?id=${b.id }">${b.subject }</a></td>
/view/boardDetail 페이지가 없죠? 새로운 페이지 추가 Controller는 뭐였죠??
네 맞습니다!!
ViewController.java
@RequestMapping(value="view/boardDetail",method = RequestMethod.GET)
public ModelAndView boardDetail(int id) {
boardService.viewsUpdate(id);
Board result = boardService.getBoardDetail(id);
ModelAndView mav = new ModelAndView();
mav.addObject("result",result);
return mav;
}
매개변수 int id : get으로 넘어오는 "id" 매개변수를 받는다.
viewUpdate : 조회수 추가 메서드
getBoardDetail : 특정 글 하나의 데이터를 조회하는 메서드
views -> view -> boardDetail.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/jstlHeader.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 내용</title>
<style>
table {
width: 100%;
border: 1px solid #444444;
}
th, td {
border: 1px solid #444444;
}
</style>
<script type="text/javascript">
function boardDelete(){
}
function boardUpdate(){
}
</script>
</head>
<body>
<form>
<table>
<caption>게시판 글 내용 </caption>
<tbody>
<tr>
<th>제목: </th>
<td>${result.subject}</td>
</tr>
<tr>
<th>내용: </th>
<td>${result.context}</td>
</tr>
<tr>
<th>조회수: </th>
<td>${result.views}</td>
</tr>
<tr>
<th>좋아요: </th>
<td>${result.likes}</td>
</tr>
<tr>
<td colspan="2">
<input type="button" value="수정" onclick="boardDelete()"/>
<input type="button" value="삭제" onclick="boardUpdate()"/>
<input type="button" value="목록보기" onclick="javascript:location.href='dashboard'"/>
</td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
BoardService.java
Board getBoardDetail(int id);
void viewsUpdate(int id);
BoardServiceImpl.java
@Override
public Board getBoardDetail(int id) {
return boardDAO.getBoardDetail(id);}
@Override
public void viewsUpdate(int id) {
boardDAO.viewUpdate(id);}
BoardDAO.java
public Board getBoardDetail(int id) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("id",id);
return sqlSession.selectOne("getBoardDetail",map);
}
public void viewUpdate(int id) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("id",id);
sqlSession.update("viewUpdate", map);
}
board-Mapper.xml
<select id="getBoardDetail" resultType="board">
SELECT * FROM board where id = #{id};
</select>
<!-- update -->
<update id="viewUpdate">
UPDATE board SET views = views+1 WHERE id = #{id}
</update>
대시보드
제목에 클릭할 수 있는 링크가 생겼습니다.
글 내용(boardDetail)
내용 페이지에서 새로고침을 하게 되면 조회수가 1씩 증가하는 걸 볼 수 있습니다.
삭제와 수정은 아무나 하면 안 되기 때문에 다음 글인 로그인 구현하기를 하고 진행하도록 하겠습니다.
귀찮아서 그런 거 아닙니다.
그럼 다음은 회원가입 그리고 로그인 후 세션 저장까지 해보겠습니다.
최종 Project Explorer
'Spring > 커뮤니티(블로그) 프로젝트' 카테고리의 다른 글
[Spring] 프로젝트 커뮤니티,블로그 만들기(#5)-회원가입,로그인,로그아웃 구현하기 (5) | 2019.12.08 |
---|---|
[Spring] 프로젝트 커뮤니티,블로그 만들기(#3)-DB 연결+MyBatis 설정하기 (1) | 2019.11.24 |
[Spring] 프로젝트 커뮤니티,블로그 만들기(#2)-package 생성 및 설정 (Feat.Controller,Service,DAO) (4) | 2019.11.17 |
[Spring] 프로젝트 커뮤니티,블로그 만들기(#1)-프로젝트 생성 및 톰캣 설정,인코딩 설정 (0) | 2019.11.17 |
[Spring] annotations 정리
Annotation(어노테이션 || 애너테이션 || 애노테이션)이란?
아하영어사전 - 애너테이션
http://aha-dic.com/View.asp?word=Annotation
대중적인 발음 - 어노테이션
여기선 어노테이션이라 칭하겠음
1.본래 주석이란 뜻으로 사용됨
2.인터페이스를 기반으로 한 문법
3.클래스에 특별한 의미 부여 || 기능 주입 가능
종류
1.built-in annotation
예) Override
2.Meta annotation
예) @Target
3.Custom annotation
예)public @interface AnnotationName{}
쨋든 이 글에서 다루어볼것은 Spring 프레임워크에 들어있는 자주쓰이는 기본 어노테이션들을 다루어 보겠습니다.
[@Controller]
해당 클래스가 Controller임을 나타내기 위한 어노테이션
[@RequestParam]
Controller 메소드의 파라미터와 웹요청 파라미터와 맵핑하기 위한
어노테이션
[@ModelAttribute]
Controller 메소드의 파라미터나 리턴값을 Model 객체와 바인딩하기 위한 어노테이션
[@SessionAttributes]
Model 객체를 세션에 저장하고 사용하기 위한 어노테이션
[@RequestPart]
Multipart 요청의 경우, 웹요청 파라미터와 맵핑 가능한 어노테이션
[@CommandMap]
Controller메소드의 파라미터를 Map형태로 받을 때 웹요청 파라미터와 맵핑하기 위한 어노테이션(egov 3.0부터 추가)
[@ControllerAdvice]
Controller를 보조하는 어노테이션으로 Controller에서 쓰이는 공통기능들을 모듈화하여 전역으로 쓰기 위한 어노테이션(egov 3.0, Spring 3.2.X부터 추가)
[@RequestMapping] ★★★★★
이름 |
타입 |
설명 |
value |
String[] |
URL 값으로 매핑 조건을 부여 (default) |
method |
RequetMethod[] |
HTTP Request 메소드 값을 매핑 조건으로 부여 사용 가능한 메소드는 GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE (7개) |
params |
String[] |
HTTP Request 파라미터를 매핑 조건으로 부여 |
consumes |
String[] |
설정과 Content-Type request 헤더가 일치할 경우에만 URL이 호출됨 |
produces |
String[] |
설정과 Accept request 헤더가 일치할 경우에만 URL이 호출됨 |
[@ResponseBody] ★★★★★
이 어노테이션이 붙으면 View Page를 리턴하는게 아니고 '데이터'를 리턴합니다.
즉, return type이 String이며 "home"이라는 문자열을 되돌려준다고 가정해볼께요.
@ResponseBody 어노테이션을 안붙이면 "home.jsp" 페이지를 보여주지만
어노테이션을 붙이게되면 "home"이라는 문자열 자체를 보여주게됩니다.
[@RequestBody] ★★★★★
보통 AJAX + JSON을 사용할때 사용하는 어노테이션
요청받은 데이터의 Body(내용)의 전체내용을 파라메터로 받습니다.
View페이지의 AJAX요청의 contentType이 "application/json"이면 @RequestBody 어노테이션을 통해서만
웹서버에서 내용을 받을 수 있어요.
※주의 ResponseBody,RequestBody 문법 헷갈림
[@RestController]
- 스프링 4 부터 @RestController 애노테이션의 경우 기존의 특정한 JSP와 같은 뷰를 만들어 내는 것이 아닌REST방
식의 데이터 자체를 서비스하는 것을 말한다.
- 스프링 3에는 해당 메소드의 리턴 타입에 @ResponseBody 애노테이션을 추가하는 형태로 작성되었다.
- 기능은 달라진것이 없지만, 컨트롤러 자체의 용도를 지정한다는 점에서 변화가 있다고 할 수 있다.
- URI가 원하는 리소스를 의미한다.(복수형으로 작성)
- URI에는 식별할 수 있는 데이터를 같이 전달하는 것이 일반적이다.
// 컨트롤러 위에 어노테이션을 붙혀서 사용한다.
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/sample")
public class RestControllerExampleController {
}
만약 import시 오류가 발생하면 maven의 webmvc 버전을 확인하라.
@RestController는 JSP와 같은 뷰를 만들어 내지 않는 대신에 데이터 자체를 반환하는데, 이때 주로 사용되는 것은 단순 문자열과 JSON, XML, 등으로 나누어 볼 수 있다.
이상 글을 마칩니다. 이 글은 계속해서 공부하고 싶은 어노테이션들이 추가될 예정입니다.
'Spring' 카테고리의 다른 글
[Spring] GET 파라미터(parameter) 데이터 받기 총 정리 (0) | 2019.12.15 |
---|---|
[Spring] MyBatis 데이터 HashMap으로 받기 (0) | 2019.10.31 |
[Spring] @Scheduled (0) | 2019.10.30 |
[Spring] DTO(Data Transfer Object)와 VO(Value Object) (1) | 2019.10.29 |
[Spring] GET과 POST의 차이점과 문법 정리 (0) | 2019.10.21 |