- 안드로이드 재생 플레이어 만들기 중 Spring Boot 부분 추가중!

- 파일 업로드 폼에서 mp3파일만 선택 가능하게 하고 싶다면,


- jsp의 insertform 에서 지정해주면 된다.
- input 요소에 accept 라는 속성이 있다. 여기서 업로드할 수 있는 확장자를 지정할 수 있다.
- 여러 종류를 지정하고 싶다면 , 로 구분해서 나열하면 된다.

- input요소 name 속성의 value 값을 주의해서 넣어야 한다!
- 업로드를 처리할 때 쓰는 컨트롤러의 지역변수명과 같아야 한다.

- 만약 다르게 쓰고싶다면 이렇게 쓸 수도 있다.
- @RequestParam 은 요청 파라미터의 기능을 지원하는 어노테이션

- 이 @RequestParam 어노테이션에는 defaultvalue 라는 것이 있는데,
만약 요청 파라미터가 전달되지 않으면 기본값을 지정할 수 있는 기능이다.
- 하지만 굳이..? 이렇게 작성하는 것이 훨씬 불편하다...

- 컨트롤러 메소드의 지역변수명과 일치시켜서 사용하는 방법이 편하다.
- 아니면 전달되는 정보가 여러개라면 dto 안에 multipartFile을 만들어놓으면 되는데,
이 경우에는 Dto의 필드명과 일치시켜야 파일 업로드 처리가 잘 된다.
- 선택한 음원파일이 업로드되고, list로 출력되도록 할 예정!

