로지텍 M280 무선 마우스

노트북을 구매하면서 마우스를 하나 골라야하는데 고민이 됬다.

전에 블루투스 마우스를 썻다가 진짜 배터리가 한달 가더라.

이번에는 마우스를 뭐사야하나 찾다가 로지텍 무선 마우스가 1년간다고???

찾아보니 로지텍 무선 마우스가 배터리 끼고 1년 정도 간다고 되어있다.

블루투스 방식이 아닌 USB 리시버를 끼워서 별도의 통신 방식인거 같다.


장점

1. 잡는 부분이 고무로 되어있어 편하다.

2. 무광이라 반짝바짝하지 않는다

3. 블루투스 잡을 필요도 없고 그냥 꽂으면 된다!!편하다.


단점

1. 약 2만원정도 금액( 누군가에게는 마우스 따위가?? )

정말 단점이 가격밖에 없다.

근데 그 가격 값을 한다. ㅋㅋㅋㅋㅋ




노트북이 흰색인데 마우스가 검은색이라 ㅋㅋㅋㅋ먼가 어울리지는 않는 것 같다...

무광이라 번뜩번뜩거리지도 않고 생각보다 괜찮다.





손이 좀 못생기긴 했지만 ㅋㅋ

저 엄지 들어가는 부분이 진짜 편하다.

설명서에는 인체 공학적이라는데 엄지손가락과 새끼 손가락 부분이 진짜 편하다.

고무로 되어있는 것도 있지만 굴곡이 있어 잡기 괜찮은 것 같다.


아직까지 5천원 ~ 1만원 짜리 보급형 마우스 쓰다가 2만원 짜리 써봤는데

정말 괜찮다고 생각된다.

jQuery DataTables Plugin


이번에 소개 하는 jQuery Plugin 은 DataTables 입니다.

보통 데이터 리스트를 보일 때 반복문으로 <tr><td></td><tr> 코드를 돌립니다.

이런 방식으로 간단한 데이터들은 기존 방식대로 해도 되지만

여러 부가적인 기능들을 직접 코딩하여 개발을 하려면 시간도 많이 걸리고 디버깅도 쉽지가 않습니다.

그래서 제가 이번에 사용해본 DataTables 는 많은 기능도 있고 사용하기 편리합니다.

우선 간단하게 사용했을 때 편리한 점은


1. 다양하게 제공되는 기능

2. 심플한 코드


이 두가지가 가장 좋았습니다.

특히 기능 중에 sorting 이라던지 rendering 등 잘 구현되어있어 좋습니다.

다양한 기능은 사이트에서 직접 예제들을 보시면 바로 이해되실겁니다.




간략하게 개발했던 코드입니다.


dataTable = $('#dataTable').DataTable({
    "order": [[ 5"desc" ]],
    "columns"
        [
            {
                "searchable"false,
                "orderable"false,
                "data":null,
                "render":function(data,type,full,meta){
                    if(full.pds_event == "Stop" || full.pds_event == "Collect"){
                        return "";
                    }else{
                        return "<button class='btn btn-block btn-info btn-sm' id='pdsSelect'> 선택</button>";
                    }
                }
            },
            {data: "pds_key"},
            {
                data: "pds_event",
                render:function(data,type,full,meta){
                    var returnStr = "";
                    switch (data){
                        case "Start":
                            returnStr = "<span class=\"label label-success\">Start</span>";
                            break;
                        case "Stop":
                            returnStr = "<span class=\"label label-danger\">Stop</span>";
                            break;
                        case "Pause":
                            returnStr = "<span class=\"label label-default\">Pause</span>";
                            break;
                        case "UnPause":
                            returnStr = "<span class=\"label label-warning\">UnPause</span>";
                            break;
                        case "Collect":
                            returnStr = "<span class=\"label label-danger\">Collect</span>";
                            break;
                        case "Ready":
                            returnStr = "<span class=\"label label-info\">Ready</span>";
                            break;
                        default : 
                            returnStr = data;
                            break;
                    }
                    
                    return returnStr;
                }
            },
            {
                data: "pds_users_cnt",
                render:function(data,type,full,meta){
                    if(data == 0){
                        return "0 명";
                    }else{
                        return "<button class='btn btn-block btn-default btn-sm' id='pdsUsers'> "+data+" 명</button>";
                    }
                    
                }
            },
            {
                data: "pds_cid",
                "render":function(data,type,full,meta){
                    if(data == null){
                        return data;
                    }else{
                        return phone_format(data);
                    }
                    
                }
            },
            {data: "dt_frt"},
            {
                data: "totalCnt",
                render:function(data,type,full,meta){
                    if(data == 0){
                        return " 0 ";
                    }else{
                        return "<button class='btn btn-block btn-default btn-sm' id='pdsTarget'> "+data+" </button>";
                    }
                    
                }
            },
            {
                data: "processCnt",
                render:function(data,type,full,meta){
                    if(data == 0){
                        return " 0 ";
                    }else{
                        return "<button class='btn btn-block btn-default btn-sm' id='pdsProcess'> "+data+" </button>";
                    }
                    
                }
            },
            {
                "searchable"false,
                "orderable"false,
                "data":null,
                render:function(data,type,full,meta){
                    if(full.pds_event == "Stop" || full.pds_event == "Collect"){
                        return "";
                    }else{
                        return "<button type='button' class='btn btn-info btn-sm' id='pdsTargetCollect'> 고객회수</button>";
                    }
                    
                }
            },
        ],
    "ajax" : {
        url : "/pds/getPdsList",
        type : "POST",
        data : function(d){
            d.searchStartDate         = dateRangeFormat($("#searchDate").val()).getStartDate();
            d.searchEndDate         = dateRangeFormat($("#searchDate").val()).getEndDate();
        }
    }
});
cs



