728x90

[허교수의 ARM Mbed 프로그래밍 입문 리뷰] 이벤트로 도서를 받았습니다.


마이크로비트 오프라인 컴파일로 처음 Mbed를 접하게 되면서,

기초부터 배우고 싶었는데, 이 도서의 출판과 이벤트에 당첨되어 리뷰를 작성합니다.

Mbed의 기초(실행방법부터 컴파일, 설치까지)부터 각종 통신방법(디지탈I/O, 아두이노I/O, UART, I2C)과 각종 센서의 동작 원리와 작동 방법까지 자세히 설명되어 있어 기초부터 실정에 필요한 내용이 이 책하나에 다 있습니다.

기초부터 시작하시는 처음 배우시는 분도, 기존에 하셨분들도 필요한 부분만 찾아서 보셔도 챕터별로 정리가 잘되서 있어 좋은 책인것 같습니다.

이 책은 4단계로 나누어져서 설명이 되어 있는데,

1단계는 "Mbed소개"로 ARM프로세서의 소개 및 역사, Mbed가 지원하는 보드의 소개, Mbed의 컴파일과 누클레오 보드에 설치하는 방법이 나와있습니다.

2단계는 "기본 프로그래밍"에서는 MbedAPI, 디지털 I/O, UART 시리얼 통신, 아나로그, PWM 출력, SPI 통신, I2C 통신 방법이 원리부터 설명이 되어 있고,

3단계는 "주변장치 프로그래밍"에서는 블루투스, 로터리 인코더, 온습도 센서, 초음파 거리센서, 릴레이, 텍스트 LCD, RTC, DC모터 서보모터제어가,

4단계는 "고급 프로그래밍"에서는 RTOS-멀티스레드, 누클레오-우두이노 UART 통신이 설명 되어 있습니다.  

이 책에서 사용하는 누클레오 보드는 국내 쇼핑몰의 경우 외국에서 배송되는 것이라서 배송이 일주일정도 걸려서, 중고나라에서 1만원 주고 구입했습니다.

728x90
728x90

출처

가상 레코드 생성 예제

public class DemoReport {
	
	public static void main(String[] args) throws Exception {
		JasperReport jasperReport = JasperCompileManager.compileReport("src/ireport/report1.jrxml");
		
		// creating the data source
		JRDataSource dataSource = new JREmptyDataSource(1000); // 가상의 1000개의 레코드 생성
		
		JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, null, dataSource);
		
		// view report to UI
		jasperReport.setWhenNoDataType(WhenNoDataTypeEnum.ALL_SECTIONS_NO_DETAIL);
		JasperViewer.viewReport(jasperPrint, false);
	}
}

PDF 출력 예제

public class DemoReport2 {

	public static void main(String[] args) throws Exception {
		String outfilename = "src/ireport/report1.pdf";
		JasperReport jasperReport = JasperCompileManager.compileReport("src/ireport/report1.jrxml");

		// compile report hm.put(“REPORT_TITLE”,”This is the title of the report”)
		HashMap<String, Object> hm = new HashMap<String, Object>();
		hm.put("id", "121");

		List list = new ArrayList();
		list.add("test data");
		JRBeanCollectionDataSource jrbcds = new JRBeanCollectionDataSource(list, false);

		// 리포트 목록
		// List<JasperPrint> japerPrintList = new ArrayList<JasperPrint>();

		JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, hm, jrbcds);

		// PDF 출력
		JRExporter ex = new JRPdfExporter();
		ex.setParameter(JRPdfExporterParameter.IS_COMPRESSED, true);
		ex.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, outfilename);
		// ex.setParameter(JRExporterParameter.JASPER_PRINT_LIST, japerPrintList);
		ex.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
		ex.exportReport();
	}
}

JRDataSource 확장

필드 추가

필드 이름 변경

필드 객체를 선택해서 Detail 밴드에 드래그해 놓기

필드 배치

