반응형

id, email : 입력

상품번호 : 자동생성

입력 받는 것은 중복체크를 해야 한다.

글번호 -> 일련번호

기본키로 분류나 검색 인덱싱

분류코드 + 일련번호

 

 

**기본키

기본키를 직접 입력받는 경우에는 중복검사를 해주는 것이 좋습니다.

이벤트는 포커스가 잃어버릴 때를 많이 이용하고 이 때 ajaxwebsocket을 이용해서 서버에게 기본키 입력값을 전송하고 서버는 넘어온 기본키 입력 값을 가지고 데이터베이스에서 조회하고 그 결과를 json이나 xml 형태로 클라이언트에게 알려주며 클라이언트느느 그 값을 가지고 중복 여부를 판단해서 처리를 합니다.

 

=>기본키를 일련번호 형태로 자동 생성하는 경우는 auto_incrementsequence를 이용하기도 하고 현재 입력된 번호 중 가장 큰 번호를 찾고 여기에 +1를 해서 생성하는 방법도 있습니다.

이 방법은 일반적으로 비 추천하고 되도록이면 숫자나 문자의 조합을 이용해서 분류의 기능을 갖도록 만드는 것을 권장합니다.

대표적으로 주민번호나 학번

 

**폼의 데이터 전송 시 유효성 검사

=>클라이언트에서의 유효성 검사

클라이언트에서 유효성 검사를 하게 되면 서버로 전송하지 않고 수행을 하기 떄문에 속도나 트래픽 면에서 유리하지만 보안지 되지 않기 때문에 클라이어느가 유효성 검사 로직을 파악할 수 있습니다.

=>폼의 경우는 submit이번트에서 유효성검사하고 유효성 검사를 통과하지 못하면 서버로 전송하지 못하도록 이벤트 객체의 preventDefault()를 호출하면 됩니다

=>가장 많이 수행하는 유효성 검사는 필수 입력 , 중복 검사 통과 여부 , 패턴 일치 , 2개의 값 일치 등이 있습니다.

필수 입력은 ->required에서 해서 sumit에서 안해도 된다.

 

 

실습insert.jsp에 유효성 검사를 위한 코드를 추가

//폼의 데이터를 전송할 때 발생하는 이벤트 처리

           document.getElementById("myform").addEventListener("submit",function(e){

                                  //중복 체크통과 여부 확인

                                  if(idcheck == false){

                                              iddiv.innerHTML = '아이디 중복검사를 하세요.';

                                              iddiv.style.color ='red';

                                              itemid.focus();

                                              //화면 이동을 안한다.

                                              e.preventDefault();

                                              return;

                                  }

                                 

                                  //price 입력란의 숫자만 입력되었는지 체크

                                  //+ - 기호를 앞에 붙일 수 있는지

                                  //,의 경우는 어떻게 할것인지

                                  //number은 모바일만 가능

                                  //길이는 - length, 개수는count

                                  var price = document.getElementById('price');

                                  for(var i = 0; i < price.value.length;i++){

                                              var ch = price.value.charAt(i);

                                              //console.log(ch);

                                              if(i == 0){

                                                         if(!(ch == '+' || ch == '-' || (ch >= '0' && ch <= '9'))){

                                                                     price.focus();

                                                                     alert("가격의 첫번째 자리는 숫자나 +,- 기호여야 합니다.")

                                                                     //화면 이동을 안한다.

                                                                     e.preventDefault();

                                                                     return;

                                                         }

                                              }else if(!(ch>= '0'  && ch <= '9')){

                                                         price.focus();

                                                         alert("가격은 숫자로만 입력하세요.")

                                                         //화면 이동을 안한다.

                                                         e.preventDefault();

                                                         return;

                                              }

                                  }

                       });

 

 

 

 

**spring에서의 file upload처리

=>MultipartFile 타입으로 처리

1. 준비사항

1)comons-fileupload: 라이브러리의 의존성 설정

