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

[Spring Boot] ํšŒ์›๊ฐ€์ž…/ ํšŒ์›์ •๋ณด์ˆ˜์ •/ ํšŒ์›ํƒˆํ‡ด/ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ

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

 

 

 

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

 

 

 

 

Spring Boot๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํšŒ์›๊ฐ€์ž…/ ํšŒ์›์ •๋ณด์ˆ˜์ •/ ํšŒ์›ํƒˆํ‡ด/ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

ํšŒ์›๊ฐ€์ž…

 

 

ํšŒ์›์ •๋ณด์ˆ˜์ • / ํšŒ์›ํƒˆํ‡ด

 

 

๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ

 

 

 

 

 

[ํšŒ์›๊ฐ€์ž…]

- ์ด์šฉ์•ฝ๊ด€ ํ•„์ˆ˜์‚ฌํ•ญ ๋™์˜, ์•„์ด๋”” ์ค‘๋ณตํ™•์ธ, ์ด๋ฉ”์ผ ์ธ์ฆ์„ ์™„๋ฃŒํ•ด์•ผ ํšŒ์›๊ฐ€์ž… ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™” ๋ฉ๋‹ˆ๋‹ค.

- ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ†ตํ•ด ํ•œ๊ธ€, ์˜์–ด๋ฅผ ์ž…๋ ฅํ•ด์•ผ ์ด๋ฆ„์„ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

- ๋น„๋ฐ€๋ฒˆํ˜ธ ์กฐ๊ฑด(์˜์–ด, ์ˆซ์ž)๋ฅผ ์ถฉ์กฑํ•ด์•ผ ๊ฐ€์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋ฐ์ดํ„ฐ ์ €์žฅ์€ h2 database ์ด์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

 

https://www.h2database.com/html/main.html

 

H2 Database Engine

H2 Database Engine Welcome to H2, the Java SQL database. The main features of H2 are: Very fast, open source, JDBC API Embedded and server modes; in-memory databases Browser based Console application Small footprint: around 2.5 MB jar file size     Supp

www.h2database.com

 

 

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

 

 

UserController.java

 

package com.example.board.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpSession;

import com.example.board.model.CarType;
import com.example.board.model.Company;
import com.example.board.model.Coupon;
import com.example.board.model.Membership;
import com.example.board.model.User;
import com.example.board.repository.CarTypeRepository;
import com.example.board.repository.CompanyRepository;
import com.example.board.repository.CouponRepository;
import com.example.board.repository.MembershipRepository;
import com.example.board.repository.UserRepository;

@Controller
public class UserController {
	@Autowired
	UserRepository userRepository;

	@Autowired
	HttpSession session;

	@Autowired
	PasswordEncoder passwordEncoder;

	@Autowired
	CarTypeRepository carTypeRepository;

	@Autowired
	CompanyRepository companyRepository;

	@Autowired
	CouponRepository couponRepository;

	@Autowired
	MembershipRepository membershipRepository;

	@GetMapping("/email-check")
	@ResponseBody
	public String emailCheck(@ModelAttribute User user) {
		String email = user.getEmail();

		User result = userRepository.findByEmail(email);

		if (result != null) { // ๊ฐ’ ์žˆ์Œ, ์•„์ด๋””๊ฐ€ ์žˆ์Œ, ๊ฐ€์ž… ๋ถˆ๊ฐ€
			return "๊ฐ€์ž…๋ถˆ๊ฐ€";
		} else { // ๊ฐ’ ์—†์Œ, ์•„์ด๋””๊ฐ€ ์—†์Œ, ๊ฐ€์ž… ๊ฐ€๋Šฅ
			return "๊ฐ€์ž…๊ฐ€๋Šฅ";
		}
	}

	@GetMapping("/signin")
	public String signin() {

		return "signin";
	}

