2. classpath 사용
이전 연습 프로젝트 만들 때 했던 방법으로 해보니 이번엔 계속 에러가 난다 ..
| java.io.IOException: The byte array is not a recognized imageformat. |
@Controller
@RequestMapping("/report")
public class ReportController {
private String signImg = "/image/signImg.png"; // 대표자 서명 이미지.
@PostMapping("/reportPDF.do")
public ResponseEntity<byte[]> reportPDF(HttpServletRequest request) throws Exception {
Map<String, Object> param = new HashMap<String, Object>();
Integer userSeq = Integer.parseInt(String.valueOf(SessionManager.get(SessionKeys.session_user_seq)));
String baseUrl = request.getScheme() + "://" +
request.getServerName() + ":" +
request.getServerPort() +
request.getContextPath();
String signImgUrl = baseUrl + signImg;
...
param.put("signImg", signImgUrl);
...
return ReportUtils.exportPDF(print, "order_list_");
}
http://localhost:포트번호/OrderManager/image/signImg.png
signImgUrl 로 생성되는 위 경로로 접속하면 이미지는 뜬다.
그러니 URL 이 문제는 아니라는 이야기고, 결국 jasper 가 받을 때 뭔가 문제가 있다는 뜻..



| new java.io.File($P{signImg}).toURI().toURL() |
image 요소의 Expression 에 이렇게 적어주고
당연히 파라미터 signImg 도 String 으로 추가해주고

String signImgPath = ResourceUtils.getFile("classpath:static/image/signImg.png").getAbsolutePath();

도장 이미지가 잘 뜬다.

후후. 이전 코드로 똑같이 했을 때 왜 안되는지 찾았다.
바로바로
Interceptor 때문 !
: Spring Interceptor 설정에서 excludePathPatterns 에 이미지 경로를 추가하는 것은
Interceptor 가 이미지 리소스에 대 한 요청을 가로채지 않도록 하는 것이다.
| - Interceptor의 역할 -> Spring MVC의 Interceptor는 Controller의 메서드를 호출하기 전/후에 로직을 수행할 수 있도록 요청을 가로채는 역할. 주로 인증/권한 확인, 로깅, 세션 관리 등의 공통적인 처리를 위해 사용됨 - addPathPatterns("/**/*.*", "/**/*") -> 이 설정은 모든 URL 요청(.do나 리소스 파일, 일반 경로 포함)에 대해 Interceptor를 적용하겠다는 의미. |
나는 signImgUrl 이라는 변수에 URL 을 담아 사용하는 건데,
Interceptor의 addPathPatterns 가 모든 경로 ("/**/*.*")를 포함하기 때문에
이미지 요청도 Interceptor 를 거치게 된다.
이러면 PDF 도구는 이미지 요청할 때 session 정보가 없기 때문에 제대로 데이터를 가져오지 못한다.
그래서 excludepathPatterns 에 "/image/**" 를 추가해서 Interceptor 가 가로채지 않고 통과하도록 만든다.
이러면 정적 리소스 핸들러가 이미지 파일을 즉시 반환한다.
package dev.kloz.weborder.common.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebCustomConfig implements WebMvcConfigurer {
@Autowired
CommonInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(new DeviceResolverHandlerInterceptor());
registry.addInterceptor(interceptor)
.addPathPatterns("/**/*.*", "/**/*")
.excludePathPatterns("/login/**/*.*", "/common/codeHelp/getLanguageList.do", "/assets/*.*", "/error", "/dev/*.*",
"/common/doFileDownload/**/*","/image/**");
// .excludePathPatterns("/buySCM/notice/**/*.*");
}
}
"/image/**" 로 내가 이미지 저장해둔 경로를 포함시켜주면~ 끝.

