서버 구축 이후에 FTP로 문제가 많았다. 그 중 하나가 FTP Write가 안된다.

 

550 Permission denied. 뭐 대충 에러 메시지 보니깐 권한 없다고 나온다. 이럴 경우 폴더에 대한 쓰기 권한이 없거나 FTP 자체 쓰기 권한이 없거나 둘 중 하나 같다.

 

그래서 이전에 폴더 권한 문제를 봤으니 이번에는 FTP 쓰기 권한을 봐야될 것 같다.

 

먼저 vsftpd.conf 파일을 들여다 보자 기본적으로 시스템 파일은 root 권한을 사용해야 한다. 안 그러면 수정이 안된다.

sudo vi /etc/vsftpd.conf  

 

그러면 많은 주석 중 #write enable=YES 이게 있을 것이다. 가볍게 주석을 해제해주자

 

그리고 서비스 재시작하면 내 경우는 바로 쓰기가 가능했다.

sudo /etc/init.d/vsftpd restart

그리고 회사 AWS EC2 백업 도중 파일을 업로드 해야되는 경우가 생겼다. 그래서 올리는데 에러가 발생한다.

open for write: permission denied

현재 유저는 해당 폴더에 쓰기 권한이 없다는 에러다. 간단하게 명령어로 권한을 주면 된다.

sudo chmod -R 777 /var/www/html

 

급하게 회사에서 외주 프로젝트가 들어왔다. 한번쯤은 스프링으로 해보는 것도 나쁘지 않다고 생각했는데... 너무 두렵다... 아무튼 예전에 egov랑 스프링을 조금 해본 정도로 프로젝트를 진행한다. 개념은 아예 없기 때문에 블로그 쓰면서 스터디 하면서 정리할 예정이다. 너무 쉽게 생각했다...

 

IDE

우선 IDE인데 이클립스를 하려고 했는데 나의 상황이 사용중인 IDE가 안드로이드 스튜디오(안드로이드), VS Code(Node.js) 인데 스프링 하려고 이클립스까지 쓰면 IDE는 총 3개 사용하는 것이다. 아마 PC 바꾸면 대참사가 날 것이다. 그래서 IntelliJ IDE를 사용해보려고 한다. 아마 자기가 학생이면 잘 모를수도 있다.  IntelliJ도 학생은 무료로 사용할 수 있다. 그렇기 때문에 한번 쯤 써보는 것도 좋다. 굉장히 많은 툴들을 지원하고 JAVA, PHP, Node.js, Android...등 많은 언어들을 지원하기 때문에 나로썬 써보는 게 좋다고 생각했다. 그래서 대부분 IDE를 IntelliJ로 진행해보려한다.

 

프로젝트 세팅은 스프링 페이지에서 만들어서 IDE에 Import하는 방법과 IDE에서 생성하는 방법이 있다. 물론 두 방법 다 과정은 같기 때문에 IDE에서 생성해보려고 한다.

 

1. New > project > New Project 에서 왼쪽 탭에 Spring Initalizr을 누르면 위 이미지처럼 나온다. 물론 탭에 없다면 맨 아래 Empty Project에서 찾아보기 바란다...

2. 스프링 프로젝트의 세팅 - Group과 Artifact, package name 등을 입력하고 빌드도구랑 언어는 우선은 Maven, Java를 선택

패키징은 Jar와 War중 선택이 가능한데 Jar를 선택하면 스프링부트 내장톰캣(Embeded Tomcat)을 사용하여 Stand Alone으로 WAS를 구동시키고. 외부 WAS에 Deploy해서 사용하는 환경이시라면 War를 선택하여 내보내면 된단다...


3. Next를 눌러서 다음으로 DI 세팅이다. 내가 필요한 DI를 선택하면 빌드에 자동으로 항목이 추가되고 리포지토리에서 내려받아진다. 물론 나중에 따로 추가도 가능하다.

4. Finish를 누르면 끝난다. 생성된 스프링부트 프로젝트의 구조인데 주요 파일로는 스프링부트 컨테이너를 실행시키기 위한 src폴더내의 main가 있고 resources 폴더에는 web을 선택했기 때문에 html, css, js 등의 정적 컨텐츠가 위치할 static 폴더가 자동으로 생성됐으며 여러가지 설정 정보를 위한 application.properties 파일도 생성됐다. 

 

