**2개 이상의 테이블이 존재하는 경우 특별한 경우가 아니면 2개의 테이블은 오래키로 연결되어야합니다. 

외래키를 설정하는 방법은 2 테이블 간의 candinality를 파악해야 합니다. 대응 수입니다. (1:1, 1:N, N:N)


1:1관계일 때는 양쪽의 기본키를 상대방 테이블의 외래키로 추가해야합니다. 

1:N 관계 일 때는 1쪽의 기본키를 N쪽의 외래키로 추가해 주저야합니다.

N:N 관계일 때는 양쪽의 기본키를 외래키로 갖는 별도의 테이블을 생성해야 합니다. 


회원테이블           게시글테이블             댓글 테이블 



1명의 회원은 몇개의 게시글을 작성할 수 있는가>? N개의 게시글 작성 가능 

 

1개의 게시글은 몇명의 회원이 작성할 수 있는가> ? 1개의 게시글은 1명의 회원 작성 

회원 (1) : 게시글 (N)



게시글 테이블에 회원 테이블의 기본키인 email을 외래키로 추가해주어야 합니다.


1명의 회원은 몇개의 댓글을  작성할 수 있는가? n개의 댓글 작성가능 N

1개의 댓글은 몇명의 회원이 작성할 수 있는가 ? n개의 댓글 작성가능 1명

댓글 테이블에 회원 테이블의 기본키인 email을 외래키로 추가해주어야합니다. 

회원 (N) : 댓글 (1)



1개의 게시글에 몇개의 댓글을 작성할 수 있는가 > N개 

1개의 댓글은 몇개의 게시글에 작성될 수 있는가 ? 1개 

댓글 테이블에 게시글 테이블의 기본키인 글번호를 외래키로 추가해 주어야합니다.



**게시글 작업 준비

1.게시글 테이블 작성

=>글번호, 글제목, 글내용, 작성한 날짜 및 시간, 작성한 곳의 IP, 조회수, 작성한 사람의 email(springuser 테이블의 email을 참조, 작성한 사람의 nickname을 소유

=>글번호는 기본키, 글제목은 not null, 작성한 날짜는 date이고 기본값은 현재 날짜 및 시간, 조회수의 기본값은 0


--게시글 테이블

create table springboard(

bno number(10) primary key,

title varchar2(100) not null,

content clob,

regdate date default sysdate,

readcnt number(10) default 0,

ip varchar2(100),

email varchar2(100) references springuser(email),

nickname varchar2(100))


2.글번호를 일련번호로 삽입할 수 있도록 sequence를 생성

--sequence 생성

drop sequence boardseq;

create sequence boardseq;


3.springboard 테이블에 수행할 sql을 작성할 mapper 파일을 생성

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

<!DOCTYPE mapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="board">


</mapper>


4.dao 패키지에 springboard 테이블에 대한 작업을 수행할 BoardDao 클래스 생성

package kr.co.pk.dao;


import org.apache.ibatis.session.SqlSession;

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

import org.springframework.stereotype.Repository;


@Repository

public class BoardDao {

@Autowired

private SqlSession sqlSession;

}

 

5.service 패키지에 BoardService 인터페이스 생성

package kr.co.pk.service;


public interface BoardService {


}


6.service 패키지에 BoardServiceImpl 클래스 생성

package kr.co.pk.service;


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

import org.springframework.stereotype.Service;


import kr.co.pk.dao.BoardDao;


@Service

public class BoardServiceImpl implements BoardService {

@Autowired

private BoardDao boardDao;

}


7.게시글에 대한 요청을 처리해 줄 BoardController를 생성

package kr.co.pk;


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

import org.springframework.stereotype.Controller;


import kr.co.pk.service.BoardService;


@Controller

public class BoardController {

@Autowired

private BoardService boardService;

}


8. Board Dao 클래스 생성 



package com.seunghoo.na.domain;


import java.sql.Date;


public class Board {


private int bno;

private String title;

private String content;

private Date regdate;

private int readcnt;

private String email;

private String ip;

private String nickname;

public int getBno() {

return bno;

}

public void setBno(int bno) {

this.bno = bno;

}

public String getTitle() {

return title;

}

public void setTitle(String title) {

this.title = title;

}

public String getContent() {

return content;

}

public void setContent(String content) {

this.content = content;

}

public Date getRegdate() {

return regdate;

}

public void setRegdate(Date regdate) {

this.regdate = regdate;

}

public int getReadcnt() {

return readcnt;

}

public void setReadcnt(int readcnt) {

this.readcnt = readcnt;

}

public String getEmail() {

return email;

}

public void setEmail(String email) {

this.email = email;

}

public String getIp() {

return ip;

}

public void setIp(String ip) {

this.ip = ip;

}

public String getNickname() {

return nickname;

}

public void setNickname(String nickname) {

this.nickname = nickname;

}

@Override

public String toString() {

return "board [bno=" + bno + ", title=" + title + ", content=" + content + ", regdate=" + regdate + ", readcnt="

+ readcnt + ", email=" + email + ", ip=" + ip + ", nickname=" + nickname + "]";

}

}



1) home.jsp 파일 링크 





2)header.jsp 파일에 추가 

<li role="presentation"><a href="${pageContext.request.contextPath}/board/register">게시물 쓰기</a></li>




=> home.jsp 파일의 위치는 항상 일정하지만 header.jsp의 URL은 다르게 적용이 됩니다. 

