Socket
Socket
Sign inDemoInstall

hetamvc

Package Overview
Dependencies
335
Maintainers
1
Versions
82
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    hetamvc

Backend mvc framework for node expressJs


Version published
Weekly downloads
9
increased by350%
Maintainers
1
Install size
47.7 MB
Created
Weekly downloads
 

Readme

Source

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')

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

    //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 처리를 자동으로 해준다.

    
    /** @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를 붙이지 않는다.

  2. @Component File

    • 공통소스 , 배치 , Filter 등의 용도로 사용합니다.
    • class상단에 @Component를 추가해야합니다.
    • 모든 @Annotation은 Comment로 추가해야 합니다.
        /** @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') : 캐시 업데이트, 무조건 리턴값을 캐싱한다.

  3. @Controller File

    • Express router 설정을 annotation으로 진행 합니다.
    • class상단에 @Controller를 추가해야합니다.
    • 모든 @Annotation은 Comment로 추가해야 합니다.
        /** @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 )

  4. @Service File

    • Service 상호간의 Inject가 가능 하도록 설계된 모듈
    • class상단에 @Service를 추가해야합니다.
    • 모든 @Annotation은 Comment로 추가해야 합니다.
    • @Inject annotation으로 Component, Controller, Service에 추가 될수 있습니다.
    • @Inject 할때 Service또는 Model을 inject한다. Service는 2depth까지 Inject가능
        /** @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를 수동으로 지정 해야함 )

  5. @Model File

    • Database(mongodb) 연결설정 Annotation입니다.
    • class상단에 @Model를 추가해야합니다.
    • 모든 @Annotation은 Comment로 추가해야 합니다.
    • @Inject annotation으로 Component, Controller, Service에 추가 될수 있습니다.
    • mode항목에 sequelize 또는 mongodb를 입력해서 구분
    • Sequelize
        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
        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);
            }
        }
    

Keywords

FAQs

Last updated on 28 Aug 2023

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc