WebApplicationInitializer 인터페이스를 사용하면 web.xml에서 했던 서블릿, 필터, 리스너 설정 등을 java로 설정할 수 있다.
처음에 그것도 모르고 web.xml에 아무것도 없어 당황을....^^;

프로젝트를 하나 만들어 아래와 같이 간단히 등록하고 테스트를 해보니 정상 동작되는 것을 확인했다.

 

package testweb;
 
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
 
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;
 
public class Init implements WebApplicationInitializer {
 
	@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		System.out.println("onStartup...");
		addListender(servletContext);
		addDispatcher(servletContext);
		addFilter(servletContext);
	}
 
	public void addListender(ServletContext servletContext) {
		System.out.println("addListender...");
		AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
		appContext.register(AppConfig.class);
		ContextLoaderListener listender = new ContextLoaderListener(appContext);
		servletContext.addListener(listender);
	}
 
	public void addDispatcher(ServletContext servletContext) {
		System.out.println("addDispatcher...");
		AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
		webContext.register(WebConfig.class);
		DispatcherServlet dispatcherServlet = new DispatcherServlet(webContext);
		ServletRegistration.Dynamic webServlet = servletContext.addServlet("webServlet", dispatcherServlet);
		webServlet.addMapping("/");
		webServlet.setLoadOnStartup(1);
	}
 
	public void addFilter(ServletContext servletContext) {
		System.out.println("addFilter...");
		CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter("UTF-8", true, true);
		FilterRegistration.Dynamic webEncodingFilter = servletContext.addFilter("webEncodingFilter", encodingFilter);
		webEncodingFilter.addMappingForUrlPatterns(null, false, "/*");
	}
}

 

반응형

* Maven dependency 추가


<dependency>

<groupId>org.java-websocket</groupId>

<artifactId>Java-WebSocket</artifactId>

<version>1.5.1</version>

</dependency>


1. TestEndpointServer.java (Websocket Server)


import javax.websocket.OnClose;

import javax.websocket.OnError;

import javax.websocket.OnMessage;

import javax.websocket.OnOpen;

import javax.websocket.server.ServerEndpoint;


/**

 * Websocket Test Server

 */

@ServerEndpoint("/websocket")

public class TestEndpointServer {

/**

* 웹 소켓이 연결되었을 때 호출(또는 URL 접근시 호출)

*/

@OnOpen

public void connectionOpen() {

System.out.println("################# client is connected!");

}


/**

* 웹 소켓에서 메시지가 날라왔을 때 호출

* cf) 메세지를 받기만 할 경우 return 값을 void로 설정

*/

@OnMessage

public String receiveMessage(String message) {

System.out.println("################# Message from the client : " + message);

String sendMessage = "return message " + message + " -> Lucky Number : " + Math.floor(Math.random() * 100);

System.out.println("################# Echo from the server : " + sendMessage);

return sendMessage;

}


/**

* 웹 소켓이 닫혔을 때 호출(또는 브라우저가 닫혔을 때 호출)

*/

@OnClose

public void connectionClose() {

System.out.println("################# client is disconnected!");

}


/**

* 웹 소켓이 에러가 났을 때 호출

* @param t

*/

@OnError

public void connectionError(Throwable t) {

t.printStackTrace();

}

}


2-1. TestEndpointClient.java (Websocket Client : java 테스트용 1. 서버를 띄운뒤 2-1, 2-2 같이 작성해서 돌려야됨)


import java.io.IOException;

import java.net.URI;


import javax.websocket.ClientEndpoint;

import javax.websocket.ContainerProvider;

import javax.websocket.OnOpen;

import javax.websocket.Session;

import javax.websocket.WebSocketContainer;


/**

 * Websocket Test Client

 */

@ClientEndpoint

public class TestEndpointClient {

public String SocketIp = "127.0.0.1";

public String SocketPort = "7200";

public String SocketPath = "/websocket";


Session userSession = null;


/**

* Websocket 연결

*/

public TestEndpointClient() {

try {

WebSocketContainer container = ContainerProvider.getWebSocketContainer();

container.connectToServer(this, new URI("ws://" + SocketIp + ":" + SocketPort + SocketPath));

} catch (Exception e) {

throw new RuntimeException(e);

}

}


/**

* 웹 소켓이 연결되었을 때 호출

*/

@OnOpen

public void onOpen(Session userSession) {

System.out.println("################# open Websocket");

this.userSession = userSession;

}


/**

* 웹 소켓 닫기

* @OnClose을 사용하였으나 연결이 끈기지 않어(왜?) 직접 연결끈기...ㅜ.ㅡ

*/

public void onClose() {

System.out.println("################# close Websocket");

try {

if(this.userSession != null) {

this.userSession.close();

}

} catch (IOException e) {

e.printStackTrace();

}

finally {

this.userSession = null;

}

}


/**

* 웹 소켓에 메시지 보내기

*/

public void sendMessage(String message) {

System.out.println("################# sendMessage : " + message);

this.userSession.getAsyncRemote().sendText(message);

}

}


2-2. TestEndpointJavaRun.java


public class TestEndpointJavaRun {


public static void main(String[] args) {

try {

// open websocket

TestEndpointClient clientEndPoint = new TestEndpointClient();

// send message

clientEndPoint.sendMessage("메세지를 첫번째로 보냅니다......");

clientEndPoint.sendMessage("메세지를 두번째로 보냅니다......");

clientEndPoint.sendMessage("메세지를 세번째로 보냅니다......");


// close websocket

clientEndPoint.onClose();


} catch (Exception e) {

e.getStackTrace();

}

}

}


3. TestEndpointJspRun.jsp (Websocket Client : jsp 테스트용 1. 서버를 띄운뒤 3. jsp에 접근해서 테스트)


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

<!DOCTYPE html>

<html>

<head>

<title>Websocket Test</title>

</head>

<body>

<form>

<input id="message" type="text">

<input onclick="wsSendMessage();" value="Echo" type="button">

<input onclick="wsCloseConnection();" value="Disconnect" type="button">

</form>

<br>

<textarea id="echoText" rows="30" cols="100"></textarea>

<script type="text/javascript">

var webSocket = new WebSocket("ws://127.0.0.1:7200/websocket");

var echoText = document.getElementById("echoText");

echoText.value = "";

var message = document.getElementById("message");

webSocket.onopen = function(message){ wsOpen(message);};

webSocket.onmessage = function(message){ wsGetMessage(message);};

webSocket.onclose = function(message){ wsClose(message);};

webSocket.onerror = function(message){ wsError(message);};

function wsOpen(message){

echoText.value += "Connected ... \n";

}

function wsSendMessage(){

webSocket.send(message.value);

echoText.value += "Message sent to the server : " + message.value + "\n";

message.value = "";

}

function wsCloseConnection(){

webSocket.close();

}

function wsGetMessage(message){

echoText.value += "Message received from to the server : " + message.data + "\n";

}

function wsClose(message){

echoText.value += "Disconnect ... \n";

console.log("disconnect", message);

}


function wsError(message){

echoText.value += "Error \n";

console.log("error", message);

}

</script>

</body>

</html>






반응형

1. context-common.xml (bean 추가)


<!-- MultipartResolver 설정 -->

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

<property name="maxUploadSize" value="100000000" />

<property name="maxInMemorySize" value="100000000" />

</bean>


2. ExcelUtil.java (공통 엑셀 유틸 추가)


package egovframework.cmn.cmn;


import java.text.SimpleDateFormat;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;


import org.apache.poi.hssf.usermodel.HSSFDateUtil;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import org.apache.poi.ss.usermodel.Cell;

import org.apache.poi.ss.usermodel.Row;

import org.apache.poi.ss.usermodel.Sheet;

import org.apache.poi.ss.usermodel.Workbook;

import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import org.springframework.web.multipart.commons.CommonsMultipartFile;


public class ExcelUtil {

/**

* 엑셀 파일 읽기

* @param file

* @param sheetNum

* @param strartRowNum

* @param startCelNum

* @return List<HashMap<Integer, String>>

* @throws Exception

*/

public List<HashMap<Integer, String>> excelReadSetValue(CommonsMultipartFile file, int sheetNum, int strartRowNum, int startCelNum) throws Exception {

List<HashMap<Integer, String>> resultList = new ArrayList<>();

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

//xls, xlsx 구분

Workbook workbook = null;

if(file.getOriginalFilename().toUpperCase().endsWith("XLSX")) {

workbook = new XSSFWorkbook(file.getInputStream());

}

else {

workbook = new HSSFWorkbook(file.getInputStream());

}

//Sheet 수 확인

int sheetCnt = workbook.getNumberOfSheets();

int listNum = 0;


try {

if (sheetCnt > 0) {

//첫번째 Sheet 선택

Sheet sheet = workbook.getSheetAt(sheetNum);

//Sheet의 Row와 Cell 수 확인

int rows = sheet.getPhysicalNumberOfRows();

int cells = sheet.getRow(0).getPhysicalNumberOfCells();

HashMap<Integer, String> valueMap = null;

//Header Row 빼고 시작(0에서 시작)

for(int r = strartRowNum ; r < rows; r++) {

//String device_id = "";

valueMap = new HashMap<Integer, String>();

//한 줄씩 읽고 데이터 저장

Row row = sheet.getRow(r);

if (row != null) {

//Cell 기본값 빼고 시작(0에서 시작)

for(int c = startCelNum ; c < cells ; c++) {

Cell cell = row.getCell(c);

if (cell != null) {

String value = "";

switch(cell.getCellType()) {

case Cell.CELL_TYPE_BLANK :

value = "";

break;

case Cell.CELL_TYPE_BOOLEAN :

value = "" + cell.getBooleanCellValue();

break;

case Cell.CELL_TYPE_ERROR :

value = "" + cell.getErrorCellValue();

break;

case Cell.CELL_TYPE_FORMULA :

value = cell.getCellFormula();

break;

case Cell.CELL_TYPE_NUMERIC :

if(HSSFDateUtil.isInternalDateFormat(cell.getCellStyle().getDataFormat())) {

value = sdf.format(cell.getDateCellValue());

}

else {

cell.setCellType(Cell.CELL_TYPE_STRING ); 

value = cell.getStringCellValue(); 

}

break;

case Cell.CELL_TYPE_STRING :

value = cell.getStringCellValue();

break;

}

//공백과 트림 제거

value = value.trim().replaceAll(" ", "");

valueMap.put(c, value);

}

}//end col for

resultList.add(listNum++, valueMap);

}//end if

}//end row for

}

} catch(Exception e) {

e.getStackTrace();

}

return resultList;

}

}