header.jsp 파일은 모든 페이지에 포함되서 출력되기 때문입니다. 

이럴 때는 링크의 경롤르 절대경로로 표시를 해주어야합니다. 



2. 게시글 작성 링크를 눌렀을 때 게시글 작성 페이지로 포워딩하도록 해주는 메소드를 BoardController에 작성 

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

public String register() {

return "board/register";

}


1. 입력받아야할 내용  ;title,content

2. 전달할 내용 title, content, ip, email, nickname

=>session에 email 과 nickname이 저장되어있습니다.


작업을 할 때는 제일먼저 확인할 때 DB를 사용여부 


4. board.xml 파일에 게시글을 저장하는 sql을 생성 

<!--게시글으 ㄹ저장하는 SQL--> 

 <insert id="register">

 

 insert into springboard(bno, title, content, ip, email, nickname) 

  values(boardseq.nextval, #{title}, #{content}, #{ip}, #{email}, #{nickname})

 </insert>

 </mapper>


 

5.BoardDao 클래스에 메소드를 생성 

public void register(Board board) {

return sqlSession.insert("board.register",board);

}



6. BoardService 인터페이스에 게시글 작성 요청을  처리하는 메소드를 선언 


public void insertreg(HttpServletRequest request);


7. boardServiceImpl클래스에 가서 게시글 작성을 요청을 처리하느 메소드를 구현 


@Override

public void insertreg(HttpServletRequest request) {

//파라미터 읽기 

//파라미터를 이용해서 수행할 작업이 있으면 수행 

//Dao 메소드를 호출해야하는 경우 Dao 메소드의 

//파라미터를 생성 

//Dao 메소드를 호출 

//리턴한 결과를 만들어서 리턴 

}

7-1. boardServiceImpl클래스에 게시글작성 요청을 처리하는 메소드를 구현 


@Override

public void insertreg(HttpServletRequest request) {

//파라미터 읽기 

//파라미터를 이용해서 수행할 작업이 있으면 수행 

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

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

String ip = request.getRemoteAddr();

//Dao 메소드를 호출해야하는 경우 Dao 메소드의 파라미터를 생성 

HttpSession session = request.getSession();

User user = (User)session.getAttribute("user");

String email = user.getEmail();

String nickname = user.getNickname();

//Dao 메소드를 호출 

Board board = new Board();

board.setEmail(email);

board.setIp(ip);

board.setContent(content);

board.setTitle(title);

board.setNickname(nickname);

boardDao.register(board);


}

8. BoardController 클래스에 게시글 저장 요청이 왔을 때 처리하는 메소드를 생성 

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

public String register(HttpServletRequest request, RedirectAttributes attr, Model model) {

boardService.insertreg(request);

attr.addFlashAttribute("msg","게시글 작성");

//데이터베이스에 저장하는 작업을 수행했으므로 

//리다이렉트로 이동 

return "redirect:list";

}

]

오라클은 날짜가 년도4자리-월2자리 공백 시간2자리:분2자리:초2자리

java.sql.Date 클래스의 toString은 년도4자리-월2라리-일2자리 


**게시물 전체 목록보기 

1. home.jsp 파일에 게시물 목록보기 링크를 생성 

<div class="box-header with-border">

              <a href="board/list"><h3 class="box-title">게시판 목록보기</h3></a>

 </div>


2)header.jsp 파일에 생성 

<a href="${pageContext.request.contextPath}/board/list">목록보기 </a>




2.board.xml 파일에 SpringBoard 테이블의 전체 데이터를 가져오는 SQL을 생성 

<!--게시글 전체를 가져오는 SQL -->

<select id="getAllList"  resultType="Board">

select bno, title, nickname,regdate,readcnt, email

from springboard

</select>


3. BoardDao 클래스에 게시물 전체를 가져오는 메소드를 생성 


//게시물 전체 목록을 가져오는 메소드 

