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 />



**인터셉터 

게시글쓰기, 상세보기, 수정, 삭제 등은 로그인 되어 있지 않은 유저는 작업을 수행할 수 없도록 하고자 하는 경우 이러한 코드를 Controller, Service, Dao 등에 작성하는 것은 이상합니다.

스프링에서는 Interceptor 나 AOP 등을 이용해서 구현 할 수 있습니다.

Interceptor는 URL을 설정해서 URL 요청이 왔을 때 메소드를 호출하도록 할 수 있습니다.


1. 로그인이 되어 있지 않으면 로그인 페이지로 이동시키고 로그인을 하면 작업을 할 수 있는 페이지로 이동하도록 만들어봅시다. 


=> Interceptor : url 요청이 왔을 때 Controller 보내기 전이나 Controller가 작업한 후에 수행할 내용을 작성할 수 있는 Spring이

제공하는 기능 

=>HandlerInterceptor 인터페이스나 HandlerInterceptorAdapter 클래스를 상속받는 클래스를 만들어서 메소드를 재정의 하고 

dispatcher-servlet(Servlet-Context.xml)에 interceptors 태그를 이용해서 설정하면 됩니다.

=> HandlerInterceptorAdapter인터페이스는 모든 메소드가 추상메소드라서 전부 재정의 해야하고 

HandlerInterceptorAdapter 클래스는 모든 메소드가 내용이 없는 상태로 구현되어 있어서 필요한 메소드만 재정의 하면 되는데 

메소드 이름을 기억하기 어려우므로 인터페이스를 이용합시;다. 



2.HandlerInterceptorAdapter를 implements 한 클래스 안의 재정의 된 메소드 설명 

=> com.seunghoo.na.AuthenticationInerceptor


1. preHandle 메소드 : Controller가 처리하기 전에 호출되는 메소드 


2. postHandle 메소드 : Controller가 사용자의 요청을 정상적으로 처리하고 난 후 호출되는 메소드 


3. afterCompletion메소드 :  Controller에서 예외 발생여부에 상관없이 호출되는 메소드 



3.HandlerInterceptorAdapter를 implements 한 클래스를 생성 

@Component

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {


// 로그인을 확인하기 위해서 session 가져오기

HttpSession session = request.getSession();

// 로그인 정보는 session의 user 속성에 저장되어 있습니다.

if (session.getAttribute("user") == null) {

// 사용자의 요청을 session에 dest라는 속성에 저장

// 로그인이 되면 원래의 요청을 처리하기 위해서

// 클라이언트 요청 전체 주소

String requestURI = request.getRequestURI();

// 현재 프로젝트 경로 가져오기

String contextPath = request.getContextPath();

String uri = requestURI.substring(contextPath.length() + 1);

// 주소 뒤에 파라미터를 가져오기

String query = request.getQueryString();

System.out.println("쿼리"+query);

System.out.println("URI"+uri);

// 실제 주소만들기

if (query == null || query.equals("null")) {

query = "";

} else {

query = "?" + query;

}

//세션에 주소 저장하기 

session.setAttribute("dest", uri+query);

//세션에 메시지 저장하기 

session.setAttribute("msg","로그인을 하셔야 이용할 수 있는 서비스 입니다.");


response.sendRedirect(contextPath + "/user/login");

return false;

}

// 로그인된 경우에는 Controller가 처리합니다.


return true;

}

4. UserController 에서 로그인을 처리하는 메소드를 수정 

=> 이전에는 무조건 시작 페이지로 가도록 되어 있었지만 요청이 있는 경우 그페이지로 이동하도록 코드를 수정 

session.setAttribute("user", user);

//이전 요청을 가져오기 

Object dest = session.getAttribute("dest");

//이전 요청이 없으면 시작페이지로 이동 

if(dest==null) {

return "redirect:/";

//이전 요청이 있으면 그 페이지로 이동 

}else {

return "redirect:/"+dest.toString();

}

**게시물 삭제

1.detail.jsp 파일에 삭제를 위한 UI 와 이벤트를 작성

=>jquery ui의 dialog 기능을 이용

1)삭제 버튼(deletebtn)을 눌렀을 때 수행되는 코드가 있으면 제거


2)파일의 하단에 대화상자로 사용할 내용 만들기

<c:if test="${user.email == vo.email}">

<link rel="stylesheet"

href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>


<div id="dialog-confirm" title="정말로 삭제?" style="display: none">

<p>삭제하시면 복구할 수 없습니다. 그래도 삭제하실 건가요?</p>

</div>


<script>

//삭제 버튼을 눌렀을 때 처리