3. XxxController.java


/**

* 엑셀 업로드 처리

* @param multiRequest

* @param request

* @return

* @throws Exception

*/

@RequestMapping("cfgUploadAction.do")

public String cfgUploadAction(HttpServletRequest request, RedirectAttributes redirectAttributes) throws Exception {

try {

cfgService.excelUpload(request);


redirectAttributes.addFlashAttribute("Code", 0);

redirectAttributes.addFlashAttribute("Message", egovMessageSource.getMessage("proc.success"));

} catch (Exception ex) {

redirectAttributes.addFlashAttribute("Code", 1);

redirectAttributes.addFlashAttribute("Message", "오류가 발생하였습니다. 엑셀양식을 확인해 주세요.");

}

return "redirect:/mng/fac/cfg/cfgUploadPop.do";

}


4. XxxServiceImpl.java


/**

* 엑셀 업로드 처리

* @param multiRequest

* @return String

* @throws Exception

*/

@SuppressWarnings("unchecked")

public void excelUpload(HttpServletRequest request) throws Exception{

MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest)request;

//파일 정보

CommonsMultipartFile file = (CommonsMultipartFile)multiRequest.getFile("excelFile");

//엑셀정보

ExcelUtil eu = new ExcelUtil();

int sheetNum = 0; //1번째 시트 읽음 

int strartRowNum = 1; //2번째 줄부터 읽음

int startCelNum = 2; //3번째 줄부터 읽음(지역ID)

List<HashMap<Integer, String>> excelList = eu.excelReadSetValue(file, sheetNum, strartRowNum, startCelNum);

//테이블 Key 정보

DeviceBaseVO deviceBaseVO = null;


//엑셀 Row 수 만큼 For문 조회 

for(Object obj : excelList) {

Map<Integer, String> mp = (Map<Integer, String>)obj;

Set<Integer> keySet = mp.keySet();

Iterator<Integer> iterator = keySet.iterator();

deviceBaseVO = new DeviceBaseVO();

while(iterator.hasNext()) {

int key = iterator.next();

String value = StringUtil.nullConvert(mp.get(key));

switch(key) {

case 2 :

deviceBaseVO.setAreaId(value);

break;

case 4 :

deviceBaseVO.setFacilityId(value);

break;

case 5 :

deviceBaseVO.setDeviceNm(value);

break;

case 6 :

deviceBaseVO.setDeviceId(value);

break;

case 7 :

deviceBaseVO.setInstDt(value);

break;

case 8 :

deviceBaseVO.setUseYn(value);

break;

}

}

if(!"".equals(deviceBaseVO.getAreaId()) && deviceBaseVO.getAreaId() != null) {

cfgMapper.updateCfgInfo(deviceBaseVO);

}

}

}


5. Xxx.jsp


<form name="popForm" method="post" action="${actionUrl}" enctype="multipart/form-data">

<table>

<caption>엑셀 업로드</caption>

<colgroup>

<col><col>

</colgroup>


<tbody>

<tr>

<th><label for="code2">파일찾기</label></th>

<td><input name="excelFile" id="excelFile" type="file" size="30"></td>

</tr>

</table>


<!-- 버튼 영역 -->

<div class="btn-area">

<a href="#" onclick="doSubmit();" class="btn btn-yellow btn-ok">업로드</a>

<a href="javascript:self.close();" class="btn btn-yellow btn-cancel">창닫기</a>

</div>

</form>


반응형

1. context-common.xml (bean 추가)


<bean id="excelView" class="egovframework.cmn.cmn.ExcelView" />


2. ExcelView.java (공통 엑셀다운로드)


package egovframework.cmn.cmn;


import java.net.URLEncoder;

import java.util.List;

import java.util.Map;


import javax.servlet.ServletOutputStream;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.apache.poi.hssf.usermodel.HSSFCellStyle;

import org.apache.poi.hssf.usermodel.HSSFFont;

import org.apache.poi.hssf.util.HSSFColor;

import org.apache.poi.ss.usermodel.CellStyle;

import org.apache.poi.ss.usermodel.Font;

import org.apache.poi.ss.util.CellRangeAddress;

import org.apache.poi.xssf.usermodel.XSSFCell;

import org.apache.poi.xssf.usermodel.XSSFRow;

import org.apache.poi.xssf.usermodel.XSSFSheet;

import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import org.springframework.web.servlet.view.AbstractView;


import egovframework.rte.psl.dataaccess.util.EgovMap;


public class ExcelView extends AbstractView {

    /** The content type for an Excel response */

     private static final String CONTENT_TYPE_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";


    /**

     * Default Constructor. Sets the content type of the view for excel files.

     */

    public ExcelView() {

    }


    @Override

    protected boolean generatesDownloadContent() {

        return true;

    }


    /**

     * Renders the Excel view, given the specified model.

     */

    @Override

    protected final void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {


        XSSFWorkbook workbook = new XSSFWorkbook();


        setContentType(CONTENT_TYPE_XLSX);


        buildExcelDocument(model, workbook, request, response);

        

        // Set the filename

        String sFilename = "";

        if(model.get("filename") != null){

            sFilename = (String)model.get("filename");

        }else if(request.getAttribute("filename") != null){

            sFilename = (String)request.getAttribute("filename");

        }else{

            sFilename = getClass().getSimpleName();

         }


        response.setContentType(getContentType());

        

        String header = request.getHeader("User-Agent");

        sFilename = sFilename.replaceAll("\r","").replaceAll("\n","");

        if(header.contains("MSIE") || header.contains("Trident") || header.contains("Chrome")){

            sFilename = URLEncoder.encode(sFilename,"UTF-8").replaceAll("\\+","%20");

            response.setHeader("Content-Disposition","attachment;filename="+sFilename+".xlsx;");

        }else{

            sFilename = new String(sFilename.getBytes("UTF-8"),"ISO-8859-1");

            response.setHeader("Content-Disposition","attachment;filename=\""+sFilename + ".xlsx\"");

        }

        

        // Flush byte array to servlet output stream.

        ServletOutputStream out = response.getOutputStream();

        out.flush();

        workbook.write(out);

        out.flush();


        // Don't close the stream - we didn't open it, so let the container handle it.

        // http://stackoverflow.com/questions/1829784/should-i-close-the-servlet-outputstream

    }

    

    @SuppressWarnings("unchecked")

    protected void buildExcelDocument(Map<String, Object> model, XSSFWorkbook wb, HttpServletRequest req, HttpServletResponse resp) throws Exception {

    List<Map<String, Object>> dataMapList = (List<Map<String, Object>>) model.get("dataMapList");

   

    for(Map<String, Object> dataMap : dataMapList) {

            XSSFCell cell = null;

     

            String sheetNm = (String) dataMap.get("sheetNm"); // 엑셀 시트 이름

            

            String[] titleArr = (String[]) dataMap.get("titleArr"); // 각 컬럼 이름

            String[] fieldArr = (String[]) dataMap.get("fieldArr"); // 각 컬럼의 변수 이름

            

            List<EgovMap> dataList = (List<EgovMap>) dataMap.get("list"); // 데이터가 담긴 리스트 

            

            CellStyle cellStyle = wb.createCellStyle(); // 제목셀의 셀스타일

            cellStyle.setWrapText(true); // 줄 바꿈            

            cellStyle.setFillForegroundColor(HSSFColor.GREY_25_PERCENT.index); // 셀 색상

            cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); // 셀 색상 패턴

            cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 셀 가로 정렬

            cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 셀 세로 정렬

            cellStyle.setDataFormat((short)0x31); // 셀 데이터 형식

            cellStyle.setBorderRight(HSSFCellStyle.BORDER_DOUBLE);

            cellStyle.setBorderLeft(HSSFCellStyle.BORDER_DOUBLE);

            cellStyle.setBorderTop(HSSFCellStyle.BORDER_DOUBLE);

            cellStyle.setBorderBottom(HSSFCellStyle.BORDER_DOUBLE);

            

            // 셀 폰트색상, bold처리

            Font font = wb.createFont();

            font.setColor(HSSFColor.WHITE.index);

            font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);

            cellStyle.setFont(font);

            

            CellStyle cellStyle2 = wb.createCellStyle(); // 데이터셀의 셀스타일

            cellStyle2.setWrapText(true); // 줄 바꿈           

            cellStyle2.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 셀 가로 정렬

            cellStyle2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 셀 세로 정렬

            cellStyle2.setDataFormat((short)0x31); // 셀 데이터 형식

            cellStyle2.setBorderRight(HSSFCellStyle.BORDER_THIN);

            cellStyle2.setBorderLeft(HSSFCellStyle.BORDER_THIN);

            cellStyle2.setBorderTop(HSSFCellStyle.BORDER_THIN);

            cellStyle2.setBorderBottom(HSSFCellStyle.BORDER_THIN);

            

            XSSFSheet sheet = wb.createSheet(sheetNm);

            sheet.setDefaultColumnWidth(12);

            

            // 컬럼명 삽입

            for(int i=0; i<titleArr.length; i++){

                setText(getCell(sheet, 0, i), titleArr[i]);

                getCell(sheet, 0, i).setCellStyle(cellStyle);

                sheet.autoSizeColumn(i);

                int columnWidth = (sheet.getColumnWidth(i))*5;

                sheet.setColumnWidth(i, columnWidth);

                

                if(dataList.size() < 1){

                    cell = getCell(sheet, 1, i);

                    if(i==0){

                        setText(cell, "등록된 정보가 없습니다.");

                    }

                    cell.setCellStyle(cellStyle2);

                }

            }

            

