javaFX maven 프로젝트를 빌드하면 Target 폴더에 jar파일이 생성되게 된다. 동일한 폴더에 jre와 javafx-sdk를 복사해 넣으면 작동 환경은 구성된 것이다. 그런데 이렇게 해도 잘 안된다. 그냥 javafx-sdk에 있는 lib, bin을 jre폴더에 추가 복사해넣는게 제일 낫다.
4. pom.xml
우선 jar파일이 정상적으로 실행이 되어야한다. 그런데 실행하다보면 MainClass가 빠졌다는 등의 오류가 발생하는 경우가 있다. 이런경우 maven-shade-plugin을 사용해 Fat JAR을 생성한다. 아래 플러그인 부분에서 Fat JAR만들기 부분 참조
시작점이 되는 파일이다. 코드 아래쪽을 보면 SerialService라는 서비스를 불러내는데, controller를 인자로 넘겨준다. controller는 화면 구성요소와 그에 대한 controll을 하는 부분이다. 이 controller를 넘겨줘야 Serial 데이터의 입력에 맞춰 화면에 정보를 뿌릴 수 있다.
package com.example.javafx05;
import com.example.javafx05.emp.EmpDto;
import com.example.javafx05.emp.EmpService;
import com.fazecast.jSerialComm.SerialPort;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.stage.Stage;
import java.io.IOException;
public class HelloApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader loader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(loader.load(), 900, 800);
HelloController controller = loader.getController();
stage.setTitle("Data Room Security");
stage.setScene(scene);
stage.show();
SerialService serialService = new SerialService(controller); //<-- 시리얼 통신 + UI 컨트롤
serialService.initializeSerialCommunication(); //<-- 시리얼 통신 + UI 컨트롤
}
public static void main(String[] args) {
launch();
}
}
7. SerialService.java
위의 HelloApplication에서 시작하여 Serial데이터를 받기 시작하는 서비스이다. 데이터를 너무 빨리 처리하면 Serial데이터가 두번에 나눠져 들어온다. 그래서 초기에 약간의 대기시간(50ms)을 두었으며, 그래도 모를 예외를 대비해서 12자리를 모두 채우면 데이터를 처리하도록 만들었다.
데이터(message)가 취득되면 emp_check이라는 직원 체크 함수로 간다. 이 함수에서 MyBatis를 통한 DB데이터를 가져오고, 최종 만들어진 데이터 및 인사말은
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.javafx05.emp.EmpMapper">
<select id="select_member" resultType="com.example.javafx05.emp.EmpDto">
select emp_# as emp_no,
emp_x,
kornm_n,
hannm_n,
engnm_n,
res_#1 as res,
dept_c,
dept_n
from bemp a
where a.emp_#=#{emp_no}
</select>
<select id="history_found" resultType="map">
select EMP_# as emp_no,
IN_D,
OUT_D,
PURPOSE,
LOCATION
FROM BEMP_DATAROOM_HSTRY a
where a.emp_#=#{emp_no}
AND to_char(a.in_d,'YYYYMMDD')=to_char(SYSDATE,'YYYYMMDD')
AND a.OUT_D IS null
ORDER BY a.IN_D DESC
</select>
<select id="history_in_log">
insert into BEMP_DATAROOM_HSTRY (emp_#, in_d, out_d, purpose, location)
values (#{emp_no}, sysdate,NULL,#{purpose},#{location})
</select>
<select id="history_out_log">
update BEMP_DATAROOM_HSTRY a
set a.out_d=sysdate
where a.emp_#=#{emp_no}
and a.out_d IS NULL
AND to_char(a.in_d,'YYYYMMDD')=to_char(SYSDATE,'YYYYMMDD')
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.javafx05.history.HistoryMapper">
<select id="historyRecords" resultType="com.example.javafx05.history.HistoryDto">
select a.emp_# ,
b.KORNM_N ,
b.dept_c,
a.in_d,
a.out_d,
a.purpose,
a.location
from temp_dataroom_hstry a, temp b
where a.emp_#=b."EMP_#"
<if test="emp_name!=null and emp_name!=''">
and b.kornm_n like '%'||#{emp_name}||'%'
</if>
<if test="purpose!=null and purpose!=''">
and a.purpose like '%'||#{purpose}||'%'
</if>
<if test="location!=null and location!=''">
and a.location like '%'||#{location}||'%'
</if>
<if test="from!=null and from!=''">
and a.in_d > to_date(#{from},'YYYY-MM-DD')
</if>
<if test="to!=null and to!=''">
and a.in_d < to_date(#{to},'YYYY-MM-DD')
</if>
order by a.in_d desc
</select>
</mapper>
namespace winform_ex02;
using System;
using System.Text;
using System.Xml;
using MaterialSkin; //추가
using MaterialSkin.Controls; //추가
// public partial class Form1 : Form
public partial class Form1 : MaterialForm
{
public Form1()
{
InitializeComponent();
// 아래 추가
var materialSkinManager = MaterialSkinManager.Instance;
materialSkinManager.AddFormToManage(this);
materialSkinManager.Theme = MaterialSkinManager.Themes.DARK;
materialSkinManager.ColorScheme=new ColorScheme(Primary.BlueGrey900, Primary.BlueGrey900, Primary.BlueGrey500, Accent.LightBlue200, TextShade.WHITE);
// 여기까지
// 이하는 버튼 클릭 이벤트...
this.button1.Click += new System.EventHandler(this.button1_Click);
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDlg = new OpenFileDialog();
openFileDlg.Filter = "XML Files (*.xml)|*.xml";
openFileDlg.ShowDialog();
// MessageBox.Show("Hello World!");
if (openFileDlg.FileName.Length > 0)
{
foreach (string Filename in openFileDlg.FileNames)
{
this.textBox1.Text = Filename;
XmlDocument xmlDoc = new XmlDocument(); // XmlDocument 객체 생성
xmlDoc.Load(Filename); // XML 파일 로드
XmlNodeList allNodes = xmlDoc.SelectNodes("//bookstore//*");
StringBuilder sb = new StringBuilder();
foreach(XmlNode node in allNodes){
if(node.NodeType == XmlNodeType.Element){
sb.Append(node.InnerText);
}
else if (node.NodeType == XmlNodeType.Text){
sb.Append(node.Value );
}
// sb.Append("\n");
sb.Append(Environment.NewLine);
}
this.result1.Text = sb.ToString();
}
}
}
}
ColorScheme클래스의 생성 인자
materialSkinManager.ColorScheme=new ColorScheme(Primary.BlueGrey900, Primary.BlueGrey900, Primary.BlueGrey500, Accent.LightBlue200, TextShade.WHITE); // 인자1 `Primary.BlueGrey900`: 테마의 기본 색상. 메인 강조 색상. 진한 청회색. // 인자2 `Primary.BlueGrey900`: 보조 색상으로 호버 색상. 초점 색상. // 인자3 `Primary.BlueGrey500`: 3차 색상. 배경색 or 은은한 그림자 색상으로 가끔 사용됨. // 인자4 `Accent.LightBlue200`: 버튼, 링크 등 강조 색상. 연한 파란색 // 인자5 `TextShade.WHITE`: 텍스트 음영
4. Form1.Designer.cs (버튼 클릭 이벤트/폼 예제)
namespace winform_ex02;
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private Button button1;
private TextBox textBox1;
private TextBox result1;
private Panel panel1;
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "Form1";
// 버튼 컨트롤 생성 및 설정
this.button1 = new System.Windows.Forms.Button();
this.button1.Location = new System.Drawing.Point(10, 10);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(70, 50);
this.button1.Text = "Click Me!";
this.button1.UseVisualStyleBackColor = true;
// this.button1.Click += new System.EventHandler(this.button1_Click); // 클릭 이벤트 핸들러 등록
// 버튼을 폼에 추가
this.Controls.Add(this.button1);
// 텍스트 박스 생성 및 추가
this.textBox1 = new System.Windows.Forms.TextBox();
this.textBox1.Location = new System.Drawing.Point(10, 70);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(500, 500);
this.textBox1.Text = "";
// this.textBox1.UseVisualStyleBackColor = true;
this.Controls.Add(this.textBox1);
// 패널 생성 및 추가
this.panel1 = new System.Windows.Forms.Panel();
this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right | System.Windows.Forms.AnchorStyles.Bottom)));
this.panel1.Location = new System.Drawing.Point(10, 100);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(1090,330);
// this.panel1.TabIndex = 0;
// this.panel1.Width = this.ClientSize.Width;
// this.panel1.Height = this.ClientSize.Width;
// this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel1.AutoScroll = true;
this.panel1.BackColor = Color.DimGray;
this.Controls.Add(this.panel1);
// 텍스트 박스 생성 및 추가
this.result1 = new System.Windows.Forms.TextBox();
this.result1.Name = "resul1";
this.result1.Multiline = true;
this.result1.Location = new System.Drawing.Point(0, 0);
this.result1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.result1.Dock = System.Windows.Forms.DockStyle.Fill; // Dock 속성 설정
this.result1.Text = "";
// 텍스트 박스의 크기와 위치를 조정
// this.result1.Width = this.panel1.ClientRectangle.Width;
// this.result1.Height = this.panel1.ClientRectangle.Height;
this.panel1.Controls.Add(this.result1);
}
#endregion
}
간단하게 'Hello World'만 return하는 서버를 만들어 두었습니다. Github에서 해당 서버로 자동배포하는 것까지 구성은 못해서 FTP로 일일이 옮겨넣었습니다.
var express = require('express');
var app = express();
var user = require('./routes/user');
const cors = require('cors');
app.use(cors());
app.get('/', function (req, res) { // 기본 root('/') 는 main.js에서 routing
res.send('Hello World');
});
//app.use('/user', user); // 나머지 접근은 router(/routes/user)에서 routing
app.listen(3000, function () { // 3000 포트로 서버 실행
console.log('Example App is listening on port 3000');
});
소스코드에 보시면, 다른 서버로부터의 요청이 허용되도록 app.use(cors())를 선언해줘야합니다.
[[redirects]]
from = "/api/*"
to = "http://1xx.6xx.2xx.2xx:3000/:splat"
status = 200
force = true
oracle 서버에서 cors 허용을 해놓았는데도 원래의 주소로 request를 보내면 오류가 납니다. 이유는 oracle에서는 http로 서비스를 하고 있고, netlify에서는 https로 서비스를 하고 있어서 그렇습니다. oracle에도 https서비스를 위한 인증서를 구해서 넣으면 좋지만, 위와 같이 proxy 우회 방법으로 간단히 두 서버간 통신이 가능합니다.