document.getElementById("deletebtn").addEventListener(

"click", function(){

$("#dialog-confirm").dialog({

      resizable: false,

      height: "auto",

      width: 400,

      modal: true,

      buttons: {

        "삭제": function() {

          $(this).dialog("close");

          location.href="delete?bno=${vo.bno}";

        },

        "취소": function() {

          $(this).dialog("close");

        }

      }

    });

});

</script>

</c:if>


2.board.xml 파일에 게시글을 삭제하는 SQL을 작성

<!-- 게시글 삭제를 위한 SQL -->

<delete id="delete" parameterType="java.lang.Integer">

delete from springboard

where bno=#{bno}

</delete>


3.BoardDao 클래스에 게시글을 삭제하는 메소드를 생성

//글번호에 해당하는 데이터를 삭제를 하는 메소드

public void delete(int bno) {

sqlSession.delete("board.delete", bno);

}


4.BoardService 인터페이스에 게시글을 삭제하는 메소드를 선언

//게시글 삭제를 처리해 줄 메소드를 선언

public void delete(HttpServletRequest request);


5.BoardServiceImpl 클래스에 게시글을 삭제하는 메소드를 구현

@Override

public void delete(HttpServletRequest request) {

//파라미터 읽기

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

//Dao 메소드 호출

boardDao.delete(Integer.parseInt(bno));

}


6.Controller 에 게시물 삭제를 처리해주는 메소드 생성 


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

public String delete(HttpServletRequest request, RedirectAttributes attr) {

boardService.delete(request);

attr.addFlashAttribute("msg", "삭제");

return "redirect:list";

}

















 게시글 수정 

상세보기를 작업할 때는 글번호를 가지고 이미 데이터를 찾아오는 방법이 있기 때문에 Service부터작업하면 됩니다.


1. BoardService 인터페이스에 게시글을 가져와서 수정보기에 사용할 메소드스를 선언 

//게시물 수정 보기를 위한 메소드 

public Board updateView(HttpServletRequest request);


2. BoardServiceImpl 클래스에 게시글을 가져와 수정보기에 사용할 메소드를 구현 


@Override

public Board updateView(HttpServletRequest request) {

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

return boardDao.detail(Integer.parseInt(bno));}

3. BoardController 클래스에 게시글을 가져와서 수정보기 화면에 출력하는 메소드를 구현 

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

public String update(HttpServletRequest request ,Model model){

Board board = boardService.detail(request);

model.addAttribute("vo", board);

return "board/update";


}


4.Board디렉토리에 update.jsp 파일을 만들고 수정화면을 작성 

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

pageEncoding="UTF-8"%>

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

<section class="content">

<div class="box-header">

<h3 class="box-title">게시판 수정</h3>

</div>


<form role="form" method="post">

<!-- 데이터 수정을 할 때 기본키의 값이 있어야 해서 필요하고

작업이 끝나고 결과 페이지로 이동할 때

상세보기로 이동하려면 글번호가 필요합니다. -->

<input type="hidden" name="bno" value="${vo.bno}" />

<div class="box-body">

<div class="form-group">

<label>제목</label> <input type="text" name='title'

class="form-control" value="${vo.title}">

</div>

<div class="form-group">

<label>내용</label>

<textarea class="form-control" name="content" rows="5">${vo.content}</textarea>

</div>


<div class="form-group">

<label>작성자</label> <input type="text" name="nickname"

value="${user.nickname}" class="form-control" readonly="readonly">

</div>

</div>


<div class="box-footer">

<button type="submit" class="btn btn-primary">작성완료</button>

</div>

</form>

</section>

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


5. board.xml 파일에 게시글 수정을 위한 SQL 작성 

<update id="update" parameterType="Board">


update springboard

set

title=#{title}, content=#{content}, regdate=sysdate

where bno=#{bno}


</update>

6. BoardDao 클래스에 게시글 수정을 위한 메소드 생성 

public void update(Board board) {

sqlSession.update("board.update",board);

}


7.게시글 수정을 처리해 줄 메소드를 선언 

public void update(HttpServletRequest request);


8.BoardServiceImpl 클래스에 게시글 수정을 처리해 줄 메소드를 구현 

@Override

public void update(HttpServletRequest request) {

// 파라미터 읽기

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

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

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

String ip = request.getRemoteAddr();

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


// Dao 메소드를 호출

Board board = new Board();

board.setIp(ip);

board.setContent(content);

board.setTitle(title);

board.setBno(Integer.parseInt(bno));

boardDao.update(board);


}


9. BoardController에서 게시물 수정을 처리해줄 메소드  

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

public String update(HttpServletRequest request , RedirectAttributes attr){

boardService.update(request);

attr.addFlashAttribute("msg","게시글 수정");

return "redirect:list";


}

 **상세보기 