	@PostMapping("/signin")
	public String signinPost(@ModelAttribute User user, Model model) {
		User dbUser = userRepository.findByEmail(user.getEmail());

		// ์˜ค๋ฅ˜
		if (dbUser == null) {
			model.addAttribute("error", "์ด๋ฉ”์ผ ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
			return "signin";
		}
		String encodedPwd = dbUser.getPwd();
		String userPwd = user.getPwd();
		boolean isMatch = passwordEncoder.matches(userPwd, encodedPwd);

		if (isMatch) {
			// ๋กœ๊ทธ์ธ ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ
			session.setAttribute("user_info", dbUser);

			// ๋ฉค๋ฒ„์‹ญ ์ •๋ณด
			List<Membership> memberships = membershipRepository.findByUser(dbUser);
			if (memberships != null && !memberships.isEmpty()) {
				session.setAttribute("has_membership", true);
			} else {
				session.setAttribute("has_membership", false);
			}

			return "redirect:/";
		} else {
			model.addAttribute("error", "์ด๋ฉ”์ผ ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
			return "signin";
		}
	}

	@GetMapping("/signout")
	public String signout() {
		session.invalidate();
		return "redirect:/";
	}

	@GetMapping("/signup")
	public String signup(Model model) {
		List<CarType> carTypes = carTypeRepository.findAll();
		model.addAttribute("carTypes", carTypes);
		List<Company> companys = companyRepository.findAll();
		model.addAttribute("companys", companys);
		return "signup";
	}

	@PostMapping("/signup")
	public String signupPost(@ModelAttribute User user,
			@RequestParam(value = "isAdmin", required = false) boolean isAdmin,
			@RequestParam("carname") String carname) {
		String userPwd = user.getPwd();
		String encodePwd = passwordEncoder.encode(userPwd);
		user.setPwd(encodePwd);
		user.setCreDate(new Date());

		// ์‚ฌ์šฉ์ž ์—ญํ•  ์„ค์ •
		User.UserRole userRole = isAdmin ? User.UserRole.ADMIN : User.UserRole.CUSTOMER;

		// ์‚ฌ์šฉ์ž ์ •๋ณด ์ €์žฅ
		user.setRole(userRole);
		user.setCarname(carname);
		user.setCoin(0);
		user.setCoinDate(new Date(0));

		userRepository.save(user);

		// User ์ˆ˜ ์ฆ๊ฐ€
		List<User> users = userRepository.findAll();
		int userCount = users.size();
		userCount++;
		for (User u : users) {
			u.setCount(userCount);
		}
		userRepository.saveAll(users);

		return "redirect:/";
	}

	@GetMapping("/mypage")
	public String mypage(Model model, @RequestParam String email) {
		User opt = userRepository.findByEmail(email);
		model.addAttribute("user", opt);
		User user = (User) session.getAttribute("user_info");
		if (user != null) {
			int userCoins = user.getCoin();
			
			model.addAttribute("userCoin", userCoins);
		}

		return "mypage";
	}

	@PostMapping("/mypage")
	public String updatePost(@ModelAttribute User user) {
		User sessionUser = (User) session.getAttribute("user_info");

		long id = sessionUser.getId();
		User dbUser = userRepository.findById(id);

		String userPwd = user.getPwd();
		String dbPwd = dbUser.getPwd();
		String encodedPwd = passwordEncoder.encode(userPwd);
		if (userPwd.equals(dbPwd)) {
			encodedPwd = userPwd;
		}
		user.setPwd(encodedPwd);
		user.setCreDate(new Date());

		userRepository.save(user);
		return "/signin";
	}

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

	@GetMapping("/getCarType")
	@ResponseBody
	public List<CarType> getCarType(String companyName) {
		Company company = companyRepository.findByCompanyName(companyName);
		List<CarType> carTypes = carTypeRepository.findByCompany(company);
		return carTypes;
	}

	// ํƒˆํ‡ดํ•˜๊ธฐ
	@GetMapping("/exit")
	public String exit() {
		User user = (User) session.getAttribute("user_info");
		userRepository.delete(user);
		session.invalidate();

		return "redirect:/";
	}

	// ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝํ•˜๊ธฐ
	@GetMapping("/pwdforget")
	public String pwdforget() {
		return "/pwdforget";
	}

	@PostMapping("/pwdforget")
	@ResponseBody
	public String pwdforgetPost(@RequestBody User user) {
		// ์„ธ์…˜์—์„œ ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
    User sessionUser = (User) session.getAttribute("user");
		if (sessionUser != null) {
			String newPassword = user.getNewPassword();
			if (newPassword != null && !newPassword.isEmpty()) {
					String hashedPassword = passwordEncoder.encode(newPassword);
					sessionUser.setPwd(hashedPassword);
					userRepository.save(sessionUser);
					return "๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.";
			} else {
					return "๋น„๋ฐ€๋ฒˆํ˜ธ ๊ฐ’์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž…๋ ฅํ•˜์‹ญ์‹œ์˜ค.";
			}
	}
	return "๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ์— ์‹คํŒจํ•˜์…จ์Šต๋‹ˆ๋‹ค.";
	
	}
	
	// ๋ณธ์ธ ์ธ์ฆํ•˜๊ธฐ
	@PostMapping("/validateUser")
	public ResponseEntity<Map<String, Boolean>> validateUser(@RequestBody User user) {
		String email = user.getEmail();
		String name = user.getName();
		Integer phone = user.getPhone();
		List<User> resultList = userRepository.findByEmailAndNameAndPhone(email, name, phone);

		Map<String, Boolean> response = new HashMap<>();
		if (!resultList.isEmpty()) {
			response.put("isValid", true);
			// ์„ธ์…˜์— ์‚ฌ์šฉ์ž ์ •๋ณด ์ €์žฅ
			session.setAttribute("user", resultList.get(0));
		} else {
			response.put("isValid", false);
		}

		return ResponseEntity.ok(response);
	}

}

 

Mailer.java

 

package com.example.board.email;

import java.util.Properties;
import java.util.Random;

import javax.servlet.http.HttpSession;

import javax.mail.Address;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpSession;

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;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class Mailer {
  @Autowired
	HttpSession session;

@GetMapping("/emailcode")
@ResponseBody
  public void sendMail(
    SMTPAuthenticator smtp , @RequestParam String email){
     
        
        String content = Long.toString(Math.abs(new Random().nextLong()),36).substring(0,4);
    Properties p = new Properties();
    p.put("mail.smtp.host", "smtp.gmail.com");
    p.put("mail.smtp.port", "465");
    p.put("mail.smtp.starttls.enable", "true");
    p.put("mail.smtp.auth", "true");
    p.put("mail.smtp.debug", "true");
    p.put("mail.smtp.socketFactory.port", "465");
    p.put("mail.smtp.socketFactory.class", "javax.net.ssl.");
    p.put("mail.smtp.socketFactory.fallback", "false");
    try {
      Session ses = Session.getInstance(p, smtp);
      ses.setDebug(true);
      MimeMessage msg = new MimeMessage(ses); // ๋ฉ”์ผ์˜ ๋‚ด์šฉ์„ ๋‹ด์„ ๊ฐ์ฒด
      msg.setSubject("pika์ถฉ์ „์†Œ ํšŒ์›๊ฐ€์ž… ๋ณธ์ธ ์ธ์ฆ"); // ์ œ๋ชฉ
      Address fromAddr = new InternetAddress("์ด๋ฉ”์ผ");
      msg.setFrom(fromAddr); // ๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ
      Address toAddr = new InternetAddress(email);
      msg.addRecipient(Message.RecipientType.TO, toAddr); // ๋ฐ›๋Š” ์‚ฌ๋žŒ
      msg.setContent(content, "text/html;charset=UTF-8"); // ๋‚ด์šฉ๊ณผ ์ธ์ฝ”๋”ฉ
      Transport.send(msg); // ์ „์†ก
    } catch (Exception e) {
      e.printStackTrace();
    }
    session.setAttribute("code",content);
  }
  @GetMapping("emailcode-check")
  @ResponseBody
  public String codecheck(@RequestParam String emailcode){
    Object code = session.getAttribute("code");
    System.out.println(code);
    System.out.println(emailcode);
    if(code.equals(emailcode) ){
      System.out.println("yes");
      return "์ฝ”๋“œ์ผ์น˜";
    }else{
      System.out.println("no");
      return "์ฝ”๋“œ๋ถˆ์ผ์น˜";
    }
  }
}

 

 

SMTPAuthenticator.java

 

package com.example.board.email;

import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;

public class SMTPAuthenticator extends Authenticator {
  @Override
  protected PasswordAuthentication getPasswordAuthentication() {
    return new PasswordAuthentication(
        "์ด๋ฉ”์ผ", "ํ‚ค");
  }
}

 

 

SignInCheckInterceptor.java

 

package com.example.board.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.example.board.model.User;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class SignInCheckInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(
            HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {
        log.debug("preHandle");
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user_info");
        if (user == null) {
            response.sendRedirect("/loginnoti");
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(
            HttpServletRequest request, HttpServletResponse response,
            Object handler, ModelAndView modelAndView) throws Exception {
        log.debug("postHandle");
    }

    @Override
    public void afterCompletion(
            HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex) throws Exception {
        log.debug("afterCompletion");
    }
}

 

 

User.java

 

package com.example.board.model;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

import lombok.Data;

@Entity
@Data
public class User implements Serializable {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	private String email;
	private String pwd;
	private String name;
	private Integer phone;
	private Date creDate;
	private String carname;
	@Column(nullable = true)
	private Integer count;
	private UserRole role;

	public enum UserRole {
		CUSTOMER, // ์ผ๋ฐ˜ ๊ณ ๊ฐ0
		ADMIN // ๊ด€๋ฆฌ์ž1
	}

	public String getRole() {
		return role.name(); // ์—ด๊ฑฐํ˜• ๊ฐ’์˜ ์ด๋ฆ„์„ ๋ฌธ์ž์—ด๋กœ ๋ฐ˜ํ™˜
	}

	private Integer coin;
  private Date coinDate;
	private String newPassword;
	
	@OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.EAGER)
	List<Board> boards = new ArrayList<>();

	@OneToMany(mappedBy = "user")
    private List<Membership> memberships;

	@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	private List<Coupon> coupons;
}

 

 

UserRepository.java

 

package com.example.board.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import com.example.board.model.User;


public interface UserRepository extends JpaRepository<User, Long> {
  public User findByEmailAndPwd(String email, String pwd);
  public User findByEmail(String email);
  public User findById(long id);
  List<User> findByEmailAndNameAndPhone(String email,String name, Integer phone);
}

 

loginnoti.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;
    /* ์ด๋ฏธ์ง€ ๋ฐ˜๋ณต์„ ์ค‘์ง€ */
  }
  .btn {
    background-color: rgb(228, 179, 93);
    border-color: rgb(228, 179, 93);
  }

  .btn:hover {
    background-color: rgb(228, 179, 93);
    border-color: rgb(228, 179, 93);
  }
</style>

<body>

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

  </div>

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

  </nav>

  <div class="container mt-5">
    <div class="row">

      <div class="d-grid gap-2 text-center">
        <h1>๋กœ๊ทธ์ธ ํ›„ ์‚ฌ์šฉํ•ด์ฃผ์„ธ์š”๐Ÿฆ–</h1>
        <button class="btn btn-primary" id="loginnoti" onclick="loginnoti()">๋กœ๊ทธ์ธํŽ˜์ด์ง€๋กœ ์ด๋™</button>
      </div>

    </div>
  </div>

  <div th:replace="common/footer">
  </div>
  <script>
    function loginnoti() {
      location = '/signin';
    }
  </script>

</body>

</html>

 

mypage.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;
    /* ์ด๋ฏธ์ง€ ๋ฐ˜๋ณต์„ ์ค‘์ง€ */
  }