최종 결과물

커스텀 JRDataSource

import java.util.HashMap;
import java.util.Map;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;

public class SampleDS implements JRDataSource {

	String[] fields;
	String[][] data;

	private Map<String, Integer> fieldIndex = new HashMap<String, Integer>();
	
	public SampleDS(String[] fields, String[][] data) {
		this.fields = fields;
		this.data = data;

		for (int i = 0; i < fields.length; i++)
			fieldIndex.put(fields[i], i);
	}

	int pos = -1;

	@Override
	public boolean next() throws JRException {
		for (;;) {
			pos++;
			if (pos >= data.length)
				return false;

			return true;
		}
	}

	@Override
	public Object getFieldValue(JRField jrField) throws JRException {
		Integer index = fieldIndex.get(jrField.getName());
		return data[pos][index];
	}
	
	public static JRDataSource getDataSource() {
		String[] fields = { "a", "b", "c", "d", "e" }; 
		String[][] data = {
				{ "a1", "b1", "c1", "d1", "e1" },
				{ "a2", "b2", "c2", "d2", "e2" },
				{ "a3", "b3", "c3", "d3", "e3" }
		};
		
		return new SampleDS(fields, data);
	}

}

예제소스

public class DemoReport3 {
	
	public static void main(String[] args) throws Exception {
		String outfilename = "src/ireport/report2.pdf";
		JasperReport jasperReport = JasperCompileManager.compileReport("src/ireport/report2.jrxml");
		
		// 커스텀 JRDataSource 생성
		JRDataSource dataSource = SampleDS.getDataSource();
		
		//
		JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, null, dataSource);

		// PDF 출력
		JRExporter ex =new JRPdfExporter();
		ex.setParameter(JRPdfExporterParameter.IS_COMPRESSED, true);
		ex.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, outfilename);
		//ex.setParameter(JRExporterParameter.JASPER_PRINT_LIST, japerPrintList);
		ex.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
		ex.exportReport();
	}

}

실행

동적으로 이미지 출력

디자인

Image Expression

$P{image_home}+"/"+$F{image1}

ImageBean 소스

public class ImageBean {
	
	private String image1;
	
	private String image2;

	public ImageBean(String image1, String image2) {
		super();
		this.image1 = image1;
		this.image2 = image2;
	}

	public String getImage1() {
		return image1;
	}

	public void setImage1(String image1) {
		this.image1 = image1;
	}

	public String getImage2() {
		return image2;
	}

	public void setImage2(String image2) {
		this.image2 = image2;
	}

}

이미지 출력 예제 소스

public class DemoReport4 {
	
	public static void main(String[] args) throws Exception {
		String outfilename = "src/ireport/report3.pdf";
		JasperReport jasperReport = JasperCompileManager.compileReport("src/ireport/report3.jrxml");
		
		// compile report hm.put(“REPORT_TITLE”,”This is the title of the report”)
		HashMap<String, Object> hm = new HashMap<String, Object>();
		hm.put("image_home", "C:\\Users\\bluesanta\\Pictures");
		
		//
		List list = new ArrayList();
		list.add(new ImageBean("73196c49-adeb-4ebd-9bde-069791498a28.jpg", "70947765.jpg"));
		JRBeanCollectionDataSource jrbcds = new JRBeanCollectionDataSource(list, false);
		
		// 리포트 목록
		// List<JasperPrint> japerPrintList = new ArrayList<JasperPrint>();

		JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, hm, jrbcds);

		// PDF 출력
		JRExporter ex = new JRPdfExporter();
		ex.setParameter(JRPdfExporterParameter.IS_COMPRESSED, true);
		ex.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, outfilename);
		// ex.setParameter(JRExporterParameter.JASPER_PRINT_LIST, japerPrintList);
		ex.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
		ex.exportReport();
	}

}
728x90
728x90

출처

MMDevApi.pas

unit MMDevApi;

interface