5. 우선 국룰을 통해서 프로젝트를 만들었으면 실행을 해야한다고 생각한다. 이클립스 자바 할 때처럼 Run을 해보자...당연히 바로 안된다. 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-06-25 16:08:48.400 ERROR 238940 --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class


Action:

Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).


Process finished with exit code 0

 

뭐라고 주절주절 하는데 아래 Action: 을 보면 뭐라 써있다. 대충 읽어보면 아까 DI 세팅할 때 DB를 같이 추가 했는데 DB에 대한 기본 설정을 하지 않아 발생한 문제다.

2가지 방법으로 해결했다. 

 

 

5-1 application.properties에 DB 세팅을 해준다. 자신의 설정에 맞게 해주면 된다.

5-2 우선 어노테이션을 통해 Auto Configuration에서 DataSource 관련 설정 로드를 WAS 구동시 하지 않도록 exclude하는 방법이 있다.

@SpringBootApplication(exclude={DataSourceAutoConfiguration.class}) (붙여서 하면 자꾸 클래스 부분이 주석처리 되어 에러나니깐 @SpringBootApplication을 엔터 몇번 치고 복붙하자)

6. 그러면 이제 세팅이 완료 됐으면 빌드 후 다시 실행해보면 정상적으로 작동한다. 맨 아래 Started DemoApplication in 2.162 seconds (JVM running for 3.37) 나온다면 정상 작동을 한 것이다. 

7. 그럼 정말 정상 작동하는지 브라우저에서 확인을 해봐야 하지 않나... 우선 index.html을 간단하게 만들어서 테스트해보자.

리소스 정적 폴더에 index.html을 만들면 바로 intellij에서는 해당하는 html 파일을 바로 브라우저를 킬 수 있게 되어 있지만 브라우저에서 https://localhost:8080에 접속하면 index.html에 작성한 페이지가 나온다. 물론 internet explorer은 https가 안된다. 주의하자!

 

 

'IT > Spring' 카테고리의 다른 글

[Spring Boot] 파일 업로드 / 다운로드 REST API  (0) 2021.07.13
[Spring] Spring Framework 이클립스 세팅  (0) 2021.06.03

이 포스팅에선 postman을 이용하여 업로드를 진행할 것이다. 추후에 안드로이드 어플을 통해서 업로드 Client 부분을 작성할 예정이며 작성하면 이 글을 수정하여 링크를 달아놓을 예정이다.

 

우선 파일을 업로드하여 서버 upload라는 폴더 안에 저장할 것이고, DB에 파일에 대한 정보를 넣을 생각이다. 이 이유는 맨 아래에 남겨놨다.

 

우선 NPM 에서 사용하는 기본 예제다.

var express = require('express')
var multer  = require('multer')
var upload = multer({ dest: 'uploads/' })
 
var app = express()
 
app.post('/profile', upload.single('avatar'), function (req, res, next) {
  // req.file is the `avatar` file
  // req.body will hold the text fields, if there were any
})
 
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
  // req.files is array of `photos` files
  // req.body will contain the text fields, if there were any
})
 
var cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', cpUpload, function (req, res, next) {
  // req.files is an object (String -> Array) where fieldname is the key, and the value is array of files
  //
  // e.g.
  //  req.files['avatar'][0] -> File
  //  req.files['gallery'] -> Array
  //
  // req.body will contain the text fields, if there were any
})

코드에서 보면 알 수 있듯이 upload할 때 속성이 다르다. 

.single(fieldname)

이름을 가진 단일 파일을 허용합니다 fieldname. 단일 파일은 req.file. 로 사용하면 된다.

.array(fieldname[, maxCount])

이름이 모두 인 파일 배열을 허용합니다 fieldname. 둘 이상의 maxCount파일이 업로드 되면 선택적으로 오류가 발생합니다 . 파일 배열은 req.files. 로 사용하면 된다.

.fields(fields)

fields 파라미터로 넘어오는 것들을 배열 형태로 저장된다. 파일은 req.files로 사용하면 된다.

 

 

 

NPM에 나와있는 각 파일 정보다.

multer(opts)

업로드된 파일을 Multer에게 어디로 업로드할 지 알려주며 옵션 객체를 하지않았다면 메모리에 저장된다. 보통은 dest 옵션으로 파일 저장 위치를 지정하는데 더 자세하게 제어하고 싶으면 storage를 사용하면 된다.

