Security News
38% of CISOs Fear They’re Not Moving Fast Enough on AI
CISOs are racing to adopt AI for cybersecurity, but hurdles in budgets and governance may leave some falling behind in the fight against cyber threats.
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 objectconst express = express();
(필수)
socket : websocket objectconst socketIo = require('socket.io')(serv,{});
forceAwait : true일때 모든 file에 비동기 필요하면 자동으로 async await를 붙인다.
sequelize : sequelize objectrequire('./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}}"
}
}
파일은 Component, Controller, Service, Model 이렇게 4가지 형태의 @Annotation으로 구분해주며
모든 파일은 Common
@Annotation을 호출 할 수 있습니다.
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
문서의 암/복호화를 사용할 수 있다.
@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를 붙이지 않는다.
@Component
File
@Component
를 추가해야합니다.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')
: 캐시 업데이트, 무조건 리턴값을 캐싱한다.
@Controller
File
@Controller
를 추가해야합니다.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});
}
}
}
// @Starter()
: node실행할때 선행 실행된다.
// @RequestMapping ('/v1')
: class 밖의 RequestMapping은 전역 경로
// @RequestMapping ('/login',post)
: 전역과 더해진 router
( method list: get, post, delete, put, patch, files, file, all, use )
@Service
File
@Service
를 추가해야합니다.Comment
로 추가해야 합니다. /** @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;
}
}
// @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를 수동으로 지정 해야함 )
@Model
File
@Model
를 추가해야합니다.Comment
로 추가해야 합니다. 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
);
}
}
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);
}
}
FAQs
Backend mvc framework for node expressJs
The npm package hetamvc receives a total of 0 weekly downloads. As such, hetamvc popularity was classified as not popular.
We found that hetamvc demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
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.
Security News
CISOs are racing to adopt AI for cybersecurity, but hurdles in budgets and governance may leave some falling behind in the fight against cyber threats.
Research
Security News
Socket researchers uncovered a backdoored typosquat of BoltDB in the Go ecosystem, exploiting Go Module Proxy caching to persist undetected for years.
Security News
Company News
Socket is joining TC54 to help develop standards for software supply chain security, contributing to the evolution of SBOMs, CycloneDX, and Package URL specifications.