|
@@ -3,7 +3,6 @@ package cn.com.qmth.examcloud.core.questions.base.word;
|
|
|
import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
|
|
|
import cn.com.qmth.examcloud.core.questions.base.ZipUtils;
|
|
|
import cn.com.qmth.examcloud.core.questions.base.enums.QuesUnit;
|
|
|
-
|
|
|
import freemarker.template.Configuration;
|
|
|
import freemarker.template.Template;
|
|
|
import net.sf.saxon.TransformerFactoryImpl;
|
|
@@ -11,7 +10,6 @@ import net.sourceforge.jeuclid.LayoutContext;
|
|
|
import net.sourceforge.jeuclid.context.LayoutContextImpl;
|
|
|
import net.sourceforge.jeuclid.context.StyleAttributeLayoutContext;
|
|
|
import net.sourceforge.jeuclid.converter.Converter;
|
|
|
-
|
|
|
import org.apache.commons.codec.binary.Base64;
|
|
|
import org.apache.commons.io.FileUtils;
|
|
|
import org.apache.commons.io.IOUtils;
|
|
@@ -33,6 +31,7 @@ import org.docx4j.openpackaging.exceptions.Docx4JException;
|
|
|
import org.docx4j.openpackaging.io3.stores.ZipPartStore;
|
|
|
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
|
|
import org.docx4j.openpackaging.parts.Part;
|
|
|
+import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPart;
|
|
|
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
|
|
|
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
|
|
|
import org.docx4j.openpackaging.parts.relationships.Namespaces;
|
|
@@ -60,25 +59,9 @@ import javax.xml.transform.TransformerFactory;
|
|
|
import javax.xml.transform.dom.DOMSource;
|
|
|
import javax.xml.transform.stream.StreamResult;
|
|
|
import javax.xml.transform.stream.StreamSource;
|
|
|
-
|
|
|
import java.awt.image.BufferedImage;
|
|
|
-import java.io.BufferedWriter;
|
|
|
-import java.io.ByteArrayInputStream;
|
|
|
-import java.io.ByteArrayOutputStream;
|
|
|
-import java.io.File;
|
|
|
-import java.io.FileInputStream;
|
|
|
-import java.io.FileOutputStream;
|
|
|
-import java.io.InputStream;
|
|
|
-import java.io.OutputStream;
|
|
|
-import java.io.OutputStreamWriter;
|
|
|
-import java.io.StringReader;
|
|
|
-import java.io.StringWriter;
|
|
|
-import java.io.Writer;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.HashSet;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Set;
|
|
|
-import java.util.UUID;
|
|
|
+import java.io.*;
|
|
|
+import java.util.*;
|
|
|
import java.util.regex.Matcher;
|
|
|
import java.util.regex.Pattern;
|
|
|
import java.util.zip.ZipOutputStream;
|
|
@@ -88,13 +71,13 @@ import java.util.zip.ZipOutputStream;
|
|
|
*/
|
|
|
public final class DocxProcessUtil {
|
|
|
|
|
|
- private static final Logger logger = LoggerFactory.getLogger(DocxProcessUtil.class);
|
|
|
-
|
|
|
+ private static final Logger logger = LoggerFactory.getLogger(DocxProcessUtil.class);
|
|
|
+
|
|
|
public static final LayoutContext IMG_LAYOUT = new StyleAttributeLayoutContext(
|
|
|
LayoutContextImpl.getDefaultLayoutContext(), "2em", java.awt.Color.BLACK);
|
|
|
-
|
|
|
+
|
|
|
public static Configuration configuration;
|
|
|
-
|
|
|
+
|
|
|
public static final String IMG_OUT_TYPE = "image/png";
|
|
|
|
|
|
public static final String ENCODING = "utf-8";
|
|
@@ -179,14 +162,14 @@ public final class DocxProcessUtil {
|
|
|
*/
|
|
|
public static boolean isNumPr(P p) {
|
|
|
PPr pPr = p.getPPr();
|
|
|
- if(pPr != null){
|
|
|
+ if (pPr != null) {
|
|
|
PPrBase.NumPr numPr = pPr.getNumPr();
|
|
|
if (numPr != null && numPr.getNumId() != null) {
|
|
|
return true;
|
|
|
} else {
|
|
|
return false;
|
|
|
}
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
@@ -324,7 +307,7 @@ public final class DocxProcessUtil {
|
|
|
"http://schemas.openxmlformats.org/officeDocument/2006/math", "oMath", CTOMath.class);
|
|
|
byte[] imgByte = convertMathml2Img(omml2mml(omml));
|
|
|
pContent.set(index, newImage(wordMLPackage, imgByte, "math" + (index), "math" + (index)));
|
|
|
- }else if(child.getClass().equals(CTOMathPara.class)){
|
|
|
+ } else if (child.getClass().equals(CTOMathPara.class)) {
|
|
|
String omml = XmlUtils.marshaltoString(child, true, true, Context.jc,
|
|
|
"http://schemas.openxmlformats.org/officeDocument/2006/math", "oMathPara", CTOMathPara.class);
|
|
|
byte[] imgByte = convertMathml2Img(omml2mml(omml));
|
|
@@ -393,7 +376,7 @@ public final class DocxProcessUtil {
|
|
|
* @param omml
|
|
|
* @return
|
|
|
*/
|
|
|
- public static String omml2mml(String omml)throws Exception {
|
|
|
+ public static String omml2mml(String omml) throws Exception {
|
|
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
|
|
InputStream stylesheet = DocxProcessUtil.class.getClassLoader().getResourceAsStream(OMML2MML_XSL);
|
|
|
StringReader sr = new StringReader(omml);
|
|
@@ -447,9 +430,9 @@ public final class DocxProcessUtil {
|
|
|
* @param htmlStr
|
|
|
* @return
|
|
|
*/
|
|
|
- public static String getTextInHtml(String htmlStr){
|
|
|
+ public static String getTextInHtml(String htmlStr) {
|
|
|
htmlStr = htmlStr.replaceAll("\\&[a-zA-Z]{1,10};", "").trim();
|
|
|
- if(!htmlStr.startsWith("<p>")){
|
|
|
+ if (!htmlStr.startsWith("<p>")) {
|
|
|
return htmlStr;
|
|
|
}
|
|
|
try {
|
|
@@ -612,14 +595,14 @@ public final class DocxProcessUtil {
|
|
|
|
|
|
// 过滤题干标题
|
|
|
if (tmpText.matches("^\\d{1,}\\.[\\s\\S]*")) {
|
|
|
- tmpText = tmpText.replaceFirst("\\d{1,}\\.","");
|
|
|
+ tmpText = tmpText.replaceFirst("\\d{1,}\\.", "");
|
|
|
text.setValue(tmpText);
|
|
|
return p;
|
|
|
- } else if(tmpText.matches("^\\d{1,}$")){
|
|
|
- tmpText = tmpText.replaceFirst("\\d{1,}","");
|
|
|
+ } else if (tmpText.matches("^\\d{1,}$")) {
|
|
|
+ tmpText = tmpText.replaceFirst("\\d{1,}", "");
|
|
|
text.setValue(tmpText);
|
|
|
- } else if(tmpText.contains(".")){
|
|
|
- tmpText = tmpText.replaceFirst("\\.","");
|
|
|
+ } else if (tmpText.contains(".")) {
|
|
|
+ tmpText = tmpText.replaceFirst("\\.", "");
|
|
|
text.setValue(tmpText);
|
|
|
return p;
|
|
|
}
|
|
@@ -628,14 +611,14 @@ public final class DocxProcessUtil {
|
|
|
|
|
|
// 过滤选项标题
|
|
|
if (tmpText.matches("^[A-Z]\\.[\\s\\S]*")) {
|
|
|
- tmpText = tmpText.replaceFirst("[A-Z]\\.","");
|
|
|
+ tmpText = tmpText.replaceFirst("[A-Z]\\.", "");
|
|
|
text.setValue(tmpText);
|
|
|
return p;
|
|
|
- } else if(tmpText.matches("^[A-Z]$")){
|
|
|
- tmpText = tmpText.replaceFirst("[A-Z]","");
|
|
|
+ } else if (tmpText.matches("^[A-Z]$")) {
|
|
|
+ tmpText = tmpText.replaceFirst("[A-Z]", "");
|
|
|
text.setValue(tmpText);
|
|
|
- } else if(tmpText.contains(".")){
|
|
|
- tmpText = tmpText.replaceFirst("\\.","");
|
|
|
+ } else if (tmpText.contains(".")) {
|
|
|
+ tmpText = tmpText.replaceFirst("\\.", "");
|
|
|
text.setValue(tmpText);
|
|
|
return p;
|
|
|
}
|
|
@@ -643,11 +626,11 @@ public final class DocxProcessUtil {
|
|
|
} else if (quesUnit == QuesUnit.QUES_ANSWER) {
|
|
|
|
|
|
// 过滤答案标题
|
|
|
- if(index <= 4){
|
|
|
- tmpText = tmpText.replaceFirst("\\[","").replaceFirst("\\]","")
|
|
|
- .replaceFirst("答案","").replaceFirst("[:|:]","");
|
|
|
+ if (index <= 4) {
|
|
|
+ tmpText = tmpText.replaceFirst("\\[", "").replaceFirst("\\]", "")
|
|
|
+ .replaceFirst("答案", "").replaceFirst("[:|:]", "");
|
|
|
text.setValue(tmpText);
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
return p;
|
|
|
}
|
|
|
// if(tmpText.contains(":") || tmpText.contains(":")){
|
|
@@ -673,15 +656,16 @@ public final class DocxProcessUtil {
|
|
|
|
|
|
/**
|
|
|
* 导出word
|
|
|
+ *
|
|
|
* @param dataModel
|
|
|
* @param fileName
|
|
|
* @param template
|
|
|
- * @throws Exception File outFile = new File(TEMP_FILE_EXP+fileName);
|
|
|
+ * @throws Exception File outFile = new File(TEMP_FILE_EXP+fileName);
|
|
|
*/
|
|
|
- public static void exportWord(Object dataModel, String fileName,Template template)throws Exception {
|
|
|
+ public static void exportWord(Object dataModel, String fileName, Template template) throws Exception {
|
|
|
Writer out = null;
|
|
|
// 输出文件
|
|
|
- File outFile = new File(TEMP_FILE_EXP+fileName);
|
|
|
+ File outFile = new File(TEMP_FILE_EXP + fileName);
|
|
|
// 将模板和数据模型合并生成文件
|
|
|
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), ENCODING));
|
|
|
// 生成文件
|
|
@@ -692,13 +676,14 @@ public final class DocxProcessUtil {
|
|
|
|
|
|
/**
|
|
|
* 导出wordnew
|
|
|
+ *
|
|
|
* @param dataModel
|
|
|
* @param outFile
|
|
|
* @param template
|
|
|
* @throws Exception
|
|
|
*/
|
|
|
- public static void exportWordNew(Object dataModel, File outFile,Template template)throws Exception {
|
|
|
- Writer out = null;
|
|
|
+ public static void exportWordNew(Object dataModel, File outFile, Template template) throws Exception {
|
|
|
+ Writer out = null;
|
|
|
// 将模板和数据模型合并生成文件
|
|
|
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), ENCODING));
|
|
|
// 生成文件
|
|
@@ -707,14 +692,28 @@ public final class DocxProcessUtil {
|
|
|
IOUtils.closeQuietly(out);
|
|
|
}
|
|
|
|
|
|
+ public static boolean hasImage(String html) throws Exception {
|
|
|
+ if (html == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ String reg = "<\\s*img\\s+([^>]*)\\s*>";
|
|
|
+ Pattern pattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);
|
|
|
+ Matcher matcher = pattern.matcher(html);
|
|
|
+ if (matcher.find()) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 处理导出word中的图片
|
|
|
- * @param fileName 需要带文件后缀
|
|
|
+ *
|
|
|
+ * @param fileName 需要带文件后缀
|
|
|
* @param wordMLPackages
|
|
|
* @throws Exception
|
|
|
*/
|
|
|
public static void processImage(String fileName, List<WordprocessingMLPackage> wordMLPackages) throws Exception {
|
|
|
- logger.info("试卷:“"+fileName+"”导出处理图片开始...");
|
|
|
+ logger.info("试卷:“" + fileName + "”导出处理图片开始...");
|
|
|
String filePath = TEMP_FILE_EXP + fileName;
|
|
|
InputStream mainFile = new FileInputStream(filePath);
|
|
|
// 取到当前生成的主Word
|
|
@@ -723,9 +722,9 @@ public final class DocxProcessUtil {
|
|
|
//构建relationships
|
|
|
RelationshipsPart relationshipsPart = wordMLPackage.getMainDocumentPart().getRelationshipsPart();
|
|
|
for (WordprocessingMLPackage wp : wordMLPackages) {
|
|
|
- if(wp==null){
|
|
|
- continue;
|
|
|
- }
|
|
|
+ if (wp == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
// 获取资源文件存储
|
|
|
ZipPartStore partStore = (ZipPartStore) wp.getSourcePartStore();
|
|
|
// 获取图片资源定义、只取图片
|
|
@@ -740,8 +739,17 @@ public final class DocxProcessUtil {
|
|
|
for (Part p : parts) {
|
|
|
String relId = p.getSourceRelationships().get(0).getId();
|
|
|
//如果不存在该relId,拷贝图片
|
|
|
- if(!relationshipsPart.isRelIdOccupied(relId)){
|
|
|
- copyImage(wordMLPackage,partStore,p,relId);
|
|
|
+ if (!relationshipsPart.isRelIdOccupied(relId)) {
|
|
|
+ byte[] bytes = null;
|
|
|
+ if (partStore != null) {
|
|
|
+ bytes = partStore.getByteArray(p.getPartName().getName().substring(1)).getBytes();
|
|
|
+ } else {
|
|
|
+ if (p instanceof BinaryPart) {
|
|
|
+ BinaryPart imagePart = (BinaryPart) p;
|
|
|
+ bytes = imagePart.getBytes();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ copyImage(wordMLPackage, bytes, relId);
|
|
|
}
|
|
|
}
|
|
|
// 添加资源文件存储
|
|
@@ -751,27 +759,40 @@ public final class DocxProcessUtil {
|
|
|
OutputStream os = new FileOutputStream(filePath);
|
|
|
Docx4J.save(wordMLPackage, os, Docx4J.FLAG_SAVE_ZIP_FILE);
|
|
|
IOUtils.closeQuietly(os);
|
|
|
- logger.info("试卷:“"+fileName+"”导出处理图片结束");
|
|
|
+ logger.info("试卷:“" + fileName + "”导出处理图片结束");
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void copyImage(WordprocessingMLPackage wordMLPackage, byte[] bytes, String relId) throws Exception {
|
|
|
+ if (bytes == null || bytes.length == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
|
|
+ BufferedImage bi1 = ImageIO.read(bais);
|
|
|
+ if (bi1 != null) {
|
|
|
+ BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
|
|
|
+ imagePart.getRelLast().setId(relId);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* word合并时复制图片
|
|
|
* 将partStore中的Relationship复制到wordMLPackage中
|
|
|
+ *
|
|
|
* @param wordMLPackage
|
|
|
* @param partStore
|
|
|
* @param p
|
|
|
* @throws Exception
|
|
|
*/
|
|
|
- public static void copyImage(WordprocessingMLPackage wordMLPackage, ZipPartStore partStore, Part p,String relId)throws Exception{
|
|
|
- byte [] bytes = partStore.getByteArray(p.getPartName().getName().substring(1)).getBytes();
|
|
|
- ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
|
|
+ public static void copyImage(WordprocessingMLPackage wordMLPackage, ZipPartStore partStore, Part p, String relId) throws Exception {
|
|
|
+ byte[] bytes = partStore.getByteArray(p.getPartName().getName().substring(1)).getBytes();
|
|
|
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
|
|
BufferedImage bi1 = ImageIO.read(bais);
|
|
|
- if(bi1!=null){
|
|
|
- BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
|
|
|
+ if (bi1 != null) {
|
|
|
+ BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
|
|
|
imagePart.getRelLast().setId(relId);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* 获取word二进制数据(空文档,只有样式和资源)
|
|
|
*
|
|
@@ -853,37 +874,39 @@ public final class DocxProcessUtil {
|
|
|
|
|
|
/**
|
|
|
* 下载word文件
|
|
|
- * @param fileNames 需带后缀
|
|
|
+ *
|
|
|
+ * @param fileNames 需带后缀
|
|
|
* @param response
|
|
|
* @throws Exception
|
|
|
*/
|
|
|
- public static void processDownload(List<String> fileNames, HttpServletResponse response) throws Exception {
|
|
|
- String zipFileName = fileNames.get(0);
|
|
|
- response.setHeader("Content-Disposition","attachment; filename="+new String(zipFileName.getBytes("UTF-8"), "iso-8859-1")+".zip");
|
|
|
- // 设置强制下载不打开
|
|
|
- response.setContentType("application/octet-stream;charset=utf-8");
|
|
|
- ZipOutputStream out = new ZipOutputStream(response.getOutputStream());
|
|
|
- for(String fileName:fileNames){
|
|
|
- ZipUtils.doCompress(TEMP_FILE_EXP+fileName, out);
|
|
|
+ public static void processDownload(List<String> fileNames, HttpServletResponse response) throws Exception {
|
|
|
+ String zipFileName = fileNames.get(0);
|
|
|
+ response.setHeader("Content-Disposition", "attachment; filename=" + new String(zipFileName.getBytes("UTF-8"), "iso-8859-1") + ".zip");
|
|
|
+ // 设置强制下载不打开
|
|
|
+ response.setContentType("application/octet-stream;charset=utf-8");
|
|
|
+ ZipOutputStream out = new ZipOutputStream(response.getOutputStream());
|
|
|
+ for (String fileName : fileNames) {
|
|
|
+ ZipUtils.doCompress(TEMP_FILE_EXP + fileName, out);
|
|
|
response.flushBuffer();
|
|
|
}
|
|
|
//删除本地文件
|
|
|
- for(String fileName:fileNames){
|
|
|
- File file = new File(TEMP_FILE_EXP+fileName);
|
|
|
- if(file.exists()){
|
|
|
- file.delete();
|
|
|
- }
|
|
|
+ for (String fileName : fileNames) {
|
|
|
+ File file = new File(TEMP_FILE_EXP + fileName);
|
|
|
+ if (file.exists()) {
|
|
|
+ file.delete();
|
|
|
+ }
|
|
|
}
|
|
|
out.close();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* html转word
|
|
|
+ *
|
|
|
* @param html
|
|
|
* @return
|
|
|
* @throws Exception
|
|
|
*/
|
|
|
- public static String html2Docx(WordprocessingMLPackage wordMLPackage,String html)throws Exception {
|
|
|
+ public static String html2Docx(WordprocessingMLPackage wordMLPackage, String html) throws Exception {
|
|
|
initTmpPackage(wordMLPackage);
|
|
|
RFonts rfonts = Context.getWmlObjectFactory().createRFonts();
|
|
|
rfonts.setAscii("eastAsia");
|
|
@@ -892,12 +915,12 @@ public final class DocxProcessUtil {
|
|
|
XHTMLImporter.setHyperlinkStyle("Hyperlink");
|
|
|
String wordMl = "";
|
|
|
wordMLPackage.getMainDocumentPart().getContent().addAll(
|
|
|
- XHTMLImporter.convert(html, TEMP_FILE_IMP) );
|
|
|
+ XHTMLImporter.convert(html, TEMP_FILE_IMP));
|
|
|
//转换完后就初始化image
|
|
|
initPkgImage(wordMLPackage);
|
|
|
// 获取word文档中所有段落
|
|
|
List<Object> pList = getAllElementFromObject(wordMLPackage.getMainDocumentPart(), P.class);
|
|
|
- for(Object p:pList){
|
|
|
+ for (Object p : pList) {
|
|
|
wordMl += formatPWordMl(XmlUtils.marshaltoString(p));
|
|
|
}
|
|
|
return wordMl;
|
|
@@ -958,42 +981,43 @@ public final class DocxProcessUtil {
|
|
|
return writeByte;
|
|
|
}
|
|
|
|
|
|
- public static int getOptionNum(String wordText){
|
|
|
- if(wordText.matches("^[a-zA-Z]\\.[\\s\\S]*")){
|
|
|
- Integer num = CommonUtils.characterToNumber(wordText.substring(0,1));
|
|
|
+ public static int getOptionNum(String wordText) {
|
|
|
+ if (wordText.matches("^[a-zA-Z]\\.[\\s\\S]*")) {
|
|
|
+ Integer num = CommonUtils.characterToNumber(wordText.substring(0, 1));
|
|
|
return num;
|
|
|
}
|
|
|
return -1;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* 检测P标签中是否有值
|
|
|
+ *
|
|
|
* @return
|
|
|
*/
|
|
|
- public static boolean isTextFromP(String strHtml){
|
|
|
- String value = "";
|
|
|
- String regex = "<p>(.*)</p>";
|
|
|
- Pattern pattern = Pattern.compile(regex);
|
|
|
- Matcher matcher = pattern.matcher(strHtml);
|
|
|
- while(matcher.find()){
|
|
|
- value = matcher.group(1);
|
|
|
- }
|
|
|
- if(StringUtils.isBlank(value)){
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
+ public static boolean isTextFromP(String strHtml) {
|
|
|
+ String value = "";
|
|
|
+ String regex = "<p>(.*)</p>";
|
|
|
+ Pattern pattern = Pattern.compile(regex);
|
|
|
+ Matcher matcher = pattern.matcher(strHtml);
|
|
|
+ while (matcher.find()) {
|
|
|
+ value = matcher.group(1);
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(value)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
public static void main(String[] args) throws Exception {
|
|
|
// System.out.println(formatPWordMl("<p>A</p>"));
|
|
|
// System.out.println(getOptionNum("A.123123123"));
|
|
|
// System.out.println(getTextInHtml("<p>#include <stdio.h></p>"));
|
|
|
- StringBuilder str = new StringBuilder("");
|
|
|
- str.append("<p>11</p>");
|
|
|
- str.append("<p></p>");
|
|
|
- String html = str.toString();
|
|
|
- int index = html.lastIndexOf("<p>");
|
|
|
- String htm = html.substring(0,index);
|
|
|
- System.out.println(htm);
|
|
|
+ StringBuilder str = new StringBuilder("");
|
|
|
+ str.append("<p>11</p>");
|
|
|
+ str.append("<p></p>");
|
|
|
+ String html = str.toString();
|
|
|
+ int index = html.lastIndexOf("<p>");
|
|
|
+ String htm = html.substring(0, index);
|
|
|
+ System.out.println(htm);
|
|
|
}
|
|
|
}
|