zoukankan      html  css  js  c++  java
  • 超通俗易懂的Servlet入门教程

    不怕千万人阻挡,就怕自己投降。


    概念:运行在服务器端的小程序
    servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。将来我们自定义一个类,实现servlet接口,复写方法。所以servlet就是实现了Servlet接口的类。

    01.Servlet快速入门

    1.创建javaEE项目

    2.定义一个类,实现servlet接口
    public class servletDemo1 implements servlet

    3.实现接口中的抽象方法

    4.配置Servlet,在xml中配置。

    <servlet>
    <servlet-name>demo1</ servlet-name>
    <servlet-class>cn.itcast.web. servlet.ServletDemo1</servlet-class>< / servlet>
    <servlet-mapping>
    <servlet-name>demo1</ servlet-name><url-pattern>/demo1</url-pattern>< / servlet-mapping>
    

    执行原理:
    1,当服务器接受到客户端浏览器的请求后,会解析请求uRL路径,获取访问的servlet的资源路径2.查找web.xml文件,足否有对应的<url-pattern>标签体内容。
    3.如果有,则在找到对应的<servlet-class>全类名
    4. tomcat会将字节码文件加载进内存,并且创建其对象
    5,调用其方法。

    servlet中的生命周期方法∶
    1.被创建:执行init方法,只执行一次
    对象被创建后再执行Servlet方法。

    servlet什么时候被创建?

    默认情况下,第一次被访问时,servlet被创建。可以配置其执行servlet的创建时机。

    <servlet>标签下配置

    1,第一次被访问时,创建
    <load-on-startup>的值为负数。

    2.在服务器启动时,创建
    <load-on-startup>的值为0或正整数。

    Servlet的init方法,只执行一次,说明一个servlet在内存中只存在一个对象,Servlet是单例的。

    多个用户同时访问时,可能存在线程安全问题。

    解决∶尽量不要在servlet中定义成员变量。即使定义了成员变量,也不要对修改值。

    2.提供服务:执行service方法,执行多次。

    每次访问Servlet时,Service方法都会被调用一次。

    3.被销毁:执行destroy方法,只执行一次。

    servlet被销毁时执行,服务器关闭时,Servlet被销毁。

    只有服务器正常关闭时,才会执行destroy方法。

    destroy方法在servlet被销毁之前执行,一般用于释放资源。

    02.Servlet3.0注解配置

    java6支持Serlet3.0.

    java8支持Serlet4.0.

    好处:支持注解配置。

    可以不需要web.xml。

    步骤:
    1.创建JavaEE项目,选择Servelt3.0以上的,可以不创建web.xml。

    2.定义一个类,实现Servlet接口。

    3.复写方法。

    4.在类上使用@WebServlet注解,进行配置。

    因为注解是加在类上的,所以不需要关心类名,只需要关心资源路径。

    @WebServlet(urlPatterns="/demo")//可以配置多个路径
    public class ServletDemo implement Servlet{
    }
    

    或者

    @WebServlet("/demo")//可以配置多个路径
    public class ServletDemo implement Servlet{
    }
    

    IDEA与tomcat的相关配置
    1.IDEA会为每一个tomcat部署的项目单独建立一份配置文件.
    查看控制台的log : Using CATALINA_BASE:“c: usersfay.Intelli]Idea2018.1system omcatl_itcast"

    2.工作空间项目和 tomcat部署的web项目。

    tomcat真正访问的是"“tomcat部署的web项目”",“tomcat部署的web项目"对应着”"工作空间项目”的web目录下的所有资源。

    WEB-INF目录下的资源不能被浏览器直接访问。

    03.GenericServlet&HttpServlet(Serlvet的体系结构)

    GenericServlet是Servlet的子类(子);
    HttpServlet是GenericServlet的子类(孙);

    问题提出:有时候我们只需要重写Servlet的service方法。然而我们继承Servlet类必须实现Servlet的所有抽象方法。这样就与我们意愿相左。有什么解决办法呢?

    【解决办法】:GenericServlet为Servlet的子类,并且已经(空)实现了Servlet的4个方法,只有service方法没有实现。

    因此我们可以写一个类,继承GenericServlet抽象类。实现service方法即可。

    将来我们在定义自己的serlvet类时,可以继承抽象类GenericServlet即可,如果需要使用到其他方法,重些该方法即可。

    可以看出,此时代码书写已经很方便,但是我们以后开发并不使用这种方式。

    那我们使用哪种方式呢?

    【HttpServlet】:为什么要使用这个类呢?
    那我们得问自己,我们实现service方法干嘛呢?

    我们在写service方法体时,需要判断前端给后台的请求方式,并根据其获取数据。每次都需要判断,有没有一种方式,可以简洁的达到效果呢?
    HttpServlet抽象类,帮我们把这些事情都做好了,我们只需要重写HttpServlet对应得方法即可。
    如:

    doGet(){
    //重写部分
    };
    doPost(){
    //重些部分
    };
    

    因此我们将来需要屏蔽请求方式的处理逻辑,继承HttpServlet就显得格外好用。

    HttpSerlvet:对http协议的一种封装,简化操作。
    因此我们以后开发:就不再定义类继承GenericServlet实现service方法。而是定义类继承HttpServlet重写doGet(),或doPost()方法。

    Servlet的urlpartten配置
    因为urlpattten是一个数组,所以可以为其配置多个资源路径

    @WebServlet({"/d4","dd4","ff"})
    public class ServletDemo extends HttpServlet{
    }
    

    一个servlet可以设置多个访问路径。
    路径的定义规则

    1./xxx
    
    2./xxx/xxx(多层路径)
    (/xxx/*)
    
    
    3.*.do
    

    04.HTTP

    概念:Hyper Text Transfer Protocol超文本协议。
    传输协议:定义了,客户端和服务器端通信超时,发送数据的格式。

    请求和响应一一对应。
    无状态:每次请求之间相互独立,不能交互数据。
    历史版本:
    1.0:每一次请求响应都会建立新的连接(http1.0)
    1.1:复用连接(http1.1)。

    请求消息数据格式:
    1.请求行
    请求方式 请求url 请求协议/版本
    GET /index.html HTTP/1.1

    HTTP协议有7种请求方式。
    GET:
    (1.请求参数在请求行中,在url后。
    (2.请求的url的长度有限制。
    (3.不安全
    POST:
    (1.请求参数在请求体中。
    (2.请求的url的长度没有限制。
    (3.相对安全

    2.请求头
    请求头名称:请求头值
    常见的请求头:
    主机
    User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息,可以获取其信息解决浏览器兼容性问题。

    Accept:告诉服务器,我可以解析的格式。

    Referer:告诉服务器,当前请求从哪里来。
    作用:方式其他人盗链。统计工作。

    Connection:表示连接可以复用。

    3.请求空行
    空行(分割POST的请求头和请求体)
    4.请求体
    POST才有请求体,封装了POST的请求参数。

    响应消息数据格式:

    1.响应行
    协议及版本 响应状态码 状态码描述

    状态码:
    1xx:服务器接收客户端消息,但没有接收完成,等待一段时间后,发送1xx状态码。
    2xx:成功

    3xx:302(重定向),304访问缓存
    在这里插入图片描述
    4xx:客户端错误,405没有对应的方法。(doGet,doPost)

    5xx:服务器端错误,500代码错误,505服务器不支持客户端使用的HTTP版本。

    2.响应头
    头名称:值
    常见的响应头:
    Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式。
    Content-disposition:服务器告诉客户端以什么格式打开响应体数据。
    值:in-line默认值,在当前页面内打开。
    attachment:以附件形式打开响应体,文件下载。
    3.响应空行

    4.响应体
    传输的数据。

    05.Request对象

    1.request对象继承体系结构:
    ServletRequest —接口
    继承
    HttpServletRequest —接口
    实现
    org.apache.catalina.connector.RequestFacade 类(tomcat实现了HttpServletRequest接口)

    2.request和response的原理

    在这里插入图片描述
    1.request和response对象是由服务器创建的。我们只是使用他们。

    2.request对象是来获取请求消息,response对象是来设置响应消息。

    3.request的功能:

    3.1获取请求消息数据

    获取请求行数据

    **1.1获取请求方式**
    

    String getMethod();//了解即可

    **1.2获取虚拟目录**
    

    String getContextPath();//重要

    **1.3获取Servlet路径:**
    

    String getServletPath();

    **1.4获取get方式请求参数:**
    

    String getQueryString();//了解

    **1.5获取请求URI**
    

    String getRequestURI(); 如:/day1/demo2

    **1.6获取请求URL**
    

    StringBuffer getRequestURL(); 如: http://localhost/day1/demo2

    **1.7获取协议及版本**
    

    String getProtocol();

    **1.8获取客户机的IP地址**
    

    String getRemoteAddr();

    URI:统一资源标识符。(范围更大)
    URL:统一资源定位符。
    获取请求头数据

    String getHeader(String name);//通过请求头的名称获取请求头的值
    Enumeration<String>  getHeaderNames();//获取所有的请求头名称
    
    @WebServlet("/ServletTest2")
    public class ServletTest2 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //获取所有请求头名称
            Enumeration<String> headNames = request.getHeaderNames();
            //遍历
            while (headNames.hasMoreElements()){
                String name = headNames.nextElement();
                //根据名称获取请求头的值
                String value = request.getHeader(name);
                System.out.println(name+"---"+value);
            }
        }
    }
    

    获取请求体数据
    步骤:
    1.获取流对象

    BufferedReader getReader() ;//获取字符输入流,只能操作字符数据
    ServletInputStream getInputStream();//获取字节输入流,可以操作所有
    类型的数据(文件上传)
    

    2.再从流对象中拿数据

    @WebServlet("/ServletTest3")
    public class ServletTest3 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //获取请求参数
            //1.获取字符流
            BufferedReader br = request.getReader();
            //读取数据
            String line = null;
            while ((line=br.readLine())!=null){
                System.out.println(line);
            }
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        }
    }
    

    3.2.其他功能
    1.获取请求参数的通用方式(get和post都可以)

    String getParameter(String name):根据参数名获取参数值
    String[] getParameterValues(String name):根据参数名获取参数值的数组
    (常用于复选框)
    Enumeration<String> getParameterNames():获取所有请求参数名称。
    Map<String,String[]> getParameterMap():获取所有参数的map集合。
    

    优势:屏蔽了get和post方法的不同,代码只需要写一份,再另一方法中调用另一个已经实现的方法即可,满足get和post请求。

    获取请求参数中文乱码的问题处理:
    get方式:tomcat8已经将get方式乱码问题解决了。
    post方式:会乱码。

    解决方案:在获取参数前,设置流的编码。
    request.setCharacterEncoding(“utf-8”);

    //设置编码
    request.setCharacterEncoding("utf-8");
    //获取请求参数
    String username = request.getParameter("username");
    

    2.请求转发
    在这里插入图片描述

    一种在服务器内资源跳转的方式。
    步骤:

    1.通过request对象获取请求转发器对象:
    RequestDispatcher getRequestDispatcher(String path)
    2.使用RequestDispatcher对象来进行转发:
    forward(ServletRequest request,ServletResponse response)
    

    特点:
    浏览器地址栏路径没有发生变化。

    只能访问当前服务器内部资源中。

    转发是一次请求,多个资源使用同一个请求。
    3.共享数据
    在这里插入图片描述

    域对象:一个有作用范围的对象,可以在范围内共享数据。
    request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据。
    方法:

    setAttribute(String name,Object obj);存储数据
    Object getAttitude(String name);通过键获取值
    
    removeAttribute(String name)通过键移除值
    

    例子:

    @WebServlet("/ServletTest4")
    public class ServletTest4 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("ServletTest4被访问了");
            //存储数据到request域中
            request.setAttribute("name","MengYangchen");
            RequestDispatcher getquestDispatcher = request.getRequestDispatcher("/ServletTest5");//没有虚拟路径(项目)
            getquestDispatcher.forward(request,response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                doPost(request,response);
        }
    }
    
    @WebServlet("/ServletTest5")
    public class ServletTest5 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("ServletTest5被访问了");
            //获取数据
            Object name = request.getAttribute("name");
            System.out.println(name);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request,response);
        }
    }
    
    

    结果:
    在这里插入图片描述

    4.获取ServletContext(对象)
    返回ServletContext对象

    ServletContext getServletContext()  
    

    06.Request案例(登录)

    用户登录案例需求:
    1.编写login.html登录页面
    username &password两个输入框

    2.使用Druid数据库连接池技术,操作mysql,day14数据库中user表

    3.使用JdbcTemplate技术封装JDBC

    4.登录成功跳转到SuccessServlet展示:登录成功!用户名,欢迎您

    5.登录失败跳转到FailServlet展示:登录失败,用户名或密码错误。

    07.Response对象

    1.请求消息:客户端发送给服务器的数据。
    2.服务器端发送给客户端的数据。

    功能:设置响应消息。
    1.设置响应行。

    void setStatus(int sc)  设置状态码
    

    2.设置响应头。

    void setHeader(String name, String value)  
    

    3.设置响应体。
    获取输出流

    PrintWriter getWriter()  字符输出流
    ServletOutputStream getOutputStream()  字节输出流
    

    使用输出流,将数据输出到客户端浏览器。

    Response案例

    1.完成重定向
    在这里插入图片描述

    @WebServlet("/ServletResponseTest1")
    public class ServletResponseTest1 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("response1被访问了");
            //重定向,访问ServletResponseTest1,会自动跳转到ServletResponseTest2
            //1.设置状态码302
    /*        response.setStatus(302);
            //2.设置响应头location
            response.setHeader("location","/First/ServletResponseTest2");
            */
    
            //简单重定向方法
            response.sendRedirect("/First/ServletResponseTest2");//有虚拟路径
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request,response);
        }
    }
    
    @WebServlet("/ServletResponseTest2")
    public class ServletResponseTest2 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("response2被访问了");
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request,response);
        }
    }
    
    

    转发的特点:
    1.转发地址栏路径不变。
    2.转发只能访问当前服务器下的资源。
    3.转发是一次请求。
    4.路径不需要带虚拟路径。
    重定向的特点:
    1.地址栏发生改变。
    2.重定向可以访问其他站点(服务器)的资源。
    3.重定向是两次请求。
    4.路径需要虚拟路径。

    2.服务器输出字符数据到浏览器
    乱码原因:编码解码用的编码不同。
    在这里插入图片描述

    2.1.获取字符输出流。

    //设置输出流编码
    response.setCharacterEncoding("utf-8");
    
    //告诉浏览器,服务器发送消息体数据的编码,建议浏览器使用该编码解码
    response.setHeader("content-type","text/html;charset=utf-8");
    
    //简单形式,设置编码
    response.setContentType("text/html;charset=utf-8");
    PrintWrite out = response.getWriter();//tomcat返回的对象[ISO-8859-1]。
    

    2.2输出数据(不需要刷新)
    out.write();

    3.服务器输出字节数据到浏览器
    3.1获取字节输出流

    3.2输出数据

    response.setContentType("text/html;charset=utf-8");
    ServletOutputStream out = response.getOutputStream();
    out.writer("你好".getBytes("utf-8"));
    

    4.验证码
    1.本质:图片
    2.目的:防止恶意表单注册。
    随机生成。
    后端:servlet:

    @WebServlet("/IdentifyingCodeServlet")
    public class IdentifyingCodeServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            int width = 100;
            int height = 50;
            //1.创建一对象,在内存中的图片(验证码图片对象)
            BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
            //2.美化图片
            //2.1填充背景色
            Graphics g = image.getGraphics();
            g.setColor(Color.pink);
            g.fillRect(0,0,100,50);//填充矩形
    
            //2.2画边框
            g.setColor(Color.yellow);
            g.drawRect(0,0,width-1,height-1);
    
            String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
            //生成随机角标
            Random ran  = new Random();
    
            for(int i=1;i<=4;i++){
                int index = ran.nextInt(str.length());
                char ch = str.charAt(index);//随机字符
                //2.3写验证码
                g.setColor(Color.blue);
                g.drawString(""+ch,width/5*i,height/2);
            }
            //2.4画干扰线,防识别
            //随机生成坐标点
            for(int i=0;i<8;i++){
                int x1 =ran.nextInt(width);
                int x2 =ran.nextInt(width);
                int y1 =ran.nextInt(height);
                int y2 =ran.nextInt(height);
                g.setColor(Color.green);
                g.drawLine(x1,y1,x2,y2);
            }
    
            //3.将图片输出到页面展示
            ImageIO.write(image,"jpg",response.getOutputStream());
      
    
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request,response);
        }
    }
    
    

    前端页面:

    <body>
    <h1>账号注册</h1>
    <form action="/First/ServletTest3" method="post">
        <input type="text" placeholder="请输入用户名" name="username"><br>
        <input type="password" placeholder="请输入密码" name="password"><br>
        <input type="submit"  value="注册"><br>
        <img id="checkCode" src="/First/IdentifyingCodeServlet"/>
        <a id="change" href="">看不清换一张</a>
    </form>
        <script>
            //1.给超链接或图片绑定单击事件
            //2.重新设置图片的src属性
            window.onload = function () {
    
                var a  =document.getElementById("change");
                //1.获取图片对象
                var img  = document.getElementById("checkCode");
                //2.绑定单击事件
                img.onclick = function () {
                    //加时间戳
                    var date = new Date().getTime();
    
                    img.src = "/First/IdentifyingCodeServlet?"+date;//欺骗缓存,因为路径不变,浏览器会自动去找缓存,而不是服务器
                }
                a.onclick = function () {
                    var date = new Date().getTime();
                    img.src = "/First/IdentifyingCodeServlet?"+date;//欺骗缓存,因为路径不变,浏览器会自动去找缓存,而不是服务器
                }
            }
        </script>
    </body>
    

    路径的分类

    1.相对路径
    如:./index.html
    不以/开头,以./开头的路径(可以省略不写)。
    规则:找到当前资源和目标资源之间的相对位置关系。
    ./表示当前目录;…/上一级目录。
    2.绝对路径
    如:http://localhost/First/ServletResponseTest2
    简略写法:/First/ServletResponseTest2
    以/开头。
    规则:判断定义的路径是给谁用的。
    1.给客户端浏览器使用:需要加虚拟目录(超链接…项目的访问路径)
    2.给服务器端使用(转发…不需要加虚拟目录)
    【问题提出】在重定向写路径是我们采用的是直接书写路径,以后一旦更改了虚拟目录。所有代码将需要该过来。

    【解决方案】动态获取虚拟目录。

    //动态获取虚拟目
    String contextPath = request.getContextPath();
    
    //简单的重定向方法
    response.sendRedirect(contextPath+"ServletResponseTest2");
    

    前端代码采取jsp获取虚拟目录。

    08.ServletContext对象

    1.概念:代表整个web应用,可以和程序的容器(服务器)来通信。

    2.如何获取ServletContext对象。

    1.通过request获取
    request.getServletContext();
    
    2.通过HttpServlet获取
    this.getServletContext();//因为我们继承了HttpServlet
    

    两者获取的ServletContext是相等的。

    2.功能:
    获取MIME类型。
    MIME类型:在互联网通信过程中定义的一种文件数据类型。
    格式:大类型/小类型 text/html

    //通过HttpServlet获取
    SevletContext context = this.getServletContext();
    
    //定义文件名称
    String filename = "a.jpg";
    
    //获取MIME类型
    String mimeType = context.getMimeType(filename);
    System.out.println(mimeType);
    

    域对象:共享数据。

    1.setAttribute(String name,Object value)
    
    2.getAttribute(String name)
    
    3.removeAttribute(String name);
    

    ServletContext对象范围:所有用户所有请求的数据。

    @WebServlet("/ServletContextTest")
    public class ServletContextTest extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //通过httpServlet获取
            ServletContext context  = this.getServletContext();
    
            //设置共享数据
            context.setAttribute("name","Is me!");
    
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request,response);
        }
    }
    
    
    @WebServlet("/ServletContextTest2")
    public class ServletContextTest2 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //通过httpServlet获取
            ServletContext context  = this.getServletContext();
    
            //获取共享数据
            Object a = context.getAttribute("name");
            response.setContentType("utf-8");
            PrintWriter out = response.getWriter();
            out.print(a);
    
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request,response);
        }
    }
    

    访问http://localhost/First/ServletContextTest2得到结果:
    在这里插入图片描述

    获取文件的真实路径
    在web服务器的真实路径。
    在这里插入图片描述

    1.方法:String getRealPath(String path)

    配置文件所在地方不同,参数书写不同。

    String realPath = context.getRealPath("/a.txt");//web目录下资源访问
    String realPath = context.getRealPath("/WEB-INF/a.txt");//WEB-IN目录下资源访问
    
    String realPath = context.getRealPath("/WEB-INF/classes/a.txt");//src目录下资源访问
    
    @WebServlet("/ServletContextTest3")
    public class ServletContextTest3 extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            ServletContext context = this.getServletContext();
            String realPath = context.getRealPath("/WEB-INF/classes/a.txt");
            System.out.println(realPath);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request,response);
        }
    }
    
    

    09.文件下载案例

    文件下载需求

    1.页面显示超链接

    2.点击超链接后弹出下载提示框

    3.完成图片文件下载。
    分析:
    1.超链接指向的资源如果能过被浏览器解析,则在浏览器中显示,如果不能解析,则弹出下载提示框。不满足需求。

    2.任何资源都必须弹出下载提示框。

    3.使用响应头设置资源的打开方式。

    步骤:
    1.定义页面,编辑超链接href属性,指向servlet,传递资源名称filename

    2.定义servlet
    2.1获取文件名称
    2.2使用字节输入流加载文件进内存.
    2.3指定response的响应头:content-disposition:attachment;filename=xxx.2.4将数据写出到response输出流。

    前端:

    <body><p align="center">优质资源网站</p>
    <a href="/First/res/img/1.jpg">表情包(未处理)</a><br>
    
    <a href="/First/ServletDownLoad?filename=1.jpg">表情包</a><br>
    <a href="/First/ServletDownLoad?filename=2.jpg">表情包2</a>
    </body>
    </html>
    

    后端:

    @WebServlet("/ServletDownLoad")
    public class ServletDownLoad extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.获取请求参数,文件名称
            String filename = request.getParameter("filename");
            //2.使用字节输入流加载文件进入内存
            //2.1找到文件服务器路径
            ServletContext context = this.getServletContext();
            String realPath = context.getRealPath("/res/img/"+filename);
            //2.2用字节流关联
            FileInputStream fis = new FileInputStream(realPath);
    
            //3.设置reponse响应头
            //设置响应数据类型:context-type
            String mimeType = context.getMimeType(filename);
            response.setHeader("content-type",mimeType);
            //设置打开方式:content-disposition
            response.setHeader("content-disposition","attachment;filename="+filename);
    
            //4.将输入流的数据写出到输出流中
            ServletOutputStream sos = response.getOutputStream();
            byte[] buff = new byte[1024*4];
            int len =0;
            while ((len=fis.read(buff))!=-1){
                sos.write(buff,0,len);
            }
            fis.close();
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request,response);
        }
    }
    
    

    中文文件名的问题
    【解决思路】
    1.获取客户端使用的浏览器版本信息
    2.根据不同的版本信息,设置filename不同的编码方式。

    //1.获取user-agent请求头
    String agent = request.getHeader("user-agenet");
    
    //2.使用工具类方法编码文件名(自己从网上下载工具栏导入在自己创建的工具包)
    filename = DownLoadUtils.getFileName(agent,filename);
    
    

    别害怕顾虑,想到就去做,这世界就是这样,当你把不敢去实现梦想的时候梦想就会离你越来越远,当你勇敢地去追梦的时候,全世界都会来帮你。

    在这里插入图片描述
    在这里插入图片描述

    以梦为马,不负韶华。
  • 相关阅读:
    Count Up Down(上下计数)
    TCP与UDP的区别
    xml和json的区别
    java中String,StringBuffer,StringBuilder的区别
    java中访问修饰符public,private,protected,friendly的作用域
    java中的数据类型,基本数据类型及其包装类型
    Collection和Collections的区别
    Java中静态变量和实例变量的区别
    Java中实现多态的条件是什么
    Java中抽象类和接口的区别
  • 原文地址:https://www.cnblogs.com/huangjiahuan1314520/p/14088596.html
Copyright © 2011-2022 走看看