BaseServlet,讓一個servlet處理多個請求


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中,后續也會傳上來共同交流,感謝觀看!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM