반응형

요즘사이트에서 회원가입을 하다보면 꼭!  각종 인증들 이있다.

사용자 입장에서는 굳이?? 이걸 해야하나? 싶기도 하겠지만 

사업자 입장에서보면 각종 Black Consumer 외 다른 부분에 대해서 

보안을 강조한다. 그렇기 때문에 휴대폰인증 이메일인증은 꼭 필요하다고 말하고 싶다. 

 

why 이메일인증?? 😞

 

JUST 

 

비싸니까..

 

이유는 단순하다 그냥 프로젝트에 대해서 돈이들기 떄문이다.스프링에서 기본으로 제공하는 API로 충분한 이메일 인증이 가능하기 떄문이다!

 

자 이제 시작해보자!


 

1. API 다운 

 

https://mvnrepository.com/

 

https://mvnrepository.com/에서 javax.mail과 spring-context-support을 다운받아 준다. 

 

<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4.7</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>5.3.9</version>
</dependency>

여러분의 시간은 소중하니까. 이걸 pom.xml 라이브러리에 추가해준다.

 

👻  나름의 꿀팁  👻 

<version>${org.springframework-version}</version> 이거 써주면 알아서 버전 맞춰준다! 

 

 


2. JSP 수정(HTML , JS 영역)

 

<div class="form-group email-form">
	 <label for="email">이메일</label>
	 <div class="input-group">
	<input type="text" class="form-control" name="userEmail1" id="userEmail1" placeholder="이메일" >
	<select class="form-control" name="userEmail2" id="userEmail2" >
	<option>@naver.com</option>
	<option>@daum.net</option>
	<option>@gmail.com</option>
	<option>@hanmail.com</option>
	 <option>@yahoo.co.kr</option>
	</select>
	/div>   
<div class="input-group-addon">
	<button type="button" class="btn btn-primary" id="mail-Check-Btn">본인인증</button>
</div>
	<div class="mail-check-box">
<input class="form-control mail-check-input" placeholder="인증번호 6자리를 입력해주세요!" disabled="disabled" maxlength="6">
</div>
	<span id="mail-check-warn"></span>
</div>

기존의 Jsp에서 본인인증 버튼을 추가하고 인증번호를 받을 자리를 남겨 두었다. 😁

 

2-1 JS 작성

 

$('#mail-Check-Btn').click(function() {
		const eamil = $('#userEmail1').val() + $('#userEmail2').val(); // 이메일 주소값 얻어오기!
		console.log('완성된 이메일 : ' + eamil); // 이메일 오는지 확인
		const checkInput = $('.mail-check-input') // 인증번호 입력하는곳 
		
		$.ajax({
			type : 'get',
			url : '<c:url value ="/user/mailCheck?email="/>'+eamil, // GET방식이라 Url 뒤에 email을 뭍힐수있다.
			success : function (data) {
				console.log("data : " +  data);
				checkInput.attr('disabled',false);
				code =data;
				alert('인증번호가 전송되었습니다.')
			}			
		}); // end ajax
	}); // end send eamil

우선 회원가입 도중에 진행되는 부분이라 비동기통신인 ajax를 진행한다.

GET방식으로 진행하며 기존에 있던 name 파라미터 값을 그대로 컨트롤러로 옮기려고한다. 

 


3. SPRING 부분 

 

 

//이메일 인증
	@GetMapping("/mailCheck")
	@ResponseBody
	public String mailCheck(String email) {
		System.out.println("이메일 인증 요청이 들어옴!");
		System.out.println("이메일 인증 이메일 : " + email);
	}

 

Get방식으로 가져오며 이메일을 확인 할 수있게 간단하게 프린트로 찍어준다. 

이때 변수의 이름이 동일하면 @붙는 아노테이션을 지정 안할수 있다.

 

굳 아주 잘 들어오는 것을 알 수있다.

 

컨트롤러에서 다 작성해주어도 되지만 컨트롤러가 너무 비대해지기 때문에 따로 MailSendService라는

CLASS를 하나 만들어서 진행하려고 한다. 

 

클래스는 만들었다면 빈등록을 해주어야한다. 

 

Spring 폴더에 있는 경로로 빈 xml 파일을 만들어 주어 설정값을 해주었다.

 

XML 빈등록

 

   <context:property-placeholder location="classpath:/db-config/email.properties" />

   <!-- 이메일 인증 관련 빈 등록 -->
   <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
      <property name="host" value="smtp.gmail.com" />
      <property name="port" value="587" />
      <property name="username" value="${email.account}" />
      <property name="password" value="${email.password}" />
      <property name="javaMailProperties">
         <props>
                <prop key="mail.transport.protocol">smtp</prop>
                <prop key="mail.smtp.auth">true</prop>
                <!-- gmail의 경우 보안문제 업데이트로 인해 SSLSocketFactory를 추가해야 smtp 사용 가능. -->
                <prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
                <prop key="mail.smtp.starttls.enable">true</prop>
                <prop key="mail.debug">true</prop>
                <prop key="mail.smtp.ssl.trust">smtp.gmail.com</prop>
				<prop key="mail.smtp.ssl.protocols">TLSv1.2</prop>
            </props>
      </property>
      
   </bean>

각 property의 값

host : 이메일 보낼 url을 입력

port : 포트 번호 입력

userName : 이메일을 보낼 아이디 입력

Password : 이메일 비번

 

아래 키값은 보안 업데이트로 따로 추가 해 주어야한다. 

 

아이디 비밀번호가 노출되는게 싫은 경우 file을 따로 만들어서 빈 주입후 따로 사용이 가능하다. 

 

다시 돌아와서 

 

MailSendService.class 제작🥰

 

@Component
public class MailSendService {
	@Autowired
	private JavaMailSenderImpl mailSender;
	private int authNumber; 
	// 난수 발생(여러분들 맘대러)
	
		public void makeRandomNumber() {
			// 난수의 범위 111111 ~ 999999 (6자리 난수)
			Random r = new Random();
			int checkNum = r.nextInt(888888) + 111111;
			System.out.println("인증번호 : " + checkNum);
			authNumber = checkNum;
		}
		
		
				//이메일 보낼 양식! 
		public String joinEmail(String email) {
			makeRandomNumber();
			String setFrom = ".com"; // email-config에 설정한 자신의 이메일 주소를 입력 
			String toMail = email;
			String title = "회원 가입 인증 이메일 입니다."; // 이메일 제목 
			String content = 
					"홈페이지를 방문해주셔서 감사합니다." + 	//html 형식으로 작성 ! 
	                "<br><br>" + 
				    "인증 번호는 " + authNumber + "입니다." + 
				    "<br>" + 
				    "해당 인증번호를 인증번호 확인란에 기입하여 주세요."; //이메일 내용 삽입
			mailSend(setFrom, toMail, title, content);
			return Integer.toString(authNumber);
		}
		
		//이메일 전송 메소드
		public void mailSend(String setFrom, String toMail, String title, String content) { 
			MimeMessage message = mailSender.createMimeMessage();
			// true 매개값을 전달하면 multipart 형식의 메세지 전달이 가능.문자 인코딩 설정도 가능하다.
			try {
				MimeMessageHelper helper = new MimeMessageHelper(message,true,"utf-8");
				helper.setFrom(setFrom);
				helper.setTo(toMail);
				helper.setSubject(title);
				// true 전달 > html 형식으로 전송 , 작성하지 않으면 단순 텍스트로 전달.
				helper.setText(content,true);
				mailSender.send(message);
			} catch (MessagingException e) {
				e.printStackTrace();
			}
		}
		
	
}

🥰

makeRandomNumber()

이메일을 보낼때 인증번호로 111111~999999까지의 난수를 발생시킨다.

 

public String joinEmail(String email)

컨트롤러에서 아이디가 넘어오면서 붙을 스트링값

메일 샌드로 보내줄 준비를 마친다.

 

