아키텍처와 함께

블로그 이미지
by gregorio
  • Total hit
  • Today hit
  • Yesterday hit

'전체 글'에 해당되는 글 56건

  1. 2018.02.05
    C3 Bar Chart
  2. 2018.02.03
    Spring Batch 모니터링 SQL
  3. 2018.02.03
    MybatisBatchWriter 오류 해결방법
  4. 2018.02.02
    Linux VI editor tab space 조정
  5. 2018.02.02
    Solve the Cross Domain issue with JSP

C3는 D3 Chart 기반으로 쉽게 Chart를 생성할 수 있는 Chart 솔루션이다.


C3 Chart는 다양한 Chart를 제공하고 있으며, 개발 시 http://c3js.org/를 참조하여 개발을 수행할 수 있다.


C3 Chart를 사용하면서 데이터를 생성하는데 이슈가 되었던 부분들을 간략하게 설명한다.


■ JSON 데이터 처리

C3 Chart는 Json Data를 사용할 수 있다고 되어 있으나, 예제를 찾을 수 없어 column으로 데이터를 처리하였다.

또한 java script에서 loop를 최소화하기 위해 Oracle의 PIVOT 기능을 이용하여 데이터 조회 시 Row를 Column으로 변환하였다.



■ PIVOT을 이용한 Row를 Column으로 변환


SELECT *

