스프링 부트 스타터(https://start.spring.io/) 홈페이지에서 프로젝트에 필요한  라이브러리를 추가하고 생성할 수 있다.

 

최근 Spring Boot & JPA로 웹/앱 애플리케이션을 만들 때 보통 Gradle Project로 사용한다.

언어는 자바, 버전은 2.6.12로 설정해주었다!

버전 같은 경우 높을 수록 인텔리제이에서 호환이 안될 수 있어서 프로젝트 생성 기준 젤 낮은 거로 생성해주자.

Project Metadata에서는 Artifact는 jpashop, Name은 jpabook으로 설정해주고, 자바 버전은 11로 해준다.

 

추가한 dependency 목록

Spring Web, Lombok, Thymeleaf, H2 Database, Spring Data JPA, Validation을 추가해줬다.

 

- Spring Web: Web MVC를 사용하여 웹 어플리케이션을 만드는 데 필요한 스프링부트의 기본적인 요소를 가진다. 내장형 컨테이너로 톰캣을 기본으로 탑재하고 있다! Rest API 서버를 만든다면 필수적인 모듈
- Lombok: 클래스의 Getter/Setter 등을 자동으로 생성해주는 어노테이션들을 제공한다. 자바 특유의 장황한 클래스를 줄여주는 좋은 툴

- Thymeleaf: 뷰 템플릿 엔진으로 컨트롤러가 전달하는 데이터를 이용하여 동적으로 화면을 구성할 수 있게 해준다. html 태그를 기반으로 하여 동적인 View를 제공한다.

- H2 Database: 메모리를 데이터베이스로 사용하는, 즉각 설치되는 데이터베이스이다. 의존성에 추가하는 것만으로도 데이터베이스 설정을 전혀 할 필요 없이 바로 사용 가능! 그러나 개발 전용이기에 어플리케이션이 종료될 때 내부 데이터가 모두 사라진다.

- Spring Data JPA: JPA (Java Persistence API)라고 하며 자바 ORM 기술의 토대를 이루는 기술 명세. Hibernate를 사용하고 있으며 Spring에서는 DB를 다루는 거의 표준 기술. Class Entity를 마치 DB처럼 사용할 수 있는 매우 유용한 도구이지만 학습량이 만만한 도구는 아니다.

- Validation: 프로그래밍에 있어서 가장 필요한 부분으로 특히 java에서는 null 값에 대해서 접근하려고 할 때 NPE가 발생함으로, 이런 부분을 방지하기 위해서 미리 검증을 하는 과정

 

generate 버튼을 클릭하면 zip파일로 다운로드된다. zip파일을 압축해제해주고, 인텔리제이에서 import해준다.

 

 

다음과 같이 프로젝트 목록이 뜨게 된다.

 

build.gradle 파일이다

처음 plugins를 보면 스프링부트 버전, 의존성, 자바 언어를 사용하고 있다고 나와있다! (initializer에서 설정한 값 그대로)

plugin에서 라이브러리에대한 dependency 버전 관리도 가능하다

configurations는 lombok으로 생성된 설정값

repositories에서는 mavenCentral에서 라이브러리를 따오겠다는 의미다

initializer에서 추가한 의존성 목록 확인

 

 

 

Gradle 실행

(왼쪽에서 네번째 로고 클릭)

 

~~Application.java 에 들어가서 실행해준다

 

Tomcat started on 8080~이라는 문구가 뜬다.

로컬에 localhost:8080을 입력해주자!

 

화이트라벨 에러페이지가 뜨면 성공이다

아무것도 설정을 안했기에...!

 

test에서 똑같이 실행해준다. 프로젝트 세팅 완료!

 

External Library에 추가된게 엄청 많은데,

build.gradle에서 추가한 dependency에 보면, 하나의 목록마다 관련된 거 여러개씩 추가된다

 

설정메뉴 > 플러그인 에서 Lombok 설치해준다. (나는 이미 설치되어 있었음)

그리고 설정메뉴 > 빌드, 실행, 배포 > 컴파일러 > 어노테이션 프로세서에서 

어노테이션 처리 활성화 버튼 눌러준다

이러면 프로젝트 설정 끝끝끝이고

 

lombok이 잘 돌아가는지 확인하기 위해 Hello클래스를 작성해주었다

 

main문에 작성을 해주고 실행하면

 

콘솔에서 바로 값 확인 가능!

이렇게 스프링부트 프로젝트 기본 설정 및 출력 확인 완료~!

사진 출처 :  https://velog.io/@courage331/Spring-%EA%B3%BC-Spring-Boot-%EC%B0%A8%EC%9D%B4

Spring

스프링 프레임워크는 자바 플랫폼을 위한 오픈소스 애플리케이션 프레임워크로서 간단히 스프링이라고 불린다.

동적 웹사이트 개발하기 위해 여러 서비스를 제공한다.

 

대표적인 특징

1. DI ( Dependency Injection)
-> 개발자가 Spring 프레임워크에 의존성을 주입하면서 객체 간 결합을 느슨하게 한다.
객체 간 결합이 느슨해지면 코드의 재사용성이 증가하고, 단위 테스트가 용이해짐!

2. IoC ( Inversion of Control )
-> 컨트롤의 제어권이 개발자에게 있는 것이 아닌 프레임워크가 대신해서 해주는 것
Servlet이나 Bean 같은 코드를 개발자가 직접 작성하지 않고, 프레임워크가 대신 수행!
기존에는 자바 코드를 작성할 때 객체의 생성, 의존관계 설정 등을 개발자가 해줘야 했지만,
프레임워크가 대신해준다는 의미이다. (제어의 역전)

3. AOP ( Aspect Oriented Programming )
-> 핵심 기능 제외한 부수적 기능을 프레임워크가 제공해준다.
ex) Spring 프로젝트에 security 적용하거나 logging 등을 추가..
기존 비즈니스 로직 건들지 않고 AOP로 추가 가능