public List<Board> list(){

return sqlSession.selectList("board.getAllList;

}



4. BoardService 인터페이스에 게시물 전체를 가져오는 메소드를 선언 

//게시물 전체를 가져오는 메소드 

public List<Board> list();


5. BoardServiceImpl 클래스에 게시물 전체를 가져오는 메소드를 구현 


@Override

public List<Board> list() { 

return boardDao.list

}

6.Board 크래스의 regdate의 자료형을  String으로 바꿉니다.



7.boardController 클래스에 게시물전체를 가져오는 요청을 처리할 컨트롤러 메소드 생성 

 @RequestMapping(value="board/register" method="RequestMethod.GET"

 public String list(HttpServletRequest request, Model model ) 

 List<Board> list = boardService.list();

 

 model.addAttribute("list", list);

 return "board/list"

 

 


 

 7.Board 폴더에 list.jsp 파일을 생성후 요청한 내용을 보여줄 뷰 작성 


 

 

 

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

pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>목록보기</title>

</head>

<body>

<%@include file="../include/header.jsp"%>

<div class="box">

<div class="box-header with-border">

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

<h3 class="box-title">게시판 목록보기</h3>

</c:if>

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

<h3 class="box-title">${msg}</h3>

</c:if>

</div>

<div class="box-body">

<table class="table table-bordered table-hover">

<tr>

<th width="11%">글번호</th>

<th width="46%">제목</th>

<th width="16%">작성자</th>

<th width="16%">작성일</th>

<th width="11%">조회수</th>

</tr>

<c:forEach var="vo" items="${list }">

<tr>

<td align="right">${vo.bno}&nbsp;</td>

<td>&nbsp; <a href='detail?bno=${vo.bno}'>${vo.title}</a></td>

<td>&nbsp;${vo.nickname}</td>


<td>&nbsp; ${vo.dispDate}</td>

<td align="right"><span class="badge bg-blue">

${vo.readcnt}</span>&nbsp;</td>

</tr>

</c:forEach>

</table>

</div>

<div class="box-footer">

<div class="text-center">

<button id='mainBtn' class="btn-primary">메인으로</button>

</div>


<script>

$(function() {

$('#mainBtn').on("click", function(event) {

location.href = "../";

});

});

</script>

</div>

</div>

<%@include file="../include/footer.jsp"%>

</body>

<style>

.table th {

text-align: center;

}

</style>

</html>






 

1. 위도와 경도 구하기 

<script>

setInterval(function(){

//현재 접속한 브라우저의 위도와 경도 출력하기 

navigator.geolocation.getCurrentPosition(function(position){

alert(position.coords.latitude);

alert(position.coords.longitude);

})

},10000)

</script>



2. ajax를 통한 요청 

<script>

setInterval(function(){

//현재 접속한 브라우저의 위도와 경도 출력하기 

navigator.geolocation.getCurrentPosition(function(position){


loc = position.coords.latitude + "-" +position.coords.longitude

//address라는 URL loc를 파라미터로 넘겨서 

//json 타입으로 데이터를 받아오는 ajax 요청 

$.ajax({

url: "",

data:{"loc":loc},

dataType:'json',

success:function(data){

alert(data);

}

});

});

},10000);

</script>



**카카오 API를 이용해서 위도와 경도를 이용해서 주소를 찾아와서 출력하기 

1. kakaoapi에 가서 api를 이용해서 위도와 경도를 이용해서주소를 찾아와서 출력하기

1.userService 인터페이스에 위도와 경도를 받아서 주소를 리턴하는 메소드를 선언 

public String address(String loc)


2. UserServiceImpl 클래스에 위도와 경도를 받아서 주소를 리턴하는 메소드를 구현 



@Override

public String address(String loc) {

String [] ar  = loc.split("-");

String addr = "https://dapi.kakao.com/v2/local/geo/coord2address.json?";

addr= addr+"x=" +ar[1] +"&y="+ar[0];

//위의 주소를 가지고 URL 객체를 생성 

try {

//위의 주소를 가지고 URL 객체를 생성 

URL url = new URL(addr);

//URL 객체를 가지고 HttpURLConnection 객체 만들기

HttpURLConnection con = (HttpURLConnection)url.openConnection();

//인증부분은 받아야 하면 api에 작성되어있습니다.

//인증받기 

con.setRequestProperty("Authorization", "카카오 api 자리");

//옵션 설정 

con.setConnectTimeout(20000);

con.setUseCaches(false);

//줄단위 데이터 읽기 

BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));

StringBuilder sb = new StringBuilder();

while(true) {

String line =br.readLine();

if(line ==null) {

break;

}

//읽은 데이터가 있으면 sb에추가 

sb.append(line);

}

br.close();

con.disconnect();

 

System.out.println(sb);

JSONObject obj = new JSONObject(sb.toString());

System.out.println(obj);

JSONArray imsi = obj.getJSONArray("documents");

System.out.println(imsi);

JSONObject o = imsi.getJSONObject(0);

System.out.println(o);

JSONObject c = o.getJSONObject("address");

String address= c.getString("address_name");

return address;

}catch (Exception e) {

System.out.println("지도보이기" + e.getMessage());

e.printStackTrace();

}

return null;

}


3. JSONController 클래스에 위도와 경도를 받아서 주소를 JSON 문자열로 출력하는 메소드를 생성 


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

public Map<String, Object> login(String loc) {

Map<String, Object> map = new HashMap<String, Object>();

// 서비스에서 주소를 가져오는 메소드 호출

String address = userService.address(loc);

map.put("address", address);


return map;

}

4.home.jsp 파일에 위도와 경도를 Controller에 넘겨서 주소를 가져와서 출력하는 자바스크립트 코드와 출력 영역을 생성

1)출력 영역 생성

<div class="box-header with-border" id="address">

</div>


2)스크립트 코드 추가

ajax success에 

document.getElementById("address").innerHTML="<h3>" + data.address + "</h3>";









String json = {"meta":{"total_count":1},"documents":

[{"road_address":{"address_name":"서울특별시 중구 세종대로 110","region_1depth_name":"서울","region_2depth_name":"중구","region_3depth_name":"","road_name":"세종대로","underground_yn":"N","main_building_no":"110","sub_building_no":"","building_name":"서울시청","zone_no":"04524"},

"address":{"address_name":"서울 중구 태평로1가 31","region_1depth_name":"서울","region_2depth_name":"중구","region_3depth_name":"태평로1가","mountain_yn":"N","main_address_no":"31","sub_address_no":"","zip_code":"100744"}}]}


JSONObject obj = new JSONObject(json);

JSONArray ar = obj.getJSONArray("documents");

JSONObject ob = ar.getJSONArray(0);

String address =ob.getString("address_name");

**Java에서 JSON 파싱 

1. 의존성 라이브러리 추가 

<!--json 파싱 라이브러리 --> 

