javaweb基础之request和response

1、多个路径映射一个servlet

多个请求路径映射一个servlet:

    <servlet>
        <servlet-name>helloservlet</servlet-name>
        <servlet-class>com.guang.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--第一种映射,添加一个url-pattern-->
    <servlet-mapping>
        <servlet-name>helloservlet</servlet-name>
        <url-pattern>/hello</url-pattern>
        <url-pattern>/hell</url-pattern>
    </servlet-mapping>
    <!--第二种映射,添加一个servlet-mapping-->
    <servlet-mapping>
        <servlet-name>helloservlet</servlet-name>
        <url-pattern>/llo</url-pattern>
    </servlet-mapping>

这两种方式都可以让路径映射到具体的servlet类来进行处理对应的请求。

2、请求路径的三种格式

也就是说url-pattern的配置方式一共有三种配置:

  • 完全路径匹配:以/开头
  • 目录匹配:以/开头,以*结尾
  • 扩展名匹配:不能够以/开头,而是以*开头的

分别举几个例子来进行说明:

完全路径匹配:上面的xml文件中配置的都是完全路径匹配

目录匹配:

 <!-- 目录匹配: 以/ 开始, 以*结尾 *表示后面的内容可以有,也可以没有-->
 <servlet-mapping>
        <servlet-name>hello02</servlet-name>
        <url-pattern>/hello02/*</url-pattern>
 </servlet-mapping>

扩展名匹配:

例如:  *.action;  访问: aa.action, bb.action, c.action;   错误写法: /*.do, 不可以写*.jsp,*.html

<!--后缀名匹配的方式 : 以*打头, 以后缀名结尾-->
    <servlet-mapping>
        <servlet-name>hello02</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

注意的地方:

  • 一个路径只能对应一个servlet, 但是一个servlet可以有多个路径

  • tomcat获得匹配路径时,优先级顺序:完全路径匹配> 目录匹配 > 扩展名匹配

3、serlvet的执行流程

1、默认是在客户端第一次访问的时候,Tomcat根据客户端应用找到是哪个项目路径,然后根据url-pattern找到对应的servlet来进行处理

2、Tomcat会找到对应的servlet,然后Tomcat利用反射来创建对应的对象(单例对象);

3、在创建完成对象之后,会去调用init()方法来完成对该servlet的初始化操作;

4、Tomcat会针对每次到达的请求,都会从底层的线程池中获取得到新的线程,然后调用该servlet的service方法来进行处理;

5、在容器关闭阶段,会调用destroy方法来完成对servlet的销毁;

4、servlet的声明周期方法

一共有是三个,在继承了Servlet接口中,五个方法中,有三个是生命周期方法:

    void init(ServletConfig var1) throws ServletException;

    ServletConfig getServletConfig();

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    String getServletInfo();

    void destroy();

其中:

    void init(ServletConfig var1) throws ServletException;


    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;


    void destroy();
  1. 常规【重点】

    (1):默认情况下, 来了第一次请求, 会调用init()方法进行初始化【调用一次】

              **作用**:用于初始化.. 准备工作(创建流对象 | 准备数据库连接..)
    

    (2):任何一次请求 都会调用service()方法处理这个请求

     		 **作用**:用于接收请求、处理请求
    

    (3):服务器正常关闭或者项目从服务器移除, 调用destory()方法进行销毁【调用一次】

     		 **作用**:用于处理收尾的工作。 关流 |  释放连接
    
  2. 扩展

    servlet是单例多线程的, 尽量不要在servlet里面使用全局(成员)变量,可能会导致线程不安全(如果要使用,要保证线程安全)

    单例: 只有一个对象(init()调用一次, 创建一次)

    多线程: 服务器会针对每次请求, 开启一个线程调用service()方法处理这个请求

    因为是多线程的原因,才会导致如果使用了全局变量过程中会出现线程安全问题。

来举一个例子说明:

public class SyncronizedServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("servlet初始化方法,用来给当前的servlet进行初始化的");
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        synchronized (this){
            try {
                Thread.sleep(10000);
                servletResponse.setContentType("text/html;charset=utf-8");
                servletResponse.getWriter().println("当前的线程是:"+Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
        System.out.println("做一些收尾性工作,也就是关闭流什么之类的");
    }
}

在web.xml中进行配置:

    <servlet>
        <servlet-name>syncronized</servlet-name>
        <servlet-class>com.guang.servlet.SyncronizedServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>syncronized</servlet-name>
        <url-pattern>/syncronized</url-pattern>
    </servlet-mapping>

连续发送三个请求,然后可以看到单例多线程对象servlet,正在排队执行。

4.1、ServletConfig

Servlet的配置对象, 可以使用用ServletConfig来获得Servlet的初始化参数,(在SpringMVC里面会遇到)

注意:可以在配置中修改servlet的创建时期,默认是第一次访问的时候加载实例;我们可以通过修改servlet配置,让其提前到在容器初始化的时候就加载该实例。

对应的xml配置文件如下所示:

    <!--配置ServletConfigServlet-->
    <servlet>
        <servlet-name>servletconfig</servlet-name>
        <servlet-class>com.guang.servlet.ServletConfigServlet</servlet-class>
        <init-param>
            <param-name>password</param-name>
            <param-value>123456</param-value>
        </init-param>
        <!--表示的是在容器启动的时候就开始加载当前的servlet-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>servletconfig</servlet-name>
        <url-pattern>/servletconfig</url-pattern>
    </servlet-mapping>

对应的servlet代码是:

public class ServletConfigServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        // 获取得到serviceconfig对象
        String password = servletConfig.getInitParameter("password");
        System.out.println("在web.xml文件中配置的对当前servlet的初始化参数是:"+password); // 123456
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

5、ServletContext

1、servlet的应用上下文,在一个servlet项目中,有且只有一个servletcontext对象。

2、作用:

  1. 可以存放数据和获取数据 【使用最多】,可以给servlet共享数据
  2. 可以获取文件的MIME
  3. 获取读取文件资源【偶尔用】
  4. 获取全局的配置参数。

3、获取方式:只要是servlet类,都是可以得到servlet上下文对象

5.1、让多个servlet之间共享数据

对应的代码所示:

@WebServlet(name = "ServletContextOne", value = "/ServletContextOne")
public class ServletContextOne extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
        servletContext.setAttribute("data1",new String("hello,world"));
    }
}
@WebServlet(name = "ServletContextTwo", value = "/ServletContextTwo")
public class ServletContextTwo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Object hello = this.getServletContext().getAttribute("data1");
        System.out.println("对应的值是:"+hello.toString());
    }
}

首先访问ServletContextOne,然后再去访问ServletContextTwo,就可以获取得到在ServletContextOne中存入的数据即可。

5.2、获取得到文件mime类型和全局初始化参数

1、在web.xml全局配置文件中来进行添加对应的全局初始化参数

    <context-param>        <param-name>companyname</param-name>        <param-value>lig</param-value>    </context-param>

2、编写一个servlet来统一进行验证:

@WebServlet(name = "ServletContextThree", value = "/ServletContextThree")
public class ServletContextThree extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
        String file1 = "a.txt";
        String file2 = "a.mp3";
        String mimeType1 = servletContext.getMimeType(file1);
        String mimeType2 = servletContext.getMimeType(file2);
        System.out.println(file1+"的资源类型是:"+mimeType1);
        System.out.println(file2+"的资源类型是:"+mimeType2);
        System.out.println("------------------------------");
        System.out.println("------------------------------");
        System.out.println("------------------------------");
        String companyname = servletContext.getInitParameter("companyname");
        System.out.println("全局初始化参数是:"+companyname);
    }
}

对应的控制台显示:

a.txt的资源类型是:text/plain
a.mp3的资源类型是:audio/mpeg
------------------------------
------------------------------
------------------------------
全局初始化参数是:lig

5.3、获取得到web资源路径

    • String getRealPath(String path);根据资源名称得到资源的绝对路径.
    • getResourceAsStream(String path) ;返回制定路径文件的流

注意: filepath:直接从项目的根目录开始写

对应的代码:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    //1.获得文件的绝对路径 getRealPath()这个方法的路径已经在项目下了, 已经到了web目录下了    String realPath = getServletContext().getRealPath("a.txt");    System.out.println("realPath="+realPath);    //2.获得文件的输入流  getResourceAsStream(String path);这个方法的路径已经在项目下了, 已经到了web目录下了    //new FileInputStream(realPath);    InputStream is = getServletContext().getResourceAsStream("a.txt");    System.out.println(is);}

控制台输出结果:

realPath=D:\hello\myproject\javaweb\out\artifacts\servlet_one_war_exploded\a.txtjava.io.ByteArrayInputStream@44554de5

5.4、ServletContext小练习

需求:统计网站一共被访问了多少次?

首先写两个servlet来进行功能区分:一个负责统计,另外一个负责显示

书写两个servlet:

@WebServlet(name = "LoginCountServlet", value = "/LoginCountServlet")
public class LoginCountServlet extends HttpServlet {

    private static AtomicInteger count = new AtomicInteger(1);

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    /**
     * 这里应该是通过一个唯一标识来表示登录的次数,过滤掉重复登录的情况。这里是简单,统计所有的情况即可
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = this.getServletContext();
        Object loginCount = servletContext.getAttribute("loginCount");
        if (Objects.isNull(loginCount)) {
            servletContext.setAttribute("loginCount", count);
        } else {
            count.getAndDecrement();
            servletContext.setAttribute("loginCount", count);
        }
    }
}

负责展示的servlet:

@WebServlet(name = "ShowLoginServlet", value = "/ShowLoginServlet")public class ShowLoginServlet extends HttpServlet {    @Override    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        this.doPost(request, response);    }    @Override    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        ServletContext servletContext = this.getServletContext();        AtomicInteger loginCount = (AtomicInteger) servletContext.getAttribute("loginCount");        int currentCount = loginCount.get();        response.getWriter().println("您是第"+currentCount+"位登录用户");    }}

分别请求并进行展示即可

6、request

在使用javaweb进行开发过程中,每个请求都会被Tomcat服务器封装称为一个request请求对象,request请求对象封装了一个请求中的所有信息。

request代表请求对象. 原型是HttpServletRequest, 服务器创建好的, 以形参的方式存在doGet()/doPost()方法里面

request作用

  • 操作请求三部分(行,头,体)
  • 请求转发 . 转发这个请求给别人
  • 作为域对象存数据 像ServletContext一样,存|取数据

6.1、操作请求行

实际上的操作,就只有获取。因为已经被Tomcat服务器默认给封装好了,所以不需要来对其进行修改。

获取客户机信息(操作请求行)

请求方式  请求路径(URI)  协议版本

GET  /request/web/register.htm?username=zs&password=123456   HTTP/1.1	
  • getMethod();获取请求方式
  • getRemoteAddr() ;获取客户机的IP地址(知道是谁请求的)
  • getContextPath();获得当前应用工程名(部署的路径);
  • getRequestURI();获得请求地址,不带主机名
  • getRequestURL();获得请求地址,带主机名
  • getServerPort();获得服务端的端口
  • getQueryString();获的请求参数(get请求的,URL的?后面的. eg:username=zs&password=123456)
        //method=GET        String method = req.getMethod();        System.out.println("method=" + method);        //uri=/request/request01        String uri = req.getRequestURI();        System.out.println("uri=" + uri);        //url=http://localhost:8080/request/request01        StringBuffer url = req.getRequestURL();        System.out.println("url=" + url);        //protocol=HTTP/1.1        String protocol = req.getProtocol();        System.out.println("protocol=" + protocol);

6.2、操作请求头

请求头: 浏览器告诉服务器自己的属性,配置的, 以key value存在, 可能一个key对应多个value。

getHeader(String name)

  • User-Agent: 浏览器信息
  • Referer:来自哪个网站(防盗链)
        //2. 可以获取请求头        String ua = req.getHeader("User-Agent");        System.out.println("ua=" + ua);        	   Enumeration<String> headerNames = req.getHeaderNames();        while(headerNames.hasMoreElements()){            String header = headerNames.nextElement();            String value = req.getHeader(header);            System.out.println(header + "=" + value);        }

6.3、操作请求体

操作请求体:最主要的是用来获取得到请求体中的参数来进行操作的。

对于get请求方式来说,是没有请求体的。所以这里就只针对的是post请求方式。

获得请求参数

法名 描述
String getParameter(String name) 获得指定参数名对应的值。如果没有则返回null,如果有多个获得第一个。 例如:username=jack
String[] getParameterValues(String name) 获得指定参数名对应的所有的值。此方法专业为复选框提供的。 例如:hobby=抽烟&hobby=喝酒&hobby=敲代码
Map<String,String[]> getParameterMap() 获得所有的请求参数。key为参数名,value为key对应的所有的值。

响应的代码展示:

@WebServlet(name = "Body1Servlet", value = "/Body1Servlet")
public class Body1Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取得到单个参数的值,如果没有返回null
        String username = request.getParameter("username");
        System.out.println("获取得到的参数是:"+username);
        System.out.println("----------------------");
        // 获取得到指定参数的值,一个key对应的可以有多个value
        String[] hobbies = request.getParameterValues("hobby");
        for (String hobby : hobbies) {
            System.out.println("hobby对应的爱好有:"+hobby);
        }
        System.out.println("----------------------");
        // 获取得到所有的!
        Map<String, String[]> parameterMap = request.getParameterMap();

    }
}

浏览器请求:

http://localhost:8080/servlet_one_war_exploded/Body1Servlet?username=lig&hobby=1&hobby=2&hobby=3

对应的控制台显示:

获取得到的参数是:lig----------------------hobby对应的爱好有:1hobby对应的爱好有:2hobby对应的爱好有:3----------------------

但是如果参数过多,还要封装到javabean中去,那么调整好对应的参数之后,还需要调用对象之后来进行setXxx方法来进行操作。

非常麻烦,那么直接利用BeanUtils(Apache Commons组件),来简化JavaBean封装数据。

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

       /* //1. 获取数据
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String address = req.getParameter("address");
        String phone = req.getParameter("phone");

        //2. 封装对象
        User user = new User(username , password , address , phone);
        System.out.println("user=" + user);

        */

        try {
            //1. 获取参数 还有一些特殊的地方,爱好,,有三个数据,???
            Map<String, String[]> map = req.getParameterMap();

            //2. 创建对象
            User u = new User();

            //3. 把参数封装到对象身上
            BeanUtils.populate(u , map);

            //4. 打印一下
            System.out.println("u=" + u);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

注意:JavaBean属性需要和Map的key一致,也就是说JavaBean属性需要和表单的name一致。

乱码处理

我们在输入一些中文数据提交给服务器的时候,服务器解析显示出来的一堆无意义的字符,就是乱码。

那么这个乱码是如何出现的呢?这是因为浏览器的编码格式和服务器的编码格式是不同的,只有把服务端和客户端的编码格式进行统一之后,那么才不会乱码。

  1. get方式, 我们现在使用的tomcat>=8.0了, 乱码tomcat已经处理好了
  2. post方式, 就需要自己处理

在接收参数之前,来对参数进行处理

request.setCharacterEncoding("UTF-8");

请求转发

请求转发的本质就是: 跳转 ,不能跳转到外部的资源,只能跳转到项目内部的资源

但是对于项目内部来说,仍然是一个请求,也就是请求还未处理完成。

request.getRequestDispatcher(url).forward(request, response);  //转发

特点

  • 请求的路径不会变化
  • 一次请求
  • 转发可以转发到WEB-INF里面的资源 (WEB-INF的资源,不能直接访问,可以通过servlet进行跳转访问)

来写一个例子:

@WebServlet(name = "ForwardServlet", value = "/ForwardServlet")public class ForwardServlet extends HttpServlet {    @Override    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        this.doPost(request, response);    }    @Override    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        System.out.println("处理完成请求之后");        request.getRequestDispatcher("/WEB-INF/hello.html").forward(request,response);    }}