=>게시판에서는 글 제목을 클릭하면 상세보기를 하도록 만듭니다.

=>상세보기를 할 때는 기본키의 값을 파라미터로 넘겨주도록 링크를 작성 

=>상세보기는 2개의 sql을 실행해야 합니다. 

=> 글번호에 해당하는 데이터의 조회수를 1증가 

=> 글번호에 해당하는 데이터를 가져와야 합니다.

<a href="링크? 이름=기본키값">제목</a>





1. list.jsp 파일에서 제목을 출력하는 부분을 링크를 추가 

<a href="detail?bno=${vo.bno}">${vo.title}</a>



2. 글번호 에 해당하는 데이터를 가져와야합니다. 

<!-- 상세보기를 할때 글 번호에 해당하는 데이터의 조회수를 1증가시켜주는 sql -->

<update id="updatecnt" parameterType="java.lang.Integer">


update springboard

set readcnt = readcnt +1

where bno=#{bno}


</update>

3.상세보기를 할 때 글번호에 해당하는 데이터를 가져오는 sql 


<select id="detail" parameterType="java.lang.Integer" resultType="Board">

select * 

from springboard

where bno = #{bno}

</select>



3. BoardDao 클래스에 글번호에 해당하는 데이터의 조회수를 1증가시켜 주는 

메소드와 글번호에 해당하는 데이터를 가져오는 메소드를 생성 


public void updatecnt(int bno){

sqlSession.update("board.updatecnt",bno);

}

//글번호에 해당하는 데이터를 가져오는 메소드 

public Board detail(int bno) {

return sqlSession.selectOne("board.detail",bno);

}


4. BoardService 인터페이스에 상세보기를 처리할 메소드를 선언 

public Board detail(HttpServletRequest request) ;



5.BoardServiceImpl 클래스에 상세보기를 처리할 메소드를 구현 


@Override

public Board detail(HttpServletRequest request) {

//파라미터 읽기 

//Integer.parsint를 호출했을 때 예외가 생기는 경우 

//=> null이 리턴되서 정수로 변환을 못하는 경우 

//=> 숫자 뒤에 공백이 포함되 정수로 변환을 못하는 경우 

//NumberFormatException이 발생하면 Integer.parseint에 대입한 데이터를 먼저 출력해서 확인 

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

//조회수 1증가시키는 메소드 호출 

boardDao.updatecnt(Integer.parseInt(bno));

//데이터 가져오는 메소드를 호출해서 리턴 

return boardDao.detail(Integer.parseInt(bno));

}


5.BoardController에 상세보기 요청을 처리하는 메소드를 구현 

@Reqeustparam(value = "board/detail", method=Reqeustparam.GET)

public String detail(HttpServletRequest request ,Model model){

Board board = boardService.detail(request);

model.addAttribute("board", board);

return "board/detail";


}



7.views.board 디렉토리에 detail.jsp 파일을 만들고 출력 

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

    pageEncoding="UTF-8"%>

<!DOCTYPE html>

<html>

<head>

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

<title>상세보기</title>

</head>

<body>

${vo}

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


<section class="content">

<div class="box">

<div class="box-header">

<h3 class="box-title">상세보기</h3>

</div>

<div class="box-body">

<div class="form-group">

<label>제목</label>

<input type="text" name="title"

class="form-control" value="${vo.title}"

readonly="readonly" />

</div>

<div class="form-group">

<label>내용</label>

<textarea name="content" rows="5"

readonly="readonly" class="form-control">${vo.content}</textarea>

</div>

<div class="form-group">

<label>작성자</label>

<input type="text" 

class="form-control" value="${vo.nickname}"

readonly="readonly" />

</div>

</div>

<div class="box-footer">

<button class="btn btn-success" id="mainbtn">메인</button>

<c:if test = "${user.email == vo.email}">

<button class="btn btn-warning" id="updatebtn">수정</button>

<button class="btn btn-danger" id="deletebtn">삭제</button>

</c:if>

<button class="btn btn-primary" id="listbtn">목록</button>

</div>

</div>

</section>

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

<script>

//메인 버튼을 눌렀을 때 처리

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

location.href="../";

});

//목록 버튼을 눌렀을 때 처리

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

location.href="list";

});

<c:if test = "${user.email == vo.email}">

//삭제 버튼을 눌렀을 때 처리

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

location.href="delete?bno=" + ${vo.bno};

});

//수정 버튼을 눌렀을 때 처리

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

location.href="update?bno=" + ${vo.bno};

});

</c:if>

</script>

</body>

</html>


**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:/";

}

 

+ Recent posts