JSTL 태그 라이브러리 fmt 를 추가 한다.


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


formatDate 함수를 사용 한다. value 에 Date 형 값을 넣고, 원하는 pattern 대로 넣어주면 변환되어 출력 된다.


<fmt:formatDate value="java.util.Date" pattern="yyyy.MM.dd"/>


소개


Spring MVC 사용 시 DispatcherServlet 기능을 사용 한다. requestUri 에 따라 Controller 로 분기를 하고, 비지니스 로직 처리 후 Resolver 를 사용하여 해당 JSP 파일을 찾아 응답 하게 되는대 그 사이의 시점을 잡아 처리 하는 부분이 AbstractView 의 기능이다.


범용적으로 사용하는 Resolver 는 InternalResourceViewResolver 이다. 우리는 그 전에 DownloadView 를 구현하여 파일을 다운로드 할 것이다.


적용 방법

1. DownloadView


public class DownloadView extends AbstractView {

    public DownloadView() {
        setContentType("applicaiton/download;charset=utf-8");
    }

    private void setDownloadFileName(String fileName, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        String userAgent = request.getHeader("User-Agent");

        boolean isIe = userAgent.indexOf("MSIE") != -1;

        if(isIe){
            fileName = URLEncoder.encode(fileName, "utf-8");
        } else {
            fileName = new String(fileName.getBytes("utf-8"));
        }

        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\";");
        response.setHeader("Content-Transfer-Encoding", "binary");
    }

    private void downloadFile(File downloadFile, HttpServletRequest request, HttpServletResponse response) throws Exception {
        OutputStream out = response.getOutputStream();
        FileInputStream in = new FileInputStream(downloadFile);

        try {
            FileCopyUtils.copy(in, out);
            out.flush();
        } catch (Exception e) {
            throw e;
        } finally {
            try { if (in != null) in.close(); } catch (IOException ioe) {}
            try { if (out != null) out.close(); } catch (IOException ioe) {}
        }
    }

    @Override
    protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        try {
            this.setResponseContentType(request, response);

            File downloadFile = (File) model.get("downloadFile");

            if (logger.isDebugEnabled()) {
                logger.debug("downloadFile: " + downloadFile);
            }

            this.setDownloadFileName(downloadFile.getName(), request, response);

            response.setContentLength((int) downloadFile.length());
            this.downloadFile(downloadFile, request, response);
        } catch (Exception e) {
            throw e;
        }
    }
}


2. applicationContext.xml


파일 하단에 추가 하자.


<beans:bean id="downloadView" class="kr.co.whitelife.DownloadView" />


3. SampleController


View 를 DownloadView 로 교체 한 후 파일 객체를 넘겨 주자.


@Controller
public class SampleController {

    @Resource(name="downloadView")
    private View downloadView;

    @RequestMapping(value="/sample", method=RequestMethod.GET})
    public ModelAndView sample() {
        ModelAndView mav = new ModelAndView();
        mav.setView(this.downloadView);

        File downloadFile = new File("downloadFile");
        mav.addObject("downloadFile", downloadFile);

        return mav;
    }
}


4. SampleRequest


파일을 첨부 하여 http://localhost:8080/sample 요청 해 보자.


Maven Repository 에 있는 라이브러리 압축 파일이 께져서 발생 하는 현상 이다.


Maven Repository 를 초기화 한 후 라이브러리를 다시 받고 서버를 시작해 보자.
해결 될 것 이다.


Spring MVC 사용 시 SimpleMappingExceptionResolver 설정을 해놓았다. Controller 에서 공통으로 필요한 부분을 AOP 로 만들어서 사용 하는대, Exception 발생 시 AOP Proxy 에서 예외가 발생 했다. 정작 필요한 에러 메시지는 볼 수 없었다.


일반적으로 AOP 설정을 하는 경우 아래와 같이 선언을 했었다.


<aop:config>    
    // Doing...
</aop:config>


<aop:config> 에 아무런 설정 값을 주지 않은 경우 기본적으로 JDK Proxy 로 동작 한다. Spring 에서 제공 하는 InvocableHandlerMethod.invoke(Object[] arg) 메소드를 사용 하여 실제 targetClass를 호출 한다. Java Reflection 기반 이라고 생각 하면 된다.


