您的位置:首页 > 其它

利用poi生成word(含表格 图片)

2017-08-26 19:11 603 查看
场景:接收前台穿过来的问卷的结果信息,含表格图片,动态生成word

生成图片

上一篇介绍了用echarts可以直接将base64 码传到后台,然后经解析可生成二进制码,然后利用poi方法可以插入 word中 ,但网上看了许多例子 ,都是说原poi方法中有错无需要重写一下 ,重写的代码继承XWPFDocument即可, 网上找的代码

package com.cmos.ngqss.action;

import java.io.IOException;
import java.io.InputStream;

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;

public class CustomXWPFDocument extends XWPFDocument {
public CustomXWPFDocument() {
super();
}

public CustomXWPFDocument(OPCPackage opcPackage) throws IOException {
super(opcPackage);
}

public CustomXWPFDocument(InputStream in) throws IOException {
super(in);
}

public void createPicture(String blipId,int id, int width, int height) {
final int EMU = 9525;
width *= EMU;
height *= EMU;
//String blipId = getAllPictures().get(id).getPackageRelationship().getId();

CTInline inline = createParagraph().createRun().getCTR().addNewDrawing().addNewInline();

String picXml = "" +
"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" +
"   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
"      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
"         <pic:nvPicPr>" +
"            <pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>" +
"            <pic:cNvPicPr/>" +
"         </pic:nvPicPr>" +
"         <pic:blipFill>" +
"            <a:blip r:embed=\"" + blipId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" +
"            <a:stretch>" +
"               <a:fillRect/>" +
"            </a:stretch>" +
"         </pic:blipFill>" +
"         <pic:spPr>" +
"            <a:xfrm>" +
"               <a:off x=\"0\" y=\"0\"/>" +
"               <a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>" +
"            </a:xfrm>" +
"            <a:prstGeom prst=\"rect\">" +
"               <a:avLst/>" +
"            </a:prstGeom>" +
"         </pic:spPr>" +
"      </pic:pic>" +
"   </a:graphicData>" +
"</a:graphic>";

//CTGraphicalObjectData graphicData = inline.addNewGraphic().addNewGraphicData();
XmlToken xmlToken = null;
try {
xmlToken = XmlToken.Factory.parse(picXml);
} catch(XmlException xe) {
xe.printStackTrace();
}
inline.set(xmlToken);
//graphicData.set(xmlToken);

inline.setDistT(0);
inline.setDistB(0);
inline.setDistL(0);
inline.setDistR(0);

CTPositiveSize2D extent = inline.addNewExtent();
extent.setCx(width);
extent.setCy(height);

CTNonVisualDrawingProps docPr = inline.addNewDocPr();
docPr.setId(id);
docPr.setName("Picture " + id);
docPr.setDescr("Generated");
}
}


接收前太的base64码后做如下处理即可

//添加图片
private void addPicture(Map map) throws IOException, InvalidFormatException {
String base64Info = (String)map.get("base64Info");
base64Info = base64Info.replaceAll(" ", "+");
String pictureInfo = (String)base64Info.split("base64,")[1];

BASE64Decoder decoder = new BASE64Decoder();
byte[] a = decoder.decodeBuffer(pictureInfo);// Base64解码
for (int i = 0; i < a.length; ++i) {
if (a[i] < 0) {// 调整异常数据
a[i] += 256;
}
}
String picId1 = document.addPictureData(a, XWPFDocument.PICTURE_TYPE_JPEG);
document.createPicture(picId1, document.getNextPicNameNumber(XWPFDocument.PICTURE_TYPE_PNG), 580, 250);
}


生成word表格

package com.cmos.ngqss.action;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletRequest;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTable.XWPFBorderType;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableCell.XWPFVertAlign;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblBorders;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;
import com.cmos.core.bean.InputObject;
import com.cmos.core.bean.OutputObject;
import com.cmos.core.util.JsonUtil;
import com.cmos.core.util.StringUtil;
import com.cmos.ngqss.exeption.NgqssException;
import com.cmos.ngqss.util.Constants;
import com.cmos.ngqss.util.CustomXWPFDocument;
import com.cmos.ngqss.util.DateUtil;
import com.cmos.ngqss.util.DateUtil.DATE_PATTERN;
import com.cmos.ngqss.util.NGConstants;
import com.cmos.cache.util.PropertiesUtil;
import com.cmos.onest.ONestUtil;

