0.3.37 • Published 8 months ago

hetamvc v0.3.37

Weekly downloads
108
License
-
Repository
-
Last release
8 months ago

HetaMvc

HetaMvc is MVC back-end framework that consist of expressJs in NodeJs based

Install it with the command below

    $ npm i -save hetamvc

아래 문구를 app.js등의 시작 js에 추가해서 실행해 줍니다.

   require('hetamvc').init({
        scanPath:app_route,	        //scan path  (required)
        route:express,		            //express route (required)
        //socket:socketIo,	                            //socket object
        //sequelize:require('./sequelize.config.js'),    //DB
        //mongodb:require('./mongodb.config.js'),       //Mongo
        //email:require('./email.config.js'),       //Email
        //locale:require('./locale.config.js'),       //Locale
    	//constants:require('./app.config.js'),   //Global Value 
    	//logger:require('./logger.config.js'),   //logging
	    //uploadPath:appConfig._upload.path             //File Upload path
        //forceAwait: true                          //force await mode 
        //rootPath: __dirname                       //강제 경로   app.js를 외부에서 호출시 import한 값의 경로가 바뀔수 있음 
    });

scanPath : route path 파일의 최상위 경로 (필수)
route : express object const express = express(); (필수)
socket : websocket object const socketIo = require('socket.io')(serv,{});
forceAwait : true일때 모든 file에 비동기 필요하면 자동으로 async await를 붙인다.
sequelize : sequelize object require('./sequelize.config.js')

    //sequelize.config.js (mysql)
    module.exports = {
        dialect: "mysql",
        username: "root",
        password: "xxxxxxx",
        passKey: "Encrypt_Key",    //Password encryption key
        database: "dbname",
        host: "localhost",
        port: 3306,
        logging: true,
        force: false,
        operatorsAliases: false,
        timezone: "-08:00",
        dialectOptions: {
            charset: 'utf8mb4',
            dateStrings: true,
            typeCast: true
        },
        define: {
            timestamps: false
        },
        pool:{
            max:20,
            min:5,
            idle:10000
        }
    };
//sequelize.config.js (sqlite)
module.exports = {
    dialect: "sqlite",
    force: false,       //강제 테이블변경
    operatorsAliases: false,    
    dialectOptions: {
        charset: 'utf8mb4',
        dateStrings: true,
        typeCast: true
    },
    define: {
        freezeTableName: true,  //테이블에s 제거
        timestamps: false    //false : 자동으로 CreatedAt, UpdatedAt 방지 
    },
    pool:{
        max:20,
        min:5,
        idle:10000
    },
    storage: __dirname+"/database.sqlite" // default Sequelize('sqlite::memory:');
};
> mongodb : mongodb 연결시 설정해줌 `require('./mongodb.config.js')`  
```JavaScript
    //mongodb.config.js
    module.exports = {
        username: "",
        password: "",
        passKey: "Encrypt_Key",    //Password encryption key
        database: "test",
        host: "localhost",
        port: 27017,
        dialect: "mongodb",
        options: {
            useNewUrlParser: true,
            useUnifiedTopology: true,	//pool
            serverSelectionTimeoutMS: 10000,
        }
        /* mongodb transaction을 사용할때 활성화
        ,replicaSet: {
            name : "bgarage_replica",
            hosts: [ // Primary를 제외한 나머지 기술
            {
                host: "bgaragemongo_slave",
                port: 27118
            },
            {
                host: "bgaragemongo_arbiter",
                port: 27119
            }
            ]
        }
        */
    };

constants : constants object 초기 상수값 require('./app.config.js')

    //app.config.js 
    const path = require('path');
    module.exports = {
        _email:{
            serverUrl: "http://{IP}"
        },
        _ip:'',
        _root: __dirname,
        _upload:{
            path: path.resolve(__dirname, './upload')
        }
    };

email : email사용하기 위해 smtp설정 require('./email.config.js')

    //email.config.js 
    module.exports = {
        smtp: "smtp.naver.com",
        port: 587,
        secure: false,
        user: "xxxxx",
        pass: "04ec1b40be3a75a12ae522cc38affab8", //Passwords created using @Encrypt can be created in the documentation referenced.
        passKey: "Encrypt_Key",    //Password encryption key
        from: "xxxxx@naver.com"         //Pin the sending user
    };
> logger : winston logger사용하기 위해 설정 `require('./logger.config.js')`
```JavaScript
    //logger.config.js 
    module.exports = {
        level: "debug", //error:0, warn:1, info:2, verbose:3, debug:4, silly:5
        output:['console','file'], 	//default 'console'
        dir: 'logs'	//file directory
    };

