报表在JavaWeb中是个非常常用的技术,本文介绍使用SpringBoot+AngularJS+Jaspersoft Studio对报表打印进行实现
一.使用Jaspersoft Studio进行报表的绘制后,存放在src/main/resources/reports文件夹下。
二.实现多张报表生成后台代码详解
此方法应用了JasperReport和JRAbstractExporter包对报表进行无脑化编译。
@RestController
@RequestMapping(LevyDetailController.BASE_URL)
public class LevyDetailController {
public static Logger LOGGER = LoggerFactory.getLogger(LevyDetailController.class);
/** 根路径 */
public final static String BASE_URL = "/reports/levy";
/** 报表打印服务接口类 */
@Resource
private LevyDetailService levyDetailService;
@SuppressWarnings("unchecked")
@RequestMapping(method = RequestMethod.GET)
public void printReport(@RequestParam("format") String format, @RequestParam("companyId") Long companyId,
@RequestParam(required = false) Long issue, @RequestParam(required = false) Long pageIndex,
HttpServletRequest request, HttpServletResponse response) {
String requestFullUri = request.getRequestURI() + "?" + request.getQueryString();
OrganizationApplyService organizationApplyService = (OrganizationApplyService) SpringContextUtils
.getApplicationContext().getBean("organizationApplyServiceImpl");
OrganizationApply company = organizationApplyService.findByOrgId(companyId);
// 获取报表数据
CompanyLevyListDTO result = levyDetailService.getLevyDetail(company, issue);
// result.setList(null);测试空报表
// 打印控制获取上下文
ApplicationContext ctx = SpringContextUtils.getApplicationContext();
org.springframework.core.io.Resource resource = null;
if (result.getList() == null) {
// 生成空白报表
resource = ctx.getResource("classpath:/reports/rptEmpty.jrxml");
} else {
resource = ctx.getResource("classpath:/reports/rptLevyDetailx.jrxml");
}
InputStream inputStream;
try {
// 译为输入流
inputStream = resource.getInputStream();
// 编译报表
JasperReport jasperReport = JasperCompileManager.compileReport(inputStream);
JRAbstractExporter exporter = new JRPdfExporter();
List list = new ArrayList<>();
// 多张报表打印实现
if (result.getList() != null) {
for (CompanyLevyDTO dto : result.getList()) {
// 获取报表数据map源
JasperPrint jasperprint = JasperFillManager.fillReport(jasperReport,
LevyDetaiFactorySolitary.getReportData(format, requestFullUri, dto, issue,
company.getName(), company.getCompanyNumber()),
LevyDetaiFactorySolitary.mapData(dto.getLevyBodyListDTO()));
list.add(jasperprint);
}
} else {
JasperPrint jasperprint = JasperFillManager.fillReport(jasperReport,
(Map) DefaultEmptyFactory.getReportData(format, requestFullUri),
DefaultEmptyFactory.mapData());
list.add(jasperprint);
}
// 设置前台编译格式
ServletOutputStream baos = response.getOutputStream();
exporter.setParameter(JRExporterParameter.JASPER_PRINT_LIST, list);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
exporter.setParameter(JRExporterParameter.CHARACTER_ENCODING, "UTF-8");
exporter.exportReport();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JRException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
三.单张报表生成后台代码详解
此方法使用最基本SpringBooot response传入字节数组方式生成报表,代码如下:
@RestController
@RequestMapping(LevyDetailController.BASE_URL)
public class LevyDetailController {
public static Logger LOGGER = LoggerFactory.getLogger(LevyDetailController.class);
/** 根路径 */
public final static String BASE_URL = "/reports/levy";
/** 报表打印服务接口类 */
@Resource
private LevyDetailService levyDetailService;
@Autowired
private PileStamperClient pileStamperClient;
@RequestMapping(method = RequestMethod.GET)
public void printReport(@RequestParam("format") String format, @RequestParam("companyId") Long companyId,
@RequestParam(required = false) Long issue, @RequestParam(required = false) Long pageIndex,
HttpServletRequest request, HttpServletResponse response) throws JSONException {
String requestFullUri = request.getRequestURI() + "?" + request.getQueryString();
OrganizationApplyService organizationApplyService = (OrganizationApplyService) SpringContextUtils
.getApplicationContext().getBean("organizationApplyServiceImpl");
OrganizationApply company = organizationApplyService.findByOrgId(companyId);
// 获取报表数据
CompanyLevyListDTO result = levyDetailService.getLevyDetail(company, issue);
// result.setList(null);测试空报表
// 打印控制获取上下文
ApplicationContext ctx = SpringContextUtils.getApplicationContext();
org.springframework.core.io.Resource resource = null;
if (result.getList() == null) {
// 生成空白报表
resource = ctx.getResource("classpath:/reports/rptEmpty.jrxml");
} else {
resource = ctx.getResource("classpath:/reports/rptLevyDetailx.jrxml");
}
InputStream inputStream;
try {
byte[] bytesPdf = null;
// 译为输入流
inputStream = resource.getInputStream();
// 编译报表
JasperReport jasperReport = JasperCompileManager.compileReport(inputStream);
// 单张报表打印实现
if (result.getList() != null) {
for (int t = 0; t < result.getList().size(); t++) {
CompanyLevyDTO dto = result.getList().get(t);
bytesPdf = JasperRunManager.runReportToPdf(jasperReport,
LevyDetaiFactorySolitary.getReportData(format, requestFullUri, dto, issue,
company.getName(), company.getCompanyNumber()),
LevyDetaiFactorySolitary.mapData(dto.getLevyBodyListDTO()));
}
} else {
bytesPdf = JasperRunManager.runReportToPdf(jasperReport,
DefaultEmptyFactory.getReportData(format, requestFullUri), DefaultEmptyFactory.mapData());
}
ByteArrayInputStream stream = new ByteArrayInputStream(bytesPdf);
int length = stream.available();
if (length != -1) {
byte[] buffer3 = new byte[1024];
int readCount = 0;
ServletOutputStream sos = response.getOutputStream();
while ((readCount = stream.read(buffer3)) > 0) {
sos.write(buffer3, 0, readCount);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JRException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
五.使用PDFMergerUtility进行PDF字节流合成导出
mvn引入jar包
<dependency>
<groupId>org.apache.pdfboxgroupId>
<artifactId>pdfbox-appartifactId>
<version>1.8.13version>
dependency>
@RestController
@RequestMapping(LevyDetailController.BASE_URL)
public class LevyDetailController {
public static Logger LOGGER = LoggerFactory.getLogger(LevyDetailController.class);
/** 根路径 */
public final static String BASE_URL = "/reports/levy";
/** 报表打印服务接口类 */
@Resource
private LevyDetailService levyDetailService;
@RequestMapping(method = RequestMethod.GET)
public void printReport(@RequestParam("format") String format, @RequestParam("companyId") Long companyId,
@RequestParam(required = false) Long issue, @RequestParam(required = false) Long pageIndex,
HttpServletRequest request, HttpServletResponse response) {
String requestFullUri = request.getRequestURI() + "?" + request.getQueryString();
OrganizationApplyService organizationApplyService = (OrganizationApplyService) SpringContextUtils
.getApplicationContext().getBean("organizationApplyServiceImpl");
OrganizationApply company = organizationApplyService.findByOrgId(companyId);
// 获取报表数据
CompanyLevyListDTO result = levyDetailService.getLevyDetail(company, issue);
// result.setList(null);测试空报表
// 打印控制获取上下文
ApplicationContext ctx = SpringContextUtils.getApplicationContext();
org.springframework.core.io.Resource resource = null;
if (result.getList() == null) {
// 生成空白报表
resource = ctx.getResource("classpath:/reports/rptEmpty.jrxml");
} else {
resource = ctx.getResource("classpath:/reports/rptLevyDetailx.jrxml");
}
InputStream inputStream;
try {
byte[] bytesPdf = null;
// 译为输入流
inputStream = resource.getInputStream();
// 编译报表
JasperReport jasperReport = JasperCompileManager.compileReport(inputStream);
// 多张报表打印实现
if (result.getList() != null) {
List<byte[]> list = new ArrayList<byte[]>();
for (CompanyLevyDTO dto : result.getList()) {
// 获取报表数据map源
bytesPdf = JasperRunManager.runReportToPdf(jasperReport,
LevyDetaiFactorySolitary.getReportData(format, requestFullUri, dto, issue,
company.getName(), company.getCompanyNumber()),
LevyDetaiFactorySolitary.mapData(dto.getLevyBodyListDTO()));
list.add(bytesPdf);
}
if (result.getList().size() > 1) {
// 多张表单拼接实现
PDFMergerUtility mergePdf = new PDFMergerUtility();
for (int i = 0; i < list.size(); i++) {
byte[] content = list.get(i);
ByteArrayInputStream in = new ByteArrayInputStream(content);
mergePdf.addSource(in);
}
// 多个pdf流合成处理
mergePdf.setDestinationStream(new ByteArrayOutputStream());
try {
mergePdf.mergeDocuments();
} catch (COSVisitorException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 获取合成后的OutputStream流
ByteArrayOutputStream outputStream = (ByteArrayOutputStream) mergePdf.getDestinationStream();
bytesPdf = outputStream.toByteArray();
}
} else {
bytesPdf = JasperRunManager.runReportToPdf(jasperReport,
DefaultEmptyFactory.getReportData(format, requestFullUri), DefaultEmptyFactory.mapData());
}
ByteArrayInputStream stream = new ByteArrayInputStream(bytesPdf);
// 返回从输入流中读取的字节数,若无字节 返回0
int length = stream.available();
if (length != -1) {
byte[] buffer3 = new byte[1024];
int readCount = 0;
ServletOutputStream sos = response.getOutputStream();
while ((readCount = stream.read(buffer3)) > 0) {
// 从buffer3中读取0-readCount的数据
sos.write(buffer3, 0, readCount);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JRException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
四.LevyDetaiFactorySolitary实现,代码如下
public class LevyDetaiFactorySolitary {
private LevyDetaiFactorySolitary() {
}
public static final String LEVY_REPORT_NAME = "rptLevyDetailx";
public static final String LEVY_FULL_URI = "request_full_uri";
public static String getReportName() {
return LEVY_REPORT_NAME;
}
/**
* 获取报表数据
*
* @param format
* @param requestFullUri
* @param dto
* @return
*/
public static Map getReportData(String format, String requestFullUri, CompanyLevyDTO dto,
Long issue, String name, String companyNumber) {
Map model = new HashMap();
model.put(JasperReportsMultiFormatView.DEFAULT_FORMAT_KEY, format);
model.put(LEVY_FULL_URI, requestFullUri);
model.put("name", "名称:" + name);
...//这里面放不是循环的参数
return model;
}
/**
* 获取报表DataSource数据
*
* @param format
* @param requestFullUri
* @param dto
* @return
*/
public static JRMapCollectionDataSource mapData(List list) {
Collection
五.也可以使用直接返回前台ModelAndView的形式进行实现
代码入下:
ModelAndView module = null;
if (listDimissionDTO.size() == 0) {
// 生成报表
module = new ModelAndView(DefaultEmptyFactory.getReportName(),
DefaultEmptyFactory.getReportData(format, requestFullUri));
} else {
// 生成报表
module = new ModelAndView(LevyDetaiFactorySolitary .getReportName(),
LevyDetaiFactorySolitary .getReportData(reportPageIndex, format, requestFullUri, listDimissionDTO, issue,
company.getName(), company.getCompanyNumber(), reviewedStatus, submitType));
}
五.前端angularJS显示方案
目前市面上多种浏览器对报表的支持程度不一,最优解决方案如下:
ie十以上支持下载,谷歌火狐浏览器可在线预览
html:
class="form-group" style="margin-left:90px">
class="btn btn-success" type="button" style="width:100px;" value="打印报表"
ng-click="report()"/>
js
$scope.report = function () {
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
$http({
url: $scope.URL + '?format=pdf&companyId=' + $scope.companyId + '&issue=' + $scope.issue,
method: 'GET',
responseType: 'arraybuffer'
}).success(function (response) {
var file = new Blob([response], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
window.navigator.msSaveOrOpenBlob(file);
});
} else {
var reportOption = {};
reportOption.pdfName = $scope.title;
reportOption.method = 'GET';
reportOption.url = $scope.URL + '?format=pdf&companyId=' + $scope.companyId + '&issue=' + $scope.issue;
reportOption.headers = {Accept: '*/*'};
reportHelper.showReport(reportOption);
}
};
六.从ftp服务器获取方案
@RestController
@RequestMapping(ApplyPrintController.BASE_URL)
public class ApplyPrintController {
/** 根路径 */
public final static String BASE_URL = "/reports/applyReport";
@RequestMapping(method = RequestMethod.GET)
public void printReport(@RequestParam("format") String format,
@RequestParam(value = "companyId", required = true) String companyId,
@RequestParam(value = "issue", required = false) Long issue, @RequestParam("buzzType") String buzzType,
@RequestParam("submitType") String submitType,
@RequestParam(value = "reviewedStatus", required = false) String reviewedStatus,
@RequestParam(required = false) Long pageIndex, HttpServletRequest request, HttpServletResponse response) {
String host = "10.154.227.46";// 设置服务器地址
int port = 21; // 设置服务器端口号
String username = "ftp2012";// 设置服务器访问用户
String password = "dfca@123";// 设置服务器密码
String remoteDir = "/ftpuser"; // 切换报表所在路径
/** 文件路径通配符 */
String regEx = "A20170020062.pdf";
String encoding = System.getProperty("file.encoding"); // 设置编码
FTPClient client = new FTPClient();
// 设置超时时间
client.setConnectTimeout(30000);
try {
// 1、连接服务器
if (!client.isConnected()) {
// 如果采用默认端口,可以使用client.connect(host)的方式直接连接FTP服务器
client.connect(host, port);
// 登录
client.login(username, password);
// 获取ftp登录应答码
int reply = client.getReplyCode();
// 验证是否登陆成功
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
throw new RuntimeException("未连接到FTP,用户名或密码错误。");
} else {
System.out.println("FTP连接成功。IP:" + host + "PORT:" + port);
}
// 2、设置连接属性
client.setControlEncoding(encoding);
// 设置以二进制方式传输
client.setFileType(FTPClient.BINARY_FILE_TYPE);
client.enterLocalPassiveMode();
}
} catch (SocketException e) {
try {
client.disconnect();
} catch (IOException e1) {
}
throw new RuntimeException("连接FTP服务器失败" + e.getMessage());
} catch (IOException e) {
}
InputStream stream = null;
try {
// 1、设置远程FTP目录
client.changeWorkingDirectory(remoteDir);
System.out.println("切换至工作目录【" + remoteDir + "】");
stream = client.retrieveFileStream(regEx);
int length = stream.available();
if (length != -1) {
byte[] buffer3 = new byte[1024];
int readCount = 0;
ServletOutputStream sos = response.getOutputStream();
while ((readCount = stream.read(buffer3)) > 0) {
sos.write(buffer3, 0, readCount);
}
}
} catch (IOException e) {
throw new RuntimeException("读取文件失败" + e.getMessage());
}
}
}
六.实现导出Excel格式
“““
OrganizationApply company = organizationApplyService.findByOrgId(companyId);
List dtolist = new ArrayList<>();
QueryCompanyPaymentInfoDTO qcpdto = new QueryCompanyPaymentInfoDTO(companyId, issueBegin, issueEnd);
CompanyPaymentInfo companyPaymentInfo = companyPaymentReportPrintService.queryCompanyPaymentInfo(qcpdto);
if (companyPaymentInfo.getCompanyPaymentBasicDTO() == null
|| companyPaymentInfo.getCompanyPaymentDTOList().size() == 0) {
resource = ctx.getResource("classpath:/reports/rptEmpty.jrxml");
} else {
dtolist = companyPaymentInfo.getCompanyPaymentDTOList();
resource = ctx.getResource("classpath:/reports/rptCompanyPayment.jrxml");
}
// 打印报表
InputStream inputStream;
try {
// 译为输入流
inputStream = resource.getInputStream();
// 编译报表
JasperReport jasperReport = JasperCompileManager.compileReport(inputStream);
Map map = new HashMap<>();
// 报表打印实现
if (companyPaymentInfo.getCompanyPaymentBasicDTO() == null
|| companyPaymentInfo.getCompanyPaymentDTOList().size() == 0) {
// 空报表
map = DefaultEmptyFactory.getReportData(format, requestFullUri);
} else {
map = CompanyPaymentPrintFactory.getReportData(format, requestFullUri, dtolist, company,
companyPaymentInfo, issueBegin, issueEnd);
}
JasperPrint print = JasperFillManager.fillReport(jasperReport, map,CompanyPaymentPrintFactory.mapData(dtolist));
JRAbstractExporter exporter = new JRXlsExporter();
response.reset();
response.setContentType("application/vnd.ms-execl");
response.setHeader("Content-Disposition",
"attachment;filename=" + new String("单位缴费清单".getBytes("gbk"), "iso8859-1") + ".xls");
JasperReportsUtils.render(exporter, print, response.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JRException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
“`