注意:对于WEB-INF下面的资源,客户端是无法直接来进行访问的,只能够通过转发的方式来进行请求访问到。

域对象存取数据

ServletContext: 可以存|取值,范围是整个应用程序, AServlet 存值, BServlet能取值request范围:  一次请求内有效!!! 域对象是一个容器,这种容器主要用于Servlet与Servlet/JSP之间的数据传输使用的。
  • Object getAttribute(String name) ;
  • void setAttribute(String name,Object object) ;
  • void removeAttribute(String name) ;

写一个案例来进行说明:

存数据的servlet:

@WebServlet(name = "StorageServlet", value = "/StorageServlet")
public class StorageServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setAttribute("store","hello,world");
        request.getRequestDispatcher("/TakeOutServlet").forward(request,response);
    }
}

取数据的servlet:

@WebServlet(name = "TakeOutServlet", value = "/TakeOutServlet")
public class TakeOutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String storeMsg = (String) request.getAttribute("store");
        System.out.println("存储的数据是:"+storeMsg);
        response.getWriter().println(storeMsg);
    }
}

发送对应的请求之后,然后浏览器上会显示:

hello,world

7、response

在Servlet API中,定义了一个HttpServletResponse接口(doGet,doPost方法的参数),它继承自ServletResponse接口,专门用来封装HTTP响应消息。由于HTTP响应消息分为响应行、响应头、响应体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码、响应头、响应体的方法

7.1、操作响应行

对应的格式:

HTTP/1.1 200
  1. 设置的API: response.setStatus(int code);

  2. 一般不需要设置, 可能302 重定向需要设置

  3. 常见的响应状态码

    • 200 成功
    • 302 重定向
    • 304 读缓存
    • 404 客户端错误
    • 500 服务器错误

7.2、操作响应头

响应头: 是服务器指示浏览器去做什么

关注的方法: setHeader(String name,String value);

常用的响应头

	Refresh:定时跳转 (eg:服务器告诉浏览器5s之后跳转到百度)

	Location:重定向地址(eg: 服务器告诉浏览器跳转到xxx)

	Content-Disposition: 告诉浏览器下载

	Content-Type:设置响应内容的MIME类型(服务器告诉浏览器内容的类型)

对应的demo:

@WebServlet(name = "RefreshServlet", value = "/RefreshServlet")public class RefreshServlet extends HttpServlet {    @Override    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        this.doPost(request, response);    }    @Override    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        response.setHeader("Refresh" , " 5; url=http://www.baidu.com");    }}

告知浏览器,在5秒钟后跳转到百度页面上。

@WebServlet(name = "LocationServlet", value = "/LocationServlet")
public class LocationServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setStatus(302);
        response.setHeader("Location","/RefreshServlet");
        // 还有一种更加简单的写法,直接省略上面两个步骤
        // resp.sendRedirect("http://www.baicu.com");
        // resp.sendRedirect("/RefreshServlet");
    }
}

