2017년 11월 27일 월요일

発音インフォ

英語の発音の確認
http://en.hatsuon.info/word/value

契約画面

1. 契約検索画面

CSV出力処理
子画面の動きをまだ確認してない。
子画面
1.見積もり検索画面
2.契約検索画面
3.受注検索画面
4.テンプレート選択画面

1.  契約メイン画面

キャンセルボタン
  契約メイン画面をそのまま、閉じる。


流用ボタン
メイン画面の流用ボタンがクリックされたときの処理を実装する。
 
検索画面から、選択された契約の情報で、照会モードで、メイン画面へ繊維する。
当契約情報をベースにして、流用機能を実装する。 

質問。
 新規モードで、登録した後、すぐ流用機能を使えるか?
 --> 登録した後は、メイン画面が閉じられるから、流用機能は使えない。
 照会モードでしか使えない。

1. ワークフローと関係あるか?
1. 登録ボタンが活性化状態になる。
1. 照会モードの契約情報を利用して、新規登録する。
1. 各項目の値チェック処理
1. 申請ボタン ---> 活性化か無効化か?
1. 処理ボタン  ---> 活性化か無効化か?
1. 訂正ボタン ---> 活性化か無効化か?
1. キャンセルボタン ---> 活性化
1. 当契約のリビジョン番号はどうなる?
1. 契約番号と、見積もり番号も変更可能か?
1. 排他チェック
1. 保存すると、画面を閉じるか?検索画面に繊維する。


訂正ボタンの処理
1. ワークフローと関係あるか?
1. 編集の意味と同じなのか?
1. 契約検索画面から、繊維して、訂正ボタンをクリックした場合、
1. 照会モードから、訂正モードに変更。
1. 各項目の変更が可能になるように、実装する。
1. 登録ボタンで保存するのか?
1. 申請ボタン ---> 有効化か無効化か?
1. 処理ボタン  ---> 有効化か無効化か?
1. 各項目の値チェック処理
1. 当契約のリビジョン番号はどうなる?
1. 契約番号と、見積もり番号も変更可能か?
1. 排他チェック
1. 保存は、登録ボタンでする?
1. 保存すると、画面を閉じるか?検索画面に繊維する。


照会モード
1. すべての項目をreadonlyにしておく。
1. 登録ボタン無効化すること。 
1. 訂正ボタンを活性化する。---> 当契約情報を修正する。
1. 流用ボタンを活性化する。---> 当契約情報を修正する。
1. 訂正機能と、流用機能の違いは?
1. キャンセルボタン有効化すること。
1. 申請ボタン --> 無効化?
1. 処理ボタン --> 無効化?




新規モード
1. 登録ボタン有効化すること。
1. 登録した後、画面が閉じられる。
1. メイン画面の新規登録時の初期処理
1. 申請ボタンは、無効化すること。
1. 処理ボタン、無効化すること。
1. 流用ボタン、無効化すること。
1. 訂正ボタン、無効化すること。
1. キャンセルボタン有効化すること。
1. 各項目の値チェック処理
1. 排他チェック
1. 登録ボタンで、保存すると、画面を閉じるか?検索画面に繊維する。
1. 新規登録するとき、個別の現場情報と、すべての現場情報をどのように保存するか?
1. 自動計算された情報をどのように、保存するか?
1. 各グリッドのデータ保存方法は?--->DBへ

1. 申請ボタン
   ワークフロー

1. 処理ボタン
   ワークフロー

1. 画面繊維処理
    検索画面から、メイン画面に繊維するときの処理
 
1. 保守詳細表示と設定

1. 自動計算

1. ファイルのアップロード

1. メイン画面の初期表示
照会モードのとき
新規登録モードのとき
流用ボタンがクリックされたとき
訂正ボタンがクリックされたとき


1. メイン画面と、子画面とのやりとり

1. 子画面作成

2017년 11월 26일 일요일

컴퓨터에서 사용하는 용량 단위

컴퓨터에서 사용하는 용량 단위
관례적 표기 IEC prefix 내용
이름 기호 이름 기호 2진 기준 값 (Byte)
kilo byte KB kibi byte KiB 210 Byte 1,024 Byte
mega byte MB mebi byte MiB 220 Byte 1,048,576 Byte
giga byte GB gibi byte GiB 230 Byte 1,073,741,824 Byte
tera byte TB tebi byte TiB 240 Byte 1,099,511,627,776 Byte
peta byte PB pebi byte PiB 250 Byte 1,125,899,906,842,624 Byte
exa byte EB exbi byte EiB 260 Byte 1,152,921,504,606,846,976 Byte
zetta byte ZB zebi byte ZiB 270 Byte 1,180,591,620,717,411,303,424 Byte
yotta byte YB yobi byte YiB 280 Byte 1,208,925,819,614,629,174,706,176 Byte

spring framework2


import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class OrgSearchBLogicImpl implements OrgSearchBLogic {

    /** 組織サービス. */
    @Autowired
    private OrgService orgService;

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.app.blogic.OrgSearchBLogic#execute(com.isurp.neo.app.dto.
     * OrgSearchBLogicInputDto)
     */
@Override
public OrgSearchBLogicOutputDto execute(OrgSearchBLogicInputDto inputDto) {
MOrgExample example = new MOrgExample();

// 検索要求元より、組織名称で検索を要求した場合。
// 組織名称がなにもない場合、
if (inputDto.getOrgName() != "") {
example.createCriteria().andDeleteFlagEqualTo(DeleteFlagEnum.OFF.getValue())
.andOrgNameLike(inputDto.getOrgName()).andCompanyCodeEqualTo(inputDto.getCompanyCode());
} else
// 組織名称が指定されている場合、
{
example.createCriteria().andDeleteFlagEqualTo(DeleteFlagEnum.OFF.getValue());
}

List<MOrg> list = orgService.selectByExample(example);
OrgSearchBLogicOutputDto outputDto = new OrgSearchBLogicOutputDto();
outputDto.setList(list);
return outputDto;
}

}

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class OrgSearchController {
   
    /** 組織検索BLogic. */
    @Autowired
    private OrgSearchBLogic orgSearchBLogic;
   
/**
* AJAX用メソッド.
*
* @param criteria
*            組織検索クリテリア
* @return 組織検索結果クラス.
*/
@RequestMapping(value = "/org/search/ajax", method = { RequestMethod.GET, RequestMethod.POST })
@ResponseBody
public OrgSearchResult search(@AuthenticationPrincipal final CustomUserDetails userDetails,
@Validated OrgSearchCriteria criteria) {

OrgSearchBLogicInputDto inputDto = new OrgSearchBLogicInputDto();
// 組織名称とユーザーの会社コードを設定しておく。
inputDto.setOrgName(criteria.getOrgName());
inputDto.setCompanyCode(userDetails.getMUser().getCompanyCode());

OrgSearchBLogicOutputDto outputDto = orgSearchBLogic.execute(inputDto);
OrgSearchResult searchResult = new OrgSearchResult();
searchResult.setList(outputDto.getList());
return searchResult;
}
}

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.terasoluna.gfw.common.exception.BusinessException;

@Service
@Transactional
public class HinmokuDeleteConfirmDeleteBLogicImpl implements HinmokuDeleteConfirmDeleteBLogic {

    /** 品目サービス. */
    @Autowired
    private HinmokuService hinmokuService;

    /**
     * ロジック実行.
     * 
     * @param inputDto
     *            ロジックパラメータ
     * @return ロジック結果
     */
    @Override
    public HinmokuDeleteConfirmDeleteBLogicOutputDto execute(final HinmokuDeleteConfirmDeleteBLogicInputDto inputDto) {

        MHinmoku mHinmokuBefore = inputDto.getmHinmoku();

        String key = mHinmokuBefore.getHinmokuCode();

        MHinmoku selectedMHinmoku = hinmokuService.selectByPrimaryKey(key);

        // 値チェック
        validate(mHinmokuBefore, selectedMHinmoku);

        // 削除フラグを有効で設定。
        Date updateDate = Timestamp.valueOf(LocalDateTime.now());
        selectedMHinmoku.setDeleteFlag(DeleteFlagEnum.ON.getValue());
        selectedMHinmoku.setUpdateDate(updateDate);
        selectedMHinmoku.setUpdateUserId(inputDto.getUpdateUserId());

        // 品目
        int deleteResultCount = hinmokuService.updateByPrimaryKey(selectedMHinmoku);

        if (deleteResultCount <= 0) {
            throw new BusinessException("e.ne.fw.9001");
        }

        return new HinmokuDeleteConfirmDeleteBLogicOutputDto();
    }

    /**
     * 検証.
     * 
     * @param mHinmokuBefore
     *            更新前の品目情報
     * @param selectedMHinmoku
     *            DBの品目情報
     */
    private void validate(MHinmoku mHinmokuBefore, MHinmoku selectedMHinmoku) {

        LocalDateTime temp = LocalDateTime.ofInstant(mHinmokuBefore.getUpdateDate().toInstant(),
                ZoneId.systemDefault());
        DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

        LocalDateTime tempSelect = LocalDateTime.ofInstant(selectedMHinmoku.getUpdateDate().toInstant(),
                ZoneId.systemDefault());

        System.out.println("Select = " + tempSelect.format(formatter));
        System.out.println("Before = " + temp.format(formatter));

        //DB情報の更新日時が既に更新されている場合
        if (selectedMHinmoku.getUpdateDate().after(mHinmokuBefore.getUpdateDate())) {
            throw new BusinessException("e.ne.fw.9001");
        }

    }
}
<meta name="contextPath" content="${pageContext.request.contextPath}" />
<script type="text/javascript">
var contextPath = $("meta[name='contextPath']").attr("content");