uses
  Windows, ActiveX, ComObj;

const
  CLSID_MMDeviceEnumerator : TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
  IID_IMMDeviceEnumerator : TGUID = '{A95664D2-9614-4F35-A746-DE8DB63617E6}';
  IID_IMMDevice : TGUID = '{D666063F-1587-4E43-81F1-B948E807363F}';
  IID_IMMDeviceCollection : TGUID = '{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}';
  IID_IAudioEndpointVolume : TGUID = '{5CDF2C82-841E-4546-9722-0CF74078229A}';
  IID_IAudioMeterInformation : TGUID = '{C02216F6-8C67-4B5B-9D00-D008E73E0064}';
  IID_IAudioEndpointVolumeCallback : TGUID = '{657804FA-D6AD-4496-8A60-352752AF4F89}';
  IID_IMMNotificationClient : TGUID = '{7991EEC9-7E89-4D85-8390-6C703CEC60C0}';

  DEVICE_STATE_ACTIVE = $00000001;
  DEVICE_STATE_UNPLUGGED = $00000002;
  DEVICE_STATE_NOTPRESENT = $00000004;
  DEVICE_STATEMASK_ALL = $00000007;

type
 PAUDIO_VOLUME_NOTIFICATION_DATA = ^AUDIO_VOLUME_NOTIFICATION_DATA;
 AUDIO_VOLUME_NOTIFICATION_DATA = packed record
  guidEventContext: TGUID;
  bMuted: BOOL;
  fMasterVolume: Single;
  nChannels: UINT;
  afChannelVolumes: array[1..1] of Single;
 end;

type
  EDataFlow = TOleEnum;

const
  eRender = $00000000;
  eCapture = $00000001;
  eAll = $00000002;
  EDataFlow_enum_count = $00000003;

type
  ERole = TOleEnum;

const
  eConsole = $00000000;
  eMultimedia = $00000001;
  eCommunications = $00000002;
  ERole_enum_count = $00000003;

type
  IAudioEndpointVolumeCallback = interface(IUnknown)
  [IID_IAudioEndpointVolumeCallback]
    function OnNotify(pNotify: PAUDIO_VOLUME_NOTIFICATION_DATA): HRESULT; stdcall;
  end;

  IAudioEndpointVolume = interface(IUnknown)
  [IID_IAudioEndpointVolume]
    function RegisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
    function UnregisterControlChangeNotify(AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
    function GetChannelCount(out PInteger): Integer; stdcall;
    function SetMasterVolumeLevel(fLevelDB: single; pguidEventContext: PGUID): Integer; stdcall;
    function SetMasterVolumeLevelScalar(fLevelDB: single; pguidEventContext: PGUID): Integer; stdcall;
    function GetMasterVolumeLevel(out fLevelDB: single): Integer; stdcall;
    function GetMasterVolumeLevelScaler(out fLevelDB: single): Integer; stdcall;
    function SetChannelVolumeLevel(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): Integer; stdcall;
    function SetChannelVolumeLevelScalar(nChannel: Integer; fLevelDB: double; pguidEventContext: PGUID): Integer; stdcall;
    function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double): Integer; stdcall;
    function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: double): Integer; stdcall;
    function SetMute(bMute: Boolean; pguidEventContext: PGUID): Integer; stdcall;
    function GetMute(out bMute: Boolean): Integer; stdcall;
    function GetVolumeStepInfo(pnStep: Integer; out pnStepCount: Integer): Integer; stdcall;
    function VolumeStepUp(pguidEventContext: PGUID): Integer; stdcall;
    function VolumeStepDown(pguidEventContext: PGUID): Integer; stdcall;
    function QueryHardwareSupport(out pdwHardwareSupportMask): Integer; stdcall;
    function GetVolumeRange(out pflVolumeMindB: double; out pflVolumeMaxdB: double; out pflVolumeIncrementdB: double): Integer; stdcall;
  end;

  IAudioMeterInformation = interface(IUnknown)
  [IID_IAudioMeterInformation]
    function GetPeakValue(out Peak: Real): HRESULT; stdcall;
  end;

  IPropertyStore = interface(IUnknown)
  end;

  IMMDevice = interface(IUnknown)
  [IID_IMMDevice]
    function Activate(const refId: TGUID; dwClsCtx: DWORD; pActivationParams: PInteger; out pEndpointVolume: IAudioEndpointVolume): HRESULT; stdCall;
    function OpenPropertyStore(stgmAccess: DWORD; out ppProperties: IPropertyStore): HRESULT; stdcall;
    function GetId(out ppstrId: PLPWSTR): HRESULT; stdcall;
    function GetState(out State: Integer): HRESULT; stdcall;
  end;

  IMMDeviceCollection = interface(IUnknown)
  [IID_IMMDeviceCollection]
    function GetCount(out pcDevices: UINT): HRESULT; stdcall;
    function Item(nDevice: UINT; out ppDevice: IMMDevice): HRESULT; stdcall;
  end;

  IMMNotificationClient = interface(IUnknown)
  [IID_IMMNotificationClient]
  end;

  IMMDeviceEnumerator = interface(IUnknown)
  [IID_IMMDeviceEnumerator]
    function EnumAudioEndpoints(dataFlow: EDataFlow; deviceState: SYSUINT; out DevCollection: IMMDeviceCollection): HRESULT; stdcall;
    function GetDefaultAudioEndpoint(EDF: SYSUINT; ER: SYSUINT; out Dev: IMMDevice): HRESULT; stdcall;
    function GetDevice(pwstrId: pointer; out Dev: IMMDevice): HRESULT; stdcall;
    function RegisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall;
    function UnregisterEndpointNotificationCallback(pClient: IMMNotificationClient): HRESULT; stdcall;
  end;