            if(dataList.size() > 0){ // 저장된 데이터가 있을때

                // 리스트 데이터 삽입

                for (int i = 0; i<dataList.size(); i++) {

                    EgovMap dataEgovMap = dataList.get(i);

                    

                    // 맨 앞 컬럼인 "번호"는 idx라는 이름으로 여기서 생성하여 넣어준다.

                    dataEgovMap.put("idx", (i+1)+""); 


                    for(int j=0; j<fieldArr.length; j++){

                        String data = String.valueOf(dataEgovMap.get(fieldArr[j]));

                        cell = getCell(sheet, 1 + i, j);

                        setText(cell, data);

                        cell.setCellStyle(cellStyle2);

                    }

                }

            }else{ // 저장된 데이터가 없으면 셀 병합

                // 셀 병합(시작열, 종료열, 시작행, 종료행)

                sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, titleArr.length-1));

            }

    }

    }


    /**

     * Convenient method to obtain the cell in the given sheet, row and column.

     * 

     * <p>Creates the row and the cell if they still doesn't already exist.

     * Thus, the column can be passed as an int, the method making the needed downcasts.</p>

     * 

     * @param sheet a sheet object. The first sheet is usually obtained by workbook.getSheetAt(0)

     * @param row thr row number

     * @param col the column number

     * @return the XSSFCell

     */

    protected XSSFCell getCell(XSSFSheet sheet, int row, int col) {

        XSSFRow sheetRow = sheet.getRow(row);

        if (sheetRow == null) {

            sheetRow = sheet.createRow(row);

        }

        XSSFCell cell = sheetRow.getCell((short) col);

        if (cell == null) {

            cell = sheetRow.createCell((short) col);

        }

        return cell;

    }


    /**

     * Convenient method to set a String as text content in a cell.

     * 

     * @param cell the cell in which the text must be put

     * @param text the text to put in the cell

     */

    protected void setText(XSSFCell cell, String text) {

        cell.setCellType(XSSFCell.CELL_TYPE_STRING);

        cell.setCellValue(text);

    }            

}


3. SearchVO.java (VO 변수 추가)


private String schFileNm = ""; /** 엑셀다운로드 파일명 */

private String[] schSheetNmArr = null; /** 엑셀다운로드 시트명 배열 */

private String[][] schTitleArrArr = null; /** 엑셀다운로드 Title 배열 */

private String[][] schFieldArrArr = null; /** 엑셀다운로드 Field 배열 */


4. XxxController.java (Controller 엑셀다운로드 함수 추가)


@RequestMapping("disorderAllList.do")

public ModelAndView selectDisorderAllList(@ModelAttribute("searchVO") SearchVO searchVO, HttpServletRequest request, HttpServletResponse response, BindingResult bindingResult) throws Exception {

//코드관리 목록 조회

List<?> list = cfgService.selectDisorderList(searchVO);

//코드1관리 목록 조회

List<?> list1 = cfgService.selectCauseList(searchVO);

//코드2관리 목록 조회

List<?> list2 = cfgService.selectActionList(searchVO);

    ModelAndView mav = new ModelAndView("excelView");

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

    Map<String, Object> subMap = null;

    

    for(int i = 0 ; i < searchVO.getSchSheetNmArr().length ; i++) {

    subMap = new HashMap<String, Object>();

    subMap.put("titleArr", searchVO.getSchTitleArrArr()[i]);

    subMap.put("fieldArr", searchVO.getSchFieldArrArr()[i]);

    subMap.put("sheetNm", searchVO.getSchSheetNmArr()[i]);

    if(i == 0) subMap.put("list", list);

    else if(i == 1) subMap.put("list", list1);

    else if(i == 2) subMap.put("list", list2);

   

    dataMapList.add(i, subMap);

    }

    mav.addObject("dataMapList", dataMapList);

    mav.addObject("filename", searchVO.getSchFileNm());

    

    return mav;

}


5. common.js (공통 Tabulator 엑셀 다운로드 함수 추가)


//Tabulator 엑셀 다운로드

function downBaseExcelTabulator(vAction, vFileNm, vSheetNmArr, vSheetArr, vParams){

//action 정보 세팅

var vForm = document.createElement("FORM");

vForm.action = vAction;

vForm.method = "POST";


//파일명 세팅

appendMakeInput(vForm, "schFileNm", vFileNm);


//시트명 세팅

for(var i = 0 ; i < vSheetNmArr.length ; i++){

appendMakeInput(vForm, "schSheetNmArr[" + i + "]", vSheetNmArr[i]);

}

//sheet 컬럼 정보 세팅

for(var j = 0 ; j < vSheetArr.length ; j++){

var vColumns = vSheetArr[j];

for(var jj = 0 ; jj < vColumns.length ; jj++){

if(vColumns[jj].download != false){

appendMakeInput(vForm, "schTitleArrArr[" + j + "]", vColumns[jj].title);

appendMakeInput(vForm, "schFieldArrArr[" + j + "]", vColumns[jj].field);

}

}

}

//params 정보 세팅

if(vParams != null && vParams != ""){

for(var k = 0 ; k < vParams.length ; k++){

appendMakeInput(vForm, vParams[k].name, vParams[k].value);

}

}

window.document.body.appendChild(vForm);

vForm.submit();

}



//Tabulator 단일 시트 엑셀 다운로드

function downOneExcelTabulator(vAction, vFileNm, vSheetNm, vSheet, vParams){

var vSheetNmArr = [vSheetNm];

var vSheetArr = [vSheet.getColumnDefinitions()];

downBaseExcelTabulator(vAction, vFileNm, vSheetNmArr, vSheetArr, vParams);

}


//Tabulator 멀티 시트 엑셀 다운로드

function downMultiExcelTabulator(vAction, vFileNm, vSheetNmArr, vSheetArr, vParams){

var reSheetArr = new Array();

for(var i = 0 ; i < vSheetArr.length ; i++){

var tempArr = new Array();

for(var j = 0 ; j < vSheetArr[i].getColumns().length ; j++){

tempArr[j] = vSheetArr[i].getColumns()[j].getDefinition();

}

reSheetArr[i] = tempArr;

}

downBaseExcelTabulator(vAction, vFileNm, vSheetNmArr, reSheetArr, vParams);

}


//input hidden 객체 만들어 붙이기

function appendMakeInput(obj, nm, val){

var vInput = document.createElement("INPUT");

vInput.name = nm;

vInput.value = val;

vInput.type = "hidden";

obj.append(vInput);

}


6. Xxx.js (각 화면 엑셀 다운로드 함수 추가)


//엑셀 다운로드

function excelDown(opt){

if(opt == "ALL"){

var vAction = "/common/disorderAllList.do";

var vFileNm = "코드관리(전체)";

var vSheetNmArr = ["코드관리", "코드1관리", "코드2관리"];

var vSheetArr = [disorderSheet, causeSheet, actionSheet];

var vParams = null;

//Tabulator 엑셀 다운로드

downMultiExcelTabulator(vAction, vFileNm, vSheetNmArr, vSheetArr, vParams);

}

else{

var sheets = {

    "코드관리": true,

    "코드1관리": causeSheet,

    "코드2관리": actionSheet

};


disorderSheet.download("xlsx", "코드관리.xlsx", {sheets:sheets});

}

}



반응형

1.메이븐을 사용한다면 pom.xml에 아래 dependency를 추가하고 메이븐을 사용하지 않는다면 아래 사이트에가서 필요한 jar를 다운 받는다.

(https://mvnrepository.com/artifact/org.apache.tiles)

 

  <!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-api -->
  <dependency>
      <groupId>org.apache.tiles</groupId>
      <artifactId>tiles-api</artifactId>
      <version>3.0.8</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-autotag-core -->
  <dependency>
      <groupId>org.apache.tiles</groupId>
      <artifactId>tiles-autotag-core</artifactId>
      <version>1.2</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-autotag-core-runtime -->
  <dependency>
      <groupId>org.apache.tiles</groupId>
      <artifactId>tiles-autotag-core-runtime</artifactId>
      <version>1.2</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-core -->
  <dependency>
      <groupId>org.apache.tiles</groupId>
      <artifactId>tiles-core</artifactId>
      <version>3.0.8</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-extras -->
  <dependency>
      <groupId>org.apache.tiles</groupId>
      <artifactId>tiles-extras</artifactId>
      <version>3.0.8</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-jsp -->
  <dependency>
      <groupId>org.apache.tiles</groupId>
      <artifactId>tiles-jsp</artifactId>
      <version>3.0.8</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-request-api -->
  <dependency>
      <groupId>org.apache.tiles</groupId>
      <artifactId>tiles-request-api</artifactId>
      <version>1.0.7</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-request-jsp -->
  <dependency>
      <groupId>org.apache.tiles</groupId>
      <artifactId>tiles-request-jsp</artifactId>
      <version>1.0.7</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-request-servlet -->
  <dependency>
      <groupId>org.apache.tiles</groupId>
      <artifactId>tiles-request-servlet</artifactId>
      <version>1.0.7</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-servlet -->
  <dependency>
      <groupId>org.apache.tiles</groupId>
      <artifactId>tiles-servlet</artifactId>
      <version>3.0.8</version>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.apache.tiles/tiles-template -->
  <dependency>
      <groupId>org.apache.tiles</groupId>
      <artifactId>tiles-template</artifactId>
      <version>3.0.8</version>
  </dependency>

 

 

2. web.xml 설정(중간에 타일즈를 추가하는 것이면 이미 설정 되어있을 것이다.)

 

<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/config/egovframework/springmvc/dispatcher-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

 

3. dispatcher-servlet.xml 설정(프로젝트마다 파일이름이 다를 수 있다.)

   기존 설정과 중복되는 부분은 주석처리 하거나 필요한 설정이라면 order 순서를 변경한다.

   org.springframework.web.servlet.view.tiles3.SimpleSpringPreparerFactory 부분은 동적메뉴 구성을 위해 추가하였다.(5-1번 참고)

 

    <!-- Ajax jsonView Return (ModelAndView) -->
    <bean id="jsonView" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"
     p:contentType="application/json;charset=UTF-8">
    </bean>
    <bean id="viewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"
     p:order="2">
    </bean>

 


 <!-- Tiles 추가로 인해 주석처리
    <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" p:order="2"
     p:viewClass="org.springframework.web.servlet.view.JstlView"
     p:prefix="/WEB-INF/jsp/egovframework/" p:suffix=".jsp" />
  -->
    
    <!-- Tiles 추가 -->
    <bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"
        p:viewClass="org.springframework.web.servlet.view.tiles3.TilesView"
        p:order="1" />
    <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
            <property name="definitions">
                  <list>
                        <value>/WEB-INF/config/egovframework/tiles/tiles.xml</value>
                  </list>
            </property>
            <property name="preparerFactoryClass" value="org.springframework.web.servlet.view.tiles3.SimpleSpringPreparerFactory"></property>
    </bean>

 

4. tiles.xml 설정(definition의 name abc/**/*Viewdef/**/*ViewController의 리턴값과 매칭되어야 해당 Tiles Layout이 적용된다.)

  cf ex1) return "abc/aa/cc/dd/wowView";  cf ex2) return "def/a/goodView";

 