<!-- json 파싱 라이브러리 -->

<dependency>

<groupId>org.json</groupId>

<artifactId>json</artifactId>

<version>20171018</version>

</dependency>


2.JSONObject와 JSONArray를 이용해서 문자열을 파싱하면 됩니다. 

1) 문자열을 확인하고 그문자열을 생성자에 대입해서 JSONObject나 JSONArray객체로 만듭니다. 


2) get자료형(키 이름 또는 인덱스)를 이용해서 데이터를 읽어가면 됩니다.



 

[메일보내기]

 


1. 네이버메일 

비밀번호 전송이나 인증받기에 메일 보내는 기능을 많이 사용합니다.

POP3/SMTP 사용이 되야합니다. - 다른 곳에서 메일 받을 수 있음 



1. pom.xml 파일에 의존성 라이브러리 설정


<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context-support</artifactId>

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

</dependency>


<dependency>

<groupId>javax.mail</groupId>

<artifactId>mail</artifactId>

<version>1.5.6</version>

</dependency>

 

 

 

2.list.jsp 파일의 이름을 출력하는 부분에 이메일 링크를 추가

<a href="../user/sendmail?email=${vo.email}">${vo.nickname}</a>


3.servlet-context.xml 파일에 이메일 서버 설정을 위한 bean을 생성

<!-- 메일 서버 설정 -->

<beans:bean

class="org.springframework.mail.javamail.JavaMailSenderImpl"

id="mailSender">

<beans:property value="smtp.naver.com" name="host" />

<beans:property value="587" name="port" />

<beans:property name="username" value="ggangpae3" />

<beans:property name="password" value="wnddkd"></beans:property>

<beans:property value="utf-8" name="defaultEncoding" />

<beans:property name="javaMailProperties">

<beans:props>

<beans:prop key="mail.transport.protocol">smtp</beans:prop>

<beans:prop key="mail.smtp.auth">true</beans:prop>

<beans:prop key="mail.smtp.starttls.enable">true</beans:prop>

<beans:prop key="mail.debug">true</beans:prop>

</beans:props>

</beans:property>

</beans:bean>


4.UserController 클래스에 user/sendmail 요청이 오면 메일 보내기 화면으로 이동하는 메소드를 생성


//메일 보내기 링크를 눌렀을 때 메일 보내기 화면으로 이동하는 메소드

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

public String sendmail(@RequestParam("email")String email,

Model model) {

//model에 email 저장

model.addAttribute("email", email);

return "user/sendmail";

}


5.메일 보내기 화면으로 사용할 화면을 user 디렉토리에 sendmail.jsp 파일로 만들기

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

pageEncoding="UTF-8"%>


<%@ include file="../include/header.jsp"%>

<div class="container">

<form method="post">

<div class="form-group">

<label for="receiver">받는 사람 이메일</label> 

<input type="email" id="email"

name="receiver" value="${email}" readonly="readonly"

class="form-control" />

</div>


<div class="form-group">

<label for="title">메일 제목</label> 

<input type="text"

name="title"  

class="form-control" />

</div>

<div align="center">

<label for="contents">메일 제목</label>

<textarea class="form-control" rows="5" name="contents"></textarea>

</div>

<div align="center">

<input type="submit" value="메일 보내기" class="btn btn-warning">

</div>

</form>

</div>


<script>

email = document.getElementById("email");

email.addEventListener("click", function(e){

email.removeAttribute("readonly");

});

email.addEventListener("blur", function(e){

email.setAttribute("readonly","readonly")

})


</script>

<%@ include file="../include/footer.jsp"%>








6. userService인터페이스에 메일 보내기를 위한 메소드를 선언 

public void sendEmail(HttpServletRequest request) ;



7.userServiceImple 클래스에 메일 보내기를 위한 메소드를 구현 

@Override

public void sendEmail(HttpServletRequest request) {

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

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

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

try {

SimpleMailMessage message = new SimpleMailMessage();

message.setFrom("ggangpae3@naver.com");

//받는 사람 설정 

message.setTo(receiver);

//메이제목설정 

message.setSubject(title);

//메일 내용설정 

message.setText(content);

//메일 보내기 

mailSender.send(message);

}catch(Exception e) {

System.out.println("email 예외 "+e.getMessage());

e.printStackTrace();

}

}


8.UserController 클래스에 메일 보내기를 눌렀을 때 처리를 위한 메소드를 생성

@RequestMapping(

value="user/sendmail", method=RequestMethod.POST)

public String sendmail(HttpServletRequest request,

RedirectAttributes attr) {

userService.sendmail(request);

attr.addFlashAttribute("msg", "메일 보내기 성공");

return "redirec:/";

}

 

AOP 관점지향 프로그래밍 


Aspect Oriented Programming(관점 지향 프로그래밍): 객체 지향 프로그래밍을 보완하는 

개념으로 메소드나 클래스를 관점에 따라 분리시켜서 구현하는 프로그래밍 방법

하나의 메소드에 비지니스 로직을 수행하는 문장과 공통으로 사용하는 문장이 같이 존재할 때 이를 분리해서 구현하기 위한 프로그래밍 방식 

관점지향 프로그래밍이라고 하는데 spring에서는 공통으로 사용하는 문장을 별도의 클래스에 작성해서 분리를 할 수 있는 기능을 제공합니다.

실행될 때 코드를 합쳐서 하나의 proxy 객체를 만들어서 실행합니다. 