var  upload  = multer ( {  dest : ' uploads / ' } ) 

 

storage

DiskStorage

말 그대로 로컬 디스크에 저장한다는 의미이며 두 가지 옵션을 사용할 수 있다. 

1. destnation : 파일의 목적지 즉 경로를 설정 할 수 있다.

2. filename : 파일 이름을 설정 할 수 있다. 아래 코드에서 보면 알 수 있듯이 Date.now()가 들어 갔는데 타임스태프를 넣은 이유가 파일 이름이 겹칠 수 있기 때문이라고 생각해두면 될 것 같다.

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, '/tmp/my-uploads')
  },
  filename: function (req, file, cb) {
    cb(null, file.fieldname + '-' + Date.now())
  }
})
 
var upload = multer({ storage: storage })

 

MemoryStorage

메모리 스토리지 엔진은 파일을 메모리에 Buffer개체 로 저장 합니다. 옵션이 없습니다.

var storage = multer.memoryStorage()
var upload = multer({ storage: storage })

 

 

파일 정보를 DB에 저장해둬야 할 필요가 있다. 왜냐면 파일을 다운 받을 경우 자신이 업로드한 파일을 정확하게 받을 수 있다. 그리고 파일 이름은 한글로 넣을 경우 깨지는 경우가 발생했다. UTF-8 등 ... 인코딩 많은걸 해봤지만 안됐다. 나중에 듣기론 이런 경우가 많아 파일 오리지널 이름을 같이 업로드하여 DB에 넣어둔 뒤 다운로드 할 시 DB에서 파일 이름을 꺼내와 다시 붙여주는 걸로 알고 있다. 물론 파일 리스트 조회 할 시도 DB에서 파일 오리지널 이름을 가져와 Client로 넘겨준다.

비동기 다음으로 exports라는 개념이 발목을 잡았다.

지금까지C나 JAVA에서는 include나 import를 하면 그 클래스나 함수, 변수들을 사용할 수 있었다. Node에선 require를 해도 그 변수나 함수를 사용하지 못했다. 

 

Node에서는 모듈에서 exports를 하지 않으면 그 변수나 함수를 사용하지 못하는 것이다.

 

구글링으로 알아본 결과 A라는 모듈을 require를 하면 해당 모듈의 module.exports를 return 한다고 보면 되는 것이다. 그러므로 A모듈에서 module.exports를 하지 않았다면 그 어떤 것도 참조할 수 가 없다.

 

아무튼 본론으로 넘어와서 module.exports를 사용함에 많은 방법이 있었다.

 

우선 module.exports와 exports가 있다. 이 둘의 차이점... 사실 없었다. 공식 문서를 보면 그저 module.exports의 더 짧은 버전... 즉 module 조차도 길었다고 생각했나보다... 아무튼 둘의 차이점은 성능이 아닌 그저 더 짧다는 것에 있다.

exports

Added in: v0.1.12

A reference to the module.exports that is shorter to type. See the section about the exports shortcut for details on when to use exports and when to use module.exports.

 

그렇다면 어떻게 사용하면 되는건가... 여기부터는 솔직히 쓰는 사람의 특성과 그 모듈의 특성에 따라 나뉘는 듯 하다.

 

아래 예를 들어 코드를 작성해봤다. 기호에 맞게 사용하면 될듯하다.

exports.func = function (){console.log('func')}

exports = {func:func}   // 이 경우 따로 func 함수가 정의가 되어 있어야함.

exports = { func : function (){ console.log('func') } }

exports.a = b

 

오랜만에 이클립스 설치하고 JDK 다시 설치하고 하니깐 여간 귀찮다... 스프링도 세팅을 빨리 하고 좀 스터디해서 스프링에 대한것도 올려야겠다.

 

우선 이클립스 키면 스프링을 프로젝트를 생성할 수 없다. 그렇기 때문에 스프링을 추가해줘야한다. 

대부분에 이클립스 플러그인이나 툴들을 Eclipse Marketplace 에서 받으면 편하게 적용할 수 있다.

Help > Eclipse Marketplace 들어와서 스프링을 찾아주면된다.

설치됐는지 확인을 해보면 프로젝트 생성할 때 스프링이 있는지 확인하면 된다.