<!DOCTYPE tiles-definitions PUBLIC
  "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
  "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
 
<tiles-definitions>
  
    <!-- Tiles 적용 기본 Layout -->
    <definition name="base" template="/WEB-INF/jsp/egovframework/layout/TilesLayout.jsp" preparer="egovframework.cmn.MenuPreparer">
        <put-attribute name="header" value="/WEB-INF/jsp/egovframework/layout/Header.jsp" />
        <put-attribute name="menuLvl2" value="/WEB-INF/jsp/egovframework/layout/MenuLvl2.jsp" />
        <put-attribute name="menuLvl3" value="/WEB-INF/jsp/egovframework/layout/MenuLvl3.jsp" />
    </definition>
   
    <!-- Tiles 적용 팝업 Layout -->
    <definition name="baseEmpty" template="/WEB-INF/jsp/egovframework/layout/PopLayout.jsp">
    </definition>
    
    

    
 
    <!-- 기본 관리자 화면 - 첫번째관리 Layout -->
    <definition name="abc/**/*View" extends="base">
        <put-attribute name="body" value="/WEB-INF/jsp/egovframework/abc/{1}/{2}View.jsp" />
        <put-attribute name="curPath" value="abc/{1}/{2}View" cascade="true"/>
    </definition>
 
    <!-- 기본 관리자 화면 - 두번째관리 Layout -->
    <definition name="def/**/*View" extends="base">
        <put-attribute name="body" value="/WEB-INF/jsp/egovframework/def/{1}/{2}View.jsp" />
    </definition>
 



    
    <!-- 팝업 화면 Layout -->
    <definition name="**/*Pop" extends="baseEmpty">
        <put-attribute name="body" value="/WEB-INF/jsp/egovframework/{1}/{2}Pop.jsp" />
    </definition>
   
   
   
   
   
   
    <!-- 기타 Tiles 미적용 -->
    <definition name="cmn/*" template="/WEB-INF/jsp/egovframework/cmn/{1}.jsp"></definition>

  
</tiles-definitions>

 

5-1. 동적메뉴 구성을 위한 설정(MenuPreparer.java)

 

public class MenuPreparer implements ViewPreparer {

 /** SysadmService */
 @Resource(name="sysadmService")
 private SysadmService sysadmService;

