jQuery API jqPlot 을 사용하여 그래프 그리기

 

jqPlot 을 사용하여 통계 데이터를 가로/세로형 막대그래프, 선형그래프, 원형그래프 등으로 쉽게 표현 할 수 있다.

* 세로형 선형그래프를 아래와 같이 구현해 보았다.

 

 

1. js import

1
2
3
4
5
6
7
8
9
10
<link rel="stylesheet" type="text/css" href="${rq.getContextPath()}/resources/css/jquery.jqplot.css">
 
<script type="text/javascript" src="${rq.getContextPath()}/resources/js/jqplot/jquery.jqplot.min.js"></script>
<script type="text/javascript" src="${rq.getContextPath()}/resources/js/jqplot/jquery.jqplot.js"></script>
<script type="text/javascript" src="${rq.getContextPath()}/resources/js/jqplot/plugins/jqplot.enhancedLegendRenderer.js"></script>
<script type="text/javascript" src="${rq.getContextPath()}/resources/js/jqplot/plugins/jqplot.barRenderer.js"></script>
<script type="text/javascript" src="${rq.getContextPath()}/resources/js/jqplot/plugins/jqplot.highlighter.js"></script>
<script type="text/javascript" src="${rq.getContextPath()}/resources/js/jqplot/plugins/jqplot.categoryAxisRenderer.js"></script>
<script type="text/javascript" src="${rq.getContextPath()}/resources/js/jqplot/plugins/jqplot.cursor.js"></script>
<script type="text/javascript" src="${rq.getContextPath()}/resources/js/jqplot/plugins/jqplot.pointLabels.js"></script>
cs

jqPlot 을 사용하기 위해 관련 js를 import 한다.

 

 

