servlet概念

servlet其实就是运行在服务器的一个小程序

如何去理解呢?我们访问服务器的资源包括静态资源和动态资源,其中静态资源是我们放置的模板,CSS、JS等文件,是不变的。而我们访问的动态资源,是根据我们访问的请求路径,路由到指定的类去加载,运行其对应的方法而给出浏览器资源的响应。那么凭什么我们的服务器会帮我们去加载,去运行指定的方法呢?或者说服务器是怎么做到的呢?我们一定是需要遵循服务器某些规则才行的,而规则在 Java 中 就是接口,Servlet就是被服务器(Tomcat)识别的接口,我们需要根据这个接口来定义响应的方法。

快速入门

  1. 创建一个 Java EE 项目,定义一个类,实现 Servlet 接口

    public class ServletDemo1 implements Servlet
  2. 实现接口中的抽象方法

  3. 在web.xml中配置 Servlet

    <!-- 配置Servlet -->
    <servlet>
    <servlet-name>demo1</servlet-name>
    <servlet-class>org.taoguoguo.web.ServletDemo1</servlet-class>
    </servlet> <servlet-mapping>
    <servlet-name>demo1</servlet-name>
    <url-pattern>/demo1</url-pattern>
    </servlet-mapping>

Servlet执行原理:

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

Servlet中的生命周期:

  1. 被创建:执行 init 方法,只执行一次

    • Servlet 什么时候被创建?

      1. 默认情况下, 第一次访问时,Servlet被创建

      2. 可以配置Servlet的创建时机,如下:

        <!-- 配置Servlet -->
        <servlet>
        <servlet-name>demo2</servlet-name>
        <servlet-class>org.taoguoguo.web.ServletDemo2</servlet-class>
        <!--指定Servlet的创建时机
        1.第一次被访问时创建,创建
        <load-on-startup>的值为负数,默认为 -1,或者不配置 也是在第一次访问被创建
        2.在服务器启动时,创建
        <load-on-startup>的值为0或正整数 一般设置为 1
        -->
        <load-on-startup>-1</load-on-startup>
        </servlet> <servlet-mapping>
        <servlet-name>demo2</servlet-name>
        <url-pattern>/demo2</url-pattern>
        </servlet-mapping>

        注意:Servlet的 init 方法只执行一次,说明servlet在内存中只存在一个对象,是单例的,所以多个用户线程同时访问时,可能存在线程安全问题。

        解决方案:

        1.尽量不要在Servlet中定义成员变量,因为成员变量时每个线程共享的资源,可能有的线程会修改,而部分线程会去获取,容易出现数据安全问题。尽量在方法内部定义局部变量代替成员变量。因为局部变量是在每个线程方法栈中独享的一份资源,可以保证数据安全性。

        2.如果必须要定义成员变量,不要在方法中去修改成员变量的值,仅用于线程获取,是不会有线程安全问题的。

        3.在servlet解决多线程安全问题时,切记使用同步锁,因为会非常的消耗性能

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

    • 每次访问 Servlet 时,service 方法都会被调用一次
  3. 被销毁:执行 destory 方法,只执行一次

    • servlet 被销毁时执行,只有服务器正常关闭时,servlet 被销毁 才会执行destory 方法。destory 是在被销毁之前执行,一般用于释放资源

Servlet 3.0:

  • 支持注解配置,可以不需要web.xml了

  • 使用方法:在创建的servlet 上 加上注解 @WebServlet("资源路径"),支持如下写法

    @WebServlet(urlPatterns = "/demo3")

    @WebServlet("/demo3")

HTTP

概念:

Hyper Text Transfer Protocol 超文本传输协议

传输协议:

定义了 客户端 和 服务器端通信时,发送数据的格式

特点:

1.基于TCP/IP的高级协议(安全的,需要经过三次握手)

2.默认端口号:80

3.基于 请求/响应 模型 (请求响应 一 一 对应,一次请求,一次响应)

4.无状态的:每次请求之间相互独立,不能交互数据