  .change-color {
    background-color: #ffed91;
    border-color: #ffed91;
    text-decoration: none;
    color: black;
  }

  .change-color:hover {
    color: black;
    background-color: #fff9cd;
    border-color: #fff9cd;
  }

  .exit {
    display: flex;
    justify-content: center;
    color: black;
    text-decoration: none;
    width: 200px;
  }

  .exit-link {
    display: grid !important;
    justify-content: center;
    margin-top: 50px;
  }
  .card {
    padding: 2rem;
  }
</style>

<body>

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

  </div>

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

  </nav>

  <div class="container mt-5">
    <div class="card">
      <div class="row">
        <form method="post" action="/mypage">
          <div class="mb-3">
            <input type="hidden" id="id" name="id" th:value="${user.id}">
            <label for="email">Email:</label>
            <input type="text" class="form-control" id="email" name="email" th:value="${user.email}" readonly>
          </div>
          <div class="mb-3">
            <label for="pwd">Password:</label>
            <input type="password" class="form-control" id="pwd" name="pwd" th:value="${user.pwd}" readonly hidden>
          </div>
          <div class="mb-3">
            <label for="name">Name:</label>
            <input type="text" class="form-control" id="name" name="name" th:value="${user.name}">
          </div>
          <div class="mb-3">
            <label for="phone">Phone:</label>
            <input type="text" class="form-control" id="phone" name="phone" th:value="${user.phone}">
          </div>
          <div class="mb-3">
            <label for="car">My Car:</label>
            <input type="text" class="form-control" id="car" name="car" th:value="${user.carname}">
          </div>
          <div class="d-grid gap-2">
            <button class="btn btn-primary change-color" id="update" th:onclick="mypage()">ํšŒ์›์ •๋ณด ์ˆ˜์ •</button>
          </div>
          <input type="hidden" id="coin" name="coin" th:value="${user.coin}">
          <!-- <input type="hidden" id="coinDate" name="coinDate" th:value="${user.coinDate}"> -->
          <input type="hidden" id="count" name="count" th:value="${user.count}">
          <!-- <input type="hidden" id="creDate" name="creDate" th:value="${user.creDate}"> -->
          <input type="hidden" id="role" name="role" th:value="${user.role}">
          <input type="hidden" id="newPassword" name="newPassword" th:value="${user.newPassword}">
        </form>
        <div class="exit-link">
          <button class="exit" id="exit" th:onclick="confirmDeletion()">ํšŒ์›ํƒˆํ‡ด</button>
        </div>
      </div>
    </div>
  </div>

  <div th:replace="common/footer">
  </div>
  <script>
    function confirmDeletion() {
      if (confirm("์ •๋ง๋กœ ํšŒ์›ํƒˆํ‡ด๋ฅผ ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?")) {
        location.href = "/exit";
      }
    }
    function mypage() {
       // ํผ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘
        var formData = {
        id: document.getElementById("id").value,
        email: document.getElementById("email").value,
        name: document.getElementById("name").value,
        phone: document.getElementById("phone").value,
        car: document.getElementById("car").value
    };

    // AJAX ์š”์ฒญ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ ์ „์†ก
    $.ajax({
        type: "POST",
        url: "/mypage",
        data: formData,
        success: function (response) {
            // ์ˆ˜์ • ์„ฑ๊ณต ์‹œ ์ฒ˜๋ฆฌ
            alert("ํšŒ์› ์ •๋ณด๊ฐ€ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
            location.reload();  // ํŽ˜์ด์ง€ ์ƒˆ๋กœ๊ณ ์นจ ๋˜๋Š” ๋ฆฌ๋””๋ ‰์…˜
        }
    });
    }
  </script>
</body>

</html>

 

 

pwdforget.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;
    /* ์ด๋ฏธ์ง€ ๋ฐ˜๋ณต์„ ์ค‘์ง€ */
  }

  .btnn-primary {
    background-color: #f2f5c0;
    border-color: #f2f5c0;
    color: black;
  }
  .btnn-primary:hover{
    background-color: #e2ce38;
    border-color: #e2ce38;
    color: black;
  }
  

  #pwd i .eyes {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    margin: auto 2px;
    height: 30px;
    font-size: 22px;
    cursor: pointer;
    color: white;
  }

  label {
    color: white
  }

  .fa-eye:before {
    content: "\f06e";
    color: white;
  }

  .fa-eye-slash:before {
    content: "\f070";
    color: white;
  }

  /* modal */
  .modal {
    display: none;
    position: fixed;
    z-index: 1;
    padding-top: 100px;
    font-family: 'TheJamsil5Bold';
  }

  .modal-content {
    background-color: #fefefe;
    margin: auto;
    width: 600px;
    padding: 30px;
    color: black;
    overflow-y: scroll;
  }

  .close {
    color: #aaaaaa;
  }

  .subscribe-title {
    text-align: center;
    font-size: 30px;
    margin-bottom: 50px;
  }

  .subscribe-content {
    text-align: center;
    font-size: 15px;
    margin-bottom: 20px;
  }

  .content-info {
    text-align: center;
    margin-top: 2px;
    font-weight: bold;
    font-size: large;
  }

  .modal2 {
    font-size: 22px;
  }
  
