반응형

Invalid tld file: [/WEB-INF/tags/common.tld], see JSP specification section 7.3.1 for more details


잘 사용하던 JSP 커스텀 태그가 Servelt 3.0 스펙을 하면서 위와 같은 오류가 발생하기 시작했습니다.


위 오류 문구 권고대로 JSP 2.2 의 7.3.1 섹션을 찾아보았습니다.


TLD files should not be placed in /WEB-INF/classes or /WEB-INF/lib, and must not be

placed inside /WEB-INF/tags or a subdirectory of it


내용중에 위의 문구가 바로 문제의 포인트 였습니다.


/WEB-INF/classes 안돼요.

/WEB-INF/lib 안돼요.

/WEB-INF/tags 나 그 하위폴더 안돼요.


해결책은 /WEB-INF/tags/common.tld ===> /WEB-INF/custom-tags/common.tld 


이렇게 폴더 위치를 변경했습니다.


스펙이 변경되면서 뭔가 까다로워 졌네요. @.@


반응형
반응형

스프링부트의 기본 지원 뷰는 타임리프입니다.

(Springboot의 기본 지원 view는 thymeleaf 입니다.)


view를 jsp로 사용하기 위해서는 아래와 같은 설정이 필요합니다.


pom.xml - JSP 및 JSTL 사용을 위해서 필요합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>




application.properties 에서 jsp 뷰의 prefix와 suffix 를 설정해 줍니다.


1
2
3
spring.mvc.view.prefix=/WEB-INF/jsp
spring.mvc.view.suffix=.jsp




!! 404 오류 !!

위 pom.xml 에 의존성을 추가하지 않아도 별다른 컴파일 오류나 런타임 오류가 발생하지 않는다.

하지만 실제 웹페이지를 호출하면 404 오류가 발생한다.

반응형
반응형

오라클 jdbc 라이브러리는 메이븐 중앙저장소에 찾을 수가 없어서 다른 저장소에서 찾습니다.


pom.xml 에서 아래와 같이 별도 repository를 설정해서 받습니다.


1
2
3
4
5
    <repository>
      <id>oracle</id>
      <name>ORACLE JDBC Repository</name>
      <url>http://maven.jahia.org/maven2</url>
    </repository>
cs



2017년 6월 8일 기준으로 위 사이트에 들어가보면 아래와 같이 버전이 등록되어 있습니다.



https://devtools.jahia.com/nexus/content/groups/maven-jahia-org/com/oracle/ojdbc5/


11.2.0.2.0

11.2.0.3


https://devtools.jahia.com/nexus/content/groups/maven-jahia-org/com/oracle/ojdbc6/


12.1.0.1

12.1.0.2


https://devtools.jahia.com/nexus/content/groups/maven-jahia-org/com/oracle/ojdbc7/


12.1.0.2



골라서 원하시는 버전을 쓰시면 됩니다.


참고로, ojdbc6 과 ojdbc7 의 차이점은 jdk6과 jdk7로 컴파일 한 차이 입니다.






반응형
반응형

maven 을 사용하다 보면 자주 사용되지만 공개 repository에서 관리되지 않는 라이브러리들이 종종 있습니다.


대표적으로 mssql jdbc 가 있습니다.


이런 경우 mssql jdbc만 다른 방식으로 관리하고 컴파일 및 빌드를 한다는게 정말 불편하고 일관되지 않아서 어려움이 많습니다.


그래서 maven에서 이런 라이브러들까지 관리할 수 있도록 local 라이브러리 관리 기능을 제공하고 있습니다.




1. pom.xml 에서 아래처럼 repository 를 설정합니다. ${basedir}은 프로젝트 루트 디렉토리 입니다.


1
2
3
4
5
6
7
8
9
  <repositories>
    <repository>
      <!-- DO NOT set id to "local" because it is reserved by Maven -->
      <id>local-lib</id>
      <name>In Project Repo</name>
      <url>file://${basedir}/lib</url>
      <layout>default</layout>
    </repository>
  </repositories>



2. mssql jdbc를 예로 <dependecies>에서는 아래 처럼 설정합니다.


1
2
3
4
5
6
    <!-- MSSQL -->
    <dependency>
      <groupId>com.microsoft.sqlserver</groupId>
      <artifactId>sqljdbc4</artifactId>
      <version>4.2</version>
    </dependency>




3. 다운로드 받은 실제 mssql 라이브러리를 아래 폴더 형식으로 넣어둡니다. 


