报表在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<JasperPrint> 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<String, Object>) 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();
}
}
}
- 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
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
三.单张报表生成后台代码详解
此方法使用最基本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();
}
}
}
- 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
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
五.使用PDFMergerUtility进行PDF字节流合成导出
mvn引入jar包
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-app</artifactId>
<version>1.8.13</version>
</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();
}
}
}
- 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
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
四.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<String, Object> getReportData(String format, String requestFullUri, CompanyLevyDTO dto,
Long issue, String name, String companyNumber) {
Map<String, Object> model = new HashMap<String, Object>();
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<LevyBodyDTO> list) {
Collection<Map<String, ?>> collection = new ArrayList<Map<String, ?>>();
for (int i = 0; i < list.size(); i++) {
Map<String, Object> map = new HashMap<String, Object>();
LevyBodyDTO dto = list.get(i);
map.put("insuranceCode", dto.getInsuranceCode());
...//这里面放循环的数据
collection.add(map);
}
return new JRMapCollectionDataSource(collection);
}
}
- 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
五.也可以使用直接返回前台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:
<div class="form-group" style="margin-left:90px">
<input class="btn btn-success" type="button" style="width:100px;" value="打印报表"
ng-click="report()"/>
</div>
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服务器获取方案**
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
@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());
}
}
- 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
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
}
|