 @Override
 public void execute(Request tilesRequest, AttributeContext attributeContext) throws PreparerException {
  List<?> menuList;
  try {
   Map<String, String> map = tilesRequest.getParam();
   SearchVO searchVO = new SearchVO();
   
   //로그인한 세션정보 가져오기
   HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
   HttpSession session = request.getSession();
   LoginVO loginVO = (LoginVO)session.getAttribute("loginVO");
   
   //접근사용자구분 세팅
   searchVO.setSchUserGubun(loginVO.getUserGubun());
   
   //관리자메뉴 세팅
   menuList = sysadmService.getSelectMngMenuList(searchVO);
   attributeContext.putAttribute("menuList", new Attribute(menuList), true);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 

 

5-2. TilesLayout.jsp 설정

 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="validator" uri="http://www.springmodules.org/tags/commons-validator" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles-extras" prefix="tilesx" %>

<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- Stylesheets ============================================= -->
<link rel="stylesheet" href="/css/bootstrap.css" type="text/css" />
<link rel="stylesheet" href="/css/style.css" type="text/css" />

 

<!-- External JavaScripts ============================================= -->
<script type="text/javascript" src="/js/jquery.js"></script>


 

<tilesx:useAttribute name="curPath" />
<script type="text/javascript" src="/script/${curPath}.js"></script>

 

<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>관리자페이지</title>
</head>

<body class="stretched">

<!-- Document Wrapper ============================================= -->
<div id="wrapper" class="clearfix">
 <!-- Header ============================================= -->
 <tiles:insertAttribute name="header"/>
 <!-- #header end -->

    <!-- Content ============================================= -->
    <section id="content" class="content-grid">
        <div class="content-wrap nopadding">
   <div class="container-fluid">
    <div id="tabs" class="card">
     <!-- 2depth 메뉴 -->
     <tiles:insertAttribute name="menuLvl2" />
     <!-- //2depth 메뉴 -->
     
     <div class="tab-content">
      <div class="tab-pane active" id="default">
       <div class="card-body">
        <!-- 3depth 메뉴 -->
        <tiles:insertAttribute name="menuLvl3" />
        <!-- //3depth 메뉴 -->
        
        <!-- bodyContent -->
        <tiles:insertAttribute name="body" />
        <!-- //bodyContent -->
       </div>
      </div>
     </div>
    </div>
   </div>
  </div>
    </section>
    <!-- #content end -->
</div>
<!-- #wrapper end -->
</body>
</html> 

 

 

 

5-3. MenuLvl2.jsp 설정(menuList 변수는 5-1에서 지정한 변수)

 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<tiles:importAttribute name="menuList" />
<ul class="nav nav-tabs ui-sortable">
 <c:forEach var="result" items="${menuList}" varStatus="status">
  <c:if test="${result.lvl eq 2}">
   <li ${result.isActive eq 'Y' ? 'class="active"' : ''}><a href="${result.menuUrl }?menuId=${result.menuId}" ${result.popGubun eq 'Y' ? 'target="_blank"' : ''}>${result.menuNm }</a></li>
  </c:if>
 </c:forEach>
</ul> 

 

6. 만드는 것보다 글로 정리하는게 어렵네요... 로그인한 사용자에 대한 동적메뉴를 구성하는 부분에서 많이 막혔었네요.

구글 국내로 검색해도 마땅한 자료를 못찾아 많이 헤멧네요. 5-1 부분에 세션정보를 가져오는 부분이 국내에서 타일즈랑 묶어서 찾기가 참 힘들었네요

반응형

1. web.xml 설정(중간에 로그인 체크를 위한 인터셉터를 추가하는 것이면 이미 설정 되어있을 것이다.)

 

<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/config/egovframework/springmvc/dispatcher-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

 

2. dispatcher-servlet.xml 설정(프로젝트마다 파일이름이 다를 수 있다.)

 

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**/*View.do"/> <!-- 절대경로(/)부터 시작하면 중간경로가 있을 수 있기에 (**)으로 표시 -->
        <mvc:exclude-mapping path="/cmn/login/*.do"/> <!-- 예외 경로 지정 -->
        <mvc:exclude-mapping path="/mon/page/loginView.do"/> <!-- 예외 경로 지정(여러개일 수 있음으로...) -->
        <bean class="egovframework.cmn.cmn.AuthInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>

 

3. AuthInterceptor.java 설정

 

public class AuthInterceptor extends HandlerInterceptorAdapter {
    /**
     * 세션에 계정정보(LoginVO)가 있는지 여부로 인증 여부를 체크한다. 계정정보(LoginVO)가 없다면, 로그인 페이지로 이동한다.
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        LoginVO loginVO = null;
       
        try {
            loginVO = (LoginVO) request.getSession().getAttribute("loginVO");

            if (loginVO != null && loginVO.getUserId() != null) {
                return true;
            } else {
                ModelAndView modelAndView = new ModelAndView("forward:/loginView.do");
                modelAndView.addObject("message", "세션이 만료되어 로그아웃 되었습니다. 다시 로그인 해주세요.");
                throw new ModelAndViewDefiningException(modelAndView);
            }
        } catch (Exception e) {
            ModelAndView modelAndView = new ModelAndView("forward:/loginView.do");
            modelAndView.addObject("message", "세션이 만료되어 로그아웃 되었습니다. 다시 로그인 해주세요.");
            throw new ModelAndViewDefiningException(modelAndView);
        }
    }

    /**
     * 세션에 메뉴권한(LoginVO.userGubun)을 가지고 메뉴를 조회하여 권한 여부를 체크한다.
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        LoginVO loginVO = null;
        String requestURI = request.getRequestURI();
       
        try {
         if(!"/loginView.do".equals(requestURI)) {
          loginVO = (LoginVO) request.getSession().getAttribute("loginVO");
          if (loginVO != null && loginVO.getUserId() != null) {
           SearchVO searchVO = new SearchVO();
           searchVO.setSchMenuUrl(requestURI);
           searchVO.setSchUserGubun(loginVO.getUserGubun());
           List<?> resultList = sysadmService.getSelectRollMenuCheckList(searchVO);
           
           if(resultList == null || resultList.size() == 0) {
                     ModelAndView mav = new ModelAndView("forward:/monitorView.do"); 
                     mav.addObject("message", "권한이 없습니다.");
                     throw new ModelAndViewDefiningException(mav);
           }
           
          } else {
           ModelAndView mav = new ModelAndView("forward:/loginView.do");
           mav.addObject("message", "세션이 만료되어 로그아웃 되었습니다. 다시 로그인 해주세요.");
           throw new ModelAndViewDefiningException(mav);
          }
         }
        } catch (Exception e) {
            ModelAndView mav = new ModelAndView("forward:/monitorView.do"); 
            mav.addObject("message", "권한이 없습니다.");
            throw new ModelAndViewDefiningException(mav);
        }    }
}

 

4. 현재 진행 중인 프로젝트엔 세션 권한별 접근 메뉴 체크가 없기에 비워놈... 언젠가는 추가할지도??

5. 동일한 환경으로 새로운 프로젝트를 시작하여 권한도 추가하였다.

반응형

ResourceBundle 클래스를 사용하여 properties 파일 정보를 읽어올 수 있다.

 

다음과 같은 파일이 있다면

 

경로 : WEB-INF/classes/egovframework/egovProps/IpInfoSample.properties

 

IpInfoSample.properties 파일 내용

 

#소켓IP정보

SocketIp=127.0.0.1

 

#소켓포트정보

SocketPort=5001 

 

아래와 같이 사용하여 정보를 읽어올 수 있다.

 

ResourceBundle mainResource = ResourceBundle.getBundle("egovframework.egovProps.IpInfoSample");

String SocketIp = mainResource.getString("SocketIp");

String SocketPort = mainResource.getString("SocketPort");

 

System.out.println("[SocketIp] : " + SocketIp);

System.out.println("[SocketPort] : " + SocketPort);

 

결과 :

[SocketIp] : 127.0.0.1
[SocketPort] : 5001

 

properties 파일의 모든 정보를 읽어야 한다면 아래와 같이 사용할수도 있다.

 

ResourceBundle mainResource = ResourceBundle.getBundle("egovframework.egovProps.IpInfoSample");  

Enumeration enm = mainResource.getKeys();

 

while(enm.hasMoreElements()){
    String key = (String) enm.nextElement();
    String value = mainResource.getString(key);


    System.out.println("[" + key + "] : " + value);
}

 

결과 :

[SocketIp] : 127.0.0.1
[SocketPort] : 5001

 

반응형

GPKI 서버 인증서가 만료되어 GPKI를 신규로 발급받아 설치 시 표준API 라이센스 파일(gpkiapi.lic)의 내용을 복사하여

 

~(Web Root)/gpkisecureweb/client/var.js

 

위 파일에 아래 라이센스변수 내용을 수정하고 서버를 돌렸는데 계속 라이센스 만료에러가 발생하였다.

 

var.js

 

ServerCert = "MIID5 ...."

 

결론은 gpkiapi.lic 파일의 라이센스를 Base64Encode 값으로 변환하여 ServerCert 변수에 세팅해야된다. 

 

<%@ page import="com.gpki.gpkiapi.storage.Disk" %>
<%@ page import="com.gpki.gpkiapi.util.Base64" %>
<%@ page import="com.gpki.gpkiapi.cert.X509Certificate" %>
<%
String SERVER_KM_CERT_PATH = "서버인증서파일경로/서버인증서파일(SVR_env.cer)";
Base64 base64 = new Base64();
byte[] bBase64 = null;
String strBase64 = "";
X509Certificate srvCert = Disk.readCert(SERVER_KM_CERT_PATH);
bBase64 = srvCert.getCert();
strBase64 = new String(base64.encode(bBase64));
%>

 

위 내용은 표준API설치가이드에서 제공하는 Base64Encode로 변환하는 가이드인데 저대로 하면 에러가 발생한다.^^;

 

변환하기전에 아래 소스를 먼저 선언하고 돌려야한다. 참고로 가이드문서는 jsp로 되어있지만 java로 돌리면 훨신 간편하다. ^-^

 

GpkiApi.init("/subinto/conf/"); //gpkiapi.lic 가 있는 경로
반응형

Java에서 json 형태로 화면으로 떨구기

 

1. pom.xml 설정(Maven 설정)

        <!-- Ajax jQuery -->
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib-ext-spring</artifactId>
            <version>1.0.2</version>
            <exclusions>
                <exclusion>
                    <artifactId>servlet-api</artifactId>
                    <groupId>javax.servlet</groupId>
                </exclusion>
            </exclusions>
        </dependency>

 

2. action-servlet.xml 설정

    <!-- jsonView -->
    <bean id="jsonView" class="net.sf.json.spring.web.servlet.view.JsonView" >
        <property name="contentType" value="application/json;charset=UTF-8"></property>
    </bean>

 

3. Controller 설정

    @RequestMapping(value = "/biz/mkform/mkFormListJson.do")
    public ModelAndView selectMkFormListJson(CommandMap commandMap) throws Exception {
        ModelAndView mav = new ModelAndView("jsonView");
        Map<String,Object> resultMap = mkFormService.selectUserTableList(commandMap.getMap());
        mav.addObject("resultMap", resultMap);
       
        return mav;
    }

 

4. jsp 설정

 

        jQuery.ajax({
            type:'POST',
            url:'/biz/mkform/mkFormListJson.do',     
            data:'',
            async:false,
            dataType:'json',
            success:function(data){
                document.getElementById("wow").innerHTML = data.resultMap;
            }, 
            error:function(request,status,error){ 
                alert('[' + request.status + '] 에러가 발생하였습니다.');
            }
        });

 

※ 2. action-servlet.xml 설정에서 "net.sf.json.spring.web.servlet.view.JsonView" 대신 "org.springframework.web.servlet.view.json.MappingJacksonJsonView"를 사용해도 동일하게 동작된다.

차이점으로는 정렬순서와 null을 null로 처리할지 ""으로 처리할지 정도라는데 조금 더 자세한 사항은 검색!

반응형

jsoup lib를 이용하여 크롤링 연습하기

 

소스 다운 및 참고사이트 : https://jsoup.org/

 

public class CommonCrolling {
    private final static String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36";
   
    public static String getCurrentData(){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
        return sdf.format(new Date());
    }
   
    public static void main(String[] args) {
        try {
            System.out.println("############################################## Start Time : " + getCurrentData());
            // 1. URL 선언
            String connUrl = "http://www.daum.net";
           
            // 2. HTML 가져오기
            Connection conn = Jsoup
                    .connect(connUrl)
                    .header("Content-Type", "application/json;charset=UTF-8")
                    .userAgent(USER_AGENT)
                    .method(Connection.Method.GET)
                    .ignoreContentType(true);
           
            Document doc = conn.get();
           
            // 3. 가져온 HTML Document 를 확인하기
            //System.out.println(doc.toString());
            System.out.println(doc.select(".list_stxt").toString());
           
        } catch (IOException e) {
            // Exp : Connection Fail
            e.printStackTrace();
        }
        System.out.println("############################################## End Time : " + getCurrentData());
    }
}

 

반응형

/* 뺑뺑이 만들기
    각 중학교 1차원 배열
 * 문제) 2009년도 대전 시내 초등학교 졸업생이 200명이다. (0~199번) 이 학생들을
        대전중학교에 45명, 한밭중학교에 40명, 갈마중학교에 30명, 둔산중학교에 50명,
        성모중학교에 35명을 배정하라. 그리고 위와 같이 학교별 배정 학생번호 리스트와
        학번별 학교배정 리스트를 출력하시오.
 */

 

public class HomeWork02 {
    public static void main(String[] args) {
        int[] 학번 = 학생번호(200);
        int[] 배당학교 = 뺑뺑이(학번);
        int num = 0;
        for(int i = 0 ; i < 중학교.length ; i++){
            HomeWork02 hw = new HomeWork02();
            System.out.println("============================================================================");
            System.out.println("학교명 : " + 중학교[i]);
            System.out.println("============================================================================");
            for(int j = 0 ; j < 학번.length ; j ++){
                if(배당학교[j] == i){
                    System.out.print(학번[j] + "\t");
                    num += 1;
                    if(num % 10 == 0) System.out.println(" ");
                }
            }
            System.out.println("학생수 : " + num);
            num = 0;
            System.out.println("============================================================================");
            System.out.println(" ");
            System.out.println(" ");
        }
        System.out.println("============================================================================");
        System.out.println("\t번호\t학교번호\t학교명\t누적학생수");
        System.out.println("============================================================================");
        int[] 누적학생수 = new int[중학교.length];   
        for(int i = 0 ; i < 학번.length ; i++){
            for(int j = 0 ; j < 중학교.length ; j++){
                if(j == 배당학교[i]){
                    누적학생수[j] += 1;
                    System.out.printf("%10d\t%8d\t%6s\t%6d\n", 학번[i], 배당학교[i], 중학교[j], 누적학생수[j]);          
                }else{
                  
                }
            }
        }
        System.out.println("============================================================================");     
    }
    static int[] 뺑뺑이(int[] a){                   
        int[] x = new int[a.length];                                // 학교배정 x
        int 대전중학생수 = 0, 한밭중학생수 = 0, 갈마중학생수 = 0,
                둔산중학생수 = 0, 성모중학생수 = 0;
        int total = 0;
        while(total < a.length){
     gogo : for(int i = 0 ; i < a.length ; i++){
                x[i] = (int)(Math.random()*5);
                if(x[i] == 0){
                    if(대전중학생수 >= 45){
                        i = i - 1;
                        continue gogo;
                    }else{
                        대전중학생수 += 1;
                    }
                }
                else if(x[i] == 1){
                    if(한밭중학생수 >= 40){
                        i = i - 1;
                        continue gogo;
                    }else{
                        한밭중학생수 += 1;
                    }
                }
                else if(x[i] == 2){
                    if(갈마중학생수 >= 30){
                        i = i - 1;
                        continue gogo;
                    }else{
                        갈마중학생수 += 1;
                    }
                }
                else if(x[i] == 3){
                    if(둔산중학생수 >= 50){
                        i = i - 1;
                        continue gogo;
                    }else{
                        둔산중학생수 += 1;
                    }
                }
                else{
                    if(성모중학생수 >= 35){
                        i = i - 1;
                        continue gogo;
                    }else{
                        성모중학생수 += 1;
                    }
                }
            }
                total = 대전중학생수 + 한밭중학생수 + 갈마중학생수 +
                    둔산중학생수 + 성모중학생수;   
        }
        return x;                            
    }
    static int[] 학생번호 (int a){
        int[] 번호 = new int[a];
        for(int i = 0 ; i < a ; i++){           // 학생번호 생성
            번호[i] = i;
        }
        return 번호;
    };
    static String[] 중학교 = new String[]{
        "대전중학교", "한밭중학교", "갈마중학교", "둔산중학교", "성모중학교"
    };
}

 

반응형

ExecutorService 를 사용하여 스레드수를 제한하여 사용하기

 

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor; 

 

public class ThreadTest {
    public static void main(String[] args) throws Exception {
        // 스레드풀을 사용하여 스레드 수를 제한하여 사용하기
        //final ExecutorService es = Executors.newCachedThreadPool(); // 1개이상의 스레드가 추가되었을경우 60초이상 동작을 하지 않으면 스레드를 풀에서 제거함.
        final ExecutorService es = Executors.newFixedThreadPool(2);   // 스레드수를 지정
       
        for(int i = 0 ; i < 10 ; i++){
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    ThreadPoolExecutor tpe = (ThreadPoolExecutor) es;
                    int poolSize = tpe.getPoolSize();
                    String threadName = Thread.currentThread().getName();
                    System.out.println("총 스레드 개수 : " + poolSize + " \t thread Name : " + threadName);
                }
            };
           
            es.execute(runnable);
           
            Thread.sleep(100);
        }
        es.shutdown();
    }
}
반응형

int 배열 선언. 거의 안쓰다보니 종종 까먹는다. 점점 뇌세포가 죽어가는듯.... ㅜ.ㅡ

(String, 또는 long, float, double 도 같은 형태이다)

 

int[] intArr = new Int[4];

or

int[] intArr = {0, 0, 3, 100};

 

BigDecimal 배열선언은 비슷하면서 약간 다르다.

 

BigDecimal[] bdArr = new BigDecimal[4];

or

BigDecimal[] bdArr = {BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO};

 

 

BigDecimal 마찬가지로 사칙연산도 약간 다르다.

 

bdArr[0] = bdArr[0].add(BigDecimal.valueOf(5.5));         -> 결과 : 0 + 5.5 = 5.5
bdArr[0] = bdArr[0].subtract(BigDecimal.valueOf(1));      -> 결과 : 5.5 - 1 = 4.5
bdArr[0] = bdArr[0].multiply(BigDecimal.valueOf(4));      -> 결과 : 4.5 * 4 = 18
bdArr[0] = bdArr[0].divide (BigDecimal.valueOf(6));        -> 결과 : 18 / 6 = 3

 

 

반응형

아래와 같은 VO 클래스가 있다고 하자.

 

public class SearchDataVO {

