๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
IT/Java - Spring Boot

[Spring Boot] ๊ฒŒ์‹œํŒ ๋งŒ๋“ค๊ธฐ

by ITyranno 2023. 11. 1.
728x90
๋ฐ˜์‘ํ˜•

 

 

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์„ธ๊ณ„๋ฅผ ํƒ๊ตฌํ•ฉ์‹œ๋‹ค.

 

 

 

 

Spring Boot๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํŽ˜์ด์ง€์— ๊ฒŒ์‹œํŒ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

 

๊ตฌํ˜„ ํ™”๋ฉด

 

 

 

 

 

 

๊ฒŒ์‹œํŒ์€ ๊ณต์ง€์‚ฌํ•ญ, Q&A ํ•ญ๋ชฉ์ด ์žˆ์œผ๋ฉฐ ๊ธ€์“ฐ๊ธฐ, ์ด๋ฏธ์ง€ ์ฒจ๋ถ€, ๊ธ€์˜ ์ˆ˜์ • ์‚ญ์ œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. Q&A์—๋Š” ์ผ๋ฐ˜ ๊ธ€์“ฐ๊ธฐ, ์ถฉ์ „์†Œ ์ถ”๊ฐ€์š”์ฒญ, Car์ •๋ณด ์ถ”๊ฐ€์š”์ฒญ์ด ์žˆ์–ด ํ•ด๋‹น ํ•ญ๋ชฉ์„ ๊ด€๋ฆฌ์ž ๊ณ„์ •์œผ๋กœ ๋”ฐ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

pagination ํ™œ์šฉํ•˜์—ฌ ํ•˜๋‹จ์— ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ๋ถ€์—ฌํ–ˆ๊ณ , ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

 

 

 

์ž‘์„ฑ ์ฝ”๋“œ

 

 

BoardController.java

 

package com.example.board.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import javax.servlet.http.HttpSession;

import com.example.board.model.Board;
import com.example.board.model.Comment;
import com.example.board.model.FileAtch;
import com.example.board.model.User;
import com.example.board.repository.BoardRepository;
import com.example.board.repository.CommentRepository;
import com.example.board.repository.FileAtchRepository;

@Controller
public class BoardController {
	@Autowired
	BoardRepository boardRepository;

	@Autowired
	CommentRepository commentRepository;

	@Autowired
	FileAtchRepository fileAtchRepository;

	@Autowired
	HttpSession session;

	@GetMapping("/board/image")
	public String image() {
		return "/board/image";
	}

	@GetMapping("/board/delete/{id}")
	public String boardDelete(@PathVariable("id") long id) {
		User loggedUser = (User) session.getAttribute("user_info");
		String loggedName = loggedUser.getEmail();
		Optional<Board> dbBoard = boardRepository.findById(id);
		// String savedName = dbBoard.get().getUserId();
		String savedName = dbBoard.get().getUser().getEmail();

		if (savedName.equals(loggedName)) {
			Board board = new Board();
			board.setId(id);
			boardRepository.deleteById(id);
			return "redirect:/board/list";
		} else {

			return "redirect:/board/view?id=" + id;
		}
	}

	@GetMapping("/board/update/{id}")
	public String boardUpdate(Model model, @PathVariable("id") long id) {
		Optional<Board> data = boardRepository.findById(id);
		Board board = data.get();
		model.addAttribute("board", board);
		return "board/update";
	}