$(document).ready(function() {
$('#confirm').click(function() {
$('#HokanbashoRegistForm').submit();
});
$('#cancel').click(function(){
document.location.href = "${pageContext.request.contextPath}/admin/master/hokanbashoRegist/cancel";
});
// 組織検索ボタンの押下時、処理
$('#selectOrgButton').click(function() {
//alert("contextPath:"+contextPath);
searchOrg();
});
// モダル画面の組織検索ボタンが押下された場合
$('#selectOrgModalButton').click(function() {
//alert("contextPath:"+contextPath);
searchOrg();
});
// モダル画面の閉じるボタンが押下された場合
    $("#modalClose").click(function() {
    $("#orgName").val("");
    });
});
// 組織検索
function searchOrg() {
    $.ajax(contextPath + "/org/search/ajax", {
        data : $("#OrgSerachModelForm").serialize(),
        dataType : "json",

    }).done(function(json) {
//alert("json:"+json.list);
//結果を画面に表示する。
var titleStr = "<tr><th></th><th>コード</th><th>名称</th></tr>"
var str = titleStr;
var length = parseInt(Object.keys(json.list).length);

$('#org_list').empty();
$('#modal_org_list_message').empty();
//読み込んだデータが0件の場合は、エラーメッセージを表示する。
//もし、データがあれば、データをtable形式で表示する。
if (length <= 0) {
$('#modal_org_list_message').append("<p>組織データがありません。</p>");
} else if (length > 0) {
$.each(json.list, function(index) {
str = str + "<tr><td>" + 
"<button type='button' class='btn btn-primary btnSelected" + index + "'" + "id='selectBtn'>Select</button>" + "</td>" +
"<td style='vertical-align:middle'><span>" + json.list[index].orgCode + "</span></td><td style='vertical-align:middle'><span>" + json.list[index].orgName + "</span></td></tr>";
});
$('#org_list').append(str);
// 各行のごとに、selectボタンにクリックイベントをバインドしておく。
$.each(json.list, function(index) {
$(".btnSelected" + index).on("click", function() {
        var orgCode = $(this).closest('td').next('td').find('span').text();
        var orgName = $(this).closest('td').next('td').next('td').find('span').text();
        //alert(orgCode + " / " + orgName);
        $('#kanriOrgId').val(orgCode);
        $('#kanriOrgName').val(orgName);
        
        //閉じる。
        $("#modalClose").click();
});
});
}

}).fail(function(xhr) {
$('#modal_org_list_message').append(xhr);
});
    
return false;
}
</script>
<style>
.modal-header{
background-color:#00cc00;
color:#ffffff;
}
</style>
<div class="container">
<h2 class="page-header">
<spring:message code="web.admin.master.hokanbashoRegist.headerTitle" />
</h2>
<p>
<font color="red"><spring:message
code="web.admin.master.hokanbashoRegist.messageForMarkedFields" /></font>
</p>
<form:form class="form-horizontal"
modelAttribute="hokanbashoRegistForm" method="post"
action="${pageContext.request.contextPath}/admin/master/hokanbashoRegist/confirm"
id="HokanbashoRegistForm" name="HokanbashoRegistForm">
<form:errors path="*" />
<div class="form-group">
<label class="col-sm-3 control-label" for="plant"><spring:message
code="web.admin.master.hokanbashoRegist.plant" /><font color="red">&nbsp;*</font></label>
<div class="col-sm-8">
<select id="plantCode" name="plantCode" class="form-control">
<c:forEach var="item" items="${mPlantMap}">
<c:if test="${item.key == mHokanbasho.plantCode}"><option value="${item.key}" selected>${item.value}</option></c:if>
<c:if test="${item.key != mHokanbasho.plantCode}"><option value="${item.key}" >${item.value}</option></c:if>
</c:forEach>
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="hokanbashoCode"><spring:message
code="web.admin.master.hokanbashoRegist.hokanbashoCode" /><font
color="red">&nbsp;*</font></label>
<div class="col-sm-8">
<form:input type="text" path="hokanbashoCode" class="form-control"
value="${mHokanbasho.hokanbashoCode}" />
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="hokanbashoName"><spring:message
code="web.admin.master.hokanbashoRegist.hokanbashoName" /><font
color="red">&nbsp;*</font></label>
<div class="col-sm-8">
<form:input type="text" path="hokanbashoName" class="form-control"
value="${mHokanbasho.hokanbashoName}" />
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="kanriOrgName"><spring:message
code="web.admin.master.hokanbashoRegist.kanriOrgName" /><font
color="red">&nbsp;*</font></label>
<div class="col-sm-8">
<div class="form-inline">
<form:input type="hidden" path="kanriOrgId"
value="${mHokanbasho.kanriOrgId}" />
<div class="form-group col-sm-2">
<button type="button" class="btn btn-primary" id="selectOrgButton" data-toggle="modal" data-target="#orgSearchModal">
<spring:message
code="web.admin.master.hokanbashoRegist.selectOrgButton" />
</button>
</div>
<div class="form-group col-sm-10">
<form:input type="text" path="kanriOrgName" class="form-control" style="width:100%"
value="${mHokanbasho.kanriOrgName}" />
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="hokanbashoKbn"><spring:message
code="web.admin.master.hokanbashoRegist.hokanbashoKbn" /><font
color="red">&nbsp;*</font></label>
<div class="col-sm-8">
<c:forEach var="hokanbashoKbnItem" items="${CL_HOKANBASHO_KBN}"
varStatus="hokanbashoKbnStatus">
<label class="radio-inline">
<input type="radio" name="hokanbashoKbn"
<c:choose>
<c:when test="${!empty mHokanbasho.hokanbashoKbn}">
<c:if test="${hokanbashoKbnItem.key == mHokanbasho.hokanbashoKbn}">checked</c:if>
</c:when>
<c:otherwise>
<c:if test="${hokanbashoKbnStatus.index == 0}">checked</c:if>
</c:otherwise>
</c:choose>
value="${hokanbashoKbnItem.key}">
<spring:message code="${hokanbashoKbnItem.value}" />
</label>
</c:forEach>
</div>
</div>
<!-- danaExist Flag  -->
<div class="form-group">
<label class="col-sm-3 control-label" for=danaExistFlag><spring:message
code="web.admin.master.hokanbashoRegist.danaExistFlag" /><font
color="red">&nbsp;*</font></label>
<div class="col-sm-8">
<c:forEach var="danaExistFlagItem" items="${CL_DANA_EXIST_FLAG}"
varStatus="danaExistFlagStatus">
<label class="radio-inline">
<input type="radio" name="danaExistFlag"
<c:choose>
<c:when test="${!empty mHokanbasho.danaExistFlag}">
<c:if test="${danaExistFlagItem.key == mHokanbasho.danaExistFlag}">checked</c:if>
</c:when>
<c:otherwise>
<c:if test="${danaExistFlagStatus.index == 0}">checked</c:if>
</c:otherwise>
</c:choose>
value="${danaExistFlagItem.key}">
<spring:message code="${danaExistFlagItem.value}" />
</label>
</c:forEach>
</div>
</div>
<!-- yoko flag -->
<div class="form-group">
<label class="col-sm-3 control-label" for="yukoFlag"><spring:message
code="web.admin.master.hokanbashoRegist.yukoFlag" /><font
color="red">&nbsp;*</font></label>
<div class="col-sm-8">
<c:forEach var="yukoFlagItem" items="${CL_YUKO_FLAG}"
varStatus="yukoFlagStatus">
<label class="radio-inline">
<input type="radio" name="yukoFlag"
<c:choose>
<c:when test="${!empty mHokanbasho.yukoFlag}">
<c:if test="${yukoFlagItem.key == mHokanbasho.yukoFlag}">checked</c:if>
</c:when>
<c:otherwise>
<c:if test="${yukoFlagStatus.index == 0}">checked</c:if>
</c:otherwise>
</c:choose>
value="${yukoFlagItem.key}">
<spring:message code="${yukoFlagItem.value}" />
</label>
</c:forEach>
</div>
</div>
<!-- confirm, cancel button -->
<div>
<button type="button" class="btn btn-primary" id="confirm">
<spring:message code="web.admin.master.hokanbashoRegist.confirm" />
</button>
<button type="button" class="btn btn-primary" id="cancel">
<spring:message code="web.admin.master.hokanbashoRegist.cancel" />
</button>
</div>
</form:form>
</div>

<!-- Modal -->
<div class="modal" id="orgSearchModal" role="dialog">
<div class="modal-dialog">

<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<label><spring:message code="web.admin.master.hokanbashoRegist.organizationSearchTitle"></spring:message></label>
</div>
<div class="modal-body">
<div style="margin: 0px 0px 20px 0px;text-align:right">
<form class="form-horizontal" id="OrgSerachModelForm" name="OrgSerachModelForm">
<form:errors path="*" />
<div style="display:inline-block">
<input type="text" class="form-control" id="orgName" name="orgName"
placeholder="<spring:message code="web.admin.master.hokanbashoRegist.organizationSearchModalOrgNamePlaceholder"></spring:message>">
</div>
<div style="display:inline-block">
<button type="button" class="btn btn-primary" id="selectOrgModalButton">
<spring:message code="web.admin.master.hokanbashoRegist.organizationSearchModalSearchBtnName"></spring:message>
</button>
</div>
</form>
</div>

<div>
<table id="org_list" class="table table-striped">

</table>
</div>
<div id="modal_org_list_message">
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary pull-Right" data-dismiss="modal" id="modalClose">
<spring:message code="web.admin.master.hokanbashoRegist.organizationSearchModalCancelBtnName"></spring:message>
</button>
</div>
</div>
</div>
</div>

