09文件上传和PDF报表入门

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】.

  1. 设计阶段(Design):所谓的报表设计就是创建一些模板,模板包含了报表的布局与设计,包括执行计算的
    复杂公式、可选的从数据源获取数据的查询语句、以及其它的一些信息。模板设计完成之后,我们将模板保
    存为JRXML文件(JR代表JasperReports),其实就是一个XML文件。

  2. 执行阶段(Execution):使用以JRXML文件编译为可执行的二进制文件(即.Jasper文件)结合数据进行执
    行,填充报表数据

  3. 输出阶段(Export):数据填充结束,可以指定输出为多种形式的报表

    生命周期:
    jrxml->Japser->jrprint->Exporter->PDF/DOC/HTML
    
    1. JRXML:报表填充模板,本质是一个XML.
    2. JasperReport已经封装了一个dtd,只要按照规定的格式写这个xml文件,那么jasperReport就可以将其解析
      最终生成报表,但是jasperReport所解析的不是我们常见的.xml文件,而是.jrxml文件,其实跟xml是一样
      的,只是后缀不一样。
    3. Jasper:由JRXML模板编译生成的二进制文件,用于代码填充数据。
      解析完成后JasperReport就开始编译.jrxml文件,将其编译成.jasper文件,因为JasperReport只可以
      对.jasper文件进行填充数据和转换,这步操作就跟我们java中将java文件编译成class文件是一样的
    4. Jrprint:当用数据填充完Jasper后生成的文件,用于输出报表。
      这一步才是JasperReport的核心所在,它会根据你在xml里面写好的查询语句来查询指定是数据库,也可以控
      制在后台编写查询语句,参数,数据库。在报表填充完后,会再生成一个.jrprint格式的文件(读取jasper文
      件进行填充,然后生成一个jrprint文件)
    5. Exporter:决定要输出的报表为何种格式,报表输出的管理类。
    6. 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();
   }
 }

09文件上传和PDF报表入门

上一篇:Webpack 基石 tapable 揭秘


下一篇:【Linux】嵌入式开发,在Linux中使用C语言对Fork函数执行子函数及父函数,命令ps 及 ls 操作