FROM (

     SELECT TO_CHAR(START_TIME, 'YYYY-MM-DD') START_DAY

          ,INTERFACE_ID

     FROM TRANS_LOG

     WHERE 1 = 1

<if test='startDate != "" and startDate != null'>

     <![CDATA[AND START_TIME >=  #{startDate}]]>

    </if>

<if test='interfaceId != "" and interfaceId != null'>

AND   INTERFACE_ID LIKE '%' || #{interfaceId} || '%'

</if>

)

PIVOT 

(

COUNT(START_DAY)

    FOR START_DAY IN

    <foreach collection="condDate" item="item"  open="(" close=")" separator=",">

            ${item}

        </foreach>

)  


PIVOT을 사용할 경우 바인딩 변수를 사용할 수 없으며, 바인딩 변수를 사용하면 ORA-56900 오류가 발생한다.


이를 해결하기 위해서 Mybatis의 #{itme} 대신에 ${item}을 사용하여 해결하였다.


또한 PIVOT의 IN 내에 조건을 바인딩하기 위해 사전에 다음 SQL로 데이터를 조회한 후 조회결과를 파라미터를 전송하였다.


■ PIVOT의 IN 바인딩 데이터 조회

SELECT q'[']' || START_DATE || q'[']' START_DATE

FROM   

   (SELECT DISTINCT(TO_CHAR(START_TIME, 'YYYY-MM-DD')) START_DATE FROM TRANS_LOG

WHERE 1 = 1

<if test='startDate != "" and startDate != null'>

<![CDATA[AND   START_TIME >= #{startDate}]]>

</if>

<if test='interfaceId != "" and interfaceId != null'>

AND   INTERFACE_ID LIKE '%' || #{interfaceId} || '%'

</if>

ORDER BY 1


START_DATE를 값으로 사용하기 위해 조회 시 Single Quotation을 붙여주었다.


 


■ JSP Source

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">


<link rel="stylesheet" href="/resources/css/jquery-ui-1.10.1.css">

<link rel="stylesheet" href="/resources/css/table.css">

<link rel="stylesheet" href="/resources/css/c3.min.css">

<link rel="stylesheet" href="/resources/css/melon.datepicker.css">




<script type="text/javascript" src="/resources/js/jquery-3.3.1.min.js"></script>

<script type="text/javascript" src="/resources/js/jquery-ui-1.10.1.min.js"></script>  

<script type="text/javascript" src="/resources/js/c3.min.js"></script>

<script type="text/javascript" src="/resources/js/d3.v3.min.js" charset="utf-8"></script>


<script>


$(document).ready(function() {

$("#btnSearch").click(function(e) {

    e.preventDefault();

    

debugger;

var objectData =

         {

             startDate: $('#startDate').val(),

             chartType: $('#chartType').val(),

             interfaceId: $('#interfaceId').val()

         };


var sendData = JSON.stringify(objectData);

    $.ajax({

        type: "POST",

        url: '/chart/showStatistics.do',

        data : sendData,

        dataType : "json",  //Cross domain

        contentType: "application/json",

        success : function(response, status, xhr) {

        alert(response);

        debugger;

        console.log(response); 

        showChart(response);

        }, 

        error: function(jqXHR, textStatus, errorThrown) {

        debugger;

        console.log(jqXHR.responseText); 

        }

    });

});


});


//Date Picker

$(function() {

    $( "#startDate" ).datepicker({

    defaultDate: new Date(),

    dateFormat: "yy-mm-dd",

    changeMonth: true, 

        changeYear: true,

        dayNames:['Sun', 'Mon', 'Tue', 'Wed', 'Thr', 'Fri', 'Sat']

    });

});

function showChart(response) {

debugger;

var graphType =  $('#chartType').val().toUpperCase() + " Statistic Graph";

$( "#graphType" ).text(graphType);

var categories=[];

$.each(response.categories, function(idx, data) {

categories.push(data);

});

var columns = [];

$.each(response.columns, function (idx, data) {

var col = [];

var idx = 0;

$.each(data, function(key, value) {

debugger;

col[idx] = value;

idx++;

});

columns.push(col);

});

var chart = c3.generate({

bindto: "#interfacechart",

    size: {

        height: 600,

        width: 1200

    },

    data: {

        type: 'bar',

        columns: columns,

    },

    bar: {

        width: {

            ratio: 0.3 // this makes bar width 50% of length between ticks

        }

        // or

        //width: 100 // this makes bar width 100px

    },

    axis: {

    x: {

    type: 'category',

    categories:categories

    }

    },

    grid: {

        x: {

            show: true

        },

        y: {

            show: true

        }

    }

});


// setTimeout(function () {

// chart.load({

//         columns: [

//             ['data3', 130, -150, 200, 300, -200, 100]

//         ]

//     });

// }, 1000);

}


</script>

<title>Interface Monitoring</title>

</head>


<body>

<!-- Search Area -->

<div class="container">

        <form action="">

        <div class="fieldName">

        <label>START DATE</label>

        </div>

        <div class="select">

            <input type="text" id="startDate" size=10 style="align=center;"/>

        </div>

       

        <div class="fieldName">

            <label>Statistic Period</label>

  </div>

        <div class="select">

            <select name="chartType" id="chartType">

        <option value="daily">Daily</option>

        <option value="monthly">Monthly</option>

    </select>

</div>

        <div class="fieldName">

            <label>Interface Name</label>

  </div>

<div class="data">

<input type="text" id="interfaceId" title="Enter Interface Name" size="30"></input>

</div>

        <div class="logbutton">

            <button  id="btnSearch">Search</button>

        </div>

  </form>

</div>


<div>

<label style="height:100%;padding:5px; margin-top:10px; font-family:Sans-serif; font-size:1.2em;" id="graphType">Statistic Graph</label>

</div>

<div id="interfacechart" style="width: 1200px; height: 500px;"></div>

</body>

  

</body>

</html> 



■Controller 소스


import java.util.HashMap;

import java.util.List;

import java.util.Map;


import javax.annotation.Resource;


import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.servlet.ModelAndView;


import cmn.util.base.BaseController;

import cmn.util.dao.CamelMap;

import sehati.inf.chart.service.ChartService;


@Controller

public class CharController extends BaseController {


@Resource(name = "chartService")

private ChartService chartService;

@RequestMapping("/chart/viewChart")

public ModelAndView viewChart() throws Exception {

ModelAndView mav = new ModelAndView();

mav.setViewName("InterfaceStatistics");

return mav;

}

@RequestMapping(value="/chart/showStatistics.do")

public @ResponseBody Map<String, Object> showStatistics(@RequestBody Map<String, Object> param) throws Exception {


Map<String, Object> resultMap = new HashMap<String, Object>();

/** Search Condition **/

List<String> categories = chartService.selectPivotQueryTarget(param);

param.put("condDate", categories);

List<CamelMap> resultList = chartService.selectChartData(param);


resultMap.put("categories", categories);


resultMap.put("columns", resultList);

return resultMap;

}

}

 


먼저 날짜별 PIVOT을 적용하기 위해 날짜를 조회한 후 실제 데이터 조회하기 위해 condData를 파라미터로 전달한다.


'Spring Framrwork' 카테고리의 다른 글

spring framework interceptor  (0) 2018.03.02
Google Map javascript API 사용법  (0) 2018.02.07
Spring Batch 모니터링 SQL  (0) 2018.02.03
MybatisBatchWriter 오류 해결방법  (0) 2018.02.03
Solve the Cross Domain issue with JSP  (0) 2018.02.02
AND

Spring Batch를 적용하여 배치 프로그램을 수행하면 Spring Batch Framework에서 관리하는 테이블에 배치의 수행이력을 저장하고 있다.


이를 이용하여 배치 모니터링하는 SQL은 다음과 같다.


■ Job List

SELECT 

    A.JOB_INSTANCE_ID, 

    A.JOB_NAME, 

    B.JOB_EXECUTION_ID, 

    B.START_TIME JOB_START_TIME, 

    B.END_TIME JOB_END_TIME, 

    B.STATUS JOB_STATUS,

    C.JOB_PARAM

FROM BATCH_JOB_INSTANCE A,

     BATCH_JOB_EXECUTION B,

     (SELECT JOB_EXECUTION_ID,

             LISTAGG(KEY_NAME || '-' || STRING_VAL, ',')WITHIN GROUP (ORDER BY JOB_EXECUTION_ID) JOB_PARAM

      FROM BATCH_JOB_EXECUTION_PARAMS

      GROUP BY JOB_EXECUTION_ID) C

WHERE 1 = 1

AND   A.JOB_INSTANCE_ID = B.JOB_INSTANCE_ID

AND   B.JOB_EXECUTION_ID = C.JOB_EXECUTION_ID  

ORDER BY B.START_TIME DESC;



■ Step List


SELECT B.STEP_NAME,

       B.START_TIME STEP_START_TIME,

       B.END_TIME STEP_END_TIME,

       B.STATUS,

       B.READ_COUNT,

       B.WRITE_COUNT,

       B.EXIT_CODE,

       B.EXIT_MESSAGE

FROM   BATCH_JOB_EXECUTION A,

       BATCH_STEP_EXECUTION B  

WHERE  1 = 1

AND    A.JOB_EXECUTION_ID = B.JOB_EXECUTION_ID

AND    A.JOB_EXECUTION_ID = 37

ORDER BY B.START_TIME;


■일별 통계


SELECT TO_CHAR(A.START_TIME, 'YYYY-MM-DD') START_DAY

      ,B.JOB_NAME

      ,COUNT(*) CNT

FROM   BATCH_JOB_EXECUTION A

      ,BATCH_JOB_INSTANCE B

WHERE A.JOB_INSTANCE_ID = B.JOB_INSTANCE_ID

AND   START_TIME >= '2018-01-01'

GROUP BY TO_CHAR(A.START_TIME, 'YYYY-MM-DD'), B.JOB_NAME


■ 월별통계

SELECT TO_CHAR(A.START_TIME, 'YYYY-MM') START_DAY

      ,B.JOB_NAME

      ,COUNT(*) CNT

FROM   BATCH_JOB_EXECUTION A

      ,BATCH_JOB_INSTANCE B

WHERE A.JOB_INSTANCE_ID = B.JOB_INSTANCE_ID

AND   START_TIME >= '2018-01-01'

GROUP BY TO_CHAR(A.START_TIME, 'YYYY-MM'), B.JOB_NAME 



'Spring Framrwork' 카테고리의 다른 글

spring framework interceptor  (0) 2018.03.02
Google Map javascript API 사용법  (0) 2018.02.07
C3 Bar Chart  (0) 2018.02.05
MybatisBatchWriter 오류 해결방법  (0) 2018.02.03
Solve the Cross Domain issue with JSP  (0) 2018.02.02
AND

Spring Batch 수행 시 

Batch execution returned invalid results. Expected 1 but number of BatchResult objects returned was 2 오류가 발생하는 경우에 다음과 같이 조치한다.



■ 원인

하나의 Job에 Multi Step을 정의하고, ItemReader에서 MyBatisPagingItemReader ItemProcessor에서 Dao를 이용하여 DB에서 Insert 한 후 ItemWriter에서 MyBatisBatchItemWriter를 적용하는 경우에 발생함


하나의 Job에 단일 Step이 있는 경우에는 오류가 발생하지 않는다.



■ 오류 내역


09:11:40.975 [main] DEBUG o.s.transaction.support.TransactionTemplate | Initiating transaction rollback on application exception

org.springframework.dao.InvalidDataAccessResourceUsageException: Batch execution returned invalid results. Expected 1 but number of BatchResult objects returned was 2

at org.mybatis.spring.batch.MyBatisBatchItemWriter.write(MyBatisBatchItemWriter.java:136)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:606)

at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)

at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)

at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)

at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)