public void mailSend(String setFrom, String toMail, String title, String content) {

 

 

MimeMessage message = mailSender.createMimeMessage(); 객체를 생성해준다.

이것이 스프링에서 제공하는 메일 API이다.

 

여기서 중요한 점은 빈 자동등록을 위해 @component를 해준다. 

 

 

컨트롤러 마무리😊

 

	
	@Autowired
	private IUserService service;
	@Autowired
	private MailSendService mailService;
	


	
	//회원가입 페이지 이동
	@GetMapping("/userJoin")
	public void userJoin() {}
	
	//이메일 인증
	@GetMapping("/mailCheck")
	@ResponseBody
	public String mailCheck(String email) {
		System.out.println("이메일 인증 요청이 들어옴!");
		System.out.println("이메일 인증 이메일 : " + email);
		return mailService.joinEmail(email);
		
			
	}

우선 아까 만들어둔 mailsendService 부분을 등록해준다. 

AutoWired로 자동 빈등록을 해준다. 

 

이제 Jsp파일 > 컨트롤러로 이메일값을 전달해주면 리턴값으로 Email을 전달하면서 

아까 만들어둔 메일을 발송해준다.

 


🤪 JS 마무리!🤪 

아까 만들어 둔 Jsp파일에 Js부분을 마무리해준다. 

 

$('#mail-Check-Btn').click(function() {
		const eamil = $('#userEmail1').val() + $('#userEmail2').val(); // 이메일 주소값 얻어오기!
		console.log('완성된 이메일 : ' + eamil); // 이메일 오는지 확인
		const checkInput = $('.mail-check-input') // 인증번호 입력하는곳 
		
		$.ajax({
			type : 'get',
			url : '<c:url value ="/user/mailCheck?email="/>'+eamil, // GET방식이라 Url 뒤에 email을 뭍힐수있다.
			success : function (data) {
				console.log("data : " +  data);
				checkInput.attr('disabled',false);
				code =data;
				alert('인증번호가 전송되었습니다.')
			}			
		}); // end ajax
	}); // end send eamil
	
	// 인증번호 비교 
	// blur -> focus가 벗어나는 경우 발생
	$('.mail-check-input').blur(function () {
		const inputCode = $(this).val();
		const $resultMsg = $('#mail-check-warn');
		
		if(inputCode === code){
			$resultMsg.html('인증번호가 일치합니다.');
			$resultMsg.css('color','green');
			$('#mail-Check-Btn').attr('disabled',true);
			$('#userEamil1').attr('readonly',true);
			$('#userEamil2').attr('readonly',true);
			$('#userEmail2').attr('onFocus', 'this.initialSelect = this.selectedIndex');
	         $('#userEmail2').attr('onChange', 'this.selectedIndex = this.initialSelect');
		}else{
			$resultMsg.html('인증번호가 불일치 합니다. 다시 확인해주세요!.');
			$resultMsg.css('color','red');
		}
	});

Ajax부분을 우선 완성해준다! 

 

error는 없다 왜냐하면 완벽하다! 

제발..

 

우선 funtion(data)값으로 아까 보내둔 인증번호가 왔을 것이다. 

이제 이것을 비교해 주면서 회원가입을 처리해주면 될것이다. 

 

 

인증번호 어서오고

이제 받은 data값으로 인증번호를 비교 하면 된다 .

위의 코드를 참조 바란다. 

 


🤩동작 확인🤩

 

우선 이메일을 보낼 주소를 입력해주고

 

alert창이 나를 반긴다.
!?
오오 .. 인증번호는 376236이라고 한다. 이제 입력해보자!
우선 거짓말을 해보았다. 역시 거짓말은 안통한다.
콤퓨타가 준 코드를 넣었다. 이제 반응한다. 쨔식... 

 

 

이거 좀 어려워서 한두번 정도 더 반복을 해보아야겠다. 

 

항상 지적은 환영! 

 

위의 코드를 쓴 깃 주소이다 . 한번쯤 방문해보자!

 

https://github.com/MoonSeokHyun/spring/tree/master/MyWeb/src

반응형
반응형

저번에 포스팅 했던 회원가입 및 로그인 검증은 우선 끝낫다. 

이제 저번에 만들었던 게시판을 한번 만들어 보고자 한다! 

 

사용 기술 Tools
Java 11 jdk STS3
Oracle 18g SQLDev

 

 

 

1. SQL 테이블 생성 😎 

 

 -- 게시판 테이블 생성
CREATE TABLE mvc_board (
    board_no NUMBER PRIMARY KEY,
    title VARCHAR2(100) NOT NULL,
    content VARCHAR2(300) NOT NULL,
    writer VARCHAR2(50) NOT NULL,
    reg_date DATE DEFAULT sysdate,
    view_cnt NUMBER DEFAULT 0
);

-- board_no에 대한 시퀀스 설정
CREATE SEQUENCE board_seq
    START WITH 1
    INCREMENT BY 1
    MAXVALUE 1000
    NOCYCLE
    NOCACHE;

우선 게시판을 만들 수있는 뼈대 즉 테이블 부터 생성해준다! 

 

 


2. BoardVO 생성 🤪

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class BoardVO {
	
	private int boardNo;
	private String title;
	private String content;
	private String writer;
	private Timestamp regDate;
	private int viewCnt;
	
	//new 마크 부착 여부 논리타입 필드
	private boolean newMark;
	

}

 

우선 Getter or Setter를 좀 더 쉽게 하기 위해 lombok을 사용하였다. 


3.  HTML 제작

 

	<div class="container">
		<div class="row">
			<div class="col-lg-2">
			</div>
			<div class="col-lg-8">
				<div class="panel-body">
				<h2 class="page-header"><span style="color: #643691;">Spring</span> 자유 게시판
					<span id="count-per-page" style="float: right;">
	                     <input class="btn btn-cpp" type="button" value="10">  
	                     <input class="btn btn-cpp" type="button" value="20">   
	                     <input class="btn btn-cpp" type="button" value="30">
                     </span>
					
				</h2>
					<table class="table table-bordered table-hover">
						<thead>
							<tr style="background-color: #643691; margin-top: 0; height: 40px; color: white; border: 0px solid #f78f24; opacity: 0.8">
								<th>#번호</th>
								<th>작성자</th>
								<th>제목</th>
								<th>작성일</th>
								<th>조회수</th>
							</tr>
						</thead>

						<!-- 게시물이 들어갈 공간 -->
						<c:forEach var="b" items="${articles}">
							<tr style="color: #643691;">
								<td>${b.boardNo}</td>
								<td>${b.writer}</td>

								<td><a style="margin-top: 0; height: 40px; color: orange;"
								 href="<c:url value="/board/content/${b.boardNo}${pc.makeUri(pc.paging.page)}"/>">
										${b.title} 
									</a>
									&nbsp;
									<c:if test="${b.newMark}">
										<img alt="newmark" src="C:\Users\mls00\OneDrive\바탕 화면\SpringWebMvcProject\src\main\webapp\resources\img\icon_new.gif">
									</c:if>
								</td>

								<td> <fmt:formatDate pattern="yyyy-MM-dd hh:mm:ss" value="${b.regDate}"/></td>
								<td>${b.viewCnt}</td>
							</tr>
						</c:forEach>
						
						
					</table>
					
					<!-- 페이징 처리 부분  -->
						<ul class="pagination justify-content-center">
					<c:if test="${pc.prev}">
                       	<li class="page-item">
							<a class="page-link" href="/board/list/?${pc.makeUri(pc.beginPage-1)}"
							style="background-color: #643691; margin-top: 0; height: 40px; color: white; border: 0px solid #f78f24; opacity: 0.8">이전</a>
						</li></c:if>
				
						<c:forEach var="num" begin="${pc.beginPage}" end="${pc.endPage}" >
							<li class="page-item">
						   <a href="/board/list${pc.makeUri(num)}" 
						   class="page-link  ${pc.paging.page == num ? 'page-active': '' }" style="margin-top: 0; height: 40px; color: pink; border: 1px solid #643691;">${num}</a>
						</li>
					   </c:forEach>
					
					 <c:if test="${pc.next}">
					     <li class="page-item">
					      <a class="page-link" href='<c:url value='/board/list${pc.makeUri(pc.endPage+1)}}'/>' 
					      style="background-color: #643691; margin-top: 0; height: 40px; color: white; border: 0px solid #f78f24; opacity: 0.8">다음</a>
					    </li>
				    </ul></c:if>
					
					<!-- 페이징 처리 끝 -->
					</div>
				</div>
			</div>
					<!-- 검색 버튼 -->
					<div class="row">
						<div class="col-sm-2"></div>
	                    <div class="form-group col-sm-2">
	                        <select id="condition" class="form-control" name="condition">                            	
	                            <option value="title" ${param.condition == 'title' ? 'selected' : '' }>제목</option>
	                            <option value="content"${param.condition == 'content' ? 'selected' : '' }>내용</option>
	                            <option value="writer"${param.condition == 'writer' ? 'selected' : '' }>작성자</option>
	                            <option value="titleContent"${param.condition == 'titleContent' ? 'selected' : '' }>제목+내용</option>
	                        </select>
	                    </div>
	                    <div class="form-group col-sm-4">
	                        <div class="input-group">
	                            <input type="text" class="form-control" name="keyword" id="keywordInput" placeholder="검색어" value="${param.keyword}">
	                            <span class="input-group-btn">
	                                <input type="button" value="검색" class="btn btn-cpp btn-flat" id="searchBtn">                                       
	                            </span>
	                        </div>
	                    </div>
	                    <div class="col-sm-2">
							<a href="<c:url value ="/board/write"/>" class="btn btn-cpp float-right">글쓰기</a>
						</div>
						<div class="col-sm-2"></div>
					</div>
		
	</div>

 