2) CommonsMultipartResoulver 클래스의 bean을 생성

 

2.MultipartFile

=>파라미터를 직접 이 타입으로 받아도 되고 HttpServletReques대신에

MultipartHttpServletRequst를 이용해서 요청을 받고 getFile(String parameterName)을 이용해서 가져올 수 있습니다.

 

3.실습

1)파일 업로드 처리를 위한 라이브러리의 의존성을 pom.xml 파일에 추가

                       <!-- 파일 업로드 처리를 위한 의존성 라이브러리 -->

                       <dependency>

                                  <groupId>commons-fileupload</groupId>

                                  <artifactId>commons-fileupload</artifactId>

                                  <version>1.3.1</version>

                       </dependency>

                      

2)파일 업로드를 처리해 줄 수 있는 CommonsMultipart

=>servlet-context.xml파일에 추가

 

3)Dao클래스에 데이터를 삽입하기 위한 메소드를 생성하고 추가

          

           //데이터 1개를 삽입하는 메소드

           public int insertItem(Item item) {

                       sessionFactory.getCurrentSession().save(item);

                       return 1;

           }

 

4)ItemService에 인터페이스에 데이터를 삽입하기 위한 메소드를 선언

           //데이터 삽입(파일업로드 ) 처리를 위한 메소드

           public int insertItem(MultipartHttpServletRequest request);

 

5)ItemServiceImpl 클래스에 데이터를 삽입하기 위한 메소드를 구현

annotation자주 사용하는 것이 길거나 할 때 사용한다.

호출할 때 앞뒤에 코드가 들어간다.

           @Override

           @Transactional

           public int insertItem(MultipartHttpServletRequest request) {

                       // 파라미터 읽기

                       String itemid = request.getParameter("itemid");

                       String itemname = request.getParameter("itemname");

                       String price = request.getParameter("price");

                       String description = request.getParameter("description");

                      

                       //Dao 객체의 파라미터 만들기

                       Item item = new Item();

                       item.setItemid(Integer.parseInt(itemid));

                       item.setItemname(itemname);

                       item.setPrice(Integer.parseInt(price));

                       item.setDescription(description);

                      

                       //파일 읽기

                       MultipartFile mf = request.getFile("pictureurl");

                       //업로드할 파일이 있는 경우에만

                       if(mf.isEmpty() == false) {

                                  //원본 파일 이름 가져오기

                                  String originalName = request.getFile("pictureurl").getOriginalFilename();

                                  //원본 파일 이름은 여러개의 파일을 업로드 하다모변 중복될 수 있기 때문에

                                  //파일이름을 만들 때는 동일한 디렉토리에 저장한다면 중복되지 않도록

                                  //파일 이름을 생성할 필요가 있습니다.

                                  //기본키와 파일염을 합치는 방법이 있고 uuid클래스를 이용해서 만드는 방법

                                  String uploadName = itemid + originalName;

                                  item.setPictureurl(uploadName);

                                 

                                  //파일을 저장할 경로를 생성

                                  //프로젝트의 내의 경로를 가지고 절대경로를 생성

                                  //프로젝트 내의 경로가 아니면 직접 경로를 작성

                                  String uploadPath = request.getRealPath("./img");

                                  //servlet 3.0 이을 사용하면 request.getServletContext().getRealPath("./img")

                                 

                                  //업로드할 file객체 생성

                                  File file = new File(uploadPath + "\\" + uploadName);

                                  try {

                                             request.getFile("pictureurl").transferTo(file);

                                  } catch (IllegalStateException e) {

                                              e.printStackTrace();

                                  } catch (IOException e) {

                                              e.printStackTrace();

                                  }

                       }

                      

                       //데이터 삽입

                       return hibernateDao.insertItem(item);

           }

 

 

3)HomeController클래스에 insertfpost방식으로 요청했을 때 처리를 위한 메소드를 생성

 

 

7)실행하고 파일을 업로드 했을 때 파일을 확인해야 하는 디렉토리