4. 중복 코드 제거
JDBC와 같은 템플릿 사용시 중복되는 코드도 많고 복잡하다. 이를 모두 제거한다!

5. 다른 프레임워크와의 통합
JUnit, Mockito와 같은 유닛 테스트 프레임워크와 통합이 간단하다. => 개발하는 프로그램 품질 향상

 

Spring과 Spring Boot의 차이점

스프링 부트는 단독적이고 상용화 수준의 스픠링 기반 애플리케이션을 단지 실행할 수 있을 정도로 쉽게 만들었다
Spring, Spring Boot Framework 차이점

1. Dependency
Spring의 경우 dependency를 설정해줄 때 설정 파일이 매우 길고, 
모든 dependency에 대해 버전 관리도 하나하나 해줘야 한다

ex) Spring dependency 추가 코드
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.5</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.5</version>
</dependency>
(출처 https://www.baeldung.com/spring-vs-spring-boot)

Spring Boot는 보다 더 쉽게 설정하고, 버전 관리도 자동으로 해준다.
ex) Spring Boot web dependency 추가 코드
implementation 'org.springframework.boot:spring-boot-starter-web'

2. Configuration
Spring의 경우 Configuration 설정 매우 길고, 모든 어노테이션 및 빈 등록을 설정해줘야 한다.
Spring Boot의 경우 application.properties 파일이나 application.yml 파일에 설정하면 된다.

ex) Spring Thymeleaft 사용 예시 코드
@Configuration
@EnableWebMvc
public class MvcWebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {
        SpringResourceTemplateResolver templateResolver = 
          new SpringResourceTemplateResolver();
        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("/WEB-INF/views/");
        templateResolver.setSuffix(".html");
        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);
        return templateEngine;
    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);
    }
}
(출처 https://www.baeldung.com/spring-vs-spring-boot)

ex) Spring Boot Thymeleaft 추가 코드
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf

3. AutoConfiguration
Spring Boot로 실행할 수 있는 애플리케이션을 만들기 시작하면 클래스에 @SpringBootApplication이라는 어노테이션을 확인할 수 있다.
이 어노테이션을 제거하고 프로그램을 실행하면, 일반적인 자바 프로그램과 동일하게 실행되며
해당 어노테이션 덕분에 많은 외부 라이브러리, 내장 톰캣 서버 등이 실행될 수 있다!

@Annotation: 주석, 추후 특정 어노테이션을 처리하는 컴파일러가 어노테이션을 읽으면 알맞은 처리 진행
기능이 포함된 건 아니고 프로그램 곳곳에 분산된 기능을 한 곳에 모아서 처리하고 싶을 때 사용

4. 편리한 배포
Spring로 개발한 애플리케이션의 경우, war파일을 Web Application Server에 담아 배포
Spring Boot의 경우, Tomcat, Jetty 같은 내장 WAS를 가지고 있기 때문에 jar 파일로 간편하게 배포 가능
Spring으로 WAS를 정하고, 모든 설정을 마쳐 배포를 하는 것보다 훨씬 간단한 배포 방법이다!

 