- 현재 업로드, DB 저장 기능만 구현되어 있다. DB에서 확인하면 이렇게 나와있다.
- 저장하지 않은 Title, Artist 값도 잘 추출되어 들어오는 것을 볼 수 있다.
- 필요하다면 앨범 타이틀 이미지도 추출할 수 있다. (메타데이터가 있는 경우)
- interceptor 설정하기
WebConfig
package com.sy.boot07.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.sy.boot07.interceptor.LoginInterceptor;
import com.sy.boot07.interceptor.MobileLoginInterceptor;
@Configuration
public class WebConfig implements WebMvcConfigurer{
//로그인 인터셉터 주입 받기
@Autowired LoginInterceptor loginInterceptor;
@Autowired MobileLoginInterceptor mLoginInterceptor;
//인터셉터 동작하도록 등록하기
@Override
public void addInterceptors(InterceptorRegistry registry) {
//웹브라우저의 요청에 대해 개입할 인터셉터 등록
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/users/*","/gallery/*","/cafe/*","/file/*", "/music/*")
.excludePathPatterns("/users/signup_form", "/users/signup", "/users/loginform", "/users/login",
"/gallery/list", "/gallery/detail",
"/cafe/list","cafe/detail","/cafe/ajax_comment_list",
"/file/list","/file/download");
//모바일 요청에 대해 개입할 인터셉터 등록
registry.addInterceptor(mLoginInterceptor)
.addPathPatterns("/api/gallery/*");
}
// resources 폴더안에 있는 자원을 spring 컨트롤러를 거치지 않고 응답되도록 설정
// webapp 안에 resources 폴더를 만들어야 한다.
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}
- 어떤 요청에 대해서 interceptor를 동작하게 할 것인지!
- "/music/*" : music 폴더 하위의 모든 요청에 대해서 interceptor 를 사용하겠다는 의미.
MusicController
package com.sy.boot07.music.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import com.sy.boot07.music.dto.MusicDto;
import com.sy.boot07.music.service.MusicService;
@Controller
public class MusicController {
@Autowired MusicService service;
//음악파일 업로드 폼 요청 처리
@RequestMapping("/music/insertform")
public String insertForm() {
return "music/insertform";
}
//음악파일 업로드 요청처리
@RequestMapping("/music/insert")
public String insert(MultipartFile file, HttpServletRequest request) {
service.saveFile(file, request);
return "redirect:/music/list";
}
//음악파일 목록 요청처리
@RequestMapping("/music/list")
public ModelAndView list(ModelAndView mView, HttpSession session) {
service.getList(mView, session);
mView.setViewName("music/list");
return mView;
}
/*
* get 방식 파라미터로 전달되는 num에 해당하는 음악 하나의 정보를 json 형식의 문자열로 응답하는 컨트롤러 메소드
* {"writer":"xxx", "title":"xxx", "saveFileName":"xxx", .... }
*/
@RequestMapping("/music/detail")
@ResponseBody
public MusicDto checkDetail(int num, HttpServletRequest request) {
return service.getDetail(num);
}
@GetMapping("/music/delete")
public String checkDelete(int num, HttpServletRequest request) {
service.deleteFile(num, request);
return "redirect:/music/list";
}
}

- 컨트롤러에서 리턴한 ModelAndview를 서비스에 전달한다.
- service, dao 에 메소드를 만들어 주어야 한다.
MusicDao
package com.sy.boot07.music.dao;
import java.util.List;
import com.sy.boot07.music.dto.MusicDto;
public interface MusicDao {
public void insert(MusicDto dto);
public List<MusicDto> getList(String id);
public MusicDto getData(int num);
public void delete(int num);
}
MusicDaoImpl
package com.sy.boot07.music.dao;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.sy.boot07.music.dto.MusicDto;
@Repository
public class MusicDaoImpl implements MusicDao {
@Autowired SqlSession session;
@Override
public void insert(MusicDto dto) {
/*
* mapper's namespace => music
* sql's id => insert
* parameter type => MusicDto
*/
session.insert("music.insert", dto);
}
@Override
public List<MusicDto> getList(String id) {
/*
* parameter type => String
* result type => MusicDto
*/
return session.selectList("music.getList", id); //session을 통해서selelct한 메소드를보내주는
}
@Override
public MusicDto getData(int num) {
/*
* parameterType => int
* resultType => MusicDto
*/
return session.selectOne("music.getData", num);
}
@Override
public void delete(int num) {
session.delete("music.delete", num);
}
}
MusicService
package com.sy.boot07.music.service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import com.sy.boot07.music.dto.MusicDto;
public interface MusicService {
public void saveFile(MultipartFile file, HttpServletRequest request);
public void getList(ModelAndView mView, HttpSession session);
public MusicDto getDetail(int num);
public void deleteFile(int num, HttpServletRequest request);
}
MusicServiceImpl
package com.sy.boot07.music.service;
import java.io.File;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.mp3.MP3File;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.id3.AbstractID3Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import com.sy.boot07.music.dao.MusicDao;
import com.sy.boot07.music.dto.MusicDto;
@Service
public class MusicServiceImpl implements MusicService {
@Autowired MusicDao dao;
@Override
public void saveFile(MultipartFile file, HttpServletRequest request) {
//업로드한 음악파일의 정보를 담을 dto 객체 생성
MusicDto dto=new MusicDto();
//업로드한 클라이언트의 아이디(=writer)
String id=(String)request.getSession().getAttribute("id");
dto.setWriter("banana");
//원본 파일명 -> 저장할 파일 이름 만들기위해서 사용됨
String orgFileName = file.getOriginalFilename();
dto.setOrgFileName(orgFileName);
//파일 크기 -> 다운로드가 없으므로, 여기서는 필요 없다.
long fileSize = file.getSize();
// webapp/upload 폴더 까지의 실제 경로(서버의 파일 시스템 상에서의 경로)
String realPath = request.getServletContext().getRealPath("/resources/upload");
//db 에 저장할 저장할 파일의 상세 경로
String filePath = realPath + File.separator;
//디렉토리를 만들 파일 객체 생성
File upload = new File(filePath);
if(!upload.exists()) {
//만약 디렉토리가 존재하지X
upload.mkdir();//폴더 생성
}
//저장할 파일의 이름을 구성한다. -> 우리가 직접 구성해줘야한다.
String saveFileName = System.currentTimeMillis() + orgFileName;
dto.setSaveFileName(saveFileName);
try {
File mp3File=new File(filePath + saveFileName);
//upload 폴더에 파일을 저장한다.
file.transferTo(mp3File);
//mp3 파일에서 meta data 추출하기
MP3File mp3=(MP3File)AudioFileIO.read(mp3File);
//AbstractID3Tag aTag=mp3.getID3v2Tag();
Tag tag=mp3.getTag();
//제목
String title=tag.getFirst(FieldKey.TITLE);
//만일 제목 정보가 없으면
if(title==null) {
//원본 파일명을 제목으로 설정
title=orgFileName;
}
dto.setTitle(title);
//artist
String artist=tag.getFirst(FieldKey.ARTIST);
//만일 아티스트 정보가 없으면
if(artist==null) {
artist="정보없음";
}
dto.setArtist(artist);
}catch(Exception e) {
e.printStackTrace();
}
//DB에 저장
dao.insert(dto);
}
@Override
public void getList(ModelAndView mView, HttpSession session) {
//로그인된 아이디
String id=(String)session.getAttribute("id");
//아이디를 이용해서 로그인된 클라이언트가 업로드한 음악 파일 목록만 얻어낸다.
List<MusicDto> list=dao.getList(id);
//ModelAndView 객체에 담기
mView.addObject("list", list);
}
@Override
public MusicDto getDetail(int num) {
return dao.getData(num);
}
@Override
public void deleteFile(int num, HttpServletRequest request) {
//삭제할 파일의 정보를 읽어온다.
MusicDto dto=dao.getData(num);
//1. 파일 시스템에서 삭제 (삭제할 파일을 가리키는 파일 객체가 필요하다)
// webapp/upload 폴더 까지의 실제 경로(서버의 파일 시스템 상에서의 경로)
String realPath = request.getServletContext().getRealPath("/resources/upload");
//db 에 저장할 저장할 파일의 상세 경로
String filePath = realPath + File.separator;
//파일 객체를 생성해서
File f=new File(filePath);
//메소드를 이송해서 삭제
f.delete();
//2. DB에서도 삭제
dao.delete(num);
}
}
public void getList(ModelAndView mView, HttpSession session);
- 세션에 들어간 id를 추출해서 사용해야 하므로 session을 인자로 받아준다.(로그인 여부 확인)

- 세션에서는 인터페이스 타입을 받아와서 사용한다.

- Dao 에서 로그인된 아이디를 사용해서 select 해오기 때문에 Mapper에 패러미터타입이 생기는 것이다.

- DaoImpl 에서 메소드를 수정해주기
- 이 메소드를 보고 패러미터타입, 결과타입을 한눈에 알수있도록 익혀야 한다.

- 본인이 업로드한 mp3 파일의 목록만 셀렉트한다.
- 패러미터타입은 string(대,소문자 무관) 으로만 적어도 되지만, 더 확실하게 패키지명까지 적어줌

- ServiceImpl의 메소드 수정
- mView에 만들어진 리스트를 담아준다. list라는 키값으로 읽어와 사용할 수 있도록!
list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>/music/list.jsp</title>
</head>
<body>
<div class="container">
<h3>${sessionScope.id} 님의 음악 파일 목록입니다.</h3>
<h4>선택한 곡: <i id="selectedSong"></i></h4>
<audio id="myAudio" controls></audio>
<table>
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>아티스트</th>
<th>파일명</th>
<th>업로드일자</th>
<th>삭제</th>
</tr>
</thead>
<tbody>
<c:forEach var="tmp" items="${list }">
<tr>
<td>${tmp.num}</td>
<td>${tmp.title}</td>
<td>${tmp.artist }</td>
<td><a href="javascript:loadMusic(${tmp.num})">${tmp.orgFileName }</a></td>
<td>${tmp.regdate }</td>
<td>
<a href="delete?num=${tmp.num}">삭제</a>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<script>
function loadMusic(num){
//num에 해당하는 음악 정보를 서버에서 받아온다(페이지 전환 없이)
fetch("${pageContext.request.contextPath}/music/detail?num="+num)
.then((res)=>{
//json 문자열을 서버에서 응답하기 때문에 res.json() 을 리턴하면
return res.json();
})
.then((data)=>{
//data는 json 문자열에서 javascript 객체로 변환된 값이다.
document.querySelector("#selectedSong").innerText=data.title;
//로딩할 음원의 src 구성하기
const src="${pageContext.request.contextPath}/resources/upload/"+data.saveFileName;
//구성된 src를 audio 요소의 src에 부여하고 로딩하기
const myAudio=document.querySelector("#myAudio");
myAudio.setAttribute("src", src);
myAudio.load();
});
}
</script>
</body>
</html>

- 여기서 sessionScope, requestScope 는 생략 가능하다.
- session, request에 저장된 값을 EL로 간단하게 읽어오는 것!

- 이것은 JSTL을 사용한 서버 사이드 렌더링이다.
서버에서 완성된 상태의 데이터(html 형식)를 보내주는 것을 말한다.
- 클라이언트 사이드 렌더링으로 하고싶다면 정보를 json으로 전달하고 화면에서 ajax로 요청해서 받아 사용한다.
이것은 서버에서는 최소한의 html 요소만 전달하고 웹브라우저에서 화면을 조립해서 보여주는 방식이다. (vue, react)

- ${list} 로 리스트를 출력하기. Service에서 만들어진 이 list를 가리킨다.
- 제너릭이 MusicDto이므로 tmp는 MusicDto 타입이다.

- 이렇게 목록이 출력된다. 본인이 업로드한 음악의 목록만 출력됨!
- 이 파일을 클릭하면 재생할 수 있도록 만들기
- 원본 파일명이 아니라 저장된 파일명을 알아야 재생이 가능하다.

- 윗부분에 <audio> 요소 추가

- 이 src에 불러올 mp3 파일의 경로가 들어가야 하는데,
src 속성의 value는 특정 곡을 클릭할 때마다 달라져야 한다.
- 곡마다 하나씩 다른 링크를 가져다놓기.
- 동적 로딩이 이루어지도록 해야 한다.

- 클릭시 실행될 javascript 코드를 추가해준다. 이 링크를 누르면 오디오가 재생 준비를 하도록 하기!!
- 파일명을 클릭하면 javascript가 실행되도록. 아래에서 함수를 준비해준다

- 각각의 링크를 클릭할때 들어가는 값의 내용이 달라져야 한다!
- 같은 함수를 사용하므로, 이 함수에 전달되는 값이 달라져야 한다.

- javascript에 매개변수를 선언해주면 매개변수에 저 값이 들어온다.
- javascript 에서는 페이지 전환 없이 이 정보를 서버에서 정보를 받아온다.

- fetch 사용해주기
- num이라는 파라미터로 전달된 것을 json으로 응답하면 웹브라우저에서 바로 받아올 수 있다.
Controller

- dto를 응답하게되면 위와 같이 json으로 바뀌어서 응답된다.
Service

- 번호를 넘겨주면 MusicDto를 리턴해주는 메소드 추가!
Dao

- 값을 읽어오는 메소드. 번호를 이용한 select 문이 필요하다.

- selectList일 때 => <> 제너릭타입이 리턴타입
- selectOne일 때 => resultType이 리턴타입이 된다.
MusicMapper
<?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="music">
<insert id="insert" parameterType="musicDto">
INSERT INTO board_music
(num, writer, title, artist, orgFileName, saveFileName, regdate)
VALUES(board_music_seq.NEXTVAL, #{writer}, #{title}, #{artist},
#{orgFileName}, #{saveFileName}, SYSDATE)
</insert>
<select id="getList" parameterType="java.lang.String" resultType="musicDto">
SELECT num, writer, title, artist, orgFileName, saveFileName, regdate
FROM board_music
WHERE writer = #{id}
ORDER BY num DESC
</select>
<select id="getData" parameterType="int" resultType="musicDto">
SELECT num, writer, title, artist, orgFileName, saveFileName, regdate
FROM board_music
WHERE num = #{num}
</select>
<delete id="delete" parameterType="int">
DELETE FROM board_music
WHERE num=#{num}
</delete>
</mapper>

Mapper
- 각각 저 내용이 MusicDto 안에 담긴다.
- 위에것은 selectList, 밑에것은 selectOne으로 사용한다는 차이가 있을 뿐!

- 이렇게 주소창에 직접 경로를 작성해 보면 곡에 대한 정보가 json으로 넘어오는 것을 확인할 수 있다.
- 그런데 metadata 정보가 없어서 null인 경우에는 그냥 안보이므로... 뭔가 처리를 해주면 편하지 않을까?

- 타이틀이 null 이면 원본 파일명을 제목으로 구성하기!
- serviceImpl에서 이렇게 작업해준다.
- 제목이 없으면 파일명을 제목으로, 아티스트 정보가 없으면 '정보없음' 으로 나오도록! null인 경우를 대비하기

- json형식의 문자열을 웹브라우저의 fetch를 통해서 받으면 data 가 들어온다.
- 이 data 는 js에서 바로 사용할 수 있는 object 타입이다.
- json이 아니면 res.text() 으로 리턴받아 사용할 수 있고,
json타입이면 res.json() 으로 불러오면 자동으로 object 객체로 변환된 값이 리턴된다.
- res.json을 호출하면서 리턴하면 자동으로 object로 바뀐다.

- <i> 는 이탤릭체를 출력할때 사용하는 태그

서버에서 값 읽어와서 id가 "selectedSong" 으로 지정된 요소에 넣어주기

- 이렇게 title 부분이 i 요소의 innerText로 출력되도록 만들 수 있다.
- 재생되려면 src 속성의 value를 동적으로 만들어줄 필요가 있다.

- 저장된 파일명을 여기에 넣어주고

- 오디오 요소를 자바스크립트로 제어하기
- 저장된 파일명만 알면 자유롭게 구성할 수 있다.

- 페이지 전환없이 바로 로딩해서 사용할 수 있다.
- 원한다면 컨트롤러 없이도 만들 수 있다.

- 검사 창에서 이런 형태로 참조해서 제어할 수 있다.
- 현재 재생시간, 전체 재생시간 등을 읽어내기도 가능하고, 재생위치 조정, 볼륨 조절 등도 가능하다.
<audio id="myAudio" controls></audio>
- 이 오디오 요소에서 controls 를 빼면 화면에 저 컨트롤러는 나오지 않는다.
- 하지만 검사창의 제어방식과 같은 방식으로 자신만의 플레이어를 만들어 사용할 수도 있다.
- 앨범 썸네일 이미지 추출해서 보여주기 등... 새로운 기능 추가 가능
(안드로이드에서 해볼 것! 안드로이드는 MediaPlayer의 메타데이터 기능을 사용해서 별도의 라이브러리 없이 데이터 추출가능)
- 이제 여기 있는 정보를 안드로이드에서 받아가서 재생하도록 할 예정!
- 음악 파일 삭제하기

- 파일 삭제기능 추가

- DB에 저장된 파일 번호(num값)를 이용해서 삭제하고, list로 리다이렉트 이동하도록 한다.
- 삭제는? DB에서 삭제 + 파일 시스템에서 삭제 하도록 해야한다.
dao

- parameter type => int
- mapper 이름 => delete

- 경로 뒤에다가 저장된 파일명을 붙여주면 된다.
- 파일 객체를 생성해서 파일 위치(filePath)를 생성자의 인자로 넣어주면 된다.

- 파일 삭제에 request 값이 필요하므로(본인만 삭제가능) 메소드를 request 를 받는 구조로 바꾸어주기
- 파일 삭제와 db삭제를 같이 진행하기!

- 삭제 버튼이 생성되었다. 클릭하면 파일이 삭제되고 list로 리다이렉트 된다.

- 삭제, 자세히보기 요청을 할 때, 이 요청url 정보를 알면 다른 사람이 삭제할 수도 있다.
- 이런 시도를 막으려면 확인작업이 필요하다
- session에 저장된 아이디 값을 읽어와서 같은 경우에만 삭제할 수 있도록
→ AOP를 활용한다. 별도로 분리해서 개입하게 하면 코드가 지저분해지지 않는다.
- Exception Controller에서 에러 페이지를 응답하게 할 수 있다.

- 이전에 Boot02 에서 AOP를 사용했던 예제!
- AOP를 사용해서 메소드가 실행되는 중간에 개입해서 통과시키거나 or 특정 시점에 메소드를 멈추거나or 임의로 exception을 발생시켰다.

- AOP용 라이브러리 추가와 JavaConfig 작업이 필요하다
- com.sy.boot07.aop 패키지 생성

pom.xml에 라이브러리 추가하기
<!-- AOP 용 추가 라이브러리 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.0</version>
</dependency>
MusicAspect 클래스 생성
package com.sy.boot07.aop;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.sy.boot07.music.dao.MusicDao;
@Aspect
@Component
public class MusicAspect {
@Autowired MusicDao dao;
/*
* com.sy.boot07.music.controller.MusicController 클래스의
* check로 시작되는 모든 메소드가 point cut이 된다.
*/
@Around("execution(com.sy.boot07.music.controller.MusicController.check*(..))")
public Object checkWriter(ProceedingJoinPoint joinPoint) throws Throwable {
//메소드에 전달된 인자들 목록을 얻어내기
Object[] args=joinPoint.getArgs();
int num=0;
HttpServletRequest request=null;
//반복문 돌면서 원하는 type 의 값을 찾아서 작업한다.
for(Object tmp:args) {
//만일 Integer type 이면
if(tmp instanceof Integer) {
//casting 해서 담는다.
num=(int)tmp;
}
if(tmp instanceof HttpServletRequest) {
request=(HttpServletRequest)tmp;
}
}
//mp3 파일의 소유자 알아내기
String writer=dao.getData(num).getWriter();
//로그인된 아이디
HttpSession session=request.getSession();
String id = (String)session.getAttribute("id");
//만일 mp3파일의 소유자와 로그인된 아이디가 다르다면
if(writer!=id) {
//예외를 발생시켜서 ExceptionController에서 처리되도록 한다.
}
//aspect 가 적용된 메소드가 호출 되기 직전에 할 작업은 여기서 한다.
Object obj=joinPoint.proceed();
return obj;
}
}
- @Aspect, @Around 어노테이션을 사용할 예정

- aspect 를 적용할 메소드의 이름을 check로 시작하게 바꿔준다.(편하게 적용하기 위해)
- 메소드명은 check로 시작하고 인자는 request를 받아오도록 설정

MusicController.check*(..)
- MusicController 안에 있는 check로 시작하는 모든 메소드에 적용하겠다!! 는 의미
- 2개의 메소드가 여기에 부합한다.
- XX* -> XX로 시작하는 모든 메소드!
- (..) 은 인자가 없든 있든 두개든 상관없다는 뜻이다.

- Aspect가 controller에 개입해서 int, request 값을 얻어낼 수 있다.
- 정보를 얻어내고 DB를 뒤져서 로그인한 사용자와 같은지 확인할 수 있다.

- autowired로 dao를 주입받아서 얻어내서 이 메소드 안에서 활용한다.

- proceed() 에서 발생하는 exception은 throw 해주었다.
- object 배열[ ] args 안에 int, HttpServletRequest의 내용이 담겨있다.
ex) num에는 1이, request에는 참조값 40이 담겨있다고 치면
Object[ ] args = { 1, id40 } 이 들어있다. 이 내용이 담겨있는 object 배열인 것이다.
- 메소드에 전달된 인자들을 object 배열로 받아올 수 있다.
- 여기 있는 인자들은 여러개일 수 있고 타입도 다양할 수 있다.
그래서 반복문을 돌면서 빼내서 원하는 타입을 찾아내는 것이다.
- 인자 object의 목록을 반복문 돌면서 찾아낸다.

- 아래 if문에서 int 타입과 HttpServletRequest 타입을 찾는다.
- 정수를 찾아야 하므로 Integer 클래스 타입으로 바꾸어준다.

- 찾아서 num, request 안에 집어넣어 주면 된다.
- 이 찾은 tmp은 object type 으로 간주되고 있으므로 원래 타입으로 캐스팅해준다.
- 이 if문 부분이 수행되고 나면 num, request 변수에는 값이 들어가 있을 것이다. 이 변수들을 사용해서 작업한다.

- mp3파일의 소유자 알아내기 (번호로 해당 데이터를 읽어와서 그 데이터의 작성자 읽어오기)
- 로그인된 아이디정보가 필요하므로 httpsession 객체 생성, getAttribute로 알아내기

- mp3파일의 소유자와 아이디가 다르면 안된다.
- writer와 id를 비교해서 다를 경우에는 개입하고, 아니면 넘어가기

- joinPoint.proceed() 에서 리턴해주는 객체는 MusicDto 일 수도 있고 String 일 수도 있다.
- 이 값이 위의 obj에 리턴된다. object타입으로 받을 수 있다.
- joinPoint.proceed() 가 리턴해주는 값은 Aspect가 적용된 저 메소드가 리턴한 값이다.
- 소유자와 아이디가 다를 경우, if문 안에서 의도적으로 예외를 발생시킨다. (정상적인 처리가 되지 않도록 한다)
- ExceptionController 안에서 처리되도록 한다. 또는 커스텀 Exception에서 처리할 수도 있다.
'국비교육(22-23)' 카테고리의 다른 글
93일차(2)/Android App(57) : mp3 파일 재생 예제 / 로그인 기능 구현 (0) | 2023.02.21 |
---|---|
93일차(1)/Spring Boot(16) : Custom Exception 활용 예제 (0) | 2023.02.20 |
90일차(2)/Spring Boot(14) : mp3 파일 업로드, metadata 추출 (0) | 2023.02.17 |
90일차(1)/Android App(56) : mp3 파일 재생 예제 / 재생목록 출력(ListView) (0) | 2023.02.16 |
89일차(1)/Android App(55) : mp3 파일 재생 예제 / Notification(3) (0) | 2023.02.16 |