import sun.misc.BASE64Decoder;
public class DowAction extends BaseAction {

private static final String String = null;
//word文件
CustomXWPFDocument document= new CustomXWPFDocument();
//题号
int t = 1 ;

public void index() throws Exception {
InputObject inputObject = super.getInputObject();
OutputObject out = new OutputObject();
String title = (String) inputObject.getParams().get("title");
String str =(String) inputObject.getParams().get("beans");
List<Map<String,Object>> beansList = new ArrayList();
if(StringUtil.isNotEmpty(str)){
beansList= JsonUtil.convertJson2Object(str, List.class);
}

/********************生成word***********************/
//添加标题
XWPFParagraph titleParagraph = document.createParagraph();
//设置段落居中
titleParagraph.setAlignment(ParagraphAlignment.CENTER);
XWPFRun titleParagraphRun = titleParagraph.createRun();
titleParagraphRun.setText(title);
titleParagraphRun.setColor("000000");
titleParagraphRun.setFontSize(20);

XWPFParagraph p = document.createParagraph(); //每一个表格内容设置为一个段落,便于设置样式,字体
//原本是在方法内写,但每个段落好像自动会有
//一个换行,导致有多少表格 下边就有多少空行

for (Map<String, Object> beanMap : beansList){
String quTypeCd = (String)beanMap.get("quTypeCd");
//图片题
if(quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_IMAGE)){

//添加题目
addPicQueNam(beanMap);
//创建表格
XWPFTable ComTable1 = document.createTable();
//外边框样式
setBorders(ComTable1);
// 设置上下左右四个方向的距离
ComTable1.setCellMargins(20, 20, 20, 20);

//列宽自动分割
CTTblWidth comTableWidth = ComTable1.getCTTbl().addNewTblPr().addNewTblW();
comTableWidth.setType(STTblWidth.DXA);
comTableWidth.setW(BigInteger.valueOf(9072));
//去除单元格间的竖线
ComTable1.setInsideVBorder(XWPFBorderType.NONE, 0, 0, "");
//横线颜色
ComTable1.setInsideHBorder(XWPFBorderType.SINGLE , 0, 0, "F4F4F4");
//表格第一行
XWPFTableRow comTableRowOne = ComTable1.getRow(0);
setCell(comTableRowOne.getCell(0),"选项",p);
comTableRowOne.getCell(0).setColor("F4F4F4");  //设置表格颜色
setCell( comTableRowOne.addNewTableCell(),"小计",p);
comTableRowOne.getCell(1).setColor("F4F4F4");
setCell(comTableRowOne.addNewTableCell(),"百分比",p);
comTableRowOne.getCell(2).setColor("F4F4F4");

List<Map<Object,Object>> childrenList = (List<Map<Object, Object>>) beanMap.get("children");
for(Map<Object,Object> childMap : childrenList ){
XWPFTableRow comTableRow = ComTable1.createRow();
setPicCell( comTableRow.getCell(0),(String)childMap.get("aswrNm"),(String)childMap.get("picUrlAddr"),p);
setCell(comTableRow.getCell(1),(String)childMap.get("count").toString(),p);
setCell(comTableRow.getCell(2),(String)childMap.get("percent"),p);
}
//存放图片
String base64Info = (String)beanMap.get("base64Info");
if(base64Info != null){
addPicture(beanMap);
}
//换行
huanhang();

}

//填空题
if(quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_BLANK) || quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_BLANK_MULTI)
|| quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_MATRIX_BLANK)

){
//添加题目
addQueNam(beanMap);
//换行
huanhang();
}
//单选 多选 单项评分题 单项投票  多项投票 NPS题
if(quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_CHOOSE_SINGLE) || quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_CHOSSE_MULTI)
|| quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_SCORE_CHOOSE_SINGLE) || quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_VOTE_SINGLE)
|| quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_VOTE_MULTI) || quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_SCORE_NPS)

){
//添加题目
addQueNam(beanMap);
//创建表格
XWPFTable ComTable1 = document.createTable();
//外边框样式
setBorders(ComTable1);
// 设置上下左右四个方向的距离
ComTable1.setCellMargins(20, 20, 20, 20);

//列宽自动分割
CTTblWidth comTableWidth = ComTable1.getCTTbl().addNewTblPr().addNewTblW();
comTableWidth.setType(STTblWidth.DXA);
comTableWidth.setW(BigInteger.valueOf(9072));
//去除单元格间的竖线
ComTable1.setInsideVBorder(XWPFBorderType.NONE, 0, 0, "");
//横线颜色
ComTable1.setInsideHBorder(XWPFBorderType.SINGLE , 0, 0, "F4F4F4");
//表格第一行
XWPFTableRow comTableRowOne = ComTable1.getRow(0);
setCell(comTableRowOne.getCell(0),"选项",p);
comTableRowOne.getCell(0).setColor("F4F4F4");  //设置表格颜色
setCell( comTableRowOne.addNewTableCell(),"小计",p);
comTableRowOne.getCell(1).setColor("F4F4F4");
setCell(comTableRowOne.addNewTableCell(),"百分比",p);
comTableRowOne.getCell(2).setColor("F4F4F4");

List<Map<Object,Object>> childrenList = (List<Map<Object, Object>>) beanMap.get("children");
for(Map<Object,Object> childMap : childrenList ){
XWPFTableRow comTableRow = ComTable1.createRow();
setCell( comTableRow.getCell(0),(String)childMap.get("aswrNm"),p);
setCell(comTableRow.getCell(1),childMap.get("count").toString(),p);
setCell(comTableRow.getCell(2),(String)childMap.get("percent"),p);
}
//存放图片
String base64Info = (String)beanMap.get("base64Info");
if(base64Info != null){
addPicture(beanMap);
}
//换行
huanhang();
}
//矩阵单选,矩阵多选  多项评分提
if(quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_MATRIX_CHOOSE_SINGLE) || quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_MATRIX_CHOOSE_MULTI)
||  quTypeCd.equals(NGConstants.QU_TYPE_CD.QU_TYPE_CD_SCORE_CHOOSE_MULTI)){

//添加题目
addQueNam(beanMap);
//创建表格
XWPFTable ComTable5 = document.createTable();
//外边框样式
setBorders(ComTable5);
// 设置上下左右四个方向的距离
ComTable5.setCellMargins(20, 20, 20, 20);
//列宽自动分割
CTTblWidth comTableWidth11 = ComTable5.getCTTbl().addNewTblPr().addNewTblW();
comTableWidth11.setType(STTblWidth.DXA);
comTableWidth11.setW(BigInteger.valueOf(9072));
//去除单元格间的竖线
ComTable5.setInsideVBorder(XWPFBorderType.NONE, 0, 0, "");
//横线颜色
ComTable5.setInsideHBorder(XWPFBorderType.SINGLE , 0, 0, "F4F4F4");
//表格第一行
XWPFTableRow comTableRowOne11 = ComTable5.getRow(0);
comTableRowOne11.getCell(0).setText(" ");
comTableRowOne11.getCell(0).setColor("F4F4F4");  //设置表格颜色
List<Map<Object,Object>> childrenList11 = (List<Map<Object, Object>>) beanMap.get("children");
List<Map<Object,Object>> childrenList12 =(List<Map<Object, Object>>) childrenList11.get(0).get("children");
int b = 1;
for(Map<Object,Object> map : childrenList12){
setCell(comTableRowOne11.addNewTableCell(),(String)map.get("aswrNm"),p);
//comTableRowOne11.addNewTableCell().setText((String)map.get("aswrNm"));
comTableRowOne11.getCell(b).setColor("F4F4F4");
b++;
}//标题行结束

for(Map<Object,Object> map : childrenList11){
XWPFTableRow comTableRow = ComTable5.createRow();
setCell(comTableRow.getCell(0),(String)map.get("quNm"),p);
// comTableRow.getCell(0).setText((String)map.get("quNm"));//每行第一个为矩阵题目
List<Map<Object,Object>> map11 =(List<Map<Object, Object>>) map.get("children");
int c = 1;
for(Map<Object,Object> map12 : map11){
setCell(comTableRow.getCell(c),map12.get("count").toString()+"("+(String)map12.get("percent")+")",p);
// comTableRow.getCell(c).setText((String)map12.get("count")+"("+(String)map12.get("percent")+")");
c++;
}
}
String base64Info = (String)beanMap.get("base64Info");
if(base64Info != null){
addPicture(beanMap);
}
//换行
huanhang();
}

}
CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();
XWPFHeaderFooterPolicy policy = new XWPFHeaderFooterPolicy(document, sectPr);
sendOnest(document,out);