**AOP 적용

AOP: 하나의 메소드에 비지니스 로직을 수행하는 문장과 공통으로 사용하는 문장이 같이 존재할 때 이를 분리해서 구현하기 위한 프로그래밍 방식

관점 지향 프로그래밍이라고 하는데 spring에서는 공통으로 사용하는 문장을 별도의 클래스에 작성해서 분리를 할 수 있는 기능을 제공합니다.

실행 될 때 코드를 합쳐서 하나의 proxy 객체를 만들어서 실행합니다.


=>Dao 클래스의 메소드가 호출될 때의 시간을 매일 파일에 기록하는 AOP


1.advice로 사용될 클래스를 생성

=>kr.co.pk.advice.LoggingAdvice


package kr.co.pk.advice;


import java.io.FileOutputStream;

import java.io.PrintWriter;

import java.util.Calendar;


import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.springframework.stereotype.Component;


//객체를 자동으로 생성하기 위한 어노테이션

@Component

//Advice 클래스로 만들기 위한 어노테이션

@Aspect

public class LoggingAdvice {


//advice로 수행될 메소드

//pointcut 작성

//접근지정자는 public 다음 *은 모든 리턴 타입

//kr.co.pk.. 은 kr.co.pk 패키지 안에 있는 모든

//*Dao 는 Dao로 끝나는 클래스 .* 은 메소드 이름이 무엇이든지

//(..)은 매개변수 개수에 상관없이

@Around("execution(public * kr.co.pk..*Dao.*(..))")

public Object invoke(ProceedingJoinPoint joinPoint)

throws Throwable{

//pointcut으로 설정된 메소드가 호출되기 전에 수행할 내용

//메소드 이름 가져오기

String methodName = joinPoint.getSignature().toLongString();

//현재 시간 만들기

Calendar cal = Calendar.getInstance();

java.util.Date date = new java.util.Date(

cal.getTimeInMillis());

//파일에 문자열 기록하기 - 파일이 존재하면 이어쓰기

FileOutputStream fos = 

new FileOutputStream("d:\\log.txt", true);

//문자열을 기록할 수 있는 클래스의 객체 만들기

PrintWriter pw = new PrintWriter(fos);

//파일에 기록

pw.println(methodName + " " + date.toString() + "\n");

pw.flush();

pw.close();

Object obj = joinPoint.proceed();

//pointcut으로 설정된 메소드가 호출 된 후에 수행할 내용

return obj;

}

}


2.pom.xml 파일에 aop를 사용하기 위한 의존성 라이브러리를 추가

<dependency>

<groupId>org.aspectj</groupId>

<artifactId>aspectjweaver</artifactId>

<version>1.8.8</version>

</dependency>


<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-aop</artifactId>

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

</dependency>


<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-aspects</artifactId>

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

</dependency>


3.servlet-context.xml 파일에 aop 네임스페이스를 추가하고 어노테이션으로 설정한 aop를 사용할 수 있는 태그를 추가

<!-- 어노테이션으로 만든 AOP 적용 -->

<aop:aspectj-autoproxy />



 

1:1 통신이 성공하고 난 후 채팅을 만들 때는 클라이언트가 접속을 하면 각각의 클라이언트를 List에 저장을하고 하나의 클라이언트가 메시지를 보내오면 

그 메시지를 List의 모든 클라이언트에게 전송하는 것입니다.


1. Spring Web Socket을 위한 의존성 

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-websocket</artifactId>

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

</dependency>


2. 채팅을 위한 웹 소켓 서버 클래스를 생성 

=> com.seunghoo.na.service.ChatHandler클래스 

=> TextWebSocketHandler을 상속받아야합니다.


package com.seunghoo.na.service;


import java.util.ArrayList;

import java.util.List;


import org.springframework.stereotype.Component;

import org.springframework.web.socket.CloseStatus;

import org.springframework.web.socket.TextMessage;

import org.springframework.web.socket.WebSocketSession;

import org.springframework.web.socket.handler.TextWebSocketHandler;

@Component

public class ChatHandler extends TextWebSocketHandler {

// 접속한 클라이언트 세션들을 저장할 LIST를 생성

// 이 List는 1개만 만들어져야 하므로 static으로 선언

private static List<WebSocketSession> list = new ArrayList<WebSocketSession>();


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

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

@Override

public void afterConnectionEstablished(WebSocketSession session) throws Exception {

list.add(session);

System.out.println("하나의 클라이언트가 연결됨 ");

}

//클라이언트가 메시지를 보냈을 때 호출되는 메소드 

@Override

protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

// 전송된 메시지를 List의 모든 세션에 전송

String msg = message.getPayload();

for (WebSocketSession s : list) {

s.sendMessage(new TextMessage(msg));

}

}


// 클라이언트의 접속이 해제 되었을 때 호출되는 메소드

@Override

public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

System.out.println("클라이언트와 연결 해제됨");

list.remove(session);

}

}



3. home.jsp 파일에 채팅창으로 이동하는 링크를 추가 

<a href ="chat"> 채팅 </a>


4. HomeController에서 chat 요청이 왔을 때 chat.jsp로 이동하도록 메소드 생성 

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

public void chat(Locale locale, Model model) {

}


5. ChatHandler클래스를 웹 소켓으로 등록 : Servlet-context.xml 파일 

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