2. 데이터 set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fn_csCntChart : function () {
 
            var barData1 = [];
            var barData2 = [];
            var ticks = [];
            var labels = ['전체건수''1인당 처리건수'];
            
            <c:forEach var="list" items="${statsList}" >
                barData1.push("${list.cnt}");
                barData2.push("${list.cntPerEmp}")
                ticks.push("${list.graphDt}");
            </c:forEach>    
            
            var csCntMaxValue = Math.max.apply(null, barData1);        //전체 데이터 중 최대 값
            
            if(ticks.length > 1){
                csCntMaxValue = csCntMaxValue*1.2;    //전체 데이터 최대 값 * 1.2
            }else{
                csCntMaxValue = 10000;    //모든 데이터 값이 0인 경우 차트 최대값을 10000으로 set
            }
                   
            var campChart = $.jqplot('chartArea', [barData1, barData2], {
                //차트 속성 설정
            }
cs

6 Line: 데이터의 범례(각각의 그래프가 의미하는 정보 : 전체건수, 1인당 처리건수)는 lables 배열에 담는다

9 Line: 서버에서 전달한 statsList 데이터(list)에서 cnt (전체건수) 값을 barData1 array에 담는다.

10 Line:서버에서 전달한 statsList 데이터(list)에서 cntPerEmp(1인당 처리건수) 값을 barData2 array에 담는다.

11 Line : 데이터의 기준점(그리드에서 가로축)이 되는 날짜(graphDt)를 ticks 배열에 담는다.

            ticks 는 차트 옵션을 지정할 때 사용한다.

14 ~ 20 Line :

그리드 세로축의 최대값을 제한.

전체건수와 1인당 처리건수 중 전체건수의 값이 당연히 클 것임으로 list 중 전체건수의 최대 값을 뽑아낸 후  1.2를 곱한 값을 세로축의 최대값으로 사용한다.

만약 조회된 데이터가 없는 경우 세로축의 최대값을 1만으로 제한한다.

22 Line:

'chartArea' : 차트를 그릴 태그 id (id가 'chartArea' 인 tag에 완성된 차트가 그려지게 된다)

array barData1, barData2 를 array 에 다시 담아 jqplot 의 파라미터로 전달한다.

   

 

 

3. 차트 옵션 지정

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
var campChart = $.jqplot('campChartMonth', [barData1, barData2], {
            animate: true,
            animateReplot: true,
            cursor: {
                          show: true,
                          zoom: false,
                          looseZoom: false,
                          showTooltip: false
                    },
            series:[
                      {
                          color : 'blue',
                          renderer: $.jqplot.LineRenderer,
                      } ,
                      {
                          color : 'red',
                          renderer: $.jqplot.LineRenderer,
                      }
                    ],
            axesDefaults: {
                  pad: 0
            },
 
            /*그래프 범례*/
            legend: {
                 renderer: $.jqplot.EnhancedLegendRenderer,
                  show: true,
                  location's',
                  labels: labels,
                  rendererOptions:{
                        numberRows :1    
                     },
                    placement: 'outsideGrid',                 
            },    
            axes: {
                    xaxis: {
                                renderer: $.jqplot.CategoryAxisRenderer,
                              ticks: ticks,
                              drawMajorGridlines: false,
                              drawMinorGridlines: true,
                              drawMajorTickMarks: false,
                            },
                    yaxis: {
                                max: csCntMaxValue,
                                min: 0,
                                tickOptions: {
                                    formatString: "%'d"
                                },
                                rendererOptions: {
                                    forceTickAt0: true
                                }
                            },
                },
                highlighter: {
                                show: true
                                showLabel: true
                                tooltipAxes: 'y',
                                sizeAdjust: 7.5 , tooltipLocation : 'ne'
                            },
            }); 
cs

series : 각각의 선형그래프 관련 설정 (첫번째 그래프선을 blue로, 두번째 그래프선을 red 색상으로 지정)

          그래프의 형태는 선형그래프로 지정 (LineRenderer) (막대그래프는 BarRenderer)

legend : 그래프 범례 관련 설정 (위치를 그래프와 겹치지 않도록 바깥에 설정 (placement : outsideGrid))

            범례를 한줄로 설정 (rendererOptions : numberRows 1)

axes :

그리드 관련 설정 

xaxis : x 축 ( 세로형 선형그래프이므로 x 축에 ticks : ticks(graphDt 값을 담고있는 배열) 선언으로 데이터의 기준점(날짜기준(graphDt))을 셋팅 )

yaxis : y 축

 

 

* 가로형 그래프로 그릴 경우 x 축 y 축 설정을 반대로 주고,

그래프 데이터를 인자값으로 넘길 때 2차원 배열형태를 조금 더 신경 써서 만들어야 한다.

 

 

 

참고 : 아래 사이트에 예제를 비롯한 각각의 옵션들이 친절하고 자세하게 설명이 되어있다. 영어로...

http://www.jqplot.com/examples/barTest.php

 

Bar Charts

 

www.jqplot.com

 

 

반응형

[JSTL이란]

JSTL 은 JSP(Java Server Pages) Standard Tag Library의 약자로써, jsp 어플리케이션의 핵심기능을 캡슐화한 유용한 태그 모음.

 

tutorial 사이트 :

https://www.tutorialspoint.com/jsp/jsp_standard_tag_library.htm

 

<JSTL 사용을 위한 taglib 선언>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

사용하고자 하는 태그라이브러리(taglib)의 prefix 를 각각 선언

 

 

<JSTL tag 별 용도 및 설명>

1.c tag : 코어

c:if : 조건문 

c:choose c:when c:otherwise : switch case default 조건문

c:forEach : 반복문

c:set : 변수 할당

c:out : 출력

2.fn tag : 길이반환 등의 함수

fn:length : 길이 반환

fn:substring : 문자열 자르기

3.fmt tag : format 변환용으로 사용

아래 url 참고

https://www.javatpoint.com/jstl-formatting-tags

 

 

<사용 예>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<c:if test="${ not empty dataList}">
     <c:forEach var="list" items="${dataList}" varStatus="status">
        <tr class="dataTr tmpTr" style='cursor:pointer;' onclick="goInfo('${list.seq}')">
            <td>${list.start_page_limit + status.count}</td>
            <td>${list.seq}</td>
            <td>
            <c:choose>
               <c:when test="${fn:length(list.memo)>20}">
                  <c:out value="${fn:substring(list.memo, 0, 19)}"/>...
               </c:when>
               <c:otherwise>
                  <c:out value="${list.memo}"/>
               </c:otherwise>
            </c:choose>
            </td>
            <td>
            <c:set var="nm" value="${fn:split(list.user_name, '^')}" />
            <c:forEach var="obj" items="${nm}" varStatus="idx">
              ${obj}<c:if test="${!idx.last}">,<br></c:if>
            </c:forEach> 
            </td>
        </tr>
    </forEach>
</c:if>
cs

1 line : 서버로부터 받아온 dataList 가 비어있지 않다면 2~23 라인 실행

2 line : 반복문

3 line : 서버에서 받아온 dataList 를 list 변수에 담아 for 문 내에서 사용. varStatus 는 index 와 관련되어 사용이 가능한 속성

4 line : varStatus.count로 순번 출력(1부터 출력) (참고: varStatus.index는 0부터 출력)

7 ~ 14 line : if else 구문

8 line : list에서 가져온 memo 의 길이가 20 보다 큰 경우

9 line : 0~19번째 문자까지 출력 후 ... 붙이기 (말줄임)

17 line : nm 변수에 list 에서 가져온 user_name 을 ^ 문자 기준으로 split 하여 저장

18 line : nm 변수를 obj 변수에 담아 for 문 내에서 사용

19 line : 마지막이 아닌 경우 (!varStatus.last) ,<br> 을 붙임 (반대로 다시말해 마지막인 경우 ,<br> 을 붙이지 않음) 

 

 

< foreach 의 varStatus >

<c:forEach var='list' items='${dataList}' varStatus='status'>

   ${status.current} // 현재아이템

   ${status.index}   // 0부터 시작하는 인덱스

   ${status.count}   // 1부터 시작하는 카운트

   ${status.first}   // 현재 인덱스가 첫번째 인덱스인지 판별

   ${status.last}    // 현재 인덱스가 마지막 인덱스인지 판별

   ${status.begin}   // 반복문 시작 값

   ${status.end}     // 반복문 끝 값

   ${status.step}    // 반복문 증가 값

</c:forEach>

 

참고 : https://www.javatips.net/blog/jstl-last-using-varstatus

 

 

< 주의사항 > 

페이지 로드 순서(웹언어들의 동작 및 실행 순서(Load Sequence On Web))에 주의하자..

JAVA > JSTL > HTML > JavaScript(jQuery)

 

 

해당 부분은 따로 정리해서 포스팅하겠다.

 

반응형

POI (Excel) + Spring + JSP

 

POI lib 을 사용한 excel 파일 생성 및 다운로드

 

 

1. dependency 추가(HSSF 예제)

1
2
3
4
5
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.15</version>
</dependency>
cs

* HSSF이외에 XSSF, SXSSF 라이브러리 존재. 

HSSF : excel 의 .xls 파일 포맷을 위한 POI

XSSF : .xls 및 .xlsx 파일 포맷을 위한 POI

SXSSF : 이미지 및 대용량 엑셀 데이터를 위한 POI

SXSSF 의 경우 HSSF, XSSF에 비해 성능이 떨어지는 거라는 글을 봤음, 대용량 처리가 아닌 이상 XSSF 혹은 HSSF 사용

 

2. 엑셀 파일 생성(HSSF 사용 예제)

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@Override
    public HSSFWorkbook listExcelDownload(VO param) throws Exception {
        
        
        HSSFWorkbook workbook = new HSSFWorkbook();
        
        HSSFSheet sheet = workbook.createSheet("엑셀시트명");
        
        HSSFRow row = null;
        
        HSSFCell cell = null;
        
        param.setPager(false);
        param.setNullText(NULL_TEXT);
        param.setSeparator(DELI_EXCEL);
        List<VO> list = Dao.selectList(param);
        
        row = sheet.createRow(0);
        String[] headerKey = {"칼럼1""칼럼2""칼럼3""칼럼4"};
        
        for(int i=0; i<headerKey.length; i++) {
            cell = row.createCell(i);
            cell.setCellValue(headerKey[i]);
        }
        
        for(int i=0; i<list.size(); i++) {
            row = sheet.createRow(i + 1);
            StbcsTaskHstVO vo = list.get(i);
            
            cell = row.createCell(0);
            cell.setCellValue(vo.getEx1());
            
            cell = row.createCell(1);
            cell.setCellValue(vo.getEx2());
            
            cell = row.createCell(2);
            cell.setCellValue(vo.getEx3());
            
            cell = row.createCell(3);
            cell.setCellValue(vo.getEx4());
 
        }
        
        return workbook;
    }
    
cs

* HSSF lib 사용시

HSSFWorkbook 생성 > HSSFWorkbook에 HSSFSheet 생성 > HSSFSheet에 HSSFRow 생성 > HSSFRow에 HSSFCell 생성

* XSSF lib 사용시

흐름은 위와 동일, HSSF을 XSSF로만 바꿔주면 됨(ex: HSSFWorkbook >> XSSFWorkbook).

 

 

3. Controller (엑셀 다운로드)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@RequestMapping(value="/exceldownload.do")
    public void excelDownload( HttpServletRequest request ,HttpServletResponse response ,HttpSession session, VO param) throws Exception {
        
        OutputStream out = null;
        
        try {
            HSSFWorkbook workbook = Service.listExcelDownload(param);
            
            response.reset();
            response.setHeader("Content-Disposition""attachment;filename=stbcs_history.xls");
            response.setContentType("application/vnd.ms-excel");
            out = new BufferedOutputStream(response.getOutputStream());
            
            workbook.write(out);
            out.flush();
            
        } catch (Exception e) {
            logger.error("exception during downloading excel file : {}", e);
        } finally {
            if(out != nullout.close();
        }    
    }
cs

 

4. jsp

1
2
3
4
5
6
7
8
9
/* 엑셀다운로드 */
function downloadExcel(){
 
    var f = document.frmSearch;
    f.action = "/exceldownload.do";
    f.submit();
    
    return;
}
cs

 

 

 

 

반응형

CSS 적용 우선 순위

1. 사용자 스타일 시트 우선

!important 선언을 한 사용자 스타일  > !important 선언을 한 작성자 스타일 >
작성자 스타일 > 사용자 스타일 > User Agent 선언 (브라우저 자체의 선언)

 

2. 계산결과가 높을 수록 우선 적용된다.

a = 선택자중 ID의 수를 세어 100자리에 놓는다,

b = 선택자중 가상 클래스와 클래스의 수를 세어 10자리에 놓는다.

c = 선택자중 엘리먼트의 수를 세어 1의 자리에 놓는다.

  a b c 계산결과
*{} 0 0 0 0
li{} 0 0 1 1
ul li{} 0 0 2 2
li.num{} 0 1 1 11
li.num.last{} 0 2 1 21
p#wrap{} 1 0 1 101

 

3. 가장 마지막에 지정된 스타일이 우선 적용된다.

<style type="text/css">

  p.test{color:black;}

</style>

<p class="test" style="color:red;">TEST</p>

 

위 경우 동일한 p 태그의 test 클래스에 red 색상 css 가 선언되어있다.

p 태그가 마지막에 지정된 스타일이므로 TEST 문구는 red 속성이 적용된다.

 

 

*생활코딩 사이트 내용 정리.

https://opentutorials.org/module/484/4149

 

반응형

'front > html, css' 카테고리의 다른 글

[CSS] padding 순서  (2) 2019.07.04

td{padding : 1px 2px 3px 4px;}

 

: 상 우 하 좌

시계방향순서

반응형

'front > html, css' 카테고리의 다른 글

[CSS] 적용 우선 순위  (0) 2019.07.10

SELECT 한 결과를 INSERT/UPDATE 하기

 

별도의 sql id 로 select, insert 쿼리를 각각 분리하여 선언하고

select 한 값을 서버에서 다시 insert sql 의 매개변수로 던져주어 DB에 insert 할 경우

WAS서버와 DB 서버간 DB connection 이 두 번 발생 하므로, 

다음과 같은 방법을 이용하자.

 

1. mysql 의 select insert 문법 사용

ex1)

1
2
INSERT INTO sampleTable (col1, col2, col3)
SELECT #{val1}, #{val2}, #{val3}
cs

ex2)

1
2
INSERT INTO sampleTable(col1, col2, col3)    
     SELECT #{val1}, #{val2}, MAX(col3) FROM sampleTable WHERE pkKey = #{pkKey}
cs

 

2. mybatis 의 selectKey 사용

1
2
3
4
5
6
7
8
9
<insert id="sampleSelectInsert" parameterType="java.util.HashMap">
<selectKey keyProperty="selectRs" resultType="integer" order="before">
  SELECT MAX(val)
    FROM sampleTable
   WHERE key = #{value}
</selectKey>
INSERT INTO targetTable (col1, col2, col3)    
                SELECT #{val1}, #{val2}, #{selectRs}
</insert>
cs

* order 옵션을 before 로 사용시 메인 쿼리 (위 예제에서 insert sql) 실행 전에 selectKey sql 실행.

  위의 경우 insert sql 실행 전에 select sql가 실행되어야 selectRs 라는 값을 가져올 수 있으므로 order 를 before로 지정

* order 옵션을 after 로 사용시 메인 쿼리 실행 후에 selectKey sql 이 실행되므로, insert 이후의 seq(시퀀스) max 값을

  return해야 할 때 유용하게 사용 가능

 

※ update 에서 selectkey 를 사용할 경우 mybatis 버전이 낮을 때 에러가 발생하는 경우가 있는 것 같다.

   select + update 를 사용해야 하는 경우 서브쿼리를 사용하자.

 

반응형

현상]
drm:vmw_host_log [vmwgfx]] *ERROR* Failed to send host log message
우분투 실행시 위와 같은 에러메시지 출력 
해결]
환경설정 > 디스플레이 > Graphics Controller 를 VBoxVGA로 변경