스프링 프레임워크1

        if (mHokanbasho == null) {
            throw new BusinessException("e.ne.fw.9001");
        }

        Date createDate = Timestamp.valueOf(LocalDateTime.now());
        mHokanbasho.setCreateDate(createDate);
        mHokanbasho.setUpdateDate(createDate);
        mHokanbasho.setCreateUserId(inputDto.getUpdateUserId());
        mHokanbasho.setUpdateUserId(inputDto.getUpdateUserId());


        HashMap<String, String> mPlantMap = new HashMap<String, String>();
        mPlantMap.put("", " ");

        for (MPlant targetMPlant : mPlant) {
            mPlantMap.put(targetMPlant.getPlantCode(), targetMPlant.getPlantName());
        }

        LocalDateTime temp = LocalDateTime.ofInstant(mHokanbashoBefore.getUpdateDate().toInstant(),
                ZoneId.systemDefault());
        DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

        LocalDateTime tempSelect = LocalDateTime.ofInstant(selectedMHokanbasho.getUpdateDate().toInstant(),
                ZoneId.systemDefault());

        System.out.println("Select = " + tempSelect.format(formatter));
        System.out.println("Before = " + temp.format(formatter));

        if (selectedMHokanbasho.getUpdateDate().after(mHokanbashoBefore.getUpdateDate())) {
            throw new BusinessException("e.ne.fw.9001");
        }


@Override
public PlantRegistConfirmRegisterBLogicOutputDto execute(final PlantRegistConfirmRegisterBLogicInputDto inputDto) {

MPlant mPlant = inputDto.getmPlant();

MPlantKey key = new MPlantKey();
key.setCompanyCode(mPlant.getCompanyCode());
key.setPlantCode(mPlant.getPlantCode());
MPlant selectedMPlant = plantService.selectByPrimaryKey(key);

// 重複データがある場合、エラー
if (selectedMPlant != null) {
throw new BusinessException("e.ne.fw.9001");
}

Date createDate = Timestamp.valueOf(LocalDateTime.now());
mPlant.setCreateDate(createDate);
mPlant.setUpdateDate(createDate);
mPlant.setDeleteFlag(DeleteFlagEnum.OFF.getValue());
mPlant.setCreateUserId(inputDto.getUpdateUserId());
mPlant.setUpdateUserId(inputDto.getUpdateUserId());

// プラント
plantService.insert(mPlant);

return new PlantRegistConfirmRegisterBLogicOutputDto();

}


generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
  <classPathEntry location="C:\Users\sawaki\.m2\repository\org\postgresql\postgresql\9.4.1209.jre7\postgresql-9.4.1209.jre7.jar" />
  <context id="context1">
    <jdbcConnection connectionURL="jdbc:postgresql://postgre1.isurp.com:5432/activiti_spring" driverClass="org.postgresql.Driver" password="isurp1234" userId="isurp" />
    <javaModelGenerator targetPackage="com.isurp.neo.domain.model" targetProject="neo-domain/src/generated/java" />
    <sqlMapGenerator targetPackage="com.isurp.neo.domain.repository" targetProject="neo-domain/src/generated/resources" />
    <javaClientGenerator targetPackage="com.isurp.neo.domain.repository" targetProject="neo-domain/src/generated/java" type="XMLMAPPER" />
    <table schema="public" tableName="m_user"></table>
    <table schema="public" tableName="m_hinmoku"></table>
    <table schema="public" tableName="m_plant"></table>
    <table schema="public" tableName="m_hokanbasho"></table>
    <table schema="public" tableName="t_user_role"></table>
  </context>
</generatorConfiguration>

==================================================

import javax.inject.Inject;
import javax.validation.Valid;

import org.dozer.Mapper;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;

@Controller
@RequestMapping(value = "admin/master/plantRegist")
@SessionAttributes("scopedTarget.plantRegistSession")
public class PlantRegistController {

    /** プラント登録用セッション. */
    @Inject
    private PlantRegistSession plantRegistSession;

    /** Mapper. */
    @Inject
    private Mapper mapper;

    /**
     * プラント登録フォーム設定.
     *
     * @return プラント登録フォーム
     */
    @ModelAttribute
    public PlantRegistForm setUpPlantRegistForm() {
        return new PlantRegistForm();
    }

    /**
     * プラント登録用セッション設定.
     *
     * @return プラント登録用セッション
     */
    @ModelAttribute("plantRegistSession")
    public PlantRegistSession setUpPlantRegistSession() {
        return plantRegistSession;
    }

    /**
     * 初期表示.
     *
     * @param model
     *            モデル
     * @return ビュー
     */
    @RequestMapping(value = "init")
    public String init(Model model) {
        return "admin/master/plantRegist";
    }

    /**
     * 前画面からの戻るイベントによる初期表示.
     *
     * @param model
     *            モデル
     * @return ビュー
     */
    @RequestMapping(value = "initBack", method = { RequestMethod.GET, RequestMethod.POST })
    public String initBack(Model model) {

        // 情報追加
        model.addAttribute("plantCode", plantRegistSession.getmPlant().getPlantCode());
        model.addAttribute("plantName", plantRegistSession.getmPlant().getPlantName());
        model.addAttribute("spart", plantRegistSession.getmPlant().getSpart());
        model.addAttribute("yukoFlagValue", plantRegistSession.getmPlant().getYukoFlag());

        return "admin/master/plantRegist";
    }

    /**
     * プラント情報確認.
     *
     * @param userDetails
     *            ログインユーザー情報
     * @param plantRegistForm
     *            プラント登録フォーム
     * @param result
     *            バリデーション結果
     * @param model
     *            モデル
     * @return ビュー
     */
    @RequestMapping(value = "confirm", method = RequestMethod.POST)
    public String confirm(@AuthenticationPrincipal final CustomUserDetails userDetails,
            @Valid @ModelAttribute final PlantRegistForm plantRegistForm, final BindingResult result, Model model) {

        // フォームに設定された値にエラーがある場合
        if (result.hasErrors()) {

            // 登録画面に戻る
            return "admin/master/plantRegist";
        }

        // プラント
        MPlant mPlant = new MPlant();
        mapper.map(plantRegistForm, mPlant);
        mPlant.setCompanyCode(userDetails.getMUser().getCompanyCode());
        plantRegistSession.setmPlant(mPlant);

        model.addAttribute("mPlant", mPlant);

        return "redirect:/admin/master/plantRegistConfirm";
    }

    /**
     * 一覧画面に戻る.
     *
     * @param sessionStatus
     *            セッション情報
     * @return ビュー
     */
    @RequestMapping(value = "cancel", method = { RequestMethod.GET, RequestMethod.POST })
    public String cancel(final SessionStatus sessionStatus) {
        sessionStatus.setComplete();
        plantRegistSession.clear();
        return "redirect:/admin/master/plant/init";
    }
}
==================================================

AbstractService.java

import java.util.List;
import org.apache.ibatis.annotations.Param;

/**
 *
 * @param <M>
 *            モデル
 * @param <K>
 *            キー
 * @param <Q>
 *            条件
 */
public interface AbstractService<M, K, Q> {

    /**
     * 条件による件数取得.
     *
     * @param example
     *            条件
     * @return 条件による件数
     */
    long countByExample(Q example);

    /**
     * 条件による削除.
     *
     * @param example
     *            条件
     * @return 削除件数
     */
    int deleteByExample(Q example);

    /**
     * キーによる削除.
     *
     * @param key
     *            キー
     * @return 削除件数
     */
    int deleteByPrimaryKey(K key);

    /**
     * 登録.
     *
     * @param record
     *            モデル
     * @return 登録件数
     */
    int insert(M record);

    /**
     * モデルに値がnullでない項目を登録.
     *
     * @param record
     *            モデル
     * @return 登録件数
     */
    int insertSelective(M record);

    /**
     * 条件によるモデルのリスト取得.
     *
     * @param example
     *            条件
     * @return 条件による検索結果
     */
    List<M> selectByExample(Q example);

    /**
     * キーによるモデルの取得.
     *
     * @param key
     *            キー
     * @return キーによる検索結果
     */
    M selectByPrimaryKey(K key);

    /**
     * 条件によるモデルに値がnullでない項目で更新.
     *
     * @param record
     *            モデル
     * @param example
     *            条件
     * @return 更新件数
     */
    int updateByExampleSelective(@Param("record") M record, @Param("example") Q example);

    /**
     * 条件によるモデルの項目で更新.
     *
     * @param record
     *            モデル
     * @param example
     *            条件
     * @return 更新件数
     */
    int updateByExample(@Param("record") M record, @Param("example") Q example);

    /**
     * モデルのキーによるモデルに値がnullでない項目で更新.
     *
     * @param record
     *            モデル
     * @return 更新件数
     */
    int updateByPrimaryKeySelective(M record);

    /**
     * モデルのキーによるモデルの項目で更新.
     *
     * @param record
     *            モデル
     * @return 更新件数
     */
    int updateByPrimaryKey(M record);
}

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

/**
 * プラントサービス.

@Service
public interface PlantService extends AbstractService<MPlant, MPlantKey, MPlantExample> {

    /**
     * @param pageable
     *            Pageable
     * @param example
     *            example
     * @return PlantViewPageDtoページ
     */
    Page<PlantViewPageDto> getPageByExample(Pageable pageable, MPlantExample example);

}

==================================================

package com.isurp.neo.domain.service;

import java.util.List;

import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.isurp.neo.domain.model.MPlant;
import com.isurp.neo.domain.model.MPlantExample;
import com.isurp.neo.domain.model.MPlantKey;
import com.isurp.neo.domain.model.PlantViewPageDto;
import com.isurp.neo.domain.repository.MPlantMapperExt;

