
✔️ 루트 URL 사용하기
- 생성한 url을 접속 시, 기존 루트 url로 뜨도록 설정
- MainController
>> localhost:8080으로 접속하면 localhost:8080/question/list로 주소가 바뀜(맵핑)
package com.mysite.sbb;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MainController {
@GetMapping("/sbb") // 경로매핑
@ResponseBody //응답은이거다!
public String index() {
return "hello~~ 안녕하세용 ";
}
@GetMapping("/") //root로 들어오면 question/list page로 바로 전환
public String root() {
return "redirect:/question/list";
}
}
✔️ 서비스 활용하기
- repository를 통해 가져오는게 맞지만, 한곳에 기능을 모아두고 그걸 이용해서 사용하자
repo - db연결
|
( 중간 ) 생성한 기능을 가져오라는 구조를 한개 만들자 -> 서비스 만들기
|
controller - 화면처리
- class >> QuestionService.java 생성
package com.mysite.sbb.question;
import java.util.List;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Service
public class QuestionService {
private final QuestionRepository questionRepository;
public List<Question> getList() {
return this.questionRepository.findAll();
}
}
- QuestionController.java 수정
package com.mysite.sbb.question;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
//import org.springframework.web.bind.annotation.ResponseBody; @ResponseBody를 삭제했으니 필요없다~
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Controller
public class QuestionController {
private final QuestionRepository questionRepository;
private final QuestionService questionService;
@GetMapping("/question/list")
// @ResponseBody 필요없으니 삭제
public String list(Model model) {
// List<Question> questionList = this.questionRepository.findAll();
List<Question> questionList = this.questionService.getList();
model.addAttribute("questionList", questionList);
return "question_list"; // html file 명 "" 안에 작성하면 됨
}
}
❓ 서비스가 필요한 이유
Controller - Repository 사이에 비즈니스 로직(=시스템이 해야할 일)을 하는 계층.
코드의 재사용성, 유지보수성을 제공한다.
✔️ 상세 페이지 만들기
- 목표) 제목을 클릭하면 > 상세페이지로 이동하도록 만들기
- question_list.html에 추가
<td>
<a th:href="@{|/question/detail/${question.id}|}" th:text="${question.subject}"></a>
</td>
- id 누르면 detail(page)로 연결

- QuestionController.java
package com.mysite.sbb.question;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.RequiredArgsConstructor; // 추가
import org.springframework.web.bind.annotation.PathVariable; // 추가
@RequiredArgsConstructor
@Controller
public class QuestionController {
private final QuestionRepository questionRepository;
private final QuestionService questionService;
@GetMapping("/question/list")
public String list(Model model) {
List<Question> questionList = this.questionService.getList();
model.addAttribute("questionList", questionList);
return "question_list"; // html file 명 "" 안에 작성하면 됨
}
// Detail page 추가
@GetMapping(value = "/question/detail/{id}")
public String detail(Model model, @PathVariable("id") Integer id) {
return "question_detail";
}
}
- DataNotFoundException.java
- id값에 해당하는 질문 데이터가 없을 경우에는 예외 클래스 출력
package com.mysite.sbb;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "entity not found")
public class DataNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public DataNotFoundException(String message) {
super(message);
}
}
- QuestionController.java 에 추가
public String detail(Model model, @PathVariable("id") Integer id) {
Question question = this.questionService.getQuestion(id); // 추가
model.addAttribute("question", question); // 추가
return "question_detail";
}
- question_detail.html
<h1 th:text="${question.subject}"></h1>
<div th:text="${question.content}"></div>
- 제목을 누르면 질문페이지로 넘어감


- 예외 id 입력 시(ex. ~/detail/33) Error Page 출력 (DataNotFoundException)

✔️ URL 프리픽스
최종적으로 질문 상세 페이지에서 답변을 입력할 수 있도록 만들예정.
그전에 매핑을 더 간단하게. /question위로 빼서 root 페이지와 연결되도록 간단히 수정
- QuestionController.java
package com.mysite.sbb.question;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; // 추가
@RequestMapping("/question")// 추가
@RequiredArgsConstructor
@Controller
public class QuestionController {
private final QuestionRepository questionRepository;
private final QuestionService questionService;
@GetMapping("/list")//question빼기
public String list(Model model) {
List<Question> questionList = this.questionService.getList();
model.addAttribute("questionList", questionList);
return "question_list"; // html file 명 "" 안에 작성하면 됨
}
// Detail page 추가
@GetMapping(value = "/detail/{id}") //question빼기
public String detail(Model model, @PathVariable("id") Integer id) {
Question question = this.questionService.getQuestion(id);
model.addAttribute("question", question);
return "question_detail";
}
}
✔️ 답변 기능 만들기
POST 방식을 사용하여, 사용자가 입력한 val 값을 서버에 전송함
서버는 값을 받아서 답변 페이지에 출력해주고, 이후 해당 페이지로 전환됨(ex. 2번 페이지를 전해줌)
✔️ 답변 컨트롤러 만들기
- AnswerController.java
package com.mysite.sbb.answer;
import com.mysite.sbb.question.Question;
import com.mysite.sbb.question.QuestionService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@RequestMapping("/answer")
@RequiredArgsConstructor
@Controller
public class AnswerController {
private final QuestionService questionService;
@PostMapping("/create/{id}")
public String createAnswer(Model model, @PathVariable("id") Integer id, @RequestParam(value="content") String content) {
Question question = this.questionService.getQuestion(id);
// TODO: 답변을 저장한다.
return String.format("redirect:/question/detail/%s", id);
}
}
✔️ 답변 서비스 만들기
- AnswerService.java
package com.mysite.sbb.answer;
import com.mysite.sbb.question.Question;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@RequiredArgsConstructor
@Service
public class AnswerService {
private final AnswerRepository answerRepository;
public void create(Question question, String content) {
Answer answer = new Answer();
answer.setContent(content);
answer.setCreateDate(LocalDateTime.now());
answer.setQuestion(question);
this.answerRepository.save(answer);
}
}
- AnswerController.java에 추가
public class AnswerController {
private final QuestionService questionService;
private final AnswerService answerService; // 추가
@PostMapping("/create/{id}")
public String createAnswer(Model model, @PathVariable("id") Integer id, @RequestParam(value="content") String content) {
Question question = this.questionService.getQuestion(id);
this.answerService.create(question, content); // TODO: 답변을 저장한다. AnswerService - create method 호출
return String.format("redirect:/question/detail/%s", id);
}
}