implementation

end.

Demo

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  MMDevApi, ActiveX, ComObj, Vcl.ComCtrls, Vcl.StdCtrls;

type
  TEndpointVolumeCallback = class(TInterfacedObject, IAudioEndpointVolumeCallback)
    function OnNotify(pNotify: PAUDIO_VOLUME_NOTIFICATION_DATA): HRESULT; stdcall;
  end;

  TForm1 = class(TForm)
    trackVolumeLevel: TTrackBar;
    spdMute: TCheckBox;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    endpointVolume: IAudioEndpointVolume;
  public
    { Public declarations }
    procedure doMasterVolumeMute(bMute: Boolean);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.doMasterVolumeMute(bMute: Boolean);
var
  MMDeviceCollection: IMMDeviceCollection;
  MMDeviceEnumerator: IMMDeviceEnumerator;
  device :IMMDevice ;
  hr: HRESULT;
  deviceCount : UINT;
  i : integer;
begin
  hr := CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_ALL, IID_IMMDeviceEnumerator, MMDeviceEnumerator);
  if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr));

  MMDeviceCollection := nil; // wegen dem OUT-Parameter *1
  hr := MMDeviceEnumerator.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, MMDeviceCollection);
  if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr));

  hr := MMDeviceCollection.GetCount(deviceCount);
  if hr <> ERROR_SUCCESS then ShowMessage(SysErrorMessage(hr));

  for i:=0 to deviceCount-1 do begin
    MMDeviceCollection.Item(i, device);
    endpointVolume:=nil;
    device.Activate(IID_IAudioEndpointVolume, CLSCTX_INPROC_SERVER, nil, endpointVolume);
    endpointVolume.SetMute(bMute,nil);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  doMasterVolumeMute(true);
end;

end.
728x90
728x90

출처

/config/dbHelper.js

const mariadb = require('mariadb');
var config = require('./db_config');    // ./는 현재 디렉토리를 나타냅니다

const pool = mariadb.createPool({
    host: config.host,
    port: config.port,
    user: config.user,
    password: config.password,
    database: config.database,
    connectionLimit: 5
});

