8. Mini Project
8. 2 . Backend
Spring Boot is a tool that facilitates the rapid and easy development of Java-based web applications. Built on top of the
Spring Framework, Spring Boot automates many configuration tasks required for starting and configuring projects, thereby
enhancing productivity. When discussing it comprehensively, it can be structured into key aspects: history and evolution, core
features, internal operational mechanisms, as well as use cases and ecosystem.
Here's a detailed list of the topics
- 8.2.3 Customer, Admin, Main:
8.2.1 Project:
application.properties
spring.application.name=miniproject
server.servlet.session.timeout=2h
# Database Setting
spring.datasource.dbcp2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/miniproject
spring.datasource.username=root
spring.datasource.password=1111
# JPA
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.show_sql=true
# aws
cloud.aws.s3.endpoint=https://kdh0608.s3.ap-northeast-2.amazonaws.com
8.2.2 Configuration:
Spring Security
SecurityConfig.java
package com.example.miniproject.customer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll())
.formLogin((formLogin) -> formLogin
.loginPage("/signin")
.defaultSuccessUrl("/admin")
)
.logout((logout) -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/signout"))
.logoutSuccessUrl("/")
.invalidateHttpSession(true))
;
return http.build();
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
Customer.java
package com.example.miniproject.customer;
import java.time.LocalDateTime;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;
@Data
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer cid;
@Column(unique = true)
private String username; // for SpringSecurity Policy
private String password; // for SpringSecurity Policy
private boolean enabled; // for SpringSecurity Policy
private String role; // for SpringSecurity Policy
private String cphone;
private String cname;
private LocalDateTime cdate;
}
CustomerRepository.java
package com.example.miniproject.customer;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
Optional<Customer> findByusername(String username); // login check
}
CustomerService.java
package com.example.miniproject.customer;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.stereotype.Service;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
@Service
public class CustomerService implements UserDetailsService {
@Autowired
private CustomerRepository customerRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<Customer> tcustomer = customerRepository.findByusername(username);
if (tcustomer.isEmpty()) {
throw new UsernameNotFoundException("You need to Sign up first...");
}
Customer customer = tcustomer.get();
List<GrantedAuthority> authorities = new ArrayList<>();
if ("ROLE_USER".equals(customer.getRole())) {
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
} else if ("ROLE_MANAGER".equals(customer.getRole())) {
authorities.add(new SimpleGrantedAuthority("ROLE_MANAGER"));
} else {
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
return new User(customer.getUsername(), customer.getPassword(), authorities);
}
public void create(Customer customer) {
customer.setEnabled(true);
customer.setRole("ROLE_USER"); //ROLE_ADMIN, ROLE_MANAGER, ROLE_PAID...
customer.setCdate(LocalDateTime.now());
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
customer.setPassword(passwordEncoder.encode(customer.getPassword()));
customerRepository.save(customer);
}
public Customer authen() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
String username = userDetails.getUsername();
Optional<Customer> oc = customerRepository.findByusername(username);
return oc.get();
}
//naver logincheck
@Autowired
private HttpServletRequest req;
public int logincheck(String username) throws UsernameNotFoundException {
Optional<Customer> tcustomer = customerRepository.findByusername(username);
if (tcustomer.isEmpty()) {
return 1;//db에 없음, 회원 가입으로
}
Customer customer = tcustomer.get();
List<GrantedAuthority> authorities = new ArrayList<>();
if ("ROLE_USER".equals(customer.getRole())) {
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
} else if ("ROLE_MANAGER".equals(customer.getRole())) {
authorities.add(new SimpleGrantedAuthority("ROLE_MANAGER"));
} else {
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
//스프링 시큐리티 규격에 맞게 로그인 처리
SecurityContext sc = SecurityContextHolder.getContext();
sc.setAuthentication(new UsernamePasswordAuthenticationToken(customer.getUsername(), customer.getPassword(), authorities));
HttpSession session = req.getSession(true);
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,sc);
return 0; //db에 있음, 세션 처리까지
}
}
CustomerController.java
package com.example.miniproject.customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class CustomerController {
@Autowired
private CustomerService customerService;
@GetMapping("/signup")
public String signup() {
return "signup";
}
@PostMapping("/signup")
public String signup(Customer customer) {
customerService.create(customer);
return "signup";
}
@GetMapping("/signin")
public String signin() {
return "signin";
}
}
signup.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<span sec:authorize="isAnonymous()">Signin First...<a href="/signin">Sign in</a></span>
<span sec:authorize="isAuthenticated()">Welcome...<span th:text="${#authentication.name}"></span>
<span th:text="${#authentication.authorities}"></span>
<a href="/signout">Sign out</a>
</span>
<form action="/signup" method="post">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<p>ID : <input type="text" name="username">
<p>PW : <input type="password" name="password">
<p>Mail : <input type="text" name="cemail">
<p><input type="submit" value="Sign up">
</form>
</body>
</html>
signin.html
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<form action="/signin" method="post">
<div th:if="${param.error}">
<div class="alert alert-danger">
Please, Check your ID or Password...
</div>
</div>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<p>ID : <input type="text" name="username">
<p>PW : <input type="password" name="password">
<p><input type="submit" value="Sign in">
</form>
</body>
</html>
Naver Login
NaverController.java
package com.example.miniproject.customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class NaverController {
@Autowired
private CustomerService customerService;
@GetMapping("/naver")
public String naver() {
return "NaverLogin";
}
@GetMapping("/naverlogin")
public String naverlogin() {
return "callback";
}
@GetMapping("/logincheck")
public String logincheck(@RequestParam("email") String email) {
if (1 == customerService.logincheck(email)) {
return "redirect:/";
}else {
return "admin";
}
}
}
NaverController.java
@GetMapping("/logincheck")
public String logincheck(@RequestParam("email") String email) {
if (1 == customerService.logincheck(email)) {
return "redirect:/";
}else {
return "admin";
}
}
CustomerService.java
//naver logincheck
@Autowired
private HttpServletRequest req;
public int logincheck(String username) throws UsernameNotFoundException {
Optional<Customer> tcustomer = customerRepository.findByusername(username);
if (tcustomer.isEmpty()) {
return 1;//db에 없음, 회원 가입으로
}
Customer customer = tcustomer.get();
List<GrantedAuthority> authorities = new ArrayList<>();
if ("ROLE_USER".equals(customer.getRole())) {
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
} else if ("ROLE_MANAGER".equals(customer.getRole())) {
authorities.add(new SimpleGrantedAuthority("ROLE_MANAGER"));
} else {
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
//스프링 시큐리티 규격에 맞게 로그인 처리
SecurityContext sc = SecurityContextHolder.getContext();
sc.setAuthentication(new UsernamePasswordAuthenticationToken(customer.getUsername(), customer.getPassword(), authorities));
HttpSession session = req.getSession(true);
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,sc);
return 0; //db에 있음, 세션 처리까지
}
NaverLogin.html
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>네이버 로그인</title>
<script type="text/javascript" src="https://static.nid.naver.com/js/naverLogin_implicit-1.0.3.js" charset="utf-8"></script>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
</head>
<body>
<!-- 네이버 로그인 버튼 노출 영역 -->
<div id="naver_id_login"></div>
<!-- //네이버 로그인 버튼 노출 영역 -->
<script type="text/javascript">
var naver_id_login = new naver_id_login("YOURS.....", "http://localhost:8080/naverlogin");
var state = naver_id_login.getUniqState();
naver_id_login.setButton("white", 2,40);
naver_id_login.setDomain("http://localhost:8080/");
naver_id_login.setState(state);
//naver_id_login.setPopup();
naver_id_login.init_naver_id_login();
</script>
</html>
callback.html
<!doctype html>
<html lang="ko">
<head>
<script type="text/javascript" src="https://static.nid.naver.com/js/naverLogin_implicit-1.0.3.js" charset="utf-8"></script>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
</head>
<body>
<script type="text/javascript">
var naver_id_login = new naver_id_login("YOURS.....", "http://localhost:8080/naverlogin");
// 접근 토큰 값 출력
//alert(naver_id_login.oauthParams.access_token);
// 네이버 사용자 프로필 조회
naver_id_login.get_naver_userprofile("naverSignInCallback()");
// 네이버 사용자 프로필 조회 이후 프로필 정보를 처리할 callback function
function naverSignInCallback() {
//alert(naver_id_login.getProfileData('email'));
location.href="/logincheck?email=" + naver_id_login.getProfileData('email');
}
</script>
</body>
</html>
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<span sec:authorize="isAnonymous()">Signin First...<a href="/signin">Sign in</a></span>
<span sec:authorize="isAuthenticated()">Welcome...<span th:text="${#authentication.name}"></span>
<span th:text="${#authentication.authorities}"></span>
<a href="/signout">Sign out</a>
</span>
<form action="/signup" method="post">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<p>ID : <input type="text" name="username">
<p>PW : <input type="password" name="password">
<p>Mail : <input type="text" name="cemail">
<p><input type="submit" value="Sign up">
</form>
</body>
</html>
admin.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<input type="text" id="colFormLabelLg" th:value="${#authentication.name}" disabled>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#staticBackdrop">
새 행사 등록
</button>
</div>
<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h1 class="modal-title fs-5" id="staticBackdropLabel">새 행사 등록</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form action="/event/create" method="post">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<div class="input-group mb-3">
<label for="colFormLabelLg" class="col-sm-2 col-form-label col-form-label-lg">행사명 </label>
<input type="text" name="etitle" class="form-control form-control-lg" id="colFormLabelLg" placeholder="행사명을 입력하세요">
</div>
<div class="input-group mb-3">
QT 코드는 먼저 행사를 등록하여 id를 생성한 후 수정을 통해 사진으로 추가합니다.
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark" data-bs-dismiss="modal">취소</button>
<input type="submit" class="btn btn-primary" value="등록">
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>
CustomerController.java
@GetMapping("/")
public String index() {
return "index";
}
행사 입력 테스트 !!!
Event.java
package com.example.miniproject.event;
import java.time.LocalDateTime;
import com.example.miniproject.customer.Customer;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import lombok.Data;
@Entity
@Data
public class Event {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer eid;
@ManyToOne
private Customer ecustomer;
private String etitle;
private String eimg;
private LocalDateTime edate;
}
EventController
package com.example.miniproject.event;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import lombok.RequiredArgsConstructor;
@RequestMapping("/event")
@RequiredArgsConstructor
@Controller
public class EventController {
private final EventService eventService;
@PostMapping("/create")
public String create(Event event
) {
eventService.create(event);
return "redirect:/admin";
}
}
EventService
package com.example.miniproject.event;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.example.miniproject.S3Service;
import com.example.miniproject.customer.CustomerService;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Service
public class EventService {
private final EventRepository eventRepository;
private final S3Service s3Service;
private final CustomerService customerService;
public void create(Event event) {
event.setEcustomer(customerService.authen());
event.setEdate(LocalDateTime.now());
eventRepository.save(event);
}
}
EventRepository.java
package com.example.miniproject.event;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EventRepository extends JpaRepository<Event, Integer> {
}
EventService <- readlist
MainController.java
admin.html 수정
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<input type="text" id="colFormLabelLg" th:value="${#authentication.name}" disabled>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#staticBackdrop">
새 행사 등록
</button>
</div>
<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h1 class="modal-title fs-5" id="staticBackdropLabel">새 행사 등록</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form action="/event/create" method="post">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<div class="input-group mb-3">
<label for="colFormLabelLg" class="col-sm-2 col-form-label col-form-label-lg">행사명 </label>
<input type="text" name="etitle" class="form-control form-control-lg" id="colFormLabelLg" placeholder="행사명을 입력하세요">
</div>
<div class="input-group mb-3">
QT 코드는 먼저 행사를 등록하여 id를 생성한 후 수정을 통해 사진으로 추가합니다.
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark" data-bs-dismiss="modal">취소</button>
<input type="submit" class="btn btn-primary" value="등록">
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<th:block th:each="event: ${events}">
<div class="row mt-3">
<label for="colFormLabelLg" class="col-sm-1 col-form-label col-form-label-lg"></label>
<div class="col-sm-10 d-flex align-items-center">
<img th:src="|${downpath}/${event.eimg}|" height="40px" width="40px" class="me-3">
<input type="text" class="form-control form-control-lg me-2" id="colFormLabelLg"
th:value="${event.etitle}" disabled>
</th:block>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>
사진 업데이트
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<input type="text" id="colFormLabelLg" th:value="${#authentication.name}" disabled>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#staticBackdrop">
새 행사 등록
</button>
</div>
<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h1 class="modal-title fs-5" id="staticBackdropLabel">새 행사 등록</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form action="/event/create" method="post">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<div class="input-group mb-3">
<label for="colFormLabelLg" class="col-sm-2 col-form-label col-form-label-lg">행사명 </label>
<input type="text" name="etitle" class="form-control form-control-lg" id="colFormLabelLg" placeholder="행사명을 입력하세요">
</div>
<div class="input-group mb-3">
QT 코드는 먼저 행사를 등록하여 id를 생성한 후 수정을 통해 사진으로 추가합니다.
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark" data-bs-dismiss="modal">취소</button>
<input type="submit" class="btn btn-primary" value="등록">
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<th:block th:each="event: ${events}">
<div class="row mt-3">
<label for="colFormLabelLg" class="col-sm-1 col-form-label col-form-label-lg"></label>
<div class="col-sm-10 d-flex align-items-center">
<img th:src="|${downpath}/${event.eimg}|" height="50px" width="50px" class="me-3">
<input type="text" class="form-control form-control-lg me-2" id="colFormLabelLg"
th:value="${event.etitle}" disabled>
<button type="button" class="btn btn-danger me-2" style="width: 100px;">삭제</button>
<button type="button" class="btn btn-primary me-2" style="width: 100px;"data-bs-toggle="modal" data-bs-target="#exampleModal"
th:data-bs-eid="${event.eid}" th:data-bs-whatever="${event.etitle}">수정</button>
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-primary text-white">
<h1 class="modal-title fs-5" id="exampleModalLabel">행사 수정</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form action="/event/update" method="post" enctype="multipart/form-data">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<div class="mb-3">
<label for="eid-name" class="col-form-label">행사 번호:</label>
<input type="text" name="eid" class="form-control bg-light text-black" id="modal-eid" readonly>
</div>
<div class="mb-3">
<label for="recipient-name" class="col-form-label">행사 제목:</label>
<input type="text" name="etitle" class="form-control" id="modal-etitle" th:value="${event.etitle}">
</div>
<div class="mb-3">
<label for="message-text" class="col-form-label">QR Code: 아래 주소를 복사해서 QRCode 를 만들어 첨부하세요.<br>
http://localhost:8080/event/[[${event.eid}]] <a href="https://qr.naver.com/create" target="_blank">QR만들기</a></label>
<input name="image" type="file" />
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">취소</button>
<input type="submit" class="btn btn-primary" value="수정">
</div>
</form>
</div>
</div>
</div>
<button type="button" class="btn btn-success me-2" style="width: 100px;">보기</button>
</th:block>
<script>
const exampleModal = document.getElementById('exampleModal')
if (exampleModal) {
exampleModal.addEventListener('show.bs.modal', event => {
// Button that triggered the modal
const button = event.relatedTarget
// Extract info from data-bs-* attributes
const recipient = button.getAttribute('data-bs-whatever')
const eid = button.getAttribute('data-bs-eid')
// If necessary, you could initiate an Ajax request here
// and then do the updating in a callback.
// Update the modal's content.
const modalTitle = exampleModal.querySelector('.modal-title')
const modalBodyEid = document.getElementById('modal-eid')
const modalBodyInput = document.getElementById('modal-etitle')
modalTitle.textContent = `행사 수정`
modalBodyEid.value = eid
modalBodyInput.value = recipient
})
}
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>
EventController.java
EventService.java
삭제
<button type="button" class="btn btn-danger me-2" style="width: 100px; "data-bs-toggle="modal" data-bs-target="#deleteModal"
th:data-bs-eid="${event.eid}" th:data-bs-whatever="${event.etitle}">삭제</button>
<!-- 삭제 모달 버튼 시작 -->
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-danger text-white">
<h1 class="modal-title fs-5" id="exampleModalLabel">행사 삭제</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form action="/event/delete" method="post">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<div class="mb-3">
<label for="eid-name" class="col-form-label">행사 번호:</label>
<input type="text" name="eid" class="form-control bg-light text-black" id="delete-modal-eid" readonly>
</div>
<div class="mb-3">
<label for="recipient-name" class="col-form-label">행사 제목:</label>
<input type="text" name="etitle" class="form-control" id="delete-modal-etitle">
</div>
<div class="mb-3">
<p>한 번 삭제하신 행사는 다시 복구 하실 수 없습니다. 신중하게 결정하시 바랍니다.
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">취소</button>
<input type="submit" class="btn btn-danger" value="삭제">
</div>
</form>
</div>
</div>
</div>
<!-- 삭제 모달 버튼 끝 -->
controller
@PostMapping("/delete")
public String update(Event event
) {
eventService.delete(event);
return "redirect:/admin";
}
service
public void delete(Event event) {
eventRepository.delete(event);
}