자신의 워크스 페이스 \ 프로젝트 이름

 

=>프로젝트는 원래 모양 그대로 있고 실행이 될때는 프로젝트의 내용을 build해서 위의 디렉토리에 있는 내용이 실행되는 것입니다.

 

=>프로젝트를 복사해서 다른 곳에서 실행하는 경우 프로젝트를 만들 때 존재했던 파일들은 그대로 있지만 실행 중 생성한 파일들은 없습니다.

개발환경에서 운영환경으로 이전(이 작업을 이행이라고 합니다.) 할 때 기존 데이터베이스 내용을 전부 삭제해야 할 때도 있습니다.

 

 

 

 

 

applicataion server

db server

file server

 

 

 

**websocket

=>httphttps는 연결형 프로토콜이기는 하지만 한 번 요청을 해서 응답을 받으면 연결이 끊어집니다.

=>채팅과 같은 애플리케이션을 만들 때 httphttps를 이용하는 것은 어려운 작업입니다.

데이터를 여러번 주고 받고자 하는 경우 연결하고 끊고 다시 연결하고 끊고 하는 작업을 반복해야 합닏.

데이터를 주고받는 시간보다 연결과 해제에 많은 자원을 소모합니다.

그래서 등장방법 중의 하나는 애플리케이션을 설치하는 방법이었습니다.

=>순수 웹 환경에서 실시간 양방향 통신을 위한 Spec  HTML5에서 추가가 되었는데 Spec WebSocket입니다.

websocket은 한 번 연결하면 close할 때 까지 계속 연결되어 있습니다.

 

=>최근에는 Andriod ios 에서도 웹 소켓에 접속하는 api가 추가

 

1.클라이언트(웹 브라우저)에서의 사용 방법(자바스크립트)

1)websocket 객체 생성

new WebSocket("ws://domain/demo")

 

2)데이터 전송

websocket객체.send("데이터")

 

3)데이터 전송받기 - 콜백 사용

WebSocket객체.addEventListener("message",function(e){

           //매개변수 e가 전송된 데이터입니다.

});

 

4)기타 이벤트

open, close이벤트

 

 

5)연결 해제

WebSocket객체.close()

 

 

2.spring 을 이용한 websocket서버 설정

=>websocketHandler인터페이스를 구현한 클래스를 생성하고 메소드 재정의

 

=>클래스 위에 @EnableWebScocket이나 설정 파일에 websocket:handlers태그를 이용해서 웹 소켓 서버 설정

 

3.websockethandler인터페이스르 구현한 클래스

=>TextWebSocketHandler, AbstractWebSocketHandler

 

4.의존성 라이브러리

spring-websocket

 

5.주의할점

=>springwebsocket은 서블릿 3.0부터 사용 가능

 

6.실습

1)pom.xml파일에 spring-websocket의존성 설정

                       <dependency>

                                  <groupId>org.springframework</groupId>

                                  <artifactId>spring-websocket</artifactId>

                                  <version>${org.springframework-version}</version>

                       </dependency>

 

 

2)websocket 서버 클래스를 생성

=>TextWebSocketHandler클래스를 상속

=>기본 패지키 안에 생성

=>com.pk.util.ChatHandler

연결 되면 유저 정보 연결하고 연결이 끊어질때 유저정보 끊고 메세지를 왔을 때 전부 다 보내주면 된다.

//Bean생성을 자동으로 해주기 위한 어노테이션

@Component

//웹 소켓 채팅 서버 클래스

public class ChatHandler extends TextWebSocketHandler {

           //접속한 유저 목록을 가질 List를 생성

           private List<WebSocketSession> users = new ArrayList<WebSocketSession>();

          

           //클라이언트가 접속했을 때 호출될 메소드

           //매개변수로  대입된 데이터가 접속한 클라이언트

           @Override

           public void afterConnectionEstablished(WebSocketSession sesssion) {

                       //List에 추가

                       //접속을 했으면 추가

                       users.add(sesssion);

           }

          

