반응형
환경부터 소개하겠다 간단하게.
Spring Boot - InteliJ 툴
빌드 Gradle
Swagger 테스트
ms-sql
1. 우선은 build.gradle 에 들어가서 dependecies에 해당 외부 라이브러리를 추가한다 .
// 나머지 라이브러리는 word, excel ,pdf 를 다운로드 받기 위해 선언.
implementation 'net.sf.jasperreports:jasperreports:6.21.5' // jasper 버전
implementation 'com.github.librepdf:openpdf:1.3.30'
implementation 'org.apache.poi:poi-ooxml:5.2.3'
implementation 'org.apache.poi:poi-ooxml-schemas:4.1.2'
2. 이후 clean -> build 순서대로 클릭 . (gradle 환경설정이 되어있는 프로젝트라 가정)

3.resource Pakage에 jrxml 폴더 및 파일 생성 기존 mapper에 생성말고 따로 패키지를 만들자.report-> ㅁㅁ -> .jrxml 파일 생성

4. Jasper Report 에서 만든 파일 -> source로 이동 후 복사 -> 이후 jxrml파일에 붙여넣기 -> 이떄 Value값이 DTO에 값이 된다. 그러므로 카멜케이스형식으로 value값을 변경해줘야한다 !!!


5. Controller 생성
package com.test.gw.controller.reports;
import com.test.gw.model.rnd.RndArticleReq;
import com.test.gw.service.reports.ReportsService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/in/reports")
public class ReportsController {
private final ReportsService reportsService;
@PostMapping(value = "/rnd/article/export")
public ResponseEntity<byte[]> exportRndArticleReport(@RequestBody RndArticleReq req) {
return reportsService.exportReport("rndArticleReportGenerator", req.getDocType(), req);
}
}
6. Service 생성
package com.test.gw.service.reports;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class ReportsService {
private final Map<String, ReportGenerator> generatorMap;
/**
* ReportGenerator 구현체를 수집하여 Map에 저장
*/
public ReportsService(List<ReportGenerator> generators) {
this.generatorMap = new HashMap<>();
for (ReportGenerator generator : generators) {
String beanName = generator.getClass().getAnnotation(Service.class).value();
if (beanName == null || beanName.isBlank()) {
throw new IllegalArgumentException("ReportGenerator 구현체에는 @Service(\"beanName\")로 식별자 지정이 필요합니다.");
}
generatorMap.put(beanName, generator);
}
}
/**
* 공통 리포트 export 처리
* @param reportType: generator의 bean name
* @param docType: "pdf" 또는 "excel"
* @param dto: 리포트 생성에 필요한 요청 객체
*/
public ResponseEntity<byte[]> exportReport(String reportType, String docType, Object dto) {
ReportGenerator generator = generatorMap.get(reportType);
if (generator == null) throw new IllegalArgumentException("등록되지 않은 reportType: " + reportType);
byte[] fileBytes = generator.generate(docType, dto);
String extension;
MediaType mediaType;
if ("excel".equalsIgnoreCase(docType)) {
extension = "xls"; // 기존 유지
mediaType = MediaType.APPLICATION_OCTET_STREAM;
} else if ("word".equalsIgnoreCase(docType)) {
extension = "docx";
mediaType = MediaType.parseMediaType(
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
);
} else {
extension = "pdf";
mediaType = MediaType.APPLICATION_PDF;
}
String fileName = reportType + "_report." + extension;
return ResponseEntity.ok()
.contentType(mediaType)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.body(fileBytes);
}
/**
* Resource 형태로 반환할 경우 (프론트에서 Blob 처리 없이 iframe/open 등으로 사용 시)
*/
public ResponseEntity<Resource> exportReportAsResource(String reportType, String docType, Object dto) {
ReportGenerator generator = generatorMap.get(reportType);
if (generator == null) throw new IllegalArgumentException("등록되지 않은 reportType: " + reportType);
byte[] fileBytes = generator.generate(docType, dto);
String extension;
MediaType mediaType;
if ("excel".equalsIgnoreCase(docType)) {
extension = "xls";
mediaType = MediaType.APPLICATION_OCTET_STREAM;
} else if ("word".equalsIgnoreCase(docType)) {
extension = "docx";
mediaType = MediaType.parseMediaType(
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
);
} else {
extension = "pdf";
mediaType = MediaType.APPLICATION_PDF;
}
String fileName = reportType + "_report." + extension;
return ResponseEntity.ok()
.contentType(mediaType)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.body(new ByteArrayResource(fileBytes));
}
}
7. 6번에서 호출한 service 즉 공통함수를 만들자.
package com.test.gw.service.reports;
// interface 생성
public interface ReportGenerator {
byte[] generate(String docType, Object dto);
}
8.interface와 연결해주는 객체 생성
package com.test.gw.service.reports;
import com.test.gw.model.rnd.RndArticleAllListRes;
import com.test.gw.model.rnd.RndArticleReq;
import com.test.gw.model.rnd.RndArticleRes;
import com.test.gw.service.rnd.RndService;
import lombok.RequiredArgsConstructor;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.ooxml.JRDocxExporter;
import net.sf.jasperreports.export.SimpleDocxReportConfiguration;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
import net.sf.jasperreports.export.SimpleXlsReportConfiguration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service("rndArticleReportGenerator")
@RequiredArgsConstructor
public class RndArticleReportGenerator implements ReportGenerator {
private final RndService rndService;
@Override
public byte[] generate(String docType, Object dto) {
try {
RndArticleReq req = (RndArticleReq) dto;
RndArticleAllListRes result = rndService.getRndArticleAllList(req);
List<RndArticleRes> articleList = result.getRndArticleList();
// resource 경로를 정확히 입력
InputStream jrxmlInput = new ClassPathResource("com/test/gw/reports/rnd/reportRnd.jrxml").getInputStream();
JasperReport jasperReport = JasperCompileManager.compileReport(jrxmlInput);
Map<String, Object> parameters = new HashMap<>();
parameters.put("reportTitle", "기본 정보");
JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(articleList);
JasperPrint print = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
if ("excel".equalsIgnoreCase(docType)) {
return exportToExcel(print);
} else if ("word".equalsIgnoreCase(docType)) {
return exportToDocx(print);
} else {
return JasperExportManager.exportReportToPdf(print);
}
} catch (Exception e) {
throw new RuntimeException("RndArticle 리포트 생성 중 오류 발생", e);
}
}
private byte[] exportToDocx(JasperPrint print) throws JRException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
JRDocxExporter exporter = new JRDocxExporter();
exporter.setExporterInput(new SimpleExporterInput(print));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(out));
SimpleDocxReportConfiguration config = new SimpleDocxReportConfiguration();
// 필요 시 옵션들 (선택)
// config.setFlexibleRowHeight(true);
// config.setFramesAsNestedTables(true);
exporter.setConfiguration(config);
exporter.exportReport();
return out.toByteArray();
}
/**
* JasperPrint → Excel (.xls) 변환
*/
private byte[] exportToExcel(JasperPrint print) throws JRException {
ByteArrayOutputStream xlsOutput = new ByteArrayOutputStream();
JRXlsExporter exporter = new JRXlsExporter();
exporter.setExporterInput(new SimpleExporterInput(print));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(xlsOutput));
SimpleXlsReportConfiguration config = new SimpleXlsReportConfiguration();
config.setOnePagePerSheet(false);
config.setDetectCellType(true);
config.setWhitePageBackground(false);
config.setRemoveEmptySpaceBetweenRows(true);
exporter.setConfiguration(config);
exporter.exportReport();
return xlsOutput.toByteArray();
}
}
9. Request와 Response DTO는 각자 DB에 맞춰 생성해주자 . (테스트 결과) 테스트는 swagger