</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="/pwdforget">
        <div class="mb-3">
          <label for="email">Email:</label>
          <input type="email" class="form-control" id="email" name="email" pattern="[a-z0-9._+-]+@[a-z]+\.[a-z]{2,}$"
            title=" ์ •ํ™•ํ•œ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”" placeholder="ex.daram@dotori.com" required>
        </div>
        <div class="mb-3">
          <label for="name">Name:</label>
          <input type="text" class="form-control" id="name" name="name" pattern="^[๊ฐ€-ํžฃ]+$" title="์˜ฌ๋ฐ”๋ฅธ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š” ex.ํ™๊ธธ๋™"
            placeholder="์ด๋ฆ„" required>
        </div>
        <div class="mb-3">
          <label for="name">Phone:</label>
          <input type="text" class="form-control" id="phone" name="phone" pattern="[0-9]{10,11}"
            title="10-11์ž๋ฆฌ์˜ ์ˆซ์ž๋ฅผ '-' ์—†์ด ์ž…๋ ฅํ•˜์„ธ์š”" placeholder="ํœด๋Œ€์ „ํ™”๋ฒˆํ˜ธ('-'๊ธฐํ˜ธ ์ œ์™ธ 10~11์ž๋ฆฌ)" required>
        </div>
        <div class="d-grid gap-2">
          <button type="button" class="btn btnn-primary" id="signup" onclick="validateUser()" >๋ณธ์ธ ์ธ์ฆํ•˜๊ธฐ</button>
        </div>
        <div id="error-message1" class="d-none" style="color: red; margin: 10px;">
          <p>์ž…๋ ฅํ•˜์‹  ์ •๋ณด์™€ ์ผ์น˜ํ•˜๋Š” ์‚ฌ์šฉ์ž๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.</p>
        </div>
        <div id="change-password-form" class="d-none">
          <div class="mb-3">
            <label for="pwd">New Password:</label>
            <input type="password" class="form-control" id="newPassword" name="newPassword"
              pattern="(?=.*\d)(?=.*[a-zA-Z]).{8,}" title="์˜๋ฌธ๋Œ€์†Œ๋ฌธ์ž/์ˆซ์ž๋กœ ์ด๋ฃจ์–ด์ง„ ์ตœ์†Œ 8๊ธ€์ž์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”"
              placeholder="์ƒˆ๋กœ์šด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”" required>
            <i class="fa fa-eye fa-lg eyes" th:attr="onclick='togglePasswordVisibility()'"></i>
          </div>
          <div class="d-grid gap-2">
            <button type="button" class="btn btnn-primary" id="changePassword">๋น„๋ฐ€๋ฒˆํ˜ธ
              ๋ณ€๊ฒฝ</button>
          </div>
        </div>

        <!-- <div id="error-message1" class="d-none" style="color: red; margin: 10px;">
          <p>์ž…๋ ฅํ•˜์‹  ์ •๋ณด์™€ ์ผ์น˜ํ•˜๋Š” ์‚ฌ์šฉ์ž๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.</p>
        </div> -->
        <!-- <div id="error-message2" class="d-none" style="color: red; margin: 10px;">
          <p>๋น„๋ฐ€๋ฒˆํ˜ธ ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜๋ฌธ๋Œ€์†Œ๋ฌธ์ž/์ˆซ์ž๋กœ ์ด๋ฃจ์–ด์ง„ ์ตœ์†Œ 8๊ธ€์ž์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”.</p>
        </div> -->
      </form>

    </div>
  </div>
  <script>
    //๋ณธ์ธ ์ธ์ฆ
    function validateUser() {
      var email = document.getElementById('email').value;
      var name = document.getElementById('name').value;
      var phone = document.getElementById('phone').value;

      // AJAX ์š”์ฒญ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„์— ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๊ฐ€ ์œ ํšจํ•œ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
      $.ajax({
        url: '/validateUser',
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({
          email: email,
          name: name,
          phone: phone
        }),
        success: function (response) {
          if (response.isValid) {
            // ์œ ํšจํ•˜๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ํผ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
            document.getElementById('error-message1').classList.add('d-none');
            document.getElementById('change-password-form').classList.remove('d-none');
          } else {
            // ์œ ํšจํ•˜์ง€ ์•Š์œผ๋ฉด ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
            document.getElementById('error-message1').classList.remove('d-none');
          }
        }
      });
    }

    //๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ
    const changeBtn = document.querySelector('#changePassword')
    changeBtn.addEventListener('click', changePassword);
    function changePassword() {
      var email = document.getElementById('email').value;
      var name = document.getElementById('name').value;
      var phone = document.getElementById('phone').value;
      var newPassword = document.getElementById('newPassword').value;
      console.log(newPassword);

      //data ์†์„ฑ์„ ํ†ตํ•ด ๋‚ด์šฉ์„ ์„œ๋ฒ„๋กœ ์ „๋‹ฌ
      $.ajax({
        url: '/pwdforget',
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({
          email: email,
          name: name,
          phone: phone,
          newPassword: newPassword
        }),
        success: function (response) {
          // ์„œ๋ฒ„์—์„œ ์‘๋‹ต์ด ์˜ค๋ฉด, ์„ฑ๊ณต ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
          alert(response);
          location = '/signin';
        },
        error: function (error) {
          // ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ, ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
          alert("์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: " + error.responseText);
        }
      });
    }
    

    // ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณด์ด๊ธฐํ‘œ์‹œ
    function togglePasswordVisibility() {
      var $passwordInput = $('#newPassword'); // ID๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ๋ž€์„ ์„ ํƒ
      if ($passwordInput.attr('type') === 'password') {
        $('.eyes').removeClass('fa-eye').addClass('fa-eye-slash');
        $passwordInput.attr('type', 'text');
      } else {
        $('.eyes').removeClass('fa-eye-slash').addClass('fa-eye');
        $passwordInput.attr('type', 'password');
      }
    }

  </script>
  </div>

  <div th:replace="common/footer" style="margin-top: 1rem;">
  </div>

</body>

</html>

 

 

signin.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;
    /* ์ด๋ฏธ์ง€ ๋ฐ˜๋ณต์„ ์ค‘์ง€ */
  }
  .btn-primary {
    background-color: #f2f5c0;
    border-color: #f2f5c0;
    color: black;
  }
  .btn-primary:hover{
    background-color: #e2ce38;
    border-color: #e2ce38;
    color: black;
  }
  
  #pwd{
  border-top-right-radius: 4px;
  border-bottom-right-radius: 4px;
 }

  .form-control{
  position: relative;
  padding-right: 40px;
  z-index: 1;
  }
  .form-control:disabled {
    z-index: 1; /* ๋น„ํ™œ์„ฑํ™”๋œ ์ž…๋ ฅ๋ž€์˜ ์Šคํƒ€์ผ๋„ ๋ฎ์–ด์“ฐ๊ธฐ ์œ„ํ•ด z-index ์„ค์ • */
  }
  .eyes {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    right: 10px;
    cursor: pointer;
    z-index: 2 ; 
  }
  .form-control:focus + .eyes {
    z-index: 3 ; /* ํฌ์ปค์Šค๋œ ์ž…๋ ฅ๋ž€๊ณผ ์—ฐ๊ฒฐ๋œ ๋ˆˆ ๋ชจ์–‘ ์•„์ด์ฝ˜์„ ๋” ๋†’์€ z-index๋กœ ์„ค์ •ํ•˜์—ฌ ํฌ์ปค์Šค ์‹œ ์œ„๋กœ ์˜ค๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. */
  }
  .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">
      <form method="post" action="/signin">
        <div class="mb-3 input-group flex-nowrap">
          <span class="input-group-text">๐Ÿ’ป</span>
          <input type="email" class="form-control" id="email" name="email" placeholder="email" title="์ด๋ฉ”์ผ ํ˜•์‹์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค" required>
        </div>
        <div class="mb-3 input-group flex-nowrap">
          <span class="input-group-text">๐Ÿ”’</span>
          <input type="password" class="form-control" id="pwd" name="pwd" placeholder="password" required>
          <i class="fa fa-eye fa-lg eyes" th:attr="onclick='togglePasswordVisibility()'"></i>
        </div>
        <div th:if="${error}" class="alert alert-danger">
          <p th:text="${error}"></p>
        </div>
        <div class="d-grid gap-2">
          <button class="btn btn-primary" id="signin">๋กœ๊ทธ์ธ</button>
        </div>
        <div class="d-grid gap-2">
          <a class="pwdforget" id="pwdforget" href="/pwdforget" style=" color: rgb(22, 208, 255); padding: 20px 5px;">๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๊ธฐ์–ต๋‚˜์ง€ ์•Š๋Š”๋‹ค๋ฉด?</a>
        </div>
      </form>
    </div>
  </div>

  <script>
    function togglePasswordVisibility() {
      var $passwordInput = $('#pwd');
      if ($passwordInput.attr('type') === 'password') {
          $('.eyes').removeClass('fa-eye').addClass('fa-eye-slash');
          $passwordInput.attr('type', 'text');
      } else {
          $('.eyes').removeClass('fa-eye-slash').addClass('fa-eye');
          $passwordInput.attr('type', 'password');
      }
  }
  </script>