- 데이터는 ANSWER 에 전달됨

✔️ 상세 페이지에 답변 표시하기
- question_detail.html
<h5 th:text="|${#lists.size(question.answerList)}개의 답변이 있습니다.|"></h5>
<div>
<ul>
<li th:each="answer : ${question.answerList}" th:text="${answer.content}"></li>
</ul>
</div>

✔️ 웹 페이지 디자인하기
- static > New - File > style.css

- style.css
textarea {
width:100%;
}
input[type=submit] {
margin-top:10px;
}
- question_detail.html
style.css 사용 하도록 코드 추가
<link rel="stylesheet" type="text/css" th:href="@{/style.css}">
[결과]

✔️ 부트스트랩으로 화면 꾸미기
다운로드 하시오..
https://getbootstrap.com/docs/5.3/getting-started/download/
Download
Download Bootstrap to get the compiled CSS and JavaScript, source code, or include it with your favorite package managers like npm, RubyGems, and more.
getbootstrap.com
- 다운 받아서 해당 파일 static folder에 넣기

- question_list.html 수정 (코드는 교재 체크)

- question_detail.html (교재 확인하기)
✔️ 표준 HTML 구조로 변경하기
어떤 웹 브라우저를 사용하더라도 웹 페이지가 동일하게 보이고 정상적으로 작동하게 하려면 반드시 웹 표준을 지키는 HTML 문서로 작성해야 함. 그래서 템플릿 상속을 통해 css, html 등을 표준 HTML 구조로 구성되도록 하기
- templates > New - File > layout.html
<!doctype html>
<html lang="ko">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" type="text/css" th:href="@{/bootstrap.min.css}">
<!-- sbb CSS -->
<link rel="stylesheet" type="text/css" th:href="@{/style.css}">
<title>Hello, sbb!</title>
</head>
<body>
<!-- 기본 템플릿 안에 삽입될 내용 Start -->
<th:block layout:fragment="content"></th:block>
<!-- 기본 템플릿 안에 삽입될 내용 End -->
</body>
</html>
✔️ question_list.html에 템플릿 상속하기
- question_list.html
<html layout:decorate="~{layout}"> // question_list.html을 layout.html에 상속하겠다
<div layout:fragment="content" class="container my-3">
question_list.html의 layout:fragment="content"는
부모(layout.html)에 작성된 (<th:block layout:fragment="content"></th:block>)이부분을 자식(question_list)의 내용으로 적용될 수 있도록 다음과 같이 사용
✔️ 질문 등록 기능 추가하기
question_list.html 추가하기
</table>
<a th:href="@{/question/create}" class="btn btn-primary">질문 등록하기</a>
</div>
</html>
- QuestionController.java에 추가
@GetMapping("/create")
public String questionCreate() {
return "question_form";
}
- templates > question_form.html 생성 후 코드 추가(교재 참조)
>> 입력한 내용을 /question/create URL로 post 방식을 이용해 전송할 수 있도록 form과 버튼을 추가


- QuestionService.java
import java.time.LocalDateTime;
// 제목(subject)과 내용(content)을 입력받아 이를 질문으로 저장
public void create(String subject, String content) {
Question q = new Question();
q.setSubject(subject);
q.setContent(content);
q.setCreateDate(LocalDateTime.now());
this.questionRepository.save(q);
}
- QuestionController.java
QuestionService의 create 메서드를 호출하여 질문 데이터(subject, content)를 저장
// 질문 등록하기
@GetMapping("/create")
public String questionCreate() {
return "question_form";
}
@PostMapping("/create")
public String questionCreate(@RequestParam(value="subject") String subject, @RequestParam(value="content") String content) {
this.questionService.create(subject, content); // TODO 질문을 저장한다.
return "redirect:/question/list"; // 질문 저장후 질문목록으로 이동
}



- DB에서 확인 가능

- 이메일 생성시 valication check 잘 해야함
'ICT 네트워크 과정' 카테고리의 다른 글
| 0616 :: Spring boot Security, Login/Logout 구현 (1) | 2025.06.16 |
|---|---|
| 0613 :: Spring Boot 게시판 생성 (2) (1) | 2025.06.13 |
| 0611 :: Spring(3) - JPA (1) | 2025.06.11 |
| 0610 :: Spring Boot(2) - 웹을 만들어보쟈~ (1) | 2025.06.10 |
| 0610 :: Spring Boot(1) - Spring Boot, Lombok 설치 & 설정 (1) | 2025.06.10 |