@Service
@Transactional
public class PlantServiceImpl implements PlantService {

    /**
     *
     */
    @Autowired
    private MPlantMapperExt mPlantMapperExt;

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.domain.service.AbstractService#countByExample(java.lang.
     * Object)
     */
    @Override
    public long countByExample(MPlantExample example) {
        return mPlantMapperExt.countByExample(example);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.domain.service.AbstractService#deleteByExample(java.lang.
     * Object)
     */
    @Override
    public int deleteByExample(MPlantExample example) {
        return mPlantMapperExt.deleteByExample(example);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.domain.service.AbstractService#deleteByPrimaryKey(java.lang
     * .Object)
     */
    @Override
    public int deleteByPrimaryKey(MPlantKey key) {
        return mPlantMapperExt.deleteByPrimaryKey(key);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.domain.service.AbstractService#insert(java.lang.Object)
     */
    @Override
    public int insert(MPlant record) {
        return mPlantMapperExt.insert(record);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.domain.service.AbstractService#insertSelective(java.lang.
     * Object)
     */
    @Override
    public int insertSelective(MPlant record) {
        return mPlantMapperExt.insertSelective(record);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.domain.service.AbstractService#selectByExample(java.lang.
     * Object)
     */
    @Override
    public List<MPlant> selectByExample(MPlantExample example) {
        return mPlantMapperExt.selectByExample(example);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.domain.service.AbstractService#selectByPrimaryKey(java.lang
     * .Object)
     */
    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.domain.service.AbstractService#selectByPrimaryKey(java.lang
     * .Object)
     */
    @Override
    public MPlant selectByPrimaryKey(MPlantKey key) {
        return mPlantMapperExt.selectByPrimaryKey(key);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.domain.service.AbstractService#updateByExampleSelective(
     * java.lang.Object, java.lang.Object)
     */
    @Override
    public int updateByExampleSelective(MPlant record, MPlantExample example) {
        return mPlantMapperExt.updateByExampleSelective(record, example);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.domain.service.AbstractService#updateByExample(java.lang.
     * Object, java.lang.Object)
     */
    @Override
    public int updateByExample(MPlant record, MPlantExample example) {
        return mPlantMapperExt.updateByExample(record, example);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.domain.service.AbstractService#updateByPrimaryKeySelective(
     * java.lang.Object)
     */
    @Override
    public int updateByPrimaryKeySelective(MPlant record) {
        return mPlantMapperExt.updateByPrimaryKeySelective(record);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.domain.service.AbstractService#updateByPrimaryKey(java.lang
     * .Object)
     */
    @Override
    public int updateByPrimaryKey(MPlant record) {
        return mPlantMapperExt.updateByPrimaryKey(record);
    }

    // /* (non-Javadoc)
    // * @see
    // com.isurp.neo.domain.service.PlantService#getfindAllPages(org.springframework.data.domain.Pageable)
    // */
    // @Override
    // public Page<PlantViewPageDto> getfindAllPages(Pageable pageable) {
    // // 全件取得
    // RowBounds rowBounds = new RowBounds(pageable.getOffset(),
    // pageable.getPageSize());
    // long count = mPlantMapperExt.countByExample(null);
    // List<PlantViewPageDto> list =
    // mPlantMapperExt.selectPageByExample(rowBounds);
    // return new PageImpl<>(list, pageable, count);
    // }

    /*
     * (non-Javadoc)
     *
     * @see com.isurp.neo.domain.service.PlantService#getPageByExample(org.
     * springframework.data.domain.Pageable,
     * com.isurp.neo.domain.model.MPlantExample)
     */
    @Override
    public Page<PlantViewPageDto> getPageByExample(Pageable pageable, MPlantExample example) {
        // 全件取得
        RowBounds rowBounds = new RowBounds(pageable.getOffset(), pageable.getPageSize());
        long count = mPlantMapperExt.countByExample(example);
        List<PlantViewPageDto> list = mPlantMapperExt.selectViewPageByExample(rowBounds, example);
        return new PageImpl<>(list, pageable, count);
    }

}
==================================================

src/generated/java
---> package com.isurp.neo.domain.model;
table..

package com.isurp.neo.domain.repository;
table mapper

src/generated/resources
---> domain ---> repository ---> mapper.xml..

package com.isurp.neo.app.blogic;

import org.springframework.stereotype.Service;

import com.isurp.neo.app.dto.PlantManagementInitBLogicInputDto;
import com.isurp.neo.app.dto.PlantManagementInitBLogicOutputDto;

@Service
public interface PlantManagementInitBLogic {

    /**
     *
     * @param inputDto
     * @return
     */
    PlantManagementInitBLogicOutputDto excute(PlantManagementInitBLogicInputDto inputDto);

}


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

@Service
public class PlantManagementInitBLogicImpl implements PlantManagementInitBLogic {

    /**
     * プラントサービス.
     */
    @Autowired
    private PlantService plantService;

    /*
     * (non-Javadoc)
     *
     * @see
     * com.isurp.neo.app.blogic.PlantManagementInitBLogic#excute(com.isurp.neo.
     * app.dto.PlantManagementInitBLogicInputDto)
     */
    @Override
    public PlantManagementInitBLogicOutputDto excute(PlantManagementInitBLogicInputDto inputDto) {
        // 全件取得
        MPlantExample example = new MPlantExample();
        example.createCriteria().andCompanyCodeEqualTo(inputDto.getCompanyCode())
                .andDeleteFlagNotEqualTo(DeleteFlagEnum.ON.getValue());
        example.setOrderByClause("plant_code");
        Page<PlantViewPageDto> page = plantService.getPageByExample(inputDto.getPageable(), example);

        // 結果
        PlantManagementInitBLogicOutputDto outputDto = new PlantManagementInitBLogicOutputDto();
        outputDto.setPage(page);
        return outputDto;
    }

}


 */
@Service
public interface PlantRegistConfirmRegisterBLogic {

    /**
     *  ロジック実行.
     *
     * @param inputDto ロジックパラメータ
     * @return ロジック結果
     */
    PlantRegistConfirmRegisterBLogicOutputDto execute(PlantRegistConfirmRegisterBLogicInputDto inputDto);

}

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.terasoluna.gfw.common.exception.BusinessException;

@Service
@Transactional
public class PlantRegistConfirmRegisterBLogicImpl implements PlantRegistConfirmRegisterBLogic {

/** プラントサービス. */
@Autowired
private PlantService plantService;

/**
* ロジック実行.
*
* @param inputDto
*            ロジックパラメータ
* @return ロジック結果
*/
@Override
public PlantRegistConfirmRegisterBLogicOutputDto execute(final PlantRegistConfirmRegisterBLogicInputDto inputDto) {

MPlant mPlant = inputDto.getmPlant();

MPlantKey key = new MPlantKey();
key.setCompanyCode(mPlant.getCompanyCode());
key.setPlantCode(mPlant.getPlantCode());
MPlant selectedMPlant = plantService.selectByPrimaryKey(key);

// 重複データがある場合、エラー
if (selectedMPlant != null) {
throw new BusinessException("e.ne.fw.9001");
}

Date createDate = Timestamp.valueOf(LocalDateTime.now());
mPlant.setCreateDate(createDate);
mPlant.setUpdateDate(createDate);
mPlant.setDeleteFlag(DeleteFlagEnum.OFF.getValue());
mPlant.setCreateUserId(inputDto.getUpdateUserId());
mPlant.setUpdateUserId(inputDto.getUpdateUserId());

// プラント
plantService.insert(mPlant);

return new PlantRegistConfirmRegisterBLogicOutputDto();

}

}


일본어 단어정리

contract
カァントゥラァクトゥ | コォントゥラァクトゥ

estimate
エスタァマァトゥ

DNS 【 Domain Name System 】
燚 불 모양 일
驫 떼지어 달릴 표

사상
しそう [思想]
어떠한 사물에 대하여 가지고 있는
구체적인 사고나 생각.

とつげき[突撃]
공격 전투의 마지막 단계에 적진으로
돌진하여 공격함. 또는 그런 일.

腹黒い

くりこす[繰(り)越す] 이월하다, 차례로 다음으로 넘기다
よくげつ[翌月] 익월; 다음달.(↔반의어前月)

くりこす[繰(り)越す] 이월하다, 차례로 다음으로 넘기다
よくげつ[翌月] 익월; 다음달.(↔반의어前月)

UML

도조 히데키
국제 우호협정
지미 두리틀

도쿄 상경

こんしんかい[懇親会] 간친회.

御社 おんしゃ  귀사; 상대의 회사나 신사(神社) 등을 높여 부르는 말.
きしゃ[貴社]귀사(상대의 회사나 신사).
へいしゃ[弊社]폐사(자기 회사의 겸칭).

誘惑 Yūwaku 유혹
O nīchan お兄ちゃん
敏感 Binkan 민감

文脈 Bunmyaku 문맥
妥当 Datō 타당
さらす[晒す·曝す] 햇볕에 쬐다;또, 비바람을 맞히다,
바래다, 여러 사람의 눈에 띄게 하다

くりこす[繰(り)越す] 이월하다, 차례로 다음으로 넘기다
よくげつ[翌月]

익월; 다음달.(↔반의어前月)
ふせつ[敷設·布設] 부설.
しく[敷く] 깔다,
널리 깔리다, 퍼지다

しこうさくご[試行錯誤] 시행착오.
りんきおうへん[臨機応変] 임기응변.