at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)

at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)

at com.sun.proxy.$Proxy14.write(Unknown Source)

at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:175)

at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:151)

at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:274)

at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:199)

at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:75)

at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406)

at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330)

at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)

at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:271)

at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81)

at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374)

at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)

at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)

at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)

at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200)

at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)

at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:64)

at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67)

at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169)

at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144)

at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:134)

at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306)

at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135)

at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)

at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128)

at cmn.util.spring.batch.runner.BaseCmdRunner.start(BaseCmdRunner.java:278)

at sehati.batch.sample.runner.SampleDB2FileJobRunner.main(SampleDB2FileJobRunner.java:162) 

  


■ MyBatisBatchItemWriter Code


MyBatisBatchItemWriter Class의 136라인에 result Size를 Check하는 로직이 들어있다. 

result.size() 가 1 이 아닌 경우 Exception을 Throw하고 있다.


      if (assertUpdates) {

        if (results.size() != 1) {

          throw new InvalidDataAccessResourceUsageException("Batch execution returned invalid results. " +

              "Expected 1 but number of BatchResult objects returned was " + results.size());

        }

 


■ 해결방법


<bean id="stepWriter1" class="org.mybatis.spring.batch.MyBatisBatchItemWriter" scope="step">

<property name="sqlSessionFactory" ref="sqlSession" />

<property name="statementId" value="batch.sample.Message.insMessage1" />

<property name="assertUpdates" value="false" />

</bean> 


MyBatisItemWriter의 속성 assertUpdates를 false로 하면 오류없이 정상적으로 처리된다.


'Spring Framrwork' 카테고리의 다른 글

spring framework interceptor  (0) 2018.03.02
Google Map javascript API 사용법  (0) 2018.02.07
C3 Bar Chart  (0) 2018.02.05
Spring Batch 모니터링 SQL  (0) 2018.02.03
Solve the Cross Domain issue with JSP  (0) 2018.02.02
AND

Linux에서 Vi editor Tab Space를 조정하는 방법은 다음과 같아요.


1. Linux 계정의 Home directory에 .exrc 파일 생성한다.


2. .exrc 파일에 다음과 같이 추가한다.


set ts=4

set expandtab

set ai

 


3. 해당 User 다시 로그인

AND

프로젝트에서 각각 서버에 있는 로그 파일을 조회하고자 한다.

로그 파일 조회화면은 특정 서버에 있고, 특정 서버에서 각각의 서버에 있는 로그 파일을 조회해야 한다.


이때 발생하는 이슈가 Cross Domain 이다.

이를 해결하기 위해 JSONP를 적용하기로 하였다.  서버에 넘기는 파라미터가 많지 않기 때문에 JSONP를 사용해도 이슈가 발생하지 않을것이다.


JQury ajax 호출 시 JSONP를 적용하기 위해 파라미터로 jsonpCallback을 정의하여야 한다.

jsonCallback에 Value를  logCallBack을 주고 Callback 함수를 작성한다.


■ Ajax JSONP 호출 함수

$("#btnSearch").click(function(e) {

    e.preventDefault();

$('#logText').val("");

var targetURL = $("#system option:selected").val();

var logSize = $('#logSize').val();


if (logSize > 1000) {

alert("Log size should be less than 1000");

return false;

}

var sendData = {"logType" : $('#logType').val(), "logSize" : $('#logSize').val()};

//var sendData = "logType=" + $('#logType').val() + "&logSize=" + $('#logSize').val();

    $.ajax({

        type: "POST",

        url: targetURL,

        crossDomain : true,

        data : sendData,

        jsonpCallback : "logCallBack",

        dataType : "jsonp",  //Cross domain

        contentType: "application/json"

    });

});


logCallBack은 서버에 get 방식으로 파라미터로 넘겨지고, 서버에서 결과를 생성할 때 

logCallBack으로 감싸서 내려 보내야 한다.



■logCallBack  함수는 다음과 같다.


  function logCallBack(result) {

debugger;

var lastIdx = result.string.lastIndexOf("}") - 2;

var firstIdx = result.string.indexOf(":") + 2;

var logText = result.string.substring(firstIdx, lastIdx);

alert(logText);


$("#logText").val(logText);

}


logCallBack함수의 result는 String 형식으로 전달되기 때문에 파싱이 필요하다.

서버에서는 보내때 logCallBack 안에 넣기 때문에 Json으로 받을 수 없었다.


서버에서 전달되는 Response는 logCallBack("JSON Data") 형식으로 생성되기 때문이다.


그래서 응답을 받아서 필요한 내용만 잘라서 사용하기로 하였다.



■서버의 로직은 다음과 같다.


@RequestMapping(value = "/log/viewer.do")

public ModelAndView logViewer(String logType, String logSize, String callback) throws Exception {

Map<String, Object> resultMap = new HashMap<String, Object>();

/** Log file location **/

// String logType = params.get("logType") != null ? String.valueOf(params.get("logType")) : "";

String logLocation = null;

if (NullUtil.isNull(logType)) {

logLocation = "log.app.location";

}

else {

logLocation = "log." + logType + ".location";

}

String logFile = PropertyUtil.getString(logLocation);

int logLength =  0;

if (!NullUtil.isNull(logSize)) {

logLength = Integer.parseInt(logSize);

}

else {

logLength =  PropertyUtil.getInt("log.read.line");

}


if (LOGGER.isDebugEnabled()) {

LOGGER.debug("Read log file :: {}", logFile);

}


ModelAndView mav = new ModelAndView("ajaxMultiDataView");

String result = null;

/** Check log file exists **/

File file = new File(logFile);

if (!file.exists()) {

resultMap.put("log", "Log file not found :: " + logFile);

StringBuilder sb = new StringBuilder();

result = sb.append(callback).append("(").append(map2Json(resultMap)).append(")").toString();

return mav.addObject(result);

}

if (!file.canRead()) {

resultMap.put("log", "Log file can't read :: " + logFile);

StringBuilder sb = new StringBuilder();

result = sb.append(callback).append("(").append(map2Json(resultMap)).append(")").toString();

return mav.addObject(result);

}


BufferedReader in = null;

StringBuilder logContent = new StringBuilder();

int idx = 0;

try {

in = new BufferedReader (new InputStreamReader (new ReverseReader(file)));

boolean isLoop = true;

while(isLoop) {

String contents = in.readLine();

logContent.append(contents).append("\n");

if (idx++ >= logLength) {

isLoop = false;

}

}

}

catch(Exception logex) {

logex.printStackTrace();

}

finally {

if (in != null) {

in.close();

}

}

if (logContent.length() <= 0) {

resultMap.put("log", "No Contents");

StringBuilder sb = new StringBuilder();

result = sb.append(callback).append("(").append(map2Json(resultMap)).append(")").toString();

return mav.addObject(result);


}

else {

resultMap.put("log", logContent.toString());

StringBuilder sb = new StringBuilder();

result = sb.append(callback).append("(").append(map2Json(resultMap)).append(")").toString();


}

LOGGER.info("result :: {}", result);

mav.addObject(result);

return mav;

 

서버에서 parameter로 callback을 받으면 클라이언트에서 보낸 logCallBack이 넘어오고 이를 이용하여 클라이언트에 전달할 때 callback으로 감싸서 내려 보내 준다.



테스트 결과는 다음과 같다.


 "logCallBack({"log":"17:02:08.864 [localhost-startStop-1] INFO  org.springframework.web.servlet.DispatcherServlet.initServletBean(503) | FrameworkServlet 'DispatcherServlet': initialization completed in 1043 ms\n17:02:08.775 [localhost-startStop-1] INFO  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(220) | Mapped \"{[/sample/dataset.do],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}\" onto public java.util.Map<java.lang.String, java.lang.Object> sehati.ibm.sample.controller.MessageController.testDataset(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,java.lang.String,java.lang.String) throws java.lang.Exception\n17:02:08.775 [localhost-startStop-1] INFO  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(220) | Mapped \"{[/sample/message.do],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}\" onto public java.util.Map<java.lang.String, java.lang.Object> sehati.ibm.sample.controller.MessageController.testMessage(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.lang.Exception\n"})


'Spring Framrwork' 카테고리의 다른 글

spring framework interceptor  (0) 2018.03.02
Google Map javascript API 사용법  (0) 2018.02.07
C3 Bar Chart  (0) 2018.02.05
Spring Batch 모니터링 SQL  (0) 2018.02.03
MybatisBatchWriter 오류 해결방법  (0) 2018.02.03
AND

ARTICLE CATEGORY

분류 전체보기 (56)
Spring Framrwork (33)
Linux (1)
APM (1)
Java (8)
python (0)
ant (1)
chart (1)
OS (1)
tomcat (1)
apache (1)
database (0)

RECENT ARTICLE

RECENT COMMENT

CALENDAR

«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31

ARCHIVE

LINK