历史版本:

1.0:每一次请求,建立一次新的连接

1.1: 复用连接,对缓存性能较好

请求消息数据格式:

  1. 请求行

    • 组成格式:请求方式 请求url 请求协议/版本

      请求行: GET	/login.html	HTTP/1.1
    • HTTP协议有7种请求方式,常用的有两种请求头

      • GET

        1. 请求参数在请求行中,在url后。

        2. 请求的url长度有限制

        3. 相对安全

      • POST

        1. 请求参数在请求体中

        2. 请求的url是没有限制的

        3. 相对安全

  2. 请求头(客户端告知服务端自身信息)

    • 组成格式: 请求头名称:请求头值

      Host:localhost	当前主机
      User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
      //作用:服务端可以根据这个头信息区分不同浏览器解决浏览器兼容问题
      Accept:告诉服务器,浏览器可以解析哪些格式类型的信息 如 text/html
      Accept-Language: 告诉服务器所支持的语言环境
      Accept-Encoding: 告诉服务器所支持的压缩格式
      Referer:http://localhost:8080/login.html 告诉服务器,当前请求从那里来
      Referer的常用场景: 1.防盗链 2.统计工作
      Connection: keep-alive 连接状态 保持活跃服用
      Upgrade-Insecure-Requests:1 浏览器升级信息
  3. 请求空行

    • 空行,用于用于分割POST请求的请求头,和请求体的
  4. 请求体

    • 封装POST请求消息的请求参数 username=zhangsan

响应消息数据格式:

服务端发送给客户端的数据

1.响应行

  1. 格式:协议/版本 响应状态码 状态码描述
HTTP/1.1 200 OK

响应状态码:服务器告诉客户端本次请求和响应的一个状态

  • 状态码都是三位数字:

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

    2xx: 成功。代表: 200

    3xx: 重定向。

        302(重定向) 服务器响应状态码302 并给客户端响应一个地址,客户端收到302状态码后自动请求对应地址进行重定向。
    
        304 (访问缓存)例如请求访问图片等大二进制数据时较慢,当浏览器请求服务器,服务器返回图片资源时,浏览器会进行图片的本地缓存,当再次访问时,如果服务器资源没有变化,
    并且当前浏览器存在图片缓存,可返回状态码 304 告知浏览器访问缓存,提高交互体验。

    4xx: 客户端错误

         404 客户端访问路径错误,未找到访问资源 -
    
         405 请求方式没有对应的 doXXX 方法

    5xx: 服务端错误

         500 服务器内部异常

2.响应头

1.格式: 头名称:值

2.常见的响应头:
Content-Type: 服务器告诉客户端本次响应体数据格式及编码格式
Content-Length: 响应字节长度
Date: 响应时间
Content-disposition: 服务器告诉客户端以什么格式打开响应体数据
默认值: in-line 在当前页面打开
attachment;filename 以附件形式打开响应体,文件下载中使用

3.响应空行

4.响应体

响应体就是传输的响应数据,有整个页面的解析响应,也有二进制数据

Request

request对象和response对象的原理

  1. request对象和response对象是由服务器创建的,我们来使用它
  2. request对象是来获取请求消息,response对象是来设置响应消息的

Request对象继承体系结构

  • ServletRequest -- 接口

    • HttpServletRequest -- 子接口(继承 ServletRequest)

      • org.apache.catalina.connector.RequestFacade 类(Tomcat)

request功能:

1.获取请求消息数据

1.获取请求行数据

*GET /day14/demo1?name=zhangsan HTTP/1.1

  • 获取请求方式:GET

    String getMethod();
  • 获取虚拟目录:/day14

    String getContextPath();
  • 获取servlet路径:/demo1

    String getServletPath();
  • 获取get方式请求参数:name=zhangsan

    String getQueryString();
  • 获取请求的URI:/day14/demo1

    //URI:	统一资源标识符	共和国
    //URL: 统一资源定位符 中华人民共和国
    String getRequestURI(); //URI如: /day14/demo1
    StringBuffer getRequestURL(); //URL如: http://localhost/day14/demo1
  • 获取协议及版本:HTTP/1.1

    String getProtocol();	//ServletRequest中的方法
  • 获取客户机的IP地址

    String getRemoteAddr();
