대분류에 따라 소분류의 리스트가 변경되는 코드 샘플

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<select id="cnfmReturnSe" class="cnfmReturnSe" name="cnfmReturnSe" style="width: 200px;">
   <option value="0">선택</option>
   <option value="aaa" >aaa</option>
   <option value="bbb" >bbb</option>
   <option value="ccc" >ccc</option>
</select>
>
<select id="srClSe" class="srClSe" name="srClSe" style="width: 200px;">
   <option value="0">선택</option>
   <option value="ggg" class="sel1">ggg</option>
   <option value="ttt" class="sel1">ttt</option>
   <option value="yyy" class="sel2">yyy</option>
   <option value="uuu" class="sel3">uuu</option>
</select>        
cs

html 코드
class에 sel뒤 숫자를 가지고 구분해서 띄운다

 

$(function () {
		var bigSelId = "#cnfmReturnSe"; // 대분류 id
		var smlSelId = "#srClSe"; // 소분류 id
		function updateSelected() { 
			  $(smlSelId).val(0);
			  $(smlSelId).find("option[value!=0]").detach();
			  $(smlSelId).append(comboSel.filter(".sel" + $(bigSelId+" option").index($(bigSelId+" option:selected"))));
			}
		
		comboSel = $(smlSelId).find("option[value!=0]");
		comboSel.detach();
		
		$(bigSelId).change(updateSelected);
		$(bigSelId).trigger("change");
		
		// 처음 선택되어 있어야할 값. 없을시 ""으로 하면 초기화됨
		var bigSelLoad = "${selectAnswerDrBrdDetail[0].cnfmReturnSe}"; 
		var smlSelLoad = "${selectAnswerDrBrdDetail[0].srClSe}";
		
		// 대분류 값이 있으면 select에 적용
		if(bigSelLoad!="")
		$(bigSelId+' option[value="'+bigSelLoad+'"]').prop("selected", true);
		
		// 대분류값이 바뀌면 소분류 리스트 변경
		$(smlSelId).val(0);
		$(smlSelId).find("option[value!=0]").detach();
		$(smlSelId).append(comboSel.filter(".sel" + $(bigSelId+" option").index($(bigSelId+" option:selected"))));
		
		// 소분류 값이 있으면 select에 적용
		if(smlSelLoad!="")
		$(smlSelId+' option[value="'+smlSelLoad+'"]').prop("selected", true);
});

bigSelId에는 해당 select의 id 입력
bigSelLoad에 선택되어져야할 값이 있을때 value 값을 넣으면 선택되어짐
단, 대분류와 소분류의 관계가 맞아야함

 

위 구성으로 서버에 있는 파일을 로컬로 복사할수있다.

 

 

ListSFTP 설정

서버 IP와 비번 입력후 Path는 복사해오기 원하는 경로 지정

 

 

FetchSFTP 설정

 

PutFile

 

이상태로 시작시키면 지정폴더로 복사되는걸 확인할수 있음

'업무관련 > 그외' 카테고리의 다른 글

sourceInsight4 Base utils.em 주석 처리 추가하기  (0) 2024.12.04
NIFI 임시 실행법  (1) 2023.11.22

다운받으면 압축풀고 하위 폴더 bin 폴더를 찾아 

 

run-nifi.bat 더블클릭 실행

실행이 완료되면

127.0.0.1:8443/nifi/

접속하면 아이디 패스워드 입력란 뜸

 

 

logs 폴더에 들어가면 nifi-app.log안에 아이디와 비번이 있음

임시 아이디와 비번이 나옴

 

 

 

 

difingo에서 api형식으로 받아올때 그대로 입력하고 그대로 받아올수 있게 만듬

 

 

우선 컨트롤러단에서 아래 함수를 만든다.

 

 

 

 