	@PostMapping("/board/update/{id}")
	public String boardUpdate(
			@ModelAttribute Board board,
			@RequestParam("file") MultipartFile mFile,
			@PathVariable("id") long id) {

		User user = (User) session.getAttribute("user_info");
		if (user == null) {
			return "redirect:/login";
		}
		String userId = user.getEmail();

		Optional<Board> data = boardRepository.findById(id);

		if (data.isPresent()) {
			Board existingBoard = data.get();
			// !userId.equals(existingBoard.getUserId())
			if (!userId.equals(existingBoard.getUser().getEmail())) {
				// ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒŒ์‹œ๋ฌผ์˜ ์ž‘์„ฑ์ž๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ ์ฒ˜๋ฆฌํ•  ๋‚ด์šฉ
				return "redirect:/board/view?id=" + id; // ์˜ˆ: ๊ฒŒ์‹œ๋ฌผ ๋ณด๊ธฐ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜
			}

			// ๊ฒŒ์‹œ๋ฌผ ์ˆ˜์ • ๊ถŒํ•œ์ด ์žˆ๋Š” ๊ฒฝ์šฐ, ์—…๋ฐ์ดํŠธ ์ง„ํ–‰
			existingBoard.setTitle(board.getTitle());
			existingBoard.setContent(board.getContent());

			// ํŒŒ์ผ ์ €์žฅ ๋กœ์ง ์‹œ์ž‘
			String originalFilename = mFile.getOriginalFilename();
			FileAtch fileAtch = new FileAtch();
			fileAtch.setOriginalName(originalFilename);
			fileAtch.setSaveName(originalFilename);
			fileAtch.setBoard(existingBoard);

			fileAtchRepository.save(fileAtch);

			String filename = mFile.getOriginalFilename();

			File file = new File("C:/files/" + filename);
			try {
				mFile.transferTo(file);
			} catch (IllegalStateException | IOException e) {
				e.printStackTrace();
			}
			// ํŒŒ์ผ ์ €์žฅ ๋กœ์ง ๋

			boardRepository.save(existingBoard);
		}

		return "redirect:/board/" + id;
	}

	@GetMapping("/board/{id}")
	public String boardView(Model model, @PathVariable("id") long id) {
		Optional<Board> data = boardRepository.findById(id);
		Board board = data.get();
		model.addAttribute("board", board);
		return "board/view";
	}

	@GetMapping("/board/list")
	public String boardList(Model model,
			@RequestParam(required = false) String keyword,
			@RequestParam(defaultValue = "1") int P) {
		Sort sort = Sort.by(Order.desc("id"));
		Pageable pageable = PageRequest.of(P - 1, 10, sort);
		// Page<Board> list = boardRepository.findAll(pageable);

		Page<Board> page;
		if (keyword != null && !keyword.isEmpty()) {
			page = boardRepository.findByTitleContaining(keyword, pageable);
		} else {
			page = boardRepository.findAll(pageable);
		}

		List<Board> list = page.getContent();

		model.addAttribute("list", list);

		int startPageGroup = ((P - 1) / 10) * 10;

		int totalPages = page.getTotalPages();

		// calculate end page
		int startPage = Math.max(1, startPageGroup + 1);
		int endPage = Math.min(totalPages, startPageGroup + 10);

		model.addAttribute("startPage", startPage);
		model.addAttribute("endPage", endPage);
		model.addAttribute("prevGroupStart", Math.max(1, startPage - 10));
		model.addAttribute("nextGroupStart", Math.min(totalPages, startPage + 10));
		model.addAttribute("totalPages", totalPages);

		User user = (User) session.getAttribute("user_info");
		if (user != null) {
			int userCoins = user.getCoin();
			model.addAttribute("userCoin", userCoins);
		}
		return "board/list";
	}

	@GetMapping("/board/write")
	public String boardWrite() {

		return "board/write";
	}

	@PostMapping("/board/write")
	@Transactional(rollbackFor = { ArithmeticException.class })
	public String boardWrite(
			@ModelAttribute Board board,
			@RequestParam("file") MultipartFile[] mFiles) {

		User user = (User) session.getAttribute("user_info");
		if (user == null) {
			return "redirect:/signin";
		}
		board.setUser(user);
		user.getBoards().add(board);
		Board saveBoard = boardRepository.save(board);

		for (MultipartFile mFile : mFiles) {
			String originalFilename = mFile.getOriginalFilename();

			FileAtch fileAtch = new FileAtch();
			fileAtch.setOriginalName(originalFilename);
			fileAtch.setSaveName(originalFilename);
			fileAtch.setBoard(saveBoard);

			fileAtchRepository.save(fileAtch);

			String filename = mFile.getOriginalFilename();

			File file = new File("C:/files/" + filename);
			try {
				mFile.transferTo(file);
			} catch (IllegalStateException | IOException e) {
				e.printStackTrace();
			}
		}

		boardRepository.save(board);

		return "redirect:/board/list";
	}

