java实现pdf的生成下载打印,java生成pdf电子账单,java生成pdf合同模板,pdf账单
java实现pdf的生成下载打印,java生成pdf电子账单,java生成pdf合同模板,pdf账单
最近公司要做个生成pdf电子账单凭证的功能,由于这个公司没有任何代码可借鉴,这个时候我就必须得自己搞明白具体的每一步应该怎么做,引什么jar包?用什么方式去实现?这篇博客中会给出从头到尾及其详细的代码和工具类以及jar包,方便大家需要时直接粘贴到自己项目中,此功能完成加调试1天即可完成,此案列可以用模板套打的方式完成合同以及账单或是单纯的文案式pdf。下面先给一张最终实现的效果图片。
在看到此图的时候我首先想到两种方案,第一个是直接由java生成pdf,每一行的生成都由java代码控制。第二种使用模板套打的方式,即我有个空白的pdf模板,把需要改变的地方的值置为空白,然后通过程序去写入。很明显第二种方案简单,且效率高。java实现对pdf的编辑用到了itext技术,引用了itext的相关jar包如下:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.10</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
大家如果不是maven的项目可以去下载相应的jar包。
触发下载pdf的肯定是页面的某个按钮等,jsp页面代码如下:
function printPDF(outOrderId,serialNumber){//outOrderId,serialNumber 这是参数,可根据自己的项目需求来,window.open默认是get方式,所以参数大家需要注意一下
window.open("${ctx}/pdf/print?templateName=certificate.pdf&outOrderId="+outOrderId+"&serialNumber="+serialNumber,'_blank',
'left=0,top=0,width='+ (screen.availWidth - 10) +',height='+ (screen.availHeight-50) +',scrollbars,resizable=yes,toolbar=yes');
}
window.open方法中就不在此解释了,前面参数是访问后台的url,后面的是打开浏览器的一个新的页面和窗口。
紧跟着代码进入到后台的controller控制层,--------------------------------------------------
@RequestMapping(value = "/print")
@ResponseBody
public void pdfPrint(@RequestParam(required=false,value="templateName") String templateName,
HttpServletRequest request, HttpServletResponse response,AgentPayDetailInfo agentForm) throws Exception {
//agentPayInfo 这个对象可以根据具体的需求换成你们自己的java对象,Text1-Text13,是pdf模板上空白处的表单的key值,通过该值可以用程序编辑pdf
//组装模板所需数据HashMap
HashMap<String, String> mapPDF = new HashMap<String, String>();
mapPDF.put("Text1", DateUtil.getDateFormatYH(agentPayInfo.getFinishDate()));//交易时间
mapPDF.put("Text2", Constants.PAY_ONESELF_NAME);//付款方全称
mapPDF.put("Text3", NumberToCN.number2CNMontrayUnit(agentPayInfo.getAmount()));//金额人民币大写 汉字
mapPDF.put("Text4", agentPayInfo.getCardholder());//账户名称
mapPDF.put("Text5", agentPayInfo.getBankCardNo());//银行卡号
mapPDF.put("Text6", agentPayInfo.getBankName());//开户行
mapPDF.put("Text7", agentPayInfo.getAmount().toString());////金额人民币小写 数字
mapPDF.put("Text8", Constants.RMB);//账户类型
mapPDF.put("Text9", Constants.PAY_CERTIFICATE_TYPE);//交易类型
mapPDF.put("Text10", "");//用途
mapPDF.put("Text11", Constants.PAY_CERTIFICATE_REMARK);//备注
String receiptNumber = DateUtil.getFDate(agentPayInfo.getFinishDate()) + agentPayInfo.getOutOrderId() + agentPayInfo.getSerialNumber();
mapPDF.put("Text12", "电子回单编号:" + receiptNumber);//电子回单编号
mapPDF.put("Text13", DateUtil.getFormatDate(agentPayInfo.getFinishDate()));//章子时间
//生成pdf
pdfStream = this.print(templateName, mapPDF, request);
ServletOutputStream op = response.getOutputStream();
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "inline; filename=\""
+ new String(receiptNumber.getBytes("gb18030"), "ISO8859-1") + ".pdf" + "\"");
int length = 0;
byte[] bytes = new byte[1024];
while ((pdfStream != null) && ((length = pdfStream.read(bytes)) != -1)) {
op.write(bytes, 0, length);
}
op.close();
response.flushBuffer();
}
/**
* 打印,以PDF为模板
* @param templateName String 模板名字
* @param map 模板数据HashMap
* @return InputStream
* @throws IOException
*/
private InputStream print(String templateName, HashMap map, HttpServletRequest request) throws IOException {
InputStream is = null;
//服务器端PDF模板文件名
//String merchId = getCurrentUser().getMerchId();
String realPath = request.getSession().getServletContext().getRealPath("/");
String web_info_URL = PropertyUtils.getValue("WEB_INFO_URL");
String agentPayPath = PropertyUtils.getValue("PDF_PATH");
String url = realPath + web_info_URL + agentPayPath;// pdf
String templatePath = url + "/model/";//模板路径
String serverPath = url + "/template/";//临时文件路径
PdfFormater pdf = new PdfFormater(templatePath, serverPath, templateName, map);
String PdfFilePath = pdf.doTransform();
is = new FileInputStream(PdfFilePath);
return is;
}
------------------------------------------------------------------------------------------------------------------------
输出给页面是用的ServletOutputStream,设置了response的.setContentType("application/pdf"); 文件为pdf,,这种方式下载和打印方法由客户端自己电脑上的flash和浏览器去完成,省去了服务端的一部分功能。
小写数字转化大写汉字 金额的工具类可以网上搜索一个NumberToCN.number2CNMontrayUnit()这个也是我自己从网上搜索的
PdfFormater 类-------------------------
public class PdfFormater {
//pdf模板和结果路径相关设置
private String templateDir;
private String basePath;
private String templateFileFo;
//需填充数据
private Map dataMap;
private String barcodeString;
private String tempFileName;
private String resultFileName;
//动态数据
private List dynData;
/**
* 构造器,生成PDF引擎实例,并引入相应模板文件XXX.FO、路径和报表数据HashMap
*
* @param templateDir
* 模板文件所在目录
* @param basePath
* 模板文件工作副本及结果PDF文件所在工作目录
* @param templateFileFo
* 模板文件名,推荐格式为“XXXTemplate.FO”, 其文件由word模板文档在设计时转换而成
* @param dataMap
* 对应模板的数据HashMap,由调用该打印引擎的里程根据模板格式和约定进行准备
*/
public PdfFormater(String templateDir, String basePath,
String templateFileFo, Map dataMap) {
this.templateDir = templateDir;
this.basePath = basePath;
this.templateFileFo = templateFileFo;
this.dataMap = dataMap;
}
private BaseFont getBaseFont(Object obj) {
// 需要根据不同的模板返回字体
BaseFont bf = null;
try {
/*bf = BaseFont.createFont("simsun.ttf",
BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);*/
bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bf;
}
public String doTransform() {
long name = System.currentTimeMillis();
tempFileName = "temp" + name + ".pdf";
resultFileName = "best" + name + ".pdf";
try {
PdfReader reader;
PdfStamper stamper;
reader = new PdfReader(templateDir + "/" + templateFileFo);
stamper = new PdfStamper(reader, new FileOutputStream(basePath + "/" + tempFileName));
AcroFields form = stamper.getAcroFields();
form.addSubstitutionFont(getBaseFont(""));
transformRegular(form);
stamper.setFormFlattening(true);
stamper.close();
postProcess();
//FileOutputStream fos = new FileOutputStream(basePath + "/" + tempFileName);
} catch (Exception e) {
e.printStackTrace();
}
return basePath + "/" + resultFileName;
}
/**
* 填充规整的表单域
*
* @param form
*/
private void transformRegular(AcroFields form) {
if (dataMap == null || dataMap.size() == 0)
return;
String key = "";
Iterator ekey = dataMap.keySet().iterator();
Object obj = null ;
while (ekey.hasNext()) {
key = ekey.next().toString();
try {
obj = dataMap.get(key);
if(obj instanceof List) {
//map中放的是list,为动态字段
dynData = (List)obj;
transformDynTable(form);
}else{
//非空放入
if( dataMap.get(key) != null)
form.setField(key, dataMap.get(key).toString());
}
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
/**
* 动态table的填充
* @param form
*/
private void transformDynTable(AcroFields form) {
if (dynData == null || dynData.size() == 0)
return;
Object obj = null;
ReflectUtils rutil = new ReflectUtils();
String name = "";
String value = "";
for (int x = 0; x < dynData.size(); x++) {
obj = dynData.get(x);
Field[] fld = obj.getClass().getDeclaredFields();
for (int i = 0; i < fld.length; i++) {
name = fld[i].getName();
value = (String) rutil.getFieldValue(obj, name);
try {
form.setField(name + x, value);
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
}
/**
* 对生成的pdf文件进行后处理
*
* @throws RptException
*/
private synchronized void postProcess() throws Exception {
FileOutputStream fosRslt = null;
PdfStamper stamper = null;
try {
PdfReader reader = new PdfReader(basePath + "/" + tempFileName);
fosRslt = new FileOutputStream(basePath + "/" + resultFileName);
stamper = new PdfStamper(reader, fosRslt);
Rectangle pageSize = reader.getPageSize(1);
float width = pageSize.getWidth();
//float height = pageSize.getHeight();
/*BaseFont bf = BaseFont.createFont("simsun.ttf",
BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);*/
BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
/*BaseFont bfComic = BaseFont.createFont("simhei.ttf",
BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);*/
PdfContentByte over;
int total = reader.getNumberOfPages() + 1;
for (int i = 1; i < total; i++) {
over = stamper.getOverContent(i);
if (total <= 2) break;
over.beginText();
over.setFontAndSize(bf, 10);
over.setTextMatrix(width - 92f, 32);
over.showText("第 " + i + " 页");
over.endText();
}
} catch (Exception ie) {
ie.printStackTrace();
} finally {
if (stamper != null) {
try {
stamper.close();
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fosRslt != null) {
try {
fosRslt.close();
} catch (IOException e) {
e.printStackTrace();
}
}
File pdfFile = new File(basePath, "/" + tempFileName);
pdfFile.delete();
}
}
}
---------------------------------------------------------------------------------------
本地项目pdf模板路径:
接下来说一下这个模板的问题,我们需要根据需求去自己编辑pdf,而编辑pdf的软件一般是收费的,我这边是用的迅捷PDF编辑器,然后加水印后用AI编辑器删除水印。给大家截图哈还是:
这个章子是一个图片添加进去的,章子的中间是没有日期的,这个中间的日期因为是可变的,所以需要作为一个表单由程序去写入具体的值,在点击编辑内容时,如图所示,右侧有属性什么的,很好使用的。我们看到表单需要填写内容的区域为空白区域,然后我们点击编辑表单按钮出现如图所示的:
域名就是程序中的map的key值,通过这个程序把内容写入到pdf具体的位置,可以设置字体大小,颜色,边框,对齐方式等。
再看一下项目运行后的的效果,在点击某个按钮后,浏览器会弹出个新的窗口如图所示:
好了,模板套打的基本说完了,在PdfFormater类中有些对页数的设置,页眉页脚都可以用类似的方法去实现,合同模板套打的案例我就不给出了。
还有一些本地生成pdf文件的:
public class PDFBillUtil {//(此工具类转载 http://blog.csdn.net/justinytsoft/article/details/53320225)
public static void createBillPDF(BillPDF billPDF) {
try {
// 输出路径
String outPath = "C:/Users/Administrator/Desktop/Helloworld.PDF";
// 设置纸张
Rectangle rect = new Rectangle(PageSize.A4);
// 创建文档实例
Document document = new Document(rect);
PdfWriter.getInstance(document, new FileOutputStream(outPath));
// 设置字体
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
com.itextpdf.text.Font FontChinese24 = new com.itextpdf.text.Font(bfChinese, 24,
com.itextpdf.text.Font.BOLD);
com.itextpdf.text.Font FontChinese18 = new com.itextpdf.text.Font(bfChinese, 18,
com.itextpdf.text.Font.BOLD);
com.itextpdf.text.Font FontChinese16 = new com.itextpdf.text.Font(bfChinese, 16,
com.itextpdf.text.Font.BOLD);
com.itextpdf.text.Font FontChinese12 = new com.itextpdf.text.Font(bfChinese, 12,
com.itextpdf.text.Font.NORMAL);
com.itextpdf.text.Font FontChinese11Bold = new com.itextpdf.text.Font(bfChinese, 11,
com.itextpdf.text.Font.BOLD);
com.itextpdf.text.Font FontChinese11 = new com.itextpdf.text.Font(bfChinese, 11,
com.itextpdf.text.Font.ITALIC);
com.itextpdf.text.Font FontChinese11Normal = new com.itextpdf.text.Font(bfChinese, 11,
com.itextpdf.text.Font.NORMAL);
document.open();
// table1
PdfPTable table1 = new PdfPTable(3);
PdfPCell cell11 = new PdfPCell(new Paragraph("费用报销", FontChinese24));
cell11.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell11.setHorizontalAlignment(Element.ALIGN_CENTER);
cell11.setBorder(0);
String imagePath = "D:/111.jpg";
Image image1 = Image.getInstance(imagePath);
Image image2 = Image.getInstance(imagePath);
// 设置每列宽度比例
int width11[] = { 35, 40, 25 };
table1.setWidths(width11);
table1.getDefaultCell().setBorder(0);
table1.addCell(image1);
table1.addCell(cell11);
table1.addCell(image2);
document.add(table1);
// 加入空行
Paragraph blankRow1 = new Paragraph(18f, " ", FontChinese18);
document.add(blankRow1);
// table2
PdfPTable table2 = new PdfPTable(2);
// 设置每列宽度比例
int width21[] = { 2, 98 };
table2.setWidths(width21);
table2.getDefaultCell().setBorder(0);
PdfPCell cell21 = new PdfPCell(new Paragraph("报销概要", FontChinese16));
String imagePath2 = "D:/111.jpg";
Image image21 = Image.getInstance(imagePath2);
cell21.setBorder(0);
table2.addCell(image21);
table2.addCell(cell21);
document.add(table2);
// 加入空行
Paragraph blankRow2 = new Paragraph(18f, " ", FontChinese18);
document.add(blankRow2);
// table3
PdfPTable table3 = new PdfPTable(3);
int width3[] = { 40, 35, 25 };
table3.setWidths(width3);
PdfPCell cell31 = new PdfPCell(new Paragraph("申请人:" + "XXX", FontChinese11Normal));
PdfPCell cell32 = new PdfPCell(new Paragraph("日期:" + "2011-11-11", FontChinese11Normal));
PdfPCell cell33 = new PdfPCell(new Paragraph("报销单号:" + "123456789", FontChinese11Normal));
cell31.setBorder(0);
cell32.setBorder(0);
cell33.setBorder(0);
table3.addCell(cell31);
table3.addCell(cell32);
table3.addCell(cell33);
document.add(table3);
// 加入空行
Paragraph blankRow31 = new Paragraph(18f, " ", FontChinese11);
document.add(blankRow31);
// table4
PdfPTable table4 = new PdfPTable(2);
int width4[] = { 40, 60 };
table4.setWidths(width4);
PdfPCell cell41 = new PdfPCell(new Paragraph("公司:" + "XXX", FontChinese11Normal));
PdfPCell cell42 = new PdfPCell(new Paragraph("部门:" + "XXX", FontChinese11Normal));
cell41.setBorder(0);
cell42.setBorder(0);
table4.addCell(cell41);
table4.addCell(cell42);
document.add(table4);
// 加入空行
Paragraph blankRow41 = new Paragraph(18f, " ", FontChinese11);
document.add(blankRow41);
// table5
PdfPTable table5 = new PdfPTable(1);
PdfPCell cell51 = new PdfPCell(new Paragraph("报销说明:" + "XXX", FontChinese11));
cell51.setBorder(0);
table5.addCell(cell51);
document.add(table5);
// 加入空行
Paragraph blankRow51 = new Paragraph(18f, " ", FontChinese18);
document.add(blankRow51);
// table6
PdfPTable table6 = new PdfPTable(2);
table6.getDefaultCell().setBorder(0);
table6.setWidths(width21);
PdfPCell cell61 = new PdfPCell(new Paragraph("报销明细", FontChinese16));
cell61.setBorder(0);
table6.addCell(image21);
table6.addCell(cell61);
document.add(table6);
// 加入空行
Paragraph blankRow4 = new Paragraph(18f, " ", FontChinese16);
document.add(blankRow4);
// table7
PdfPTable table7 = new PdfPTable(6);
BaseColor lightGrey = new BaseColor(0xCC, 0xCC, 0xCC);
int width7[] = { 20, 18, 13, 20, 14, 15 };
table7.setWidths(width7);
PdfPCell cell71 = new PdfPCell(new Paragraph("费用类型", FontChinese11Bold));
PdfPCell cell72 = new PdfPCell(new Paragraph("费用发生时间", FontChinese11Bold));
PdfPCell cell73 = new PdfPCell(new Paragraph("详细信息", FontChinese11Bold));
PdfPCell cell74 = new PdfPCell(new Paragraph("消费金币/币种", FontChinese11Bold));
PdfPCell cell75 = new PdfPCell(new Paragraph("报销汇率", FontChinese11Bold));
PdfPCell cell76 = new PdfPCell(new Paragraph("报销金额", FontChinese11Bold));
// 表格高度
cell71.setFixedHeight(25);
cell72.setFixedHeight(25);
cell73.setFixedHeight(25);
cell74.setFixedHeight(25);
cell75.setFixedHeight(25);
cell76.setFixedHeight(25);
// 水平居中
cell71.setHorizontalAlignment(Element.ALIGN_CENTER);
cell72.setHorizontalAlignment(Element.ALIGN_CENTER);
cell73.setHorizontalAlignment(Element.ALIGN_CENTER);
cell74.setHorizontalAlignment(Element.ALIGN_CENTER);
cell75.setHorizontalAlignment(Element.ALIGN_CENTER);
cell76.setHorizontalAlignment(Element.ALIGN_CENTER);
// 垂直居中
cell71.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell72.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell73.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell74.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell75.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell76.setVerticalAlignment(Element.ALIGN_MIDDLE);
// 边框颜色
cell71.setBorderColor(lightGrey);
cell72.setBorderColor(lightGrey);
cell73.setBorderColor(lightGrey);
cell74.setBorderColor(lightGrey);
cell75.setBorderColor(lightGrey);
cell76.setBorderColor(lightGrey);
// 去掉左右边框
cell71.disableBorderSide(8);
cell72.disableBorderSide(4);
cell72.disableBorderSide(8);
cell73.disableBorderSide(4);
cell73.disableBorderSide(8);
cell74.disableBorderSide(4);
cell74.disableBorderSide(8);
cell75.disableBorderSide(4);
cell75.disableBorderSide(8);
cell76.disableBorderSide(4);
table7.addCell(cell71);
table7.addCell(cell72);
table7.addCell(cell73);
table7.addCell(cell74);
table7.addCell(cell75);
table7.addCell(cell76);
document.add(table7);
// table8
PdfPTable table8 = new PdfPTable(6);
int width8[] = { 20, 18, 13, 20, 14, 15 };
table8.setWidths(width8);
PdfPCell cell81 = new PdfPCell(new Paragraph("差旅报销", FontChinese12));
PdfPCell cell82 = new PdfPCell(new Paragraph("2011-11-11", FontChinese12));
PdfPCell cell83 = new PdfPCell(new Paragraph("XXX", FontChinese12));
PdfPCell cell84 = new PdfPCell(new Paragraph("XXX", FontChinese12));
PdfPCell cell85 = new PdfPCell(new Paragraph("XXX", FontChinese12));
PdfPCell cell86 = new PdfPCell(new Paragraph("XXX", FontChinese12));
// 表格高度
cell81.setFixedHeight(25);
cell82.setFixedHeight(25);
cell83.setFixedHeight(25);
cell84.setFixedHeight(25);
cell85.setFixedHeight(25);
cell86.setFixedHeight(25);
// 水平居中
cell81.setHorizontalAlignment(Element.ALIGN_CENTER);
cell82.setHorizontalAlignment(Element.ALIGN_CENTER);
cell83.setHorizontalAlignment(Element.ALIGN_CENTER);
cell84.setHorizontalAlignment(Element.ALIGN_CENTER);
cell85.setHorizontalAlignment(Element.ALIGN_CENTER);
cell86.setHorizontalAlignment(Element.ALIGN_CENTER);
// 垂直居中
cell81.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell82.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell83.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell84.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell85.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell86.setVerticalAlignment(Element.ALIGN_MIDDLE);
// 边框颜色
cell81.setBorderColor(lightGrey);
cell82.setBorderColor(lightGrey);
cell83.setBorderColor(lightGrey);
cell84.setBorderColor(lightGrey);
cell85.setBorderColor(lightGrey);
cell86.setBorderColor(lightGrey);
// 去掉左右边框
cell81.disableBorderSide(8);
cell82.disableBorderSide(4);
cell82.disableBorderSide(8);
cell83.disableBorderSide(4);
cell83.disableBorderSide(8);
cell84.disableBorderSide(4);
cell84.disableBorderSide(8);
cell85.disableBorderSide(4);
cell85.disableBorderSide(8);
cell86.disableBorderSide(4);
table8.addCell(cell81);
table8.addCell(cell82);
table8.addCell(cell83);
table8.addCell(cell84);
table8.addCell(cell85);
table8.addCell(cell86);
document.add(table8);
// 加入空行
Paragraph blankRow5 = new Paragraph(18f, " ", FontChinese18);
document.add(blankRow5);
// table9
PdfPTable table9 = new PdfPTable(3);
int width9[] = { 30, 50, 20 };
table9.setWidths(width9);
PdfPCell cell91 = new PdfPCell(new Paragraph("", FontChinese12));
PdfPCell cell92 = new PdfPCell(new Paragraph("收到的报销金额", FontChinese12));
PdfPCell cell93 = new PdfPCell(new Paragraph("1000", FontChinese24));
cell92.setHorizontalAlignment(Element.ALIGN_RIGHT);
cell92.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell93.setHorizontalAlignment(Element.ALIGN_LEFT);
cell93.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell91.setBorder(0);
cell92.setBorder(0);
cell93.setBorder(0);
table9.addCell(cell91);
table9.addCell(cell92);
table9.addCell(cell93);
document.add(table9);
document.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
BillPDF billPDF = new BillPDF();
createBillPDF(billPDF);
}
}
将图片等信息修改后可以直接运行。通过完全用java代码生成的这个案例可以更好的理解java对pdf的操作的一些属性和方法等。
相关文章
- 暂无相关文章
用户点评