</body>

</html>

 

 

 

signup.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;
    /* ์ด๋ฏธ์ง€ ๋ฐ˜๋ณต์„ ์ค‘์ง€ */
  }

  .btnn-primary {
    background-color: #f2f5c0;
    border-color: #f2f5c0;
    color: black;
  }
  .btnn-primary:disabled{
    background-color: #f2f5c0;
    border-color: #f2f5c0;
    color: black;
    
  }
  .btnn-primary:hover{
    background-color: #e2ce38;
    border-color: #e2ce38;
    color: black;
  }

  #pwd i .eyes {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    margin: auto 2px;
    height: 30px;
    font-size: 22px;
    cursor: pointer;
    color: white;
  }

  label {
    color: white
  }

  .fa-eye:before {
    content: "\f06e";
    color: white;
  }

  .fa-eye-slash:before {
    content: "\f070";
    color: white;
  }

  /* modal */
  .modal {
    display: none;
    position: fixed;
    z-index: 1;
    padding-top: 100px;
    font-family: 'TheJamsil5Bold';
  }

  .modal-content {
    background-color: #fefefe;
    margin: auto;
    width: 600px;
    padding: 30px;
    color: black;
    overflow-y: scroll;
  }

  .close {
    color: #aaaaaa;
  }

  .subscribe-title {
    text-align: center;
    font-size: 30px;
    margin-bottom: 50px;
  }

  .subscribe-content {
    text-align: center;
    font-size: 15px;
    margin-bottom: 20px;
  }

  .content-info {
    text-align: center;
    margin-top: 2px;
    font-weight: bold;
    font-size: large;
  }

  .modal2 {
    font-size: 22px;
  }

  .mb-3 {
    width: 50%;
  }
  .btn-gradient {
        text-decoration: none;
        color: white;
        padding: 10px 30px;
        display: inline-block;
        position: relative;
        border: 1px solid rgba(0, 0, 0, 0.21);
        border-bottom: 4px solid rgba(0, 0, 0, 0.21);
        border-radius: 4px;
        text-shadow: 0 1px 0 rgba(0, 0, 0, 0.15);
    }

    .btn-gradient.yellow {
        background: rgba(240, 210, 100, 1);
        background: -webkit-gradient(linear, 0 0, 0 100%, from(rgba(240, 210, 100, 1)), to(rgba(229, 201, 96, 1)));
        background: -webkit-linear-gradient(rgba(240, 210, 100, 1) 0%, rgba(229, 201, 96, 1) 100%);
        background: -moz-linear-gradient(rgba(240, 210, 100, 1) 0%, rgba(229, 201, 96, 1) 100%);
        background: -o-linear-gradient(rgba(240, 210, 100, 1) 0%, rgba(229, 201, 96, 1) 100%);
        background: linear-gradient(rgba(240, 210, 100, 1) 0%, rgba(229, 201, 96, 1) 100%);
        filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f0d264', endColorstr='#e5c960', GradientType=0);
    }

  /* joinForm */
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box
  }

  ul>li {
    list-style: none
  }

  a {
    text-decoration: none;
  }

  .clearfix::after {
    content: "";
    display: block;
    clear: both;
  }

  #joinForm {
    width: 460px;
    margin:  auto;
  }

  ul.join_box {
    border: 2px solid #ddd;
    background-color: #fff;
    width:500px;
    padding-inline-start:40px;
    padding-inline-end:40px;
  }

  .checkBox,
  .checkBox>ul {
    position: relative;
  }

  .checkBox>ul>li {
    float: left;
  }

  .checkBox>ul>li:first-child {
    width: 85%;
    padding: 15px;
    font-weight: 600;
    color: #888;
  }

  .checkBox>ul>li:nth-child(2) {
    position: absolute;
    top: 50%;
    right: 30px;
    margin-top: -12px;
  }

  .checkBox textarea {
    width: 96%;
    height: 90px;
    margin: 0 2%;
    background-color: #f7f7f7;
    color: #888;
    border: none;
  }

  .footBtwrap {
    margin-top: 15px;
  }

  .footBtwrap>li {
    float: left;
    width: 50%;
    height: 60px;
  }

  .footBtwrap>li>button {
    display: block;
    width: 100%;
    height: 100%;
    font-size: 20px;
    text-align: center;
    line-height: 43px;
  }

  .fpmgBt1 {
    background-color: #fff;
    color: #888
  }

  .fpmgBt2 {
    background-color: #f2f5c0;
    color: #171616
  }
  .fpmgBt2:hover {
    background-color: #e2ce38;
    border-color: #e2ce38;
    color: #171616
  }
  .fpmgBt2:disabled {
    background-color: #f2f5c0;
    border-color: #f2f5c0;
    color: #171616
  }

  .signupForm{
    display: flex;
    margin-left: 10rem;
  }
  #realsignupForm{
    display:inline-flex;
    flex-direction: column;
    align-items: center;
  }
  .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="signupForm">
    <form action="" id="joinForm">
      <ul class="join_box">
        <li class="checkBox check01">
          <ul class="clearfix">
            <li>์ด์šฉ์•ฝ๊ด€, ๊ฐœ์ธ์ •๋ณด ์ˆ˜์ง‘ ๋ฐ ์ด์šฉ,
              ์œ„์น˜์ •๋ณด ์ด์šฉ์•ฝ๊ด€(์„ ํƒ), ํ”„๋กœ๋ชจ์…˜ ์•ˆ๋‚ด
              ๋ฉ”์ผ ์ˆ˜์‹ (์„ ํƒ)์— ๋ชจ๋‘ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.</li>
            <li class="checkAllBtn">
              <input type="checkbox" name="chkAll" id="chk" class="chkAll" onchange="chkAll(this.checked)">
            </li>
          </ul>
        </li>
        <li class="checkBox check02">
          <ul class="clearfix">
            <li>์ด์šฉ์•ฝ๊ด€ ๋™์˜(ํ•„์ˆ˜)</li>
            <li class="checkBtn">
              <input type="checkbox" name="chk">
            </li>
          </ul>
          <textarea name="" id="">์—ฌ๋Ÿฌ๋ถ„์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.
        Pika ์ถฉ์ „์†Œ ์„œ๋น„์Šค ๋ฐ ์ œํ’ˆ(์ดํ•˜ ‘์„œ๋น„์Šค’)์„ ์ด์šฉํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋ณธ ์•ฝ๊ด€์€ ๋‹ค์–‘ํ•œ Pika ์ถฉ์ „์†Œ ์„œ๋น„์Šค์˜ ์ด์šฉ๊ณผ ๊ด€๋ จํ•˜์—ฌ Pika ์ถฉ์ „์†Œ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” Pika ์ถฉ์ „์†Œ ์ฃผ์‹ํšŒ์‚ฌ(์ดํ•˜ ‘Pika ์ถฉ์ „์†Œ’)์™€ ์ด๋ฅผ ์ด์šฉํ•˜๋Š” Pika ์ถฉ์ „์†Œ ์„œ๋น„์Šค ํšŒ์›(์ดํ•˜ ‘ํšŒ์›’) ๋˜๋Š” ๋น„ํšŒ์›๊ณผ์˜ ๊ด€๊ณ„๋ฅผ ์„ค๋ช…ํ•˜๋ฉฐ, ์•„์šธ๋Ÿฌ ์—ฌ๋Ÿฌ๋ถ„์˜ Pika ์ถฉ์ „์†Œ ์„œ๋น„์Šค ์ด์šฉ์— ๋„์›€์ด ๋  ์ˆ˜ ์žˆ๋Š” ์œ ์ตํ•œ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
        </textarea>
        </li>
        <li class="checkBox check03">
          <ul class="clearfix">
            <li>๊ฐœ์ธ์ •๋ณด ์ˆ˜์ง‘ ๋ฐ ์ด์šฉ์— ๋Œ€ํ•œ ์•ˆ๋‚ด(ํ•„์ˆ˜)</li>
            <li class="checkBtn">
              <input type="checkbox" name="chk">
            </li>
          </ul>

          <textarea name="" id="">๊ฐœ์ธ์ •๋ณด๋ณดํ˜ธ๋ฒ•์— ๋”ฐ๋ผ Pika ์ถฉ์ „์†Œ์— ํšŒ์›๊ฐ€์ž… ์‹ ์ฒญํ•˜์‹œ๋Š” ๋ถ„๊ป˜ ์ˆ˜์ง‘ํ•˜๋Š” ๊ฐœ์ธ์ •๋ณด์˜ ํ•ญ๋ชฉ, ๊ฐœ์ธ์ •๋ณด์˜ ์ˆ˜์ง‘ ๋ฐ ์ด์šฉ๋ชฉ์ , ๊ฐœ์ธ์ •๋ณด์˜ ๋ณด์œ  ๋ฐ ์ด์šฉ๊ธฐ๊ฐ„, ๋™์˜ ๊ฑฐ๋ถ€๊ถŒ ๋ฐ ๋™์˜ ๊ฑฐ๋ถ€ ์‹œ ๋ถˆ์ด์ต์— ๊ด€ํ•œ ์‚ฌํ•ญ์„ ์•ˆ๋‚ด ๋“œ๋ฆฌ์˜ค๋‹ˆ ์ž์„ธํžˆ ์ฝ์€ ํ›„ ๋™์˜ํ•˜์—ฌ ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.์ด์šฉ์ž๋Š” ํšŒ์›๊ฐ€์ž…์„ ํ•˜์ง€ ์•Š์•„๋„ ์ •๋ณด ๊ฒ€์ƒ‰, ๋‰ด์Šค ๋ณด๊ธฐ ๋“ฑ ๋Œ€๋ถ€๋ถ„์˜ Pika ์ถฉ์ „์†Œ ์„œ๋น„์Šค๋ฅผ ํšŒ์›๊ณผ ๋™์ผํ•˜๊ฒŒ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์šฉ์ž๊ฐ€ ๋ฉ”์ผ, ์บ˜๋ฆฐ๋”, ์นดํŽ˜, ๋ธ”๋กœ๊ทธ ๋“ฑ๊ณผ ๊ฐ™์ด ๊ฐœ์ธํ™” ํ˜น์€ ํšŒ์›์ œ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด ํšŒ์›๊ฐ€์ž…์„ ํ•  ๊ฒฝ์šฐ, Pika ์ถฉ์ „์†Œ๋Š” ์„œ๋น„์Šค ์ด์šฉ์„ ์œ„ํ•ด ํ•„์š”ํ•œ ์ตœ์†Œํ•œ์˜ ๊ฐœ์ธ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•ฉ๋‹ˆ๋‹ค.
        </textarea>
        </li>
        <li class="checkBox check03">
          <ul class="clearfix">
            <li>์œ„์น˜์ •๋ณด ์ด์šฉ์•ฝ๊ด€ ๋™์˜(์„ ํƒ)</li>
            <li class="checkBtn">
              <input type="checkbox" name="chk1">
            </li>
          </ul>

          <textarea name="" id="">์—ฌ๋Ÿฌ๋ถ„์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.
            ์œ„์น˜๊ธฐ๋ฐ˜์„œ๋น„์Šค ์ด์šฉ์•ฝ๊ด€์— ๋™์˜ํ•˜์‹œ๋ฉด, ์œ„์น˜๋ฅผ ํ™œ์šฉํ•œ ๊ด‘๊ณ  ์ •๋ณด ์ˆ˜์‹  ๋“ฑ์„ ํฌํ•จํ•˜๋Š” Pika ์ถฉ์ „์†Œ ์œ„์น˜๊ธฐ๋ฐ˜ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์•ฝ๊ด€์€ Pika ์ถฉ์ „์†Œ ์ฃผ์‹ํšŒ์‚ฌ (์ดํ•˜ “ํšŒ์‚ฌ”)๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์œ„์น˜๊ธฐ๋ฐ˜์„œ๋น„์Šค์™€ ๊ด€๋ จํ•˜์—ฌ ํšŒ์‚ฌ์™€ ๊ฐœ์ธ์œ„์น˜์ •๋ณด์ฃผ์ฒด์™€์˜ ๊ถŒ๋ฆฌ, ์˜๋ฌด ๋ฐ ์ฑ…์ž„์‚ฌํ•ญ, ๊ธฐํƒ€ ํ•„์š”ํ•œ ์‚ฌํ•ญ์„ ๊ทœ์ •ํ•จ์„ ๋ชฉ์ ์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.
        </textarea>
        </li>
        <li class="checkBox check04">
          <ul class="clearfix">
            <li>์ด๋ฒคํŠธ ๋“ฑ ํ”„๋กœ๋ชจ์…˜ ์•Œ๋ฆผ ๋ฉ”์ผ ์ˆ˜์‹ (์„ ํƒ)</li>
            <li class="checkBtn">
              <input type="checkbox" name="chk1">
            </li>
          </ul>

        </li>
      </ul>
      <ul class="footBtwrap clearfix">
        <li><button type="button" class="fpmgBt1 btn btnn-primary" onclick="disagreement()">๋น„๋™์˜</button></li>
        <li><button type="button" class="fpmgBt2 btn btnn-primary" onclick="agreement()">๋™์˜</button></li>
      </ul>
    </form>

    <div class="container mt-5">
      <div class="row">
        <form method="post" action="/signup" id="realsignupForm">
          <div class="mb-3">
            <label for="email">Email:</label>
            <input type="email" class="form-control" id="email" name="email" pattern="[a-z0-9._%+-]+@[a-z]+\.[a-z]{2,}$"
              title=" ์ •ํ™•ํ•œ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”" placeholder="ex.daram@dotori.com" required>
            <button class="btn btnn-primary" type="button" onclick="checkEmail()">์ค‘๋ณตํ™•์ธ</button>
            <button class="btn btnn-primary" type="button" onclick="run()">์ด๋ฉ”์ผ ์ธ์ฆ</button>
            <span id="duplicateResult"></span>
          </div>
          <div class="mb-3">
            <label for="pwd">Password:</label>
            <input type="password" class="form-control" id="pwd" name="pwd" pattern="(?=.*\d)(?=.*[a-zA-Z]).{8,}"
              title="์˜๋ฌธ๋Œ€์†Œ๋ฌธ์ž/์ˆซ์ž๋กœ ์ด๋ฃจ์–ด์ง„ ์ตœ์†Œ 8๊ธ€์ž์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”" placeholder="์˜๋ฌธ๋Œ€์†Œ๋ฌธ์ž/์ˆซ์ž๋กœ ์ด๋ฃจ์–ด์ง„ ์ตœ์†Œ 8๊ธ€์ž์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ" required>
            <i class="fa fa-eye fa-lg eyes" th:attr="onclick='togglePasswordVisibility()'"></i>

          </div>
          <div class="mb-3">
            <label for="name">Name:</label>
            <input type="text" class="form-control" id="name" name="name" pattern="^[a-zA-Z๊ฐ€-ํžฃ]+$"
              title="์˜ฌ๋ฐ”๋ฅธ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š” ex.ํ™๊ธธ๋™" placeholder="์ด๋ฆ„" required>
          </div>
          <div class="mb-3">
            <label for="name">Phone:</label>
            <input type="text" class="form-control" id="phone" name="phone" pattern="[0-9]{10,11}"
              title="10-11์ž๋ฆฌ์˜ ์ˆซ์ž๋ฅผ '-' ์—†์ด ์ž…๋ ฅํ•˜์„ธ์š”" placeholder="ํœด๋Œ€์ „ํ™”๋ฒˆํ˜ธ('-'๊ธฐํ˜ธ ์ œ์™ธ 10~11์ž๋ฆฌ)" required>
          </div>
          <div class="mb-3">
            <label for="campany">ํšŒ์‚ฌ ์„ ํƒ:</label>
            <select class="form-select" id="company" name="company">
              <option value="">ํšŒ์‚ฌ๋ฅผ ์„ ํƒํ•˜์„ธ์š”</option>
              <option th:each="type : ${companys}" th:value="${type.Id}" th:text="${type.companyName}"></option>
            </select>
            <label for="carType">์ฐจ์ข… ์„ ํƒ:</label>
            <select class="form-select" id="carname" name="carname">
              <option value="">์ฐจ์ข…์„ ์„ ํƒํ•˜์„ธ์š”</option>
              <!-- <option th:each="type : ${carTypes}" th:value="${type.name}" th:text="${type.name}"></option> -->
            </select>
          </div>
          <div class="mb-3 form-check">
            <input type="checkbox" class="form-check-input" id="isAdmin" name="isAdmin">
            <label class="form-check-label" for="isAdmin">๊ด€๋ฆฌ์ž</label>
          </div>
          <div class="d-grid gap-2">

            <button class="btn btnn-primary" id="signup" style="width : 250px;">๊ฐ€์ž…ํ•˜๊ธฐ</button>
          </div>
        </form>
      </div>


      <!-- Modal -->
      <div id="myModal" class="modal">
        <div class="modal-dailog">
          <div class="modal-content" style="color:black;">
            <span class="close">&times;</span>
            <div class="subscribe-title"> ์ด๋ฉ”์ผ ๋ณธ์ธ ์ธ์ฆ </div>
            <div class="subscribe-content">
              ์ž‘์„ฑํ•˜์‹  ์ด๋ฉ”์ผ ์ฃผ์†Œ๋กœ ๋ฐœ์†ก๋œ ์ด๋ฉ”์ผ์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”.
            </div>
            <div class="content-info">
              <input type="text" class="codetext">
            </div>
            <div class="coupon-btn"
              style="display: flex; justify-content: space-evenly;align-items: center; margin-top: 20px;">
              <button class="btn-gradient yellow large" onclick="checkEmailcode()">ํ™•์ธ</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  
      <script>