참고:
https://unix.stackexchange.com/questions/502540/why-does-drmvmw-host-log-vmwgfx-error-failed-to-send-host-log-message-sh

반응형

1. 변화하는 기능을 별도의 interface로 분리(캡슐화)

2. 각각의 기능(interfaceImple)들이 인터페이스를 구현(implements)

3. 기능을 사용하는 객체(class) 내에서 기능(interface)을 멤버변수로 포함

4. 기능을 사용하는 객체(class) 내에서 기능(interfaceImple)을 주입받는 setter를 선언하여 각각의 객체(class)가 다른 기능(interfaceImple) 을 사용할 수 있게 설계

 

* 무조건적인 상속은 소스의 중복을 야기, 소스 수정시 구현체들의 소스 수정을 야기

 

[ex]

[Shout interface]

소리지르기 비명지르기 기능이 있는 Shout 인터페이스 작성.

1
2
3
4
5
6
7
package design_pattern.strategy;
 
public interface Shout {
    public void yell();
    public void scream();
}
 
cs

 

[Human class]

Shout 인터페이스를 구현한 Human 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package design_pattern.strategy;
 
public class Human implements Shout{
    
    @Override
    public void yell() {
        System.out.println("으악");
    }
 
    @Override
    public void scream() {
        System.out.println("꺄");
    }
    
}
 