locale : 다국어 사용을 위해 i18n설정 require('./locale.config.js')

    //locale.config.js 
    module.exports = {
        locales:['en', 'ko'],   //사용언어 설정 / 'de' 나 'ja' , 'fr' 등등 추가 가능 
        directory: '/locales', // 사용언어에 대한 템플릿폴더 생성위치,  
        defaultLocale: 'en',    //기본 사용언어 설정 
        cookie: 'lang',         //쿠키의 이름 설정, 개발자가 자유롭게 이름 설정가능
        autoReload: true,
        //updateFiles: false,   //없는 param을 있으면 json파일을 변경한다
        //syncFiles: false,		//로케일 정보 동기화 
        objectNotation:true 
    };
//en.json
{
    "home": {
	    "title": "test {{aa}}"
    }
}
## File 구성
---  
파일은 Component, Controller, Service, Model 이렇게 4가지 형태의 @Annotation으로 구분해주며   
모든 파일은 `Common` @Annotation을 호출 할 수 있습니다.  

1. `Common` @Annotation  
    변수로만 할당하며 모두 contructor안에서 정의한다.  
    호출하는 객체는 모두 async await 처리를 자동으로 해준다. 
    ```JavaScript

    /** @NoAutoAwait () */ 
    class Test{
        constructor(){
		    /** @Inject ('SettingMasterService') */
		    this.SettingMasterService;

            /** @Websocket ('/ns') */ 
            this.websocket;

            /** @Sequelize () */ 
            this.sequelize;

            /** @Request () */ 
            this.request;

            /** @Render () */ 
            this.render;

            /** @Route () */ 
            this.route;

            /** @Constants () */ 
            this.constants;

            /** @Encrypt ('Encrypt_Key')    */ 
            this.encrypt;

            /** @Email () */ 
            this.email;

            /** @Locale () */ 
            this.i18n;

            /** @Logger () */ 
            this.log;
        }
        /** @Starter () */
        start(){
            console.log('Component/Service/Controller Started.');
        }

        Websocket(){
            this.websocket.emit('send data to all');

            for(let item of this.websocket.sockets){
                let socketId = item[0];
			    let socket = item[1];
                socket.emit('User Id :',socket.userId || 'Anonymous');
            }
        }
        Sequelize(){
            var param = {sDate: sDate, eDate: eDate};
            let s = `SELECT * FROM TEST`;
            let resultList = this.sequelize.query(s,{
                type:this.sequelize.QueryTypes.SELECT,raw:true,
                replacements: param
            });
        }
        Request(){
            try{
                var OPTIONS = {
                    uri: 'http://test.com/rest/testinsert',
                    method: 'PUT',	//POST
                    json: true,     //response type
                    headers: {
                        'Content-Type': 'application/json',
                        'x-token': "mytoken"
                    },
                    body: {
                        "id": "test_id",
                        "name": "test_name"
                    }
                };
                const response = this.request(OPTIONS);
                console.log(response);
                
            }catch(e){
                console.log('ERROR :',e);
                //return e;     // throw exception
            }
        }
        Render(){
            const str = this.render(this.constants._root+"/templates/email.html", {
                param1: "title", param2: "contents", param3: "copyright"
            });
        }
        Route(){
            this.route.get('/some/url',function(req,res,next){
                res.send('this is dynamic router');
            });
        }
        Constants(){
            console.log(this.constants._root);  // the data in app.config.js
        }
        Encrypt(){
            let enc = this.encrypt.encode('testEncrypt');  
            console.log(enc);  //14ec1b40be3a75a12ae522cc38affab8
            console.log(this.encrypt.decode(enc)); //testEncrypt
        }
        Email(){
            try{
                let mailOptions = {
                    //from: 'sender@gmail.com',             //single
                    to: 'test1@gmail.com,test2@gmail.com',  //multiple
                    subject: 'some title',	                //title
                    html: '<p> some contents </p>'			//contents
                };
                let result = this.email.send(mailOptions);
                console.log("Finish sending email : " + result.response);
            }catch(e){
                console.log(e.response);
                //return e;     // throw exception
            }
        }
        Locale(){
            console.log(this.i18n.getLocale());		//read default 'en'
            this.i18n.setLocale('en');	//set lang
            res.cookie('lang', 'en'); 	//set lang - same as above
            // http://host/lang/en      //set lang - same as above
            console.log(this.i18n.__('home.title',{aa:'test'});  //translate back-end
            
            //<%= __('sample_title')/*Title*/%>     //translate front-end
            //Using the en.json file when call in the VUE
        }
        Logger(){
            this.log.debug('debug test');
            this.log.info('info test');
            this.log.error('error test');
        }
    }
        
    ```
    > `@Inject('Service or Model')` @Service 또는 @Model객체를 변수에 할당  
    > `@Websocket('/ns')` socketIO객체를 가져옴 namespace(option)로 구분  
    > `@Sequelize('')` this.sequelize.query()로 query를 바로 호출한다.  
    > `@Request` 외부의 http url을 호출한다.  
    > `@Render` 메일 발송같은 임의로 ExpressJs Render(ejs parsing)를 한다.  
    > `@Route` ExpressJs 객체를 사용한다. (get,post,delete등을 동적 설정)  
    > `@Constants` 초기에 입력받은 상수 값을 사용 할 수 있다.(config)  
    > `@Encrypt` 문서의 암/복호화를 사용할 수 있다.  
    > `@Email` 초기에 입력받은 Smtp설정으로 간편하게 이메일을 사용 한다.(config)  
    > `@Locale` 다국어 객체를 받음. en.json,ko.json 등의 파일을 사용한다.(config)  
    > `@Logger` winston logger를 사용 (config)  
    > `@Starter` 시스템이 시작될때 Method를 onload해준다.    
    > `@ForceAwait` Class 상단에 사용하며 forceAwait == false 일때 자동으로 async와 await를 붙인다. 
    > `@NoForceAwait` Class 상단에 사용하며 forceAwait == true 일때 자동으로 async와 await를 붙이지 않는다.  