function dbHelper() {
    //
    this.getConnection = function(callback) {
        pool.getConnection()
            .then(conn => {
                callback(conn);
            }).catch(err => {
            //not connected
        });
    };

    //
    this.getConnectionAsync = async function() {
        try {
            let conn = await pool.getConnection();
            // console.log("conn = " + conn); // { affectedRows: 1, insertId: 1, warningStatus: 0 }
            return conn;
        } catch (err) {
            throw err;
        }
        return null;
    };

    //
    this.sendJSON = function(response, httpCode, body) {
        var result = JSON.stringify(body);
        response.send(httpCode, result);
    };
}

module.exports = new dbHelper();

/config/passport.js

var dbHelper = require('./dbHelper');
const LocalStrategy = require('passport-local').Strategy;

module.exports = (passport) => {

    // 로그인이 성공하면, serializeUser 메서드를 이용하여 사용자 정보를 Session에 저장할 수 있다.
    passport.serializeUser((user, done) => {
        console.log('serialize');
        done(null, user);
    });

    // 인증 후, 페이지 접근시 마다 사용자 정보를 Session에서 읽어옴.
    passport.deserializeUser((user, done) => {
        console.log('deserialize');
        done(null, user);
    });

    passport.use(new LocalStrategy({
            usernameField : 'userid',
            passwordField : 'password',
            passReqToCallback : true
        },

        // 인증 요청
        function(req, userid, password, done) {
            if(!userid || !password ) { return done(null, false, req.flash('message','All fields are required.')); }
            dbHelper.getConnection(function(conn) {
                console.log('conn = ' + conn);
                conn.query("select * from member where email = ?", [userid]).then((rows) => {
                    // console.log(rows);
                    if(!rows.length) {
                        return done(null, false, req.flash('message','Invalid username or password.'));
                    }
                    var dbPassword  = rows[0].password;
                    if(!(dbPassword == password)) {
                        return done(null, false, req.flash('message','Invalid username or password.'));
                    }
                    return done(null, rows[0]);
                })
                .then((res) => {
                    console.log('res = '+res); // { affectedRows: 1, insertId: 1, warningStatus: 0 }
                    conn.end();
                })
                .catch(err => {
                    //handle error
                    console.log(err);
                    conn.end();
                    if (err) return done(req.flash('message',err));
                });
            });
        }
    ));
};

웹페이지에 값 전달 (connect-flash 모듈)

/app.js

var flash = require('connect-flash');

app.use(passport.session()); //로그인 세션 유지
app.use(flash());
728x90
728x90

출처

/config/db_config.js

module.exports = (function() {
    return {
        host: "localhost",
        port : 10312,
        user: "root",
        password: "sqldba",
        database: "simplesns"
    }
})();

/config/dbHelper.js

const mariadb = require('mariadb');
var config = require('./db_config');    // ./는 현재 디렉토리를 나타냅니다

const pool = mariadb.createPool({
    host: config.host,
    port: config.port,
    user: config.user,
    password: config.password,
    database: config.database,
    connectionLimit: 5
});

function dbHelper() {
    //
    this.getConnection = function(callback) {
        pool.getConnection()
            .then(conn => {
                callback(conn);
            }).catch(err => {
            //not connected
        });
    };

    //
    this.getConnectionAsync = async function() {
        try {
            let conn = await pool.getConnection();
            // console.log("conn = " + conn); // { affectedRows: 1, insertId: 1, warningStatus: 0 }
            return conn;
        } catch (err) {
            throw err;
        }
        return null;
    };

    //
    this.sendJSON = function(response, httpCode, body) {
        var result = JSON.stringify(body);
        response.send(httpCode, result);
    };
}

module.exports = new dbHelper();

/api/user/UserService.js

var dbHelper = require('../../config/dbHelper');