	@PostMapping("/board/comment")
	public String comment(@ModelAttribute Comment comment, @RequestParam int boardId) {
		User user = (User) session.getAttribute("user_info");
		String name;

		if (user != null) {
			name = user.getName(); // ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฆ„์„ ๊ฐ€์ ธ์˜ด
		} else {
			name = "Anonymous"; // ๋กœ๊ทธ์ธํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋Š” "Anonymous"
		}

		comment.setWriter(name);
		comment.setWriter(name);
		comment.setCreDate(new Date());

		Board board = new Board();
		board.setId(boardId);
		comment.setBoard(board);

		commentRepository.save(comment);

		return "redirect:/board/view?id=" + boardId;
	}

	@GetMapping("/board/comment/remove")
	public String commentRemove(@ModelAttribute Comment comment, @RequestParam int boardId) {
		// 1๋ฒˆ new Comment(), setId()
		// 2๋ฒˆ @ModelAttribute Comment comment
		commentRepository.delete(comment);
		return "redirect:/board/view?id=" + boardId;
	}

	@GetMapping("/board/fileAtch/remove")
	public String fileAtchRemove(@ModelAttribute FileAtch fileAtch, @RequestParam int boardId) {
		// 1๋ฒˆ new Comment(), setId()
		// 2๋ฒˆ @ModelAttribute Comment comment
		fileAtchRepository.delete(fileAtch);
		return "redirect:/board/view?id=" + boardId;
	}

	@GetMapping("/board/view")
	public String view(Model model, @RequestParam long id) {
		Optional<Board> opt = boardRepository.findById(id);
		model.addAttribute("board", opt.get());
		return "board/view";
	}

}

 

 

BoardRepository.java

 

package com.example.board.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

import com.example.board.model.Board;

public interface BoardRepository extends JpaRepository<Board, Long> {
    List<Board> findTop5ByOrderByIdDesc();

    Page<Board> findByTitleContaining(String keyword, Pageable pageable);
}

 

 

Board.java

 

package com.example.board.model;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

import lombok.Data;

@Entity
@Data
public class Board{
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private long id;
	private String title;
	private String content;
	// private String userId;

		@ManyToOne
		@JoinColumn(name = "member_id")
		User user; //user_id
	
    @OneToMany(mappedBy = "board", cascade = CascadeType.ALL)
    List<Comment> comments = new ArrayList<>();

    @OneToMany(mappedBy = "board", cascade = CascadeType.ALL)
    List<FileAtch> fileAtchs = new ArrayList<>();
}

 

 

list.html

 

<!DOCTYPE html>
<html lang="en">

<head th:replace="common/head">
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet">
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"></script>
</head>

<style>
  @font-face {
    font-family: 'TheJamsil5Bold';
    src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2302_01@1.0/TheJamsil5Bold.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
  }

  body {
    font-family: 'TheJamsil5Bold';
    height: 100vh;
    /* ํ™”๋ฉด ๋†’์ด์˜ 100%๋กœ ์„ค์ • */
    background-color: #000;
    background-size: cover;
    /* ์ด๋ฏธ์ง€๋ฅผ ํ™”๋ฉด์— ๋งž๊ฒŒ ์กฐ์ ˆ */
    background-repeat: no-repeat;
    /* ์ด๋ฏธ์ง€ ๋ฐ˜๋ณต์„ ์ค‘์ง€ */
  }

  .table {
    color: white;
  }

  #write-btn {
    background-color: #f2f5c0;
    width: 150px;
    height: 40px;
    position: fixed;
    float: right;
    right: 120px;
    bottom: 20px;
  }

  #write-btn:hover {
    background-color: #e2ce38;
    border-color: #e2ce38;
  }

  #search-btn {
    background-color: #f2f5c0;
    border-color: #f2f5c0;
  }

  .pagination-form {
    margin-top: 20px;
  }

  .search-form {
    margin-top: 20px;
    margin-bottom: 40px;
  }

  .pagination .page-link {
    color: #7e7c53;
  }

  .pagination .page-link:hover {
    color: #FFFFFF;
    background-color: #e2ce38;
  }

  .title h1{
        text-align: center;
        margin-bottom: 3rem;
        color: white;
    }
</style>