2.获取请求头数据
  • String getHeader(String var1);	//通过请求头的名称获取请求头的值
  • Enumeration<String> getHeaders(String var1);	//获取所有的请求头名称

根据所有请求头获取所有的请求头对应的值:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
Enumeration<String> names = request.getHeaderNames();
while(names.hasMoreElements()){
String s = names.nextElement();
System.out.println(s +":" + request.getHeader(s));
}
}
  • 判断浏览器版本,根据请求头 1user-agent的值来判断 是否包含指定浏览器关键字,比如Chrome

    user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
  • 判断请求来源,用于防盗链 可根据请求头 referer的值来判断

    referer:http://localhost:8080/hello.html
3.获取请求体数据
请求体:只有POST请求,才有请求体,在请求体中封装了POST请求的请求参数

步骤:

1.获取流对象

BufferedReader getReader()		//获取字符输入流,只能操作字符数据

获取页面表单提交数据

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求消息体-请求参数
//1.获取字符流
BufferedReader br = request.getReader();
//2.读取数据
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
}

2.再从流对象中拿数据

ServletInputStream getInputStream()	//获取字节输入流 可以操作所有类型数据 文件上传中使用
4.其他功能
1.获取请求参数通用方式:

不论是get 还是post 请求方式都可以使用下列方法来获取请求参数

  1. String getParameter(String name) 根据请求参数获取参数值 username=zhangsan&password=123

    @WebServlet("/demo5")
    public class ServletDemo5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //post获取请求参数
    String username = request.getParameter("username");
    System.out.println("post");
    System.out.println(username); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //get获取请求参数
    String username = request.getParameter("username");
    System.out.println("get");
    System.out.println(username);
    }
    }
  2. String[] getParameter(String name) 根据请求参数获取参数值的数组 hobby=study&hobby=eat

  3. Enumeration getParameterNames() 获取所有请求的参数名称

  4. Map<String, String[]>getParameterMap()获取所有的请求参数和值 封装为一个Map返回

    技巧:获取前台参数时,可创建一个Java Bean对象,然后使用BeanUtils.populate(Object obj,Map map)

     	将map集合的键值信息,封装到 Java Bean对象中

获取请求参数乱码问题

  1. get方式:Tomcat 8 已经将get方式乱码问题解决

  2. post方式:会乱码

    解决方法:获取参数前设置一下流的编码,编码来自于请求提交页面编码格式

    request.setCharacterEncoding("utf-8");
2.请求转发:

一种在服务器内部资源跳转的方式

步骤:

		1.通过 request 对象获取请求转发器对象,RequestDispatcher getRequestDispatcher(String var1);	

		2.使用	RequestDispatcher 来进行转发:forward(ServletRequest var1, ServletResponse var2)

特点:

		1.浏览器地址栏不发生变化

		2.转发只能转发当前服务器的内部资源,比如不能转发到访问百度

		3.转发是一次请求
3.共享数据
域对象:一个有作用范围的对象,可以在范围内共享数据。

request域:代表一次请求,一般用于一次请求转发的访问多个资源中共享数据

方法:
1.setAttribute(String name,Object obj); 存储对象
2.Object getAttribute(String name); 通过键获取值
3.removeAttribute(String name); 通过键移除值
4.获取ServletContext
ServletContext getServletContext()

Response

功能:设置响应消息

1.设置响应行

1.格式:HTTP /1.1 200

 一般是设置响应状态码   :setStatus(int sc)

2.设置响应头

	setHeader(String name, String value)

3.响应体

使用步骤:

1.获取输出流

	1.字符输出流:PrintWriter getWriter()

	2.字节输出流:ServletOutputStream getOutputStream()

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