//  System.out.println("create_table document written success.");

//下载地址传到页面

}
//添加图片    //base64Info为前台传过来的图片信息
private void addPicture(Map map) throws IOException, InvalidFormatException {
String base64Info = (String)map.get("base64Info");
base64Info = base64Info.replaceAll(" ", "+");
String pictureInfo = (String)base64Info.split("base64,")[1];

BASE64Decoder decoder = new BASE64Decoder();
byte[] a = decoder.decodeBuffer(pictureInfo);// Base64解码
for (int i = 0; i < a.length; ++i) {
if (a[i] < 0) {// 调整异常数据
a[i] += 256;
}
}
String picId1 = document.addPictureData(a, XWPFDocument.PICTURE_TYPE_JPEG);
document.createPicture(picId1, document.getNextPicNameNumber(XWPFDocument.PICTURE_TYPE_PNG), 660, 180);
}
//换行
private void huanhang(){
XWPFParagraph paragraph = document.createParagraph();
XWPFRun paragraphRun = paragraph.createRun();
paragraphRun.setText("");
XWPFParagraph paragraph1 = document.createParagraph();
XWPFRun paragraphRun1 = paragraph1.createRun();
paragraphRun.setText("");

}

//添加图片题题目
private void addPicQueNam(Map map) throws InvalidFormatException, IOException{

XWPFParagraph paragraph = document.createParagraph();
XWPFRun queNum = paragraph.createRun();
queNum.setText(String.valueOf(t));
queNum.setColor("87CEFF");
queNum.setFontSize(12);//每一个creatRun是一个样式
XWPFRun paragraphRun = paragraph.createRun();
String quNm = (String)map.get("quNm");
paragraphRun.setText((String)map.get("quNm"));
String quPicUrlAddr = (String)map.get("quPicUrlAddr");
paragraphRun.setFontSize(10);

if(quPicUrlAddr != null){

URL picUrl = new URL(quPicUrlAddr);
//   DataInputStream pictureData = new DataInputStream(picUrl.openStream());
InputStream pictureData = picUrl.openStream();
XWPFRun quPic =paragraph.createRun();
quPic.addPicture(pictureData, XWPFDocument.PICTURE_TYPE_PNG, "", Units.toEMU(40), Units.toEMU(20));

}

t++;
}
//添加题目
private void addQueNam(Map map){

XWPFParagraph paragraph = document.createParagraph();
XWPFRun queNum = paragraph.createRun();
queNum.setText(String.valueOf(t));
queNum.setColor("87CEFF");
queNum.setFontSize(12);
XWPFRun paragraphRun = paragraph.createRun();
paragraphRun.setText((String)map.get("quNm"));
paragraphRun.setFontSize(10);
t++;
}

