JSP day 5

유요한·2022년 11월 23일
0

JSP

목록 보기
7/14
post-thumbnail

DBCP(DataBase Connection Pool)

  • 사용자의 요청이 있을 때마다 DB 연결을 한다면 코드가 복잡해지며 많은 요청이 있을 때 연결속도가 저하될 수 있다. 따라서 미리 Connection을 만들어 두고 필요시 저장된 공간에 가져다 쓰고 다시 반납하는 기법이다.
  • 먼저, sql에서 DB를 만들어준다.
    	use jsp;
    drop table test_user;

create table test_user(
userid varchar(300) primary key,
userpw varchar(300) not null,
username varchar(300),
usergender varchar(300),
zipcode varchar(300),
addr varchar(1000),
addrdatail varchar(1000),
addretc varchar(300),
userhobby varchar(1000)
);

 
joinView.jsp
 
```html
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입</title>
<style>
	body{
		background-color:rgb(245,246,247);
	}
	input{
		box-sizing: border-box;
		cursor:pointer;
	}
	table{
		border-collapse: collapse;
	}
	th{
		text-align: left;
	}
	th::after{
		content:"";
		display:inline-block;
		box-sizing:border-box;
		width:1px;
		height:14px;
		
	}
	th,td{
		padding:5px;
	}
	td{
		padding-left:20px;
		width:400px;
	}
	input[type=text], input[type=password]{
		padding:10px 15px 10px 10px;
		border:1px solid #ccc;
		width:250px;
	}
	input:focus{
		outline:none;
		border:1px solid rgb(0,200,80);
	}
	
	td > input[type=text]+input[type=button]{
		margin-left:10px;
		padding:8px 10px;
		background-color:rgb(0,200,80);
		color:#fff;
		font-size:14px;
		font-weight:bold;
		border:none;
		border-radius:5px;
		width:80px;
	}
	.gender_area > td{
		font-size:16px;
	}
	.zipcode_area > td > input[type=text]{
		width:200px;
	}
	.zipcode_area > td > input[type=button]{
		width:130px !important;
	}
	.addr_area > td > input[type=text], .addr_area+tr > td > input[type=text], .addr_area+tr+tr > td > input[type=text]{
		width:340px;
	}
	.hobby_area > td > div{
	 	display: flex;
		width:360px;
		flex-wrap: wrap;
	}
	.hobby_area > td > div > div{
		padding:10px;
		flex:1 1 40%;
	}
	.hobby_area > td > div > div:nth-child(2n){
		border-left:1px solid #ccc;
	}
	input[type=submit]{
		margin:0 auto;
		padding:10px 10px;
		margin-left:40px;
		background-color:rgb(0,200,80);
		color:#fff;
		font-size:20px;
		font-weight:bold;
		border:none;
		border-radius:5px;
		width:400px;
	}
</style>
</head>
<body>
	<form name="joinForm" method="post" action="join_db.jsp">
		<table>
			<tr>
				<td id="result" colspan="2"></td>
			</tr>			
			<tr>
				<th><label for="userid">아이디</label></th>
				<td><input type="text" name="userid" id="userid"><input type="button" value="중복검사" onclick="checkId()"></td>
			</tr>
			<tr>
				<th><label for="userpw">비밀번호</label></th>
				<td><input type="password" name="userpw" id="userpw"></td>
			</tr>
			<tr>
				<th><label for="userpw_re">비밀번호 확인</label></th>
				<td><input type="password" name="userpw_re" id="userpw_re"></td>
			</tr>
			<tr>
				<th><label for="username">이름</label></th>
				<td><input type="text" name="username" id="username"></td>
			</tr>
			<tr class="gender_area">
				<th>성별</th>
				<td>
					<label>남자 <input type="radio" name="usergender" value="M"></label>
					<label>여자 <input type="radio" name="usergender" value="W"></label>
				</td>
			</tr>
			<tr class="zipcode_area">
				<th>우편번호</th>
				<td>
					<!-- readonly는 수정이 안되게 막는 것이다. -->
					<input readonly name="zipcode" type="text" id="sample6_postcode" placeholder="우편번호"><input type="button" onclick="sample6_execDaumPostcode()" value="우편번호 찾기">
				</td>
			</tr>
			<tr class="addr_area">
				<th>주소</th>
					<!-- readonly는 수정이 안되게 막는 것이다. -->
				<td><input readonly name="addr" type="text" id="sample6_address" placeholder="주소"></td>
			</tr>
			<tr>
				<th>상세주소</th>
				<td><input name="addrdetail" type="text" id="sample6_detailAddress" placeholder="상세주소"></td>
			</tr>
			<tr>
				<th>참고항목</th>
					<!-- readonly는 수정이 안되게 막는 것이다. -->
				<td><input readonly name="addretc" type="text" id="sample6_extraAddress" placeholder="참고항목"></td>
			</tr>
			<tr class="hobby_area">
				<th>취미</th>
				<td>
					<div>
						<div>
							<label><input type="checkbox" name="userhobby" value="게임"> 게임하기</label>
						</div>
						<div>
							<label><input type="checkbox" name="userhobby" value="그림"> 그림그리기</label>
						</div>
						<div>
							<label><input type="checkbox" name="userhobby" value="영화"> 영화보기</label><br>
						</div>
						<div>
							<label><input type="checkbox" name="userhobby" value="운동"> 운동하기</label>
						</div>
						<div>
							<label><input type="checkbox" name="userhobby" value="노래"> 노래부르기</label>
						</div>
						<div>
							<label><input type="checkbox" name="userhobby" value="코딩"> 코딩하기</label>
						</div>
					</div>
				</td>
			</tr>
			<tr>
				<th colspan="2">
					<input type="submit" value="가입 완료">
				</th>
			</tr>
		</table>
	</form>
</body>
<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
<script>
    function sample6_execDaumPostcode() {
        new daum.Postcode({
            oncomplete: function(data) {
                // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.

                // 각 주소의 노출 규칙에 따라 주소를 조합한다.
                // 내려오는 변수가 값이 없는 경우엔 공백('')값을 가지므로, 이를 참고하여 분기 한다.
                var addr = ''; // 주소 변수
                var extraAddr = ''; // 참고항목 변수

                //사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
                if (data.userSelectedType === 'R') { // 사용자가 도로명 주소를 선택했을 경우
                    addr = data.roadAddress;
                } else { // 사용자가 지번 주소를 선택했을 경우(J)
                    addr = data.jibunAddress;
                }

                // 사용자가 선택한 주소가 도로명 타입일때 참고항목을 조합한다.
                if(data.userSelectedType === 'R'){
                    // 법정동명이 있을 경우 추가한다. (법정리는 제외)
                    // 법정동의 경우 마지막 문자가 "동/로/가"로 끝난다.
                    if(data.bname !== '' && /[동|로|가]$/g.test(data.bname)){
                        extraAddr += data.bname;
                    }
                    // 건물명이 있고, 공동주택일 경우 추가한다.
                    if(data.buildingName !== '' && data.apartment === 'Y'){
                        extraAddr += (extraAddr !== '' ? ', ' + data.buildingName : data.buildingName);
                    }
                    // 표시할 참고항목이 있을 경우, 괄호까지 추가한 최종 문자열을 만든다.
                    if(extraAddr !== ''){
                        extraAddr = ' (' + extraAddr + ')';
                    }
                    // 조합된 참고항목을 해당 필드에 넣는다.
                    document.getElementById("sample6_extraAddress").value = extraAddr;
                
                } else {
                    document.getElementById("sample6_extraAddress").value = '';
                }

                // 우편번호와 주소 정보를 해당 필드에 넣는다.
                document.getElementById('sample6_postcode').value = data.zonecode;
                document.getElementById("sample6_address").value = addr;
                // 커서를 상세주소 필드로 이동한다.
                document.getElementById("sample6_detailAddress").focus();
            }
        }).open();
    }
    function checkId() {
    	const userid = document.joinForm.userid;
    	if(userid.value.length<5 || userid.value.length>12) {
    		alert("아이디는 5자 이상 12자 이하로 입력해주세요!");
    		userid.focus();
    		return false;
    	}
    	const result = document.getElementById("result");
    	const xhr = new XMLHttpRequest();
    	
    	xhr.open("GET","checkId_db.jsp?userid="+userid.value,true);
    	// 서버에서 응답이 도착하면 특정한 자바스크립트 함수를 호출
    	xhr.onreadystatechange = function() {
    		// readyState == 4란 의미는 데이터를 전부 받은 상태, 완료된 상태를 의미한다.
    		if(xhr.readyState == 4) {
    			// status == 200은 서버로 부터 응답상태가 요청에 성공하였다는 의미다.
    			if(xhr.status == 200) {
    				// 문자열로 응답 데이터를 얻음
    				let txt = xhr.responseText;
    				txt = txt.trim();
    				
    				if(txt == "O") {
    					result.innerHTML = "사용할 수 있는 아이디입니다!";
    				} else {
    					result.innerHTML = "이미 존재하는 아이디입니다!";
    				}
    			}
    		}
    	}
    	xhr.send();
    }
</script>
</html>






● ums때처럼 포장해줄 DTO를 만들어 준다.
• java Resources안에 있는 src에 페키지를 만들어준다. (com.koreait.dto)
  페키지 안에UserDTO 생성
  
	package com.koreait.dto;

public class UserDTO {
	private String  userid;
	private String userpw;
	private String username;
	private String usergender;
	private String zipcode;
	private String addr;
	private String addrdetail;
	private String addretc;
	private String[] userhobby;
	
	
	public String getUserid() {
		return userid;
	}
	public void setUserid(String userid) {
		this.userid = userid;
	}
	public String getUserpw() {
		return userpw;
	}
	public void setUserpw(String userpw) {
		this.userpw = userpw;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getUsergender() {
		return usergender;
	}
	public void setUsergender(String usergender) {
		this.usergender = usergender;
	}
	public String getZipcode() {
		return zipcode;
	}
	public void setZipcode(String zipcode) {
		this.zipcode = zipcode;
	}
	public String getAddr() {
		return addr;
	}
	public void setAddr(String addr) {
		this.addr = addr;
	}
	public String getAddrdetail() {
		return addrdetail;
	}
	public void setAddrdetail(String addrdetail) {
		this.addrdetail = addrdetail;
	}
	public String getAddretc() {
		return addretc;
	}
	public void setAddretc(String addretc) {
		this.addretc = addretc;
	}
	public String[] getUserhobby() {
		return userhobby;
	}
	public void setUserhobby(String[] userhobby) {
		this.userhobby = userhobby;
	}
}
• Servers 프로젝트 → context.xml을 보면
  context를 읽으면 객체를 알 수 있다.
  
• 자바외부에서 자바 객체를 만드는 것이다.
• 사용하고자 하는 프로젝트의 META-INF에 넣어준다.
	<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
--><!-- The contents of this file will be loaded for each web application -->
<Context>

    <!-- Default set of monitored resources. If one of these changes, the    -->
    <!-- web application will be reloaded.                                   -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>

    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <!--
    <Manager pathname="" />
    -->
    <Resource
    	name="jdbc/mysql"
		auth="Container" 
		type="javax.sql.DataSource"  
		driverClassName ="com.mysql.cj.jdbc.Driver"
		url="jdbc:mysql://localhost:3306/jsp"
		username="root" 
		password="1234"
		maxActive="20"
		maxIdle="20"
		maxWait="-1"
    />
    
    <!-- 
    	name		: dbcp를 이용하기 위한 name(key값)
    	maxActive	: 연결 최대 허용 개수
    	maxIdle		: 항상 연결상태를 유지하는 개수
    					(보편적으로 maxActive와 maxIdle의 개수는 같게 해준다.)
    	maxWait		: 커넥션 풀에 연결 가능한 컨넥션이 없을 경우 대기하는 시간						
     --> 
</Context>

라이브러리 다운
https://commons.apache.org/
→ pool, dbcp, collections 다운로드

프로젝트에 추가 할것

META_INF에 context.xml 넣기

WEB-INF에 있는 lib에 mysql-connector하고 tomcat-dbcp를 넣어주기
tomcat-dbcp는 아파치폴더에 있는 lib에 있다.

사용할 프로젝트에 build path에서 Libraries에 add External JARs눌러서 dbcp 추가

• java Resources안에 있는 src에 페키지를 만들어준다. (com.koreait.dto)
페키지 안에UserDAO 생성

package com.koreait.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import com.koreait.dto.UserDTO;

public class UserDAO {
	Context context;
	DataSource ds;
	
	Connection conn;
	PreparedStatement ps;
	ResultSet rs;
	
	public boolean join(UserDTO newUser) {
		int result = 0;
		try {
			// context : 설정하면서 name을 적었는데 name을 찾아올 객체
			context = new InitialContext(null);
			// lookup이 항상 DataSource type만 return하는게 아니다.
			// 다른 type을 만들 수 있기 때문인데 그렇다보니까 return할 때
			// object되어 있다. 즉, 업캐스팅된 객체를 돌려주기 때문에 다운캐스팅을 해줘야 한다.
			ds = (DataSource)context.lookup("java:comp/env/jdbc/mysql");
			conn = ds.getConnection();
			
			String sql = "insert into test_user values(?,?,?,?,?,?,?,?,?)";
			
			ps = conn.prepareStatement(sql);
			ps.setString(1, newUser.getUserid());
			ps.setString(2, newUser.getUserpw());
			ps.setString(3, newUser.getUsername());
			ps.setString(4, newUser.getUsergender());
			ps.setString(5, newUser.getZipcode());
			ps.setString(6, newUser.getAddr());
			ps.setString(7, newUser.getAddrdetail());
			ps.setString(8, newUser.getAddretc());
			
			String[] hobbies = newUser.getUserhobby();		// [게임, 운동, 코딩]
			// hobbies[0]을 하는 이유는 무조건 하나는 체크를 하기 위해서
			String hobbyStr = hobbies[0];					// "게임"
			// length가 1개면 반복문을 한번도 안돈다.
			// 즉, 0번방 한개만 존재하면 for문을 돌지 않는것이다.
			for (int i = 1; i < hobbies.length; i++) {		// ← 1~2니까 운동, 코딩이 포함된다.
				hobbyStr += "," + hobbies[i];				// 운동, 코딩 앞에 ,을 붙여서 추가해 준다.
			}
			ps.setString(9, hobbyStr);
			result = ps.executeUpdate();
			
			
		} catch(NamingException ne) {
			System.out.println(ne);
		} catch (SQLException sqle) {
			System.out.println(sqle);
		}
		return result == 1;
		
	}
	public boolean checkId(String userid) {
		try {
			// context : 설정하면서 name을 적었는데 name을 찾아올 객체
			context = new InitialContext(null);
			// lookup이 항상 DataSource type만 return하는게 아니다.
			// 다른 type을 만들 수 있기 때문인데 그렇다보니까 return할 때
			// object되어 있다. 즉, 업캐스팅된 객체를 돌려주기 때문에 다운캐스팅을 해줘야 한다.
			ds = (DataSource)context.lookup("java:comp/env/jdbc/mysql");
			conn = ds.getConnection();
			
			String sql = "select * from test_user where userid=?";
			
			ps = conn.prepareStatement(sql);
			ps.setString(1, userid);
			
			rs = ps.executeQuery();
			
			// 없어야 true
			return !rs.next();
			
		} catch(NamingException ne) {
			System.out.println(ne);
		} catch (SQLException sqle) {
			System.out.println(sqle);
		}
		return false;
	}
}
• jsp:useBean을 사용해서 DTO에 보내준다.
• jsp:setProperty를 사용해서 데이터 값을 설정해준다.
• join_db.jsp
• 이대로 복붙해서 실행하면 오류가 생긴다. 
  그 이유는 위에 주석 해놓은 설명을 지워야 하는데 지우지 않아서 그런다.
  저 사이에는 아무것도 없어야 한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% request.setCharacterEncoding("UTF-8"); %>
<!--<jsp:useBean> 액션 태그 
	반복적인 작업을 효율적으로 하기 위해 useBean을 사용한다.
	디자인 부분과 비즈니스 로직 부분을 분리하고, 복잡한 JSP 코드를 줄이고,
	프로그램의 재사용성을 증가시키기 위해서 사용한다.
	id : 자바빈즈를 식별하기 위한 이름이다.
	class : 패키지 이름을 포함한 자바빈즈 이름이다. (인수 없는 기본 생성자가 필요하며 추상 클래스는 사용할 수없다. -->
<jsp:useBean id="newUser" class="com.koreait.dto.UserDTO"/>
<!-- <jsp:setProperty>
	  -업데이트(수정)
	  -데이터 값을 설정할 때 사용한다.
	  name : 자바빈즈 식별자이다.
	  property : 자바빈즈 프로퍼티 이름이다. (객체의 멤버변수) -->
<jsp:setProperty property="*" name="newUser"/>

<%
	
	/* 	String[] hobbies = newUser.getUserhobby();
	
		for(int i=0;i<hobbies.length;i++) {
		System.out.println(hobbies[i]);	
		} 
	*/
	UserDAO udao = new UserDAO();
	
	if(udao.join(newUser)) {
%>
	<script>
	alert("회원가입을 축하합니다!");
	location.href = "loginview.jsp";
	</script>
<% 	
	} else {
%>	
	<script>
		alert("잠시 후에 다시 시도해주세요.")
		location.href = "joinview.jsp";
	</script>	
<%
	}
	
 %>


→ 아직 전부 구성한게 아니기 때문에 404 오류 뜨는게 정상이다.

sql workbench가서 확인해보면 다음과 같이 뜬다.

	<%@page import="com.koreait.dao.UserDAO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	UserDAO udao = new UserDAO();
	String userid = request.getParameter("userid");
	
	if(udao.checkId(userid)) {
		out.println("O");
	} else {
		out.println("X");
	}
%>

주소찾기 기능 넣기

구글에서 주소찾기 api 검색하면 다음꺼 나오는데 우리가 사용하는 것은
두 번째꺼 사용자가 선택한 값 이용하기다.
https://postcode.map.daum.net/guide

이것들을 넣어주면 주소찾기 기능이 된다.

	<input type="text" id="sample6_postcode" placeholder="우편번호">
<input type="button" onclick="sample6_execDaumPostcode()" value="우편번호 찾기"><br>
<input type="text" id="sample6_address" placeholder="주소"><br>
<input type="text" id="sample6_detailAddress" placeholder="상세주소">
<input type="text" id="sample6_extraAddress" placeholder="참고항목">
	<script>
    function sample6_execDaumPostcode() {
        new daum.Postcode({
            oncomplete: function(data) {
                // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.

                // 각 주소의 노출 규칙에 따라 주소를 조합한다.
                // 내려오는 변수가 값이 없는 경우엔 공백('')값을 가지므로, 이를 참고하여 분기 한다.
                var addr = ''; // 주소 변수
                var extraAddr = ''; // 참고항목 변수

                //사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
                if (data.userSelectedType === 'R') { // 사용자가 도로명 주소를 선택했을 경우
                    addr = data.roadAddress;
                } else { // 사용자가 지번 주소를 선택했을 경우(J)
                    addr = data.jibunAddress;
                }

                // 사용자가 선택한 주소가 도로명 타입일때 참고항목을 조합한다.
                if(data.userSelectedType === 'R'){
                    // 법정동명이 있을 경우 추가한다. (법정리는 제외)
                    // 법정동의 경우 마지막 문자가 "동/로/가"로 끝난다.
                    if(data.bname !== '' && /[동|로|가]$/g.test(data.bname)){
                        extraAddr += data.bname;
                    }
                    // 건물명이 있고, 공동주택일 경우 추가한다.
                    if(data.buildingName !== '' && data.apartment === 'Y'){
                        extraAddr += (extraAddr !== '' ? ', ' + data.buildingName : data.buildingName);
                    }
                    // 표시할 참고항목이 있을 경우, 괄호까지 추가한 최종 문자열을 만든다.
                    if(extraAddr !== ''){
                        extraAddr = ' (' + extraAddr + ')';
                    }
                    // 조합된 참고항목을 해당 필드에 넣는다.
                    document.getElementById("sample6_extraAddress").value = extraAddr;
                
                } else {
                    document.getElementById("sample6_extraAddress").value = '';
                }

                // 우편번호와 주소 정보를 해당 필드에 넣는다.
                document.getElementById('sample6_postcode').value = data.zonecode;
                document.getElementById("sample6_address").value = addr;
                // 커서를 상세주소 필드로 이동한다.
                document.getElementById("sample6_detailAddress").focus();
            }
        }).open();
    }
</script>


JNDI(Java Naming and Directory Interface)

디렉터리 서비스에서 제공하는 데이터 및 객체를 발견하고 참고하기 위한
자바 API이며 외부에 있는 객체를 가져오기 위한 기술이다.

사용자 요청 > JNDI에 등록된 DB객체 검색 > 찾은 객체에서 커넥션 획득
> DB작업 종료 후 커넥션 반납
profile
발전하기 위한 공부

0개의 댓글