案例:

1.完成重定向

重定向是客户端浏览器访问服务器时,服务器响应客户端访问重定向另一个资源进行处理的过程

第一种方式:
设置响应状态码为302 response.setStatus(302);
设置响应头location 值为要跳转的路径 response.setHeader("location","/demo7"); 第二种方式:
使用response对象的重定向方法: response.sendRedirect("/demo7");

重定向特点

1.地址栏发生变化

2.重定向可以访问其他站点服务器资源

3.重定向是多次请求,不能使用request域对象来共享数据

路径分类

  1. 相对路径:通过相对路径不可以确定唯一资源

    • 如:./index.html
    • 相对路径通常以 . 开头
    • 写法规则:先确定当前资源和访问的目标资源之间的相对位置关系
    • ./ 代表当前目录,也可省略 , ../ 代表上一级目录

    相对目录路径写法举例:

    比如一个项目,有个路径为 demo1的 Servlet,访问路径为::

    http://localhost:8080/project/demo1 -> 目标资源

    项目的web目录下有个index.html,访问路径为:

    http://localhost:8080/project/index.html -> 当前资源

    当前资源和目标资源在同一个层级上,那么从 index.html访问 demo1的路径通常为

    <a href="./demo1">访问Demo1</a> 当前目录的 ./ 是可以省略的,所以也可以简写为:demo1

  2. 绝对路径:通过绝对路径可以确定唯一资源

2.服务器输出字符数据到浏览器

  1. 获取字符输出流,这个流是获取的不是创建的,说明流向是到客户端浏览器的

  2. 输出数据

     //1.获取字符输出流
    PrintWriter pw = response.getWriter();
    //2.输出数据
    pw.write("hello world");
    • 乱码问题:

      1. 设置输出流的默认编码及设置响应头,服务器告诉客户端本次响应体数据格式及编码格式

        //设置流的默认编码
        response.setCharacterEncoding("utf-8");
        //设置一下响应头 Content-Type: 服务器告诉客户端本次响应体数据格式及编码格式
        response.setContentType("text/html;charset=utf-8");

3.服务器输出字节数据到浏览器

  1. 获取字节输出流,可以输出任意类型字节数据,如果输出是中文,同样需要注意编码一致问题。

    //1.获取字节输出流
    ServletOutputStream outputStream = response.getOutputStream();
    //2.输出数据
    outputStream.write("hello world".getBytes());

4.验证码

验证码的实现非常简单,就是后台生成随机数,然后通过画笔画出验证码图案进行填充,实现如下:

  1. html表单

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>注册页面</title>
    </head>
    <body>
    <img src="/CheckCodeServlet" id="checkCode" />
    <a id="changeCheckCode" href="#" onclick="clickChangeCheckCode()">看不清,换一张?</a>
    </body> <script>
    /**
    * 分析:点击超链接或者图片,需要换一张
    * 1.给超链接和图片绑定单机事件
    * 2.重新设置的src属性值
    */
    window.onload = function () {
    //1.获取图片对象
    var img = document.getElementById("checkCode");
    //2.绑定单机事件
    img.onclick = function () {
    //加时间戳,防止浏览器缓存,验证码刷新重复问题
    var date = new Date().getTime();
    img.src = "/CheckCodeServlet?"+date;
    }
    } function clickChangeCheckCode() {
    var img = document.getElementById("checkCode");
    var date = new Date().getTime();
    img.src="/CheckCodeServlet?"+date;
    } </script>
    </html>
  2. 验证码生成Servlet

    package org.taoguoguo.web;
    
    import javax.imageio.ImageIO;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.util.Random; /**
    * 验证码生成Servlet
    */
    @WebServlet(name = "CheckCodeServlet", value = "/CheckCodeServlet")
    public class CheckCodeServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1.创建一个图像缓冲区对象
    int width = 100;
    int height = 50;
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
    //2.美化图片
    //2.1填充背景色
    Graphics graphics = image.getGraphics(); //画笔对象
    graphics.setColor(Color.pink); //设置画笔颜色
    graphics.fillRect(0,0,width,height);
    //2.2画边框
    graphics.setColor(Color.blue);
    graphics.drawRect( 0,0,width-1,height-1);
    //2.3写验证码
    String code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789";
    //生成随机角标
    Random random = new Random();
    for (int i=1; i<=4; i++){
    int index = random.nextInt(code.length());
    //获取字符
    char c = code.charAt(index);
    graphics.drawString(String.valueOf(c),width/5*i,height/2);
    }
    //2.4画干扰线
    graphics.setColor(Color.green);
    for(int i=0; i<10; i++){
    int x1 = random.nextInt(width);
    int y1 = random.nextInt(height); int x2 = random.nextInt(width);
    int y2 = random.nextInt(height);
    graphics.drawLine(x1,y1,x2,y2);
    } //3.将图片输出到页面展示
    ImageIO.write(image,"jpg",response.getOutputStream());
    } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.doPost(request,response);
    }
    }