           //클라이언트가 해제했을 때 호출될 메소드

           //매개변수로  대입된 데이터가 접속한 클라이언트

           @Override

           public void afterConnectionClosed(WebSocketSession sesssion,CloseStatus status) {

                       //해제된 이후

                       //List에 제거

                       users.remove(sesssion);

           }

          

           //메시지가 전송되었을 대 호출되는 메소드

           @Override

           public void handleTextMessage(WebSocketSession session, TextMessage message) {

                       System.out.println(message.getPayload()+"가 전송됨");

                       for(WebSocketSession ses: users) {

                                  try {

                                              ses.sendMessage(new TextMessage(message.getPayload()));

                                  } catch (IOException e) {

                                              e.printStackTrace();

                                  }

                       }

           }

}

 

3)ChatHandler클래스를 url과 매핑하는 코드를 servlet-context.xml파일에 작성

=>servlet-context.xml파일에 websocket넴임스페이스를 추가

           <!-- websocket 클래스와  url매핑 -->

           <websocket:handlers>

                       <!-- handler에서 bean id를 작성하고 path는 클라이언트의 접속할 url -->

                       <websocket:mapping handler="chatHandler" path="/chat-ws"/>

           </websocket:handlers>

 

 

4)home.jsp 파일에 채팅페이지로 이동할 링크를 추가

           <a href="chat">websocket을 이용한 채팅 구현</a><br/>

 

5)HomeController클래스의 위의 요청을 처리하는 메소드를 작성

           //chat이라는 요청이 오면 chat이라는 문자열을 가지고 ViewResolver설정을 확인해서

           //뷰 페이지를 결정 -web-inf/views/?.jsp

           @RequestMapping(value="/chat",method = RequestMethod.GET)

           public String chat(MultipartHttpServletRequest request, Model model) {

                       return "chat";

           }

 

6) views디렉토리에 chat.jsp파일을 만들고 작성

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>채팅</title>

<style type="text/css">

           #chatArea{

                       width: 200px;

                       height: 100px;

                       overflow-y : auto;

                       border : 1px solid black;

           }

</style>

</head>

<body>

           <!--  -->

           <a href ="./">메인화면으로 이동</a>

           이름<input type="text" id="nickname"/>

           <input type="button" id="enterbtn" value="입장"/>

           <input type="button" id="exitbtn" value="나가기"/>

          

           <h1>채팅창</h1>

           <div id="chatArea">

                       <div id="chatmessagearea"></div>

           </div>

           <br/>

          

           <input type="text" id="message"/>

           <input type="button" id="sendbtn" value="전송" />

          

           <script type="text/javascript">

                       //웹 소켓 변수

                       var wsocket;

                      

                       //변수에 ㅇ이름을 기재하고 함수를 대입합면

                       //이 함수를 만들고 난 후 뒤에서 사용가능해집니다.

                       //function이름(매개변수){}로 만들면 순서에 상관없이 아무곳에서나 호출가능

                      

                       //문자열을 출력하는 함수

                       var appendMessage = function(msg){

                                  document.getElementById("chatmessagearea").innerHTML = msg+"<br/>" + document.getElementById("chatmessagearea").innerHTML;

                       }

                      

                       //이번체 처리 함수                    

                       var onOpen = function(){

                                  appendMessage("연결 되었습니다.");

                       }

                      

                       var onClose = function(){

                                  appendMessage("연결 해지되었습니다.");

                                  wsocket.close();

                       }

                      

                       var onMessage = function(evt){

                                  var data = evt.data;

                                  appendMessage(data);

                       }

                      

                       var send = function(){

                                  //입력한 내용을 websocket서버에게 전달하고 message 란은 클리어

                                  var nickname = document.getElementById("nickname").value;

                                  var msg = document.getElementById("message").value;

                                  wsocket.send(nickname+":"+msg);

                                  document.getElementById("message").value="";

                       }

                      

                      

                       //웺 소켓 연결함수

                       var connect = function(){

                                  //http://localhost:9000/db/chat-ws - 자기 컴퓨터에서만 접속

                                  wsocket = new WebSocket("ws://ip주소:9000/db/chat-ws");

                      

                                  //이벤트 핸들러 연결

                                  wsocket.addEventListener("open",onOpen);

                                  wsocket.addEventListener("message",onMessage);

                                  //wsocket.addEventListener("close",onClose);

                       }

                      

                       //message 입력란에어 키보드 이벤트가 발생하면

           document.getElementById("message").addEventListener("keypress",function(e){

                                  //enter를 누르면 send()호출

                                  event = e || window.event;

                                  var keycode = (event.keyCode?event.keyCode:event.widch);

                                  if(keycode == 13){

                                              send();

                                  }

                                  event.stopPropagation();

                       });

                       //버튼 들의 이번트 처리

               document.getElementById('sendbtn').addEventListener('click',function(){

                                  send();

                       });

               document.getElementById('enterbtn').addEventListener('click',function(){

                                  connect();

                       });

                 document.getElementById('exitbtn').addEventListener('click',function(){

                                  onClose();

                       });

           </script>