<body>

  <div th:replace="common/header">

  </div>

  <nav th:replace="common/nav">

  </nav>

  <div class="title">
      <h1>๊ณต์ง€์‚ฌํ•ญ</h1>
  </div>

  <div class="container mt-5">
    <div class="row">
      <table class="table table-hover">
        <thead>
          <tr>
            <th>๋ฒˆํ˜ธ</th>
            <th>์ œ๋ชฉ</th>
            <th>์ž‘์„ฑ์ž</th>
          </tr>
        </thead>
        <tbody>
          <tr th:each="board : ${list}" th:onclick="'window.location = \'/board/view?id=' + ${board.id} + '\''">
            <td th:text="${board.id}"></td>
            <td th:text="${board.title}"></td>
            <td th:text="${board.user.name}"></td>
          </tr>
        </tbody>
      </table>
      <button type="button" class="btn btn-block" id="write-btn">๊ธ€์“ฐ๊ธฐ</button>
      <div class="d-flex justify-content-center pagination-form">
        <ul class="pagination">
          <li class="page-item">
            <a class="page-link" th:href="@{/board/list(P=1)}">ใ€Š</a>
          </li>
          <li class="page-item">
            <a class="page-link" th:href="@{/board/list(P=${prevGroupStart})}">ใ€ˆ</a>
          </li>
          <th:block th:each="pageNumber : ${#numbers.sequence(startPage, endPage)}">
            <li class="page-item" th:if="${pageNumber > 0}">
              <a class="page-link" th:href="@{/board/list(P=${pageNumber})}">[[ ${pageNumber} ]]</a>
            </li>
          </th:block>
          <li class="page-item">
            <a class="page-link" th:href="@{/board/list(P=${nextGroupStart})}">ใ€‰</a>
          </li>
          <li class="page-item">
            <a class="page-link" th:href="@{/board/list(P=${totalPages})}">ใ€‹</a>
          </li>
        </ul>
      </div>
      <div class="d-flex justify-content-center search-form">
        <form th:action="@{/board/list}" method="get">
            <input type="text" name="keyword" placeholder="๊ฒ€์ƒ‰์–ด ์ž…๋ ฅ">
            <button type="submit" id="search-btn">๊ฒ€์ƒ‰</button>
        </form>
    </div>
    </div>
  </div>

  <script>
    document.querySelector('#write-btn').addEventListener('click', () => {
      location = '/board/write';
    });
  </script>

</body>

</html>

 

 

update.html

 

<!DOCTYPE html>
<html lang="en">

<head th:replace="common/head">

</head>

<style>

@font-face {
    font-family: 'TheJamsil5Bold';
    src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2302_01@1.0/TheJamsil5Bold.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
  }

  body {
    font-family: 'TheJamsil5Bold';
    height: 100vh;
    /* ํ™”๋ฉด ๋†’์ด์˜ 100%๋กœ ์„ค์ • */
    background-color: #000;
    background-size: cover;
    /* ์ด๋ฏธ์ง€๋ฅผ ํ™”๋ฉด์— ๋งž๊ฒŒ ์กฐ์ ˆ */
    background-repeat: no-repeat;
    /* ์ด๋ฏธ์ง€ ๋ฐ˜๋ณต์„ ์ค‘์ง€ */
    color: white;
  }


  .btn {
    background-color: #eee788;
    border-color: #eee788;
    text-decoration: none;
    color: black;
  }

  .btn:hover {
    background-color: #9c9b83;
    border-color: #9c9b83;
   
  }

</style>

<body>

  <div th:replace="common/header">

  </div>

  <nav th:replace="common/nav">

  </nav>

  <div class="container mt-5">
    <div class="row">
      <form method="post" th:action="@{/board/update/} + ${board.id}" enctype="multipart/form-data">
        <div class="mb-3">
          <label for="title">Title:</label>
          <input type="text" class="form-control" id="title" name="title" th:value="${board.title}">
        </div>
        <div class="mb-3">
          <label for="content">Content:</label>
          <textarea class="form-control" rows="5" name="content" id="content">[[ ${board.content} ]]</textarea>
        </div>
        <input type="file" name="file" id="" multiple>
        <br>
        <br>
        <div class="d-grid gap-2">
          <button class="btn btn-primary" type="submit" id="complete">์ˆ˜์ •์™„๋ฃŒ</button>
        </div>
      </form>
    </div>
  </div>

  <div th:replace="common/footer">
  </div>

</body>

</html>

 

 

 

view.html

 

<!DOCTYPE html>
<html lang="en">

<head th:replace="common/head"></head>