결론

Spring은 기존에 EJB (Enterprise Java Bean) 를 대신해 자바 애플리케이션을 더 쉽게 만들 수 있게 해주고,

Spring Boot는 Spring보다 개발자가 개발에만 더욱 더 집중할 수 있도록 도와주는 프레임워크다!

Spring Boot 짱

1. heroku [remote rejected] master -> master (pre-receive hook declined) 에러

git push heroku master

 (나같은 경우는 git push heroku main) 명령어 치는데 계속 저 에러가 떴다

원인은 브랜치 생성할 때 main 브랜치가 Protected branches로 설정돼서 Developer는 push할 수 없다는 거였다..

그래서 중요도에 따라 Maintainer가 처리하거나 Developer가 직접 처리할 수 있도록 권한 설정할 수 있다 

바로 gitlab에서!

 

GitLab의 Project에서 Settings -> Protected branches로 들어가면 권한을 변경하거나 사용하지 않도록 변경할 수 있다.

이렇게!

근데 난 이렇게 해도 안됐다..

 

2. Node.js application not detected by Heroku 

해도해도 안돼서 에러 내용 구글링하니..

 

Node.js application not detected by Heroku

I created a small site in Visual Studio and used Node.js and Express. I can access it via Visual Studio and with Heroku local web. However, when trying to push it to Heroku, I get the error: Appli...

stackoverflow.com

루트 디렉토리... error에서 이미 방향 제시를 해줬건만 난 이미 루트 디렉토리에 package.json 위치 맞는 줄 알고 계속 나둠

알고보니 node 코드들 있는 폴더 상단에 두라는 거였구먼

이거덕에 해결했다!

 

0. AWS S3(Simple Storage Service)

AWS S3란 인터넷용 스토리지 서비스이다. 이 서비스는 개발자가 더 쉽게 웹 규모 컴퓨팅 작업을 수행할 수 있도록 설계되어있다.

- 단순 웹 서비스 인터페이스를 사용해서 웹에서 언제 어디서나 원하는 양의 데이터를 저장하고 검색

- S3의 버킷은 무한대의 객체를 저장할 수 있으므로 스토리지의 요구를 미리 추정하여 관리할 필요가 없어 확장, 축소에 신경쓰지 않아도 됨

- HTTPS 프로토콜을 사용하여 SSL로 암호화된 엔드포인트를 통해 데이터를 안전하게 업로드, 다운로드 가능

 

1. 준비작업

(1) AWS 계정

(2) AWS 계정의 Access Key, Secret Key

(3) S3 버킷 생성

 

2. AWS SDK 모듈 설치

npm install aws-sdk

 

3. config/awsconfig.json

{
  "accessKeyId": "access key를 입력해주세요.",
  "secretAccessKey": "secret key를 입력해주세요.",
  "region": "ap-northeast-2"
}

 

파일에 AWS 계정의 Access key, Secret key 작성

절대 외부로 노출되어서는 안됨

 

routes/waste-upload.js 파일에 AWS SDK 로딩

const AWS = require("aws-sdk");
AWS.config.loadFromPath(__dirname + "/../config/awsconfig.json");

let s3 = new AWS.S3();

추가해준다

 

4. multer 모듈

일반적으로 파일 업로드를 위해서 multer 모듈 필요

업로드된 파일을 S3에 바로 업로드할 수 있도록 multer-s3 모듈 사용하자

npm install multer
npm install multer-s3

 

클라이언트로부터 받은 이미지 파일을 S3에 업로드하는 라우터 함수 작성

var storage = multer.multerS3({ //s3
    s3: s3,
    bucket: 'cmh-project',
    acl: 'public-read',
    key: function (req, file, cb) {
        cb(null, Math.floor(Math.random() * 1000).toString() + Date.now() + '.' + file.originalname.split('.').pop());
    }
});

* 하단의 블로그 보고 참고하였음!

 

헤로쿠(heroku) 가입부터 node.js 배포까지

오늘은 헤로쿠 가입부터 node.js 배포까지 진행해보도록 하겠습니다. 간단하게 서비스를 띄울 무료 PaaS 서비스를 찾는다면 무조건 헤로쿠겠죠. 1. PaaS 서비스의 대표주자 헤로쿠(Heroku) 헤로쿠라는