1. `@Component` File
    - 공통소스 , 배치 , Filter 등의 용도로 사용합니다.
    - class상단에 `@Component`를 추가해야합니다.
    - 모든 @Annotation은 `Comment`로 추가해야 합니다.
    
    ```JavaScript
        /** @Component */
        export class FilterComponent{
	        constructor(){}

            /** @Starter () */
            start(){
                console.log('component started.');
            }
            // @FilterMapping ('/*')
            SessionInterceptor(req,res,next){
                res.header('X-XSS-Protection' , 0 );
                console.log('페이지 호출전에 이 function을 선행 호출');
                return next();
            }

            // @Scheduler ('0 */10 * * * *')
            every10min(){
                console.log('10분마다 호출됨.');
            }

            // @Scheduler ('500')
            every10min(dt, d){
                console.log('0.5초 마다 호출됨.');
            }

            /** @Socket ('message','/ns') */
            socketMessage(data,socket){
		        socket.userId = data.userId;

                console.log('Client에서 socket.emit("message",{}); 로 호출함');
                socket.emit('log','Client said : '+data);
                socket.broadcast.emit('message',data);      //나빼고 전체발송
            }

            /** @SocketConnect ('/ns') */
            connect(socket){
                console.log("socket connection : "+socket.id);
                const roomId = socket.request.session.roomId;   //session읽기
                return {roomId:roomId};
            }
            
            /** @SocketDisconnect ('/ns') */
            disconnect(socket, connectReturn){
                console.log(connectReturn);     //위connect에서 return한 값
                console.log("socket disconnected : "+socket.id);
            }

            /** @Cacheable ('key', '#vo.id') */
            getList(vo){
                return this.commonBoardMapper.getOptList(vo);
                
            }
            /** @CacheEvict ('key', '#vo.id') */
            insertVo(vo){
                return true;
            }
            /** @CachePut ('key', '#vo.id') */
            updateVo(vo){
                return true;
            }
            
        }
    ```
    - Component에서 사용 할수 있는 Method용 Annotation목록 입니다.  
        > `// @FilterMapping ('/*')` :  request 호출의 선행자로 동작  
        > `// @Starter()` : node실행할때 선행 실행된다.  
        > `// @Scheduler ('0 */10 * * * *')` : cron을 이용한 Scheduler  
        > `// @Socket ('emit name',ns)` : server에서 socket request처리, ns는 옵션  
        > `// @SocketConnect (ns)` : socket 사용자 접속시, ns는 옵션  
        > `// @SocketDisconnect (ns)` : socket 사용자 분리시, ns는 옵션  
        > `// @Cacheable (key, '#param.id')` : 캐시를 사용한다. 1회로드 하고 리턴받은 값을 다음 호출시 전달, ()는 Class+Method로 생성  
        > `// @CacheEvict (key, '#param.id')` : 캐시 삭제, (key)만 입력하면 하위 캐시 모두 제거  
        > `// @CachePut (key, '#param.id')` : 캐시 업데이트, 무조건 리턴값을 캐싱한다.  
  
  