Transport 차량, 이동 (방법)
Telemetry   텔레미터법, 원격 측정
プロトコル 프로토콜, (조약의) 의정서, 컴퓨터간의 데이터 통신을 원활히
 하기 위해서 정해 놓은, 통신 규약.

アンテナ(안테나)정보를 재빨리 능숙하게 포착하는
 능력. 촉각. 더듬이.

きょうい[脅威] 위협.

ふせん[付箋·附箋] 부전;

だいきぎょう[大企業] 대기업.(↔小企業)

きぼ[規模]  규모.

こうぼう[工房]공방; 조각가·화가·공예가가 일하는 방. (=アトリエ)

おしつける[押しつける·押し付ける]억누르다;강압하다,
강제로 시키다;강요하다きょうよう[強要] 강요.(=無理強い)

非営利 ひえいり
비영리 Institute US [|ɪnstɪtu:t]  (특히 교육・전문 직종과 관련된)기관[협회]

さくてい[策定] 책정.
しゅほう[手法] 수법; 기교.(=テクニック)
じゅうらい[従来] 종래.(=従前)
ちゃくもく[着目] 착목; 주목; 착안.
きばつ [奇抜] 기발.

ここのつ[九つ] 아홉; 또, 아홉 살.
たね[たね·種]종자;씨,원인, 거리;재료

じゅんかん[循環]  순환.
つましい[倹しい]검소하다,알뜰하다.
せんえつ[僭越]참월; 분수에 지나친 일을 함; 또, 그러한 태도.(=出しゃばり)

せんえつながら [僭越ながら]외람되지만.
つつましい[慎ましい]조심성스럽다;

조신하다; 얌전[음전]하다; 수줍다.
みみざわり[耳障り]귀에 거슬림.

ばれい[馬齢] 자기 나이를 겸손하게 이르는 말.
ばれいをかさねる [馬齢を重ねる](헛되이) 나이만
먹다.(=馬齢を加える)

きさく[気さく]담백하고 상냥함; 싹싹함.(=気軽)きがる[気軽]
사물에 구애치 않고, 선뜻선뜻 처신하는 모양: 소탈함; 선선함.(=きさく)↔...きがおけない
[気が置けない]마음이 쓰이지 않다; 스스럽지 않다; 무간하다.かかりつけ[掛(か)り付け]
언제나 그 의사의 진찰·치료를 받는 일.

かかり付けの医者 단골 의사

いきつけの喫茶店늘
다니는 다방

うしろがみをひかれる[後ろ髪を引かれる]뒷머리를 끌리는 것 같다(미련이 남아서
떨쳐 버릴 수 없다).

ひっかかる[引っ掛かる]걸리다, 무엇에 걸려 떨어지지 않다, 걸려들어
도중에 방해받다

みれん[未練]미련;단념하기 어려움, 미숙;아직 숙련되지 않음

たちきれる
[断(ち)切れる]たちきる[断(ち)切る]끊다; 잘라 버리다.[가능형]たちき-れる[하1단 자동사]

悲喜(ひきこもごも)至る(いたる) 희비가 엇갈리다

多摩川たまがわ新丸子しんまるこ武蔵小杉
むさしこすぎ元住吉 もとすみよし綱島 つなしま大倉山 おおくらやまかんこ실제로 할수잇는것을하자자이센

常盤 ときわ 영구불변

勝田 かつた 이바라키현 북부의 공업도시욧츠도

로나가타쵸에도카와쿠시이나쵸히가시나
가사키에코다토시마엔사쿠라다이
구이구이

스소구다루오모테우라용고키우치아와세 산카이하브하가유이

쿠시하칭 串八珍

インタラクティブ
内蔵 ないぞう
インタプリタ型容易 ようい
発揮 はっき
協調 きょうちょう
適合素朴

そぼく初歩 しょほ
多能性 たのうせい

HashMap

HashMap<String,String> hmap = HashMap<String,String>();
hmap.put("key1","val1");
hmap.put("key2","val2");
hmap.put("key3","val3");

String[] keys = hmap.keySet().toArray(new String[0]);

for(int i=0;i<keys.length;i++){
 String key = keys[i];
 String val = hmap.get(key);

 System.out.println(key+" : "+val);
}

Set key = map.keySet();
 
  for (Iterator iterator = key.iterator(); iterator.hasNext();) {
                   String keyName = (String) iterator.next();
                   String valueName = (String) map.get(keyName);
 
                   System.out.println(keyName +" = " +valueName);
  }

List<Map<String, String>> list2 = new ArrayList<Map<String, String>>();
Map<String, String> map2 = new HashMap<String, String>();
map2.put("Label", "未申請");
map2.put("Value", "1");
list2.add(map2);

Map<String, String> map3 = new HashMap<String, String>();
map3.put("Label", "申請中");
map3.put("Value", "2");
list2.add(map3);

Map<String, String> map4 = new HashMap<String, String>();
map4.put("Label", "申請済");
map4.put("Value", "3");
list2.add(map4);

List<Map<String, String>> listNew = new ArrayList<Map<String, String>>();

for (int i=0; i < list2.size(); i++)
{
Map<String, String> maptt = new HashMap<String, String>();
String[] keys = list2.get(i).keySet().toArray(new String[0]);
maptt.put(keys[0], list2.get(i).get(keys[0]));
maptt.put(keys[1], list2.get(i).get(keys[1]));
listNew.add(maptt);
}

Iterator iterator = map.entrySet().iterator();

while (iterator.hasNext()) {
Entry entry = (Entry)iterator.next();

System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());

HashMap은 key 와 value 쌍으로 존재하는 자료구조이다.
프로그래머가 key값을 알고 있는 상태에서 쓰는 경우도 있지만,
프로그래머가 동적으로 구한 데이터를 key, value 쌍으로
HashMap을 쓴 경우는 프로그래머도 key 값이 무엇이 들어갔는지 알 수가 없다.
arrayList 처럼 index 가 정해져 있는것도 아니라
순차적으로 Log 에 찍어보기도 애매하다.

오늘 포스팅 내용은 이러한 상황에서 HashMap key값이 무엇이 있는지
구하는것이다.

HashMap 클래스 내부구조로 Set 자료구조에 key를 보관한 객체가 존재한다.
Set 객체를 통해 key를 가져오는 것이다. Set 객체에 들어있는 값(key)를 iterator 인터페이스를 통해, 순차적으로 탐색할 준비를한다.

HashMap<String,String> hashMap = new HashMap<>();
hashMap.put("key","value");

Set set = hashMap.keySet();
Iterator iterator = set.iterator();

가져온 후, iterator를 통해 순차탐색한다.

while(iterator.hasNext()){
  String key = (String)iterator.next();
  System.out.println("hashMap Key : " + key);
}

Entry 객체를 이용한 방법도 있다.
Entry 객체를 이용하면 key 와 value를 동시에 구할 수 있다.
물론 위에 코드로 key값을 구한 후, hashMap.get(key) 로 value를 구해도 상관없다.

Set set = hashMap.entrySet();
Iterator iterator = set.iterator();

while(iterator.hasNext()){
  Map.Entry entry = (Map.Entry)iterator.next();
  String key = (String)entry.getKey();
  String value = (String)entry.getValue();
  System.out.println("hashMap Key : " + key);
  System.out.println("hashMap Value : " + value);
}

주의할 점은 Set 자료형에 keySet() 을 넣은 경우와 entrySet() 경우를 잘 구별해서 이용 해야한다.

Map<String, Integer> map = list.stream()      // 1. listをstream()に渡す。
    .collect(Collectors.toMap(   // 2. streamをcollect()メソッドに渡し、CollectorsクラスのMapインスタンス生成メソッドを実行します
    s -> s, // 3. Mapキーを取得するラムダ式
    s -> s.length() // 4. Mapの値を取得するラムダ式
));

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Main {

    public static void main(String[] args) {
        //Listの宣言
        List<String> list = new ArrayList<>();
       
        list.add("apple");
        list.add("orange");
        list.add("melon");
       
        //Mapの宣言
        Map<Integer, String> map = new HashMap<>();
       
        int i = 1;
        for(String str : list) {
            // MapにListの値を追加
            map.put(i, str);
            i++;
        }
       
        System.out.println(map);
    }

}

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Main {

    public static void main(String[] args) {
        //Listの宣言
        List<Integer> list = new ArrayList<>();
       
        list.add(1);
        list.add(2);
        list.add(3);
       
        //Mapの宣言
        Map<Integer, String> map = new HashMap<>();
       
        for(Integer num : list) {
            // MapにListのキーと値を追加
            map.put(num, "apple");
        }
       
        System.out.println(map);
    }

}

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Main {

    public static void main(String[] args) {
        //Mapの宣言
        Map<String, Integer> map = new HashMap<>();
        map.put("apple", 1);
        map.put("orange", 2);
        map.put("melon", 3);
       
        //Listを宣言し、valuesメソッドを使用して値を取得する
        List<Integer> list = new ArrayList<>(map.values());
        System.out.println(list);
    }

}

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Main {

    public static void main(String[] args) {
        //Mapの宣言
        Map<String, Integer> map = new HashMap<>();
        map.put("apple", 1);
        map.put("orange", 2);
        map.put("melon", 3);
       
        //Listを宣言し、keySetメソッドを使用してキーの値を取得する
        List<String> list = new ArrayList<>(map.keySet());
        System.out.println(list);
    }

}

  HashMap map = new HashMap();

  map.put("key01", "value01");
  map.put("key02", "value02");
  map.put("key03", "value03");
  map.put("key04", "value04");
  map.put("key05", "value05");         

  Set key = map.keySet();
 
  for (Iterator iterator = key.iterator(); iterator.hasNext();) {
                   String keyName = (String) iterator.next();
                   String valueName = (String) map.get(keyName);
 
                   System.out.println(keyName +" = " +valueName);
  }