告知浏览器重定向到RefreshServlet这个路径下来,重新发起对应的请求。

转发和重定向区别

  1. 重定向可以跳转到外面的资源(网站) , 请求转发跳转不了(只能跳转项目内部资源,因为这是由tomcat来完成)
  2. 请求转发只有一次请求,重定向有两次请求。
  3. 请求转发的地址栏不会改变,但是重定向的地址栏会发生改变。
  4. 请求转发和重定向都能跳转到servlet。
    1. AServlet (request)存值 ----请求转发---到BServlet , 在BServlet里面能取值。
    2. AServlet (request)存值 ----重定向---到BServlet , 在BServlet里面不能取值!!。
  5. 因为WEB-INF 文件夹是受保护的,只能由项目内部跳转,所以请求转发可以跳转到里面的资源,但是重定向不行(因为重定向是从浏览器开始)

7.3、操作响应体

响应体影响着浏览器的显示。

响应乱码处理

解决字符流输出中文乱码问题

response.setContentType("text/html;charset=utf-8");

响应的内容类型是文本类型并以utf-8的形式将内容进行响应。

使用字节输出流输出中文乱码问题

//设置浏览器打开方式
response.setHeader("Content-type", "text/html;charset=utf-8");
//得到字节输出流
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write("你好".getBytes("utf-8"));// 使用平台的默认字符(utf-8)集将此 String 编码为 byte 序列