 private String searchUserId;
 private String searchUserName;
 
    public String getSearchUserId() {
        return searchUserId;
    }

    public void setSearchUserId(String searchUserId) {
        this.searchUserId = searchUserId;
    }

    public String getSearchUserName() {
        return searchUserName;
    }

    public void setSearchUserName(String searchUserName) {
        this.searchUserName = searchUserName;
    }

}

 

콘솔에 SearchDataVO 값을 찍기위해 다음과 같이 입력하면

 

System.out.println("console : " + SearchDataVO);

 

결과는 아래와 같이 이상하게 찍힌다.

 

 

ToStringBuilder 클래스의 reflectionToString 함수를 다음과 같이 추가하여 사용하면

    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }

 

결과는 다음과 같이 보다 쉽게 VO 변수들을 json형태나 multi형식으로 볼 수 있다.

 

test.SearchDataVO@2f032f9c[
  searchUserId=superman
  searchUserName=슈퍼맨
]

 

ToStringStyle.MULTI_LINE_STYLE 이외에 아래에서 맞는 형태를 찾아서 적용하면 된다.

 

ToStringStyle.DEFAULT_STYLE

ToStringStyle.MULTI_LINE_STYLE
ToStringStyle.NO_FIELD_NAMES_STYLE
ToStringStyle.SHORT_PREFIX_STYLE
ToStringStyle.SIMPLE_STYLE
ToStringStyle.NO_CLASS_NAME_STYLE
ToStringStyle.JSON_STYLE

반응형

전자정부프레임워크 트랜잭션 파일 설정(context-transaction.xml)

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="egov.dataSource"/>
 </bean>
  
 <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes> 
        <tx:method name="*" rollback-for="Exception" propagation="REQUIRED"/>
    </tx:attributes>
 </tx:advice>
   
 <aop:config>
  <aop:pointcut id="requiredTx" expression="execution(* com.testproject..impl.*Impl.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="requiredTx" />
 </aop:config>

</beans>

반응형

RedirectAttributes 클래스를 사용하면 리다이렉트시 주소표시줄에 덕지덕지 붙여서 안넘기고 깔끔하게 넘기는것이 가능

 

아래와 같이 addFlashAttribute 속성을 사용하여 VO나 파라미터정보 등을 리다이렉트화면으로 전송함.

 

- 주소표시줄에 표시는 되지않으나 post방식이 아니고 get방식임.

- addFlashAttribute를 사용하여 세션에 잠시 저장한 후 리다이렉트화면으로 넘기고 소멸함.

 

redirectAttributes.addFlashAttribute("SearchVO", searchVO);

 

return "redirect:/dataInfo/reqstDataInfo.do?menuId="+searchVO.getMenuId();

 

반응형

RedirectAttributes 사용

리다이렉트시 "redivect:/view.do?rMsg=완료되었습니다."와 같이 표시되는것을 "redivect:/view.do"로 깔끔히 표시되도록 해준다.

(인코딩 문제도 해결)

 

@Controller
public class PortalController extends BaseController{

 

@RequestMapping("/list.do")
 public String doList(@ModelAttribute("listVO")ListVO vo, HttpServletRequest request,
   RedirectAttributes redirectAttributes) throws Exception{

   redirectAttributes.addFlashAttribute("rMsg", "완료되었습니다.");
  return "redirect:/view.do";
 }

 

}

 

주의할 점중 하나는 egov-com-servlet.xml 설정파일에 아래 설정이 잡혀있어야된다.

(리다이렉트 하기전 자꾸 에러가 나고 PortalController의 /list.do에 접근하기 전에 튕겨버려서 에러찾기가 힘들었다.)

 

<mvc:annotation-driven />

반응형

pdf 생성 라이브러리 itextpdf jar

 

import java.io.File;

import org.terracotta.agent.repkg.de.schlichtherle.io.FileOutputStream;

import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

public class TestPdfCreate {

 public void pdfCreate() throws Exception {
  String[] nameArr = {"Mr.Lee", "Mr.Kim", "Mr.Bae", "Mr.Hong"};
  String[] ageArr = {"41", "25", "16", "30"};
  String fileName = "";
  String dir = "E:/Test/Pdf";
  fileName = "testFile.pdf";
  
  File directory = new File(dir);
  if(!directory.exists()) directory.mkdirs();
  File file = new File(dir+"/"+fileName);
  file.createNewFile();
  
  Document document = new Document();
  FileOutputStream fos = new FileOutputStream(file);
  PdfWriter.getInstance(document, fos);
  
  document.open();
  PdfPTable table = new PdfPTable(2);
  
  for(int i = 0 ; i < nameArr.length ; i++){
   table.addCell("name : " + nameArr[i]);
   table.addCell("age : " + ageArr[i]);
  }
  
  document.add(table);
  document.close();
 }
 