< difingo로 들어가는 로직 INput 후 Jsion으로 return >

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
 
    // Api 요청시 가져오기 반복적인 부분을 단축시키기 위해 넣음
    // String sRequiredParam = "SHYR,SMST_CD,DERT_MAJR_CD"; // 필수 파라미터 ','값으로 구분/ 빈칸없게
    // ArrayList<DataSet> arrDataSet = 데이터셋으로 전달할 데어터
    private HashMap<Integer, Object> GetRestXupProcess(String domainName, String modelName, String sRequiredParam,
            HttpServletRequest request, HttpServletResponse response,ArrayList<DataSet> arrDataSet) throws Exception {
        // 1 Json 문자열, 2 HttpHeaders 3 HttpStatus
        HashMap<Integer, Object> RestMap = new HashMap<Integer, Object>();
 
        HttpHeaders resHeaders = new HttpHeaders();
        resHeaders.add("Content-Type""application/json;charset=UTF-8");
        RestMap.put(2, resHeaders);
 
        InetAddress inetAddress = InetAddress.getLocalHost();
        // System.out.println("##########################################################");
        // System.out.println("/lms/stdCose.do");
        // System.out.println("parameter == > " +
        // request.getParameter("param").toString());
        // System.out.println("ip == > " + inetAddress.getHostAddress());
        // System.out.println("##########################################################");
 
        HttpPlatformRequest tempRequest = new HttpPlatformRequest(request);
        tempRequest.receiveData();
        PlatformData reqdata = tempRequest.getData();
        
        // 데이터셋 전부 가져오기
        if(arrDataSet!=null)
        {
            for(DataSet data : arrDataSet) {
                reqdata.addDataSet(data);
            }
        }
        
        // 필수 파라미터 ','값으로 구분
        String[] arrRequiredParam = sRequiredParam.split(",");
        ArrayList<String> arrParams = new ArrayList<String>();
        int nIndex = 0// while문에 index를 넣기 위함
        int nRequiredParamCnt = 0// 필수 파라미터 횟수
 
        // 모든 파라미터 XUP Variable에 넣기
        Enumeration params = request.getParameterNames();
        while (params.hasMoreElements()) {
            //String name = (String) params.nextElement();
            arrParams.add((String) params.nextElement());
            
        }
        
        for(String sParam:arrParams) {
            for(String sRParam:arrRequiredParam) {
                if (sRParam.equals(sParam)) {
                    nRequiredParamCnt++;
                }
            }
            reqdata.addVariable(new Variable(sParam, PlatformDataType.STRING, request.getParameter(sParam)));
        }
        
        // 필수 파라미터가 부족하면
        if (nRequiredParamCnt < arrRequiredParam.length) {
            // 400 에러
            // System.out.println("#### 에러");
            RestMap.put(1"Required Error");
            RestMap.put(3, HttpStatus.BAD_REQUEST);
            return RestMap;// new ResponseEntity<String>("Required Error", resHeaders,
                            // HttpStatus.BAD_REQUEST);
        }
        
 
        XIConnector connector = XIConnector.getConnector((HttpServletRequest) request, (HttpServletResponse) response);
        XIServiceRequest serviceRequest = connector.createXIRequest(domainName, modelName, reqdata);
        serviceRequest.setSession(((HttpServletRequest) request).getSession());
        ServiceResponse res = connector.execute(serviceRequest);
        PlatformData data = res.getPlatformData();
 
        JSONObject rootObject = new JSONObject();
        DataSetList dataSetList = data.getDataSetList();
 
        // 레코드셋 → JSON으로 변형
        for (int dataSetIndex = 0; dataSetIndex < dataSetList.size(); dataSetIndex++) {
            DataSet temp = dataSetList.get(dataSetIndex);
 
 
            JSONArray rows = new JSONArray();
 
 
            for (int rowIndex = 0; rowIndex < temp.getRowCount(); rowIndex++) {
                JSONObject tempRow = new JSONObject();
                for (int columnIndex = 0; columnIndex < temp.getColumnCount(); columnIndex++) {
                    tempRow.put(temp.getColumn(columnIndex).getName(), temp.getString(rowIndex, columnIndex));
                }
                rows.add(tempRow);
 
            }
            rootObject.put(temp.getName(), rows);
        }
 
        RestMap.put(1, rootObject.toJSONString());
        RestMap.put(3, HttpStatus.OK);
        return RestMap;
    }
 
cs

 

 

< 위 함수에 데이터셋이 여러개라면 데이터셋을 묶어주는 함수 >

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
 
 
    // 데이터셋 컬럼 및 ROW 추가
    // String DsName -> "dsSearch" xup에 넣을 데이터셋 이름
    // String DsParameter -> "SHYR,SMST_CD,USER_NO" 생성된 데이터셋에 넣을 파라미터
    // int DsRowType -> DataSet.ROW_TYPE_NORMAL, DataSet.ROW_TYPE_INSERTED, DataSet.ROW_TYPE_UPDATED, DataSet.ROW_TYPE_DELETED
    // HttpServletRequest request
        
    private DataSet DataSetProcess(String DsName,String DsParameter,int DsRowType,HttpServletRequest request) {
        DataSet dsSet = new DataSet(DsName);
        
        //System.out.println("AAAA : "+ DsRowType);
        String[] arrRequiredParam = DsParameter.split(",");
        for(String sRequiredParam : arrRequiredParam)
        {
            dsSet.addColumn(sRequiredParam, PlatformDataType.STRING, 255);
            //System.out.println("ADASD : "+sRequiredParam);
        }
        int iRow = dsSet.newRow();
        for(String sRequiredParam : arrRequiredParam)
        {
            dsSet.set(iRow, sRequiredParam, request.getParameter(sRequiredParam));
            //System.out.println("bbbb : "+sRequiredParam);
        }
        dsSet.setRowType(iRow, DsRowType);
        return dsSet;
    }
 
 
 
cs

 

 

 

 

 

< 실제 사용법 예제 1 >

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
        
        //http://localhost:8088/kcu/lms/LRN_LM_01501M01_M01.do?SHYR=2022&SMST_CD=10&USER_NO=22134064&COSE_CD=ES100201&DERT_MAJR_CD=1404150100&SUBJ_CD=ES1002&COPL_SE_CD=1&PNT_SCOR=3&LESS_SHYR=1&ATNLC_APLY_STTS_CD=0&userId=22134064&clientIP=127.0.0.1&programID=LRN_LM_01501M01
        @RequestMapping(value = "/lms/LRN_LM_01501M01_M01.do", method = RequestMethod.POST)
        @ResponseBody
        public ResponseEntity<String> LRN_LM_01501M01_M01(HttpServletRequest request, HttpServletResponse response) throws Exception {
            HashMap<Integer, Object> RestMap = new HashMap<Integer, Object>();
            
            ArrayList<DataSet> arrDataSet = new ArrayList<DataSet>();
            // 데이터셋 작성
            arrDataSet.add(DataSetProcess("dsSearch","USER_NO",DataSet.ROW_TYPE_INSERTED,request));
            arrDataSet.add(DataSetProcess("dsCoplBag","SHYR,SMST_CD,COSE_CD,SUBJ_CD,COPL_SE_CD,PNT_SCOR,LESS_SHYR,DERT_MAJR_CD,ATNLC_APLY_STTS_CD",DataSet.ROW_TYPE_INSERTED,request));
            arrDataSet.add(DataSetProcess("gdsCommonIn1","userId,clientIP,programID",DataSet.ROW_TYPE_INSERTED,request));
            
            
            try {
                // 일반 파라미터 및 데이터셋 xup 실행
                RestMap = GetRestXupProcess("xup_lms""LRN_LM_01501M01_M01",
                        "USER_NO,SHYR,SMST_CD,COSE_CD,DERT_MAJR_CD,SUBJ_CD,COPL_SE_CD,PNT_SCOR,LESS_SHYR,DERT_MAJR_CD,ATNLC_APLY_STTS_CD,userId,clientIP,programID"
                        ,request,response,arrDataSet);
            } catch (Exception e) {
                // TODO: handle exception
                HttpHeaders resHeaders = new HttpHeaders();
                resHeaders.add("Content-Type""application/json;charset=UTF-8");
                return new ResponseEntity<String>(e.toString(), resHeaders, HttpStatus.INTERNAL_SERVER_ERROR);
            }
 
            return new ResponseEntity<String>((String) RestMap.get(1), (HttpHeaders) RestMap.get(2),(HttpStatus) RestMap.get(3));
        }
 
 
cs

 

아래 invoke 사용시 위 함수를 사용하면 그대로 사용할수 있다.

 

 

 

< 실제 사용법 예제 2 >

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
        
        //http://localhost:8088/kcu/lms/LRN_LM_01201M01_S01.do?SHYR=2022&SMST_CD=10&USER_NO=22134064
        @RequestMapping(value = "/lms/LRN_LM_01201M01_S01.do", method = RequestMethod.GET)
        @ResponseBody
        public ResponseEntity<String> LRN_LM_01201M01_S01(HttpServletRequest request, HttpServletResponse response) throws Exception {
            HashMap<Integer, Object> RestMap = new HashMap<Integer, Object>();
            
            ArrayList<DataSet> arrDataSet = new ArrayList<DataSet>();
            // 데이터셋 작성
            arrDataSet.add(DataSetProcess("dsSearch","SHYR,SMST_CD,USER_NO",DataSet.ROW_TYPE_NORMAL,request));
            
            try {
                // 일반 파라미터 및 데이터셋 xup 실행
                RestMap = GetRestXupProcess("xup_lms""LRN_LM_01201M01_S01",
                        "SHYR,SMST_CD,USER_NO"
                        ,request,response,arrDataSet);
            } catch (Exception e) {
                // TODO: handle exception
                HttpHeaders resHeaders = new HttpHeaders();
                resHeaders.add("Content-Type""application/json;charset=UTF-8");
                return new ResponseEntity<String>(e.toString(), resHeaders, HttpStatus.INTERNAL_SERVER_ERROR);
            }
 
            return new ResponseEntity<String>((String) RestMap.get(1), (HttpHeaders) RestMap.get(2),(HttpStatus) RestMap.get(3));
        }
 
 
cs

 

아래 invoke 에서 가져올수 있다.

위 예제 실행시 return 결과

 

 

 

 

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
 
    public static void addCookie(HttpServletResponse response, String name, String value, String sSameSite) {
        ResponseCookie cookie = ResponseCookie.from(name, value)
            .path("/kcu")
            .sameSite(sSameSite)
            .httpOnly(true)
            .secure(true//-> secure 옵션을 true로 변경한다.
            //.maxAge(maxAge)
            .build();
 
        response.addHeader("Set-Cookie", cookie.toString());
    }
 
....
        // sameSite=None 처리
        addCookie(response,"JSESSIONID",request.getSession().getId(),"None");
....
 
        // None이 아니게 복구하기
        addCookie(response,"JSESSIONID",request.getSession().getId(),"");
 
 
cs

 

 

 

 

 

 

 

Popup_Nexacro.jsp 또는 html로 만든다.

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.*"%>
<%
    // 고유한 세션 객체의 ID를 되돌려준다.
    String id_str = session.getId();
 
    // 세션에 마지막으로 엑세스한 시간을 되돌려 준다.
    long lasttime = session.getLastAccessedTime();
   
    // 세션이 생성된 시간을 되돌려 준다.
    long createdtime = session.getCreationTime();
   
    // 세션에 마지막으로 액세스한 시간에서 세션이 생성된 시간을 빼면 웹 사이트에 머문 시간이 계산된다.
    long time_used = (lasttime - createdtime) / 60000;
   
    // 세션의 유효 시간 얻어오기
    int inactive = session.getMaxInactiveInterval() / 60;
   
    // 세션이 새로 만들어졌는지를 알려준다.
    boolean b_new = session.isNew();
%>
<!doctype html>
<html>
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    
    <title>결재창</title>
</head>
 
<body>
    <div >
        <h1>결제중</h1>
        <h1>이창을 닫지 마세요</h1>
        <!--
        <h1><%=id_str%></h1>
        <h1><%=b_new%></h1>
        -->
    </div>
    <script>
        let NexPopUp;
 
        if (!window.NEXACROHTML) {
            window.NEXACROHTML = {};
        }
 
        // 키와 데이터를 전달
        window.NEXACROHTML.FireUserNotify = function (sAddr,sData) {
            var arrData = new Array();
            arrData[0]= sAddr; // Key
            arrData[1]= sData; // Value
 
            if (window.NEXACROWEBBROWSER) {
                window.NEXACROWEBBROWSER.on_fire_onusernotify(window.NEXACROWEBBROWSER, arrData);
            }
        }
 
 
        // 새로운 팝업창에 올림
        function fnCallPopUp(arrInfo) {
            var hostUrl =  document.location.protocol +"//"+document.location.host;
            console.log(hostUrl);
            //alert(hostUrl);
            //var url = "http://"+hostUrl+"/kcu/pay/INIstdpay_pc_req.jsp?";
            var url = hostUrl+"/kcu/chat/lmsChat.html?";
            var name = "lmsChat";
            var option = "width = 1000, height = 800, top = 100, left = 200, location = no";
            // 파라메터 입력
            for (let index = 0; index < arrInfo.length; index++) {
                url+=arrInfo[index][0]+"="+arrInfo[index][1]+"&";
            }
            //alert(url);
            NexPopUp=window.open(url, name, option);
            setTimeout(fnIsPopupClosed, 1000);
        }
 
        // 팝업창이 떠있는지 확인해서 없으면 사용자가 팝업창을 강제로 닫은거임
        function fnIsPopupClosed() {
            if(NexPopUp.closed)
            {
                fnFromPopup("PopupClose","0");
            }
            else{
                setTimeout(fnIsPopupClosed, 1000);
            }
            
        }
        
 
        // 팝업으로 보내기
        function fnToPopup(x) {
            NexPopUp.document.getElementsByName("buyertel")[0].value=x;
        
        }
 
        // 팝업에서 받기
        function fnFromPopup(key,val) {
            window.NEXACROHTML.FireUserNotify(key,val);
        }
 
        // 팝업 닫기
        function fnFromPopupCloseMe() {
            NexPopUp.close();
        }
 
        
 
    </script>
</body>
 
</html>
cs

 

 

 

 

넥사크로에는 아래와 같이 webBrowser 컴포넌트와 이벤트 2개를 생성한다.

팝업을 띄우고 싶은 부모화면 안에 추가해야함.

 

 

 

넥사크로 코드

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
this.divMain_btnIntoChat00_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
 
        if(this.dsList.rowcount==0)
        {
            return;
        }
        
        // 팝업을 실행시키기
        var objEnv = nexacro.getEnvironment();
        var sUrl = objEnv.services['exlUrl'].url;// + "/addr/postcode.jsp";
        trace("aa : "+sUrl); // http://localhost:8088/kcu/
 
        this.divMain.form.web00.set_url(sUrl+"chat/lmsChat_Nexacro.jsp");
};
 
 
 