</body>

</html>

 

7)pom.xml파일의 서블릿 설정을 2.53.1.0으로 수정

                       <dependency>

                                  <groupId>javax.servlet</groupId>

                                  <artifactId>javax.servlet-api</artifactId>

                                  <version>3.1.0</version>

                       </dependency>

 

 

 

**로그인 기능 추가

1.데이터베이스에 접속해서 로그인 처리를 테이블을 생성하고 샘플 데이터를 입력

CREATE TABLE MEMBER(

num NUMBER(10),         

userid varchar2(100) UNIQUE,

userpw varchar2(100) NOT NULL,

nickname varchar2(100),

           PRIMARY KEY (num)

);

 

 

INSERT INTO MEMBER VALUES (1,'root','1234','관리자');

INSERT INTO MEMBER VALUES (2,'hhh','1234','김');

INSERT INTO MEMBER VALUES (3,'jessica','1234','제시카');

 

COMMIT;

 

 

2.테이블과 매핑할 dto클래스를 생성

=>com.pk.db.domain.Member

@Data

public class Member {

           private int num;

           private String userid;

           private String userpw;

           private String nickname;

}

 

3.dao 패키지와 클래스와 데이터베이스 테이블을 매핑시키는 xml파일을 생성

=>member.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.pk.db.domain">

           <class name="Member" table="MEMBER">

                       <id name="num" column="NUM">

                       </id>

                       <property name="userid" column="USERID" />

                       <property name="userpw" column="USERPW" />

                       <property name="nickname" column="NICKNAME" />

           </class>

</hibernate-mapping>

 

4.Hibernate설정 파일을 등록하는 코드를 root-context.xml파일에 추가

                                             <value>com/pk/db/dao/member.hbm.xml</value>

 

5.hibernate 사용을 위한 dao클래스를 만들고 로그인 관련 메소드를 작성

=>dao.MemberDao

@Repository

public class MemberDao {

 

           @Autowired

           private SessionFactory sessionFactory;

          

           //로그인 관련 메소드

           //idpw를 매개변수로 받아서 일치하는 데이터가 있는지 찾아옵니다.

           public Member login(Member member) {

                      

                       //setString(0,member.getUserid())

                       //userid가 기보ㄴ키가 아니라서 sql을 이용해서 직접 조회

                       List<Member> list = sessionFactory.getCurrentSession().createSQLQuery("select * from Member where userid=:userid").addEntity(Member.class).setString("userid",member.getUserid()).list();

                       if(list == null || list.size() < 1) return null;

                       return list.get(0);

           }

}

 

6.home.jsp 파일에 로그인과 로그아웃 링크를 생성

=>로그인에 성공하면 member라는 속성에 회원정보를 저장할 것임

