zoukankan      html  css  js  c++  java
  • 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中,后续也会传上来共同交流,感谢观看!

  • 相关阅读:
    python中F/f表达式优于format()表达式
    java8新特性-foreach&lambda
    Java实现多线程的四种方式
    Java中的字符串常量池,栈和堆的概念
    java对象只有值传递,为什么?
    面向对象和面向过程程序设计理解及区别
    String对象为什么不可变
    mybatis_plus插件——生成器
    基于grpc的流式方式实现双向通讯(python)
    Django使用DataTables插件总结
  • 原文地址:https://www.cnblogs.com/stefan95/p/7667451.html
Copyright © 2011-2022 走看看