1. `@Controller` File
    - Express router 설정을 annotation으로 진행 합니다.
    - class상단에 `@Controller`를 추가해야합니다.
    - 모든 @Annotation은 `Comment`로 추가해야 합니다.
    
    ```JavaScript
        /** @Controller */
        /** @RequestMapping ('/v1') */
        export class LoginController{
	        constructor(){}
            
            /** @Starter () */
            start(){
                console.log('controller started.');
            }

            /** @RequestMapping ('/login/:id',get) */
            login_get(req,res,next){
                let userid = req.params.id;
                res.render('account/login',{userid}); 
            }
            /** @RequestMapping ('/login',post) */
            login_post(req,res,next){
                try{
                    let userid = req.body.param1;

                    console.log("express 문법을 따릅니다.");

                    res.status(200).json({result:"SUCCESS"});   //put:201
                }catch(e){
                    res.status(500).json({result:e});
                }
            }
            
            /** 여러개 파일 업로드 (uploadPath필수)
             * @anno1 : 경로
             * @anno2 : method type (files 고정값) -> (req.files :  파일정보)  
             * @anno3 : input의 name attribute 
               예) <input type="file" name="image"/>
            */
            /** @RequestMapping ('/imagesubmit',files,'image') */
            imageuploadSubmit(req,res,next){
                try{
                    for(var i in req.files){
                        const fileInfo = req.files[i];
                        console.log('이미 uploadPath에 파일은 저장됨.');
                        console.log('파일정보.(filepath:/202101/20/xx)',fileInfo);
                        this.service.insertFileManager(fileInfo);
                    }
                    
                    res.json({result:'SUCCESS'});
                }catch(e){
                    console.log(e);
                    res.json({errorMsg:e});
                }
            }
            
            /** 1개파일만 업로드 (uploadPath필수)
             * @anno1 : 경로
             * @anno2 : method type (file 고정값) -> (req.file :  파일정보)  
             * @anno3 : input의 name attribute 
               예) <input type="file" name="layout"/>
            */
            /** @RequestMapping ('/imagesubmit',file,'layout') */
            singleFileUploadSubmit(req,res,next){
                try{
                    const fileInfo = req.file;
                    console.log('이미 uploadPath에 파일은 저장됨.');
                    console.log('파일정보.(filepath:/202101/20/xx)',fileInfo);
                    this.service.insertFileManager(fileInfo);
                    res.json({result:'SUCCESS'});
                }catch(e){
                    console.log(e);
                    res.json({errorMsg:e});
                }
            }
        }
    ```
    - Controller에서만 사용 할수 있는 Method용 Annotation목록 입니다.  
        > `// @Starter()` : node실행할때 선행 실행된다.  
        > `// @RequestMapping ('/v1')` : class 밖의 RequestMapping은 전역 경로  
        > `// @RequestMapping ('/login',post)` : 전역과 더해진 router  
            ( method list: get, post, delete, put, patch, files, file, all, use )