jrxml파일을 백엔드 서버와 연결을 해봤다 . spring boot 에 inteliJ툴을 사용하였고 빌드는 gradle 그리고 테스트는 swagger로 진행하였다.
2025.08.11 - [Report] - [Jaspersoft Studio] jxrml 파일 생성 및 DB SELECT(4)
[Jaspersoft Studio] jxrml 파일 생성 및 DB SELECT(4)
앞에서 연결했던 DB에 대해서 값이 정상적으로 jxrml로 호출이 되는지 알아보려고 한다 . 1. project 우클릭 -. new -> jasper Report 클릭2. Blank A4 클릭 후 Next -> File Name 작성 후 Next .jxrml은 지우면안됀다 ->
ycds.tistory.com
2025.08.06 - [Report] - [Jaspersoft Studio] Data Adapters DBMS 연결 ClassNotFoundException 해결 (3)
[Jaspersoft Studio] Data Adapters DBMS 연결 ClassNotFoundException 해결 (3)
DBMS에 연결을 해보자 . MSSQL을 사용중이다. 1. Data Adapters 우클릭 -> Create Data Adapter 클릭 2. Database JDBC Connection 클릭 3.JDBC Driver 클릭 후 사용하고 있는 DB Driver 클릭 4. 접속 정보 확인- JDBC Driver(어떤 DB
ycds.tistory.com
반응형
'Report' 카테고리의 다른 글
| [Jaspersoft Studio] JAVA 연동 QR CODE 출력 안됌 해결 - (7) (0) | 2025.10.21 |
|---|---|
| [Jaspersoft Studio] Jasper Report - React 연동 (6) (1) | 2025.08.25 |
| [Jaspersoft Studio] jxrml 파일 생성 및 DB SELECT(4) (3) | 2025.08.11 |
| [Jaspersoft Studio] Data Adapters DBMS 연결 ClassNotFoundException 해결 (3) (4) | 2025.08.06 |
| [Jaspersoft Studio] Jasper Project 및 Jasper Report 생성 (2) (2) | 2025.08.06 |