<select>
  <option value="volvo">Volvo</option>
  <option value="saab">Saab</option>
  <option value="opel">Opel</option>
  <option value="audi">Audi</option>
</select>

$("#selectBtn").click(function() {
var target = document.getElementById("gender");
alert(target.options[target.selectedIndex].text);
//alert($('select option:selected').text());
});

 <input id="selectBtn" type="button" value="selectButton">
  <select id="gender" name="gender" class="style12">
    <option selected="selected">ALL</option>
    <option>Male Only</option>
    <option>Female Only</option>
</select>

<a href="https://www.w3schools.com" target="_blank">Visit W3Schools</a>

<form action="/action_page.php" method="get" target="_blank">
  First name: <input type="text" name="fname"><br>
  Last name: <input type="text" name="lname"><br>
  <input type="submit" value="Submit">
</form>

데이터단위

8 bit (비트)                  1 byte
1024 byte (바이트)          1 kilobyte
1024 kilobyte (킬로바이트)   1 megabyte
1024 megabyte (메가바이트)  1 gigabyte
1024 gigabyte  (기가바이트)  1 terabyte
1024 terabyte (테라바이트)   1 petabyte
1024 petabyte (페타바이트)   1 exabyte
1024 exabyte (엑사바이트)   1 zettabyte

데이터 타입   메모리의 크기 표현 가능 범위
byte            1 byte          -128 ~ 127
short            2 byte          -32,768 ~ 32,767
int            4 byte          -2,147,483,648~2,147,483,647
long            8 byte          -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807

1메가바이트는 ---> 1048576바이트다.
1024킬로바이트는 --> 1메가바이트이다.
1킬로바이트는 ---> 1024바이트다.

float a = 2.2F;
double a = 2.2;

int의 최댓값인 2147483647

byte -> short -> int -> long -> float -> double

2017년 11월 25일 토요일

합리와 감성 리더십

합리와 감성 리더십

[이정규 칼럼] 어려운 상황에 진짜 리더십 나온다

출처 - http://www.zdnet.co.kr/column/column_view.asp?artice_id=20171106110527

이정규 비즈니스IT 칼럼니스트

입력 : 2017.11.06.15:28
수정 : 2017.11.06.15:28

군대에 있을 때 얻은 창피한 트라우마가 있다.
가장 힘든 일명 말호봉의 때의 일이다.
폭력이 일상이 된 군대생활에서 선임의 구타를 면하기 위해 거짓말을 했다.
고참들은 식기가 깨끗하지 않다는 둥 자기 빨래를 찾아내라는 둥 하찮은 일로 트집을 잡았다.  “제가 하지 않았습니다.” 궁색한 내 변명 때문에 선임 밑의 부하들은 같이 고초를 겪어야 했다.

자신이 부끄러웠다. “어려운 상황은 내가 어떤 사람인지 비로소 드러나게 만든다.” 는 깨우침을 얻었다. 겁내지 않고 의연하게 살아왔다고 자신했지만 작은 시련에도 나약해지는 섣부른 자만심의 속살이 보였다.

군종 신부를 찾았다. 안수기도를 받으니 신기하게 폭력이 두렵지 않았다.
그다음 부터 “제가 그랬습니다. 시정하겠습니다.”라고 당당하게 맞섰다.
선임은 가슴팍을 치려던 주먹을 내려놓으며 “다음부터 잘해!”라 말했다.
거짓말 할 줄 알았던 내가 솔직하게 말하니 오히려 당황하는 듯 했다.
그 사건 이후에 괴롭히던 선임과 친해지게 되었다.


■ "충성심과 존경심은 관계의 산물"

사회생활에서 여러 상사를 만나게 된다. 분위기가 좋을 때는 좋기만 하던 선배나 상사가
궁지에 몰리면 후배에게 책임을 넘긴다. 협력업체에 재고를 밀어내고는 년말 매출목표를 채운다.

비용을 다음해로 넘기고 수익율을 부풀린다. 분식회계다. 매일같이 고함 치며 목표달성을 닥달한 상사는 책임져야 할 그 순간 “제가 시키지 않았습니다.” 하며 부하 뒤로 숨는다.

건망증이 있을 나이도 아닌데, 아침에 한 약속을 상사는 저녁에 뒤집는다.
고객에게 약속한 일, 협력사와 맺은 거래를 싹싹빌며 없던 것으로 해달라는 어려운 부탁은 부하의 몫이다.

정작 책일질 상사는 회사에 남고, 애궂은 부하만 징계를 받고 회사를 떠나기도 한다.

이처럼 “어려운 상황은 상사가 어떤 관리자인지 비로서 드러나게 만든다.”
난세에 리더가 부하들에게 신의와 의리를 지키는 일은 대개 자신의 직을 거는 위험한 일이다. 시험이 닥치면 부하들의 편에서 의리를 지킬지, 부하에게 책임을 씌우고 자리를 보전할지 고민이 시작된다.

중세의 마녀사냥에 쓰던 방법을 들었다.
물에 빠뜨린 다음에 마녀가 아니면 물에 가라앉을 것이고,
마녀라면 물위에 떠오를 것이니 죽이라는 것이다.
마녀로 내 몰린 여인은 죽어서 명예를 지킨다. 물위에 떠서 살았다한들 결국 생명을 부지할 어떤 방법도 없다. 리더에게 닥치는 도전이 이와 같다면 “본성 테스트”의 시간이다.

어려운 상황에서도 본성을 잃지 않고 인간애를 유지하는 상사를 만나는 것은 직장인에게는 은총이다.

다행히도 오랜 직장생활 동안 서너분의 좋은 상사를 만났다.
그분들과 지금도 좋은 관계를 유지하고 즐거이 만나고 있다.
그분들이 부르면 달려나가고, 몇개월 지나면 보고 싶고,
어려우면 조언을 청한다. 그러한 선배들과 같은 시대를 살아가는 일이 기쁨이다.
그분들과의 스토리가 접착제처럼 끈끈한 관계를 만든다.

왜 그럴까 생각해 보았다. 인간에 대한 최우선의 가치를 두는 진정성만큼 강한 리더십은 세상에 없다.

그들은 부당한 주먹이 뻗쳐올 때 자기 가슴팍을 대신 들이밀었다.
핑계의 시간에 “제 책임입니다.” 말했다. 상황을 설명하지 않아도,
부하들은 감성으로 리더의 마음을 읽는다. 드디어 관계 형성의 스토리가 만들어진다.
그러한 리더의 이름을 지워버리면, 자신의 성장을 설명할 수 없다.
불행한 일은 리더의 역량과 리더십은 그가 조직을 떠나고 나서야 알게된다.

장석주 작가와 만났다.
만날 때마다 귀한 지혜의 말씀을 주신다.
"20세기는 뭐든지 끌어 않는 사람의 세계이었다면,
21세기는 나누는 주는 사람, 주변에 자기 것을 넓게 뿌리는 사람의 세계"라는 말에 공감했다.

사회생활 사반세기를 지나 마침내 “사람을 움직이는 것은 지식이나 합리성이 아니라, 감성임”을 알게되었다. 합리성은 사람이 같은 방향을 보도록 만든다. 그러나 사람을 움직이게 만드는 것은 합리를 넘어선 감성이다. 감성이 사람을 모으고, 따라오게 만든다. 따르는 부하를 만드는 상사는 감성관리가 남다르다. 리더십은 부하에 대한 진솔한 존중과 배려에서 시작된다.

이렇게 만들어진 리더십은 조직의 경계에 구속되지 않는다.
엄격한 규율로 부터 조직에 대한 충성심, 상사에 대한 존경심이 생기는 것이 아니다.
충성심과 존경심은 관계의 산물이며, 공유된 가치와 상호간에 내어준 배려의 시간으로 부터 나온다. 요즈음 참다운 리더들이 그리운 시간이다.

칼럼니스트 : 이정규
이메일 dominiclee@naver.com

약력

현 케이씨에이 전문위원. 정보처리기술사, 미국회계사, IT수석감리원.
IT 다국적기업에서 16년, 컴퓨터 보안회사 본부장 및 대표 6년 ,
H그룹 계열사 기술연구소장으로 2년을 역임하였다.

5년간 스타트업 대표와 1 년간 비영리재단의 사무국장으로 일하였고,
3년간 KAIST 기술경영대학원에서 겸직교수로 벤처창업을 가르쳤다.
저서로는 “동시병행설계”와 “딥스마트”가 있다.
주된 관심분야는 지속가능 발전, 스타트업 창업경영과 프로세스 혁신이다.
네이버 사이트 검색어는 '딥스마트'다.

‘전원 연결하면 끝’ 어플라이언스 총정리

‘전원 연결하면 끝’ 어플라이언스 총정리

출처 - http://www.zdnet.co.kr/news/news_view.asp?artice_id=20121027073547

김우용 기자
입력 : 2012.10.27.13:59
수정 : 2012.10.28.07:30

가전제품처럼 전원만 연결하면 즉시 사용가능한 IT인프라제품, 어플라이언스가 인기를 얻고 있다.
서버, 스토리지, 네트워크 하드웨어와 운영체제, 애플리케이션 등을 벤더가
사전에 통합, 최적화해 판매하므로 시스템 구축 시간을 대폭 줄일 수 있기 때문이다.

오라클은 아예 어플라이언스를 완제품 자동차에 비유하기도 한다.
마크 허드 오라클 공동사장은 지난 9월 한국방문 당시 “자동차는 전문기술을 가진 회사의 완제품을 사면서,
왜 IT인프라는 고생을 자처하며 직접 조립하느냐”고 역설했다.