// 웹이 성공적으로 열렸을때 html에 아래 파라미터를 넣고 호출할수 있다. 
this.web00_onloadcompleted = function(obj:nexacro.WebBrowser,e:nexacro.WebLoadCompEventInfo)
{
    trace("web00_onloadcompleted :"+e.url);
    
    // url에 파라메터로 넘길값
    var arrList = new Array();
    
    // 참가자명
    var arrKeyVal = new Array("NAME",this.dsSearch.getColumn(0,"USER_NAME"));
    arrList.push(arrKeyVal);
    
    // 학년도 학기명 EX)2023학년도 1학기
    arrKeyVal = new Array("SMST_NM",this.dsList.getColumn(0,"SHYR")+"학년도 "+this.dsList.getColumn(0,"SMST_NM"));
    arrList.push(arrKeyVal);
    
    
    // 과목명
    arrKeyVal = new Array("DERT_NM",this.dsList.getColumn(this.divMain.form.cboSubj.index,"SUBJ_KORN_NM"));
    arrList.push(arrKeyVal);
    
    
    
    // 과목코드 (방번호지정됨)
    arrKeyVal = new Array("DERT_CD",this.dsList.getColumn(this.divMain.form.cboSubj.index,"COSE_CD"));
    arrList.push(arrKeyVal);
    
    
    // 과목기본정보명
    var sInfoString = "";
    sInfoString += this.dsList.getColumn(this.divMain.form.cboSubj.index,"COPL_SE_NM")+" / ";
    sInfoString += this.dsList.getColumn(this.divMain.form.cboSubj.index,"BAN")+"반 / ";
    sInfoString += this.dsList.getColumn(this.divMain.form.cboSubj.index,"PROFINSTR_NM")+"교수님 / ";
    sInfoString += this.dsList.getColumn(this.divMain.form.cboSubj.index,"PNT_SCOR")+"학점";
    
    arrKeyVal = new Array("DERT_INFO",sInfoString);
    arrList.push(arrKeyVal);
    
    
    trace(arrList);
    
    
        
    // web에 결재정보 보내기
    // OID  년월일시분초학년도학기학번 2023061314353920221022134061
    var _doc = this.divMain.form.web00.getProperty("window");
    _doc.callMethod("fnCallPopUp", arrList);
    
    
    if(_doc){
        _doc.destroy();
        _doc = null;
    }
};
 
 
 
 
// html에서 받아올수도 있다.
this.web00_onusernotify = function(obj:nexacro.WebBrowser,e:nexacro.WebUserNotifyEventInfo)
{
    switch(e.userdata[0]) {
    case "visibilityState"// visible, hidden
        if(e.userdata[1]=="visible")
        {
            // 작업
        }
        else
        {
            // 작업    
        }
        break;
    case "videoState":
        if(e.userdata[1]=="pause")
        {
            // 작업
        }
        else
        {
            // 작업    
        }
        
        break;
    default:
        break;
    }
};
 
 
this.fnPopClose = function ()
{
    // 여기서 팝업을 닫을수도 있다.
    var _doc = this.divMain.form.web00.getProperty("window");
    _doc.callMethod("fnFromPopupCloseMe");
    
    
    if(_doc){
        _doc.destroy();
        _doc = null;
    }
};
 
 
 
cs

 

이렇게 해야 넥사크로의 팝업을 제어할수 있고 데이터도 받을수 있음

 

 

 

 

 

 

 

 

websocket으로 채팅방 만드는 방법

 

채팅방 번호로 방을 구분하고

일반적인 문자 채팅을 구현한다.

 

 

pom.xml 에 아래 라이브러리를 추가

1
2
3
4
5
6
<dependency>
              <groupId>javax.websocket</groupId>
              <artifactId>javax.websocket-api</artifactId>
              <version>1.1</version>
</dependency>
 
cs

 

 

컨트롤러단

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
 
 
 
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Controller;
 
 
 
 
@Controller
@ServerEndpoint("/lms/chat")
public class lmsChatController extends Socket {
    private static final List<Session> session = new ArrayList<Session>();
    private static final HashMap<StringString[]> chatIdMap = new HashMap<StringString[]>(); // 접속자의 정보를 저장
    
    @OnOpen
    public void open(Session newUser) {
        System.out.println("connected");
        
        session.add(newUser);
        System.out.println("현재 접속중인 유저 수 : " + session.size() + " : "+newUser.getId());
        
        
    }
 