ServletContext对象

概念:

代表整个 web 应用,可以和程序的容器(服务器)来进行通信

获取

  1. 通过request对象获取

    request.getServletContext();
  2. 通过HttpServlet获取

    this.getServletContext();

注意:ServletContext 既然代表整个应用,那么它只有唯独一份,无论通过哪种方式获取,都是同一个对象。

举例:

//1.通过request对象获取
ServletContext context1 = request.getServletContext();
//2.通过HttpServlet获取
ServletContext context2 = this.getServletContext(); System.out.println(context1);
System.out.println(context2); System.out.println(context1 == context2); 输出:
org.apache.catalina.core.ApplicationContextFacade@586b90db
org.apache.catalina.core.ApplicationContextFacade@586b90db
true

功能

  1. 获取 MIME 类型

    MIME类型:在互联网通信过程中定义的一种文件数据类型

    格式:大类型/小类型 比如: text/html image/jpeg

    用途:响应返回时,设置响应头 Content-Type 告知浏览器用对应的引擎来解析返回数据

    获取方式

    String getMimeType(String var1);

    举例:

    public class ServletContextDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    ServletContext context = this.getServletContext();
    String fileName = "a.jpg";
    String mimeType = context.getMimeType(fileName);
    System.out.println(mimeType);
    } 输出:
    image/jpeg
  2. 域对象:共享数据

    范围:所有用户所有请求数据

    1. setAttribute(String name, Object value);
    2. getAttribute(String name);
    3. removeAttribute(String name);
    /*
    * 在Servlet1中存储值,在Servlet2中获取值
    */
    @WebServlet("/servletContextDemo1")
    public class ServletContextDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    ServletContext context = this.getServletContext();
    context.setAttribute("zhangsan","token123456");
    } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.doPost(request,response);
    }
    } package org.taoguoguo.web.servletcontext; import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException; /**
    * @author taoGG
    * @description
    * @create 2020-10-28 22:21
    */
    @WebServlet("/servletContextDemo2")
    public class ServletContextDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    ServletContext context = this.getServletContext();
    String str = (String) context.getAttribute("zhangsan");
    System.out.println(str);
    } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.doPost(request,response);
    }
    } 输出:
    token123456
  3. 获取文件的真实(服务器)路径

    package org.taoguoguo.web.servletcontext;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException; /**
    * @author taoGG
    * @description
    * @create 2020-10-28 22:21
    */
    @WebServlet("/servletContextDemo1")
    public class ServletContextDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    ServletContext context = this.getServletContext();
    String realPath1 = context.getRealPath("/b.txt"); // web目录下
    String realPath2 = context.getRealPath("/WEN-INF/a.txt"); // WEB-INF目录下的资源访问
    String realPath3 = context.getRealPath("/WEB-INF/calsses/a.txt"); //src目录下 System.out.println("web目录下:" + realPath1);
    System.out.println("WEB-INF下" + realPath2);
    System.out.println("src目录下" + realPath3); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.doPost(request,response);
    }
    }
  4. 文件下载案例

    1. download.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8">
      <title>文件下载</title>
      </head>
      <body>
      <a href="/downloadServlet?fileName=001.jpg">图片下载</a>
      <a href="/downloadServlet?fileName=代码.jpg">图片(中文名称)下载</a>
      </body>
      </html>
    2. DownloadServlet

      package org.taoguoguo.web.download;
      
      import utils.DownLoadUtils;
      import javax.servlet.ServletContext;
      import javax.servlet.ServletException;
      import javax.servlet.ServletOutputStream;
      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.FileInputStream;
      import java.io.IOException; /**
      * @author taoGG
      * @description
      * @create 2020-10-28 23:14
      */
      @WebServlet("/downloadServlet")
      public class DownloadServlet 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("/img/" + fileName);
      //2.2使用字节流关联
      FileInputStream fis = new FileInputStream(realPath); //3.设置response响应头
      //3.1设置响应头类型 content-type
      String mimeType = context.getMimeType(fileName); //获取文件MIME类型
      response.setHeader("content-type",mimeType);
      //3.2解决中文文件名问题,设置响应头打开方式
      String agent = request.getHeader("user-agent");
      fileName = DownLoadUtils.getFileName(agent, fileName);
      response.setHeader("content-disposition","attachment;filename="+fileName); //4将输入流的数据写出到输出流中
      ServletOutputStream outputStream = response.getOutputStream();
      byte[] buff = new byte[1024*8]; //字节缓冲数组
      int len = 0; //读到的个数
      while ((len = fis.read(buff))!=-1){ //未读到末尾
      outputStream.write(buff,0,len); //从0开始写,写读到的长度
      }
      fis.close();
      } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      this.doPost(request,response);
      }
      }

    中文文件名称问题

    解决思路:

    1. 获取客户端使用的浏览器版本信息
    2. 根据不同的版本信息,设置fileName的编码方式不同