어플라이언스는 현재 거의 대부분의 회사들에서 제공된다.
어플라이언스가 최근들어 아주 새롭게 등장한 트렌드는 아니다.
10년전부터 소프트웨어와 하드웨어를 한번에 판매하는 트렌드는 이어져왔다.
다만, 전보다 더 저명한 벤더가 나서, 하드웨어와 소프트웨어의 최적화를 약속한다는 차이가 있다.

단순히 하드웨어와 소프트웨어를 통합한 것이라고 어플라이언스가 쉽기만 하지 않다.
어플라이언스에 대한 업계의 현황을 정리해본다.


스티브■‘범용 vs. 목적별’ 어플라이언스의 갈래

현재 어플라이언스 시장은 두 갈래로 나뉜다.
시스코-EMC V블록, 시스코-넷앱 플렉스포드, 델 V스타트, HP 클라우드시스템, IBM 퓨어플렉스 등 범용 어플라이언스가 한 갈래다.
다른 하나는 오라클 엑사시리즈, HP 앱시스템, IBM 퓨어애플리케이션 등 목적별 어플라이언스다.

선발주자였던 범용 어플라이언스 제품들이 확산에 힘든 시기를 겪는 반면,
목적별 어플라이언스는 출시 초기부터 빠르게 시장규모를 늘렸다.
이에 범용 어플라이언스를 내놨던 벤더도 애플리케이션 측면의 제품에 더 집중하고 있다.

어플라이언스 시장이 점차 특정 업무를 위한 목적별 어플라이언스로 수렴되는 모습이다.
통합 하드웨어에 가상화 수준까지만 제공해온 범용 어플라이언스도 점차 애플리케이션에 대한 최적화를 강화하고 있다.

대형 벤더의 어플라이언스는 테라데이타가 선도했다. 하지만 본격적인 어플라이언스 시장이 열린 시점은 2009년이다.
그 해 시스코, EMC는 각자의 하드웨어에 VM웨어 가상화 솔루션을 사전통합한 V블록을 출시했다.
V블록은 기본적인 IT인프라를 가상화 단계까지 완료해 공급되고, 구매자는 V블록에 애플리케이션을 따로 구매해 설치한다.

오라클은 그해 엑사데이터 버전2를 선보인다.
데이터베이스와 데이터웨어하우징(DW)에 특화된 제품이다.
처음 나온 엑사데이터는 오라클과 HP의 협력으로 만들어졌지만,
오라클은 썬마이크로시스템즈를 인수해 자신들만의 완제품으로 새롭게 내놨다.
웹로직을 위한 엑사로직 어플라이언스도 함께 나왔다.

이후 시스코는 넷앱과 손잡고 플렉스포드를 출시했다.
기본 콘셉트는 V블록과 같지만, 넷앱 스토리지를 사용한다는 점이 다르다.
그해 HP가 클라우드시스템을 내놨고, 델이 V스타트를 출시했다.

IBM은 올해 퓨어시스템이란 새로운 제품을 출시했다.
지난 4월 선보인 이 제품은 가상화 환경 구축을 위한
‘퓨어플렉스’와 애플리케이션 환경 구축을 위한 ‘퓨어애플리케이션’ 두종류로 나왔다.
그리고 이달 9일 데이터베이스와 관련된 ‘퓨어데이터’가 출시됐다.

HP는 작년 컨버지드인프라(CI) 제품군을 가상화와 VDI를 위한 버추얼시스템,
클라우드 구축을 위한 클라우드시스템, 애플리케이션 구축을 위한 앱시스템 등으로 분화했다.
이중 앱시스템은 MS SQL서버, 버티카, 통합커뮤니케이션(UC) 등 SW 파트너의 솔루션을 최적화해 제공하는 형태다.

■범용보다 목적별 어플라이언스가 더 대세

V블록, 플렉스포드, 클라우드시스템, V스타트 등은 특정 애플리케이션에 특화되지 않은 범용 제품이다.
클라우드 컴퓨팅이란 서비스형 인프라를 빠르게 구비하기 위한 용도다. IBM의 퓨어플렉스도 마찬가지이며,
오라클의 엑사로직도 본래 ‘엑사로직 엘라스틱 클라우드’란 정식명칭에서 나타나듯 클라우드 인프라를 위한 범용 제품에 가깝다.

이 제품들은 기본 구성에 애플리케이션을 포함하지 않기 때문에 엄밀한 의미로
어플라이언스라 부르기 힘들다. 오라클 엑사데이터와 HP 앱시스템, IBM 퓨어애플리케이션이 좁은 의미의 어플라이언스에 부합하는 제품이다.

V블록 이후 쏟아진 각사의 범용 어플라이언스들은 기대보다 더딘 성장을 보였다.
플렉스포드가 상대적으로 많은 판매량을 거뒀을 뿐이다. V블록은 출시 3년째에야
조금씩 반응을 얻기 시작했고, HP와 델의 제품들은 뚜렷한 레퍼런스조차 언급하지 못하는 처지다.

반면, 엑사데이터는 확실한 시장을 형성했다. 이미 테라데이타가 만들어 놓은
목적별 어플라이언스 시장에 성능과 SW 인스톨베이스를 무기로 뛰어든 만큼 확산이 어렵지 않았던 것으로 분석된다.

엑사데이터의 성공과 마찬가지로 HP의 앱시스템도 나름 좋은 성과를 거두고 있다.
HP는 기존 MS SQL서버 앱시스템 외에 SAP HANA용 앱시스템으로 속속 고객사를 확보하고 있다.

이런 흐름 속에서 각사는 범용 어플라이언스보다 목적별 어플라이언스에 집중하는 모습을 보이고 있다.
IBM이 퓨어시스템의 외연을 데이터분석 분야로 확대한 것이 대표적이다.

IBM은 전문가통합시스템 ‘퓨어시스템’에 데이터분석에 특화된
‘퓨어데이터’를 추가했다. 퓨어데이터는 업무환경에 따라 DB를 제공하기
위한 '퓨어데이터시스템 포 트랜잭션', 분석업무를 위한 '퓨어데이터시스템 포 애널리틱스',
분석역량을 녹인 운영최적화 용도를 겨냥한 '퓨어데이터세스템 포 오퍼레이셔널 애널리틱스'로 나뉜다.


■SW없는 벤더가 목적별 어플라이언스를 내놓는 방법

올해 사전통합플랫폼을 새로 선보인 히타치데이터시스템(HDS)과 델도 IBM이 걷는 행보와 유사하다.

HDS는 이달 11일 ‘유니파이드 컴퓨트 플랫폼(UCP)’을 출시했다.
UCP는 VM웨어 가상화, 클라우드 환경을 위한 UCP프로와 애플리케이션별로
구성을 달리해 제공되는 UCP셀렉트 등 두 종류로 나왔다.