=>로그인 여부는 sessionmember라는 속성에 데이터가 있으면 로그인 된것이고 그렇지 않으면 로그인이 되지 않은 것으로 간주

빨간 표시가 나면 지우고 다시 입력하면 된다.예쩐 jsp에서 나오는 것이 남을 수 있다.

           <c:if test ="${member == null} ">

                       <a href="login">로그인</a>

           </c:if>

           <c:if test = "${member != null }">

                       ${member.nickname} <a href="logout">로그아웃</a>

           </c:if>

 

7.login요청이 Get방식으로 오면 login페이지로 포워딩 하도록 메소드를 HomeController에 작성

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>로그인</title>

</head>

<body>

           <form method="post" id="loginform">

                       아이디 <input type="text" id="userid" name ="userid" required="required">

                       비밀번호 <input type ="text" id="userpw" name ="userpw" required="required">

                       <input type="submit" value="전송">

           </form>

</body>

</html>

 

8.MemberService인터페이스를 만들고 로그인 처리 메소드를 선언

public interface MemberService {

           //로그인 처리 메소드

           public Member login(HttpServletRequest request);

}

 

 

9.MemberService implements를 한 MemberServiceImpl클래스를 만들고 로그인 처리 메소드를 구현

package com.pk.db.service;

 

import javax.servlet.http.HttpServletRequest;

import javax.transaction.Transactional;

 

import org.apache.ibatis.executor.ReuseExecutor;

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

import org.springframework.stereotype.Service;

 

import com.pk.db.dao.MemberDao;

import com.pk.db.domain.Member;

 

@Service

public class MemberServiceImpl implements MemberService {

          

           @Autowired

           public MemberDao memberDao;

          

           @Override

           @Transactional

           public Member login(HttpServletRequest request) {

                       Member member = null;

                      

                       //파라미터 읽기

                       String userid= request.getParameter("userid");

                       String userpw = request.getParameter("userpw");

                      

                       //userid에 해당하는 데이터 찾아오기

                       member = memberDao.login(member);

                       //userid에 해당하는 데이터가 있다면

                       if(member != null) {

                                  if(member.getUserpw().equals(userpw)) {

                                              //로그인 성공한 경우는 session에 로그인 정보를 저장

                                              member.setUserpw(null);//비밀번호를 저장하고 싶지 않았을 경우

                                             request.getSession().setAttribute("member", member);

                                  }else {

                                              //로그인 실패

                                              member  = null;

                                  }

                       }

                      

                       return member;

           }

 

}

 

10. HomeController에서 login요청이 post방식으로 오면 처리하는 메소드를 생성

1)새로운 서비스를 주입받는 코드를 작성

@Autowired

private MemberService memberService;

 

 

2)요청을 처리하는 메소드를 생성

           @RequestMapping(value="/login",method = RequestMethod.POST)

           public String login(HttpServletRequest request, Model model,RedirectAttributes attrs) {

                       //RedirectAttributes redirect를 할 때 한번만 사용하는 데이터를 저장할 수 있는 spring이 제공하는 클래스

                      

                       //서비스의 메소드를 호출

                       Member member = memberService.login(request);

                       //로그인 처리도 redirect로 이동

                       if(member == null) {

                                  //로그인 실패의 경우

                                  attrs.addFlashAttribute("msg", "없는 아이디이거나 잘못된 비밀번호입니다.");

                                  return "redirect:login";

                       }else {

                                  //로그인 성공이면 메인 페이지로 이동

                                  return "redirect:./";//main페이지로 이동

                       }

                      

           }

 

 

11. login.jsp파일에 로그인 실패 메시지를 출력할 영역을 생성

 

 

반응형

'Study > spring' 카테고리의 다른 글

spring-8  (0) 2020.10.26
spring-7  (0) 2020.10.26
spring-5  (0) 2020.10.23
spring-4  (0) 2020.10.23
spring-3  (0) 2020.10.23

+ Recent posts