대학교 이후로는 이클립스를 처음 써본다... 안드로이드도 예전에는 이클립스를 이용했지만 지금은 분리되어 더더욱 쓸일이 없었고 왠만한건 다 VSCODE를 사용하기 때문에 쓸 일이 없었다. 갑자기 스프링을 하게 되어서 급하게 설치를 하는데 그냥 남겨봤다. 이런건 패스해도 되는데...

 

이클립스 홈페이지에서 주황색 다운로드를 누르면 된다.

그러면 exe 파일이 다운이 되면서 실행하면 된다. 실행을 하면 아래 그림 처럼 나올것이다.

우선 첫번째 Eclipse IDE for Java Developers 는 단순히 자바만 사용하는 개발자의 IDE 타입입니다. 그러나 저는 스프링을 사용해야해서 두번째꺼 Eclipse IDE for Enterprise Java and Web Developers 선택을 합니다. 

 

이 다음부터는 설치 위치나 JDK 위치경로 정도만 설정하고 설치하면 됩니다.

 

설치가 다 되면 혹시나 한글이 깨질 걸 생각에서 인코딩만 해보자.

 

메뉴에서 Window > Preferences > general > workspace 로 들어가면 하단에 Text file encoding 을 Other : UTF-8로 바꾼다.

그 다음으로 General > Editors > Text Editors > Spelling 에서 하단에 Encoding 을 Other : UTF-8로 바꿔준다.

고작 같은 명령어인데 왤캐 많은지 이해 안가는 중... 시스템 재시작하거나 종료하는 명령어는 ROOT 권한자만 가능하다.  대충 4개정도로 정리할 수 있다.

shutdown

기본 문법

 # shutdown 옵션 시간 (메세지)

옵션을 쓰지 않으면 기본 디폴트가 종료다. 

옵션 내용
-r 재시작
-h 종료
-c 명령 취소
#shutdown -r now   // 즉시 재시작
#shutdown -h now   // 즉시 종료
#shutdown -c       // 예약된 명령어 취소

#shutdown -r 5     // 5분 뒤 재시작
#shutdown -r 22:55 // 22:55에 시스템 재시작

 

reboot

단어에서 딱 느낌이 오듯이 재시작이라는 뜻이지만 옵션으로 종료를 할 수 있다.

문법

# reboot 옵션

옵션 내용
-p poweroff의 약자로 종료
-f 시스템 강제 재부팅

 

halt, poweroff, init 0

마찬가지로 다 종료 다.

# halt
# poweroff
# init 0

init은 시스템의 런레벨을 0으로 변경함으로써 종료시킨다.

런레벨 6은 재부팅이다.

 

참고. 로그아웃

# logout
# exit

 

혹시 이미 jdk 가 있을 수 있으니 기존의 jdk를 먼저 삭제한다.

$ sudo apt-get remove openjdk*
$ sudo apt-get remove oracle*
$ sudo apt-get autoremove --purge 
$ sudo apt-get autoclean

JDK를 처음 설치하는거라면 굳이 할 필요 없다. 

 

다음으로 apt 업데이트를 한다.

$ sudo apt-get update && sudo apt-get upgrade

그리고 나도 한번 에러가 발생했었다. 11 버전부터 사람들이 갈린다.

해외도 마찬가지긴 했는데 나는 서버 4대 설치하는거라서 다 해봤는데 다 잘된다.

 

간혹 어떤사람은 PPA Repository에 openJDK를 추가하고 설치하는경우가 있다.

20.04 버전에서는 추가하지 않아도 설치가 됐다.

$ sudo apt-get install openjdk-11-jdk

설치가 완료가 되면 완료가 정말 됐는지 확인할 수 있다.

$ java -version
openjdk version "11.0.11" 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing)

$ javac -version
javac 11.0.11

환경설정이다. JAVA_HOME 시스템 변수 설정을 해야한다면 ~/.bashrc 파일에 변수들을 추가해주면 된다.

$ vim ~/.bashrc
export JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))
export PATH=$PATH:$JAVA_HOME/bin

추가 했으면 현재 변경한 설정을 적용해야한다.

$ source ~/.bashrc

이제는 JAVA_HOME이 잘 설정 되었는지 아래 명령어로 확인해보자

$ echo $JAVA_HOME
/usr/lib/jvm/java-11-openjdk-amd64

 

혹시 JRE만 설치하고 싶다면 아래 명령어로 설치할 수 있다.

$ sudo apt-get install openjdk-11-jre

+ Recent posts