델은 19일 ‘액티브 인프라스트럭처’란 새 통합제품을 선보였다.
액티브 인프라스트럭처는 가상화, 가상데스크톱인프라(VDI) 등을 쉽게 구축하고,
그 위에 마이크로소프트(MS 링크, 셰어포인트 등 애플리케이션을 클라우드 상에 쉽게 배포할 수 있도록 설계됐다.

구성요소를 모두 갖지 못한 시스코와 넷앱은 최근 플렉스포드에 클러스터모드를
탑재하면서 오라클 RAC 데이터베이스를 위한 인증 설계를 지원한다고 발표했다.
플렉스포드와 VM웨어 환경에 오라클 RAC 데이터베이스를 사용하는 최적화된 설계법을
제공한다는 의미다. 오라클 DB 시장을 겨냥한 목적별 어플라이언스로 볼 수 있다.

이뿐 아니다. 시스코와 넷앱은 ‘SAP HANA를 위한 시스코-넷앱 스케일아웃 솔루션’을
공개했다. 클라우드 상에 SAP HANA 환경을 쉽게 구축할 수 있다는 설명을 덧붙였다.

JP 반 스티어티그헴 시스코 월드와일드세일즈 CTO는 “시스코는 SAP, 오라클 같은
주요 애플리케이션 제공업체의 인증을 많이 받았고, 다양한 어플라이언스를 제공하고 있다”라며
“그밖에 그린플럼, 클라우데라처럼 새롭게 부각된 여러 빅데이터 솔루션과도 적극적으로 같이 협업하고 있다”고 설명했다.

벤더가 전면에 나서지 않고 파트너를 이용하는 OEM 어플라이언스 전략도 있다.
HP의 OEM 사업이 대표적이다. HP는 각국의 지역 SW개발사 솔루션을 OEM 어플라이언스 형태로
제공한다. 판매되는 어플라이언스는 HP의 ODP(OEM Development Partner)가 HP 하드웨어를 이용해 제작하고,
제품의 상표명은 솔루션 제작사가 짓는다. 한국의 경우도 티맥스 어플라이언스가 대표적이다.

EMC의 행보도 비슷하다. EMC는 올해 VSPEX란 브랜드를 발표했다. VSPEX는 EMC가 각 하드웨어,
소프트웨어 구성요소의 최적 조합을 만들어 레퍼런스 디자인으로 공개하고, 선정된 EMC 파트너가
솔루션을 최적화시켜 판매하는 어플라이언스다. 상표명은 EMC 파트너의 명칭을 사용한다.
국내에서
■어플라이언스를 사려는 사람의 심리

목적별 어플라이언스가 대세를 이루는 현상은 애플리케이션 중심의 접근을
선호하는 고객의 심리에서 기인한다.

애초부터 어플라이언스 구매의향을 가진 기업은 자신의 수고를 최소화해
곧바로 운영한다는 제품의 취지에 동의한 만큼 애플리케이션 구축까지 간소화하길 원한다.
클라우드 컴퓨팅 환경을 구축해서 알아서 쓰겠다는 생각은 별로 하지 않는다.

때문에 인프라 구축단계만 없애주는 범용 어플라이언스는 고객 접근이 힘들다는 한계를 갖게 된다.

범용 어플라이언스를 다양한 용도에 폭넓게 사용할 수 있다는 장점도 있긴 하다.
하지만 어플라이언스는 확장, 증설할 경우 벤더에 종속되는 상황을 만들어낸다.
이를 염려하는 고객은 용도에 따라 가격과 규모를 따져 어플라이언스를 고른다.

어플라이언스는 과거 ‘베스트오브브리드’라 불렸던 IT인프라 구축방식을 깨뜨리는
사업방식이다. 하지만 고객입장에서 베스트오브브리드는 사라지지 않는다.
과거 서버, 스토리지, 네트워크, OS, 애플리케이션 등 세부적으로 바라봤던 것이
애플리케이션이란 더 넓은 시야의 베스트오브브리드로 바뀌는 것이다.

하드웨어뿐 아니라 운영체제, 미들웨어, 애플리케이션 등 소프트웨어 스택을
폭넓게 보유한 IBM, 오라클 같은 회사는 목적별 어플라이언스를 강력하게 밀어붙인다.
상대적으로 SW 스택이 빈약한 HP나 델은 SW개발사를 파트너 삼아 애프리케이션에 최적화된
제품을 공급한다. 하드웨어 스택을 모두 갖추지 못한 시스코, EMC, 넷앱 같은 회사는
파트너 전략을 더 광범위하게 구사한다.

사이버 공격 대응하기 위한 6가지 비결

사이버 공격 대응하기 위한 6가지 비결
[마이클 지 칼럼] 나눠서 정복-신속 조정 등 중요

출처 - http://www.zdnet.co.kr/column/column_view.asp?artice_id=20170919152328

마이클 지 포티넷 CTO

입력 : 2017.09.21.15:57
수정 : 2017.09.21.15:57

사이버 위협이 날로 정교해지고 있다.
전 세계 수많은 기업들은 매일 사이버 위협을 효과적으로 대응해야 하는
어려운 과제를 안고 있으며 보안 어플라이언스를 구축하여
기업의 데이터와 중요한 자산을 보호하는 중이다.

보안 어플라이언스는 사이버 위협을 방어하는데 매우 중요한 역할을 한다.
이것이 바로 위협 인텔리전스다.

진화하는 위협 환경을 면밀히 파악하고 적절히 대응하는 보안 어플라이언스의 역량은
사이버 방어력을 강화하는데 매우 중요하다.

적시에 정확하고 예측 가능한 위협 정보를 확보하는 것은 쉽지 않은 일이다.
효과적인 위협 인텔리전스는 아래와 같은 6가지 요건이 충족돼야 한다.


첫째, 나눠서 정복하라.

비즈니스의 여러 측면에서 대규모 팀은 대규모 생산량과 동일시된다.

동기 부여가 확실한 사이버 범죄자를 넘어서고 싶다면 최적의 전략이 필요하다.
효과적인 위협 연구 조직은 여러 팀으로 나눠서 구성돼야하며 각 팀은 특정 위협에 초점을 맞춰야 한다.
이를 통해 각 팀의 전문적인 역량이 향상되면 보다 신속하게 위협을 감지하고 식별할 수 있으며
고객 대응 시간을 단축시킬 수 있다.

둘째, 신속히 조정하라.

위협 연구팀은 민첩해야 한다.
위협 상황은 매우 역동적이기 때문에 시간,
분단위로도 상황이 달라질 수 있다.
팀은 즉각적이고 유연하게 우선 순위를 조정할 수 있어야 한다.

포티넷은 위협 환경이 어떻게 진화할지에 대한 예측을 기반으로
연구 계획을 업데이트한다. 방향이 정해지면 최적의 기술을 가진 연구원이
특정 테스크포스팀에 참여하여 새롭게 주목받고 있는 위협을 연구한다.

최근 예로는 IoT, 랜섬웨어, 자율적 멀웨어 등이 있다.

셋째, 전체를 조망하라.

연구자는 직접적인 연관이 없는 사안이라도 늘 주변 상황에 관심을 가지고 큰 그림,
즉 전체를 조망할 수 있어야 한다. 예를 들어 사물인터넷(IoT) 취약성을 연구해
위협 전망에 대한 엔터프라이즈 보안 업체의 이해도가 높아질 수도 있다.

넷째. 직감을 키워라.

연구 책임자는 실제 위협 상황이 벌어지기 전에 팀원들이 위협에 대한
통찰력을 가질 수 있도록 교육해야 한다.

예를 들어 뛰어난 위협 연구원들은 미라이 IoT 봇넷이 지난 9월에 등장하기 전에
이미 수 년 간 IoT 취약점이 차세대 위협이 될 것이라고 경고해 왔다.
새로운 위협이 끊임없이 등장하고 빠르게 진화하고 있다.
보안 업체들이 위협에 대한 조사를 늦추고 신속하게 반응하지 못하면 고객들도 신속한 보호를 받을 수 없다.

다섯째, 데이터를 축적하라.

위협 연구팀이 접근 가능한 데이터를 많이 확보할수록 연구 결과의 정확도가 커진다.
선두의 연구 기관들은 정보를 축적만 하는 것이 아니라, 공유한다.

포티넷은 전세계 3 백만 개의 센서를 통해 인텔리전스를 확보하는 것을 넘어서,
사이버 위협 연합(Cyber Threat Alliance, CTA)을 통해 인터폴, 나토(NATO),
국내서는 한국인터넷진흥원(KISA) 및 기타 보안 업체들과 적극적으로 위협 정보를 공유하고 있다.
최근 몇 달 간 포티넷은 전 세계 더 많은 정부 기관과 통신사업자들과 협업하는데 성공했다.

여섯째, 연구 기술에 투자하라.

위협 정보를 수동으로 분석하는 시대는 지났다.
효과적인 연구 팀은 매 초 마다 들어오는 엄청난 데이터를 분석하는 고급 툴이 필요하다.
포티넷은 단일 시그니처로 수천 개의 현재, 미래 악성코드 변종을 식별하는
콘텐츠 패턴 인식 언어(Content Pattern Recognition Languages, CPRL)를 보유했다.

그러나 미래에는 빅데이터 분석 및 인공 지능과 같은 기술이 더 많은 역할을 할 것이다.
사람들은 네트워크를 연결하고 데이터를 공유하며 시스템에 데이터를 적용하는
복잡한 작업을 수행하고 있다. 미래에는 더욱 성숙한 인공 지능 시스템이
이러한 복잡한 작업을 자동화시켜줄 것이다.

그러나 AI가 아무리 발전한다고 해도 100% 자동화 시스템을 구현하기는 어렵다.
사람의 개입이 여전히 필요하다. 빅데이터 및 분석 플랫폼을 통해 멀웨어 진행을 예측할 수는 있지만
멀웨어의 변이는 예측이 어렵다.

워너크라이와 같은 랜섬웨어는 패치가 적용되지 않은 시스템을 감염시키기 위해
미국 국가안보국(NSA)으로부터 유출된 취약점을 악용했는데 이를 미리 예측하는 것은 쉽지 않다.

멜웨어의 진화는 본질적으로 인간의 진화와 사람들이 일상 생활에
새로운 기술을 어떻게 적용하는지에 따라 달라진다.
자율주행차와 웨어러블 IoT가 더욱 대중화되면 사이버 범죄자들은
이들 장치를 악용할 방법을 찾을 것이다. 마찬가지로 암호화 화폐에 대한 관심이
높아지면 해커들은 이를 악용할 방법도 찾아낼 것이다.

자동화의 개념이 사이버 범죄자들에게 새로운 가능성을 열어주면서
많은 기업들이 이를 주목하고 있다. 해커들이 멜웨어 자동화 기능을 강화하면서
대상 기업에 대한 공격 속도가 빨라지고 침입 후 영향을 미치는 시간도
단축됐으며 탐지를 피하는 방법도 빠르게 발전하고 있다.

기업들은 IoT부터 클라우드에 이르기까지 분산 네트워크 에코시스템 전반에 걸쳐
거의 실시간 위협에 대응해야 한다.

그러나 오늘날 많은 기업들이 이를 위한 역량을 확보하지 못하고 있다.
최고정보책임자(CIO)들이 주목해야 할 대목이다.

*본 칼럼 내용은 본지 편집방향과 다를 수 있습니다.

마이클 지 포티넷 CTO
이메일 sjung@fortinet.com

약력

마이클 지(Michael Xie)는
네트워크 보안 업계에서 15년 이상 경력을 가졌다.
2000년 10월 포티넷을 공동 창업했으며 2010년 10월부터
CTO로 기술 전반을 책임지고 있다.

이전에는 넷스크린에서 소프트웨어 디렉터이자 아키텍트로,
서브게이트에서 CTO 겸 부사장을 맡았다. 그는 CRN 매거진이
수여하는 '2009 테크 이노베이터 어워즈'를 수상했으며 2006년 바비즈니스 매거진 주최
'언스트앤영(Ernst & Young) 및 톱 테크놀로지 이노베이터(Top Technology Innovator)'에서
올해의 노던 캘리포니아(Northern California) 기업인에 선정되기도 했다.
중국 칭화대학 자동차공학과 석사 및 캐나다 매니토바 대학교에서
전기 및 컴퓨터 공학과 석사 학위를 받았다.