09文件上传和PDF报表入门
1.图片上传
1.1 DataURL概述
所谓DataURL是指"data"类型的Url格式,是在RFC2397中提出的,目的是对于一些“小”的数据,可以在网页中直接
嵌入,而不是从外部文件载入。
1.2 Data URL入门
完整的DataURL语法:DataURL= data:mediatype;base64,<Base64编码的数据>。
**mediatype****:表述传递的数据的MIME类型(text/html,image/png,image/jpg)
data:,<文本数据>
data:text/plain,<文本数据>
data:text/html,<html代码>
data:text/html;base64,<base64编码的html代码>
data:text/css,<css代码>
data:text/css;base64,<base64编码的css代码>
data:text/javascript,<javascript代码>
data:text/javascript;base64,<base64编码的javascript代码>
data:image/gif;base64,base64编码的gif图片数据
data:image/png;base64,base64编码的png图片数据
data:image/jpeg;base64,base64编码的jpeg图片数据
data:image/x-icon;base64,base64编码的icon图片数据
1.3 Data URL实现用户头像上传
修改用户实体类,用户数据库表添加用户头像字段
使用基于Data URL的方式实现用户上传,实质是将前端上传的文件以Base64进行编码并且保存到数据库中。
用户controller中添加用户上传方法
用户service中添加上传文件处理的方法
在service中需要对文件进行base64编码,并且保存到数据库中
userController
@RequestMapping(value = "/user/upload/{id}",method = RequestMethod.GET)
public Result upload(@PathVariable String id,
@RequestParam(name = "file") MultipartFile file) throws IOException {
String image = userService.uploadImage(id,file);
return new Result(ResultCode.SUCCESS,image);
}
userService
public String uploadImage(String id, MultipartFile file) throws IOException {
//findById
User user = userDao.findById(id).get();
//对图片byte数组进行base64对文件编码
//import com.sun.org.apache.xml.internal.security.utils.Base64
String fileBytes = Base64.encode(file.getBytes());
//拼接DataURL地址
String dataURL = new String("data:image/jpg;base64," + fileBytes);
//更新用户头像地址
user.setStaffPhoto(dataURL);
//保存图片信息
userDao.save(user);
return dataURL;
}
用户头像回显
将头像实体字符串加入,userResult
/**
* 用户头像
*/
private String staffPhoto;
2 七牛云存储
1入门案例
maven
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>[7.4.0, 7.4.99]</version>
</dependency>
1.1文件上传
//构造一个带指定 Region 对象的配置类
//指定上传服务器地址
Configuration cfg = new Configuration(Region.region0());
//...其他参数参考类注释
//上传管理器
UploadManager uploadManager = new UploadManager(cfg);
//...生成上传凭证,然后准备上传
String accessKey = "your access key";
String secretKey = "your secret key";
String bucket = "your bucket name";
//如果是Windows情况下,格式是 D:\\qiniu\\test.png
String localFilePath = "/home/qiniu/test.png";
//默认不指定key的情况下,以文件内容的hash值作为文件名
//存入到存储空间的文件名
String key = "test";
Auth auth = Auth.create(accessKey, secretKey);
String upToken = auth.uploadToken(bucket,key);
try {
//上传
Response response = uploadManager.put(localFilePath, key, upToken);
//解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
System.out.println(putRet.key);
System.out.println(putRet.hash);
} catch (QiniuException ex) {
Response r = ex.response;
System.err.println(r.toString());
try {
System.err.println(r.bodyString());
} catch (QiniuException ex2) {
//ignore
}
}
1.2断点续传
//构造一个带指定 Region 对象的配置类
Configuration cfg = new Configuration(Region.region0());
//...其他参数参考类注释
//...生成上传凭证,然后准备上传
String accessKey = "your access key";
String secretKey = "your secret key";
String bucket = "your bucket name";
//如果是Windows情况下,格式是 D:\\qiniu\\test.png
String localFilePath = "/home/qiniu/test.mp4";
//默认不指定key的情况下,以文件内容的hash值作为文件名
String key = “test”;
Auth auth = Auth.create(accessKey, secretKey);
****
//指定覆盖目录
String upToken = auth.uploadToken(bucket,test);
****
String localTempDir = Paths.get(System.getenv("java.io.tmpdir"), bucket).toString();
try {
//设置断点续传文件进度保存目录
FileRecorder fileRecorder = new FileRecorder(localTempDir);
UploadManager uploadManager = new UploadManager(cfg, fileRecorder);
try {
Response response = uploadManager.put(localFilePath, key, upToken);
//解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
System.out.println(putRet.key);
System.out.println(putRet.hash);
} catch (QiniuException ex) {
Response r = ex.response;
System.err.println(r.toString());
try {
System.err.println(r.bodyString());
} catch (QiniuException ex2) {
//ignore
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
访问图片
将图片上传到七牛云服务
1.更新用户图片信息
2.访问图片
存储空间分配的域名
上传的文件名称
跟新图片后:访问的时候,在请求连接添加上时间戳
域名/test?id=123
1.3基于七牛云实现头像上传和下载
1.3.1文件上传工具类
public class QiniuUploadUtil {
private static final String accessKey = "COuoDRVa7JLsuurzIvQSI_pEDceHDw3yGfJEmvwv";
private static final String secretKey = "3RWpTjB5Jxg3QosUFr4mxbHXJ5JR2m6AHQqYsSlr";
private static final String bucket = "test-bucket";
private static final String prix = "http://pk9vj7em6.bkt.clouddn.com/";
private UploadManager manager;
public QiniuUploadUtil() {
//初始化基本配置
Configuration cfg = new Configuration(Zone.zone0());
//创建上传管理器
manager = new UploadManager(cfg);
}
//文件名:key
文件的bytes数组
返回请求路径
//
public String upload(String imgName , byte [] bytes) {
Auth auth = Auth.create(accessKey, secretKey);
//构造覆盖上传token
String upToken = auth.uploadToken(bucket,imgName);
try {
Response response = manager.put(bytes, imgName, upToken);
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(),DefaultPutRet.class);
//返回请求地址
return prix+putRet.key+"?t="+new Date().getTime();
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
1.3.2使用七牛云实现用户头像上传
修改UserService方法
public String uploadImage(String id, MultipartFile file) throws Exception {
User user = userDao.findById(id).get();
//将图片上传到七牛云服务,获取请求路径
String key = new QiniuUploadUtil().upload(user.getId(), file.getBytes());
if(key != null) {
user.setStaffPhoto(key);
userDao.save(user);
}
return key;
3.PDF报表打印
3.1JasperReport框架的介绍
JasperReport是一个强大、灵活的报表生成工具,能够展示丰富的页面内容,并将之转换成PDF,HTML,或者XML格式。该库完全由Java写成,可以用于在各种Java应用程序,包括J2EE,Web应用程序中生成动态内容。只需要将JasperReport引入工程中即可完成PDF报表的编译、显示、输出等工作。
在开源的JAVA报表工具中,JASPER Report发展是比较好的,比一些商业的报表引擎做得还好,如支持了十字交叉报表、统计报表、图形报表,支持多种报表格式的输出,如PDF、RTF、XML、CSV、XHTML、TEXT、DOCX以及OpenOffice。
数据源支持更多,常用 JDBC SQL查询、XML文件、CSV文件 、HQL(Hibernate查询),HBase,JAVA集合
等。还允许你义自己的数据源,通过JASPER文件及数据源,JASPER就能生成最终用户想要的文档格式。
4.JaperReport的开发步骤
4.1JaperReport的生命周期
通过JaperReport生成PDF需要经过三个阶段,我们称之为JaperReport的生命周期,这三个阶段为设计【Design】,执行【Excution】,输出【Export】.
-
设计阶段(Design):所谓的报表设计就是创建一些模板,模板包含了报表的布局与设计,包括执行计算的
复杂公式、可选的从数据源获取数据的查询语句、以及其它的一些信息。模板设计完成之后,我们将模板保
存为JRXML文件(JR代表JasperReports),其实就是一个XML文件。 -
执行阶段(Execution):使用以JRXML文件编译为可执行的二进制文件(即.Jasper文件)结合数据进行执
行,填充报表数据 -
输出阶段(Export):数据填充结束,可以指定输出为多种形式的报表
生命周期: jrxml->Japser->jrprint->Exporter->PDF/DOC/HTML
- JRXML:报表填充模板,本质是一个XML.
- JasperReport已经封装了一个dtd,只要按照规定的格式写这个xml文件,那么jasperReport就可以将其解析
最终生成报表,但是jasperReport所解析的不是我们常见的.xml文件,而是.jrxml文件,其实跟xml是一样
的,只是后缀不一样。 - Jasper:由JRXML模板编译生成的二进制文件,用于代码填充数据。
解析完成后JasperReport就开始编译.jrxml文件,将其编译成.jasper文件,因为JasperReport只可以
对.jasper文件进行填充数据和转换,这步操作就跟我们java中将java文件编译成class文件是一样的 - Jrprint:当用数据填充完Jasper后生成的文件,用于输出报表。
这一步才是JasperReport的核心所在,它会根据你在xml里面写好的查询语句来查询指定是数据库,也可以控
制在后台编写查询语句,参数,数据库。在报表填充完后,会再生成一个.jrprint格式的文件(读取jasper文
件进行填充,然后生成一个jrprint文件) - Exporter:决定要输出的报表为何种格式,报表输出的管理类。
- Jasperreport可以输出多种格式的报表文件,常见的有Html,PDF,xls等
public class JrDemo {
public static void main(String[] args) {
createJasper();
}
//1.将pdf模板编译为japer文件
public static void createJasper(){
try{
String path = "E:\\BaiduNetdiskDownload\\【bxg】SaaS实战\\09-图片上传及Jasper\\01-文件上传与PDF报表入门\\资源\\资源\\生命周期测试\\test01.jrxml";
JasperCompileManager.compileReportToFile(path);
}catch(Exception e){
e.printStackTrace();
}
}
//2.将japer文件和数据进行填充,获取Jrprint
public static void createJrprint(){
try{
String path = "E:\\BaiduNetdiskDownload\\【bxg】SaaS实战\\09-图片上传及Jasper\\01-文件上传与PDF报表入门\\资源\\资源\\生命周期测试\\test01.jasper";
//通过空参数和空数据源进行填充
JasperFillManager.fillReportToFile(path,new HashMap(),new JREmptyDataSource());
}catch(Exception e){
e.printStackTrace();
}
}
//3.预览
public static void showPdf(){
try{
String path = "E:\\BaiduNetdiskDownload\\【bxg】SaaS实战\\09-图片上传及Jasper\\01-文件上传与PDF报表入门\\资源\\资源\\生命周期测试\\test01.jrprint";
JasperViewer.viewReport(path,false);
}catch(Exception e){
e.printStackTrace();
}
}
}
4.2整合JasperReport
(1)新建SpringBoot工程引入坐标
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.5.0</version>
</dependency>
<dependency>
<groupId>org.olap4j</groupId>
<artifactId>olap4j</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
(2)引入配置文件
server:
port: 8181
spring:
application:
name: jasper-demo #指定服务名
resources:
static-locations: classpath:/templates/
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/ihrm?useUnicode=true&characterEncoding=utf8
username: root
password: root
(3)创建启动类
@SpringBootApplication(scanBasePackages = "cn.itcast")
public class JasperApplication {
public static void main(String[] args) {
SpringApplication.run(JasperApplication.class, args);
}
}
(4)导入生成的.jasper文件
在resourse目录下导入test.jasper文件
(5)创建测试controller
@RestController
public class JasperController {
@GetMapping("/testJasper")
public void createHtml(HttpServletResponse response, HttpServletRequest
request)throws Exception{
//1.引入jasper文件。由JRXML模板编译生成的二进制文件,用于代码填充数据
Resource resource = new ClassPathResource("templates/test01.jasper");
//2.加载jasper文件创建inputStream
FileInputStream isRef = new FileInputStream(resource.getFile());
//获取输出流,为打印做准备
ServletOutputStream sosRef = response.getOutputStream();
try {
/**
fis:文件输出流
new hashMap:向模板中输入的参数
JasperDataOource:数据源(和数据库数据源不同),填充模板数据来源(可以是connection/javaBean/Map)
没有就填充空数据源:JreEmptyDataSource
/
//创建JasperPrint对象
JasperPrint jasperPrint = JasperFillManager.fillReport(isRef, new HashMap<>(),new JREmptyDataSource());
//3.将JasperPrint以pdf数据输出,response.getOutputStream()
JasperExportManager.exportReportToPdfStream(jasperPrint,sosRef);
} finally {
sosRef.flush();
sosRef.close();
}
}
}
4.3中文处理
通过手动指定中文字体的形式解决中文不现实
1.添加.properties
文件:
net.sf.jasperreports.extension.registry.factory.simple.font.families=net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory
net.sf.jasperreports.extension.simple.font.families.lobstertwo=stsong/fonts.xml
2.指定中文配置文件font.xml
<?xml version="1.0" encoding="UTF-8"?>
<fontFamilies>
<!--<fontFamily name="Lobster Two">-->
<!--<normal>lobstertwo/LobsterTwo-Regular.otf</normal>-->
<!--<bold>lobstertwo/LobsterTwo-Bold.otf</bold>-->
<!--<italic>lobstertwo/LobsterTwo-Italic.otf</italic>-->
<!--<boldItalic>lobstertwo/LobsterTwo-BoldItalic.otf</boldItalic>-->
<!--<pdfEncoding>Identity-H</pdfEncoding>-->
<!--<pdfEmbedded>true</pdfEmbedded>-->
<!--<!–-->
<!--<exportFonts>-->
<!--<export key="net.sf.jasperreports.html">‘Lobster Two‘, ‘Times New Roman‘,Times, serif</export>-->
<!--</exportFonts>-->
<!--–>-->
<!--</fontFamily>-->
<fontFamily name="华文宋体">
<normal>stsong/stsong.TTF</normal>
<bold>stsong/stsong.TTF</bold>
<italic>stsong/stsong.TTF</italic>
<boldItalic>stsong/stsong.TTF</boldItalic>
<pdfEncoding>Identity-H</pdfEncoding>
<pdfEmbedded>true</pdfEmbedded>
<exportFonts>
<export key="net.sf.jasperreports.html">‘华文宋体‘, Arial, Helvetica, sans-serif</export>
<export key="net.sf.jasperreports.xhtml">‘华文宋体‘, Arial, Helvetica, sans-serif</export>
</exportFonts>
<!--
<locales>
<locale>en_US</locale>
<locale>de_DE</locale>
</locales>
-->
</fontFamily>
</fontFamilies>
3.引入字体库stsong.TTF
4.用户档案PDF报表
(1) 配置坐标
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.5.0</version>
</dependency>
<dependency>
<groupId>org.olap4j</groupId>
<artifactId>olap4j</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
(2)解决乱码问题
net.sf.jasperreports.extension.registry.factory.simple.font.families=net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory
net.sf.jasperreports.extension.simple.font.families.lobstertwo=stsong/fonts.xml
4.1实现用户档案下载
/**
* 打印员工pdf报表x
*/
@RequestMapping(value="/{id}/pdf",method = RequestMethod.GET)
public void pdf(@PathVariable String id) throws IOException {
//1.引入jasper文件
//加载类资源,创建inputStream
Resource resource = new ClassPathResource("templates/profile.jasper");
FileInputStream fis = new FileInputStream(resource.getFile());
//2.构造数据
//a.用户详情数据
UserCompanyPersonal personal = userCompanyPersonalService.findById(id);
//b.用户岗位信息数据
UserCompanyJobs jobs = userCompanyJobsService.findById(id);
//c.用户头像 域名 / id
String staffPhoto = "http://pkbivgfrm.bkt.clouddn.com/"+id;
System.out.println(staffPhoto);
//3.填充pdf模板数据,并输出pdf
Map params = new HashMap();
//javaBean转map
Map<String, Object> map1 = BeanMapUtils.beanToMap(personal);
Map<String, Object> map2 = BeanMapUtils.beanToMap(jobs);
params.putAll(map1);
params.putAll(map2);
params.put("staffPhoto","staffPhoto");
//输出流,输出pdf文件
ServletOutputStream os = response.getOutputStream();
try {
JasperPrint print = JasperFillManager.fillReport(fis, params,newJREmptyDataSource());
JasperExportManager.exportReportToPdfStream(print,os);
} catch (JRException e) {
e.printStackTrace();
}finally {
os.flush();
}
}