BaseServlet
第一次學習servlet的時候是跟着傳智播客免費的教學視頻,其中崔希凡講的是我學過自認講的最好的一位,BaseServlet也是跟着他寫過一次,當時很多東西不能理解,后來慢慢發現其中的內層深意,本工具類在崔老師的基礎之上增加了文件下載功能,如果能很好掌握,非常有利對struts2的掌握!
1. 我們希望在一個Servlet中可以有多個請求處理方法!
2. 客戶端發出請求時,必須給出一個參數,來說明要調用哪一個方法
3. 客戶端必須傳遞名為method的參數
http://localhost:8080/test/UserServlet?method=login、http://localhost:8080/test/UserServlet?method=regist等等
原理
BaseServlet中調用request.getParameter("method")來確定你需要調用的方法,因為每次請求都是執行service方法,所以通過反射來執行
BaseServlet
package hui.zhang.servlet; import hui.zhang.down.DownUtils; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.Method; import java.util.List; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.IOUtils; /** * BaseServlet * 我們希望在一個Servlet中處理多個請求 * 創建Servlet時繼承本類而不是繼承HttpServlet,重寫service方法 * 客戶端在發起請求時需要傳遞method參數來判斷調用哪個方法 * eg:http://localhost:8080/test/UserServlet?method=login * 返回值"f:/xxx"為轉發、"r:/xxx"為重定向、"d:/xxx"為下載 * 重定向可以重定向到其他項目中,寫法:"r:/192.168.11.24:8080/example/index.jsp" * 下載可以下載服務器中目錄下的文件 "d:/WEB-INF/a.jpg" * 也可以下載磁盤絕對路徑下的文件 "d:/G:/a.jpg" * @author hui.zhang * */ @SuppressWarnings("serial") public class BaseServlet extends HttpServlet { @Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8");//處理響應編碼 //獲取傳遞的method參數 String methodName = request.getParameter("method"); if (methodName == null || methodName.trim().isEmpty()) { throw new RuntimeException("沒有傳遞method參數,不能確定要調用的方法!"); } //得到當前類的class對象 Class c = getClass(); Method method = null; try { method = c.getMethod(methodName, HttpServletRequest.class,HttpServletResponse.class); } catch (Exception e) { throw new RuntimeException("要調用的方法:"+methodName+"(HttpServletRequest,HttpServletResponse),不存在!",e); } //調用method表示的方法 try { String result = (String)method.invoke(this, request,response); /* * 獲取請求處理方法執行后返回的字符串,它表示轉發或重定向的路徑 * 如果返回為null或者"",什么也不做 * 判斷返回值中是否存在冒號,如果沒有默認轉發,因為轉發的情況較多 * 如果有冒號,分割,得到前綴f表示forward,前綴r表示redirect * 后綴為要轉發或重定向的路徑 */ if (result == null || result.trim().isEmpty()) { return; } if (result.contains(":")) { //"f:/index.jsp" int index = result.indexOf(":"); String s = result.substring(0, index); //f String path = result.substring(index+1); // "/index.jsp" if (s.equalsIgnoreCase("r")) { // "/192.168.11.24:8080/example/index.jsp" if (path.contains(":")) { //有:說明有端口號是其他項目的路徑 if (path.contains("http")) { // "/http://192.168.11.24:8080/example/index.jsp" response.sendRedirect(path.substring(1)); } else { response.sendRedirect("http://"+path.substring(1)); } } else { response.sendRedirect(request.getContextPath()+path); } } else if (s.equalsIgnoreCase("f")) { request.getRequestDispatcher(path).forward(request, response); } else if (s.equalsIgnoreCase("d")) { //表示下載 /** * 兩個頭一個流 * 1. Content-Type * 2. Content-Disposition * 3. 流:下載文件的數據 */ // path = "/WEB-INF/mp3/自娛自樂.mp3"; // path = "/G://a.jpg"; int indexOf = path.lastIndexOf("/"); String name = path.substring(indexOf); // /自娛自樂.mp3 //如果包含:,說明是絕對路徑 String filename = null; if (path.contains(":")) { filename = path.substring(1); } else { //說明是服務器端文件,需要獲得絕對路徑 //獲得文件的絕對路徑 filename = this.getServletContext().getRealPath(path); } //去掉文件名前的/ name = name.substring(1); // 自娛自樂.mp3 //通過DownUtils工具類處理不同瀏覽器下載時中文名亂碼問題 String framename = DownUtils.filenameEncoding(name, request); //頭1:獲得要下載的文件MIME類型 String contentType = this.getServletContext().getMimeType(filename); //頭2:ContentDisposition String contentDisposition = "attachment;filename="+framename; FileInputStream input = new FileInputStream(filename); response.setHeader("Content-Type", contentType); response.setHeader("Content-Disposition",contentDisposition); ServletOutputStream output = response.getOutputStream(); IOUtils.copy(input, output); input.close(); output.close(); } else { throw new RuntimeException("操作:"+s+"目前還不支持!"); } } else { //默認轉發 request.getRequestDispatcher(result).forward(request, response); } } catch (Exception e) { throw new RuntimeException("調用的方法:"+methodName+"(HttpServletRequest,HttpServletResponse),內部拋出異常!", e); } } }
DownUtils
/** * 文件下載時處理瀏覽器不同編碼的中文亂碼 * @author hui.zhang * @date 2017-10-12 下午6:04:06 */ public class DownUtils { public static String filenameEncoding(String filename, HttpServletRequest request) throws IOException{ //獲取瀏覽器頭信息 String agent = request.getHeader("User-Agent"); if(agent.contains("Firefox")){ BASE64Encoder base64Encoder = new BASE64Encoder(); filename = "=?utf-8?B?"+base64Encoder.encode(filename.getBytes("utf-8"))+"?="; } else if(agent.contains("MSIE")){ filename = URLEncoder.encode(filename,"utf-8"); } else { filename = URLEncoder.encode(filename,"utf-8"); } return filename; } }
代碼中注釋還算清楚,下載文件的功能是新加上的,測試還挺正常,如果使用出現問題歡迎提出!因為getParameter()在上傳文件中失效,所以沒寫在Base中,后續也會傳上來共同交流,感謝觀看!