기본 뼈대의 Html이다 CSS는 BOOTSTRAP을 사용하였다. 😎😎😎

 


4. 본격적인 Spring 시작!😁

 

4-1 Controller 제작

 

 

@Controller
@RequestMapping("/board")
public class BoardController {

   @GetMapping("/list")
   public String list(Model model) {
      System.out.println("/board/list: GET");
      model.addAttribute("articles", service.getArticleList());
      
      return "board/list";
   	}
   }

 

 

4-2 인터페이스 제작

package com.spring.mvc.board.service;

import java.util.List;

import com.spring.mvc.board.commons.SearchVO;
import com.spring.mvc.board.commons.pageVO;
import com.spring.mvc.board.model.BoardVO;

public interface IBoardService {

	//게시글 등록 기능
	void insert(BoardVO article);

	//게시글 전체 목록 기능
	List<BoardVO> getArticleList(SearchVO search);

	//게시글 상세 조회 기능
	BoardVO getArticle(int boardNo);

	//게시글 수정 기능
	void update(BoardVO article);

	//게시글 삭제 기능
	void delete(int boardNo);

	//게시물 수 조회 기능 
	int countArticles(SearchVO search);
	
	//날자 한글로 변경
	
}

 

IboardService를 만든다. 기능은 단순하게 세팅해준다.

 

그 다음은 IBoardMapper를 생성해준다.

 

package com.spring.mvc.board.repository;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Param;

import com.spring.mvc.board.commons.SearchVO;
import com.spring.mvc.board.commons.pageVO;
import com.spring.mvc.board.model.BoardVO;

public interface IBoardMapper {

	//게시글 등록 기능
	void insert(BoardVO article);
	
	//검색 결과와 페이지 정보까지 가지고 있는 하나의 객체를 매개값으로 받는 방식
	List<BoardVO> getArticleList(SearchVO search);
	//게시글 상세 조회 기능
	BoardVO getArticle(int boardNo);
	
	//게시글 수정 기능
	void update(BoardVO article);
	
	//게시글 삭제 기능
	void delete(int boardNo);
	
	//게시물 수 조회 기능
	int countArticles(SearchVO search);


	
	
}

 여기서 주의 할 점!

 

 MYBatis로 db연동을 진행할 떄 파라미터 값이 2개 이상이라면 
 1. @param으로 작성하는법

 2. map으로 포장해서 보내는법 

 3. 객체하나를 매개값으로 보내는법 들을 적절하게 상황에 맞게 선택하면 됨

 

 

주로 Map을 이용한 방법을 많이 쓴다. 

 

 


5. Service 제작 👏

package com.spring.mvc.board.service;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.spring.mvc.board.commons.SearchVO;
import com.spring.mvc.board.commons.pageVO;
import com.spring.mvc.board.model.BoardVO;
import com.spring.mvc.board.repository.IBoardMapper;

@Service
public class BoardService implements IBoardService {
	
	@Autowired
	private IBoardMapper mapper;

	@Override
	public void insert(BoardVO article) {
		mapper.insert(article);
	}


	@Override
	public List<BoardVO> getArticleList(SearchVO search) {
		//mapper에게 전달할 맵 데이터를 생성
//		Map<String, Object> datas = new HashMap<>();
//		datas.put("paging", paging);
//		datas.put("keyword", keyword);
//		datas.put("condition", condition);
		
		List<BoardVO> list = mapper.getArticleList(search);
		for(BoardVO article : list) {
			long now = System.currentTimeMillis();
			long regTime = article.getRegDate().getTime();
			if(now - regTime < 60 * 60*24 *1000) {
				article.setNewMark(true);
			}
		}
		return list;
	}

	@Override
	public BoardVO getArticle(int boardNo) {
		return mapper.getArticle(boardNo);
	}

	@Override
	public void update(BoardVO article) {
		mapper.update(article);
	}

	@Override
	public void delete(int boardNo) {
		mapper.delete(boardNo);
	}
	
	@Override
	public int countArticles(SearchVO search){
		return mapper.countArticles(search);
	}
	
}

 

IServiceBoard를 Add하여 생성해준다.

 

 

 


6. Mapper 제작🤞

 

Mapper 를 제작해준다. 

이때 꿀팁

<mybatis-spring:scan base-package="com.spring.mvc.board.repository"/>
<mybatis-spring:scan base-package="com.spring.mvc.user.repository"/>

Context-root.xml 파일일에 Mybatis.xml파일을 bean으로 등록하기 위한 스캔 설정을 해줍니다. 

<interceptors>
		<interceptor>
			<!-- <mapping path="/board/**"/>  -->	
			<mapping path="/board/write"/>
			<mapping path="/board/content/**"/> <!-- **은 글번호  -->
			<beans:bean class="com.spring.mvc.board.commons.intercertor.BoardInterceptor" />
		</interceptor>

이때 servlet-config.xml에서 이렇게 설정을 해주면 별도로 xml 파일을 만들때 빈등록을 안해줘도 됩니다. 

👏👏👏👏즉 위 지정된 경로만 지정해주면 된다! 👏👏👏👏

 

위에 지정한 대로 파일을 이렇게 설정 하였다!

	<select id="getArticleList" resultMap="BoardMap">

		SELECT * FROM mvc_board
		
		ORDER BY board_no DESC
		

	</select>

리스트를 불러올 수 있도록 Select 값을 넣어준다!

	<insert id="insert">
		INSERT INTO mvc_board
		(board_no, title, content, writer)
		VALUES(board_seq.NEXTVAL,#{title},#{content},#{writer})
	</insert>

그리고 현재 insert 관련하여 컨트롤러나 이런부분을 만들지 않았다 하지만 게시물이 보이는

리스트를 만들려면 insert를 하여 볼 데이터가 필요했다. 

sqldev로 해도 되지만 plsql하기 귀찮아 Junit으로 테스트를 한다. 

 


7. Junit Test

 

package com.spring.mvc.board;

import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.spring.mvc.board.model.BoardVO;
import com.spring.mvc.board.repository.IBoardMapper;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/mvc-config.xml"})
public class BoardMapperTest {

	@Autowired
	private IBoardMapper mapper;
	
	//게시글 등록 단위 테스트
	@Test
	public void insertTest() {
		for(int i=1; i<=300; i++) {
			BoardVO article = new BoardVO();
			article.setTitle("테스트 제목입니다." + i);
			article.setWriter("김테스트" + i);
			article.setContent("테스트 중이니까 조용히 하세요!" + i);
			mapper.insert(article);
		}
	}

 

우선 300개만 가볍게 넣어보자

 

데이터가 잘 들어갔다면 이제 화면에 뿌려주자!

 


8. 화면 작업

<c:forEach var="b" items="${articles}">
		<tr style="color: #643691;">
		<td>${b.boardNo}</td>
		<td>${b.writer}</td>

		<td><a style="margin-top: 0; height: 40px; color: orange;"
		href="<c:url value="/board/content/${b.boardNo}${pc.makeUri(pc.paging.page)}"/>">
		${b.title} 
		</a>
		&nbsp;
		<c:if test="${b.newMark}">
		<img alt="newmark" src="C:\Users\mls00\OneDrive\바탕 화면\SpringWebMvcProject\src\main\webapp\resources\img\icon_new.gif">
		</c:if>
		</td>

		<td> <fmt:formatDate pattern="yyyy-MM-dd hh:mm:ss" value="${b.regDate}"/></td>
		<td>${b.viewCnt}</td>
		</tr>
		</c:forEach>
						
						
		</table>

 

Jstl 을 이용하여 받아온 파라미터 값을 뿌려준다.

😎<c:forEach var="b" items="${articles}">😎

😎변수는 b로 하고 뿌려준다!😎


😎

9. 동작 확인🙏

 

 

테스트로 넣은 게시글이 잘 보이는걸 알 수 있다!

 

또 오류 나는 줄 알고 십년감수했다.☠️

 

 

 

주인장 Github 

 

https://github.com/MoonSeokHyun

반응형
반응형

저번에 포스팅 했던 회원가입 진행 및 아이디 중복 체크에 404에러 뜨던것 해결 했다. 

 

나는 바보였다.  학원 강사님께 문의 하니 경로가 잘 못되었엇다. 

 

Spring

🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏🙏

기도 메타가 부족했나 이번에는 🙏 *100으로  도전 한다. 

 


1. 문제의 원인🕵️‍♂️

 

<Context docBase="MyWeb" path="/myweb" reloadable="true" 
source="org.eclipse.jst.jee.server:MyWeb"/><Context docBase="SpringWebMvcProject"
path="/mvc" 
reloadable="true" source="org.eclipse.jst.jee.server:SpringWebMvcProject"/></Host>
    </Engine>

톰캣 서버 내의 context root의 path가 /인줄 알았는데 알고보니 /mvc 더라..

 


 

2. 문제의 해결🕵️‍♂️

 

$.ajax({
         		 type :'post', // 서버에 전송하는 http방식
         		 url :'/mvc/user/checkId', // 서버 요청 url
         		 headers : {
         			 'Content-Type' : 'application/json'
         		 },
        		 data : id, // 서버로 전송할 데이터 // 위에서 지정한 const id 
        		 success : function(result) { // 매개변수에 통신성공시 데이터가 저장된다.
					//서버와 통신성공시 실행할 내용 작성.
					console.log('통신 성공!' + result);
        		 	if(result === 'available'){
        		 		 $('#user_id').css('background-color', 'aqua');
        		 		 $('#idChk').html('<b style="font-size: 14px; color: green">[아이디 사용이 가능하다.]</b>');
        		 		 chk1 = true;
        		 	}else{
        		 		 $('#user_id').css('background-color', 'pink');
        		 		 $('#idChk').html('<b style="font-size: 14px; color: red">[아이디 중복!.]</b>');
        		 		 chk1 = false;
        		 	}
				},
				error : function (status, error) { //통신에 실패했을때
					console.log('통신실패');
					console.log(status, error)
				}
          	}); // end ajax(아이디 중복 확인)
         }

url 부분은 기존에 /mvc/가 빠졋었다. 

/mvc를 넣었더니 정상 작동을 하였다. 

 

 

이것과 별개로 

 

url : "<c:url value ='/user/checkId'/>

 

<c:url value ='url값'/>을 쓰는것도 방법이다. 다음부터는 이방법 위주로 쓰려고 한다.,😻😻😻

 

 


3. 정상 동작 확인💪

드디어 정상적으로 확인!!

 

드디어 올 파랭이를 볼수 있음!!!

 

👏👏👏👏👏👏👏👏

 

 

문제 해결 !👏

 

 

주인장  git 주소 : https://github.com/MoonSeokHyun

반응형
반응형
	@Override
	public void keepLogin(String session, Date limitTime, String account) {
		Map<String, Object> datas = new HashMap<String, Object>();
		datas.put("sessionId", session);
		datas.put("limitTime", limitTime);
		datas.put("account", account);
		
		mapper.keepLogin(datas);
	}
    
    	@Override
	public UserVO selectOne(String account) {
		return mapper.selectOne(account);
	}

로그인 처리를 위한 html 코드 작성. 🤩

 

부트스트랩으로 작성되었음!!

<div class="modal-body">
<table style="cellpadding: 0; cellspacing: 0; margin: 0 auto; width: 100%">
<tr>
	<td style="text-align: left">
		<p><strong>아이디를 입력해주세요.</strong>&nbsp;&nbsp;&nbsp;<span id="idCheck"></span></p>
	</td>
</tr>
<tr>
<td><input type="text" name="userId" id="signInId"
	class="form-control tooltipstered" maxlength="10"
	required="required" aria-required="true"
	style="margin-bottom: 25px; width: 100%; height: 40px; border: 1px solid #d9d9de"
	placeholder="최대 10자"></td>
	</tr>
	<tr>
<td style="text-align: left">
<p><strong>비밀번호를 입력해주세요.</strong>&nbsp;&nbsp;&nbsp;<span id="pwCheck"></span></p>
</td>
/tr>
	<tr>
	<td><input type="password" size="17" maxlength="20" id="signInPw"
	name="userPw" class="form-control tooltipstered" 
	maxlength="20" required="required" aria-required="true"
	style="ime-mode: inactive; margin-bottom: 25px; height: 40px; border: 1px solid #d9d9de"
								placeholder="최소 8자"></td>
		</tr>
		<!--  자동로그인 체크박스 -->
		<tr>
		<td><input type="checkbox" id="auto-login" name="autoLogin"> 자동 로그인</td>
			</tr>
			<tr>
		td style="padding-top: 10px; text-align: center">
		<p><strong>로그인하셔서 더 많은 서비스를 이용하세요~</strong></p>
			</td>
			</tr>
		tr>
		td style="width: 100%; text-align: center; colspan: 2;"><input
		type="button" value="로그인" class="btn form-control tooltipstered" id="signIn-btn"
		style="background-color: #643691; margin-top: 0; height: 40px; color: white; border: 0px solid #f78f24; opacity: 0.8">
			</td>
			</tr>
				<tr>
				<td
style="width: 100%; text-align: center; colspan: 2; margin-top: 24px; padding-top: 12px; border-top: 1px solid #ececec">

<a class="btn form-control tooltipstered" data-toggle="modal"
href="#sign-up"
style="cursor: pointer; margin-top: 0; height: 40px; color: white; background-color: orange; border: 0px solid #388E3C; opacity: 0.8">
			회원가입</a>
			</td>
			</tr>

		</table>
			
			</div>
		</div>
	</div>
</div>

2. 로그인 처리를 위한 JQuery문 🤩

  - 아이디 검증

 

 //각 입력값들의 유효성 검증을 위한 정규표현식을 변수로 선언.
         const getIdCheck = RegExp(/^[a-zA-Z0-9]{4,14}$/);
         const getPwCheck = RegExp(/([a-zA-Z0-9].*[!,@,#,$,%,^,&,*,?,_,~])|([!,@,#,$,%,^,&,*,?,_,~].*[a-zA-Z0-9])/);
         const getNameCheck = RegExp(/^[가-힣]+$/);
// ID 입력값 검증 (공백확인 , 정규표현식 어긋나는지 확인)
		$('#signInId').keyup(function() {
			if($(this).val() === ''){
				$(this).css('background-color', 'pink');
			 	$('#idCheck').html('<b style="font-size: 14px; color: red">[아이디는 필수 값입니다.]</b>');
			 	chk1 = false;
			}else if(!getIdCheck.test($(this).val())){
				$(this).css('background-color', 'pink');
			 	$('#idCheck').html('<b style="font-size: 14px; color: red">[아이디가 형식에 어긋납니다!]</b>');
			 	chk1 = false;
			}else{
				$(this).css('background-color', 'aqua');
			 	$('#idCheck').html('<b style="font-size: 14px; color: red">[아이디 입력 성공!]</b>');
			 	chk1 = true;
			}
/ 비밀번호 입력값 검증 (공백확인 , 정규표현식 어긋나는지 확인)
		$('#signInPw').keyup(function() {
			if($(this).val() === ''){
				$(this).css('background-color', 'pink');
			 	$('#pwCheck').html('<b style="font-size: 14px; color: red">[비밀번호는 필수 값입니다.]</b>');
			 	chk2 = false;
			}else if(!getPwCheck.test($(this).val())){
				$(this).css('background-color', 'pink');
			 	$('#pwCheck').html('<b style="font-size: 14px; color: red">[비밀번호가 형식에 어긋납니다.]</b>');
			 	chk2 = false;
			}else{
				$(this).css('background-color', 'aqua');
			 	$('#pwCheck').html('<b style="font-size: 14px; color: red">[비밀번호 입력 성공!]</b>');
			 	chk2 = true;
			}
		}); // 비밀번호 검증 끝

 

 

정규식 표현식으로 아이디가 어긋나는지 or 빈칸인지 둘다 만족 된다면 

else값으로 이동하여 OK표기!

 

 

$('#signIn-btn').click(function() {
			if(chk1 && chk2){
				// ajax를 이용한 비동기 방식으로 로그인을 처리할 예정이다. 
		        /*
		        아이디, 비밀번호를 가져오셔서 객체로 포장하세요.
		        비동기 통신을 진행하여 서버로 객체를 json형태로 전송하세요.
		        그리고, console.log()로 서버가 보내온 데이터를 확인하여
		        아이디가 없습니다, 비밀번호가 틀렸습니다, 로그인 성공이라는
		        메세지를 브라우저의 console창에서 확인하세요.
		        서버에서 클라이언트로 데이터 전송은 text로 이루어 질 것이며
		        idFail, pwFail, loginSuccess라는 문자열을 리턴할 것입니다.
		        전송방식: POST, url: /user/loginCheck
		        */
		        
				const id = $('#signInId').val();
				const pw = $('#signInPw').val();
				
				//자동로그인 체크박스가 체크가 되었는지의 여부 
				//제이쿼리 is 상태여부를 확인할 수 있는 함수 논리값을 판단하여 논리값을 리턴
				const autoLogin = $('#auto-login').is(':checked');
				
				console.log("id" + id);
				console.log("pw" + pw);
				const userInfo ={
						"account" : id,
						"password" : pw,
						
						//오토로그인 추가 체크의 여부를 확인하여 자동로그인을 구현할지 말지를 정한다. 
						"autoLogin" : autoLogin
				};
				// ajax 시작!
				$.ajax({
					type : "post",
					url : "/user/loginCheck",
					contentType : "application/json",
					dataType : "text",
					data : JSON.stringify(userInfo),
					success : function(result) {
						console.log("통신 성공" + result);
						if(result === 'idFail'){
							//console.log('아이디가 없습니다.');
							$('#idCheck').css('background-color', 'pink');
						 	$('#idCheck').html('<b style="font-size: 14px; color: red">[아이디가 없습니다.]</b>');
						 	$('#signInPw').val('');
						 	$("#singInPw").focus(); // 커서 이동 및 스크롤도 해당 위치로 이동시키는 함수 
						 	 chk2 = false;
						 	
						}else if (result === 'pwFail') {
							//console.log('비밀번호가 틀렸습니다.');
							$('#pwCheck').css('background-color', 'pink');
						 	$('#pwCheck').html('<b style="font-size: 14px; color: red">[비밀번호가 틀렷습니다.]</b>');
						 	$('#signInPw').val('');
						 	$("#singInId").focus(); // 커서 이동 및 스크롤도 해당 위치로 이동시키는 함수 
						 	chk1 = false;  chk2 = false;
						}else{
							console.log('로그인 성공');
							location.href = '/';
						}
					},
					error : function() {
						alert('로그인 실패!');
					}
				}); // ajax 종료!
				
			}else{
				alert('입력값을 다시 확인하세요');
			}
		}); /

if(chk1 && chk2){ 의값으로 

아이디 및 비밀번호 입력값이 모두가 true값이 진행되면 로그인 이벤트 처리 

ajax(비동기 통신으로 진행) 이제 컨트롤러 작성하러 가보자! 😀

 


3. 스프링 작성 🤩 

 

 

자 이제 컨트롤러 및 서비스 > 매퍼 및 xml을 작성 해보자!!

 

이번에도 비동기 통신임으로 

@RestController 
@RequestMapping("/user")

를 진행해준다. 그리고 user라는 url로 진행하였다. 

 

ajax에서 loginCheck라는 url으로 컨트롤러에 요청을 보내니 loginCheck와 같은 이름으로 작성한다. 

 

@PostMapping("/loginCheck")
	public String loginCheck(@RequestBody UserVO vo, HttpSession session , HttpServletResponse respones  ) {//HttpServletRequest request) {
		System.out.println("/user/logincheck : post");
		System.out.println("param : " + vo);
		
		// 매개값으로 httpsession 객체 받아서 사용
		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		UserVO dbData =  serivce.selectOne(vo.getAccount());
		// mybatis는 조회된 데이터가 없을경우 null이 온다.
		if(dbData != null) {
			if(encoder.matches(vo.getPassword(), dbData.getPassword())) {
				//로그인 성공 히원을 대상으로 세션 정보를 생성
				session.setAttribute("login", dbData);
					serivce.keepLogin(session.getId(), limitDate, vo.getAccount());
				}
				return "loginSuccess";
			}else {
				return "pwFail";
			}
		}else {
			return "idFail";
		}
		
	}

이때 session.setAttribute("login", dbData); 세션을 생성해준다. 

스프링에서는 간단하게 세션을 만들수 있다. 라는 login이라는 이름으로 dbDate의 값을 만들었다 . 이곳에는 userVO의 객체의 값이 들어있다. 

 

이때 selectOne의 서비스와 keeplogin의 코드를 작성한다. 

 

 

	@Override
	public UserVO selectOne(String account) {
		return mapper.selectOne(account);
	}
    
    	@Override
	public void keepLogin(String session, Date limitTime, String account) {
		Map<String, Object> datas = new HashMap<String, Object>();
		datas.put("sessionId", session);
		datas.put("limitTime", limitTime);
		datas.put("account", account);
		
		mapper.keepLogin(datas);
	}

 

이때 SeletOne은 로그인하는 아이디의 검증을 위해 사용된다. 

keeplogin은 세션의 유지 등에 사용된다. 

 

package com.spring.mvc.user.repository;

import java.util.Map;

import com.spring.mvc.user.model.UserVO;

public interface IUserMapper {
	
	//아이디 중복체크 기능
	int checkId(String account);
	
	//회원 가입기능
	void register(UserVO vo);
	
	//회원 정보 조회 기능 
	UserVO selectOne(String account);
	
	//회원 탈퇴 기능 
	void delete(String account);
	
	//자동 로그인 쿠키값 db 저장 처리
	//sql > update 문으로 작성
	void keepLogin(Map<String, Object> datas);
	
	//세션아이디를 통한 회원 정보조회기능
	/*
	  - 자동로그인을 하고 싶다는 사람한테 뭘 만들어 줬죠? > 쿠키(세션Id)
	  그리고 나서 그 사람이 나중에 우리사이트에 다시 방문했다고 칩시다. 
	  단연히 우리 서버에 요청을 보낼 거고 , 요청과 함게 쿠키도 같이 전달이 되겠죠? 
	  우리는 쿠키 안에 들어있는 세션 id로 회원 정보를 조회해서 마치 이사람이 로그인 중인 것 처럼 
	  세션 데이터를 만들어 주자는 겁니다. (login이라는 세션 데이터 -> 로그인 중이라는 징표)
	 */
	UserVO getUserWithSessionId(String sessionId);
	
	
}

 

매퍼 작성 후 xml을 작성해준다. 

 

	<!-- 자동로그인을 희망하는 경우 쿠키값(세션아이디)와 유효시간을 갱신 -->
	<update id="keepLogin">
		update mvc_user set session_id = #{sessionId}, LIMIT_TIME = #{limitTime}
		where account = #{account}
	</update>
    
         <select id="selectOne" resultMap="UserMap">
		SELECT * FROM mvc_user
		WHERE account=#{account}
	</select>

 

 

이제 세션이 얻어 졌으니 로그인 유지 작업을 해보자!

 


세션의 활용 로그인 유지 HTML,JS 작업😀

 

  <c:if test="${login != null}">
	           <li class="nav-item">
	            <a class="nav-link js-scroll-trigger" href="#">My Page</a>
	          </li>
	           <li class="nav-item">
	            <a class="nav-link js-scroll-trigger" href="<c:url value='/user/logout'/>" onclick="confirm('로그아웃 하시겠음?')">LOGOUT</a>
	          </li>
	          
           </c:if>
          
          <c:if test="${login == null}">
	           <li class="nav-item">
	            <a class="nav-link js-scroll-trigger" data-toggle="modal" data-target="#log-in">LOGIN</a>
	          </li>
  </c:if>

 

jstl을 활용하여 로그인 전에는 로그인 버튼이 생성되게

로그인 후에는 로그아웃 및 마이페이지가 생성  되게 하였다. 

 

 


마무리 확인 작업 😁

🙏

🙏

🙏

🙏

🙏

🙏

🙏

자!! 기도 메타 한번 가고

 

로그인 후의 navbar 화면
로그인 하기 전의 화면 

 

이렇게 세션 적용은 완료되었다. !

 

 

chk 1 && chk2 가 모두 true일 경우
둘중 하나가 false인 경우 로그인이 안된다.
모두 false일 경우

반응형
반응형

Js.html 영역

 

 

1. 기존의 회원가입 jsp부분의 HTML 파일

<div class="modal fade" id="sign-up" role="dialog">
	<div class="modal-dialog">

		<!-- Modal content-->
		<div class="modal-content">
			<div class="modal-header">
				<h4 class="modal-title">
					<span style="color: #643691;">Spring</span> 회원 가입
				</h4>
				<button type="button" class="close" data-dismiss="modal">×</button>

			</div>

			<div class="modal-body">


				<table
					style="cellpadding: 0; cellspacing: 0; margin: 0 auto; width: 100%">
					<tr>
						<td style="text-align: left">
							<p>
								<strong>아이디를 입력해주세요.</strong>&nbsp;&nbsp;&nbsp;<span id="idChk"></span>
							</p>
						</td>


					</tr>
					<tr>
						<td><input type="text" name="userId" id="user_id"
							class="form-control tooltipstered" maxlength="14"
							required="required" aria-required="true"
							style="margin-bottom: 25px; width: 100%; height: 40px; border: 1px solid #d9d9de"
							placeholder="숫자와 영어로 4-10자"></td>

					</tr>

					<tr>
						<td style="text-align: left">
							<p>
								<strong>비밀번호를 입력해주세요.</strong>&nbsp;&nbsp;&nbsp;<span id="pwChk"></span>
							</p>
						</td>
					</tr>
					<tr>
						<td><input type="password" size="17" maxlength="20"
							id="password" name="userPw" class="form-control tooltipstered"
							maxlength="20" required="required" aria-required="true"
							style="ime-mode: inactive; margin-bottom: 25px; height: 40px; border: 1px solid #d9d9de"
							placeholder="영문과 특수문자를 포함한 최소 8자"></td>
					</tr>
					<tr>
						<td style="text-align: left">
							<p>
								<strong>비밀번호를 재확인해주세요.</strong>&nbsp;&nbsp;&nbsp;<span
									id="pwChk2"></span>
							</p>
						</td>
					</tr>
					<tr>
						<td><input type="password" size="17" maxlength="20"
							id="password_check" name="pw_check"
							class="form-control tooltipstered" maxlength="20"
							required="required" aria-required="true"
							style="ime-mode: inactive; margin-bottom: 25px; height: 40px; border: 1px solid #d9d9de"
							placeholder="비밀번호가 일치해야합니다."></td>
					</tr>

					<tr>
						<td style="text-align: left">
							<p>
								<strong>이름을 입력해주세요.</strong>&nbsp;&nbsp;&nbsp;<span id="nameChk"></span>
							</p>
						</td>
					</tr>
					<tr>
						<td><input type="text" name="userName" id="user_name"
							class="form-control tooltipstered" maxlength="6"
							required="required" aria-required="true"
							style="margin-bottom: 25px; width: 100%; height: 40px; border: 1px solid #d9d9de"
							placeholder="한글로 최대 6자"></td>
					</tr>

					<tr>
						<td style="padding-top: 10px; text-align: center">
							<p>
								<strong>회원가입을 환영합니다~~!</strong>
							</p>
						</td>
					</tr>
					<tr>
						<td style="width: 100%; text-align: center; colspan: 2;"><input
							type="button" value="회원가입" class="btn form-control tooltipstered"
							id="signup-btn"
							style="background-color: #643691; margin-top: 0; height: 40px; color: white; border: 0px solid #388E3C; opacity: 0.8">
						</td>
					</tr>

				</table>

			</div>
		</div>
	</div>
</div>

</div>

 

 

2. 패스워드 입력값 검증을 위한 Js코드

 

 

         const getIdCheck = RegExp(/^[a-zA-Z0-9]{4,14}$/);
         const getPwCheck = RegExp(/([a-zA-Z0-9].*[!,@,#,$,%,^,&,*,?,_,~])|([!,@,#,$,%,^,&,*,?,_,~].*[a-zA-Z0-9])/);
         const getNameCheck = RegExp(/^[가-힣]+$/);
         
         
          $('#password').keyup(function() {
		
    	  //비밀번호 란에 공백 확인 
    	  if($(this).val() === ''){
    		  $(this).css('background-color', 'pink');
		 	  $('#pwChk').html('<b style="font-size: 14px; color: red">[비밀번호는 필수 정보 입니다..]</b>');
		 	  chk2 = false;
    	  }
    	  
    	  //비밀번호 유효성 검사 
    	  else if(!getPwCheck.test($(this).val()) || $(this).val().length < 8){
    		  $(this).css('background-color', 'pink');
		 	  $('#pwChk').html('<b style="font-size: 14px; color: red">[특수 문자 포함 8글자 이상 !]</b>');
		 	 chk2 = false;
    	  }// 통과
    	  else{
    		  $(this).css('background-color', 'aqua');
		 	  $('#pwChk').html('<b style="font-size: 14px; color: green">[비밀번호 입력 완료!]</b>');
		 	 chk2 = true;
    	  }
    	  
	});

 

위의 const getpwcheck로 코드로 비밀번호의 유효성 검사를 한다.

 

3. 비밀번호 확인란 검증

 

//3. 비밀번호 확인란 입력 검증 
$('#password_check').keyup(function() {
// 비밀번호 확인란 검증 
if($(this).val() === ''){
	$(this).css('background-color', 'pink');
	$('#pwChk2').html('<b style="font-size: 14px; color: red">[비밀번호는 확인은 필수 정보 입니다.]</b>');
	chk3 = false;
	}
	/ 비밀번호 확인란 유효성 검사.
	else if($(this).val() != $('#password').val()){
	 $(this).css('background-color', 'pink');
	 $('#pwChk2').html('<b style="font-size: 14px; color: red">[비밀번호가 일치하지 않습니다.]</b>');
	 chk3 = false;
	}else{
	 $(this).css('background-color', 'aqua');
	 $('#pwChk2').html('<b style="font-size: 14px; color: green">[비밀번호 입력 확인 완료]</b>');
	chk3 = true;
}

 

 

4. 이름 입력값 검증

 

		$('#user_name').keyup(function() {
			if($(this).val === ''){
				 $(this).css('background-color', 'pink');
			 	 $('#nameChk').html('<b style="font-size: 14px; color: red">[이름은 필수 정보 입니다. ]</b>');
			 	 chk4 = false;
			}else if(!getNameCheck.test($(this).val())){
				 $(this).css('background-color', 'pink');
			 	 $('#nameChk').html('<b style="font-size: 14px; color: red">[이름은 한글 이외에 다른 값은 입력 할 수 없습니다. ]</b>');
			 	 chk4 = false;
			}else{
				$(this).css('background-color', 'aqua');
			 	 $('#nameChk').html('<b style="font-size: 14px; color: red">[이름 입력 완료! ]</b>');
			 	 chk4 = true;
			}
		}); //이름 입력 끝

5. 회원가입 

 

$('#signup-btn').click(function() {
			
			if(chk1 && chk2 && chk3 && chk4){
				
				//Id정보 
				const id = $("#user_id").val();
				//pw정보
				const pw = $('#password').val();
				//name
				const name = $('#user_name').val();
				//프로퍼티 이름은 반드시 userVO와 같아야 동작이 된다!! 매우 중요!
				const user ={
						"account" : id,
						"password" : pw,
						"name" : name
						// json 아님
				}
				
				// 비동기 통신 시작! 
				$.ajax({
					type : "post",
					url : "/user/",
					contentType : "application/json",
					dataType : "text",
					// 자바스크립트 객체를 json문자열로 변환해 주는 메소드
					data : JSON.stringify(user),
					success : function(result) {
						console.log("통신 성공" + result);
						alert('회원가입을 축하합니다.');
						location.href ="/";
					},
					error : function() {
						alert('회원가입 실패!');
					}
				})
			}else {
				alert('입력정보를 확인 해 주세요.');
			}
			
		})/

사용자가 회원 가입 버튼을 눌렀을 때 이벤트 처리 및 사용자가 입력하는 4가지 데이터 

(ID, PASSWORD, PASSWORD_CHECK, NAME ) 가 모두 일치해야 된다.

 

이때 ajax에서 url user쪽 컨트롤러로 const user의 정보의 객체에 담아 json 형식으로 요청을 보내게 된다.

 


스프링 영역

 

6. 컨트롤러 작성

 

	@PostMapping("/")
	public String register(@RequestBody UserVO vo) {
		System.out.println("/user/ : post");
		serivce.register(vo);
		return "joinSuccess";
	}

 

 

ajax에서 user객체를 담아 컨트롤러로 보내주어 @RequestBody의 어노테이션으로 UserVO를 전달 받아

service 쪽으로 넘기게 된다. 

 

7. 서비스 작성

 

	public void register(UserVO vo) {
		//회원 비밀번호를 암호화 인코딩
		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		System.out.println("암호화 하기 전 비번 : " + vo.getPassword());
		
		//비밀번호를 암호화 해서 user객체에 다시 저장하기.
		String securepw = encoder.encode(vo.getPassword());
		System.out.println("암호화 후 비번 : " + securepw);
		vo.setPassword(securepw);
		
		mapper.register(vo);
	}

이때 스프링의 메이븐 API인 회원 비밀번호를 암호화 하여 저장한다. 

사용 Api 명은 Spring Security이다 사용방법은 나중에 포스팅 하도록 겠다. 

 

4,5번은 암호화를 진행한 패스워드 6번은 암호화 미적용

다만 주의할 점은 암호화를 할 경우에 암호화 이전에 만들었던 아이디와 패스워드로는 로그인이 불가능하다.

 

이제 서비스에서 Mapper.register 쪽으로  User의 값을 전달한다.

 

	void register(UserVO vo);

이제 회원 가입을 할 xml을 만들자

 

8. Mapper.xml 작성

 

 <mapper namespace="com.spring.mvc.user.repository.IUserMapper">
    
    <resultMap type="com.spring.mvc.user.model.UserVO" id="UserMap">
    	<result property="regDate" column="reg_date"/>
    	<result property="sessionId" column="session_id"/>
    	<result property="limitTime" column="limit_time"/>
    </resultMap>
    
     	<insert id="register">
     	iNSERT INTO mvc_user
		(account,password,name)
		VALUES(#{account},#{password},#{name})
     	</insert>

 

코드블럭에는 xml이 없구낭... 

 

mapper의 namespace에는 직전에 작성하였던 IuserMapper의 경로를 넣어준다. 

 

이때 데이터베이스의 컬럼명과 VO객체의 변수명의 이름이 다를 때 ResultMap 이라는 태그를 작성해야한다. 

property ="UserVO의 변수명" column ="DB의 컬럼명" 을 작성해 준다.

 

단 이것은 Select문에서 적용한다 

Insert에서는 사용하지 않는다 하지만  미리 작성해서 나쁠건 없다.

 

 


 

8. 최종 동작 확인 

 

ㅇ ㅏ.. ajax에서 404에러다.. 

컨트롤러에서 리퀘스트바디나 url 문제같은데.. 

 

다했는데.. 

 

다음 포스팅은 아마도 오류 해결을 해야할거같다..

반응형
반응형

1. 회원가입 html을 작성 

<!-- 회원가입 Modal -->
<div class="modal fade" id="sign-up" role="dialog">
	<div class="modal-dialog">

		<!-- Modal content-->
		<div class="modal-content">
			<div class="modal-header">
				<h4 class="modal-title">
					<span style="color: #643691;">Spring</span> 회원 가입
				</h4>
				<button type="button" class="close" data-dismiss="modal">×</button>

			</div>

			<div class="modal-body">

				
					<table
						style="cellpadding: 0; cellspacing: 0; margin: 0 auto; width: 100%">
						<tr>
							<td style="text-align: left">
								<p><strong>아이디를 입력해주세요.</strong>&nbsp;&nbsp;&nbsp;<span id="idChk"></span></p>
							</td>
								
							
						</tr>
						<tr>
							<td><input type="text" name="userId" id="user_id"
								class="form-control tooltipstered" maxlength="14"
								required="required" aria-required="true"
								style="margin-bottom: 25px; width: 100%; height: 40px; border: 1px solid #d9d9de"
								placeholder="숫자와 영어로 4-10자">
								</td>
							
						</tr>

						<tr>
							<td style="text-align: left">
								<p><strong>비밀번호를 입력해주세요.</strong>&nbsp;&nbsp;&nbsp;<span id="pwChk"></span></p>
							</td>
						</tr>
						<tr>
							<td><input type="password" size="17" maxlength="20" id="password"
								name="userPw" class="form-control tooltipstered" 
								maxlength="20" required="required" aria-required="true"
								style="ime-mode: inactive; margin-bottom: 25px; height: 40px; border: 1px solid #d9d9de"
								placeholder="영문과 특수문자를 포함한 최소 8자"></td>
						</tr>
						<tr>
							<td style="text-align: left">
								<p><strong>비밀번호를 재확인해주세요.</strong>&nbsp;&nbsp;&nbsp;<span id="pwChk2"></span></p>
							</td>
						</tr>
						<tr>
							<td><input type="password" size="17" maxlength="20" id="password_check"
								name="pw_check" class="form-control tooltipstered" 
								maxlength="20" required="required" aria-required="true"
								style="ime-mode: inactive; margin-bottom: 25px; height: 40px; border: 1px solid #d9d9de"
								placeholder="비밀번호가 일치해야합니다."></td>
						</tr>

						<tr>
							<td style="text-align: left">
								<p><strong>이름을 입력해주세요.</strong>&nbsp;&nbsp;&nbsp;<span id="nameChk"></span></p>
							</td>
						</tr>
						<tr>
							<td><input type="text" name="userName" id="user_name"
								class="form-control tooltipstered" maxlength="6"
								required="required" aria-required="true"
								style="margin-bottom: 25px; width: 100%; height: 40px; border: 1px solid #d9d9de"
								placeholder="한글로 최대 6자"></td>
						</tr>

						<tr>
							<td style="padding-top: 10px; text-align: center">
								<p><strong>회원가입을 환영합니다~~!</strong></p>
							</td>
						</tr>
						<tr>
							<td style="width: 100%; text-align: center; colspan: 2;"><input
								type="button" value="회원가입" 
								class="btn form-control tooltipstered" id="signup-btn"
								style="background-color: #643691; margin-top: 0; height: 40px; color: white; border: 0px solid #388E3C; opacity: 0.8">
							</td>
						</tr>

					</table>
			
			</div>
		</div>
	</div>

 

 


2. 검증로직 작성(아이디 공백란)

 

$(function() {
      
      //각 입력값들의 유효성 검증을 위한 정규표현식을 변수로 선언.
         const getIdCheck = RegExp(/^[a-zA-Z0-9]{4,14}$/);
         const getPwCheck = RegExp(/([a-zA-Z0-9].*[!,@,#,$,%,^,&,*,?,_,~])|([!,@,#,$,%,^,&,*,?,_,~].*[a-zA-Z0-9])/);
         const getNameCheck = RegExp(/^[가-힣]+$/);
         
      // 입력값 중 하나라도 만족하지 못한다면 회원가입 처리를 막기위한 논리형 변수 선언.
     	 let chk1 = false, chk2 = false, chk3 = false, chk4 = false;
     	    
      //회원가입시 사용자의 입력값 검증!
      
      //1. ID입력값 검증 
      $('#user_id').keyup(function() {
         if($(this).val() === '' ) {//지금 발생하는 이곳이 빈 문자열이니?
            $(this).css('background-color', 'pink');
            $('#idChk').html('<b style="font-size: 14px; color: red">[아이디는 필수값입니다.]</b>');//텍스트를 집어넣을거야 
            chk1 = false;
         }

 

나중에 입력값 유효성 검사 진행  let chk1 = false, chk2 = false, chk3 = false, chk4 = false;
if 각 부분에 chk1 = false 등 
if로 && 앤드기호로 다 트루값이 왔는지 확인 후 이벤트 종료

 


3. DB와 연동하여 비동기 통신으로 아이디 중복값 확인

 

 

//아이디 입력값 유효성 검사(영문으로만 4~14글자 허용)
         //정규표현식변수.test('검증하고 싶은 값')  => return boolean type
         //정규표현식에 어긋난 값이면 false, 올바른 값이면true를 반환
         else if(!getIdCheck.test($(this).val())) {//정규표현식이 틀렸다면
            $(this).css('background-color', 'pink');
            $('#idChk').html('<b style="font-size: 14px; color: red">[영문자, 숫자조합 4-14로쓰세요]</b>');
            chk1 = false;
         }else{//아이디 중복확인 ajax 사용, 특정 호직이 실행이 끝날 때까지 기다리지 않고 먼저 코드를 샐행 (페이지 전환 없이 통신)
        	 
         	//ID중복 확인 통신을 위해 입력값을 가져오기
         	const id = $(this).val();
         
         	//ajax 호출.
         	//클라이언트에서 서버와 비동기 통신을 진행하는 ajax함수.
         	$.ajax({
         		 type :'post', // 서버에 전송하는 http방식
         		 url :'/user/checkId', // 서버 요청 url
         		 headers : {
         			 'Content-Type' : 'application/json'
         		 },
         		 dataType : 'text', //서버로 부터 응답받을 데이터의 형태 
        		 data : id, // 서버로 전송할 데이터 // 위에서 지정한 const id 
        		 success : function(result) { // 매개변수에 통신성공시 데이터가 저장된다.
					//서버와 통신성공시 실행할 내용 작성.
					console.log('통신 성공!' + result);
        		 	if(result === 'available'){
        		 		 $('#user_id').css('background-color', 'aqua');
        		 		 $('#idChk').html('<b style="font-size: 14px; color: green">[아이디 사용이 가능하다.]</b>');
        		 		 chk1 = true;
        		 	}else{
        		 		 $('#user_id').css('background-color', 'pink');
        		 		 $('#idChk').html('<b style="font-size: 14px; color: red">[아이디 중복!.]</b>');
        		 		 chk1 = false;
        		 	}
				},
				error : function (status, error) { //통신에 실패했을때
					console.log('통신실패');
					console.log(status, error)
				}
          	}); // end ajax(아이디 중복 확인)
         }

 

ajax의 사용법!

1.type은 get이나 post 같은 http method를 나타낸다.

2.url는 데이터를 받아올 페이지다. 이 페이지의 코드는 곧 설명하겠다.

3.data는 요청시에 함께 보낼 파라미터들이다. 난 그냥 안보낼거라 비워뒀다.

4.dataType은 받아올 데이터의 형식인데, 빼놔도 된다.

5.success는 성공시에 수행할 핸들러를 받는다.

6.error는 실패시에 수행할 핸들러를 받는다.

 


4. 컨트롤러 작성

@PostMapping("/checkId")
	public String checkId(@RequestBody String account) {	// 받을 데이터타입이 텍스트라 스트링으로함 반드시 리퀘스트바디를 붙힐것! ajax 통신시
		System.out.println("/user/checkId : post");
		System.out.println("param : " + account );
		
		int checkNum = serivce.checkId(account);
		
		if(checkNum == 1) {
			System.out.println("아이디가 중복되었다.");
			return "duplicated";
		}else {
			System.out.println("아이디 사용 가능");
			return "available";
		}
	}

@RequestBody String account의 값으로 ajax로 전달한 아이디가 account값으로 전달된다.

이때 컨트롤러에서는 UserService 객체로 전달하여 sql에 접근한다. 

이때 sql문을 count(*)을 썻으므로 1혹은 0이 값으로 오기 때문에 int로 값을 잡는다.

 


5. 서비스 작성

 

@Service
public class BoardService implements IBoardService {
	
	@Autowired
	private IBoardMapper mapper;

	@Override
	public void insert(BoardVO article) {
		mapper.insert(article);
	}

서비스에서 mapper로 값을 전달한다. 

 

즉 컨트롤러 > 서비스 > 인터페이스매퍼 > 매퍼.xml로 전달되어 SQL 쿼리문을 작동하게 된다. 

 

<select id="checkId" resultType="int">
     	select count(*) from mvc_user where account = #{account}
     	</select>

 

UserMapper.xml에서 이부분이 작동되게 된다. 

 


6. 최종 동작 확인 

 

컨트롤러에서 아이디가 중복 되었으면 duplicated 

아이디가 사용이 가능하면 available이 리턴되어 jsp파일로 가게 설정이 되어있다. 

다시 컨트롤러와 jsp를 보자

@PostMapping("/checkId")
	public String checkId(@RequestBody String account) {	// 받을 데이터타입이 텍스트라 스트링으로함 반드시 리퀘스트바디를 붙힐것! ajax 통신시
		System.out.println("/user/checkId : post");
		System.out.println("param : " + account );
		
		int checkNum = serivce.checkId(account);
		
		if(checkNum == 1) {
			System.out.println("아이디가 중복되었다.");
			return "duplicated";
		}else {
			System.out.println("아이디 사용 가능");
			return "available";
		}
	}
$.ajax({
         		 type :'post', // 서버에 전송하는 http방식
         		 url :'/user/checkId', // 서버 요청 url
         		 headers : {
         			 'Content-Type' : 'application/json'
         		 },
         		 dataType : 'text', //서버로 부터 응답받을 데이터의 형태 
        		 data : id, // 서버로 전송할 데이터 // 위에서 지정한 const id 
        		 success : function(result) { // 매개변수에 통신성공시 데이터가 저장된다.
					//서버와 통신성공시 실행할 내용 작성.
					console.log('통신 성공!' + result);
        		 	if(result === 'available'){
        		 		 $('#user_id').css('background-color', 'aqua');
        		 		 $('#idChk').html('<b style="font-size: 14px; color: green">[아이디 사용이 가능하다.]</b>');
        		 		 chk1 = true;
        		 	}else{
        		 		 $('#user_id').css('background-color', 'pink');
        		 		 $('#idChk').html('<b style="font-size: 14px; color: red">[아이디 중복!.]</b>');
        		 		 chk1 = false;
        		 	}
				},
				error : function (status, error) { //통신에 실패했을때
					console.log('통신실패');
					console.log(status, error)
				}
          	}); // end ajax(아이디 중복 확인)

 


7. 동작확인 

 

필수 값을 누락 하였을때
아이디 입력란을 공란으로 둘경우
모든 조건을 충족할 경우
아이디가 중복일 경우

반응형
반응형

학원에서 강의 겸 정리하는 회원가입 진행순서 테스트 모듈까지 

 

1. src -> resouces > web-inf - spring > mvc_config에서 

 

마이바티스 스프링 스캔 및 빈 등록을 해준다. 

 

2. 빈 등록을 마쳤으면

 

user > model > class를 만든다. userVO라는 모델클래스를 만들어 

안에 내용은 private를 사용하여 getter , setter tostring까지 생성해준다. 

 

3.

repositroy에 iUserMapper라는 인터페이스를 생성해준다. 

해당 내용은 

 

public interface IUserMapper {

//아이디 중복체크 기능
int checkId(String account);

//회원 가입기능
void register(UserVO vo);

//회원 정보 조회 기능 
UserVO selectOne(String account);

//회원 탈퇴 기능 
void delete(String account);
}

 

이정도의 추상 메소드를 작성해준다 .

 

 

4. Mapper.xml 제작

1.에서 만들었던

이형식에 맞추어 파일을 생성한다. 

 

마이바티스 xml이라는 걸 알기 위해 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 를 상단에 붙혀 준다. 

 

mapper라는 태그를 만들어 준다 이때 namespace에 IuserMapper의 주소값을 넣어준다

필자는 . <mapper namespace="com.spring.mvc.user.repository.IUserMapper"> 이런식으로 넣었다. 

 

5. Test.class파일 제작 

 

src/test/java > 경로 > user 폴더 

 

만들어 준뒤 어노테이션으로 runwith와 contextconfiguration을 입력 주소값은 자동완성으로 완성된다

 

테스트값을 위해 아까 만들어주었던 iuserMapper 객체를 사용한다. 

 

회원가입, 중복값 체크 해당 아이디 찾기 ,아이디 삭제 기능을 테스트 값으로 입력하였댜.

테스트에 메소드는 이렇게 4개를 만들어 주고 이제 아까 만들었던 userMapper.xml에서 sql문만 완성시켜주면 

테스트는 완성이된다. 

 

6.xml파일에 sql문 입력

 

resultmap에는 uservo의 변수명과 오라클의 컬럼값이 다를때 사용한다. 

prioperty에는 uservo의 변수명을 입력하고 , column값에는 테이블의 컬럼값을 입력한다. 

 

각 태그의 id값은 IuserMapper의 메소드명과 똑같이 작성한다. 

이때 <select> 문에서 resulttype값을 int로 가져온다. 왜냐하면 count(*)함수를 입력했을때 1또는 0이 나오기 떄문이다. 

그리고 selectone에서 resultMap의 경우는 regdate의 값이 달라 resultmap을 참고한다. 

 

이렇게 sql문이 완성이 되었으면 이제 테스트를 시작해보자.

 

7. 테스트 실행

 

outline에서 해당 메소드를 클릭한뒤 runas > junit을 실행하면된다. 

 

성공시 화면

값이 정상적으로 들어왔다. 

 

실패시 화면

 

실패시 로딩바가 빨간색으로 변하며 아래 모니터 모양에 오류코드가 나오게 된다. 

 

ora-00001은 중복값이 발생하여서 그렇다. 

 

다음 포스팅에는 화면구현까지 알아보자.

반응형

+ Recent posts