코드를 보면 제가 구현했던 로직은 AJAX 로 Json Array 데이터를 가지고 리스트를 출력했습니다.

DataTables에서 제공하는 Ajax 기능을 사용하면 쉽게 구현이 가능합니다.

데이터 부분은 이렇게 javascript로 구현하면 되고 html table 부분은 정말 심플합니다!!!


<table id="dataTable" class="table table-bordered table-striped" width="100%">
    <thead>
        <tr>
            <th>선택</th>
            <th>pds_key</th>
            <th>진행상태</th>
            <th>pds_users</th>
            <th>pds_cid</th>
            <th>등록일</th>
            <th>배분수량</th>
            <th>진행수량</th>
            <!-- <th>상담회수</th> -->
            <th>고객회수</th>
        </tr>
    </thead>
    <tfoot>
        <tr>
            <th>선택</th>
            <th>pds_key</th>
            <th>진행상태</th>
            <th>pds_users</th>
            <th>pds_cid</th>
            <th>등록일</th>
            <th>배분수량</th>
            <th>진행수량</th>
            <!-- <th>상담회수</th> -->
            <th>고객회수</th>
        </tr>
    </tfoot>
</table>
 
cs

한성 노트북 U45X ForceRecon 3557S2

이전에 한성 보스몬스터를 구매하여 잘 썼었는데 이번에 한성에서 노트북을 다시 구매하게 됬습니다.

이전에 구매 목적이 게임용이었습니다.

그러다보니 보스몬스터가 무겁고 두껍고 불편했습니다.

말이 노트북이지 그냥 탱크입니다;;


이번 구매의 목적은 조금 다르네요.

1. 프로그램 코딩

2. 블로거 포스팅

3. 간단한 웹서핑

이정도겠네요. 그중에 아마 프로그램 코딩이 가장 높을 것으로 생각이 됩니다.

그래서 가벼운 사이즈로 찾다가 가성비면 또 한성!!이라서 한성 제품을 찾아보니

14인치 중에 스펙이 괜찮은 노트북이 있더군요.




스펙이 좋고 가격도 약 70만원 대라 가성비가 역시나  좋더군요.

하지만 이 제품들을 찾아보니 단점들이 많다는 얘기가 많았습니다.

1. 빛샘현상이 있다

2. 터치패드가 불편하다.

3. 키패드가 잘 안눌린다.


뭐 대략 크게 이정도인데... 사실 글 쓰는 지금도 타자가 잘 안눌릴 때가 있습니다 ㅋㅋㅋ

키감이 그렇게 좋지는 않네요


우선 구매하여 개봉한 사진입니다.






박스도 심플하고 내용물도 심플합니다.

확실히 전에 노트북은 검은색이라 그냥 그랬는데 하얀색을 보니까 진짜 이쁩니다.

그리고 바로 불량화소 테스트를 해봤습니다.

불량화소는 없는데 문제가...역시 빛샘이 있네요




이 빛샘이라는게 깜깜한 방 안에서 검은색 화면 띄워놨을 때 보이더군요

여기저기 찾아보니 IPS 패널은 빛샘이 있다고 합니다.

저야 막눈이라 잘 모르겠는데 사실 깜깜한 곳에서 노트북 할일도 없고

실사용 해봤을 때 잘 모르겠더군요.

사진도 카메라로 찍어서 그런지 좀 심하게 보이지 실제로 보면 그리 심하지는 않습니다.




그리고 바로 윈도우 7을 깔아줍니다.

다들 8.1이나 이번에 나온 10버전들을 사용하실텐데요.

개발자라서 그런지 잘 모르겠지만 사실 익숙한거만 써서 다른건 불편하더군요.