에러 메시지의 일부 이다. invoke 호출 시 예외가 발생 한다. targetClass 가 Interface 를 구현하고 있는 경우 instance 를 인식하지 못해 예외가 발생 하는 것 같다.


java.lang.IllegalStateException: The mapped controller method class 'com.xxx.xxx' is not an instance of the actual controller bean instance '$Proxy22'. If the controller requires proxying (e.g. due to @Transactional), please use class-based proxying.
HandlerMethod details: 
Controller [$Proxy22]
Method [public org.springframework.web.servlet.ModelAndView com.xxx.xxx.xxxxxx() throws java.lang.Exception]
// 생략...


문제 해결을 위해서는 Class 기반 proxy 사용을 해야 한다.
please use class-based proxying. 이 메시지가 친절하게 방법을 알려 준다.


CGLIB Proxy 를 사용하려면 아래와 같이 설정 값을 변경 한다.


<aop:config proxy-target-class="true">
    // Doing...
</aop:config>


테스트를 해보자. 정상적으로 동작 할 것 이다.


참고 사이트


소개


Spring 3.0 이상 부터는 Ajax 처리 시 아래와 같은 방법으로 쉽게 처리가 가능 하다.


RequestMapping(value="/sample", method=RequestMethod.GET})
public @ResponseBody String sample() {
    return "sample";
}


하지만 범용적으로 사용하고 싶을 때가 있을 것 이다. 그런 경우 사용하는 방법 이다. 아래 설명을 참고하여 적용 해 보자.


적용 방법

1. AjaxView


public class AjaxView extends AbstractView {

    public AjaxView() {
        setContentType("text/json;charset=utf-8");
    }

    @Override
    protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        try {
            this.setResponseContentType(request, response);

            String reponseString = "";

            // responseString Doing...

            PrintWriter writer = response.getWriter();
            writer.print(reponseString);
            writer.flush();

            try { if (writer != null) { writer.close(); } } catch (IOException ioe) {}
        } catch (Exception e) {
            throw e;
        }
    }
}


2. applicationContext.xml


파일 하단에 추가 하자.


<beans:bean id="ajaxView" class="kr.co.whitelife.AjaxView" />


3. SampleController


View 를 ajaxView 로 교체 하자.


@Controller
public class SampleController {
    @Resource(name="ajaxView")
    private View ajaxView;

    @RequestMapping(value="/sample", method=RequestMethod.GET})
    public ModelAndView sample() {
        ModelAndView mav = new ModelAndView();
        mav.setView(this.ajaxJsonView);

        // Doing...

        return mav;
    }
}


4. Sample Request


http://localhost:8080/sample 요청 해 보자.


1. 다운로드


wget http://apache.mirror.cdnetworks.com/httpd/httpd-2.2.29.tar.gz
mkdir httpd
mv httpd-2.2.29.tar.gz httpd
tar zxvf httpd-2.2.29.tar.gz


2. 설정하기


./configure \
--prefix=/home/whitelife/httpd-2.2.29 \
--with-mpm=worker \
--enable-module=so \
--enable-mods-shared=most \
--enable-maintainer-mode \
--enable-deflate \
--enable-headers \
--enable-rewrite \
--enable-ssl \
--enable-proxy \
--enable-proxy-http \
--enable-proxy-ajp \
--enable-proxy-balance


3. 컴파일 하기


make


4. 설치 하기


make install


5. 확인 하기


/home/whitelife/httpd-2.2.29/bin/httpd -V


6. 시작 하기


/home/whitelife/httpd-2.2.29/bin/apachectl start


http://localhost/ 접속해 보자.


참고 사이트


문제 발생


checking for SSL/TLS toolkit base... none
checking for OpenSSL version... checking openssl/opensslv.h usability... no
checking openssl/opensslv.h presence... no
checking for openssl/opensslv.h... no
checking openssl/ssl.h usability... no
checking openssl/ssl.h presence... no
checking for openssl/ssl.h... no
no OpenSSL headers found
checking for SSL-C version... checking sslc.h usability... no
checking sslc.h presence... no
checking for sslc.h... no
no SSL-C headers found
configure: error: ...No recognized SSL/TLS toolkit detected


문제 해결


yum install -y openssl openssl-devel

참고 사이트


문제 발생


checking whether to enable mod_deflate... checking dependencies
checking for zlib location... not found


문제 해결


yum -y install zlib-devel

참고 사이트


+ Recent posts