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,
route:express,
});
scanPath : route path 파일의 최상위 경로
(필수)
route : express object const express = express();
(필수)
socket : websocket object const socketIo = require('socket.io')(serv,{});
forceAwait : true일때 모든 file상단에 @AutoAsyncAwait 붙은 효과
sequelize : sequelize object require('./sequelize.config.js')
module.exports = {
dialect: "mysql",
username: "root",
password: "xxxxxxx",
passKey: "Encrypt_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
}
};
module.exports = {
dialect: "sqlite",
force: false,
operatorsAliases: false,
dialectOptions: {
charset: 'utf8mb4',
dateStrings: true,
typeCast: true
},
define: {
freezeTableName: true,
timestamps: false
},
pool:{
max:20,
min:5,
idle:10000
},
storage: __dirname+"/database.sqlite"
};
mongodb : mongodb 연결시 설정해줌 require('./mongodb.config.js')
module.exports = {
username: "",
password: "",
passKey: "Encrypt_Key",
database: "test",
host: "localhost",
port: 27017,
dialect: "mongodb",
options: {
useNewUrlParser: true,
useUnifiedTopology: true,
serverSelectionTimeoutMS: 10000,
}
};
constants : constants object 초기 상수값 require('./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')
module.exports = {
smtp: "smtp.naver.com",
port: 587,
secure: false,
user: "xxxxx",
pass: "04ec1b40be3a75a12ae522cc38affab8",
passKey: "Encrypt_Key",
from: "xxxxx@naver.com"
};
logger : winston logger사용하기 위해 설정 require('./logger.config.js')
module.exports = {
level: "debug",
output:['console','file'],
dir: 'logs'
};
locale : 다국어 사용을 위해 i18n설정 require('./locale.config.js')
module.exports = {
locales:['en', 'ko'],
directory: '/locales',
defaultLocale: 'en',
cookie: 'lang',
autoReload: true,
objectNotation:true
};
{
"home": {
"title": "test {{aa}}"
}
}
File 구성
파일은 Component, Controller, Service, Model 이렇게 4가지 형태의 @Annotation으로 구분해주며
모든 파일은 Common
@Annotation을 호출 할 수 있습니다.
-
Common
@Annotation
변수로만 할당하며 모두 contructor안에서 정의한다.
호출하는 객체는 모두 async await 처리를 자동으로 해준다.
class Test{
constructor(){
this.SettingMasterService;
this.websocket;
this.sequelize;
this.request;
this.render;
this.route;
this.constants;
this.encrypt;
this.email;
this.i18n;
this.log;
}
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',
json: true,
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);
}
}
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);
}
Encrypt(){
let enc = this.encrypt.encode('testEncrypt');
console.log(enc);
console.log(this.encrypt.decode(enc));
}
Email(){
try{
let mailOptions = {
to: 'test1@gmail.com,test2@gmail.com',
subject: 'some title',
html: '<p> some contents </p>'
};
let result = this.email.send(mailOptions);
console.log("Finish sending email : " + result.response);
}catch(e){
console.log(e.response);
}
}
Locale(){
console.log(this.i18n.getLocale());
this.i18n.setLocale('en');
res.cookie('lang', 'en');
console.log(this.i18n.__('home.title',{aa:'test'});
}
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해준다.
@AutoAsyncAwait
Method에 자동 async와 await설정함. (전역 import를 사용 할때 사용불가.)
-
@Component
File
- 공통소스 , 배치 , Filter 등의 용도로 사용합니다.
- class상단에
@Component
를 추가해야합니다. - 모든 @Annotation은
Comment
로 추가해야 합니다.
export class FilterComponent{
constructor(){}
start(){
console.log('component started.');
}
SessionInterceptor(req,res,next){
res.header('X-XSS-Protection' , 0 );
console.log('페이지 호출전에 이 function을 선행 호출');
return next();
}
every10min(){
console.log('10분마다 호출됨.');
}
every10min(dt, d){
console.log('0.5초 마다 호출됨.');
}
socketMessage(data,socket){
socket.userId = data.userId;
console.log('Client에서 socket.emit("message",{}); 로 호출함');
socket.emit('log','Client said : '+data);
socket.broadcast.emit('message',data);
}
connect(socket){
console.log("socket connection : "+socket.id);
const roomId = socket.request.session.roomId;
return {roomId:roomId};
}
disconnect(socket, connectReturn){
console.log(connectReturn);
console.log("socket disconnected : "+socket.id);
}
}
-
@Controller
File
- Express router 설정을 annotation으로 진행 합니다.
- class상단에
@Controller
를 추가해야합니다. - 모든 @Annotation은
Comment
로 추가해야 합니다.
export class LoginController{
constructor(){}
start(){
console.log('controller started.');
}
login_get(req,res,next){
let userid = req.params.id;
res.render('account/login',{userid});
}
login_post(req,res,next){
try{
let userid = req.body.param1;
console.log("express 문법을 따릅니다.");
res.status(200).json({result:"SUCCESS"});
}catch(e){
res.status(500).json({result:e});
}
}
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});
}
}
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 )
-
@Service
File
- Service 상호간의 Inject가 가능 하도록 설계된 모듈
- class상단에
@Service
를 추가해야합니다. - 모든 @Annotation은
Comment
로 추가해야 합니다. - @Inject annotation으로 Component, Controller, Service에 추가 될수 있습니다.
- @Inject 할때 Service또는 Model을 inject한다. Service는 2depth까지 Inject가능
class CommBoardService{
constructor(){
this.commonBoardMapper;
}
start(){
console.log('service started.');
}
every10min(){
console.log('10분마다 호출됨.');
}
every10min(dt, d){
console.log('서버가 시작되면서 0.5초 마다 호출됨.');
}
setList(vo){
const cnt = this.commonBoardMapper.getCount(vo);
return true;
}
setList(vo){
this.commonBoardMapper.setList(vo, cnt);
return true;
}
setList(vo){
this.commonBoardMapper.setOptList(vo, cnt);
return true;
}
}
- Service에서만 사용 할수 있는 Method용 Annotation 입니다.
// @Starter()
: node실행할때 선행 실행된다.
// @Scheduler ('0 */10 * * * *')
: cron을 이용한 Scheduler
// @Transactional (['REQUIRED','REQUIRES_NEW'],['mongoose','sequlize'])
: DB Transaction처리
( 여러 DB를 동시 사용시 mongoose, sequelize를 수동으로 지정 해야함 )
-
@Model
File
- Database(mongodb) 연결설정 Annotation입니다.
- class상단에
@Model
를 추가해야합니다. - 모든 @Annotation은
Comment
로 추가해야 합니다. - @Inject annotation으로 Component, Controller, Service에 추가 될수 있습니다.
- mode항목에 sequelize 또는 mongodb를 입력해서 구분
- Sequelize
import {HetaSequelize} from 'hetamvc'
export default class FileManager extends HetaSequelize{
init(Sequelize, options) {
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'
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 }
},{
_id: true,
timestamps: true,
collection: this.name
});
return this.model(this.name, schema);
}
}
더 자세한 사용법