그리고 i5 5세대 & SSD & 8GB 램 조합으로 빠르긴 진짜 빠릅니다 ㅋㅋㅋ


Uvex 104 vario 선글라스 Review

eBay에서 구매할 물품이 있어서 검색을 하다가 우연히 Uvex 고글을 사게됬습니다!!!

예전부터 봐왔던 고글이긴 한데 이미 Rudy 가 있어서 고민했던 제품입니다.

Amazon 기준으로 보면 최소 약 253 달러 정도면 약 29만원인데

국내에서도 25~29만원이니 큰 메리트가 없습니다.


그런데 독일 이베이에서 92유로, 달러로는 99달러 정도 한화로 하면 약 12만원 되겠네요.

그것도 새 제품인데 반가격에 팔더군요.

아마 떨이가 아니였을까...구매하자마자 End 된거 보면요.

아마 배송비까지 다해서 약 13만원정도 들었던거 같습니다.

중고가격도 18~20에 되어있는데 정말 싸게 산거죠...



제가 가지고 있는 선글라스는 루디 프로젝트 변색 선글라스입니다.

2015년도 올해 제주도 갔다가 약 300달러 주고 샀으니 30만원이 넘지요?


Uvex 104 변색 개봉한 사진입니다.









확실히 UVEX 최상급이라 그런지 모르겠지만 가볍습니다.

특히 제가 루디를 써서 그런지 모르겠는데 안경알이 하나로 되어있어서 시야가 넓습니다.

아직 착용하고 라이딩은 하지 않았지만 그냥 쓰고 봤을 때도 넓네요.

그리고 안경테가 루디보다 커서 사이즈도 더 큰줄 알았는데 비슷한거 같습니다.


개인적인 생각은 아직 라이딩 전이지만 UVEX 104 고글이 더 편한 듯 느껴집니다.

귀에 닿는 부분이 루디보다는 우벡스가 좀 더 넓은 느낌입니다.

사진을 보면 우벡스는 곡선인 반면에 루디는 일직선인데 제 두상에는 우벡스가 편하네요

라이딩 후에 둘중에 하나를 방출해야겠죠.





jQuery Validation Plugin



jQuery Plugin 중에 이름 그대로 validation 기능을 하는 plugin 입니다.


특히 사용자 등록, 수정 또는 검색 조건 입력 부분과 같이 사용자가 입력하는 부분에 validation 체크와 함께 메세지를 편리하게 사용 가능합니다.


장점은 역시 가독성이 좋고 정규화 되어있기 때문에 편리합니다.

특히 if else, for, switch 등등 소스가 정신없이 되어있지만


jQuery Validation Plugin 쓰면 깔끔해서 좋습니다.

사용법은 아래 링크에 들어가시면 예제와 함께 금방 익히실 수 있습니다.

http://jqueryvalidation.org/



$("#formMemberAdd").validate({
    rules: {
        memId : {
            required : true,
            rangelength: [412],
            remote : {
                url : "/config/getMemberValidate",
                type : "POST",
                data : {
                    memId : function(){
                        return $("#memId").val();
                    }
                }
            }
        },
        memName : {
            required : true
        },
        memInterphone : {
            required : true,
            digits : true
        },
        grpName : {
            required : true
        },
        memPasswd : {
            required : true,
            rangelength: [832]
        },
        confirm_memPasswd: {
            required: true,
            equalTo: "#memPasswd"
        }
    },
    messages:{
        memId : {
            required : "아이디는 필수 항목 입니다.",
            rangelength: $.validator.format("아이디는 최소 {0}자 이상 {1}자 이하로 입력하세요."),
            remote : "이미 등록된 아이디입니다."
        },
        memName : {
            required : "이름은 필수 항목 입니다."
        },
        memInterphone : {
            required : "내선번호는 필수 항목 입니다.",
            digits : "숫자로 입력해주세요."
        },
        grpName : {
            required : "조직은 필수 항목 입니다."
        },
        memPasswd : {
            required : "비밀번호는 필수 항목입니다.",
            rangelength: $.validator.format("비밀번호는 최소 {0}자 이상 {1}자 이하로 입력하세요.")
        },
        confirm_memPasswd : {
            required : "비밀번호 확인은 필수 항목 입니다.",
            equalTo : "비밀번호가 맞지 않습니다."
        }
    },
    errorLabelContainer:$("#error_ul"),
    wrapper: 'li',
    highlight: function (element) {
        $(element).parent().addClass('has-error')
    },
    unhighlight: function (element) {
        $(element).parent().removeClass('has-error')
    }
});
            
cs

The specified JRE installation does not exist

이클립스에서 톰캣 구동 시 해당 오류가 나는 경우가 있습니다.

JAVA JRE 경로를 제대로 지정해주면 됩니다.



Window -> Preferences -> Server -> Runtime Environments