[프로젝트홈] \lib\com\microsoft\sqlserver\sqljdbc4\4.2\sqljdbc4-4.2.jar


위 폴더 구조는 "groupId" / "artifactId" / "version" / "artifactId"-"version".jar 이런 규칙으로 생성됩니다. 




반응형
반응형

apache poi 로 엑셀작업을 하다보면 셀(Cell) 크기 문제로 어려움을 겪는 경우가 많이 있습니다.


Cell 세로 높이에 대해서 알아보겠습니다.


가로 크기를 자동으로 해놓으면 내용에 따라 가로 넓이가 계속 늘어나기 때문에 세로 높이를 신경쓸 필요가 없습니다.

하지만 내용이 많은 경우 자동 줄 바꿈 옵션(셀객체.getCellStyle().setWrapText(true))을 통해 보여주어야 합니다. 


보통은 wrapText를 하면 세로 높이 역시 자동으로 조정 됩니다.

문제는 병합된 셀들의 경우 자동으로 높이가 조절되지 않습니다.


이런 경우 해당 셀의 텍스트를 분석해서 셀의 높이를 계산해 높이를 수동으로 설정하는 방법이 있습니다.

아래 예제 소스를 보시면 특이하게 java.awt.Font 를 사용하고 있습니다.

일종의 편법의 awt Font를 이용해서 세로 높이를 계산해 내는 겁니다.


참고로, 병합된 셀의 세로 높이가 자동으로 잡히지 않는 문제는 poi 의 영역이 아니라 엑셀 자체의 문제라고 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
 
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.io.IOException;
import java.io.OutputStream;
import java.text.AttributedString;
import java.util.List;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.ShapeTypes;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFSimpleShape;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;


...........................중략........................

/**
   * ROW 높이 자동 조절
   * 
   * @param rownum
   * @param cellValue
   */
  public void setAutoRowFit(int cellnum, int rownum) {
    XSSFRow row = sheet.getRow(rownum);
    XSSFCell cell = row.getCell(cellnum);
    XSSFFont cellFont = cell.getCellStyle().getFont();
    int fontStyle = java.awt.Font.PLAIN;
    if (cellFont.getBold())
      fontStyle = java.awt.Font.BOLD;
    if (cellFont.getItalic())
      fontStyle = java.awt.Font.ITALIC;
    java.awt.Font currFont = new java.awt.Font(cellFont.getFontName(), fontStyle,
        cellFont.getFontHeightInPoints());
    String cellText = cell.getStringCellValue();
    AttributedString attrStr = new AttributedString(cellText);
    attrStr.addAttribute(TextAttribute.FONT, currFont);
    // Use LineBreakMeasurer to count number of lines needed for the text
    //
    FontRenderContext frc = new FontRenderContext(nulltruetrue);
    LineBreakMeasurer measurer = new LineBreakMeasurer(attrStr.getIterator(), frc);
    int nextPos = 0;
    int lineCnt = 1;
    float columnWidthInPx = sheet.getColumnWidthInPixels(cellnum);
    while (measurer.getPosition() < cellText.length()) {
      nextPos = measurer.nextOffset(columnWidthInPx);
      lineCnt++;
      measurer.setPosition(nextPos);
    }
    System.out.println("lineCnt:" + lineCnt);
    if (lineCnt > 1) {
      row.setHeightInPoints(
          sheet.getDefaultRowHeightInPoints() * lineCnt * /* fudge factor */ 1f);
    }
  }
cs


반응형
반응형

웹 개발을 하다 보면 언제나 마주치는 것들 중에 하나가 바로 파일 다운로드 입니다.


파일을 다운로드 받기 위한 방법은 여러가지가 있습니다.


iframe을 이용한 방법, 새창을 이용한 방법, 자기 자신의 페이지에 바로 다운 받는 방법 등등 이 있습니다.



이번에 설명하려고 하는 것은 파일을 다운로드를 받는 방법과 무관하게 

다운로드 받을 파일을 생성하는 동안 로딩 표시나 프로그레스 바를 보여줄 수 있는 방법입니다.


용량이 작은 파일은 상관없지만 용량이 큰 파일은 생성하는데 시간이 오래 걸리기 때문에, 파일 다운로드 받기를 시도하고 있다는 사실을 사용자가 인지하지 못할 수 있습니다. 그렇게 되면 파일이 다운로드되지 않는다고 느껴 다른 페이지로 이동하거나 파일다운로드를 재시도하게 됩니다.