 public static void main(String[] args) {
  try {
   TestPdfCreate pbv = new TestPdfCreate();
   pbv.pdfCreate();
   System.out.println("file success");
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

반응형

package com.collabi.red.sys.openapi.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.collabi.red.ext.common.utils.StringUtil;

import net.sf.json.JSONObject;

public class OpenApiTest {

 private static final Logger logger = LoggerFactory.getLogger(OpenApiTest.class);

 public OpenApiTest() {

 }

 public Map<String, Object> setParamMap() {
  Map<String, Object> dataMap = new ConcurrentHashMap<String, Object>();
  dataMap.put("PARAM1", "APPLE");
  dataMap.put("PARAM2", "WOOD");
  return dataMap;
 }

 public void callApiCommon() {
  String defUrl = "subinto.test.com";
  String encodType = "UTF-8";
  StringBuffer sb = new StringBuffer();
  sb.append(defUrl);
  Map<String, Object> dataMap = this.setParamMap();
  this.getRedundancyInterLook(sb.toString(), this.setParamMapToJson(dataMap), encodType);
 }

 public String setParamMapToJson(Map<String, Object> dataMap) {
  JSONObject jsonParam = new JSONObject();
  jsonParam.putAll(dataMap);
  StringBuffer sbEqParam = new StringBuffer();
  try {
   sbEqParam.append("paramData=").append(URLEncoder.encode(jsonParam.toString().replaceAll("%", "%25"), "UTF-8"));
  } catch (UnsupportedEncodingException e) {
   logger.error(e.getMessage());
  }
  return sbEqParam.toString();
 }

 private void getRedundancyInterLook(String interLookUrl, String urlParameters, String encodType) {
  System.out.println("############################ : URL " + interLookUrl);
  System.out.println("############################ : urlParameters " + urlParameters);
  JSONObject jsonObj = this.concertFromHTTPtoJSON(interLookUrl, urlParameters, encodType);
  System.out.println(" :::::::::: interLookUrl : " + interLookUrl);
  System.out.println(" :::::::::: viewType   : " + encodType);
  System.out.println(" :::::::::: jsonObj   : " + ToStringBuilder.reflectionToString(jsonObj));
 }

 private JSONObject concertFromHTTPtoJSON(String xmlUrl, String urlParameters, String encodType) {
  URL url = null;
  HttpURLConnection httpUrlConnection = null;
  BufferedWriter bw = null;
  InputStream is = null;
  JSONObject jsonObj = null;

  try {
   url = new URL(xmlUrl);
   URLConnection urlConnection = url.openConnection();
   httpUrlConnection = (HttpURLConnection) urlConnection;

   String postData = urlParameters;

   httpUrlConnection.setDoInput(true);
   httpUrlConnection.setDoOutput(true);
   httpUrlConnection.setRequestMethod("POST");
   httpUrlConnection.setUseCaches(false);
   httpUrlConnection.setDefaultUseCaches(false);
   httpUrlConnection.setRequestProperty("Content-Length", "0");
   httpUrlConnection.setRequestProperty("Content-Language", encodType);

   bw = new BufferedWriter(new OutputStreamWriter(httpUrlConnection.getOutputStream(), "UTF-8"));
   bw.write(postData);
   bw.flush();

   is = httpUrlConnection.getInputStream();

   BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
   String jsonText = this.readAll(rd);
   jsonObj = JSONObject.fromObject(StringUtil.converterDecoding(jsonText, encodType));

   bw.close();
   is.close();
   is = null;
  } catch (MalformedURLException e) {
   logger.error(e.getMessage());
  } catch (IOException e) {
   logger.error(e.getMessage());
  } finally {

   if (httpUrlConnection != null)
    try {
     httpUrlConnection.disconnect();
     httpUrlConnection = null;
    } catch (Exception e) {
     logger.error(e.getMessage());
    }

   if (bw != null)
    try {
     bw.close();
    } catch (Exception e) {
     logger.error(e.getMessage());
    }

   if (is != null)
    try {
     is.close();
     is = null;
    } catch (Exception e) {
     logger.error(e.getMessage());
    }
  }

  return jsonObj;
 }

 private String readAll(BufferedReader rd) throws IOException {
  StringBuilder sb = new StringBuilder();

  String inputStr;
  while ((inputStr = rd.readLine()) != null) {
   sb.append(inputStr);
  }

  return sb.toString();
 }

 public static void main(String[] args) {
  new OpenApiTest().callApiCommon();
 }

}

반응형
###############################################################
## 작업 #1 프로젝트 준비

## WEB-INF/lib
commons-logging.jar
org.springframework.aop-3.0.1.RELEASE.jar
org.springframework.asm-3.0.1.RELEASE.jar
org.springframework.beans-3.0.1.RELEASE.jar
org.springframework.context-3.0.1.RELEASE.jar
org.springframework.core-3.0.1.RELEASE.jar
org.springframework.expression-3.0.1.RELEASE.jar
org.springframework.transaction-3.0.1.RELEASE.jar
org.springframework.web-3.0.1.RELEASE.jar
spring-security-config-3.0.2.RELEASE.jar
spring-security-core-3.0.2.RELEASE.jar
spring-security-web-3.0.2.RELEASE.jar


###############################################################
## 작업 #2 초간단 HTTP 보안

## web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/applicationContext*.xml</param-value>
</context-param>

<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>


## applicationContext-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.0.xsd">

<http auto-config='true'>
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
</http>

<authentication-manager>
<authentication-provider>
<user-service>
<user name="jimi" password="jimis" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="bobs" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>

</beans:beans>


## /index.jsp
<h1>메인 페이지</h1>
<br/>
<a href="/admin">관리자 페이지</a>


## /admin/index.jsp
<h1>Admin Main Page</h1>
Administrator only!!!
<br/>
<a href="/">메인 페이지</a>


###############################################################
## 응용 #1 직접 만든 로그인 폼

## applicationContext-security.xml
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
<form-login login-page="/login.jsp"/>


## login.jsp
<h1>로그인 페이지</h1>
<form name='f' action='/j_spring_security_check' method='POST'>
 <table border="1">
    <tr><td>아이디 </td><td><input type='text' name='j_username' value=''></td></tr>
    <tr><td>비밀번호 </td><td><input type='password' name='j_password'/></td></tr>
    <tr><td colspan='2'><input name="submit" type="submit" value="로그인"/></td></tr>
  </table>
</form>


###############################################################
## 응용 #2 로그아웃

## /index.jsp
<br/>
<a href="/j_spring_security_logout">로그아웃</a>


###############################################################
## 응용 #3 사용자 로그인 확인

## index.jsp
<%@page import="org.springframework.security.core.*"%>
<%@page import="org.springframework.security.core.context.*"%>
<%@page import="org.springframework.security.core.userdetails.*"%>
<%
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

String username = null;
boolean isAnonymous = true;
if (principal instanceof UserDetails) {
username = ((UserDetails) principal).getUsername();
isAnonymous = false;
} else {
username = principal.toString();
isAnonymous = true;
}
%>

...

<%
if(isAnonymous) {
%>
<a href="/login.jsp">로그인</a>
<%
} else {
%>
<%=username %>님 반갑습니다!
<br/>
<a href="/j_spring_security_logout">로그아웃</a>
<%
}
%>


###############################################################
## 응용 #4 친절한 안내

## applicationContext-security.xml
<http auto-config='true' access-denied-page="/noAuthorized.jsp">


## noAuthorized.jsp
<h1>접근 권한 없음!!</h1>
<br/>
<a href="/">메인 페이지</a>


###############################################################
## 응용 #5 로그인 실패 메시지

## applicationContext-security.xml
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error"/>


## login.jsp
<%@page import="org.springframework.security.core.*"%>
<%@page import="org.springframework.security.web.authentication.*"%>
<%
boolean loginError = request.getParameter("login_error") != null;

String errorMsg = "none";
if (loginError) {
AuthenticationException ex = (AuthenticationException) session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY);
errorMsg = ex != null ? ex.getMessage() : "none";
}
%>

...

<%
if(loginError) {
if("Bad credentials".equals(errorMsg)) {
%>
<font color="red">아이디나 비밀번호 입력이 틀렸습니다.</font>
<%
} else {
%> 
<font color="red">로그인 에러 : <%=errorMsg %></font>
<%
}
}
%> 


###############################################################
## 응용 #6 로그인 성공 페이지

## applicationContext-security.xml
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error"
default-target-url="/" always-use-default-target="true"/>


###############################################################
## 응용 #7 특정 URL 통과시키기

## applicationContext-security.xml
<intercept-url pattern="/login.jsp" filters="none"/>
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error"
default-target-url="/" always-use-default-target="true"/>


###############################################################
## 응용 #8-1 동시에 1명만 접속(기존 세션 만료)

## applicationContext-security.xml
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error"
default-target-url="/" always-use-default-target="true"/>
<session-management>
<concurrency-control max-sessions="1"/>
</session-management>


###############################################################
## 응용 #8-2 동시에 1명만 접속(로그인 에러)

## applicationContext-security.xml
<session-management>
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>
</session-management>


###############################################################
## 응용 #9 사용자 정보 DB에서 가져오기

## postgresql-8.4-701.jdbc4.jar
## org.springframework.jdbc-3.0.1.RELEASE-A.jar


## db
  create table users(
      username varchar(50) not null primary key,
      password varchar(50) not null,
      enabled boolean not null);

  create table authorities (
      username varchar(50) not null,
      authority varchar(50) not null,
      constraint fk_authorities_users foreign key(username) references users(username));
      create unique index ix_auth_username on authorities (username,authority);

INSERT INTO users(username, "password", enabled) VALUES ('bob', 'bobs', true);
INSERT INTO users(username, "password", enabled) VALUES ('jimi', 'jimis', true);

INSERT INTO authorities(username, authority) VALUES ('bob', 'ROLE_USER');
INSERT INTO authorities(username, authority) VALUES ('jimi', 'ROLE_USER');
INSERT INTO authorities(username, authority) VALUES ('jimi', 'ROLE_ADMIN');


## applicationContext-security.xml
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="securityDataSource" />
</authentication-provider>
</authentication-manager>

..

<beans:bean id="securityDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="org.postgresql.Driver" />
<beans:property name="url" value="jdbc:postgresql:security" />
<beans:property name="username" value="security" />
<beans:property name="password" value="security" />
</beans:bean>



/** 심화 **/


###############################################################
## 심화 #1 메서드 권한제어

## com.springsource.org.aopalliance-1.0.0.jar
## com.springsource.org.aspectj.tools-1.6.6.RELEASE.jar
## com.springsource.net.sf.cglib-2.1.3.jar
## org.springframework.web.servlet-3.0.1.RELEASE-A.jar


## web.xml
    <servlet>
        <servlet-name>security</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>security</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>


## security-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:component-scan base-package="my.controller" />
<context:annotation-config />

<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>

</beans>


## my.controller.MyController.java
@Controller
public class MyController {

@RequestMapping("/mvcHello")
public void mvcHello() {
}
}


## WEB-INF/view/mvcHello.jsp
<h1>MVC Hello</h1>


## applicationContext-security.xml
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error"
default-target-url="/" always-use-default-target="true"/>

----

## applicationContext-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

...

<context:component-scan base-package="my.service" />

<global-method-security secured-annotations="enabled"/>  


## my.service.MyService.java
@Service
public class MyService {

@Secured("ROLE_ADMIN")
public String getSecurity() {
return "success";
}
}


## my.controller.MyController.java
@Autowired MyService myService;
@RequestMapping("/hasSomeSecurity")
public void hasSomeSecurity(Model model) {
String result = myService.getSecurity();
model.addAttribute("result", result);
}


## index.jsp
<a href="/hasSomeSecurity.do">보안 페이지</a>
<br/>


## WEB-INF/view/hasSomeSecurity.jsp
<h1>무언가 보안요소를 가지고 있는 페이지</h1>
보안결과 : ${result }


###############################################################
## 심화 #2 MyUserDeatilsService

## applicationContext-security.xml
<authentication-manager>
<authentication-provider user-service-ref="myUserDetailsService"/>
</authentication-manager>

<beans:bean id="myUserDetailsService"
class="my.service.MyUserDetailsService">
<beans:property name="myDao">
<beans:bean class="my.dao.MyDao">
<beans:property name="dataSource" ref="securityDataSource"/>
</beans:bean>
</beans:property>
</beans:bean>


## my.domain.MyUserDetails
public class MyUserDetails implements UserDetails {

private String username;
private String password;
private boolean isEnabled = true;
private boolean isAccountNonExpired = true;
private boolean isAccountNonLocked = true;
private boolean isCredentialsNonExpired = true;
private Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
public MyUserDetails(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public Collection<GrantedAuthority> getAuthorities() {
return authorities;
}

@Override
public String getPassword() {
return password;
}

@Override
public String getUsername() {
return username;
}

@Override
public boolean isAccountNonExpired() {
return isAccountNonExpired;
}

@Override
public boolean isAccountNonLocked() {
return isAccountNonLocked;
}

@Override
public boolean isCredentialsNonExpired() {
return isCredentialsNonExpired;
}

@Override
public boolean isEnabled() {
return isEnabled;
}

}


## my.service.MyUserDetailsService
public class MyUserDetailsService implements UserDetailsService {

private MyDao myDao;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
UserDetails userDetails = myDao.getUserDetails(username);
Collection<GrantedAuthority> authorities = myDao.getAuthorities(username);
userDetails.getAuthorities().addAll(authorities);
return userDetails;
}

public void setMyDao(MyDao myDao) {
this.myDao = myDao;
}
}


## my.dao.MyDao.java
public class MyDao extends JdbcDaoSupport {

    public static final String DEF_USERS_BY_USERNAME_QUERY =
        "select username,password " +
        "from users " +
        "where username = ?";
    public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =
        "select username,authority " +
        "from authorities " +
        "where username = ?";
    
public UserDetails getUserDetails(String username) {
        List<UserDetails> userDetailsList = getJdbcTemplate().query(DEF_USERS_BY_USERNAME_QUERY, new String[] {username}, new RowMapper<UserDetails>() {
            public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException {
                String username = rs.getString(1);
                String password = rs.getString(2);
                return new MyUserDetails(username, password);
            }

        });
        
        if(userDetailsList.size() == 1)
        return userDetailsList.get(0);
        else 
        return null;
}

public Collection<GrantedAuthority> getAuthorities(String username) {
        return getJdbcTemplate().query(DEF_AUTHORITIES_BY_USERNAME_QUERY, new String[] {username}, new RowMapper<GrantedAuthority>() {
            public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException {
                String roleName = rs.getString(2);
                return new GrantedAuthorityImpl(roleName);
            }
        });
}

}


###############################################################
## 심화 #3 XML-Based Configuration

## applicationContext-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/login.jsp" filters="none"/>
<sec:filter-chain pattern="/sessionExpired.jsp" filters="none"/>
<sec:filter-chain pattern="/**" filters="
     securityContextPersistenceFilter,
     logoutFilter,
     formLoginFilter,
     exceptionTranslationFilter,
     filterSecurityInterceptor" />
</sec:filter-chain-map>
</bean>

<bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<property name="securityContextRepository">
<bean class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"/>
</property>
</bean>
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg><bean class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler"/></constructor-arg>
<constructor-arg><bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/></constructor-arg>
<property name="filterProcessesUrl" value="/j_spring_security_logout"></property>
</bean>

<bean id="formLoginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="filterProcessesUrl" value="/j_spring_security_check"/>
<property name="authenticationSuccessHandler">
<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/"></property>
<property name="alwaysUseDefaultTargetUrl" value="true"></property>
</bean>
</property>
<property name="authenticationFailureHandler">
<bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login.jsp?login_error"></property>
</bean>
</property>
<property name="sessionAuthenticationStrategy">
<bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
<constructor-arg>
<bean class="org.springframework.security.core.session.SessionRegistryImpl"></bean>
</constructor-arg>
<property name="maximumSessions" value="1"></property>
</bean>
</property>
</bean> 

<bean id="exceptionTranslationFilter"
    class="org.springframework.security.web.access.ExceptionTranslationFilter">
<property name="authenticationEntryPoint">
<bean class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login.jsp"/>
</bean>
</property>
<property name="accessDeniedHandler">
<bean class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<property name="errorPage" value="/noAuthorized.jsp"/>
</bean>
</property>
</bean>

<bean id="filterSecurityInterceptor"
       class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="securityMetadataSource">
<sec:filter-security-metadata-source>
<sec:intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
<sec:intercept-url pattern="/**" access="ROLE_USER" />
</sec:filter-security-metadata-source>
</property>
</bean>

<bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="myUserDetailsService" />
</bean>
</property>
</bean>
<bean id="myUserDetailsService"
class="my.service.MyUserDetailsService">
<property name="myDao">
<bean class="my.dao.MyDao">
<property name="dataSource" ref="securityDataSource"/>
</bean>
</property>
</bean>

<bean id="securityDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql:security" />
<property name="username" value="security" />
<property name="password" value="security" />
</bean>

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.ConsensusBased">
<property name="decisionVoters">
<list>
<bean class="org.springframework.security.access.vote.RoleVoter"></bean>
</list>
</property>
</bean>

<context:component-scan base-package="my.service" />

<sec:global-method-security secured-annotations="enabled"></sec:global-method-security>  
반응형

자바 프로그래머로써 일을하다보면 남이 만들어둔 .jar 안에 .class 파일을 열어서 확인하고 싶을때가 있다.

이때 Jad 를 사용하면 .class 파일을 .java 로 디컴파일하여 소스코드를 확인할수있다.



우선 아래 경로에서 jad.exe 파일을 다운받아야한다.

https://varaneckas.com/jad/


이제는 바로 사용하여도 좋다.


이제 콘솔창을 열어 jad.exe가 설치된 경로로 이동하여 jad 를입력해본다.

그러면 아래와 같이 option들의 대한 설명이 적혀있는 문자열이 출력된다.





현재 아래 와 같이 폴더안에는 .class 파일 하나와 dir 폴더 jad 파일이 존재한다.

클래스 파일과 dir 은 테스트 용도로 넣었다.


※ Readme.txt 를 보면 좀더 자세한 설명이 나와있다.






.class 파일 하나를 디컴파일


명렁어

jad -o -sjava ComUtil.class


-o : 디컴파일후에 생성된 파일과 동일한 파일이 있을경우 덮어쓴다.

-s<ext> : 확장자명을 지정한다.  -sjava 는 .java 로 생성한다는 뜻이다.

 






폴더(패키지)전체를 디컴파일 


명령어

jad -o -r -sjava dir/*.class


-r : 디렉토리를 기준으로 디컴파일한다.


dir/*.class 는 dir 폴더안에 모든 class 파일을 디컴파일하겠다는 뜻이다.


※ 실제 java파일 생성되는 경로는 class 파일에 들어있는 내용중 패키지내용을 따라서 폴더가 만들어진다.







확인









출처: http://javacpro.tistory.com/23 [버물리의 IT공부]

반응형

GPKI 인증서 로그인 기능을 구현하려고 하는 경우에는 EgovLoginController.java를 다음과 같이 변경한다.

  • 로그인 화면 처리 부분을 다음과 같이 수정한다.
public String loginUsrView(@ModelAttribute("loginVO") LoginVO loginVO,
    HttpServletRequest request,
    HttpServletResponse response,
    ModelMap model) 
    throws Exception {
	// # GPKI 인증을 처리하는 경우 
	GPKIHttpServletResponse gpkiresponse = null;
	GPKIHttpServletRequest gpkirequest = null;
 
	try{
 
		gpkiresponse=new GPKIHttpServletResponse(response); 
		gpkirequest= new GPKIHttpServletRequest(request);
		gpkiresponse.setRequest(gpkirequest);
		model.addAttribute("challenge", gpkiresponse.getChallenge());
		return "cmm/uat/uia/EgovLoginUsr";
 
	}catch(Exception e){
		return "cmm/egovError";
	}
}
  • 인증서 로그인 처리 부분을 다음과 같이 수정한다.
public String actionCrtfctLogin(@ModelAttribute("loginVO") LoginVO loginVO, 
    HttpServletRequest request,
    HttpServletResponse response,
    ModelMap model)
    throws Exception {
    	// # GPKI 인증을 처리하는 경우 
    	// 접속IP
    	String userIp = EgovClntInfo.getClntIP(request);
 
    	// 1. GPKI 인증
    	GPKIHttpServletResponse gpkiresponse = null;
	GPKIHttpServletRequest gpkirequest = null;
	String dn = "";
	try{
		gpkiresponse = new GPKIHttpServletResponse(response);
		gpkirequest = new GPKIHttpServletRequest(request);
		gpkiresponse.setRequest(gpkirequest);
		X509Certificate cert = null; 
 
		byte[] signData = null;
		byte[] privatekey_random = null;
		String signType = "";
		String queryString = "";
 
		cert = gpkirequest.getSignerCert();
		dn = cert.getSubjectDN();
 
		java.math.BigInteger b = cert.getSerialNumber();
		b.toString();
		int message_type =  gpkirequest.getRequestMessageType();
		if( message_type == gpkirequest.ENCRYPTED_SIGNDATA || 
		    message_type == gpkirequest.LOGIN_ENVELOP_SIGN_DATA ||
		    message_type == gpkirequest.ENVELOP_SIGNDATA || 
		    message_type == gpkirequest.SIGNED_DATA){
		    signData = gpkirequest.getSignedData();
		    if(privatekey_random != null) {
			privatekey_random   = gpkirequest.getSignerRValue();
		    }
		    signType = gpkirequest.getSignType();
		}       
		queryString = gpkirequest.getQueryString();
	}catch(Exception e){
		return "cmm/egovError";
	}
 
	// 2. 업무사용자 테이블에서 dn값으로 사용자의 ID, PW를 조회하여
	// 이를 일반로그인 형태로 인증하도록 함
	if (dn != null && !dn.equals("")) {
 
		loginVO.setDn(dn);
		LoginVO resultVO = loginService.actionCrtfctLogin(loginVO);
		if (resultVO != null && resultVO.getId() != null && 
		    !resultVO.getId().equals("")) {	
		    // 3. spring security 연동
		    return "redirect:/j_spring_security_check?j_username=" +
		           resultVO.getUserSe() + resultVO.getId() + 
			   "&j_password=" + resultVO.getUniqId();
		} else {
		    model.addAttribute("message", 
		                       egovMessageSource.getMessage("fail.common.login"));
		    return "cmm/uat/uia/EgovLoginUsr";
		}
	} else {
		model.addAttribute("message", 
		                   egovMessageSource.getMessage("fail.common.login"));
		return "cmm/uat/uia/EgovLoginUsr";
	}
}
반응형

+ Recent posts