1. `@Service` File
    - Service 상호간의 Inject가 가능 하도록 설계된 모듈  
    - class상단에 `@Service`를 추가해야합니다.  
    - 모든 @Annotation은 `Comment`로 추가해야 합니다.  
    - @Inject annotation으로 Component, Controller, Service에 추가 될수 있습니다.  
    - @Inject 할때 Service또는 Model을 inject한다. Service는 2depth까지 Inject가능  

    ```JavaScript
        /** @Service */
        class CommBoardService{
            constructor(){
                /** @Inject ('CommBoardMapper') */
                this.commonBoardMapper;
            }

            /** @Starter () */
            start(){
                console.log('service started.');
            }


            // @Scheduler ('0 */10 * * * *')
            every10min(){
                console.log('10분마다 호출됨.');
            }

            // @Scheduler ('500')
            every10min(dt, d){
                console.log('서버가 시작되면서 0.5초 마다 호출됨.');
            }

            /**
            * Add List
            * @param vo : req.body
            */
            /** @Transactional () */    //default : 'REQUIRED'
            setList(vo){
                const cnt = this.commonBoardMapper.getCount(vo);
                return true;
            }

            /** @Transactional ('REQUIRES_NEW','mongoose') */
            setList(vo){
                //transaction type of mongodb
                this.commonBoardMapper.setList(vo, cnt);
                
                return true;
            }
            /** @Transactional ('','sequelize') */
            setList(vo){
                //transaction type of sequelize
                this.commonBoardMapper.setOptList(vo, cnt);
                return true;
            }

            /** @Cacheable ('key', '#vo.id') */
            getList(vo){
                return this.commonBoardMapper.getOptList(vo);
                
            }
            /** @CacheEvict ('key', '#vo.id') */
            insertVo(vo){
                return true;
            }
            /** @CachePut ('key', '#vo.id') */
            updateVo(vo){
                return true;
            }
            
        }
    ```
    - Service에서 사용 할수 있는 Method용 Annotation 입니다.  
        > `// @Transactional (['REQUIRED','REQUIRES_NEW','NESTED','SUPPORTS','MANDATORY','NOT_SUPPORTED','NEVER'],['mongoose','sequlize'])` :  DB Transaction처리  
        > `// @Starter()` : node실행할때 선행 실행된다.  
        > `// @Scheduler ('0 */10 * * * *')` : cron을 이용한 Scheduler  
        > `// @Socket ('emit name',ns)` : server에서 socket request처리, ns는 옵션  
        > `// @SocketConnect (ns)` : socket 사용자 접속시, ns는 옵션  
        > `// @SocketDisconnect (ns)` : socket 사용자 분리시, ns는 옵션  
        > `// @Cacheable (key, '#param.id')` : 캐시를 사용한다. 1회로드 하고 리턴받은 값을 다음 호출시 전달, ()는 Class+Method로 생성  
        > `// @CacheEvict (key, '#param.id')` : 캐시 삭제, (key)만 입력하면 하위 캐시 모두 제거  
        > `// @CachePut (key, '#param.id')` : 캐시 업데이트, 무조건 리턴값을 캐싱한다.  
        ( 여러 DB를 동시 사용시 mongoose, sequelize를 수동으로 지정 해야함 )
                         