cs

 

[Dog class]

Shout 인터페이스를 구현한 Dog 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package design_pattern.strategy;
 
public class Dog implements Shout{
 
    @Override
    public void yell() {
        System.out.println("왈");
    }
 
    @Override
    public void scream() {
        System.out.println("왈");
    }
    
}
 
cs

 

[Throat class]

소리지르기, 비명지르기 기능을 갖고 있는 Shout 인터페이스를 멤버변수로 두고 있는 Throat 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package design_pattern.strategy;
 
public class Throat {
    
    Shout s;
    
    public void setThroat(Shout s) {
        this.s = s;
    }
    
    public void func1() {
        s.yell();
    }
    
    public void func2() {
        s.scream();
    }
    
}
 
cs

 

[Main class(client)]

기능을 사용하는 클라이언트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package design_pattern.strategy;
 
public class Main {
    public static void main(String args[]) {
        
        Throat throat = new Throat();
        
        throat.setThroat(new Human());
        throat.func1();
        throat.func2();
        
        System.out.println("------------------");
        
        throat.setThroat(new Dog());
        throat.func1();
        throat.func2();
        
    }
}
 
cs

 

[결과]

클라이언트 단에서 setter를 사용하여 클래스(기능)를 변경하여 사용 가능하다.

 

정리가 잘 되어있는 글

참고 도서

 

 

반응형

Head First : Design Patterns

 

자바스럽게 개발하려면 디자인 패턴에 대한 공부는 필수.

아직 1장 스트래터지 패턴 밖에 읽어 보지 못했지만, 이해하기 쉽게그래도 어렵다 정말 잘 쓴 책 같다.

공부하며 각각의 패턴들을 블로그에 따로 정리해보려고 한다.

 

실무에서 다양한 상황에 맞게 각각의 패턴들을 적용하여 개발하려면 내공이 더 쌓여야 가능하겠지만,

일단 각종 API, 라이브러리 및 고수 선배님들의 소스를 파악하는데 큰 도움이 될 듯 하다.

 

2019-06-03 시작.

반응형

'etc. > books' 카테고리의 다른 글

[Book] HTTP 완벽 가이드  (0) 2020.03.17
[Book] 객체지향의 사실과 오해  (0) 2020.02.23
[Book] 소프트웨어 장인  (0) 2020.01.16
[Book] Clean Code (클린 코드)  (0) 2019.12.28
[Book] 프로그래머의 길, 멘토에게 묻다  (0) 2019.11.22

[클라이언트 ip 가져오기]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static String getIp(HttpServletRequest request){
    String result = null;
    
    result = request.getHeader("X-Forwarded-For");
    
    if (result == null || result.length() == 0 || "unknown".equalsIgnoreCase(result)) {
        result = request.getHeader("Proxy-Client-IP");
    }
    if (result == null || result.length() == 0 || "unknown".equalsIgnoreCase(result)) {
        result = request.getHeader("WL-Proxy-Client-IP");
    }
    if (result == null || result.length() == 0 || "unknown".equalsIgnoreCase(result)) {
        result = request.getHeader("HTTP_CLIENT_IP");
    }
    if (result == null || result.length() == 0 || "unknown".equalsIgnoreCase(result)) {
        result = request.getHeader("HTTP_X_FORWARDED_FOR");
    }
    if (result == null || result.length() == 0 || "unknown".equalsIgnoreCase(result)) {
        result = request.getRemoteAddr();
    }
    
    return result==null?"":result; 
}
 
cs

 

[서버 ip 가져오기]

1
2
3
4
5
6
7
8
9
 public static String getIp(){
    String result = null;
    try {
        result = InetAddress.getLocalHost().getHostAddress();
    } catch (UnknownHostException e) {
        result = "";
    }
   return result; 
}
cs

 

찾다보니 아래와 같은 글도 찾게 되었다.

https://pkgonan.github.io/2018/06/InetAddress-getLocalHost

 

반응형

+ Recent posts