// https://github.com/jareddlc/node-datatables/blob/master/server.js
function UserService() {
    this.getUserList = function(request, response) {
        dbHelper.getConnection(function(conn) {
            conn.query('SELECT * FROM member')
                .then((results) => {
                    // console.log(results); //[ {val: 1}, meta: ... ]

                    //Output
                    var output = {};
                    var temp = [];
                    output.datas = results;
                    
                    dbHelper.sendJSON(response, 200, output);
                })
                .then((res) => {
                    console.log('res = '+res); // { affectedRows: 1, insertId: 1, warningStatus: 0 }
                    conn.end();
                })
                .catch(err => {
                    //handle error
                    console.log(err);
                    conn.end();
                })
        });
    }
}

module.exports = new UserService();
728x90
728x90

출처

/api/user/user.ctrl.js

/* api 로직 */
let users = [
    {id: 1, name: 'jinbro'},
    {id: 2, name: 'jinhyung'},
    {id: 3, name: 'park'}
];

let index = function(req, res) {
    if(!req.query.limit){
        res.json(users);
    } else {
        const limit = parseInt(req.query.limit, 10);

        if(isNaN(limit)){
            return res.status(400).end();
        }
        res.json(users.slice(0, limit));
    }
};

let read = function(req, res) {
    const id = parseInt(req.params.id, 10);

    console.log("id = " + id);

    if(isNaN(id)) {
        return res.status(400).end();
    }

    const user = users.filter((user) => {
        return user.id === id;
    })[0];

    if(!user) {
        return res.status(404).end();
    }

    res.json(user);
};

module.exports = {
    index: index,
    read: read
    //create: create,
    //update: update,
    //destroy: destroy
};

/api/user/index.js

const express = require('express');
const router = express.Router();

const controller = require('./user.ctrl');

/* user 라우팅 로직 */
router.get('/', controller.index);
router.get('/:id', controller.read);
//router.post('/', controller.create);
//router.put('/:id', controller.update);
//router.delete('/:id', controller.destroy);

module.exports = router;

/app.js

/* use router class */
const user = require('./api/user/index.js');

/* /users 요청을 모두 /user/index.js로 */
app.use('/users', user);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

실행

728x90
728x90

출처

변수

출처 : 2. 기초문법 · node.js 서버구축하기

var name; // 변수 선언
name = '홍길동'; // 변수 정의

var num2 = 3; // 변수 선언과 정의

함수

출처 : 함수 표현식 vs 함수 선언식 • Captain Pangyo

함수 선언식 - Function Declarations

// 함수 선언
function funcDeclarations() {
  return 'A function declaration';
}
funcDeclarations(); // 함수 호출

함수 표현식 - Function Expressions

// 함수 표현식 -> 함수 변수 선언
var funcExpression = function () {
    return 'A function expression';
}
funcExpression(); // 함수 호출

조건문

if < > && || ==

반복문

for, while

클래스

// User 클래스 선언
function User(_name){
    // 변수를 객체의 멤버로 사용하기 위해 this 예약어를 사용해서 정의
    this.name = _name; // 사용자 이름
    this.age = 0; // 사용자 나이

    // 사용자 이름을 반환 하는 User 클래스의 내장 함수
    this.getName = function() {
        return this.name;
    }

    this.getAge = function() {
        return this.age;
    }
}

var user1 = new User("bluexmas"); // User 객체 생성 
console.log(user1.getName()); // User 클래스의 내장 함수 호출

prototype

// User객체의 prototype을 가져와서 setAge 함수 추가
User.prototype.setAge = function(_age){
    this.age = _age;
}

user1.setAge(10);
console.log(user1.getAge()); // User 클래스의 내장 함수 호출

require - 동적 라이브러리 로딩

출처 : Node.js 기초와 모듈 (내장 모듈, npm, 사용자정의 모듈)

url 모듈을 이용해서 url 파싱하는 예제

