最近项目需要从系统获取用户输入的周报信息,再将周报信息发送给相关人员。
一开始我就直接用JavaMail,封装信息,然后发送。但是后来遇到一个问题,在客户环境获取用户输入的信息就会有问题。多个空格就会变成“?”问号。换行也会变成/n。
之后就一通搞,把用户输入的信息写入一个word文档里面,然后再把文档转换为html文件,再把html文件内容拷贝到邮件,发送。
但是在把html文件拷贝的过程中遇到了UTF-8 BOM的问题。那个html文件编码是UTF-8 BOM的,而不是UTF-8。这样就会导致在邮件的正文中的第一个字符多一个问号。在网搜了一些资料,用了别人写的一个类UnicodeReader,可以解决这个问题。
servlet 代码
@Override
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)throws ServletException, IOException {
try {
String projectId = req.getParameter("projectId");
String itemId = req.getParameter("itemId");
//周报工作项
IWorkItem item = trackerService.getWorkItem(projectId, itemId);
String mainDelivertys = WorkItemUtil.getFiledKey(item, "mainDeliverty");
String ccs = WorkItemUtil.getFiledKey(item, "cc");
String[] ids1 = mainDelivertys.split(",");
String[] ccs1 = ccs.split(",");
String main = "";
String cc = "";
//获取定制字段人员ID,再获取user对象,再获取用户邮箱
if(ids1.length > 0){
for(int i=0;i<ids1.length;i++) {
if(ids1[i] != "") {
IUser user = trackerService.getTrackerUser(ids1[i]);
if(user.getEmail() != null) {
main += user.getEmail()+",";
}
}
}
if(!main.equals("")) {
main = main.substring(0, main.length()-1);
}
}
//获取定制字段人员ID,再获取user对象,再获取用户邮箱
if(ccs1.length > 0) {
for(int i=0;i<ccs1.length;i++) {
if(ccs1[i] != "") {
IUser user = trackerService.getTrackerUser(ccs1[i]);
if(user.getEmail() != null) {
cc += user.getEmail()+",";
}
}
}
if(!cc.equals("")) {
cc = cc.substring(0,cc.length()-1);
}
}
//判断邮件是否发送成功(只要不报错,就认为邮件发送成功)
boolean flag = sendEmail(main, cc, item);
Map<String,Boolean> map = new HashMap<>();
map.put("result", flag);
Gson gson = new Gson();
responseOut(resp, gson.toJson(map));
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
获取邮件内容代码(包含生成word,再将转为html)。其中Document对象是 com.spire.doc.Document。这个工具类挺好用的,大家可以百度看一下。
public String getMailContent(IWorkItem weekly) {
try {
//周报工作项
IWorkItem item = weekly;
List<IWorkItem> projectItems = linkedItemsService.getLinking(item, "belong_to", "project");
//项目管理工作项
IWorkItem projectItem = projectItems.get(0);
InputStream inputStream = SendWeeklyEmailServlet.class.getClassLoader().getResourceAsStream("ProjectWeekly.docx");
// 获取模板ProjectWeekly.docx
Document document = new Document(inputStream);
document.replace("${title}", projectItem.getTitle(), false, false);
document.replace("${startDate}", WorkItemUtil.getDateField2String(item, "startDate"), false, false);
document.replace("${stopDate}", WorkItemUtil.getDateField2String(item, "stopDate"), false, false);
document.replace("${projectProgressDesc}", com.teamlive.boc.utils.StringUtils.getPlainText(item, "projectProgressDesc"), false, false);
document.replace("${projectStage}", WorkItemUtil.getFiledName(item, "projectStage"), false, false);
document.replace("${projectStatus1}", WorkItemUtil.getFiledName(item, "projectStatus1"), false, false);
document.replace("${contetnofThisWeek}", com.teamlive.boc.utils.StringUtils.getPlainText(item, "contetnofThisWeek"), false, false);
document.replace("${nextWeekPlan}", com.teamlive.boc.utils.StringUtils.getPlainText(item, "nextWeekPlan"), false, false);
document.replace("${projectRisk}", com.teamlive.boc.utils.StringUtils.getPlainText(item, "projectRisk"), false, false);
document.replace("${projectProblem}", com.teamlive.boc.utils.StringUtils.getPlainText(item, "projectProblem"), false, false);
document.replace("${time1}", WorkItemUtil.getFiledKey(projectItem, "time1"), false, false);
document.replace("${time2}", WorkItemUtil.getFiledKey(projectItem, "time2"), false, false);
document.replace("${time3}", WorkItemUtil.getFiledKey(projectItem, "time3"), false, false);
document.replace("${time4}", WorkItemUtil.getFiledKey(projectItem, "time4"), false, false);
document.replace("${time5}", WorkItemUtil.getFiledKey(projectItem, "time5"), false, false);
document.replace("${time6}", WorkItemUtil.getFiledKey(projectItem, "time6"), false, false);
document.replace("${time7}", WorkItemUtil.getFiledKey(projectItem, "time7"), false, false);
document.replace("${time8}", WorkItemUtil.getFiledKey(projectItem, "time8"), false, false);
document.replace("${time9}", WorkItemUtil.getFiledKey(projectItem, "time9"), false, false);
document.replace("${time10}", WorkItemUtil.getDateField2String(projectItem, "time10"), false, false);
if(!WorkItemUtil.getFiledKey(item, "percent1").equals("")) {
document.replace("${percent1}", WorkItemUtil.getFiledKey(item, "percent1")+"%", false, false);
}else {
document.replace("${percent1}", "", false, false);
}
if(!WorkItemUtil.getFiledKey(item, "percent2").equals("")) {
document.replace("${percent2}", WorkItemUtil.getFiledKey(item, "percent2")+"%", false, false);
}else {
document.replace("${percent2}", "", false, false);
}
if(!WorkItemUtil.getFiledKey(item, "percent3").equals("")) {
document.replace("${percent3}", WorkItemUtil.getFiledKey(item, "percent3")+"%", false, false);
}else {
document.replace("${percent3}", "", false, false);
}
if(!WorkItemUtil.getFiledKey(item, "percent4").equals("")) {
document.replace("${percent4}", WorkItemUtil.getFiledKey(item, "percent4")+"%", false, false);
}else {
document.replace("${percent4}", "", false, false);
}
if(!WorkItemUtil.getFiledKey(item, "percent5").equals("")) {
document.replace("${percent5}", WorkItemUtil.getFiledKey(item, "percent5")+"%", false, false);
}else {
document.replace("${percent5}", "", false, false);
}
File file2 = File.createTempFile("SIT2", ".docx");
File htmlFile = File.createTempFile("E://wordToHtml", ".html");
//将替换后的文件(document)内容写入file2
document.saveToFile(file2.getAbsolutePath(),FileFormat.Docx_2010);
//将file2转为Document对象
Document document2 = new Document(new FileInputStream(new File(file2.getAbsolutePath())));
//将word(document2)转换为html文件
document2.saveToFile(htmlFile.getAbsolutePath(), FileFormat.Html);
file2.delete();
//客户环境还是测试环境
String mode = confSvc.get("EmailMode");
String htmlCode = "";
//获取htm文件的内容
if(mode.equals("test")) {
//把img标签去掉
htmlCode = getHtmlByPageName1(htmlFile,"").replaceAll("<img[^>]*/>", "");
}else {
htmlCode = getHtmlByPageName1(htmlFile,"UTF-8").replaceAll("<img[^>]*/>", "");
LOG.error("Charset.defaultCharset().name()==============================================================="+Charset.defaultCharset().name());
}
return htmlCode;
}catch(Exception e) {
e.printStackTrace();
LOG.error(e.getMessage());
}
发送邮件的功能可以参考我上一个文章。
读取生成的html文件的内容,里面用到了UnicodeReader类型
private String getHtmlByPageName1(File htmlFile,String charSet) {
StringBuffer sb = new StringBuffer();
try {
BufferedReader br = null;
if(charSet.equals("")) {
//解决UTF-8 BOM的问题
br = new BufferedReader(new UnicodeReader(new FileInputStream(htmlFile),Charset.defaultCharset().name()));
}else {
br = new BufferedReader(new UnicodeReader(new FileInputStream(htmlFile),charSet));
}
String s = "";
while ((s = br.readLine()) != null) {
sb.append(s).append("\n");
}
} catch (Exception e) {
LOG.error(e.getMessage());
e.printStackTrace();
} finally {
}
return sb.toString();
}
以下是UnicodeReader类型
package com.teamlive.boc.utils;
/**
version: 1.1 / 2007-01-25
- changed BOM recognition ordering (longer boms first)
Original pseudocode : Thomas Weidenfeller
Implementation tweaked: Aki Nieminen
http://www.unicode.org/unicode/faq/utf_bom.html
BOMs:
00 00 FE FF = UTF-32, big-endian
FF FE 00 00 = UTF-32, little-endian
EF BB BF = UTF-8,
FE FF = UTF-16, big-endian
FF FE = UTF-16, little-endian
Win2k Notepad:
Unicode format = UTF-16LE
***/
import java.io.*;
/**
* Generic unicode textreader, which will use BOM mark to identify the encoding
* to be used. If BOM is not found then use a given default or system encoding.
*/
public class UnicodeReader extends Reader {
PushbackInputStream internalIn;
InputStreamReader internalIn2 = null;
String defaultEnc;
private static final int BOM_SIZE = 4;
/**
*
* @param in
* inputstream to be read
* @param defaultEnc
* default encoding if stream does not have BOM marker. Give NULL
* to use system-level default.
*/
public UnicodeReader(InputStream in, String defaultEnc) {
internalIn = new PushbackInputStream(in, BOM_SIZE);
this.defaultEnc = defaultEnc;
}
public String getDefaultEncoding() {
return defaultEnc;
}
/**
* Get stream encoding or NULL if stream is uninitialized. Call init() or
* read() method to initialize it.
*/
public String getEncoding() {
if (internalIn2 == null)
return null;
return internalIn2.getEncoding();
}
/**
* Read-ahead four bytes and check for BOM marks. Extra bytes are unread
* back to the stream, only BOM bytes are skipped.
*/
protected void init() throws IOException {
if (internalIn2 != null)
return;
String encoding;
byte bom[] = new byte[BOM_SIZE];
int n, unread;
n = internalIn.read(bom, 0, bom.length);
if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00)
&& (bom[2] == (byte) 0xFE) && (bom[3] == (byte) 0xFF)) {
encoding = "UTF-32BE";
unread = n - 4;
} else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)
&& (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) {
encoding = "UTF-32LE";
unread = n - 4;
} else if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB)
&& (bom[2] == (byte) 0xBF)) {
encoding = "UTF-8";
unread = n - 3;
} else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) {
encoding = "UTF-16BE";
unread = n - 2;
} else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) {
encoding = "UTF-16LE";
unread = n - 2;
} else {
// Unicode BOM mark not found, unread all bytes
encoding = defaultEnc;
unread = n;
}
// System.out.println("read=" + n + ", unread=" + unread);
if (unread > 0)
internalIn.unread(bom, (n - unread), unread);
// Use given encoding
if (encoding == null) {
internalIn2 = new InputStreamReader(internalIn);
} else {
internalIn2 = new InputStreamReader(internalIn, encoding);
}
}
public void close() throws IOException {
init();
internalIn2.close();
}
public int read(char[] cbuf, int off, int len) throws IOException {
init();
return internalIn2.read(cbuf, off, len);
}
}