diff --git a/JavaUtils/pom.xml b/JavaUtils/pom.xml index 9a63987..fc5a65c 100644 --- a/JavaUtils/pom.xml +++ b/JavaUtils/pom.xml @@ -130,7 +130,7 @@ com.fasterxml.jackson.core jackson-databind - 2.8.5 + 2.9.6 org.codehaus.woodstox diff --git a/pom.xml b/pom.xml index ede001b..ff06246 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,16 @@ + + com.itextpdf + itextpdf + 5.5.13 + + + com.itextpdf + itext-asian + 5.2.0 + commons-codec @@ -75,24 +85,8 @@ org.apache.poi - poi - 3.15 - - - org.apache.poi poi-ooxml - 3.15 - - - org.apache.poi - poi-ooxml-schemas - 3.15 - - - stax - stax-api - - + 3.17 @@ -130,7 +124,7 @@ com.fasterxml.jackson.core jackson-databind - 2.8.5 + 2.9.6 org.codehaus.woodstox @@ -246,6 +240,12 @@ itext 4.2.0 + + + org.apache.pdfbox + pdfbox + 2.0.11 + diff --git a/src/main/java/com/yumaolin/util/MessageAttestation/EncryptionUtils.java b/src/main/java/com/yumaolin/util/MessageAttestation/EncryptionUtils.java new file mode 100644 index 0000000..4686655 --- /dev/null +++ b/src/main/java/com/yumaolin/util/MessageAttestation/EncryptionUtils.java @@ -0,0 +1,75 @@ +package com.yumaolin.util.MessageAttestation; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.List; + + +public abstract class EncryptionUtils { + public static final String CERTIFICATE_TYPE = "X.509"; + + public static byte[] signByX509Certificate(byte[] data, X509Certificate x509Certificate, PrivateKey privateKey) + throws Exception { + Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); + + signature.initSign(privateKey); + signature.update(data); + return signature.sign(); + } + + public static PrivateKey getPrivateKeyByKeyStore(String keystoreType, String keyStorePath, char[] keyStorePassword, + String alias, char[] keyPassword) throws Exception { + KeyStore ks = loadKeyStore(keyStorePath, keyStorePassword, keystoreType); + if (alias == null) { + List aliases = Collections.list(ks.aliases()); + if (aliases.size() == 1) { + alias = (String) aliases.get(0); + } else { + throw new IllegalArgumentException( + "[Assertion failed] - this String argument[alias] must have text; it must not be null, empty, or blank"); + } + } + PrivateKey key = (PrivateKey) ks.getKey(alias, keyPassword); + return key; + } + + public static KeyStore loadKeyStore(String keyStorePath, char[] password, String keystoreType) throws Exception { + KeyStore ks = KeyStore.getInstance(keystoreType == null ? KeyStore.getDefaultType() : keystoreType); + File keystore = new File(keyStorePath); + if ((keystore == null) || ((keystore.exists()) && (keystore.isDirectory()))) { + throw new IllegalArgumentException("keystore[" + keyStorePath + "]"); + } + InputStream is = null; + try { + is = new FileInputStream(keystore); + ks.load(is, password); + return ks; + } finally { + if (is != null) { + is.close(); + } + } + } + + public static Certificate getCertificate(String keystoreType, String keyStorePath, char[] keyStorePassword, + String alias) throws Exception { + KeyStore ks = loadKeyStore(keyStorePath, keyStorePassword, keystoreType); + if (alias == null) { + List aliases = Collections.list(ks.aliases()); + if (aliases.size() == 1) { + alias = (String) aliases.get(0); + } else { + throw new IllegalArgumentException( + "[Assertion failed] - this String argument[alias] must have text; it must not be null, empty, or blank"); + } + } + return ks.getCertificate(alias); + } +} diff --git a/src/main/java/com/yumaolin/util/MessageAttestation/KeystoreSignProvider.java b/src/main/java/com/yumaolin/util/MessageAttestation/KeystoreSignProvider.java new file mode 100644 index 0000000..47d90b9 --- /dev/null +++ b/src/main/java/com/yumaolin/util/MessageAttestation/KeystoreSignProvider.java @@ -0,0 +1,29 @@ +package com.yumaolin.util.MessageAttestation; + +import java.nio.charset.Charset; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import org.apache.commons.codec.binary.Base64; +import org.springframework.util.Assert; + + +public class KeystoreSignProvider implements SignProvider { + private final X509Certificate x509Certificate; + private final PrivateKey privateKey; + + public KeystoreSignProvider(String kyeStoreType, String keyStorePath, char[] keyStorePassword, String alias, + char[] keyPassword) throws Exception { + Assert.hasText(keyStorePath, "客户端keystore路径不能为空"); + Assert.notNull(keyStorePassword, "keystore密码不能为空"); + this.x509Certificate = ((X509Certificate) EncryptionUtils.getCertificate(kyeStoreType, keyStorePath, + keyStorePassword, alias)); + + this.privateKey = EncryptionUtils.getPrivateKeyByKeyStore(kyeStoreType, keyStorePath, keyStorePassword, alias, + keyPassword); + } + + public String sign(byte[] plaintext, Charset charset) throws Exception { + byte[] signatureInfo = EncryptionUtils.signByX509Certificate(plaintext, this.x509Certificate, this.privateKey); + return Base64.encodeBase64String(signatureInfo); + } +} diff --git a/src/main/java/com/yumaolin/util/MessageAttestation/SignProvider.java b/src/main/java/com/yumaolin/util/MessageAttestation/SignProvider.java new file mode 100644 index 0000000..71ef982 --- /dev/null +++ b/src/main/java/com/yumaolin/util/MessageAttestation/SignProvider.java @@ -0,0 +1,9 @@ +package com.yumaolin.util.MessageAttestation; + +import java.nio.charset.Charset; + + +public interface SignProvider { + public abstract String sign(byte[] paramArrayOfByte, Charset paramCharset) + throws Exception; +} diff --git a/src/main/java/com/yumaolin/util/MessageAttestation/SignUtil.java b/src/main/java/com/yumaolin/util/MessageAttestation/SignUtil.java new file mode 100644 index 0000000..a95ee50 --- /dev/null +++ b/src/main/java/com/yumaolin/util/MessageAttestation/SignUtil.java @@ -0,0 +1,198 @@ +package com.yumaolin.util.MessageAttestation; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.security.Signature; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Base64; +/** + * 报文验签工具类 + */ +public class SignUtil { + + + private final static String charset = "UTF-8"; + + private static Map param = null; + private static String signatureInfo = ""; + + public static void main(String[] args) { + String caPath = "E:\\downFile\10円-cert\\"; + // 请求报文加签 + sign(caPath + "pfx.pfx", "123456"); + // 同步报文验签 + verifySign(caPath + "pfx.cer"); + } + + /** + * 同步报文验证签约 + * + * @param cerPath + */ + public static void verifySign(String cerPath) { + try { + Map parameters = paramsFilter(param); + String createLinkString = createLinkString(parameters); + byte[] datas = createLinkString.getBytes(charset); + // 得到的报文中的签名 + String signMsg = signatureInfo; + byte[] sign = Base64.decodeBase64(signMsg); + boolean verifySign = verifySign(datas, sign, cerPath); + System.out.println("验签名结果:" + verifySign); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void verifySign(String cerPath, Map param, String signatureInfo) { + try { + Map parameters = paramsFilter(param); + String createLinkString = createLinkString(parameters); + byte[] datas = createLinkString.getBytes(charset); + // 得到的报文中的签名 + String signMsg = signatureInfo; + byte[] sign = Base64.decodeBase64(signMsg); + boolean verifySign = verifySign(datas, sign, cerPath); + System.out.println("验签名结果:" + verifySign); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + /** + * 请求报文签约 + * + * @param pfxPath + * @param psw + */ + private static void sign(String pfxPath, String psw) { + try { + SignProvider signProvider = new KeystoreSignProvider("PKCS12", pfxPath, psw.toCharArray(), null, + psw.toCharArray()); + param = new HashMap(); + param.put("orderNo", "201801031509002"); + param.put("status", "1"); + param.put("callerIp", "10.37.20.46"); + param.put("signatureAlgorithm", "RSA"); + param.put("reconStatus", "1"); + param.put("settlementAmount", "1"); + param.put("checkDate", "20180103"); + param.put("language", "zh_CN"); + param.put("channelNo", "4100002085065666279205266395136"); + Map signParameters = signParameters(signProvider, param); + signatureInfo = signParameters.get("signatureInfo"); + System.out.println(signatureInfo); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static Map signParameters(SignProvider signProvider,final Map originalParameters) throws Exception { + final Map parameters = paramsFilter(originalParameters); + final String prestr = createLinkString(parameters); + System.out.println("prestr:" + prestr); + Charset encoding = Charset.forName(charset); + String encodeBase64String = signProvider.sign(prestr.getBytes(charset), encoding); + parameters.put("signatureInfo", encodeBase64String); + parameters.put("signatureAlgorithm", "RSA"); + return parameters; + } + + /** + * 除去参数中的空值和签名参数 + * + * @param parameters 签名参数组 + * @return 去掉空值与签名参数后的新签名参数组 + */ + private static Map paramsFilter(final Map parameters) { + if (parameters == null || parameters.size() == 0) { + return new HashMap(); + } + final Map result = new HashMap(parameters.size()); + String value = null; + for (final String key : parameters.keySet()) { + value = parameters.get(key); + if (value == null || "".equals(value) || key.equalsIgnoreCase("signatureAlgorithm") + || key.equalsIgnoreCase("signatureInfo")) { + continue; + } + result.put(key, value); + } + return result; + } + + /** + * 对请求参数排序,并按照接口规范中所述"参数名=参数值"的模式用"&"字符拼接成字符串 + * + * @param params 需要排序并参与字符拼接的参数 + * @return 拼接后字符串 + */ + private static String createLinkString(final Map params) { + + final List keys = new ArrayList(params.keySet()); + Collections.sort(keys); + final StringBuilder sb = new StringBuilder(); + String key = null; + String value = null; + for (int i = 0; i < keys.size(); i++) { + key = keys.get(i); + value = params.get(key); + sb.append(key).append("=").append(value); + // 最后一组参数,结尾不包括'&' + if (i < keys.size() - 1) { + sb.append("&"); + } + } + return sb.toString(); + } + + /** + *

验证签名,从证书中获取公钥来验证签名是否正确

+ * + * @param data 传输的数据 + * @param sign 对传输数据的签名 + * @param certificateContent 证书内容的2进制形式 + */ + public static boolean verifySign(byte[] data, byte[] sign, String certificateContent) throws Exception { + X509Certificate certificate = (X509Certificate) getCertificate(certificateContent); + Signature signature = Signature.getInstance(certificate.getSigAlgName()); + // 由证书初始化签名,使用了证书中的公钥 + signature.initVerify(certificate); + signature.update(data); + return signature.verify(sign); + } + + /** + *

从证书文件读取证书.'.crt'和'.cer'文件都可以读取 .cer是IE导出的公钥证书(der格式)

+ * @param certificatePath 证书文件路径:可以直接加载指定的文件,例如"file:C:/kft.cer" + */ + private static Certificate getCertificate(String certificatePath) throws Exception { + File certificate = new File(certificatePath); + if (certificate == null || (certificate.exists() && certificate.isDirectory())) { + throw new IllegalArgumentException("certificatePath[" + certificatePath + "]必须是一个已经存在的文件,不能为空,且不能是一个文件夹"); + } + InputStream inputStream = null; + try { + inputStream = new FileInputStream(certificate); + // 实例化证书工厂 + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Certificate cert = cf.generateCertificate(inputStream); + return cert; + } finally { + if (inputStream != null) { + inputStream.close(); + } + } + } +} diff --git a/src/main/java/com/yumaolin/util/PDFBoxUtil/ITextUtil.java b/src/main/java/com/yumaolin/util/PDFBoxUtil/ITextUtil.java new file mode 100644 index 0000000..61e8211 --- /dev/null +++ b/src/main/java/com/yumaolin/util/PDFBoxUtil/ITextUtil.java @@ -0,0 +1,124 @@ +package com.yumaolin.util.PDFBoxUtil; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; + +import com.itextpdf.text.BaseColor; +import com.itextpdf.text.Document; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.Font; +import com.itextpdf.text.Paragraph; +import com.itextpdf.text.pdf.AcroFields; +import com.itextpdf.text.pdf.BaseFont; +import com.itextpdf.text.pdf.PdfReader; +import com.itextpdf.text.pdf.PdfStamper; +import com.itextpdf.text.pdf.PdfWriter; + +public class ITextUtil { + + /** + *

创建PDF文件

+ * @param filePath + */ + public void createPDFFile(String filePath) { + try{ + Document doc = new Document(); + String fontPath = "C:\\Windows\\Fonts\\MSYHMONO.ttf"; + PdfWriter.getInstance(doc, new FileOutputStream(filePath)); + doc.open(); + BaseFont bfChinese = BaseFont.createFont(fontPath,BaseFont.IDENTITY_H,BaseFont.EMBEDDED); + Font fontChinese = new Font(bfChinese, 12, Font.NORMAL, BaseColor.GREEN); + Paragraph pf = new Paragraph("protocolNo|custIdenNo|custName", fontChinese); + //pf.add(new Paragraph("我们的家好大的家", fontChinese)); + //pf.add(new Paragraph("sfsfsf")); + doc.add(pf); + doc.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void parsePDFFile(String oldPath,String newPath,Map value) throws IOException { + Path out = Paths.get(newPath); + Files.deleteIfExists(out); + out = Paths.get(newPath); + PdfReader reader = null; + PdfStamper ps = null; + try { + reader = new PdfReader(oldPath); // 模版文件目录 + ps = new PdfStamper(reader, new FileOutputStream(out.toFile())); // 生成的输出流 + BaseFont bf = BaseFont.createFont("STSong-Light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED); + AcroFields s = ps.getAcroFields(); + if(value != null){ + for(String mapKey : value.keySet()){ + s.setFieldProperty(mapKey,"textfont",bf,null); + s.setField(mapKey,value.get(mapKey)); + } + } + /*//设置文本域表单的字体 + s.setFieldProperty("custName","textfont",bf,null); + s.setFieldProperty("merchantName","textfont",bf,null); + s.setFieldProperty("1", "textfont",bf,null); + s.setFieldProperty("2", "textfont",bf,null); + s.setFieldProperty("bankType","textfont",bf,null); + s.setFieldProperty("custBankCardNo","textfont",bf,null); + s.setFieldProperty("custPhoneNo","textfont",bf,null); + s.setFieldProperty("Signature1","textfont",bf,null); + s.setFieldProperty("Signature2","textfont",bf,null); + s.setFieldProperty("signDate","textfont",bf,null); + //编辑文本域表单的内容 + s.setField("custName","测试客户");//授权人 + s.setField("merchantName", "测试商户");//被授权人 + s.setField("1","2018-07-31");//签署业务合同时间 + s.setField("2","代购协议");//合同名称 + s.setField("bankType","招商银行");//授权人缴费开户银行 + s.setField("custBankCardNo","62284801245784");//银行卡账号 + s.setField("custPhoneNo","18684320213");//授权人联系手机 + s.setField("Signature1","测试客户1");//授权人签名 + s.setField("Signature2","测试商户2");//被授权人签名 + s.setField("signDate","2018-07-31");//签订日期*/ + ps.setFormFlattening(true);//如果为false那么生成的PDF文件还能编辑,一定要设为true + } catch (Exception e) { + //logger.warn("生成合同预览文件出错", e); + e.printStackTrace(); + }finally{ + if(ps != null){ + try { + ps.close(); + } catch (DocumentException e) { + } + } + if(reader != null){ + reader.close(); + } + } + //logger.info("商户下载入网合同,全路径[{}]", out); + } + + public static void main(String[] args) throws IOException, DocumentException { + ITextUtil textUtil = new ITextUtil(); + //textUtil.createPDFFile("D:\\test.PDF"); + //PDFReplacer textReplacer = new PDFReplacer("D://test.PDF"); + //textReplacer.replaceText("protocolNo", "小白"); + //textReplacer.replaceText("本科", "社会大学"); + //textReplacer.replaceText("0755-29493863", "15112345678"); + //textReplacer.toPdf("D://newTest.PDF"); + Map value = new HashMap(); + value.put("custName","测试客户"); + value.put("merchantName", "测试商户"); + value.put("1","2018/07/31"); + value.put("2","代购协议"); + value.put("custBankCardNo","62284801245784"); + value.put("custPhoneNo","18684320213"); + value.put("Signature1","测试客户1"); + value.put("Signature2","测试商户2"); + value.put("signDate","2018/07/31"); + value.put("bankType","招商银行"); + textUtil.parsePDFFile("D:\\委托代扣款协议测试(旧).pdf","D:\\委托代扣款协议测试(新).pdf",value); + } +} diff --git a/src/main/java/com/yumaolin/util/PDFBoxUtil/PDFPositionParse.java b/src/main/java/com/yumaolin/util/PDFBoxUtil/PDFPositionParse.java new file mode 100644 index 0000000..fcb7fdf --- /dev/null +++ b/src/main/java/com/yumaolin/util/PDFBoxUtil/PDFPositionParse.java @@ -0,0 +1,81 @@ +package com.yumaolin.util.PDFBoxUtil; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.itextpdf.text.pdf.PdfReader; +import com.itextpdf.text.pdf.parser.PdfReaderContentParser; + +/** + * 解析PDF中文本的x,y位置 + * @user : caoxu-yiyang@qq.com + * @date : 2016年11月9日 + */ +public class PDFPositionParse { + + private PdfReader reader; + private List findText = new ArrayList();//需要查找的文本 + private PdfReaderContentParser parser; + + public PDFPositionParse(String fileName) throws IOException{ + FileInputStream in = null; + try{ + in =new FileInputStream(fileName); + byte[] bytes = new byte[in.available()]; + in.read(bytes); + init(bytes); + }finally{ + in.close(); + } + } + + public PDFPositionParse(byte[] bytes) throws IOException{ + init(bytes); + } + + private boolean needClose = true; + /** + * 传递进来的reader不会在PdfPositionParse结束时关闭 + * @user : caoxu-yiyang@qq.com + * @date : 2016年11月9日 + * @param reader + */ + public PDFPositionParse(PdfReader reader){ + this.reader = reader; + parser = new PdfReaderContentParser(reader); + needClose = false; + } + + public void addFindText(String text){ + this.findText.add(text); + } + + private void init(byte[] bytes) throws IOException { + reader = new PdfReader(bytes); + parser = new PdfReaderContentParser(reader); + } + + /** + * 解析文本 + * @user : caoxu-yiyang@qq.com + * @date : 2016年11月9日 + * @throws IOException + */ + public Map parse() throws IOException{ + try{ + if(this.findText.size() == 0){ + throw new NullPointerException("没有需要查找的文本"); + } + PositionRenderListener listener = new PositionRenderListener(this.findText); + parser.processContent(1, listener); + return listener.getResult(); + }finally{ + if(reader != null && needClose){ + reader.close(); + } + } + } +} diff --git a/src/main/java/com/yumaolin/util/PDFBoxUtil/PDFReplacer.java b/src/main/java/com/yumaolin/util/PDFBoxUtil/PDFReplacer.java new file mode 100644 index 0000000..a8fea63 --- /dev/null +++ b/src/main/java/com/yumaolin/util/PDFBoxUtil/PDFReplacer.java @@ -0,0 +1,220 @@ +package com.yumaolin.util.PDFBoxUtil; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.itextpdf.text.BaseColor; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.Font; +import com.itextpdf.text.pdf.BaseFont; +import com.itextpdf.text.pdf.PdfContentByte; +import com.itextpdf.text.pdf.PdfReader; +import com.itextpdf.text.pdf.PdfStamper; + +/** + * 替换PDF文件某个区域内的文本 + * @user : caoxu-yiyang@qq.com + * @date : 2016年11月8日 + */ +public class PDFReplacer { + private static final Logger logger = LoggerFactory.getLogger(PDFReplacer.class); + + private int fontSize; + private Map replaceRegionMap = new HashMap(); + private Map replaceTextMap =new HashMap(); + private ByteArrayOutputStream output; + private PdfReader reader; + private PdfStamper stamper; + private PdfContentByte canvas; + private Font font; + + public PDFReplacer(byte[] pdfBytes) throws DocumentException, IOException{ + init(pdfBytes); + } + + public PDFReplacer(String fileName) throws IOException, DocumentException{ + FileInputStream in = null; + try{ + in =new FileInputStream(fileName); + byte[] pdfBytes = new byte[in.available()]; + in.read(pdfBytes); + init(pdfBytes); + }finally{ + in.close(); + } + } + + private void init(byte[] pdfBytes) throws DocumentException, IOException{ + logger.info("初始化开始"); + reader = new PdfReader(pdfBytes); + output = new ByteArrayOutputStream(); + stamper = new PdfStamper(reader, output); + canvas = stamper.getOverContent(1); + setFont(10); + logger.info("初始化成功"); + } + + private void close() throws DocumentException, IOException{ + if(reader != null){ + reader.close(); + } + if(output != null){ + output.close(); + } + + output=null; + replaceRegionMap=null; + replaceTextMap=null; + } + + public void replaceText(float x, float y, float w,float h, String text){ + ReplaceRegion region = new ReplaceRegion(text); //用文本作为别名 + region.setH(h); + region.setW(w); + region.setX(x); + region.setY(y); + addReplaceRegion(region); + this.replaceText(text, text); + } + + public void replaceText(String name, String text){ + this.replaceTextMap.put(name, text); + } + + /** + * 替换文本 + * @throws IOException + * @throws DocumentException + * @user : caoxu-yiyang@qq.com + * @date : 2016年11月9日 + */ + private void process() throws DocumentException, IOException{ + try{ + parseReplaceText(); + canvas.saveState(); + Set> entrys = replaceRegionMap.entrySet(); + for (Entry entry : entrys) { + ReplaceRegion value = entry.getValue(); + canvas.setColorFill(BaseColor.WHITE); + canvas.rectangle(value.getX(),value.getY(),value.getW(),value.getH()); + } + canvas.fill(); + canvas.restoreState(); + //开始写入文本 + canvas.beginText(); + for (Entry entry : entrys) { + ReplaceRegion value = entry.getValue(); + //设置字体 + canvas.setFontAndSize(font.getBaseFont(), getFontSize()); + canvas.setTextMatrix(value.getX(),value.getY()+2/*修正背景与文本的相对位置*/); + canvas.showText((String) replaceTextMap.get(value.getAliasName())); + } + canvas.endText(); + }finally{ + if(stamper != null){ + stamper.close(); + } + } + } + + /** + * 未指定具体的替换位置时,系统自动查找位置 + * @user : caoxu-yiyang@qq.com + * @date : 2016年11月9日 + */ + private void parseReplaceText() { + PDFPositionParse parse = new PDFPositionParse(reader); + Set> entrys = this.replaceTextMap.entrySet(); + for (Entry entry : entrys) { + if(this.replaceRegionMap.get(entry.getKey()) == null){ + parse.addFindText(entry.getKey()); + } + } + + try { + Map parseResult = parse.parse(); + Set> parseEntrys = parseResult.entrySet(); + for (Entry entry : parseEntrys) { + if(entry.getValue() != null){ + this.replaceRegionMap.put(entry.getKey(), entry.getValue()); + } + } + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + + } + + /** + * 生成新的PDF文件 + * @user : caoxu-yiyang@qq.com + * @date : 2016年11月9日 + * @param fileName + * @throws DocumentException + * @throws IOException + */ + public void toPdf(String fileName) throws DocumentException, IOException{ + FileOutputStream fileOutputStream = null; + try{ + process(); + fileOutputStream = new FileOutputStream(fileName); + fileOutputStream.write(output.toByteArray()); + fileOutputStream.flush(); + }catch(IOException e){ + logger.error(e.getMessage(), e); + throw e; + }finally{ + if(fileOutputStream != null){ + fileOutputStream.close(); + } + close(); + } + logger.info("文件生成成功"); + } + + + /** + * 添加替换区域 + * @user : caoxu-yiyang@qq.com + * @date : 2016年11月9日 + * @param replaceRegion + */ + public void addReplaceRegion(ReplaceRegion replaceRegion){ + this.replaceRegionMap.put(replaceRegion.getAliasName(), replaceRegion); + } + + public int getFontSize() { + return fontSize; + } + + /** + * 设置字体大小 + * @user : caoxu-yiyang@qq.com + * @date : 2016年11月9日 + * @param fontSize + * @throws DocumentException + * @throws IOException + */ + public void setFont(int fontSize) throws DocumentException, IOException{ + if(fontSize != this.fontSize){ + this.fontSize = fontSize; + BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED); + font = new Font(bf,this.fontSize,Font.BOLD); + } + } + + public void setFont(Font font){ + if(font == null){ + throw new NullPointerException("font is null"); + } + this.font = font; + } +} \ No newline at end of file diff --git a/src/main/java/com/yumaolin/util/PDFBoxUtil/PDFUtil.java b/src/main/java/com/yumaolin/util/PDFBoxUtil/PDFUtil.java new file mode 100644 index 0000000..8377b7d --- /dev/null +++ b/src/main/java/com/yumaolin/util/PDFBoxUtil/PDFUtil.java @@ -0,0 +1,185 @@ +package com.yumaolin.util.PDFBoxUtil; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +import org.apache.pdfbox.contentstream.operator.Operator; +import org.apache.pdfbox.cos.COSArray; +import org.apache.pdfbox.cos.COSString; +import org.apache.pdfbox.pdfparser.PDFStreamParser; +import org.apache.pdfbox.pdfwriter.ContentStreamWriter; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDPageTree; +import org.apache.pdfbox.pdmodel.PDResources; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.common.PDStream; +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDType0Font; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; +import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; +import org.apache.pdfbox.pdmodel.interactive.form.PDTextField; +import org.apache.pdfbox.text.PDFTextStripper; +import org.apache.pdfbox.util.Charsets; + + +public class PDFUtil { + + /** + *

创建PDF文件

+ * @param filePath + */ + public void createPDFFile(String filePath) { + try(PDDocument document = new PDDocument()){ + PDPage page = new PDPage(); + document.addPage(page); + PDAcroForm acroForm = new PDAcroForm(document); + document.getDocumentCatalog().setAcroForm(acroForm); + // Add and set the resources and default appearance at the form level + PDFont formFont = PDType0Font.load(document, new FileInputStream( + "C:\\Windows\\Fonts\\MSYHMONO.ttf"), false); + final PDResources resources = new PDResources(); + acroForm.setDefaultResources(resources); + + final String fontName = resources.add(formFont).getName(); + + // Acrobat sets the font size on the form level to be + // auto sized as default. This is done by setting the font size to '0' + acroForm.setDefaultResources(resources); + String defaultAppearanceString = "/" + fontName + " 0 Tf 0 g"; + + PDTextField textBox = new PDTextField(acroForm); + textBox.setPartialName("SampleField"); + textBox.setDefaultAppearance(defaultAppearanceString); + acroForm.getFields().add(textBox); + + // Specify the widget annotation associated with the field + PDAnnotationWidget widget = textBox.getWidgets().get(0); + PDRectangle rect = new PDRectangle(50, 700, 200, 50); + widget.setRectangle(rect); + widget.setPage(page); + page.getAnnotations().add(widget); + + // set the field value. Note that the last character is a turkish capital I with a dot, + // which is not part of WinAnsiEncoding + textBox.setValue("protocolNo"); + + document.save(filePath); + /*PDFont font = PDType0Font.load(document,new FileInputStream("C:\\Windows\\Fonts\\MSYHMONO.ttf"),false); + //PDFont font = PDType1Font.COURIER; + PDPageContentStream content = new PDPageContentStream(document, page); + content.beginText(); + content.setFont(font, 12); + content.newLineAtOffset(100, 700); + content.showText("protocolNo"); + content.endText(); + content.close();*/ + document.save(filePath); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + *

读取PDF文件

+ * @param filePath + */ + public void readPDF(String filePath) { + PDDocument helloDocument = null; + try { + helloDocument = PDDocument.load(new File(filePath)); + PDFTextStripper textStripper = new PDFTextStripper(); + System.out.println(textStripper.getText(helloDocument)); + helloDocument.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + *

替换PDF文件中的某个字符串

+ * @param inputFile + * @param outputFile + * @param strToFind + * @param message + * @throws IOException + */ + public void replaceText(String inputFile, String outputFile, String strToFind, String message) + throws IOException { + // the document + PDDocument document = null; + try{ + document = PDDocument.load(new File(inputFile)); + //PDFTextStripper stripper=new PDFTextStripper("ISO-8859-1"); + PDPageTree pages = document.getPages(); + PDResources resources = new PDResources(); + PDFont font = PDType0Font.load(document,new FileInputStream("C:\\Windows\\Fonts\\MSYHMONO.ttf"),false); + resources.add(font); + for (int i = 0; i < document.getNumberOfPages(); i++) { + PDPage page = (PDPage) pages.get(i); + page.setResources(resources); + PDFStreamParser parser = new PDFStreamParser(page); + parser.parse(); + List tokens = parser.getTokens(); + System.out.println(tokens); + for (int j = 0; j < tokens.size(); j++) { + Object next = tokens.get(j); + System.out.println(next); + if (next instanceof Operator) { + // Tj and TJ are the two operators that display + // strings in a PDF + String operatorName = ((Operator) next).getName(); + if (operatorName.equals("Tj")) { + // Tj takes one operator and that is the string + // to display so lets update that operator + COSString previous = (COSString) tokens.get(j-1); + byte[] bytes = previous.getBytes(); + String string = new String(bytes,Charsets.UTF_8); + System.out.println(string); + System.out.println(previous.getASCII()); + System.out.println(previous.getForceHexForm()); + System.out.println(previous.getCOSObject()); + System.out.println(previous.getString()); + System.out.println(previous.getClass()); + string = string.replaceFirst(strToFind, message); + previous.setValue(string.getBytes(Charsets.UTF_8)); + } else if (operatorName.equals("TJ")) { + COSArray previous = (COSArray) tokens.get(j - 1); + for (int k = 0; k < previous.size(); k++) { + Object arrElement = previous.getObject(k); + if (arrElement instanceof COSString) { + COSString cosString = (COSString) arrElement; + String string = cosString.getString(); + string = string.replaceFirst(strToFind, message); + cosString.setValue(string.getBytes(Charsets.UTF_8)); + } + } + } + } + } + // now that the tokens are updated we will replace the + // page content stream. + PDStream updatedStream = new PDStream(document); + OutputStream out = updatedStream.createOutputStream(); + ContentStreamWriter tokenWriter = new ContentStreamWriter(out); + tokenWriter.writeTokens(tokens); + page.setContents(updatedStream); + out.close(); + } + document.save(outputFile); + }finally{ + if(document != null){ + document.close(); + } + } + } + + public static void main(String[] args) throws IOException { + PDFUtil pdfUtil = new PDFUtil(); + pdfUtil.createPDFFile("D:\\test.PDF"); + pdfUtil.replaceText("D:\\test.PDF","D:\\newTest.PDF","protocolNo","合同编号"); + } +} diff --git a/src/main/java/com/yumaolin/util/PDFBoxUtil/PositionRenderListener.java b/src/main/java/com/yumaolin/util/PDFBoxUtil/PositionRenderListener.java new file mode 100644 index 0000000..2fff0d2 --- /dev/null +++ b/src/main/java/com/yumaolin/util/PDFBoxUtil/PositionRenderListener.java @@ -0,0 +1,77 @@ +package com.yumaolin.util.PDFBoxUtil; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.itextpdf.awt.geom.Rectangle2D.Float; +import com.itextpdf.text.pdf.parser.ImageRenderInfo; +import com.itextpdf.text.pdf.parser.RenderListener; +import com.itextpdf.text.pdf.parser.TextRenderInfo; + +/** + * pdf渲染监听,当找到渲染的文本时,得到文本的坐标x,y,w,h + * @user : caoxu-yiyang@qq.com + * @date : 2016年11月9日 + */ +public class PositionRenderListener implements RenderListener{ + + private List findText; + private float defaultH; ///出现无法取到值的情况,默认为12 + private float fixHeight; //可能出现无法完全覆盖的情况,提供修正的参数,默认为2 + public PositionRenderListener(List findText, float defaultH,float fixHeight) { + this.findText = findText; + this.defaultH = defaultH; + this.fixHeight = fixHeight; + } + + public PositionRenderListener(List findText) { + this.findText = findText; + this.defaultH = 12; + this.fixHeight = 2; + } + + @Override + public void beginTextBlock() { + + } + + @Override + public void endTextBlock() { + + } + + @Override + public void renderImage(ImageRenderInfo imageInfo) { + } + + private Map result = new HashMap(); + @Override + public void renderText(TextRenderInfo textInfo) { + String text = textInfo.getText(); + for (String keyWord : findText) { + System.out.println(keyWord); + System.out.println(text); + System.out.println(textInfo.getPdfString()); + if (null != text && text.contains(keyWord)){ + + Float bound = textInfo.getBaseline().getBoundingRectange(); + ReplaceRegion region = new ReplaceRegion(keyWord); + region.setH(bound.height == 0 ? defaultH : bound.height); + region.setW(bound.width); + region.setX(bound.x); + region.setY(bound.y-this.fixHeight); + result.put(keyWord, region); + } + } + } + + public Map getResult() { + for (String key : findText) {//补充没有找到的数据 + if(this.result.get(key) == null){ + this.result.put(key, null); + } + } + return this.result; + } +} \ No newline at end of file diff --git a/src/main/java/com/yumaolin/util/PDFBoxUtil/ReplaceRegion.java b/src/main/java/com/yumaolin/util/PDFBoxUtil/ReplaceRegion.java new file mode 100644 index 0000000..21725d3 --- /dev/null +++ b/src/main/java/com/yumaolin/util/PDFBoxUtil/ReplaceRegion.java @@ -0,0 +1,67 @@ +package com.yumaolin.util.PDFBoxUtil; + +/** + * 需要替换的区域 + * + * @user : caoxu-yiyang@qq.com + * @date : 2016年11月9日 + */ +public class ReplaceRegion { + + private String aliasName; + private Float x; + private Float y; + private Float w; + private Float h; + + public ReplaceRegion(String aliasName) { + this.aliasName = aliasName; + } + + /** + * 替换区域的别名 + * + * @user : caoxu-yiyang@qq.com + * @date : 2016年11月9日 + * @return + */ + public String getAliasName() { + return aliasName; + } + + public void setAliasName(String aliasName) { + this.aliasName = aliasName; + } + + public Float getX() { + return x; + } + + public void setX(Float x) { + this.x = x; + } + + public Float getY() { + return y; + } + + public void setY(Float y) { + this.y = y; + } + + public Float getW() { + return w; + } + + public void setW(Float w) { + this.w = w; + } + + public Float getH() { + return h; + } + + public void setH(Float h) { + this.h = h; + } +} \ No newline at end of file diff --git a/src/main/java/com/yumaolin/util/PoiForExcel/ReadExcelUtilsForExcel.java b/src/main/java/com/yumaolin/util/PoiForExcel/ReadExcelUtilsForExcel.java index ba91e96..8794fc9 100644 --- a/src/main/java/com/yumaolin/util/PoiForExcel/ReadExcelUtilsForExcel.java +++ b/src/main/java/com/yumaolin/util/PoiForExcel/ReadExcelUtilsForExcel.java @@ -1,20 +1,21 @@ package com.yumaolin.util.PoiForExcel; +import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.PushbackInputStream; import java.math.BigDecimal; import java.text.DecimalFormat; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Date; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.hssf.util.HSSFColor.BLACK; -import org.apache.poi.poifs.filesystem.DocumentFactoryHelper; -import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined; +import org.apache.poi.poifs.filesystem.FileMagic; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; @@ -24,91 +25,210 @@ import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSFWorkbook; + public class ReadExcelUtilsForExcel { - private Workbook wb; private Sheet sheet; - private Row row; private CellStyle setBorder; private Font font; - private static final long fileSize = 1024*1024*10;//10mb - - public ReadExcelUtilsForExcel(Workbook wb){ - this.wb = wb; + + public Workbook createWorkBook(String path) throws IOException { + InputStream input = new FileInputStream(new File(path)); + BufferedInputStream bufferedInput = (BufferedInputStream) FileMagic.prepareToCheckMagic(input); + Workbook wb = null; + if (FileMagic.valueOf(bufferedInput) == FileMagic.OOXML) { + wb = new XSSFWorkbook(bufferedInput); + } else if (FileMagic.valueOf(bufferedInput) == FileMagic.OLE2) { + wb = new HSSFWorkbook(bufferedInput); + } else { + throw new IOException("该文件类型不是excel文件类型!"); + } + IOUtils.closeQuietly(bufferedInput); + return wb; } - public String[][] readExcelContent(){ - String[][] content; - sheet = wb.getSheetAt(0); + /** + * 读取excel文件 + * + * @param wb + * @param sheetIndex sheet页下标:从0开始 + * @param startReadLine 开始读取的行:从0开始 + * @param tailLine 去除最后读取的行 + */ + public String[] readExcelContent(Workbook wb, int sheetIndex, int startReadLine, int tailLine) { + Sheet sheet = wb.getSheetAt(sheetIndex); // 得到总行数 - int rowNum = sheet.getLastRowNum(); - row = sheet.getRow(1); - //int colNum = row.getPhysicalNumberOfCells(); - int colNum = row.getLastCellNum(); - content = new String[rowNum+1][colNum]; - System.out.println(content.length); + int rowNum = sheet.getLastRowNum() - tailLine; + String[] content = new String[rowNum - startReadLine]; // 正文内容应该从第二行开始,第一行为表头的标题 - for (int i = 0; i <= rowNum; i++){ + Row row = null; + int emptyCount = 0;// 计算空行的个数 + for (int i = startReadLine; i < rowNum; i++) { row = sheet.getRow(i); - if (null == row) { - break; - } - if(StringUtils.isEmpty(getCellFormatValue(row.getCell(0)))){//如果某行第一列出现空 就不读取这行 + if (row == null) { continue; } - int j = 0; - while (j < colNum){ - // 每个单元格的数据内容用"-"分割开,以后需要时用String类的replace()方法还原数据 - // 也可以将每个单元格的数据设置到一个javabean的属性中,此时需要新建一个javabean - // str += getStringCellValue(row.getCell((short) j)).trim() + - // "-"; - /*sbd.append(getCellFormatValue(row.getCell(j)).trim() == null - || "".equals(getCellFormatValue(row.getCell(j)).trim()) ? nullStr - : getCellFormatValue(row.getCell(j)).trim() + SPLITF);*/ - content[i][j]=getCellFormatValue(row.getCell(j)); - j++; + StringBuilder cellValue = new StringBuilder(30); + for (Cell c : row) { + boolean isMerge = isMergedRegion(sheet, i, c.getColumnIndex()); + // 判断是否具有合并单元格 + if (isMerge) { + String value = getMergedRegionValue(sheet, row.getRowNum(), c.getColumnIndex()); + if (StringUtils.isNotBlank(value)) { + cellValue.append(value).append("|"); + } + } else { + String value = getCellFormatValue(c); + if (StringUtils.isNotBlank(value)) { + cellValue.append(value).append("|"); + } + } + } + String value = cellValue.toString(); + if (StringUtils.isNotEmpty(value)) { + content[i - startReadLine - emptyCount] = value; + } else { + ++emptyCount; } } + content = Arrays.copyOf(content, content.length - emptyCount); setBorder = wb.createCellStyle(); font = wb.createFont(); return content; } - @SuppressWarnings("deprecation") + /** + * 判断指定的单元格是否是合并单元格 + * + * @param sheet + * @param row 行下标 + * @param column 列下标 + * @return + */ + private boolean isMergedRegion(Sheet sheet, int row, int column) { + int sheetMergeCount = sheet.getNumMergedRegions(); + for (int i = 0; i < sheetMergeCount; i++) { + CellRangeAddress range = sheet.getMergedRegion(i); + int firstColumn = range.getFirstColumn(); + int lastColumn = range.getLastColumn(); + int firstRow = range.getFirstRow(); + int lastRow = range.getLastRow(); + if (row>= firstRow && row <= lastRow) { + if (column>= firstColumn && column <= lastColumn) { + return true; + } + } + } + return false; + } + + /** + * 获取合并单元格的值 + * + * @param sheet + * @param row + * @param column + * @return + */ + public String getMergedRegionValue(Sheet sheet, int row, int column) { + int sheetMergeCount = sheet.getNumMergedRegions(); + for (int i = 0; i < sheetMergeCount; i++) { + CellRangeAddress ca = sheet.getMergedRegion(i); + int firstColumn = ca.getFirstColumn(); + int lastColumn = ca.getLastColumn(); + int firstRow = ca.getFirstRow(); + int lastRow = ca.getLastRow(); + if (row>= firstRow && row <= lastRow) { + if (column>= firstColumn && column <= lastColumn) { + Row fRow = sheet.getRow(firstRow); + Cell fCell = fRow.getCell(firstColumn); + return getCellFormatValue(fCell); + } + } + } + return null; + } + + /** + * 判断合并了行 + * + * @param sheet + * @param row + * @param column + * @return + */ + private boolean isMergedRow(Sheet sheet, int row, int column) { + int sheetMergeCount = sheet.getNumMergedRegions(); + for (int i = 0; i < sheetMergeCount; i++) { + CellRangeAddress range = sheet.getMergedRegion(i); + int firstColumn = range.getFirstColumn(); + int lastColumn = range.getLastColumn(); + int firstRow = range.getFirstRow(); + int lastRow = range.getLastRow(); + if (row == firstRow && row == lastRow) { + if (column>= firstColumn && column <= lastColumn) { + return true; + } + } + } + return false; + } + + /** + * 判断sheet页中是否含有合并单元格 + * + * @param sheet + * @return + */ + private boolean hasMerged(Sheet sheet) { + return sheet.getNumMergedRegions()> 0 ? true : false; + } + + /** + * 合并单元格 + * + * @param sheet + * @param firstRow 开始行 + * @param lastRow 结束行 + * @param firstCol 开始列 + * @param lastCol 结束列 + */ + private void mergeRegion(Sheet sheet, int firstRow, int lastRow, int firstCol, int lastCol) { + sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)); + } + private static String getCellFormatValue(Cell cell) { String cellvalue = ""; if (cell != null) { // 判断当前Cell的Type - switch (cell.getCellTypeEnum()){ - // 如果当前Cell的Type为NUMERIC - case NUMERIC: - BigDecimal db = new BigDecimal(String.valueOf(cell.getNumericCellValue()));// 避免精度问题,先转成字符串 - cellvalue = db.toPlainString(); - break; - case FORMULA:{ - // 判断当前的cell是否为Date - if (DateUtil.isCellDateFormatted(cell)) { - // 如果是Date类型则,转化为Data格式 - // 方法1:这样子的data格式是带时分秒的:2011年10月12日 0:00:00 - // cellvalue = cell.getDateCellValue().toLocaleString(); - // 方法2:这样子的data格式是不带带时分秒的:2011年10月12日 - Date date = cell.getDateCellValue(); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - cellvalue = sdf.format(date); - }else{// 如果是纯数字 + switch (cell.getCellTypeEnum()) { + // 如果当前Cell的Type为NUMERIC + case NUMERIC: + // 判断当前的cell是否为Date + if (DateUtil.isCellDateFormatted(cell)) { + Date date = cell.getDateCellValue(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + cellvalue = sdf.format(date); + } else { + BigDecimal db = new BigDecimal(String.valueOf(cell.getNumericCellValue()));// 避免精度问题,先转成字符串 + cellvalue = db.toPlainString(); + } + break; + case FORMULA: { DecimalFormat df = new DecimalFormat("0"); - cellvalue = df.format(cell.getNumericCellValue());//取得当前Cell的数值 + cellvalue = df.format(cell.getNumericCellValue());// 取得当前Cell的数值 + break; + } + case STRING: {// 如果当前Cell的Type为STRIN + // 取得当前的Cell字符串 + cellvalue = cell.getRichStringCellValue().getString(); + break; + } + default: {// 默认的Cell值 + cellvalue = ""; } - break; - } - case STRING:{// 如果当前Cell的Type为STRIN - // 取得当前的Cell字符串 - cellvalue = cell.getRichStringCellValue().getString(); - break; - }default:{// 默认的Cell值 - cellvalue = ""; - } } } else { cellvalue = ""; @@ -116,7 +236,7 @@ private static String getCellFormatValue(Cell cell) { return cellvalue.trim(); } - public void writeInTemplate(String newContent, int beginRow,int beginCell, boolean flag){ + public void writeInTemplate(String newContent, int beginRow, int beginCell, boolean flag) { Row row = sheet.getRow(beginRow); if (null == row) { // 如果不做空判断,你必须让你的模板文件画好边框,beginRow和beginCell必须在边框最大值以内 @@ -129,7 +249,7 @@ public void writeInTemplate(String newContent, int beginRow,int beginCell, boole cell = row.createCell(beginCell); } // 设置存入内容为字符串 - //cell.setCellType(Cell.CELL_TYPE_STRING); + // cell.setCellType(Cell.CELL_TYPE_STRING); cell.setCellType(CellType.STRING); getHssfCellStyle(flag); cell.setCellStyle(setBorder); @@ -140,58 +260,31 @@ public void writeInTemplate(String newContent, int beginRow,int beginCell, boole public void getHssfCellStyle(boolean flag) { // cell.setCellStyle(styleFactory.getHeaderStyle()); font.setFontHeightInPoints((short) 12); // 字体高度 - //font.setBoldweight(Font.BOLDWEIGHT_BOLD); + // font.setBoldweight(Font.BOLDWEIGHT_BOLD); font.setBold(true); - font.setColor(BLACK.index); - /*setBorder.setBorderBottom(CellStyle.BORDER_THIN); - setBorder.setBorderLeft(CellStyle.BORDER_THIN); - setBorder.setBorderTop(CellStyle.BORDER_THIN); - setBorder.setBorderRight(CellStyle.BORDER_THIN);*/ + font.setColor(HSSFColorPredefined.BLACK.getIndex()); + /* + * setBorder.setBorderBottom(CellStyle.BORDER_THIN); + * setBorder.setBorderLeft(CellStyle.BORDER_THIN); + * setBorder.setBorderTop(CellStyle.BORDER_THIN); + * setBorder.setBorderRight(CellStyle.BORDER_THIN); + */ setBorder.setBorderBottom(BorderStyle.THIN); setBorder.setBorderLeft(BorderStyle.THIN); setBorder.setBorderTop(BorderStyle.THIN); setBorder.setBorderRight(BorderStyle.THIN); setBorder.setFont(font); } + public static void main(String[] args) throws Exception { - File file = new File("d:\\交易明细信息.xls"); - //File file = new File("d:\\主表.xls"); - InputStream input = new FileInputStream(file); - if (!input.markSupported()) { - input = new PushbackInputStream(input, 8); - } - //boolean flag = ReadExcelUtilsForXls.getTypeByStream(file, "xlsx"); - //POIXMLDocument.hasOOXMLHeader(input)判断是否是xlsx文件 /** * 如果是xlsx文件,则按照xlsx文件类型读取 */ - if(DocumentFactoryHelper.hasOOXMLHeader(input)){ - if(file.length()>fileSize){ - System.out.println("http://blog.csdn.net/lee_guang/article/details/8936178"); - }else{ - Workbook wb = new XSSFWorkbook(input); - String[][] list = new ReadExcelUtilsForExcel(wb).readExcelContent(); - for(String[] map:list){ - for(int i=0;i
    = firstRow && row <= lastRow) { + if (column>= firstColumn && column <= lastColumn) { + Row fRow = sheet.getRow(firstRow); + Cell fCell = fRow.getCell(firstColumn); + return getCellValue(fCell); + } + } + } + return null; + } + + /** + * 判断合并了行 + * + * @param sheet + * @param row + * @param column + * @return + */ + private boolean isMergedRow(Sheet sheet, int row, int column) { + int sheetMergeCount = sheet.getNumMergedRegions(); + for (int i = 0; i < sheetMergeCount; i++) { + CellRangeAddress range = sheet.getMergedRegion(i); + int firstColumn = range.getFirstColumn(); + int lastColumn = range.getLastColumn(); + int firstRow = range.getFirstRow(); + int lastRow = range.getLastRow(); + if (row == firstRow && row == lastRow) { + if (column>= firstColumn && column <= lastColumn) { + return true; + } + } + } + return false; + } + + /** + * 判断指定的单元格是否是合并单元格 + * + * @param sheet + * @param row 行下标 + * @param column 列下标 + * @return + */ + private boolean isMergedRegion(Sheet sheet, int row, int column) { + int sheetMergeCount = sheet.getNumMergedRegions(); + for (int i = 0; i < sheetMergeCount; i++) { + CellRangeAddress range = sheet.getMergedRegion(i); + int firstColumn = range.getFirstColumn(); + int lastColumn = range.getLastColumn(); + int firstRow = range.getFirstRow(); + int lastRow = range.getLastRow(); + if (row>= firstRow && row <= lastRow) { + if (column>= firstColumn && column <= lastColumn) { + return true; + } + } + } + return false; + } + + /** + * 判断sheet页中是否含有合并单元格 + * + * @param sheet + * @return + */ + private boolean hasMerged(Sheet sheet) { + return sheet.getNumMergedRegions()> 0 ? true : false; + } + + /** + * 合并单元格 + * + * @param sheet + * @param firstRow 开始行 + * @param lastRow 结束行 + * @param firstCol 开始列 + * @param lastCol 结束列 + */ + private void mergeRegion(Sheet sheet, int firstRow, int lastRow, int firstCol, int lastCol) { + sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)); + } + + /** + * 获取单元格的值 + * + * @param cell + * @return + */ + public String getCellValue(Cell cell) { + String cellvalue = ""; + if (cell != null) { + // 判断当前Cell的Type + switch (cell.getCellTypeEnum()) { + // 如果当前Cell的Type为NUMERIC + case NUMERIC: + BigDecimal db = new BigDecimal(String.valueOf(cell.getNumericCellValue()));// 避免精度问题,先转成字符串 + cellvalue = db.toPlainString(); + break; + case FORMULA: { + // 判断当前的cell是否为Date + if (DateUtil.isCellDateFormatted(cell)) { + Date date = cell.getDateCellValue(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + cellvalue = sdf.format(date); + } else {// 如果是纯数字 + DecimalFormat df = new DecimalFormat("0"); + cellvalue = df.format(cell.getNumericCellValue());// 取得当前Cell的数值 + } + break; + } + case STRING: {// 如果当前Cell的Type为STRIN + // 取得当前的Cell字符串 + cellvalue = cell.getRichStringCellValue().getString(); + break; + } + default: {// 默认的Cell值 + cellvalue = ""; + } + } + } else { + cellvalue = ""; + } + return cellvalue.trim(); + } +} \ No newline at end of file diff --git a/src/main/java/com/yumaolin/util/TwoDimensionCode/BufferedImageLuminanceSource.java b/src/main/java/com/yumaolin/util/TwoDimensionCode/BufferedImageLuminanceSource.java index 4a16287..6294dae 100644 --- a/src/main/java/com/yumaolin/util/TwoDimensionCode/BufferedImageLuminanceSource.java +++ b/src/main/java/com/yumaolin/util/TwoDimensionCode/BufferedImageLuminanceSource.java @@ -3,6 +3,9 @@ import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.Arrays; +import java.util.Locale; import com.google.zxing.LuminanceSource;

    AltStyle によって変換されたページ (->オリジナル) /