var url = require("url");
var parsedURL = url.parse("http://www.example.com/profile?name=barry");
 
console.log(parsedURL.protocol); // "http:"
console.log(parsedURL.host); // "www.example.com"
console.log(parsedURL.query); // "name=barry"
728x90
728x90

출처

/app.js

// 모듈 추가
const passport = require('passport');
const session = require('express-session');
var bodyParser = require('body-parser');

// ... 생략 ...

/*
cookieParser
session
passport.initialize
passport.session
app.route
 */
var app = express();

// ... 생략 ...

app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// 세션 설정
app.use(session({
  secret: 'simpleSNS',
  resave: true,
  saveUninitialized: false
})); // 세션 활성화

require('./config/passport')(passport);
app.use(passport.initialize());
app.use(passport.session()); //로그인 세션 유지

app.use(bodyParser.urlencoded({extended: true}));

/public/login.html

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<form action="/login" method="post">
    <div>
        <label>UserId:</label>
        <input type="text" name="userid"/><br/>
    </div>
    <div>
        <label>Password:</label>
        <input type="password" name="password"/>
    </div>
    <div>
        <input type="submit" value="Submit"/>
    </div>
</form>
</body>
</html>

/config/passport.js

const LocalStrategy = require('passport-local').Strategy;

module.exports = (passport) => {

    // 로그인이 성공하면, serializeUser 메서드를 이용하여 사용자 정보를 Session에 저장할 수 있다.
    passport.serializeUser((user, done) => {
        console.log('serialize');
        done(null, user);
    });

    // 인증 후, 페이지 접근시 마다 사용자 정보를 Session에서 읽어옴.
    passport.deserializeUser((user, done) => {
        console.log('deserialize');
        done(null, user);
    });

    passport.use(new LocalStrategy({
            usernameField : 'userid',
            passwordField : 'password',
            passReqToCallback : true
        },
        
        // 인증 요청
        function(req, userid, password, done) {
            if(userid=='test' && password=='1111') {
                var user = {
                    'userid':'hello',
                    'email':'hello@world.com'
                };
                return done(null, user);
            }else{
                return done(null, false);
            }
        }
    ));
};

/routes/index.js

var express = require('express');
var router = express.Router();
const passport = require('passport');

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

// 로그인
router.post('/login', passport.authenticate('local', {failureRedirect: '/login.html'}), (req, res) => {
  res.redirect('/login_suc.html');
});

/*
router.post('/login', passport.authenticate('local', {
  successRedirect: '/login_suc.html',
  failureRedirect: '/login.html'
}));
*/

// 로그아웃
router.get('/logout', (req, res) => {
  req.logout();
  res.redirect('/');
});

module.exports = router;

Facebook 로그인 적용

/config/passport.js 내용 추가

const FacebookStrategy = require('passport-facebook').Strategy;

module.exports = (passport) => {

// ... 생략 ...

    passport.use(new FacebookStrategy({
            clientID: "",
            clientSecret: "",
            profileFields: ['id', 'displayName', 'photos'],
            callbackURL: 'http://localhost:3000/markdown/auth/facebook/callback'
        },

        function (accessToken, refreshToken, profile, done) {
            const socialId = profile.id;
            const nickname = profile.displayName;
            const profileImageUrl = profile.photos[0].value;

            onLoginSuccess('Facebook', socialId, nickname, profileImageUrl, done);
        }
    ));

/routes/index.js 내용 추가

// ... 생략 ...

// 로그아웃
router.get('/logout', (req, res) => {
  req.logout();
  res.redirect('/');
});

// 페이스북 로그인 시작
router.get('/facebook', passport.authenticate('facebook'));

// 페이스북 로그인 결과 콜백
router.get('/facebook/callback', passport.authenticate('facebook', {
    failureRedirect: '/markdown/auth/login'
}), (req, res) => {
    loginSuccessHandler(req, res);
});

module.exports = router;
728x90

+ Recent posts