注意:页面输出只能使用其中的一个流实现,两个流是互斥的.

  1. 为什么会出现乱码?

    • iso8859-1不支持中文
    • 编码和解码不一致
  2. 乱码解决

    • 请求乱码

      • get方式, tomcat>=8.0 不需要解决, 服务器已经解决好了
      • post方式
      request.setCharacterEncoding("utf-8");
      
    • 响应乱码

    response.setContentType("text/html;charset=utf-8");
    

文件下载

@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


        //1. 获取要下载的文件名称,通过参数传递进来的
        String fileName = req.getParameter("file");  //a.jpg


        //2. 根据文件找到得到该文件的输入流
//        FileInputStream fis = new FileInputStream();

        InputStream fis = getServletContext().getResourceAsStream("download/"+fileName);

        if(fis == null){
            System.out.println("文件路径错误!!!");

        }

        //设置一下文件的类型,以及告诉浏览器要下载。
        String mimeType = getServletContext().getMimeType(fileName);
        resp.setContentType(mimeType);

        resp.setHeader("Content-Disposition" , "attachment;filename="+fileName);



        //3. 使用字节流的方式写给浏览器
        OutputStream os = resp.getOutputStream();

        byte [] buffer = new byte[1024];
        int len = 0 ;
        while( (len = fis.read(buffer)) != -1 ){
            os.write(buffer , 0 , len);
        }

        os.close();
        fis.close();
    }
}

8、request和response总结

对于来自客户端的请求来说,服务器端无所不应。

所以Tomcat服务器会将请求封装成为一个对象,将响应也封装成为一个对象。

对于一个http的请求来说,格式分为:请求行、请求头、请求体。这里都是获取的功能;

对于一个http的响应来说,格式分为:响应行、响应头、响应体。而响应我们可以通过response响应对象来进行响应的设置操作。

对于请求来说,我们可以知道从哪里请求来的,能够接收到什么

对于响应来说,服务器则是告知客户端需要来做些什么

posted @ 2022-02-11 00:32  写的代码很烂  阅读(315)  评论(0编辑  收藏  举报