nhj12311.tistory.com

 

0. 헤로쿠

- 여러 프로그래밍 언어를 지원하는 클라우드 컴퓨팅 플랫폼. Git, GitHub 등을 지원하고 많은 서비스를 애드온과 API로 지원

- Application 배포시 바로 온 사이트로 서비스 해주는 대표적인 PaaS 서비스

- PaaS (Platform as a Service) : 클라우드에서 제공되는 완전한 개발 및 배포 환경. 개발적으로 서버, 저장소, 네트워킹, 미들웨어, 개발도구, BI, 서비스, DB, 빌드, 테스트, 배포, 관리, 업데이트 등 모든 어플리케이션 수명 주기를 지원하는 서비스

 

출처: 테라데이타

 

1. 헤로쿠 가입

Log in or sign 중 sign 클릭하고 이메일 인증

 

로그인하면!

 

2. Create a new app

왼쪽 버튼 클릭

 

3. App 이름 설정

이름 설정 후 국가는 미국으로! ( 비용 안나감 ,,)

4. 소스 설정

 

이제 소스 어떻게 넣을지 물어보는데 heroku Git - heroku CLI 사용 선택하자

 

5. Windows 64-bit installer 설치 클릭

Heroku CLI 버튼 누르고 조금 내리다 보면 위 사진과 같이 뜨는데, 본인 노트북 OS에 맞게 설치하자!

 

6. 설치 진행

Next 누르고 서서히 진행하다보면 ! 잘 설치된다.

참고한 블로그 보면 기존에 Node.js 깔려있을시 충돌된다고 해서, 하단의 명령어를 통해 설치하면 된다고 한다

C:\Users\Administrator\npm install -g heroku

설치 확인!

 

7. Heroku 저장소 생성

 

터미널에 heroku login을 입력하면 브라우저가 뜨면서 로그인 인증을 요하고 로그인이 된다!

Opening browser to https://cli-auth.heroku.com/auth/cli/browser/......
Logging in... done
Logged in as xxx@naver.com

 

8. 배포하고자 하는 디렉토리로 이동한 후 아래 명령어를 수행

heroku git: remote -a [app name]

 

git remote -v 명령어로 연결된 원격저장소 확인

$ git remote -v
heroku  https://git.heroku.com/cmh-node-js.git (fetch)
heroku  https://git.heroku.com/cmh-node-js.git (push)
origin  https://github.com/codusl100/dongguk_cmh.git (fetch)
origin  https://github.com/codusl100/dongguk_cmh.git (push)

 

9. 연결된 로컬 디렉토리 내 파일들을 heroku 원격 저장소로 push

git push heroku [브랜치]

main 브랜치로 push 하려했는데 안돼서 새로 브랜치 생성하고 (node1) 상단의 명령어 다시 입력했다

 

 

10. push까지 끝나면 배포는 완료됐고, 배포된 링크로 이동해서 확인하면 정상적으로 메인페이지가 보인다. 

그러나 sleep 상태의 dyno를 깨워주는 명령어를 수행해야함. 안그러면 배포된 웹 서비스에서 request 못받음

heroku ps:scale web=1

 

 

11. 배포된 프로젝트 확인하는 법

 

(1) 직접 타이핑 

https://[heroku dashboard에 보이는 app 이름].herokuapp.com/

 

(2) heroku dashboard에서 app 클릭 -> 우측 상단에 위치하는 open app 버튼 클릭

 

(3) heroku 명령어: 터미널에서 heroku app 실행

 

1. ../routes/login.js

const express = require("express");
const User = require("../models/User");
const router = express.Router();
const bcrypt = require("bcryptjs"); // 암호화 모듈
const jwt = require("jsonwebtoken");

router.post('/', (req, res)=>{
    // 요청된 이메일을 db에서 찾는다.
    User.findOne({email: req.body.email}, (err, user)=>{
        if(!user){
            return res.json({
                loginSuccess: false,
                message: "Unvalid email"
            });
        }
    // 요청된 이메일이 db에 있다면 비밀번호 일치여부 확인
    user.comparePassword(req.body.password, (err, isMatch)=>{
        if(!isMatch)
            return res.json({
                loginSuccess:false,
                message:"Wrong password"
            });
    // 일치 시, 토큰 생성. 생성한 토큰을 쿠키에 저장한다
    user.generateToken((err, user)=>{
        if(err) return res.status(400).send(err);
        // 토큰을 쿠키에 저장
        res.cookie("x_auth", user.token)
        .status(200)
        .json({
            loginSuccess: true,
            userId: user._id,
            token: user.token,
            name: user.name,
            email: user.email,
            password: user.password
            });
        });        
        });
    });
});

