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中,后续也会传上来共同交流,感谢观看!