public class ReportController {
private String signImg = "/image/signImg.png";
@PostMapping("/reportPDF.do")
public ResponseEntity<byte[]> reportPDF(HttpServletRequest request) throws Exception {
Map<String, Object> param = new HashMap<String, Object>();
Integer userSeq = Integer.parseInt(String.valueOf(SessionManager.get(SessionKeys.session_user_seq)));
String baseUrl = request.getScheme() + "://" +
request.getServerName() + ":" +
request.getServerPort() +
request.getContextPath();
String signImgUrl = baseUrl + signImg;
...
param.put("signImg", signImgUrl);
...
3. 입사 초반 이것 저것 시도한 기록들 .
.jrxml
<parameter name="klozImg" class="java.lang.String"/>
public class ReportController {
private ApplicationContext applicationContext;
private String klozImg = "https://res.cloudinary.com/dlujvuy6p/image/upload/kloz_giefku.png";
@GetMapping("/reportPDF.do")
public ResponseEntity<byte[]> reportPDF(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception{
Map<String, Object> param = new HashMap<>();
String loginUserId = (String) session.getAttribute("userId");
// if (loginUserId == null || loginUserId.isEmpty()) {
// loginUserId = "UNKNOWN_USER"; // 로그인 정보가 없을 경우 기본값 설정
// log.warn("Session userId not found. Using default: {}", loginUserId);
// } else {
// log.info("Logged in user ID from session: {}", loginUserId);
// }
param.put("loginUserId", loginUserId);
param.put("klozImg", klozImg);
String mstReportUri = String.valueOf(
ResourceUtils.getFile("classpath:templates/report/assetsList/assets_list.jrxml"));
log.debug("mstReportUri ====>>>> {}", mstReportUri);
DataSource ds = (DataSource)ApplicationContextProvider.getApplicationContext().getBean("dataSource");
Connection con = ds.getConnection();
JasperReport report = JasperCompileManager.compileReport(mstReportUri);
JasperPrint print = JasperFillManager.fillReport(report, param, con);
ResponseEntity<byte[]> responseEntity = exportPDF(print, "assets_list_");
con.close();
return responseEntity;
}
@GetMapping("/reportExcel.do")
public void reportExcel(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception {
// param : 검색 조건 등 넘기는 용도. JASPER에 $P{}없으면 무시됨
Map<String, Object> param = new HashMap<>();
String loginUserId = (String) session.getAttribute("userId");
// if (loginUserId == null || loginUserId.isEmpty()) {
// loginUserId = "UNKNOWN_USER"; // 로그인 정보가 없을 경우 기본값 설정
// log.warn("Session userId not found. Using default: {}", loginUserId);
// } else {
// log.info("Logged in user ID from session: {}", loginUserId);
// }
param.put("loginUserId", loginUserId);
param.put("klozImg", klozImg);
String mstReportUri = String.valueOf(
ResourceUtils.getFile("classpath:templates/report/assetsList/assets_list.jrxml"));
log.debug("mstReportUri ====>>>> {}", mstReportUri);
DataSource ds = (DataSource)ApplicationContextProvider.getApplicationContext().getBean("dataSource");
Connection con = ds.getConnection();
JasperReport report = JasperCompileManager.compileReport(mstReportUri);
JasperPrint print = JasperFillManager.fillReport(report, param, con);
exportExcel(print, "assets_list_", response);
con.close();
}
서버 꺼졌을 때도 접근, 다른 사람도 접근 가능하게 하려고 네트리파이랑 클라우디너리 계정도 만들고 별 짓을 다 했지만
(이걸 url 파라미터로 넘기면 됨)
결국 내가 자리에 없을 때 이미지 파일 수정을 못한다는 단점.
그래서 다시 GPT괴롭혔더니~
동적 URL 생성 방법이 있다.
이건 프로젝트 내 경로를 참조해서 접근할 수 있기 때문에 다른 개발자도 접근 가능하고
내 서버, 내 컴퓨터에 저장한 게 아니니까 다른 브라우저에서도 접근 가능하다.
String baseUrl = request.getScheme() + "://" +
request.getServerName() + ":" +
request.getServerPort();
String klozImgUrl = baseUrl + "/images/kloz.png";
param.put("klozImg", klozImgUrl);
이렇게 넘기면 된다. Scheme..ServerName.. 전부 Boot 가 제공하는 자동 매핑 기능이라고 한다.
.jrxml 에서는 이렇게 받는다.
<parameter name="klozImg" class="java.lang.String"/>
<element kind="image" uuid="4861f6f2-a861-4fef-8118-f91279d7a84f" x="0" y="0" width="140" height="50">
<expression><![CDATA[new java.net.URL($P{klozImg})]]></expression>
</element>

이렇게하면 끝.
아래는 gpt설명..
뭔소린지 몰라서 나중에 천천히 읽어보기
Spring Boot가 resources/static/ 폴더의 내용을 자동으로 HTTP 경로에 매핑해주는 건,
Spring Boot 자체의 기본 정적 자원 매핑 규칙 때문입니다.
이건 공식 문서에도 명시되어 있는 Spring Boot의 기본 동작이에요.
✅ Spring Boot의 정적 리소스 매핑 규칙
다음 경로에 파일이 있으면 자동으로 서빙됩니다:
폴더 위치 HTTP 경로
classpath:/static/ / 하위 경로 (예: /images/kloz.png)
classpath:/public/ / 하위 경로
classpath:/resources/ / 하위 경로
classpath:/META-INF/resources/ / 하위 경로
이 규칙에 따라
src/main/resources/static/images/kloz.png 라는 파일은
Spring Boot가 실행되면 자동으로:
bash
복사
편집
http://localhost:8080/images/kloz.png
이렇게 서빙됩니다.
📚 공식 문서 근거
Spring Boot 2.x~3.x 기준 문서:
🔗 Spring Boot Reference: Static Content
By default, Spring Boot serves static content from a number of locations:
/static, /public, /resources, or /META-INF/resources.
💡 직접 실험해보는 방법
src/main/resources/static/images/kloz.png 파일 넣기
Spring Boot 서버 실행
브라우저에서:
bash
복사
편집
http://localhost:8080/images/kloz.png
→ 이미지가 바로 보이면 성공!
✅ 추가 팁
만약 경로를 커스터마이징 하고 싶다면
application.properties에서 다음처럼 경로를 지정할 수도 있어요:
properties
복사
편집
spring.web.resources.static-locations=classpath:/static/
하지만 별도로 설정하지 않으면, 기본 경로는 /static/ 입니다.
✅ 정리
Spring Boot는 resources/static/ 아래의 파일을 자동으로 URL로 노출하고,
그 경로는 http://<host>:<port>/<static 하위 경로> 로 자동 매핑됩니다.
이건 Spring Boot의 기본 기능이라 별도 코드나 설정 없이도 동작합니다.
궁금하시면 예제 프로젝트도 바로 만들어 드릴 수 있어요.



report:
kloz:
image-url: https://res.cloudinary.com/dlujvuy6p/image/upload/kloz_giefku.png
import org.springframework.beans.factory.annotation.Value;
// ... 다른 import 문
@Controller
@RequiredArgsConstructor
@RequestMapping(value = "/report", method = RequestMethod.GET)
@Slf4j
public class ReportController {
@Value("${report.kloz.image-url}") // 설정 파일에서 값을 주입받음
private String klozImg;
// ... 나머지 컨트롤러 코드
}
'웹 개발 > [KLOZ] 웹 프로젝트' 카테고리의 다른 글
| [LottoInsight] result (당첨 결과) 정적 데이터를 DB에서 받아 넣기로 변경 (0) | 2025.07.23 |
|---|---|
| [KLOZ] getUserId.do쓰지않고 session 과 thymeleaf 이용해서 사용자 정보 출력 (0) | 2025.06.26 |
| [KLOZ] 파비콘 생성 추가 (0) | 2025.06.13 |
| [KLOZ] 한 행 입력~ 여러 행 입력~ 할 때 Dto와 Controller (0) | 2025.06.04 |
| [KLOZ] map -> builder Pattern (0) | 2025.06.04 |