사용자 입장에서나 시스템 입장에서 모두 불편해지는 상황이 됩니다.


이런 상황을 해소하고자 하는게 이번 글의 목적 입니다.


간단하게 다운로드 할 파일을 생성하는 동안 화면에 뭔까 띄우기를 시작해 보겠습니다.


다운로드 할 파일을 생성하는 흔한 경우가 바로 엑셀 파일입니다.

엑셀 파일을 다운로드 하는 자바스크립트 코드입니다. (jquery 쿠키 플러그인을 이용하고 있습니다. https://plugins.jquery.com/cookie/)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 엑셀 다운로드 받기
function goExcelDownload() {
    $('#searchForm').submit(); // 다운로드 요청 !!
 
    fullSpinOn(); // spin 화면에 띄우기
 
 
    // 0.5 초마다 fileDownloadToken 라는 쿠키가 있는지 체크합니다.
    // 해당 쿠키가 있으면 spin을 끄고 fileDownloadToken 쿠키를 지운 후 Interval 을 종료 합니다.
    FILEDOWNLOAD_INTERVAL = setInterval(function() {
      if ($.cookie("fileDownloadToken"!= null) {
        $.cookie('fileDownloadToken'null, {
          expires : 0,
          path : location.pathname
        });
        clearInterval(FILEDOWNLOAD_INTERVAL);
        fullSpinOff();// 끄기
      }
    }, 500);
  }
cs


세상 간단합니다.

이해가 안되면 무슨 코드인가 싶겠지만 간단한 트릭정도로 생각하시면 됩니다.


1. 엑셀 다운로드를 서버에 요청한다. 

2. 바로 화면에 뭔가(로딩,프로그레스,스핀 등등)를 띄운다.

3. 서버에서 쿠키를 응답할 때까지 쭈욱 기다린다.

4. 서버에서는 파일 생성이 완료되면 다운로드 파일을 포함한 응답을 준다.

5. 응답 헤더에 쿠키가 포함되어 있어 파일다운로드가 시작되면 화면에서는 뭔가를 끈다.

6. 파일 다운로드가 시작된다. !!


JAVA 기준의 서버 쪽 소스를 보면 아래 처럼 간단하게 응답헤더에 쿠키만 넣어주면 끝입니다.


1
2
3
4
5
6
7
8
9
10
11
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
 
... 중략
 
 
// 엑셀 다운로드 요청을 처리하는 곳에서
// 응답 헤더에 fileDownloadToken 쿠키를 넣어줌.
 
Cookie cookie = new Cookie("fileDownloadToken""TRUE");
response.addCookie(cookie);
cs


대용량 파일 생성 후 다운로드 하는 서비스에는 필수 입니다.

고고~


반응형
반응형
1
2
3
4
5
    int lineCnt = 0;
    int fromIndex = -1;
    while ((fromIndex = cellText.indexOf("\n", fromIndex + 1)) >= 0) {
      lineCnt++;
    }
cs



개행문자를 예시로 썼습니다.


세상 간단합니다.

반응형
반응형

List 객체를 문자열로 붙여서 변환하고 싶을 경우,

String 객체의 join 메서드를 사용하면 됩니다.


String.join("이어줄문자열', list); 이런식으로 사용하시면 됩니다.

java 1.8 부터 생겨난 기능입니다.



String.join 메서드의 설명 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Open Declaration String java.lang.String.join(CharSequence delimiter, Iterable<extends CharSequence> elements)
 
 
Returns a new String composed of copies of the CharSequence elements joined together with a copy of the specified delimiter. 
 
For example, 
List<String> strings = new LinkedList<>();
     strings.add("Java");strings.add("is");
     strings.add("cool");
     String message = String.join(" ", strings);
     //message returned is: "Java is cool"
 
     Set<String> strings = new LinkedHashSet<>();
     strings.add("Java"); strings.add("is");
     strings.add("very"); strings.add("cool");
     String message = String.join("-", strings);
     //message returned is: "Java-is-very-cool"
Note that if an individual element is null, then "null" is added.
Parameters:
delimiter a sequence of characters that is used to separate each of the elements in the resulting String
elements an Iterable that will have its elements joined together.
Returns:
new String that is composed from the elements argument
Throws:
NullPointerException - If delimiter or elements is null
Since:
1.8
See Also:
join(CharSequence, CharSequence)
java.util.StringJoiner
cs


반응형
반응형

String.format("%d%%", 5);


==> 5%


이런식으로 %% 두번 쓰면 됩니다.

반응형

+ Recent posts