6. views 디렉토리에 채팅페이지(chat.jsp)를 생성

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

pageEncoding="UTF-8"%>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

</head>

<body>

<div id="one">

별명:<input type="text" id="nickname" /> <input type="button"

id="enter" value="입장" />

</div>

<div id="two" style="display: none">

<input type="button" id="exit" value="퇴장" /><br />

<div id="chatarea" style="width:400px; height:600px; border:1px solid;"></div>

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

value="보내기" />

</div>


</body>

<script>

one = document.getElementById("one");

two = document.getElementById("two");


document.getElementById("enter").addEventListener("click", function() {

//웹 소켓 연결해주는 함수 호출 

connect();

});


document.getElementById("exit").addEventListener("click", function() {

//연결을 해제해주는 함수 호출 

disconnect();

});

document.getElementById("send").addEventListener("click", function() {

//연결을 해제해주는 함수 호출 

send();

});

var websocket;

//입장 버튼을 눌렀을 때 호출되는 함수 

function connect(){

websocket = new WebSocket("ws://localhost:9000/na/chat-ws");

//웹 소켓에 이벤트가 발생했을 때 호출될 함수 등록 

websocket.onopen = onOpen;

websocket.onmessage = onMessage;

websocket.onclose = onClose;

}

//퇴장 버튼을 눌렀을 때 호출되는 함수 

function disconnect(){

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

websocket.send(msg+"님이 퇴장하셨습니다");

websocket.close();

}

//보내기 버튼을 눌렀을 때 호출될 함수 

function send(){

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

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

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

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

}

//웹 소켓에 연결되었을 때 호출될 함수 

function onOpen(){

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

websocket.send(nickname + "님 입장하셨습니다.");

}

//웹 소켓에서 연결이 해제 되었을 때 호출될 함수 

function onMessage(evt){

data= evt.data;

chatarea = document.getElementById("chatarea");

chatarea.innerHTML = data + "<br/>" + chatarea.innerHTML

function onClose(){

}

</script>

</html>



*인코딩 

iso-8859-1(iso-lation-1) 기본 인코딩으로 많이 사용 , 한글지원이 안됨 

euc-kr(ms949, cp949) MS가 한글을 지원하기 위해 만든 인코딩 

utf-8 전 세계 모든 글자를 지원하기 위해 만든 인코딩 

최근에는 전부 utf-8로 인코딩합니다.









[ 1. home.jsp 파일에서 파일목록보기를 하면 c:\에 있는 파일들의 목록을 출력하기 ]



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

    pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>홈</title>

</head>

<body>

  <a href="fileview.do"> 파일목록보기</a>

</body>

</html>


2. ViewService인터페이스를 implements한  ViewServiceImpl에서 파일이 존재하면 list에 저장하는 메소드를 구현 


package com.naseunghoo.service;


import java.io.File;

import java.util.ArrayList;

import java.util.List;


import org.springframework.stereotype.Service;




@Service

public class ViewServiceImpl implements ViewService {


//배열이나 List를 리턴하는 경우에 받는 쪽에서 거의 대부분 

//반복문을 시용하기 때문에 null을 리턴하면 안됩니다.

//객체 생성을 먼저해서 데이터가 없는 경웨 size 0가 

//되게 리턴해야 합니다.

@Override

public List<String> filelist() {

List<String> list = new ArrayList<String>();

//파일 목록을 조사할 디렉토리를 File객체로 생성 

File f= new File("c:\\");

//디렉토리 안의 모든 파일 및 디렉토리를 가져오기 

String [] ar = f.list();

//배열의 모든 데이터를 순회해서 .이 없는 것들만 list에 추가 

//위치를 찾아주는 메소드는 데이터가 없으면 음수를 리턴하거나 

//예외를 발생시킵니다. 

for(String imsi : ar) { 

if(imsi.indexOf(".")>=0) {

list.add(imsi);

}

}

return list;

}


}



3. 화면에 출력하기 

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

    pageEncoding="UTF-8"%>

    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>보여주기</title>

</head>

<body>

<table border="1">

<tr><th>파일명</tr>


<c:forEach var="item" items="${list}">

<tr>

<!-- 파라미터 이름  -->

<td><a href="download/${temp}">${temp}</a></td>

</tr>

</c:forEach>

</table>

</body>

</html>



**Web에서 파일 다운로드 

=> web서버에서 파일의 경로만 a href="파일경로"의 형식으로 링크를 걸면 파일을 다운로드 받을 수 있습니다. 

=> 직접 파일 경로를 설정한 경우에는 브라우저가 출력할 수 있는 파일의 경우 

=> 파일을 다운로드 하지 않고 실행을 시킵니다. 

텍스트 파일이나 이미지 파일의 경우는 화면에 출력됩니다.

=> 브라우저가 출력하지 않고 다운로드 하게 만들려면 파일경로에 Controller가 처리할 수 있는 링크를 만들어주고 Controller에서 다운로드하는 

뷰로 출력하도록 설정하면 됩니다 /.


1. fileview.jsp 파일의파일명을 출력하는 부분에 링크를 설정 

<!-- 파라미터 이름  -->

<td><a href="download?filename=${item}">${item}</a></td>


2. homeController에 위의 요청을 처리하는 메소드를 생성 

@RequestMapping(value="download/{}",method=RequestMethod.GET)

public String download(@PathVariable String filename, Model model){

File f= new File("c:\\ + filenaame");

//데이터 저장 

model.addAttribute("file", f);

//출력할 뷰 이름 리턴 

return "download";

}

3. file 이라는 이름으로 넘어온 파일 객체를 가지고 다운로드 화면을 만들어주는 뷰 클래스 생성 

= com.naseunghoo.view.view.DownloadView - AbstractView를 상속 

=> 화면을 직접 만들고자 할 때 AbstractView를 상속 받습니다.


package com.naseunghoo.view.view;


import java.io.File;

import java.io.FileInputStream;

import java.io.OutputStream;

import java.net.URLEncoder;

import java.util.Map;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.springframework.util.FileCopyUtils;

import org.springframework.web.servlet.view.AbstractView;


public class DownloadView extends AbstractView {


public DownloadView() {

super();

// 파일의 종류 설정 - 다운로드 받을 수 있도록 설정

setContentType("application/download; charset=utf-8");


}


userAgent 는 유저가 접속하는 브라우져를 알기 위해서 확인 

@Override

//

protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,

HttpServletResponse response) throws Exception {


// Controller에서 넘어온 데이터를 가져오기

// Map에서 데이터를 가져올 때는 반드시 원래의 자료형으로 형변환 해주어야합니다.

// model은 Map의 형태로 자료를 가지고 있고 값은 Object 이기 때문에

// 형변환 해주는 것입니다.

//get의 값은 controller에서 model로 보내는 addAttribute 키값을 적어주면 됩니다.  

File file = (File) model.get("file");

// 응답할 객체의 종류와 크기 설정

response.setContentLength((int) file.length());

response.setContentType(getContentType());


// 접속한 클라이언트의 운영체제 종류와 브라우저 종류를

// 알아 낼 수 있는 헤더 가져오기

String userAgent = request.getHeader("User-Agent");


// 접속한 브라우저가 IE 인지 확인

boolean ie = userAgent.indexOf("rv") > -1;

// 브라우저 별 파일 이름 설정

// 브라우저 별로 한글 인코딩은 다르게 설정됩니다.

// IE와 다른 브라우저로 구분

String filename = "";

if (ie) {

filename = URLEncoder.encode(file.getName(), "utf-8");

} else {

filename = new String(file.getName().getBytes("utf-8"), "iso-8859-1");

}


// 응답 객체에 파일 이름을 설정

response.setHeader("Content-Disposition", "attachment; fulename\"" + filename + "\";");


// 원본 파일의 내용을 읽어서 response를 통해서 전송

OutputStream out = response.getOutputStream();


try (FileInputStream fis = new FileInputStream(file)) {


FileCopyUtils.copy(fis, out);


} catch (Exception e) {

System.out.println("[다운로드] 예외 " + e.getMessage());

e.printStackTrace();

}

}


}



4. servlet-context.xml 파일에 가서 기존 ViewResolver의 우선 순위를 변경하고 beanNameViewResolver를 추가하고 download 뷰 요청이 왔을 때 출력할 뷰를 설정 


1) 출력할 뷰를 설정할 때 기존의 jsp가 아닌 직접 작성한 뷰로 출력할 수 있도록 해주는 

BeanNameViewResolver 클래스의 bean 을 생성 

beanNameViewResolver를 통해 똑같은 아이디의 요청이 있는지 확인하고 처리할 빈을 선택해줍니다.

<beans:bean class="org.springframework.web.servlet.view.BeanNameViewResolver">

<beans:property name="order" value="0"></beans:property>

</beans:bean>


2) 기존 VeiwResolver의 우선 순위를 변경 

<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

에 아래 프로퍼티를 추가 

<beans:property name="order" value="1"></beans:property>



3) controller에서 download라는 뷰 이름을 넘겨줄 때 출력할 뷰를 직접 설정 

<beans:bean id="download" class="com.naseunghoo.view.view.DownloadView"></beans:bean>









[다른방법] 

1. 파라미터를 읽어서 수행해야할 경우 home.jsp  파일에  download 링크 파일을 수정  filename이라는 파라미터속성 추가 작성 


<td><a href="download?filename=${temp}">${temp}</a></td>



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

public String download(@RequestParam("filename") String filename, Model model){

File f= new File("c:\\ + filename");

//데이터 저장 

model.addAttribute("file", f);

//출력할 뷰 이름 리턴 

return "download";

}

beanNameViewResolver를 통해 똑같은 아이디의 요청이 있는지 확인하고 처리할 빈을 선택해줍니다.

1. 인터페이스와 클래스의 차이 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
hjjavainterface I2{
    public String A();
}
interface I3{
    public String B();
}
class D implements I2, I3{
    public String A(){
        return "A";
    }
    public String B(){
        return "B";
    }
}
public class PolymorphismDemo3 {
    public static void main(String[] args) {
    
        //전체 메소드 사용 가능 
        D obj = new D();
        // I2에 정의된 메소드만 사용가능 
        I2 objI2 = new D();
        //I3에 정의된 메소드만 사용가능 
        I3 objI3 = new D();
         
         //아무 문제가 없다.
        obj.A();
        obj.B();
         
        objI2.A();
        //objI2.B(); 존재하지 않는 메소드 
         
        //objI3.A();
        objI3.B(); 존재하지 않는 메소드 
    }
}
cs



 Hand 인터페이스를 implements한 클래스(Car, Book, Water)가 있다


hand에는 들어올리다, 보다라는 메소드가 있고 이것을 implements한 Car,Book,Water는  전부 구현한 상태이다. 

그리고 인터페이스에 주입하는 클래스의 객체가 어떤 것이냐에 따라 서로다른 역할 을 감당할 수 있다. 

//Car클래스의 메소드와 Hand의 인터페이스를 구현한 메소드 및 인스턴스 변수를 사용할 수 있는 것이다. 

Hand hand = new Car();

그러나 여기서 유의할점은 Hand를 implements한 다른 클래스는 new Car()객체의 메소드는 부를 수 없다 

 Hand hand2 = new Book();

//오류 없는 메소드 

hand2.door();



※ MyBatis의 자료형 매핑

number – Integer, Double, Float, Byte, Short, Long, BigDecimal

char, varchar2, clob – String

date – java.sql.Date, java.util.Date

time – java.sql.Time, java.util.Date 

timestamp – java.sql.Timestamp

blob – byte []



1. 의존성 설정 


<repositories>

<repository>

<id>codelds</id>

<url>https://code.lds.org/nexus/content/groups/main-repo</url>

</repository>

</repositories>


<dependency>

<groupId>com.oracle</groupId>

<artifactId>ojdbc6</artifactId>

<version>11.2.0.3</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-jdbc</artifactId>

<version>${spring-framework.version}</version>

</dependency>

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

<version>3.4.6</version>

</dependency>

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis-spring</artifactId>

<version>1.3.2</version>

</dependency>





2. mapper 


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

<!DOCTYPE mapper

  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

  http://mybatis.org/dtd/mybatis-3-mapper.dtd>


<mapper namespace=“매퍼이름">

<select id="호출할 이름 " resultType="결과 자료형“ 또는 parameterType=“자료형” >

    select 구문

  </select>

<insert id="호출할 이름" parameterType="매개변수 자료형">

INSERT INTO

AddressBook

VALUES (#{프로퍼티이름 또는 키이름})

</insert>

</mapper>



파라미터 설정 - #{이름}

MyBatis는 기본적으로 PreparedStatement 클래스를 이용해서 SQL을 작성하고 실행

파라미터를 ? 대신에 #{이름}으로 작성

파라미터가 1개인 경우는 wrapper 클래스나 String, Date 클래스로 parameterType을 설정하고 이름은 아무것이나 입력해도 됩니다.

파라미터가 여러 개 인 경우는 parameterType을 DTO 나 Map으로 설정

DTO 클래스를 설정한 경우는 프로퍼티(접근자 메소드 – getter) 이름으로 파라미터 이름을 설정해야 합니다.

Map으로 parameterType을 설정한 경우는 키의 이름을 설정해야 합니다.



SqlSessionTemplate 클래스는 SqlSession 클래스를 상속받았기 때문에 SqlSession의 메소드를 그대로 이용하면 됩니다.

sqlSession.insert, delete, update, selectOne, selectList(매퍼이름.id, 매개변수)를 호출하면 됩니다.

매퍼 파일의 sql 구문이 parameter를 받지 않는 경우라면 매개변수는 생략하고 호출이 가능

insert와 delete, update는 영향 받은 행의 개수를 정수로 리턴

selectOne은 설정한 resultType 객체를 리턴

selectList는 설정한 resultType의 List로 리턴

selectOne 메소드는 결과가 2개 이상 나오면 예외를 발생

Map으로 select 구문의 결과를 받는 경우 컬럼 이름이 키가 되고 데이터가 값

오라클의 데이터의 타입이 Number이면 Map에서는 BigDecimal로 저장

Map으로 select 구문의 결과를 받는 경우 키의 이름은 오라클은 모두 대문자 MySQL은 소문자로 저장



3.mybatis 패키지 경로 설정 


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

<!DOCTYPE configuration

  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

  "http://mybatis.org/dtd/mybatis-3-config.dtd">


<configuration>

<typeAliases>

<package name="com.tistory.tstigma"/>

</typeAliases>

</configuration>





4. applicationContext.xml


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

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">


<!-- 어노테이션을 사용할 수 있도록하는 설정  -->


<context:annotation-config/>

<context:component-scan base-package="transaction"></context:component-scan>



<!-- DataSource 빈 설정 -->

<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">

<property value="oracle.jdbc.driver.OracleDriver" name="driverClassName" />

<property value="jdbc:oracle:thin:@192.168.0.200:1521:xe" name="url" />

<property value="user08" name="username" />

<property value="user08" name="password" />

</bean>

<!-- SqlSessionFactoryBean : MyBatis 설정 정보 -->

<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">

<property name="dataSource" ref="dataSource" />

<!--db 내용을 good.xml에 저장 -->

<property value="classpath:mybatis/mappers/good.xml" name="mapperLocations" />

<property value="classpath:mybatis/mybatis-config.xml" name="configLocation" />

</bean>

<!-- 붙었다 떨어졌다는 여기서하고 위에서는 설정 정보만 가지고 잇습니다.  -->

<!-- SqlSessionTemplate: Mybatis 사용 객체  -->

<bean class="org.mybatis.spring.SqlSessionTemplate" id="sqlSession" destroy-method="clearCache">

<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />

</bean>

<!-- MyBatis에 트랜잭션을 적용하기 위한 객체  -->

<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"/>

</bean>

<tx:annotation-driven transaction-manager="transactionManager"/> 

</beans>



+ Recent posts