//设置外边框样式
private void setBorders( XWPFTable ComTable){
CTTblBorders borders=ComTable.getCTTbl().getTblPr().addNewTblBorders();
CTBorder lBorder=borders.addNewLeft();
lBorder.setVal(STBorder.Enum.forString("single"));
lBorder.setSz(new BigInteger("10"));
lBorder.setColor("F4F4F4");

CTBorder rBorder=borders.addNewRight();
rBorder.setVal(STBorder.Enum.forString("single"));
rBorder.setSz(new BigInteger("10"));
rBorder.setColor("F4F4F4");

CTBorder tBorder=borders.addNewTop();
tBorder.setVal(STBorder.Enum.forString("single"));
tBorder.setSz(new BigInteger("10"));
tBorder.setColor("F4F4F4");

CTBorder bBorder=borders.addNewBottom();
bBorder.setVal(STBorder.Enum.forString("single"));
bBorder.setSz(new BigInteger("10"));
bBorder.setColor("F4F4F4");

}
//设置图片题表格内容及对齐方式
private void setPicCell(XWPFTableCell cell,String text,String picUrlAddr, XWPFParagraph p) throws InvalidFormatException, IOException{

if(cell.getParagraphs().size()>0){
p=cell.getParagraphs().get(0);
}else{
p=cell.addParagraph();
}
XWPFRun pRun=p.createRun();
pRun.setText(text);
if(picUrlAddr != null){   //url为图片地址
URL picUrl = new URL(picUrlAddr);
InputStream pictureData = picUrl.openStream();
pRun.addPicture(pictureData, XWPFDocument.PICTURE_TYPE_PNG, "", Units.toEMU(40), Units.toEMU(20));

}

//垂直居中
cell.setVerticalAlignment(XWPFVertAlign.CENTER);
//水平居中
p.setAlignment(ParagraphAlignment.CENTER);

}