<style>
  @font-face {
    font-family: 'TheJamsil5Bold';
    src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2302_01@1.0/TheJamsil5Bold.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
  }

  body {
    font-family: 'TheJamsil5Bold';
    height: 100vh;
    /* ํ™”๋ฉด ๋†’์ด์˜ 100%๋กœ ์„ค์ • */
    background-color: #000;
    background-size: cover;
    /* ์ด๋ฏธ์ง€๋ฅผ ํ™”๋ฉด์— ๋งž๊ฒŒ ์กฐ์ ˆ */
    background-repeat: no-repeat;
    /* ์ด๋ฏธ์ง€ ๋ฐ˜๋ณต์„ ์ค‘์ง€ */
  }
</style>

<body>

  <div th:replace="common/header"></div>
  <nav th:replace="common/nav"></nav>

  <div class="container mt-5">
    <div class="card">
      <div class="card-body">
        <span class="badge bg-primary rounded-pill" th:text="${board.id} + '๋ฒˆ'"></span>
        <h5 class="card-title" th:text="${board.title}"></h5>
        <h6 class="card-subtitle mb-2 text-muted" th:text="${board.user.email}"></h6>
        <p class="card-text" th:text="${board.content}"></p>

        <div id="imageContainer">
          <img th:each="fileAtch : ${board.fileAtchs}" th:src="@{/download(id=${fileAtch.id})}" alt="์ฒจ๋ถ€๋œ ์ด๋ฏธ์ง€">
        </div>

        <form action="/board/comment" method="post">
          <input type="text" name="content">
          <input type="hidden" name="boardId" th:value="${board.id}">
          <button type="submit">๋Œ“๊ธ€๐Ÿ˜Š๋‹ฌ๊ธฐ</button>
        </form>
        <hr>
        ๋Œ“๊ธ€โœ๏ธ
        <ul th:each="comment : ${board.comments}">
          <li>
            [[ ${comment.content} ]] / [[ ${comment.writer} ]] / [[${#dates.format(comment.creDate, 'yyyy-MM-dd
            HH:mm:ss')}]]
            <!-- ๋Œ“๊ธ€ ์‚ญ์ œ ๋ฒ„ํŠผ -->
            <button
              th:if="${session.user_info != null && session.user_info.email == board.user.email || session.user_info.name ==comment.writer }"
              th:onclick="'commentRm(' + ${comment.id} +')'">๋Œ“์‚ญ๐Ÿฅฒ</button>
          </li>
        </ul>
        <hr>
        ์ฒจ๋ถ€๋œ ํŒŒ์ผ๐Ÿ“ฅ
        <!-- ์ฒจ๋ถ€๋œ ํŒŒ์ผ ๋ชฉ๋ก -->
        <ul th:each="fileAtch : ${board.fileAtchs}">

          <li style="list-style-type: none;">
            <a th:href="@{/download(id=${fileAtch.id})}">
              [[${fileAtch.originalName}]]
            </a>
            <!-- ํŒŒ์ผ ์‚ญ์ œ ๋ฒ„ํŠผ -->
            <button th:if="${session.user_info != null && session.user_info.email == board.user.email}"
              th:style="${fileAtch.originalName == '' ? 'display:none;' : ''}"
              th:onclick="'fileRm(' + ${fileAtch.id} +')'">ํŒŒ์ผ์‚ญ์ œโœ‚๏ธ
            </button>
          </li>
        </ul>
      </div>
    </div>
  </div>
  <div class="container mt-5">
    <ul class="nav justify-content-end">
      <li class="nav-item">
        <a class="nav-link" th:href="@{/board/list}" id="list">๋ชฉ๋ก</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" th:href="@{'/board/update/' + ${board.id}}" id="update">์ˆ˜์ •</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" th:data-num="${board.id}" id="delete">์‚ญ์ œ</a>
      </li>
    </ul>
  </div>


  <script>

    // ํŒŒ์ผ ์—…๋กœ๋“œ input ์š”์†Œ์˜ change ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œ
    document.getElementById("fileInput").addEventListener("change", function (event) {
      var files = event.target.files; // ์„ ํƒ๋œ ํŒŒ์ผ๋“ค

      // ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•  ์˜์—ญ์˜ DOM ์š”์†Œ
      var imageContainer = document.getElementById("imageContainer");

      // ์„ ํƒ๋œ ํŒŒ์ผ๋“ค์„ ์ˆœํšŒํ•˜๋ฉด์„œ ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œ
      for (var i = 0; i < files.length; i++) {
        var file = files[i];
        var imageURL = URL.createObjectURL(file); // ํŒŒ์ผ URL ์ƒ์„ฑ

        // ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋Š” <img> ์š”์†Œ ์ƒ์„ฑ ๋ฐ ์„ค์ •
        var imageElement = document.createElement("img");
        imageElement.src = imageURL;

        // ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•  ์˜์—ญ์— ์ถ”๊ฐ€
        imageContainer.appendChild(imageElement);
      }
    });
    </script>

    <script>
  
    var authorUserId = "[[${board.user.email}]]";

    document.querySelector('#update').addEventListener('click', (e) => {
      e.preventDefault();
      // ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
      var currentUser = "[[${session.user_info != null ? session.user_info.email : ''}]]"; // null ์ฒดํฌ ์ถ”๊ฐ€
      if (currentUser !== authorUserId) {
        alert('๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ์ž๋งŒ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.'); // ์ˆ˜์ • ๊ถŒํ•œ์ด ์—†์„ ๋•Œ ๊ฒฝ๊ณ ์ฐฝ ํ‘œ์‹œ
      } else {
        // ์ˆ˜์ • ํŽ˜์ด์ง€๋กœ ์ด๋™
        window.location.href = e.target.getAttribute("href");
      }
    });

    document.querySelector('#delete').addEventListener('click', (e) => {
      e.preventDefault();
      if (confirm('์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?')) {
        const num = e.target.dataset.num;
        console.log(num);
        if (num !== "null")
          location = `/board/delete/${num}`;
      }
    });

    function commentRm(id) {
      const isOk = confirm('์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?');
      if (isOk) {
        location = `/board/comment/remove?id=${id}&boardId=[[${board.id}]]`;
      }
    }

    function fileRm(id) {
      const isOk = confirm('์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?');
      if (isOk) {
        location = `/board/fileAtch/remove?id=${id}&boardId=[[${board.id}]]`;
      }
    }
  </script>
</body>

</html>

 

 

write.html

 

<!DOCTYPE html>
<html lang="en">

<head th:replace="common/head">

</head>

<style>
  @font-face {
    font-family: 'TheJamsil5Bold';
    src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2302_01@1.0/TheJamsil5Bold.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
  }

  body {
    font-family: 'TheJamsil5Bold';
    height: 100vh;
    /* ํ™”๋ฉด ๋†’์ด์˜ 100%๋กœ ์„ค์ • */
    background-color: #000;
    background-size: cover;
    /* ์ด๋ฏธ์ง€๋ฅผ ํ™”๋ฉด์— ๋งž๊ฒŒ ์กฐ์ ˆ */
    background-repeat: no-repeat;
    /* ์ด๋ฏธ์ง€ ๋ฐ˜๋ณต์„ ์ค‘์ง€ */
    color: white;
  }

  .submit-color {
    background-color: #f2f5c0;
    border-color: #f2f5c0;
    text-decoration: none;
    color: black;
  }

  .submit-color:hover {
    background-color: #e2ce38;
    border-color: #e2ce38;
    color: black;
  }
</style>

<body>

  <div th:replace="common/header">

  </div>

  <nav th:replace="common/nav">

  </nav>

  <div class="container mt-5">
    <div class="row">
      <form method="post" action="/board/write" enctype="multipart/form-data">
        <div class="mb-3">
          <label for="title">Title:</label>
          <input type="text" class="form-control" id="title" name="title">
        </div>
        <th:block th:unless="${session.name} == null">
          <input type="text" name="writer" th:value=${session.name}>
        </th:block>
        <div class="mb-3">
          <label for="content">Content:</label>
          <textarea class="form-control" rows="5" name="content" id="content"></textarea>
        </div>
        <input type="file" name="file" id="" multiple>
        <br>
        <br>
        <div class="d-grid gap-2">
          <button class="btn btn-primary submit-color" id="complete">์ž‘์„ฑ์™„๋ฃŒ</button>
        </div>
      </form>
    </div>
  </div>

  <div th:replace="common/footer">
  </div>

</body>

</html>

 

 

 

์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ํŽ˜์ด์ง€์— ๊ฒŒ์‹œํŒ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

728x90
๋ฐ˜์‘ํ˜•

loading