// ์ด์šฉ์•ฝ๊ด€

const pchkBoxes = document.querySelectorAll('input[name="chk"]');
const cchkBoxes = document.querySelectorAll('input[name="chk1"]');
function chkAll(isChecked) {
  

  // ๋ชจ๋“  ์ฒดํฌ๋ฐ•์Šค๋ฅผ ๋ฃจํ”„ ๋Œ๋ฉฐ ์ƒํƒœ๋ฅผ chkAll๊ณผ ๋™์ผํ•˜๊ฒŒ ์„ค์ •
  pchkBoxes.forEach((checkbox) => {
    checkbox.checked = isChecked;
  });
  cchkBoxes.forEach((checkbox) => {
    checkbox.checked = isChecked;
  });

  // ์ตœ์†Œ ๋‘ ๊ฐœ์˜ ์ฒดํฌ๋ฐ•์Šค๊ฐ€ ์„ ํƒ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜์—ฌ "๋™์˜" ๋ฒ„ํŠผ์„ ํ™œ์„ฑํ™”
  const checkedCount = Array.from(pchkBoxes).filter((checkbox) => checkbox.checked).length;
  agreeButton.disabled = checkedCount < 2;
}

// chkAll ์ฒดํฌ๋ฐ•์Šค์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ถ”๊ฐ€
document.querySelector('#chk').addEventListener('change', function () {
  chkAll(this.checked);
});