//设置表格内容及对齐方式
private void setCell(XWPFTableCell cell,String text,XWPFParagraph p){

if(cell.getParagraphs().size()>0){
p=cell.getParagraphs().get(0);
}else{
p=cell.addParagraph();
}
XWPFRun pRun=p.createRun();
pRun.setText(text);
//垂直居中
cell.setVerticalAlignment(XWPFVertAlign.CENTER);
//水平居中
p.setAlignment(ParagraphAlignment.CENTER);

}

//上传至onest
private void sendOnest(CustomXWPFDocument document,OutputObject out) throws NgqssException{

Map<String, Object> urlMap = new HashMap<>();
// 添加文件名和路径
Calendar c = Calendar.getInstance();
String fileName = DateUtil.date2String(new Date(), DATE_PATTERN.YYYYMMDDHHMMSS);
String suffix = ".zip";
String filePath = String.format("%d/%02d", c.get(Calendar.YEAR), c.get(Calendar.MONTH));
// 默认到工程路径下
ByteArrayOutputStream outstream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outstream);
String fileUrl = "";
try {
document.write(zip);
InputStream instream = getCompressed(new ByteArrayInputStream(outstream.toByteArray()),fileName);
String path = PropertiesUtil.getString(Constants.FIEL_SYSTEM_PROPERTIES, Constants.SYSTEM.ONEST_PATH);
fileUrl = ONestUtil.uploadAndGetPrivateUrl(path, filePath + "/" + fileName + suffix,
instream);
System.out.println(fileUrl);
String url = setUrl(fileUrl);
out.getBean().put("fileUrl", url);

super.sendJson(super.convertOutputObject2Json(out));
} catch (Exception e) {
System.out.println(e);
throw new NgqssException(e);
} finally {
try {
outstream.close();
} catch (IOException e) {

throw new NgqssException(e);
}
}
}

//设置url
private String setUrl(String fileUrl){

String url=null;
String outFlag = (String) getSession().getAttribute("userPermType");
if(!StringUtil.isEmpty(fileUrl)) {
String rst;
if(fileUrl.indexOf(PropertiesUtil.getString(Constants.FIEL_SYSTEM_PROPERTIES, Constants.SYSTEM.ONEST_PATH))>-1){
rst = fileUrl.substring(fileUrl.indexOf(PropertiesUtil.getString(Constants.FIEL_SYSTEM_PROPERTIES, Constants.SYSTEM.ONEST_PATH)), fileUrl.length());
HttpServletRequest request = super.getRequest();
String requestUrl = request.getHeader("Referer");
//String  headerHost = request.getHeader("Host");
String headerHost;
if("ngmtt".equals(outFlag)) {
headerHost = PropertiesUtil.getString(Constants.FIEL_SYSTEM_PROPERTIES, Constants.SYSTEM_CONFIG.NGMTT_URL);
}else {
headerHost = PropertiesUtil.getString(Constants.FIEL_SYSTEM_PROPERTIES, Constants.SYSTEM_CONFIG.NGQSS_URL);
}
String rst2 = requestUrl.substring(0, requestUrl.indexOf("://"));
url = rst2 +"://" + headerHost + "/" + rst;
}
}
return url;
}

private  ByteArrayInputStream getCompressed( InputStream is ,String fileName)
throws IOException
{
byte data[] = new byte[2048];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream( bos );
BufferedInputStream entryStream = new BufferedInputStream( is, 2048);
ZipEntry entry = new ZipEntry( fileName +".docx");
zos.putNextEntry( entry );
int count;
while ( ( count = entryStream.read( data, 0, 2048) ) != -1 )
{
zos.write( data, 0, count );
}
entryStream.close();
zos.closeEntry();
zos.close();

return new ByteArrayInputStream( bos.toByteArray() );
}
}




网上找的一些资料

http://53873039oycg.iteye.com/blog/2157923

https://wenku.baidu.com/view/6fdb6131fe4733687f21aa46.html

http://53873039oycg.iteye.com/blog/2152008?utm_source=tuicool

http://blog.csdn.net/zhyh1986/article/details/8717585

http://www.oschina.net/code/snippet_2621611_55212

http://blog.csdn.net/zhouseawater/article/details/54289495
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