Bootstrap 기반 AdminLTE Framework 소개

보통 개발자는 CSS, Image 들을 만들거나, 수정하거나 할 일이 거의 없습니다.

그러다보니 디자이너가 없을 경우 Web 개발 시 디자인으로 힘들 수 있습니다.

그래서 저 같은 경우에는 Bootstrap 을 자주 이용합니다.


개인적으로 Bootstrap 장점은

1. 다양한 Icon 과 디자인 구성하기 편한 Grid System

2. 편리한 Components

3. 좋은 확장성

4. IE, 크롬 등 크로스 브라우징 시 디자인 교정


특히 Bootstrap 으로 만들어진 UI Framework 들이 많습니다.

저는 일반 사용자 대상 Web 화면이 아닌 관리자 용이 대부분이기 때문에

차트, 표 와 같은 데이터들이 많습니다.


그래서 다양한 UI Framework 중에서도 AdminLTE 를 가장 선호합니다.

장점은

1. 로그인 화면부터 메뉴구성 차트, 표, 레이아웃 팝업 등 대부분 구성

2. 여러가지 Plugin을 통합하여 제공

3. 그리고 깔끔합니다!!





간단하게 캡처한 화면만 봐도 깔끔하지요.

https://almsaeedstudio.com/preview




UI Framework 가지고 만든게 아래의 화면입니다.

이런식으로 만들 수 있습니다.




특히 가장 중요한...

라이센스가 무료입니다.


Spring File Download 구현




Spring Framework 에서 File download 를 쉽게 구현이 가능합니다.

전체적인 로직은 파일 다운로드 URL 요청 시 해당 파일을 찾아 JSP 페이지가 아닌 Class 로 구현된 View 로 연결하여 Stream으로 요청한 Client 쪽으로 전달합니다.



1. dispatcher-servlet.xml 파일에 bean 등록

<bean id="fileDownloadView" class="com.util.FileDownloadView"/>
<bean id="fileViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver">
    <property name="order" value="0"/>
</bean>
cs




2. view 역활을 대신 할 class를 생성

public class FileDownloadView extends AbstractView{
    
    public FileDownloadView(){
        //content type을 지정. 
        setContentType("apllication/download; charset=utf-8");
    }
        
    @Override
    protected void renderMergedOutputModel(Map<String, Object> model,
            HttpServletRequest req, HttpServletResponse res) throws Exception {
        // TODO Auto-generated method stub
        
        
        File file = (File) model.get("downloadFile");
        
        res.setContentType(getContentType());
        res.setContentLength((int) file.length());
        res.setHeader("Content-Disposition""attachment; filename=\"" + 
                java.net.URLEncoder.encode(file.getName(), "utf-8"+ "\";");
        res.setHeader("Content-Transfer-Encoding""binary");
        
        OutputStream out = res.getOutputStream();
        FileInputStream fis = null;
        
        try {
            
            fis = new FileInputStream(file);
            FileCopyUtils.copy(fis, out);
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(fis != null) {
                try { 
                    fis.close(); 
                }catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        
        out.flush();
    }
}
cs





3. 파일 다운로드 요청 URL에서 생성한 View로 전달합니다.

@RequestMapping(value = "/call/callDownload.do")
public ModelAndView callDownload(@RequestParam (value="fileFullPath"String fileFullPath, 
            HttpServletRequest request, 
            HttpServletResponse response) throws Exception {
        
    LOGGER.debug("callDownload : "+ fileFullPath);
        
    File downloadFile = new File(fileFullPath);
        
    if(!downloadFile.canRead()){
        throw new Exception("File can't read(파일을 찾을 수 없습니다)");
    }
        
    return new ModelAndView("fileDownloadView""downloadFile",downloadFile);
}
cs

Http Request 하기






JAVA에서  HttpURLConnection 함수로 Http 연결이 가능합니다.

기본적으로 GET 방식과 POST 방식 둘다 가능하지만 코드는 "GET" 방식만 넣어놨습니다.


GET 방식이기 때문에 URL에 Parameter 를 추가하여 전송하면 됩니다.


예) http://127.0.0.1:8080/send?key=데이터


private final String USER_AGENT = "Mozilla/5.0";

public String sendHttp(String url) throws Exception {
        
    URL obj = new URL(url);
    HttpURLConnection con = (HttpURLConnection) obj.openConnection();
    con.setRequestMethod("GET");
    con.setRequestProperty("User-Agent", USER_AGENT);
    BufferedReader in = new BufferedReader(
            new InputStreamReader(con.getInputStream()));
    String inputLine;
    StringBuffer response = new StringBuffer();
    while ((inputLine = in.readLine()) != null) {
        response.append(inputLine);
    }
    in.close();
    return response.toString();
}
cs