// "๋™์˜" ๋ฒ„ํŠผ์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฐœ๋ณ„ ์ฒดํฌ๋ฐ•์Šค์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ถ”๊ฐ€
const individualCheckboxes = document.querySelectorAll('input[name="chk"]');
individualCheckboxes.forEach((checkbox) => {
  checkbox.addEventListener('change', function () {
    const checkedCount = Array.from(individualCheckboxes).filter((checkbox) => checkbox.checked).length;
    agreeButton.disabled = checkedCount < 2;
  });

});


let agree;
function agreement(){
  alert("์ด์šฉ์•ฝ๊ด€์— ๋™์˜ํ•˜์…จ์Šต๋‹ˆ๋‹ค.")
  agree = true;
}
function disagreement(){
  alert("์ด์šฉ์•ฝ๊ด€ ํ•„์ˆ˜์‚ฌํ•ญ์— ๋™์˜ํ•˜์‹œ์ง€ ์•Š์œผ์…จ์Šต๋‹ˆ๋‹ค.")
}


        // ํšŒ์›๊ฐ€์ž…ํ•˜๊ธฐ ๋ฒ„ํŠผ ๋น„ํ™œ์„ฑ/ํ™œ์„ฑํ™”
        const signupButton = document.getElementById('signup');
        signupButton.disabled = true;
        const agreeButton = document.querySelector('.fpmgBt2');
        agreeButton.disabled = true;
        let isEmailValid = false;
        let isEmailCodeValid = false;

        function updateSignupButtonState() {
          if (isEmailValid && isEmailCodeValid && agree === true) {
            signupButton.disabled = false;
          } else {
            signupButton.disabled = true;

          }
        }



        // id์ค‘๋ณต์ฒดํฌ
        async function checkEmail() {
          const email = document.querySelector("[name=email]").value;

          const response = await fetch(`/email-check?email=${encodeURIComponent(email)}`);
          const result = await response.text();

          // ์ค‘๋ณต ํ™•์ธ ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ
          const duplicateResultElement = document.getElementById("duplicateResult");

          if (result == "๊ฐ€์ž…๋ถˆ๊ฐ€") {
            duplicateResultElement.textContent = "์ค‘๋ณต๋œ Email์ž…๋‹ˆ๋‹ค.";
            duplicateResultElement.style.color = "red";
            isEmailValid = false;
            // ๋‹ค๋ฅธ ์Šคํƒ€์ผ๋ง ๋“ฑ์˜ ์ถ”๊ฐ€์ ์ธ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
          } else if (result == "๊ฐ€์ž…๊ฐ€๋Šฅ") {
            duplicateResultElement.textContent = "์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ Email์ž…๋‹ˆ๋‹ค.";
            duplicateResultElement.style.color = "green";
            isEmailValid = true;
            // ๋‹ค๋ฅธ ์Šคํƒ€์ผ๋ง ๋“ฑ์˜ ์ถ”๊ฐ€์ ์ธ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
          }
          updateSignupButtonState();
        }
        // ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณด์ด๊ธฐํ‘œ์‹œ
        function togglePasswordVisibility() {
          var $passwordInput = $('#pwd'); // ID๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ๋ž€์„ ์„ ํƒ
          if ($passwordInput.attr('type') === 'password') {
            $('.eyes').removeClass('fa-eye').addClass('fa-eye-slash');
            $passwordInput.attr('type', 'text');
          } else {
            $('.eyes').removeClass('fa-eye-slash').addClass('fa-eye');
            $passwordInput.attr('type', 'password');
          }

        }

        //ํšŒ์‚ฌ ์˜ต์…˜์— ๋”ฐ๋ผ ํ•ด๋‹น ์ฐจ ์ข…๋ฅ˜ ๊ฐ€์ ธ์˜ค๊ธฐ
        const company = document.querySelector('#company');
        const carSelect = document.querySelector('#carname');
        company.addEventListener('change', async (e) => {
          // console.dir(e.target);
          // console.dir(e.target.selectedIndex);
          const index = e.target.selectedIndex;
          // console.dir(e.target[index]);
          const selectedCompany = e.target[index].innerText;
          // console.dir(selectedCompany);
          await getCarTypes(selectedCompany);
        });

        async function getCarTypes(selectedCompany) {
          const data = await fetch(`/getCarType?companyName=${selectedCompany}`);
          const res = await data.json();
          console.log(res);

          // ๊ธฐ์กด ์˜ต์…˜ ์ œ๊ฑฐ
          carSelect.innerHTML = '';

          // "์ฐจ์ข…์„ ์„ ํƒํ•˜์„ธ์š”" ๊ธฐ๋ณธ ์˜ต์…˜ ์ถ”๊ฐ€
          let defaultOption = document.createElement('option');
          defaultOption.value = '';
          defaultOption.text = '์ฐจ์ข…์„ ์„ ํƒํ•˜์„ธ์š”';

          carSelect.appendChild(defaultOption);

          // ์ƒˆ๋กœ์šด ์˜ต์…˜ ์ถ”๊ฐ€
          res.forEach(carType => {
            let optionElement = document.createElement('option');
            optionElement.value = carType.name;
            optionElement.text = carType.name;

            carSelect.appendChild(optionElement);
          });
        }

        //์ด๋ฉ”์ผ ์ธ์ฆ ๋ชจ๋‹ฌ์ฐฝ
        async function run(code) {

          const options = { backdrop: false };
          var myModal = new bootstrap.Modal(document.getElementById('myModal'), options);
          myModal.show();

          const email = document.querySelector("[name=email]").value;
          const response = await fetch(`/emailcode?email=${email}`);


          $('.close').click(function () {
            $('#myModal').css('display', 'none');
            $('.subscribe-title').empty();
            $('.subscribe-content').empty();
          });
        }

        // ์ด๋ฉ”์ผ ์ธ์ฆ
        async function checkEmailcode() {

          const emailcode = document.querySelector('.codetext').value;
          const response = await fetch(`/emailcode-check?emailcode=${emailcode}`);
          const result = await response.text();
          console.log(response);
          console.log(result);
          if (result === "์ฝ”๋“œ๋ถˆ์ผ์น˜") {
            var contentInfo = document.querySelector('.content-info');
            var subscribecontent = document.querySelector('.subscribe-content');
            var couponbtn = document.querySelector('.coupon-btn');
            var closebtn = document.querySelector('.close');
            subscribecontent.innerHTML = '<div class="modal2">๋ณธ์ธ ์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.</div>';
            contentInfo.innerHTML = '<div class="modal2">๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.</div>';
            couponbtn.innerHTML = '<h1></h1>';
            closebtn.innerHTML = '<a href ="/signup">๋Œ์•„๊ฐ€๊ธฐ</a>';
            isEmailCodeValid = false;

          } else if (result === "์ฝ”๋“œ์ผ์น˜") {
            var contentInfo = document.querySelector('.content-info');
            var subscribecontent = document.querySelector('.subscribe-content');
            var couponbtn = document.querySelector('.coupon-btn');
            subscribecontent.innerHTML = '<div class="modal2">์ธ์ฆ์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.</div>';
            contentInfo.innerHTML = '<div class="modal2"> ํšŒ์›๊ฐ€์ž…์„ ์ง„ํ–‰ํ•ด์ฃผ์„ธ์š”.</div>';
            couponbtn.innerHTML = '<h1></h1>';
            isEmailCodeValid = true;
          }
          updateSignupButtonState();
        }


      </script>
    
    <div th:replace="common/footer" style="margin-top: 1rem;">
    </div>

</body>

</html>
728x90
๋ฐ˜์‘ํ˜•

loading