    @OnMessage
    public void getMsg(Session recieveSession, String msg) {
        System.out.println("getMsg : " + msg +" : "+recieveSession.getId());
        String[] arrChatIdMap;
        
        // 0 명령
        // 1 이름
        // 2 학과명
        // 3 학과코드
        String[] arrMsg = msg.split(":,:");
        
        System.out.println("정보 : " + arrMsg[0+" : "+ arrMsg.length);
        switch(arrMsg[0]) {
        
        case "CONNECT":
            
            chatIdMap.put(recieveSession.getId(), arrMsg);
            arrChatIdMap = chatIdMap.get(recieveSession.getId());
            System.out.println("첫 접속정보 : " + session.size() + " : "+chatIdMap.size() + " : "+recieveSession.getId());
            connectlog(chatIdMap);
             String sConnUserName ="";
              for (Entry<StringString[]> entrySet : chatIdMap.entrySet()) {
                 String[] arrChatIdInfo= entrySet.getValue();
                 if(arrChatIdInfo[3].equals(arrChatIdMap[3])) {
                     sConnUserName+=arrChatIdInfo[1]+"+,+";
                 }
                 //System.out.println("AA : "+entrySet.getKey() + " : " + sConnUserName);
             }
             sConnUserName=sConnUserName.substring(0, sConnUserName.length()-3);
            
             for (int i = 0; i < session.size(); i++) {
                  try {
                            if(session.get(i).isOpen()) {
                                System.out.println("접속자 정보 : " + i);
                                System.out.println("CON:,:"+sConnUserName+":,:"+arrChatIdMap[1]+"님이 접속하였습니다"+":,:"+arrChatIdMap[3]);
                                session.get(i).getBasicRemote().sendText("CON:,:"+sConnUserName+":,:"+arrChatIdMap[1]+"님이 접속하였습니다"+":,:"+arrChatIdMap[1]+":,:"+arrChatIdMap[2]+":,:"+arrChatIdMap[3]);
                            }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            
            break;
            
        case "MESSAGE":
        default:
             arrChatIdMap = chatIdMap.get(recieveSession.getId());
             for (int i = 0; i < session.size(); i++) {
                    if (! recieveSession.getId().equals(session.get(i).getId())) {
                        try {
                            if(session.get(i).isOpen()) {
                                session.get(i).getBasicRemote().sendText("U:,:"+arrChatIdMap[1]+":,:"+ msg+":,:"+arrChatIdMap[1]+":,:"+arrChatIdMap[2]+":,:"+arrChatIdMap[3] ); // 너가 보낸거
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    } else {
                        try {
                            if(session.get(i).isOpen()) {
                                session.get(i).getBasicRemote().sendText("I:,:"+arrChatIdMap[1]+":,:"+ msg+":,:"+arrChatIdMap[1]+":,:"+arrChatIdMap[2]+":,:"+arrChatIdMap[3] ); // 내가 보낸거
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            break;
        }     
       
    }
    
    @OnClose
    public void close(Session recieveSession) {
        int sessionSize = session.size();
        if (sessionSize != 0) {
            try {
                 for (int i = 0; i < sessionSize; i++) {
                    // System.out.println("get : "+i+":"+recieveSession.getId() + " : "+session.size());
                     if (session.get(i).isOpen()) {
                         String[] arrChatIdMap = chatIdMap.get(recieveSession.getId());
                         //0 구분
                         //1 참여자 정보
                         //2 메시지
                         //3 학과번호
                         //4 학과명
                          String sConnUserName ="";
                          for (Entry<StringString[]> entrySet : chatIdMap.entrySet()) {
                             String[] arrChatIdInfo= entrySet.getValue();
                             System.out.println("AA : "+arrChatIdInfo[3+ " : " + arrChatIdMap[3]);
                             if(arrChatIdInfo[3].equals(arrChatIdMap[3])) {
                                     sConnUserName+=arrChatIdInfo[1]+"+,+";                                
                             }
                         }
                         sConnUserName=sConnUserName.substring(0, sConnUserName.length()-3);
                         
                         
                         System.out.println("DCON:,:"+sConnUserName+":,:"+arrChatIdMap[1]+"님이 접속을 종료하였습니다"+":,:"+arrChatIdMap[3]+":,:"+arrChatIdMap[1]);
                         session.get(i).getBasicRemote().sendText("DCON:,:"+sConnUserName+":,:"+arrChatIdMap[1]+"님이 접속을 종료하였습니다"+":,:"+arrChatIdMap[1]+":,:"+arrChatIdMap[2]+":,:"+arrChatIdMap[3]);
                     }
                 }
                List<Integer> nRemoveNum=new ArrayList<Integer>();
                for (int i = 0; i < sessionSize; i++) {
                    System.out.println("close : "+i+":"+recieveSession.getId() + " : "+session.size());
                    if (! session.get(i).isOpen()) {
                        nRemoveNum.add(i);
                        chatIdMap.remove(recieveSession.getId());
                    }
                }
                for(int forInt:nRemoveNum) {
                    session.remove(forInt);
                }
                
                
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }    
    
    @OnError
    public void error(Session recieveSession, Throwable error) {
        System.out.println("error : "+error.toString()+" : "+recieveSession.getId());
        if(chatIdMap.containsKey(recieveSession.getId()))
        {
            chatIdMap.remove(recieveSession.getId());
        }
    }
    
    private void connectlog(HashMap<StringString[]> log) {
        
         for (Entry<StringString[]> entrySet : log.entrySet()) {
             String[] logtest= entrySet.getValue();
             String bb = entrySet.getKey()+" = ";
             for(String a:logtest) {
                 bb+=a+" : ";
             }
             System.out.println("AA : "+entrySet.getKey() + " : " + bb);
         }
        
    }
    
}
 
cs

 

 

 

HTML 단

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Chat</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</head>
<style>
    * {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}
 
{
    text-decoration: none;
}
 
.wrap {
    padding: 40px 0;
    background-color: #A8C0D6;
}
 
.wrap .chat {
    display: flex;
    align-items: flex-start;
    padding: 20px;
}
 
.wrap .chat .icon {
    position: relative;
    overflow: hidden;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    background-color: #eee;
}
 
.wrap .chat .icon i {
    position: absolute;
    top: 10px;
    left: 50%;
    font-size: 2.5rem;
    color: #aaa;
    transform: translateX(-50%);
}
 
.wrap .chat .textbox {
    position: relative;
    display: inline-block;
    max-width: calc(100% - 70px);
    padding: 10px;
    margin-top: 7px;
    font-size: 13px;
    border-radius: 10px;
}
 
.wrap .chat .textbox::before {
    position: absolute;
    display: block;
    top: 0;
    font-size: 1.5rem;
}
 
.wrap .ch1 .textbox {
    margin-left: 20px;
    background-color: #ddd;
}
 
.wrap .ch1 .textbox::before {
    left: -15px;
    content: "◀";
    color: #ddd;
}
 
.wrap .ch2 {
    flex-direction: row-reverse;
}
 
.wrap .ch2 .textbox {
    margin-right: 20px;
    background-color: #F9EB54;
}
 
.wrap .ch2 .textbox::before {
    right: -15px;
    content: "▶";
    color: #F9EB54;
}
 
.wrap .ch3 {
    flex-direction: row-reverse;
}
 
.wrap .ch3 .textbox {
    margin-left: 50%;
    /* background-color: #9d5830; */
}
/* 
.wrap .ch3 .textbox::before {
    right: -15px;
    color: #9d5830;
} */
 
 
</style>
<body onload="HtmlOnload();">
 
 
<div class="chatTitle">
    <h1>[과목채팅]</h1>
    <h3 id="SmstNm_h1"></h1>
    <h3 id="DertNm_h1"></h1>
    <h5 id="DertInfo_h1"></h1>
</div>
<!-- 채팅 입력창 -->
<div style="width: 70%; float: left; overflow-y: scroll; height:90%;">
    <div class="wrap"></div>
    <div id="chatFocus">
    </div>
</div>
 
<div style="float: right; width: 30%; top: 0;">
    참여자
<div class="container mt-3" id="nameTable" style="width: 100%; height: 90%; overflow-y: scroll;">
    
    <table class="table table-striped" style="width: 100%;">
        <!-- 현재 접속자 -->
        <tbody class="connecterName"> 
          <tr>
            <td>John</td>
          </tr>
        </tbody>
      </table>
</div>
</div>
 
<div class="msgArea" style="position: fixed; bottom: 0%; width: 100%;">
    <div class="input-group input-group-lg mb-3">
    <input type="text" placeholder="보낼 메세지를 입력하세요." onkeyup="if(window.event.keyCode==13){sendMsg()}" class="chatMsgText form-control">
    <span class="input-group-text"  onclick="sendMsg()">전송</span>
    <!-- <button type="button" class="btn btn-primary" value="전송" class="sendBtn" onclick="sendMsg()">전송</button> -->
    </div>
    
</div>
 
 
 
 
 
</body>
<script>
        var hostUrl = document.location.protocol +"//"+ document.location.host;
        console.log(hostUrl)
        let ws;//      var ws = new WebSocket('ws://localhost:8080');
        
        function getParameter(name) {
            name = name.replace(/[\[]/"\\[").replace(/[\]]/"\\]");
            var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
                results = regex.exec(location.search);
            return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
            
        }
 
 
 
 
        let sName    =  getParameter("NAME");
        let sDertNm    =  getParameter("DERT_NM"); // 과목명
        let sDertCd    =  getParameter("DERT_CD"); // 과목코드 (방번호)
        let sSmstNm    =  getParameter("SMST_NM"); // 학년도학기
        let sDertInfo    =  getParameter("DERT_INFO"); // 과목기본정보
        
 
        function connect() {
            let sHost = document.location.host;
            ws = new WebSocket("ws://"+sHost+"/kcu/lms/chat");
 
            console.log('connect');
            ws.onopen = function() {
                // subscribe to some channels
                
                let sChatVistor = "CONNECT"+":,:"+sName+":,:"+sDertNm+":,:"+sDertCd;
                console.log(sChatVistor);
                ws.send(sChatVistor);
            };
 
            // 메시지 수신
            ws.onmessage = function(e) {
                console.log('Message:', e.data);
                // 0 U,I,CON,DCON
                // 1 이름
                // 2 메시지
                // 3 학과명
                // 4 학과코드
                let arrMsg = e.data.split(":,:");
                console.log('a : '+sDertCd +" : "+arrMsg[5]);
                
                if(sDertCd!=arrMsg[5]){
                        return;
                }
 
                let sChatMsgDiv="";
                if(arrMsg[0]=="U"// 너가 보낸 메시지
                {
                    
                    sChatMsgDiv='<div class="chat ch1">';
                    sChatMsgDiv+='<div class="icon" style="text-align: center;">'+arrMsg[1]+'<i class="fa-solid fa-user"></i></div>';
                    sChatMsgDiv+='<div class="textbox">'+arrMsg[2]+'</div>';
                    sChatMsgDiv+='</div>';
 
                }else if(arrMsg[0]=="I"){ // 내가 보낸 메시지
                    sChatMsgDiv='<div class="chat ch2">';
                    sChatMsgDiv+='<div class="icon" style="text-align: center;">'+arrMsg[1]+'<i class="fa-solid fa-user"></i></div>';
                    sChatMsgDiv+='<div class="textbox">'+arrMsg[2]+'</div>';
                    sChatMsgDiv+='</div>';
                }
                else  if(arrMsg[0]=="CON"){ // 접속
                    sChatMsgDiv='<div class="chat ch3">';
                    sChatMsgDiv+='<div class="textbox">'+arrMsg[2]+'</div>';
                    sChatMsgDiv+='</div>';
 
                    let sChatVistorNames="";
                    sChatVistorNames+='<table class="table table-striped" style="width: 100%;">';
                    sChatVistorNames+='<tbody class="connecterName">';
                    let arrNames = arrMsg[1].split("+,+"); // 참여자들이 String에 묶에서 들어오는것 품
                    for(let i=0;i<arrNames.length;i++){ // 참여자 목록을 넣기 위함
                        sChatVistorNames+="<tr>";
                        sChatVistorNames+="<td>"+arrNames[i]+"</td>";
                        sChatVistorNames+="</tr>";
                    }
                    sChatVistorNames+='</tbody></table>';
                    document.getElementById('nameTable').innerHTML=sChatVistorNames;
 
                }
                else  if(arrMsg[0]=="DCON"){ // 접속 종료
                    console.log('DCON : ');
                    sChatMsgDiv='<div class="chat ch3">';
                    sChatMsgDiv+='<div class="textbox">'+arrMsg[2]+'</div>';
                    sChatMsgDiv+='</div>';
 
                    let sChatVistorNames="";
                    sChatVistorNames+='<table class="table table-striped" style="width: 100%;">';
                    sChatVistorNames+='<tbody class="connecterName">';
                    let arrNames = arrMsg[1].split("+,+");// 참여자들이 String에 묶에서 들어오는것 품
                    let bOutNameFlag=false// 접속 종료시 동명이인일 경우를 대비하여 한개의 이름만 빼게 함
                    for(let i=0;i<arrNames.length;i++){
 
                        console.log('CCC : '+arrNames[i] +" : "+arrMsg[3]);// 접속 종료자의 이름을 하나만 없앤다.
                        if(bOutNameFlag){
                            arrMsg[3]="";
                        }
 
                        if((arrMsg[3]!=arrNames[i])){ // 종료자를 제외한 모든 참여자 추가
                            sChatVistorNames+="<tr>";
                            sChatVistorNames+="<td>"+arrNames[i]+"</td>";
                            sChatVistorNames+="</tr>";
                        }
                        else{
                            bOutNameFlag=true;
                        }
                    }
                    sChatVistorNames+='</tbody></table>';
                    document.getElementById('nameTable').innerHTML=sChatVistorNames;
 
                }
                else{
                    return;
                }
                document.querySelector('.wrap').insertAdjacentHTML("beforeend",sChatMsgDiv);
                document.getElementById("chatFocus").scrollIntoView();
 
            };
 
            
            ws.onclose = function(e) {
                console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
                setTimeout(function() {
                connect();
                }, 1000);
            };
 
            ws.onerror = function(err) {
                console.error('Socket encountered error: ', err.message, 'Closing socket');
                ws.close();
            };
        }
 
        function HtmlOnload() {
            connect();
            document.getElementById("DertNm_h1").innerHTML =sDertNm;
            document.getElementById("SmstNm_h1").innerHTML =sSmstNm;
            document.getElementById("DertInfo_h1").innerHTML =sDertInfo;
        }
        
 
 
        function sendMsg() {
            let chatMsgText=document.querySelector('.chatMsgText').value;
            document.querySelector('.chatMsgText').value="";
            console.log("SENd : "+chatMsgText);
            if(chatMsgText!="")
            {
                ws.send(chatMsgText);
            }
        }
       
</script>
</html>
cs

 

 

 

session값 저장과 함께 사용자를 구분할 chatIdMap 을 생성한다.

들어오는 내용은 (:,:)로 split하여 보낸사람의 정보를 받는다.

 

.../lmsChat.html?NAME=황재철&DERT_NM=위험물질론&DERT_CD=FD201701 

처음 접속할때 HTML에서 @OnMessage를 한번 보낸다.

예) CONNECT:,:황재철:,:위험물질론:,:FD201701 

1 접속할때 접속했다는걸 보내기 위한 구분

2 접속자 이름

3 채팅방 이름

4. 채팅방 구분번호

 

 

그뒤 참여자 목록을 (+,+)로 구분하여 같이 묶어서 보낸다.

참여했습니다., 종료했습니다. 들어올때 참여자를 삭제 추가 하여 참여자 정보를 유지한다.

 

메시지는 이름하고 내가 보낸건지 상대가 보낸건지 구분하여 전달하고 좌우 표시한다.

 

위 파라미터에서 DERT_CD가 동일해야 같은 방에 들어있는걸로 동작됨

 

졸작 수준의 채팅 완료

 

 

 

 

 

 

네비에 글 보이기 설정