module.exports = router;

 

2. User 모델에 추가

userSchema.methods.comparePassword=function(plainPassword, cb){
    bcrypt.compare(plainPassword, this.password, function(err, isMatch){
        if(err) return cb(err);
        cb(null, isMatch);
    });
}

userSchema.methods.generateToken=function(cb){
    const user=this;
    const token=jwt.sign(user._id.toHexString(), 'secretToken');
    user.token=token;
    user.save(function(err, user){
        if(err) return cb(err);
        cb(null, user);
    });
}

위에는 비밀번호 비교해서 해당 유저가 맞는지 확인

아래는 token 생성해서 로그인시 제공!

 

3. Postman 결과 화면

login 성공 여부, userId, token, 이름, 이메일, 비밀번호 출력 완료!!

1. 회원 가입

router.post(
    "/",
    async (req, res) => {
        const { name, email, password, address } = req.body;

        try {
            // email을 비교해서 user가 이미 존재하는지 확인
            // 존재한다면 return해서 뒤의 코드를 실행하지 않음.
            let user = await User.findOne({ email });
            if (user) {
                return res.status(400).json({ errors: [{ msg: "User already exists" }] });
            };

            // user가 존재하지 않으면 새로운 user에 대해서 DB에 추가
            user = new User({
                name,
                email,
                password,
                address,
            });

            // bcrypt 모듈을 이용해 salt값을 부여하며 password 암호화
            const salt = await bcrypt.genSalt(10);
            user.password = await bcrypt.hash(password, salt);

            // 암호화된 내용까지 포함해 DB에 user를 저장.
            await user.save();
    });

 

2. jwt (jsonwebtoken) 기능 추가

// 암호화된 내용까지 포함해 DB에 user를 저장.
            await user.save();

            const payload = { // json web token 으로 변환할 데이터 정보
                user: {
                    id: user.id,
                },
            };
            // json web token 생성하여 send 해주기
            jwt.sign(
                payload, // 변환할 데이터
                "jwtSecret", // secret key 값
                { expiresIn: "1h" }, // token의 유효시간
                (err, token) => {
                    if (err) throw err;
                    res.send({ token }); // token 값 response 해주기
                }
            );

        } catch (error) {
            console.error(error.message);
            res.status(500).send("Server Error");
        };

register 밑 부분에 추가하기!

 

3. postman 결과

req에 필요한 body값들 담고 api 호출시 token 반환

 

auth api를 통해 회원가입되어 있는지 확인 가능!

1. connectDB

mongoDB와 연결되는 모듈

 

2. cookieParser

요청된 쿠키를 쉽게 추출할 수 있도록 해주는 미들웨어

request 객체에 cookies 속성이 부여됨

 

3. bodyParser

Node.js의 POST 요청 데이터를 추출할 수 있도록 만들어주는 미들웨어

req에 body 프로퍼티 사용 가능

 

- bodyParser.json()은 'application/json' 방식의 Content-Type 데이터를 받아줌

- bodyParser.urlencoded({...})는 'application/x-www-form-urlencoded' 방식의 Content-Type 데이터를 받아줌 (jQuery.ajax의 기본 타입)

- bodyParser,text()는 'text/xml' 방식의 Content-Type 데이터를 받아줌

 

4. cors

추가적인  HTTP 헤더를 사용해 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 자원에 접근할 수 있는 권한을 관리하는 체제

보안상의 이유로 cors 이슈 발생

(ex. https://domain-a.com의 프론트 엔드 JavaScript 코드가 XMLHttpRequest를 사용하여 https://domain-b.com/data.json을 요청하는 경우 cross-origin HTTP 요청이 됨)

1. vscode와 git 연동하기

git clone <복사할 깃 주소>

 

2. node.js 기본 설정

npm init
// npm init -y 하면 기본 값들 다 불러와짐

package.json 파일 생성

 

3. node 모듈 설치 + express.js까지 추가한다면

npm install --save express

그러면 프로젝트 폴더에 node_modules, package-lock.json 파일까지 생성된다.

 

package.json 파일이 존재한다면 프로젝트 공유시 node_modules 폴더까지 공유할 필요가 없어짐!!

+ Recent posts