1. `@Model` File
    - Database(mongodb) 연결설정 Annotation입니다.  
    - class상단에 `@Model`를 추가해야합니다.  
    - 모든 @Annotation은 `Comment`로 추가해야 합니다.  
    - @Inject annotation으로 Component, Controller, Service에 추가 될수 있습니다.  
    - mode항목에 sequelize 또는 mongodb를 입력해서 구분
    - Sequelize
    ```JavaScript
        import {HetaSequelize} from 'hetamvc'
        /** @Model */
        export default class FileManager extends HetaSequelize{
            init(Sequelize, options) {
                //options.indexes = [{ unique: false, fields: ['fileGroup']}];
                return this.model('filemanager', {
                    id: {type: Sequelize.INTEGER.UNSIGNED, primaryKey: true, autoIncrement: true},
                    fileGroup: {type: Sequelize.INTEGER.UNSIGNED,defaultValue: 0},	
                    fileName: {type: Sequelize.STRING(200)},
                    filePath: {type: Sequelize.STRING(100)},
                    mimeType:  {type: Sequelize.STRING(20)},
                    fileSize: {type: Sequelize.INTEGER.UNSIGNED,defaultValue: 0},
                    createUser: {type: Sequelize.STRING(16), allowNull: true},
                    createdAt: {type: 'TIMESTAMP', defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'), allowNull: false}
                    },
                    options
                );
            }
        }
    ```
    - MongoDB
    ```JavaScript
        import {HetaMongoose} from 'hetamvc'

        /** @Model */
        export default class FileManager extends HetaMongoose{
            init(mongoose) {
                let schema = new mongoose.Schema({
                    id: { type: Number, required: true, unique: true },
                    fileGroup: {type: Number, default: 0},	
                    fileName: { type: String, required: true },
                    filePath: { type: String, required: true },
                    mimeType: { type: String, required: false },
                    fileSize: {type: Number,default: 0},
                    createUser: {type: String},
                    createdAt: { type : Date, default: Date.now } //timestamp
                },{
                    _id: true,
                    timestamps: true, 
                    collection: this.name //테이블명을 classname으로
                });
                
                return this.model(this.name, schema);
            }
        }
    ```
  
0.3.37

8 months ago

0.3.36

10 months ago

0.3.35

10 months ago

0.3.34

12 months ago

0.3.33

1 year ago

0.3.32

2 years ago

0.3.31

2 years ago

0.3.30

2 years ago

0.3.29

2 years ago

0.3.28

2 years ago

0.3.27

2 years ago

0.3.26

2 years ago

0.3.25

2 years ago

0.3.24

2 years ago

0.3.23

2 years ago

0.3.20

2 years ago

0.3.22

2 years ago

0.3.21

2 years ago

0.3.19

2 years ago

0.3.18

2 years ago

0.3.17

2 years ago

0.3.16

2 years ago

0.3.15

2 years ago

0.3.14

2 years ago

0.3.13

2 years ago

0.3.12

2 years ago

0.3.11

2 years ago

0.3.0

2 years ago

0.3.6

2 years ago

0.3.5

2 years ago

0.3.8

2 years ago

0.3.7

2 years ago

0.3.2

2 years ago

0.3.1

2 years ago

0.3.4

2 years ago

0.3.3

2 years ago

0.3.9

2 years ago

0.3.10

2 years ago

0.2.30

2 years ago

0.2.33

2 years ago

0.2.32

2 years ago

0.2.31

2 years ago

0.2.27

2 years ago

0.2.26

2 years ago

0.2.25

2 years ago

0.2.24

2 years ago

0.2.23

2 years ago

0.2.29

2 years ago

0.2.28

2 years ago

0.2.22

3 years ago

0.2.21

3 years ago

0.2.20

3 years ago

0.2.19

3 years ago

0.2.18

3 years ago

0.2.17

3 years ago

0.2.16

3 years ago

0.2.15

3 years ago

0.2.14

3 years ago

0.2.13

3 years ago

0.2.12

3 years ago

0.2.11

3 years ago

0.2.10

3 years ago

0.2.9

3 years ago

0.2.8

3 years ago

0.2.7

3 years ago

0.2.6

3 years ago

0.2.5

3 years ago

0.2.4

4 years ago

0.2.3

4 years ago

0.2.2

4 years ago

0.2.1

4 years ago

0.2.0

4 years ago

0.1.9

4 years ago

0.1.8

4 years ago

0.1.7

4 years ago

0.1.6

4 years ago

0.1.4

4 years ago

0.1.5

4 years ago

0.1.3

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago