Controller → Service → DAO → Mapper
DTO
MemberDTO
package com.mystory001.domain;
import java.sql.Timestamp;
public class MemberDTO {
private String id;
private String pw;
private String name;
private Timestamp date;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPw() {
return pw;
}
public void setPw(String pw) {
this.pw = pw;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Timestamp getDate() {
return date;
}
public void setDate(Timestamp date) {
this.date = date;
}
}
참조자료형 java.sql.Timestamp는 A thin wrapper around java.util.Date that allowsthe JDBC API to identify this as an SQL TIMESTAMP value.It adds the abilityto hold the SQL TIMESTAMP fractional seconds value, by allowingthe specification of fractional seconds to a precision of nanoseconds.A Timestamp also provides formatting andparsing operations to support the JDBC escape syntax for timestamp values.라고 설명되어 있음. SQL의 timestamp 타입에 대응하기 위해 만들어진 클래스이다.
내가 프로젝트를 진행하면서 가장 애를 먹었던 것 중 하나가 Timestamp형을 String형으로 서로 변환하는 과정이었다. 이와 관련되어 볼만한 자료는 https://www.devkuma.com/docs/java/timestamp/이다. 이곳에 깔끔하게 정리가 잘 되어있다.
package com.mystory001.controller;
import javax.inject.Inject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import com.mystory001.domain.MemberDTO;
import com.mystory001.service.MemberService;
@Controller
public class MemberController {
//public @interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any
*/
//String value() default "";
//}
@Inject
private MemberService memberService;
/* 회원가입 */
@GetMapping
public String join() {
System.out.println("MemberController join()");
return "member/join"; //주소 변경 없이 이동하는 방식(forward)
}
/* 회원가입처리 */
@PostMapping
public String joinPro(MemberDTO memberDTO) {
System.out.println("Membe rController joinPro()");
memberService.joinPro(memberDTO); //join.jsp에서 입력한 데이터 → request → memberDTO 변수에 전달 → DB 작업
return "redirect:/main"; //main으로 주소 변경하면서 이동
}
}
package com.mystory001.service;
import java.sql.Timestamp;
import javax.inject.Inject;
import org.springframework.stereotype.Service;
import com.mystory001.dao.MemberDAO;
import com.mystory001.domain.MemberDTO;
@Service
public class MemberService {
@Inject
private MemberDAO memberDAO;
public void joinPro(MemberDTO memberDTO) {
System.out.println("MemberService joinPro()");
memberDTO.setDate(new Timestamp(System.currentTimeMillis())); //가입 날짜 설정
memberDAO.joinPro(memberDTO);
}
}
package com.mystory001.dao;
import javax.inject.Inject;
import org.apache.ibatis.session.SqlSession;
import com.mystory001.domain.MemberDTO;
public class MemberDAO {
@Inject
private SqlSession sqlSession;
private static final String namespace = "com.mystory001.mappers.memberMapper";
public void joinPro(MemberDTO memberDTO) {
System.out.println("MemberDAO joinPro()");
sqlSession.insert(namespace+".joinPro",memberDTO);
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mystory001.mappers.memberMapper">
<insert id="joinPro">
insert into member(id, pw, name, time)
values(#{id}, #{pw}, #{name}, #{time})
</insert>
</mapper>
오류 발생함
코드를 봤을 때 어노테이션이 빠진 것 같아 보이는데 memberDAO에 어노테이션이 빠져있었다.
package com.mystory001.dao;
import javax.inject.Inject;
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
import com.mystory001.domain.MemberDTO;
@Repository
public class MemberDAO {
@Inject
private SqlSession sqlSession;
private static final String namespace = "com.mystory001.mappers.memberMapper";
public void joinPro(MemberDTO memberDTO) {
System.out.println("MemberDAO joinPro()");
sqlSession.insert(namespace+".joinPro",memberDTO);
}
}
어노테이션을 다시 살펴보자
- @Controller : Controller에 작성. 웹 요청과 응답을 처리
- @Service : Service에 작성. 내부에서 자바 로직을 처리
- @Repository : DAO에 작성. DB나 파일 같은 외부 Input/Output 작업을 처리
DB처리를 할 DAO 클래스에 @Repository 어노테이션을 붙여줘야 함. 그렇게 되면 DAO 클래스는 루트 컨테이너에 빈 객체로 생성됨. 루트 컨테이너의 객체는 어디서든 공유가 가능하기 때문에 자동 의존성 주입 어노테이션을 이용해 객체를 받아올 수 있다. (참고 : https://codevang.tistory.com/258)
DAO에 어노테이션을 붙이면 오류가 없어지고 페이지가 뜬다.
회원가입을 진행해보자
오류가 뜬다.
뭔가 오류를 보니 DTO에서 time의 자료형을 Timestamp로 했는데 일치하지 않는다인 것 같음.
DB는 time 컬럼의 데이터타입을 datetime으로 했어서 문제가 생긴 것 같음. datetime을 timestamp로 바꿨을 때도 에러가 날까? 시도해 보자
데이터 타입이 변경된 것을 알 수 있음. 프로젝트할 때 timestamp를 사용하지 않고 DTO에 날짜를 사용할 변수에 [ String으로 했을 때 잘 들어간 것이 갑자기 생각난다.
그럼에도
문제는
DTO에 date로 만들었는데 이러니 찾지 못해서 오류가 난 것 같음. 위에 굳이 데이터타입을 변경할 필요가 없었던 것 같다.
이러면 에러 안 나겠지? 했는데
이번에는 문법 오류가 났는데 백틱(`)을 안 넣어서 그런가? 굳이 오류를 안 찾아보는 이유는 이런저런 오류 접하면서 해결 방법에 대해서 스스로 알아보고 해결하는 것이 기억에 더 많이 남기 때문이다.
DB에 member 테이블이 아니라 `member`테이블이고 time 컬럼이 `time`컬럼이라 생긴 문제인 것 같다.
DB에서 조회해 보니
잘 들어가긴 했다. 회원가입을 완료하면 주소만 main으로 바뀌고 화면은 회원가입 화면이다. 이를 수정해 보자
MemberController 일부만 수정
/* 회원가입처리 */
@PostMapping
public String joinPro(MemberDTO memberDTO) {
System.out.println("Membe rController joinPro()");
memberService.joinPro(memberDTO); //join.jsp에서 입력한 데이터 → request → memberDTO 변수에 전달 → DB 작업
return "redirect:/"; //main으로 주소 변경하면서 이동
}
이러면 회원가입에서 정보를 작성하고 회원가입을 눌렀을 때 회원가입이 완료되고 화면이 main으로 바뀐다.
일단 join.jsp에서 할 일은 정규표현식을 이용해서 정보의 유효성 검사와 ajax를 이용한 아이디 중복 검사를 먼저 처리해야 할 것 같다.
jquery.js를 resources폴더에 넣어주고 jsp에서 이를 사용하기 위해 경로 설정(body 태그 위에) 작성하고, 자바스크립트 내용은 닫히는 body 태그 위에 작성. 교육받을 때 가끔씩 자바스크립트가 잘 인식이 안 되는 버그? 같은 게 있다고 해서 가장 아래에 작성해 준다고 들었다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>그냥 게시판</title>
</head>
<style>
.container{
align-content : center;
width: 1200px;
height: 600px;
}
.content{
width: 1000px;
height: 600px;
}
.formstyle{
width : 400px;
}
.label{
width : 200px;
}
.validation{
widows: 200px;
height: 30px;
}
</style>
<script type="text/javascript" src="${pageContext.request.contextPath}/resources/jquery-3.7.1.min.js"></script>
<body>
<div class="container"> <%-- container 영역 div --%>
<jsp:include page="../inc/top.jsp" />
<jsp:include page="../inc/sidebar.jsp" />
<div class="content"> <%-- content영역 div --%>
<h1>회원가입</h1>
<form action="${pageContext.request.contextPath}/member/joinPro" method="post">
<div class="formstyle">
<input type="text" name="id" required="required" placeholder="아이디"><br> <%-- 영문 소문자, 숫자와 특수기호(_),(-)만 사용 가능 --%>
<input type="password" name="pw" required="required" placeholder="비밀번호"><br> <%-- 영문 대/소문자, 숫자, 특수문자를 사용 --%>
<input type="password" required="required" placeholder="비밀번호재확인"><br> <%-- 비밀번호를 다시 입력 --%>
<input type="text" name="name" required="required" placeholder="이름"> <%-- 한글, 영문만 입력 가능 --%>
</div>
<div class="validation"><b></b></div> <%-- 유효성 검사 시 유효성에 일치않을 때 --%>
<input type="submit" value="회원가입">
</form>
</div> <%-- content영역 div --%>
<jsp:include page="../inc/footer.jsp" />
</div> <%-- container 영역 div --%>
<script type="text/javascript">
<%-- 이곳에 자바스크립트 내용 작성 --%>
</script>
</body>
</html>
현재 비밀번호가 틀릴 경우 회원가입이 된다는 것 자체가 문제이므로 비밀번호와 비밀번호 재확인이 같을 때 페이지가 넘어가도록 제어해 보자
그전에 DOM 요소에 접근하는 것을 알아보자. 많이 있지만 여기서 사용할 것은 id 선택자로 접근, class값으로 접근하는 방법에 대해서만 알아보자
- id 선택자로 접근 getElementById()
요소명.getElementById("id이름")
id속성은 html 안에서 동일한 id 속성이 존재하면 안 됨 - class 값으로 접근 getElementsByClassName()
요소명. getElementsByClassName(("class이름")
이 외에도 태그나 쿼리셀럭터로 접근하는 방법이 있다.
※매번 혼란스러운 것을 잠시 정리하자면 id 해시 기호(#), class 마침표(.)
지금은 id로도 해보고 class로도 해보고 무슨 차이가 있는지에 대해서도 찾아보자
id 선택자로 접근하였을 때는 되었는데, class 값으로 접근하면 되지 않는 것을 확인했다. 이유는 getElementsByClassName()은 컬렉션 객체를 반환하므로 for문을 사용하거나 특정 인덱스를 반환받아 사용할 수 있다.
따라서
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>그냥 게시판</title>
</head>
<style>
.container{
align-content : center;
width: 1200px;
height: 600px;
}
.content{
width: 1000px;
height: 600px;
}
.formstyle{
width : 400px;
}
.label{
width : 200px;
}
.validation{
widows: 200px;
height: 30px;
}
</style>
<script src="${pageContext.request.contextPath}/resources/js/jquery-3.7.1.min.js"></script>
<body>
<div class="container"> <%-- container 영역 div --%>
<jsp:include page="../inc/top.jsp" />
<jsp:include page="../inc/sidebar.jsp" />
<div class="content"> <%-- content영역 div --%>
<h1>회원가입</h1>
<form action="${pageContext.request.contextPath}/member/joinPro" method="post" onsubmit="return passwordPass()">
<div class="formstyle">
<input type="text" name="id" class="id" required="required" placeholder="아이디"><br> <%-- 영문 소문자, 숫자와 특수기호(_),(-)만 사용 가능 --%>
<input type="password" name="pw" id="pw" required="required" placeholder="비밀번호"><br> <%-- 영문 대/소문자, 숫자, 특수문자를 사용 --%>
<input type="password" id="pw2" required="required" placeholder="비밀번호재확인"><br> <%-- 비밀번호를 다시 입력 --%>
<input type="text" name="name" required="required" placeholder="이름"> <%-- 한글, 영문만 입력 가능 --%>
</div>
<div class="validation"><b></b></div> <%-- 유효성 검사 시 유효성에 일치않을 때 --%>
<input type="submit" value="회원가입">
</form>
</div> <%-- content영역 div --%>
<jsp:include page="../inc/footer.jsp" />
</div> <%-- container 영역 div --%>
<script type="text/javascript">
<%-- 비밀번호와 비밀번호 재확인 --%>
function passwordPass(){
var pw = document.getElementById("pw");
var pw2 = document.getElementById("pw2");
if(pw && pw2){
var password = pw.value;
var confirmPassword = pw2.value;
if(password !== confirmPassword){
alert("비밀번호가 일치하지 않습니다.");
return false; //페이지 넘어가는 것을 막음
}
return true;
} else{
console.error("에러");
return false;
}
}
</script>
</body>
</html>
다음으로 현재 아이디가 공백이라도 회원가입이 가능함. 정규표현식을 사용하여 제어
정규식 기호
a-zA-Z | 영 대소문자(-으로 범위 지정 가능) |
ㄱ-ㅎㅎ가-힣 | 한글 문자(-으로 범위 지정 가능) |
0-9 | 숫자(-으로 범위 지정 가능) |
더 다양하게 많지만 여기서 사용할 기호는 3가지 밖에 없다.
정규식 검색 기준 패턴
[] | 대괄호 안 문자들 중 하나. or 처리 묶음 |
[^문자] | 대괄호 안의 문자를 제외 |
^문자열 | 특정 문자열로 시작 |
문자열$ | 특정 문자열로 끝 |
정규식 개수 반복 패턴
? | 없거나 최대 한 개 |
* | 없거나 여러 개 있음 |
+ | 최소 한 개 또는 최소 여러 개 |
*? | 없거거나 있거나 최대 한 개 |
+? | 최소 한 개 있거나, 없거나 최대 한 개 |
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>그냥 게시판</title>
</head>
<style>
.container{
align-content : center;
width: 1200px;
height: 600px;
}
.content{
width: 1000px;
height: 600px;
}
.formstyle{
width : 400px;
}
.label{
width : 200px;
}
.validation{
widows: 200px;
height: 30px;
}
</style>
<script src="${pageContext.request.contextPath}/resources/js/jquery-3.7.1.min.js"></script>
<body>
<div class="container"> <%-- container 영역 div --%>
<jsp:include page="../inc/top.jsp" />
<jsp:include page="../inc/sidebar.jsp" />
<div class="content"> <%-- content영역 div --%>
<h1>회원가입</h1>
<form action="${pageContext.request.contextPath}/member/joinPro" method="post" onsubmit="return passwordPass()" id="join">
<div class="formstyle">
<input type="text" name="id" class="id" required="required" placeholder="아이디"><br> <%-- 영문 소문자, 숫자와 특수기호(_),(-)만 사용 가능 --%>
<input type="password" name="pw" id="pw" required="required" placeholder="비밀번호"><br> <%-- 영문 대/소문자, 숫자, 특수문자를 사용 --%>
<input type="password" id="pw2" required="required" placeholder="비밀번호재확인"><br> <%-- 비밀번호를 다시 입력 --%>
<input type="text" name="name" required="required" placeholder="이름"> <%-- 한글, 영문만 입력 가능 --%>
</div>
<div class="validation"><b></b></div> <%-- 유효성 검사 시 유효성에 일치않을 때 --%>
<input type="submit" value="회원가입">
</form>
</div> <%-- content영역 div --%>
<jsp:include page="../inc/footer.jsp" />
</div> <%-- container 영역 div --%>
<script type="text/javascript">
<%-- 비밀번호와 비밀번호 재확인 --%>
function passwordPass(){
var pw = document.getElementById("pw");
var pw2 = document.getElementById("pw2");
if(pw && pw2){
var password = pw.value;
var confirmPassword = pw2.value;
if(password !== confirmPassword){
alert("비밀번호가 일치하지 않습니다.");
return false; //페이지 넘어가는 것을 막음
}
return true;
} else{
console.error("에러");
return false;
}
}
<%-- 정규표현식(RegExp). RegExp() : 정규표현식 표시 함수. RegExp(/정규표현식내용/) --%>
$(function(){
<%-- 대상.함수 --%>
$('#join').submit(function(){
var idRegExp = RegExp(/^[a-z0-9]{2,20}$/); <%-- 영소문자+숫자가 하나 이상 포함되며 2~20자 --%>
if(!idRegExp.test($('.id').val())){
alert("아이디 형식은 영소문자, 숫자로만 가능하며 2~20자까지 가능");
$('.id').focus();
return false;
}
})
})
</script>
</body>
</html>
이와 같이 코드를 작성했는데 비밀번호와 비밀번호 재확인은 되는데, 정규표현식은 안된다. 어떻게 검색을 해야 내가 원하는 정보를 찾을 수 있을지 고민해 봐도 되지 않아 어쩔 수 없이 gpt를 사용해서 왜 안되는지만 찾아보았다.
- 이벤트 핸들링의 순서
현재 코드에서 onsubmit 속성으로 비밀번호를 검사를 수행한 후, jQuery의 submit 이벤트 핸들러가 실행됨. 이로 인해 정규표현식 검사가 진행되지 않을 수 있다. - submit 이벤트 핸들러의 return
jQuery의 submit 핸들러에서 return false;를 사용해도 페이지 전송을 막을 수 있지만, 이를 어떻게 처리하는지에 따라 결과가 다를 수 있다. - 비밀번호 확인 기능과 ID 검증이 별도의 흐름에서 처리됨
비밀번호 확인이 이미 페이지 전송을 차단했을 경우, ID 검증이 실행되지 않을 수 있다.
이벤트 핸들링이 잘못되었는데 자바스크립트의 개념이 부족한 것인지 사실 잘 모르겠다.
생각한 해결방법으로는 아이디 정규표현식, 비밀번호와 비밀번호 재확인을 포커스가 이동했을 때 정보에 문제가 있을 때 알림 창이 뜨게 바꾸면 되지 않을까?
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>그냥 게시판</title>
</head>
<style>
.container{
align-content : center;
width: 1200px;
height: 600px;
}
.content{
width: 1000px;
height: 600px;
}
.formstyle{
width : 400px;
}
.label{
width : 200px;
}
.validation{
widows: 200px;
height: 30px;
}
</style>
<script src="${pageContext.request.contextPath}/resources/js/jquery-3.7.1.min.js"></script>
<body>
<div class="container"> <%-- container 영역 div --%>
<jsp:include page="../inc/top.jsp" />
<jsp:include page="../inc/sidebar.jsp" />
<div class="content"> <%-- content영역 div --%>
<h1>회원가입</h1>
<form action="${pageContext.request.contextPath}/member/joinPro" method="post" id="join">
<div class="formstyle">
<input type="text" name="id" id="id" required="required" placeholder="아이디" onblur="return regExp()"><br> <%-- 영문 소문자, 숫자와 특수기호(_),(-)만 사용 가능 --%>
<input type="password" name="pw" id="pw" required="required" placeholder="비밀번호"><br> <%-- 영문 대/소문자, 숫자, 특수문자를 사용 --%>
<input type="password" id="pw2" required="required" placeholder="비밀번호재확인" onblur="return passwordPass()"><br> <%-- 비밀번호를 다시 입력 --%>
<input type="text" name="name" required="required" placeholder="이름"> <%-- 한글, 영문만 입력 가능 --%>
</div>
<div class="validation"><b></b></div> <%-- 유효성 검사 시 유효성에 일치않을 때 --%>
<input type="submit" value="회원가입">
</form>
</div> <%-- content영역 div --%>
<jsp:include page="../inc/footer.jsp" />
</div> <%-- container 영역 div --%>
<script type="text/javascript">
<%-- 비밀번호와 비밀번호 재확인 --%>
function passwordPass(){
var pw = document.getElementById("pw");
var pw2 = document.getElementById("pw2");
if(pw && pw2){
var password = pw.value;
var confirmPassword = pw2.value;
if(password !== confirmPassword){
alert("비밀번호가 일치하지 않습니다.");
return false; //페이지 넘어가는 것을 막음
}
return true;
} else{
console.error("에러");
return false;
}
}
<%-- 정규표현식(RegExp). RegExp() : 정규표현식 표시 함수. RegExp(/정규표현식내용/) --%>
function regExp(){
var id = document.getElementById("id");
var idRegExp = RegExp(/^[a-z0-9]{2,20}$/); <%-- 영소문자+숫자가 하나 이상 포함되며 2~20자 --%>
// if(!idRegExp.test($('.id').val())){
// alert("아이디 형식은 영소문자, 숫자로만 가능하며 2~20자까지 가능");
// $('.id').focus();
// return false;
if(!idRegExp.test(id.value)){
alert("아이디 형식은 영소문자, 숫자로만 가능하며 2~20자까지 가능");
$('.id').focus();
return false;
}
return true;
}
</script>
</body>
</html>
정규표현식을 사용하라고는 되어있어서 아 되는구나 싶어서 회원가입을 알림 창을 무시하고 해 봤음
... 뭐지? 뭐가 문제일까... 아무리 고민하고 해 봐도 답이 나오지 않았다. 처음 다짐했을 때는 gpt를 절대 사용하지 않도록 생각했는데 검색 기술이 형편없어서인지 아무리 찾아봐도 답이 나오지 않음... 그래서 해결 방법에 대해 검색해 보았다.
- 폼 제출 이벤트 가로채기
onsubmit 이벤트를 사용하여 폼이 제출되기 전에 모든 검증을 수행한다. - 각 검증 함수의 결과를 확인
모든 검증이 통과해야만 폼이 제출되도록 한다.
즉 onsubmit 이벤트를 form 태그에 넣어주고, 유효성검사를 하게 해야 한다라는 것 같다.
function formCheck(){
var validId = regExp();
var validPw = passwordPass();
if(validId && validPw) {
return true; // 모든 검증 통과, 폼 제출
} else {
alert("형식에 맞게 작성해주세요");
return false; // 검증 실패, 폼 제출 중지
}
}
넣어주어도 계속 알림 창만 뜰뿐 가입은 가능했다. 그래서 전반적으로 조금씩 바꿔서 원하는 결과를 만들어 낸 것 같다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>그냥 게시판</title>
</head>
<style>
.container{
align-content : center;
width: 1200px;
height: 600px;
}
.content{
width: 1000px;
height: 600px;
}
.formstyle{
width : 400px;
}
.label{
width : 200px;
}
.validation{
widows: 200px;
height: 30px;
}
</style>
<script src="${pageContext.request.contextPath}/resources/js/jquery-3.7.1.min.js"></script>
<body>
<div class="container"> <%-- container 영역 div --%>
<jsp:include page="../inc/top.jsp" />
<jsp:include page="../inc/sidebar.jsp" />
<div class="content"> <%-- content영역 div --%>
<h1>회원가입</h1>
<form action="${pageContext.request.contextPath}/member/joinPro" method="post" id="join" onsubmit="return formCheck()">
<div class="formstyle">
<input type="text" name="id" id="id" required="required" placeholder="아이디"><br> <%-- 영문 소문자, 숫자와 특수기호(_),(-)만 사용 가능 --%>
<input type="password" name="pw" id="pw" required="required" placeholder="비밀번호"><br> <%-- 영문 대/소문자, 숫자, 특수문자를 사용 --%>
<input type="password" id="pw2" required="required" placeholder="비밀번호재확인"><br> <%-- 비밀번호를 다시 입력 --%>
<input type="text" name="name" required="required" placeholder="이름"> <%-- 한글, 영문만 입력 가능 --%>
</div>
<div class="validation"><b></b></div> <%-- 유효성 검사 시 유효성에 일치않을 때 --%>
<input type="submit" value="회원가입">
</form>
</div> <%-- content영역 div --%>
<jsp:include page="../inc/footer.jsp" />
</div> <%-- container 영역 div --%>
<script type="text/javascript">
<%-- 비밀번호와 비밀번호 재확인 --%>
function passwordPass() {
var pw = document.getElementById("pw");
var pw2 = document.getElementById("pw2");
if (pw && pw2) {
var password = pw.value;
var confirmPassword = pw2.value;
if (password !== confirmPassword) {
alert("비밀번호가 일치하지 않습니다.");
pw2.focus(); // 비밀번호 재확인 필드에 포커스
return false; // 검증 실패
}
}
return true; // 검증 성공
}
<%-- 정규표현식(RegExp). RegExp() : 정규표현식 표시 함수. RegExp(/정규표현식내용/) --%>
function regExp() {
var id = document.getElementById("id");
var idRegExp = /^[a-z0-9]{2,20}$/; // 영소문자 + 숫자가 하나 이상 포함되며 2~20자
if (!idRegExp.test(id.value)) {
alert("아이디 형식은 영소문자, 숫자로만 가능하며 2~20자까지 가능");
id.focus(); // 아이디 필드에 포커스
return false; // 검증 실패
}
return true; // 검증 성공
}
function formCheck(){
var validId = regExp();
var validPw = passwordPass();
if(validId && validPw) {
return true; // 모든 검증 통과, 폼 제출
} else {
alert("형식에 맞게 작성해주세요");
return false; // 검증 실패, 폼 제출 중지
}
}
</script>
</body>
</html>
자바스크립트는 처음 배울 땐 와 엄청 쉽다 이랬는데 손 놓고 있다 보니까 하나도 모르겠다. 이거 끝나면 자바스크립트를 다시 학습하도록 해야겠다.
로그인
아이디와 비밀번호가 일치하면 로그인이 되고, 그렇지 않으면 경고창
먼저 아이디, 비밀번호가 일치하지 않았을 때 msg창
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<script type="text/javascript">
alert("존재하지 않는 아이디이거나 비밀번호가 틀렸습니다.");
history.back(); //뒤로 이동
</script>
</body>
</html>
로그인 처리 과정을 살펴보면
- 사용자에게 로그인 정보(아이디, 비밀번호)를 입력받는다.
- 입력받은 정보를 DB에서 찾는다.
- 1) 가입된 정보가 있으면 로그인이 된다.
2) 가입된 정보가 없으면 로그인이 안된다.
여기서 입력받은 정보를 조회하기 위해서는 return 값이 존재해야 함
MemberController
/* 로그인 → 회원 확인 */
@PostMapping
public String loginPro(MemberDTO memberDTO, HttpSession session) {
System.out.println("MemberController loginPro()");
MemberDTO memberDTO2 = memberService.userCheck(memberDTO); //폼에서 입력받은 데이터가 존재하는지 확인
if(memberDTO2 != null) {
session.setAttribute("id", memberDTO2.getId());
return "redirect:/";
} else {
return "member/loginmsg";
}
}
MemberService
public MemberDTO userCheck(MemberDTO memberDTO) {
System.out.println("MemberService userCheck()");
return memberDAO.userCheck(memberDTO);
}
MemberDAO
public MemberDTO userCheck(MemberDTO memberDTO) {
System.out.println("MemberDAO userCheck()");
return sqlSession.selectOne(namespace+".userCheck", memberDTO);
}
memberMapper
<select id="userCheck">
select *
from `member`
where id=#{id} and pw=#{pw}
</select>
오류 발생 → java.lang.IllegalStateException: Ambiguous mapping
→ Controller에서 RequestMapping이 충돌하는 경우 에러가 발생. 동일한 value값이 지정되어 있어 핸들러 매핑이 불가능함.
package com.mystory001.controller;
import javax.inject.Inject;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import com.mystory001.domain.MemberDTO;
import com.mystory001.service.MemberService;
@Controller
public class MemberController {
//public @interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any
*/
//String value() default "";
//}
@Inject
private MemberService memberService;
/* 회원가입 */
@GetMapping
public String join() {
System.out.println("MemberController join()");
return "member/join"; //주소 변경 없이 이동하는 방식(forward)
}
/* 회원가입처리 */
@PostMapping
public String joinPro(MemberDTO memberDTO) {
System.out.println("MemberController joinPro()");
memberService.joinPro(memberDTO); //join.jsp에서 입력한 데이터 → request → memberDTO 변수에 전달 → DB 작업
return "redirect:/"; //main으로 주소 변경하면서 이동
}
/* 로그인 → 회원 확인 */
@PostMapping
public String loginPro(MemberDTO memberDTO, HttpSession session) {
System.out.println("MemberController loginPro()");
MemberDTO memberDTO2 = memberService.userCheck(memberDTO); //폼에서 입력받은 데이터가 존재하는지 확인
if(memberDTO2 != null) {
session.setAttribute("id", memberDTO2.getId());
return "redirect:/";
} else {
return "member/loginmsg";
}
}
}
? 단순히 메소드이름만 문제였던 것은 아니었다. 경로가 명시되지 않아 발생된 오류였다. 각 메소드에 대한 명확한 URL 경로를 지정해줘야 했었던 것 추가적으로 RequestMapping 어노테이션도 빠져있었다.
package com.mystory001.controller;
import javax.inject.Inject;
import javax.servlet.http.HttpSession;
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.RequestMapping;
import com.mystory001.domain.MemberDTO;
import com.mystory001.service.MemberService;
@Controller
@RequestMapping("/member/*")
public class MemberController {
//public @interface Controller {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any
*/
//String value() default "";
//}
@Inject
private MemberService memberService;
/* 회원가입 */
@GetMapping("/join")
public String join() {
System.out.println("MemberController join()");
return "member/join"; //주소 변경 없이 이동하는 방식(forward)
}
/* 회원가입처리 */
@PostMapping("/joinPro")
public String joinPro(MemberDTO memberDTO) {
System.out.println("MemberController joinPro()");
memberService.joinPro(memberDTO); //join.jsp에서 입력한 데이터 → request → memberDTO 변수에 전달 → DB 작업
return "redirect:/"; //main으로 주소 변경하면서 이동
}
/* 로그인 → 회원 확인 */
@PostMapping("/loginPro")
public String loginPro(MemberDTO memberDTO, HttpSession session) {
System.out.println("MemberController loginPro()");
MemberDTO memberDTO2 = memberService.userCheck(memberDTO); //폼에서 입력받은 데이터가 존재하는지 확인
if(memberDTO2 != null) {
session.setAttribute("id", memberDTO2.getId());
return "redirect:/";
} else {
return "member/loginmsg";
}
}
}
이렇게 수정해 주니 오류는 없어졌고 로그인을 해보니 또 다른 오류에 직면했다.
select문 같은 경우 resultType을 작성해줬어야 했는데 누락되어 생긴 오류인 것으로 보인다. memberMapper에서 resultType을 작성해 주면 해결될 문제
memberMapper
<select id="userCheck" resultType="com.mystory001.domain.MemberDTO">
select *
from `member`
where id=#{id} and pw=#{pw}
</select>
작성해 주니 되긴 되는데, 로그인이 되는 건 아니다. top.jsp에서 taglib를 이용해서 세션을 유지시키도록해보자
top.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<style>
.header{
float : right;
width: 1200px;
height: 0px;
}
</style>
<body>
<div class="header"> <%-- header 영역 div --%>
<form method="post" action="${pageContext.request.contextPath}/loginPro"> <%-- post방식 --%>
<span style="float: right;">
<c:if test="${empty sessionScope.id }">
아이디 : <input type="text" name="id">
비밀번호 : <input type="password" name="pw">
<button type="submit">로그인 </button><a href="${pageContext.request.contextPath}/member/join"><button type="button">회원가입</button></a>
</c:if>
<c:if test="${! empty sessionScope.id }">
${sessionScope.id } 님 반갑습니다. | <a href="${pageContext.request.contextPath }/member/check">내 정보</a> | <a href="${pageContext.request.contextPath }/logout">로그아웃</a>
</c:if>
</span>
</form>
</div><%-- header 영역 div --%><br>
<hr>
</body>
</html>
check.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>그냥 게시판</title>
</head>
<style>
.container{
align-content : center;
width: 1200px;
height: 600px;
}
.content{
width: 1000px;
height: 600px;
}
</style>
<body>
<div class="container"> <%-- container 영역 div --%>
<jsp:include page="../inc/top.jsp" />
<jsp:include page="../inc/sidebar.jsp" />
<div class="content"> <%-- content영역 div --%>
<h1>정보 확인</h1>
<form method="post" action="${pageContext.request.contextPath }/member/mypage">
${sessionScope.id } 님 비밀번호를 입력해주세요.<br>
<input type="password" name="pw"> <input type="submit" value="확인">
</form>
</div> <%-- content영역 div --%>
<jsp:include page="../inc/footer.jsp" />
</div> <%-- container 영역 div --%>
</body>
</html>
mypage.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>그냥 게시판</title>
</head>
<style>
.container{
align-content : center;
width: 1200px;
height: 600px;
}
.content{
width: 1000px;
height: 600px;
}
</style>
<body>
<div class="container"> <%-- container 영역 div --%>
<jsp:include page="../inc/top.jsp" />
<jsp:include page="../inc/sidebar.jsp" />
<div class="content"> <%-- content영역 div --%>
<h1>내 정보</h1>
<input type="text" name="id" readonly="readonly"><br> <%-- 영문 소문자, 숫자와 특수기호(_),(-)만 사용 가능 --%>
<input type="password" name="pw" required="required" placeholder="비밀번호"><br> <%-- 영문 대/소문자, 숫자, 특수문자를 사용 --%>
<input type="password" required="required" placeholder="비밀번호재확인"><br> <%-- 비밀번호를 다시 입력 --%>
<input type="text" name="name" required="required" placeholder="이름"> <%-- 한글, 영문만 입력 가능 --%>
<button>수정</button><button>탈퇴</button>
</div> <%-- content영역 div --%>
<jsp:include page="../inc/footer.jsp" />
</div> <%-- container 영역 div --%>
</body>
</html>
로그아웃 memberController
/* 로그아웃 */
@GetMapping("/logout")
public String logout(HttpSession session) {
System.out.println("MemberController logout()");
session.invalidate();
return "redirect:/";
}
check.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>그냥 게시판</title>
</head>
<style>
.container{
align-content : center;
width: 1200px;
height: 600px;
}
.content{
width: 1000px;
height: 600px;
}
</style>
<body>
<div class="container"> <%-- container 영역 div --%>
<jsp:include page="../inc/top.jsp" />
<jsp:include page="../inc/sidebar.jsp" />
<div class="content"> <%-- content영역 div --%>
<h1>정보 확인</h1>
<form method="post" action="${pageContext.request.contextPath }/member/mypage">
${sessionScope.id } 님 비밀번호를 입력해주세요.<br>
<input type="password" name="pw"> <input type="submit" value="확인">
</form>
</div> <%-- content영역 div --%>
<jsp:include page="../inc/footer.jsp" />
</div> <%-- container 영역 div --%>
</body>
</html>
@GetMapping("member/check")
public String check(HttpSession session) {
System.out.println("MemberController check()");
return "/member/check";
}
@PostMapping("member/mypage")
public String mypage(HttpSession session) {
System.out.println("MemberController mypage()");
return "/member/mypage";
}
정보 확인에서 아무것도 입력하지 않아도 내 정보로 갈 수 있음. 비밀번호가 맞는지 확인하는 로직이 필요함.
Controller
@GetMapping("member/check")
public String check(HttpSession session) {
System.out.println("MemberController check()");
return "/member/check";
}
@PostMapping("member/checkPro")
public String checkPro(HttpSession session) {
System.out.println("MemberController checkPro()");
String id = (String)session.getAttribute("id");
String inputPw = (String)session.getAttribute("pw");
String pw = memberService.pwCheck(id);
if(pw!=null && pw.equals(inputPw)) {
return "/member/mypage";
} else {
return "/member/checkmsg";
}
}
Service
public String pwCheck(String id) {
System.out.println("MemberService userPw()");
return memberDAO.pwCheck(id);
}
DAO
public String pwCheck(String id) {
System.out.println("MemberDAO pwCheck()");
return sqlSession.selectOne(namespace+".pwCheck", id);
}
Mapper
<select id="pwCheck" resultType="String">
select pw
from `member`
where id=#{id}
</select>
checkmsg만 뜰뿐..이었다
String inputPw = (String)session.getAttribute("pw");
현 페이지에서 입력받은 pw이라고 생각하고 했는데, 세션에 저장된 비밀번호를 뜻함. 따라서 원하는 동작이 아님...
@RequestParam을 사용함. HTTP 요청 파라미터를 메소드 매개변수로 매핑할 때 사용하는 어노테이션. 사용자가 입력한 데이터를 서버 측에 쉽게 받아올 수 있도록 해줌.
@PostMapping("member/checkPro")
public String checkPro(@RequestParam("pw") String inputPw, HttpSession session) {
System.out.println("MemberController checkPro()");
String id = (String)session.getAttribute("id");
String pw = memberService.pwCheck(id);
if(pw!=null && pw.equals(inputPw)) {
return "/member/mypage";
} else {
return "/member/checkmsg";
}
}
해결됨..
마이페이지에서 회원수정, 탈퇴와 게시판하기
'organize > 프로젝트' 카테고리의 다른 글
justBoard8 게시판 클래스 작업 (0) | 2024.09.28 |
---|---|
justBoard7 member 마무리, board 준비 (1) | 2024.09.26 |
justBoard5 화면(view)2 (0) | 2024.09.24 |
justBoard4 화면(view)1 (0) | 2024.09.23 |
justBoard3 xml설정, 프로그램 설치 (0) | 2024.09.21 |