Java Web专题攻关的更多相关文章

  1. Java Web专题

  2. 【原创】三分钟教你学会MVC框架——基于java web开发(2)

    没想到我的上一篇博客有这么多人看,还有几位看完之后给我留言加油,不胜感激,备受鼓励,啥都别说了,继续系列文章之第二篇.(如果没看过我第一篇博客的朋友,可以到我的主页上先浏览完再看这篇文章,以免上下文对 ...

  3. Java Web 高性能开发,第 2 部分: 前端的高性能

    Web 发展的速度让许多人叹为观止,层出不穷的组件.技术,只需要合理的组合.恰当的设置,就可以让 Web 程序性能不断飞跃.Web 的思想是通用的,它们也可以运用到 Java Web.这一系列的文章, ...

  4. Java Web 高性能开发,第 1 部分: 前端的高性能

    Web 发展的速度让许多人叹为观止,层出不穷的组件.技术,只需要合理的组合.恰当的设置,就可以让 Web 程序性能不断飞跃.所有 Web 的思想都是通用的,它们也可以运用到 Java Web.这一系列 ...

  5. 使用Intellij idea新建Java Web项目(servlet) 原理及初步使用

    准备 JDK       (配置JDK_HOME\bin   和 CLASSPATH)   注:JDK8下载已经需要注册了,请使用JDK11(现在是官方长期支持的版本)     对于我们新手来说,JD ...

  6. 大型Java进阶专题(一) 前言

    前言 ​ 各位读者好,本系列为Java进阶专题,为那些有一定工作经验,做了多年业务的码农,希望突破技术瓶颈,但没有形成系统的Java只是体系,缺乏清晰的提升方法和学习路径的人,比如作者本人.该课题的是 ...

  7. Java登录专题-----创建用户(一)

    Java登录专题-----创建用户(一) 我来填坑了 创建用户 入参 应该包括: 用户姓名,用户密码,用户手机号,用户所属机构 用户版本号,角色id 出参: 没有 数据结构: JavaBean    ...

  8. 高效 Java Web 开发框架 JessMA v3.5.1

    JessMA 是功能完备的高性能 Full-Stack Web 应用开发框架,内置可扩展的 MVC Web 基础架构和 DAO 数据库访问组件(内部已提供了 Hibernate.MyBatis 与 J ...

  9. 高效 Java Web 开发框架 JessMA v3.4.1

    JessMA 是功能完备的高性能 Full-Stack Web 应用开发框架,内置可扩展的 MVC Web 基础架构和 DAO 数据库访问组件(内部已提供了 Hibernate.MyBatis 与 J ...

  10. java web 之客户关系管理系统

    这个周末真的是觉得自己学会了一个比较高大上的本领,为什么这么觉得呢?那是因为星期六的时候觉得自己可以看看源码能做出来,可是让我头疼的是花费了一上午的时间还是没有弄出来,还好上天给了我机会,要是没有老师 ...

随机推荐

  1. P9210 题解

    学长给我们讲了就顺便来写一篇题解. 首先最优解一定包括根,不然一定可以从当前根连接一条到根的链. 然后考虑假若最大导出子树深度为 \(n\) 则显然可以把深度为 \(n\) 的节点全部选上,然后每个节 ...

  2. 韦东山freeRTOS系列教程之【第八章】事件组(event group)

    目录 系列教程总目录 概述 8.1 事件组概念与操作 8.1.1 事件组的概念 8.1.2 事件组的操作 8.2 事件组函数 8.2.1 创建 8.2.2 删除 8.2.3 设置事件 8.2.4 等待 ...

  3. 浙江省赛决赛 misc2 蝎子

    Misc 2 tcp.stream eq 0 内得知是冰蝎3.0,key是e46023a69f8db309 <?php @error_reporting(0); session_start(); ...

  4. Quartus Ⅱ调用FIFO IP核方法实现求和(Mega Wizard)

    摘要:本次实验学习记录主题为"FIFO_IP核实现算术求和",主要内容是上位机通过串口向FPGA发送一定规格的数字矩阵,FPGA对矩阵处理,按规定逻辑实现求和运算,将结果返回串口转 ...

  5. 持久化技术Mybatis知识精讲【形成知识体系篇】

    环境要求 JDK1.8及以上版本 MySQL数据库 Apache Maven 3.6.1构建工具 IDEA/VSCode/Eclipse开发工具任选其一 思维导图:Xmind ZEN 技术要求 熟悉J ...

  6. 网易数帆实时数据湖 Arctic 的探索和实践

    作者 | 蔡芳芳 采访嘉宾 | 马进 网易数帆平台开发专家 数据中台也要从离线为主走向实时化,湖仓一体是第一步. 数据从离线到实时是当前一个很大的趋势,但要建设实时数据.应用实时数据还面临两个难题.首 ...

  7. git 更新某个目录或文件

    不多说直接贴代码 更新文件 $ git fetch remote: Counting objects: 8, done. remote: Compressing objects: 100% (3/3) ...

  8. 可视化—gojs 超多超实用经验分享(二)

    想了想序号还是接上一篇分享的的序号接着写,如果在本文中没有获取需要的答案,可以移步去看看上一篇的分享.gojs 超多超实用经验分享(一) 目录 22. 指定线段连接到节点的某一个特定的接口上 23. ...

  9. oeasy教您玩转vim - 22 - 配置文件

    配置文件 回忆上节课内容 我们上次了解到了状态横条 通过转义表示 item 控制 item 宽度的方法 将 item 成组的方法 还有一个总开关 laststatus 但是每次都要写很长的一段话来配置 ...

  10. oeasy教您玩转vim - 48 - # ed由来

    ​ 范围控制 回忆上节课内容 我们这次研究了mark的定义和使用 mb定义 'b跳转 可以对marks,查询删除 三种marks 小写 本文件内 大写 跨文件 数字 配置文件中 甚至可以在行编辑中,使 ...