ServletContext接口

场景:
在线人数:xxx万,吸引用户来注册。

当用户进入系统,应该当前在线人数加一——servlet处理
当用户退出系统,应该当前在线人数减一——servlet处理

需求:
有在线人数的数据,必须,可以让两个servlet都可以获取使用。

希望:有这么一个容器(保存数据),这个容器可以被多个servlet同时使用。

这个就是我们ServletContext容器:
image.png
ServletContext示意图:他是一个存储数据的容器
image.png
总结:
1 容器可以存储数据
2 操作容器set get remove
3 可以被同一个web应用的多个Servlet共享使用
当tomcat启动时,会为每个web应用创建一个唯一的ServletContext对象代表当前Web应用.该对象不仅封装了当前web应用的所有信息,而且实现了多个servlet的数据共享.
在每个项目中可以有多个Servlet程序,每个Servlet程序都是独立的。Servlet中的配置信息可以使用ServletConfig获取,而当前这个项目的配置信息,就必须使用描述这个项目的ServletContext对象获取。

ServletContext容器的存取删操作(重点)

由于一个web应用程序中的所有Servlet共享同一个ServletContxt对象,因此ServletContext中的属性可以被Web应用程序中的所有servlet访问。在ServletContext中分别定义了用于 增加、删除、获取ServletContext属性的3个方法:
image.png
image.png
代码演示:

  1. package cn.igeek.web;
  2. import java.io.IOException;
  3. import java.lang.reflect.Field;
  4. import java.util.Map;
  5. import java.util.Set;
  6. import javax.servlet.ServletContext;
  7. import javax.servlet.ServletException;
  8. import javax.servlet.http.HttpServlet;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. public class MyServlet extends HttpServlet {
  12. public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  13. ServletContext servletContext = getServletContext();
  14. servletContext.setAttribute("hehe", "呵呵");
  15. String hehe = (String) servletContext.getAttribute("hehe");
  16. System.out.println("hehe:"+hehe);
  17. servletContext.removeAttribute("hehe");
  18. String hehe2 = (String) servletContext.getAttribute("hehe");
  19. System.out.println("hehe:"+hehe2);
  20. }
  21. public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  22. doGet(request, response);
  23. }
  24. }

效果:
image.png

读取全局(整个项目)配置参数(读取项目在web.xml中的配置信息)

我们在web.xml文件中是可以配置项目的初始化信息:
项目的配置信息需要在当前这个web.xml的全局位置配置:
image.png

需求: 设置项目全局参数 公司=极客营 地址=常武中路888号

1、在web.xml中配置全局(项目)参数信息

  1. <context-param>
  2. <param-name>company</param-name>
  3. <param-value>极客营</param-value>
  4. </context-param>
  5. <context-param>
  6. <param-name>address</param-name>
  7. <param-value>常武中路888号</param-value>
  8. </context-param>

2、根据key获取value

ServletContext servletContext = getServletContext();

// 方式一:根据key 获取值
//String company = servletContext.getInitParameter("company");
//String address = servletContext.getInitParameter("address");
//System.out.println("公司名称:" + company);
//System.out.println("公司地址:" + address);


// 方式二:获取所有的key 遍历,再根据key 获取值
Enumeration<String> en = servletContext.getInitParameterNames();
while(en.hasMoreElements()) {
    String key = en.nextElement();
    String val = servletContext.getInitParameter(key);

    System.out.println(key + "=" + val);
}

ServletContext读取Web工程中资源文件路径

要读取资源,必须先找到这个文件:
第一个要介绍的方法是:
image.png

ServletContext context = getServletContext();
String realPath = context.getRealPath("/WEB-INF/classes/c3p0-config.xml");
System.out.println(realPath);

效果:

C:\apache-tomcat-7.0.81\webapps\aa\WEB-INF\classes\c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbc</property>
        <property name="user">root</property>
        <property name="password">java</property>

        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
    </default-config>

    <named-config name="mySource">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/bookstore
        </property>
        <property name="user">root</property>
        <property name="password">xxxx</property>

        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
    </named-config>
</c3p0-config>

使用IO读取展示到控制台:

BufferedReader reader = new BufferedReader(new FileReader(new File(realPath)));
String line = null;
while((line = reader.readLine()) != null){
    System.out.println(line);
}

解析获取到的资源的文件类型:
image.png

ServletContext context = getServletContext();

String realPath = context.getRealPath("/WEB-INF/classes/c3p0-config.xml");
System.out.println(context.getMimeType(realPath));

String realPath2 = context.getRealPath("/1.html");
System.out.println(context.getMimeType(realPath2));

效果:

application/xml
text/html

response介绍(服务器 ——》客户端浏览器)

在之前学习servlet的时候,我们已经可以处理请求和响应,针对请求和响应,我们servlet方法中提供了request对象和response对象,方便我们使用。
今天,我们主要来学习和使用response对象:
image.png
ServletResponse定义了基本的响应数据的方法
image.png

response的状态码和响应头设置

设置状态码:
image.png
int sc 是状态码(200,302,404,500),不要设置不存在的响应状态码
默认是200;

设置响应头信息:
image.png
name:表示响应头 name的值
value:响应头对应的值

常用的响应头演示:

Refresh: 3;url=http://www.jd.com (页面自动刷新)

3 表示是的时间,3秒
url 地址
到3秒后,页面刷新url
测试代码:

response.setHeader("Refresh", "5;url=http://www.jd.com");

Location: http://www.it315.org/index.jsp

通常告知浏览器 马上向该地址发送请求 通常 和 302 一起使用!!
(重点) 结合302完成重定向 操作 Location重定向后地址

代码演示一:

response.setStatus(302);
response.setHeader("Location", " http://localhost:9090/day02/1.html ");

代码演示二:

response.sendRedirect("http://localhost:9090/day02/1.html ");

重定向的细节:
image.png
浏览器发送了两次请求,第一次请求中:
image.png
指定了让浏览器再次发送请求的地址

转发

request.setAttribute("name","zhangsan");
RequestDispatcher dispatcher = request.getRequestDispatcher("/TestServlet");
dispatcher.forward(request, response);//执行转发

请求转发和重定向的区别:
image.png
重定向和转发的区别:
1 转发操作发生在服务器内部,重定向是浏览器执行操作
2 转发地址栏不变,重定向,地址栏变化
3 转发在一次请求中完成,重定向是两次请求
4 转发可以在一次请求中共享数据,重定向不行。

Content-Type: text/html; charset=utf-8 告诉浏览器以什么样的方式打开资源,和使用编码集

text/html
text/plain
application/json

代码演示:

response.setContentType("text/html;charset=utf-8");
response.getWriter().write("<h1>哈哈哈<h1>");

效果:
image.png
如果设置普通文本形式:text/plain

response.setContentType("text/plain;charset=utf-8");
response.getWriter().write("<h1>哈哈哈<h1>");

效果:
image.png
如果设置普通文本形式:application/json

response.setContentType("application/json;charset=utf-8");
response.getWriter().write("{\"name\":\"张三\", \"age\":\"18\"}");

![(ZZWKSBZIE$7Q(3CKQ`F1N.png

设置响应体

应用场景: 浏览器显示的内容, 下载文件等.
response 以流的形式,将内容输出给浏览器
response.getWriter() 获取响应体的字符输出流,输出页面的时候使用
response.getOutputStream() 获取响应体的字节输出流,输出文件(图片,avi等。。。。)的时候使用

通过这两个流可以向浏览器输出 响应体内容.
注意问题:
1 文件数据传输: getOutputStream 手动生成响应内容时 使用 getWriter
2 getOutputStream 和 getWriter 相互排斥,不能同时使用,否则会冲突.
3 tomcat会自动调用response输出流的 close方法和flush方法, 因此不需要我们手动关闭流.

需求: 向浏览器输出一个百度的超链接 的html页面

public class Response5Servlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 需求: 向浏览器输出一个百度的超链接 的html页面
        response.setContentType("text/html;charset=utf-8");

        response.getWriter().println("<html>");
        response.getWriter().println("<head><title>百度超链接</title></head>");
        response.getWriter().println("<body>");
        response.getWriter().println("<a href='http://www.baidu.com'>百度</a>");
        response.getWriter().println("</body>");
        response.getWriter().println("</html>");
    }

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

}

页面效果:
image.png

下载介绍

下载方式介绍

文件的下载有2种方式可以完成:
1、超链接形式:
资源名称

问题:

  • 中文文件名乱码
  • 图片和文本直接解析而不是下载
  • 只有rar压缩文件,才直接下载

2、使用Servlet通知浏览器下载:

  • 修改请求路径,将要下载的文件名称,发送给服务器的servlet,让servlet进行处理
  • 加载服务器上的文件资源
  • 提示浏览器,以下载的方式,获取服务器资源
  • 使用IO的方式,将文件数据输出到浏览器(response.getOutputStream();)

    服务器端写程序下载(重点:必须掌握)

    ```java package cn.igeek.web;

import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URLEncoder;

import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;

import sun.misc.BASE64Encoder;

public class DownServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // 1)浏览器发送请求给服务器(用户要下载的文件名)
    String fileName = request.getParameter("fileName");
    //fileName = new String(fileName.getBytes("iso-8859-1"), "utf-8");

    // 2)服务器加载用户要下载的文件数据。
    String realPath = this.getServletContext().getRealPath("/upload");

    File file = new File(realPath, fileName);

    // 3)通知浏览器以下载的方式请求资源
    // a.Content-Type 设置文件媒体格式
    response.setContentType(this.getServletContext().getMimeType(fileName));
    // 处理中文文件名乱码
    String header = request.getHeader("User-Agent");
    if (header.contains("Firefox")) {
        // 表示当前是火狐
        BASE64Encoder base64Encoder = new BASE64Encoder();
        fileName = "=?utf-8?B?" + base64Encoder.encode(fileName.getBytes("utf-8")) + "?=";

    } else {
        // 谷歌
        fileName = URLEncoder.encode(fileName, "utf-8");

    }
    // b.Content-Disposition 设置要被下载的文件名
    response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

    // 4)使用IO技术,将数据发送(使用response对象发送数据)
    // a.获取输入流
    FileInputStream in = new FileInputStream(file);
    // b.获取输出流
    ServletOutputStream out = response.getOutputStream();
    // 缓冲区
    byte[] buf = new byte[8192];
    int len = 0;
    while ((len = in.read(buf)) != -1) {

        out.write(buf, 0, len);
    }
    in.close();

}

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doGet(request, response);
}

}

响应消息头设置:<br />Content-Type 设置文件媒体格式<br />response.setContentType(getServletContext().getMimeType(filename));<br /> <br />Content-Disposition  设置要被下载的文件名<br />response.setHeader("Content-Disposition", "attachment;filename=" + filename);<br />        <br />谷歌浏览器(和主流其他浏览器)中文乱码处理:<br />fileName = URLEncoder.encode(fileName,"utf-8");<br /> <br />火狐下载文件名乱码处理:(先判断是否是火狐浏览器)<br />BASE64Encoder base64Encoder = new BASE64Encoder();<br />filename = "=?utf-8?B?"    + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";

小结:<br />1) 先修改页面——发送要下载的文件的文件名<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/12418439/1618414722120-55ce723b-fe23-4120-86fa-d088dc7c5c93.png#height=133&id=WocCS&margin=%5Bobject%20Object%5D&name=image.png&originHeight=266&originWidth=1107&originalType=binary&ratio=1&size=158355&status=done&style=none&width=553.5)<br />1) 定位要被下载的文件的位置(获取文件名的时候,处理中文乱码问题)<br />2) 设置文件的媒体格式<br />3) 解决中文文件名问题(先要判断浏览器,根据不同的浏览器,不同编码处理)<br />4) 设置要被下载的文件名<br />5) 使用IO技术将数据发送给浏览器(response获取的out输出流,不用手动关闭,自己使用的输入流,需要手动关闭)

附录:学员问题解答<br />问题1 :ServletContext的getContext(),getContextPath(),getRealPath() 以及HttpServletRequst的getContextPath(),getRequestURI() getRequestURL() getServletPath() 这些方法获得路径有什么区别和联系<br />答: ServletContext  <br />    getContext() :获取指定路径的项目,它的ServletContext对象,但是,处于安全考虑,如果获取其他的项目ServletContext都会拿到null,所以方法不常用<br />    getContextPath():获取当前项目根路径<br />    getRealPath():获取当前项目中,指定资源的路径<br /> <br />     HttpServletRequst:<br />    getContextPath():获取当前项目根路径(同上)<br />    getRequestURI(): 获取请求地址,不包含协议,地址,端口<br />    getRequestURL(): 获取请求地址,包含协议,地址,端口<br /> <br />问题2 :ServletContext 与Servlet的在服务器中存在形式被称为什么? 使用ServletContext会出现并发问题么?如何解决<br />答:1 对象<br />    ServletContext tomcat在底层的实现类是org.apache.catalina.core.ApplicationContextFacade,这是一个容器存取数据的<br />        Servlet        是处理请求和响应的对象,由我们自己实现<br /> <br />    2 ServletContext对象在存取数据的时候使用ConcurrentHashMap,线程安全。
<a name="KpDMw"></a>
### Response返回的数据类型

![SLAOY0DT5[JX@1636~5A4$P.png](https://cdn.nlark.com/yuque/0/2021/png/12418439/1630373708424-fc59158a-09ce-4e2e-b74a-5cfd33691f52.png#clientId=ua3b97299-50ab-4&from=paste&height=523&id=u95ec9ca1&margin=%5Bobject%20Object%5D&name=SLAOY0DT5%5BJX%401636~5A4%24P.png&originHeight=523&originWidth=1061&originalType=binary&ratio=1&size=32650&status=done&style=stroke&taskId=u557d9080-8803-48e4-ac8a-7e8da5c8d7b&width=1061)

<a name="E5PoZ"></a>
## request对象介绍(方向:浏览器——》 服务器)
通过前面的servlet学习,我们了解的使用java servlet小程序处理请求和响应的过程中有request对象和response对象帮助我们处理请求响应<br />那么今天,我们先从请求request对象入手,开始学习:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/12418439/1618415947007-ad425f31-80ef-4e66-b9cc-a24fca61407d.png#height=295&id=Fcl3C&margin=%5Bobject%20Object%5D&name=image.png&originHeight=590&originWidth=1112&originalType=binary&ratio=1&size=143900&status=done&style=none&width=556)<br />Request对象学习的思路:

1. 如何获取请求行头体 
1. 请求中文处理
1. 请求对象的其他常用方法
<a name="G7Ybu"></a>
### request获得请求行信息和ip地址
请求行格式:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/12418439/1618416063884-3a1a9cc3-cdfa-4a7f-ae9b-d593d0041176.png#height=52&id=KBdrT&margin=%5Bobject%20Object%5D&name=image.png&originHeight=103&originWidth=537&originalType=binary&ratio=1&size=48546&status=done&style=none&width=268.5)<br />**获得请求方法的类型: 如get 或 post**<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/12418439/1618416081823-b2b7c931-210c-4d78-b47b-77956dbe58b3.png#height=72&id=QudCL&name=image.png&originHeight=144&originWidth=696&originalType=binary&ratio=1&size=20387&status=done&style=none&width=348)<br />演示代码:
```java
System.out.println(request.getMethod());

效果:
image.png
请求的路径:
image.png

System.out.println(request.getRequestURI());
System.out.println(request.getRequestURL());

效果:
image.png
uri: 统一资源标识符,用来标识一个资源,资源路径。(相当于身份证)
url: 统一资源定位符,是一种具体的URI,可以用来标识一个资源.并且指明了如何定位一个资源.(相当于身份证中的地址)

获取请求的协议类型: 如 http/1.1
image.png

System.out.println(request.getProtocol());

效果:
image.png
其他细节:
获取IP地址
image.png
访问地址:http://localhost:9090/aa/DemoServlet
image.png
访问地址:http://127.0.0.1:9090/aa/DemoServlet
image.png
注意,服务器解析的时候,效果虽然一致,但是,底层具体内容不一样

获取服务器的端口号
image.png
image.png

request获取头信息

Accept: text/html, application/xhtml+xml, */*
Referer: http://localhost/day19/post.html
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; qdesk 2.4.1272.203; Windows NT 6.1; WOW64; Trident/6.0)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: localhost
Content-Length: 30
DNT: 1
Connection: Keep-Alive
Cache-Control: no-cache

image.png
需求:获取所有的请求头信息

package cn.igeek.web;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DemoServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Enumeration<String> names = request.getHeaderNames();
        while(names.hasMoreElements()){
            String string = names.nextElement();
            System.out.println(string+":"+request.getHeader(string));
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

效果:

host:127.0.0.1:9090
connection:keep-alive
cache-control:max-age=0
user-agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
upgrade-insecure-requests:1
accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
accept-encoding:gzip, deflate, br
accept-language:zh-CN,zh;q=0.8

Request容器(存取删)和请求转发(重点)

需求:
使用一个servlet专门处理获取请求参数,比对用户名和密码,如果,成功(登陆成功),那么跳转下一个servlet,在下一个servlet响应页面结果
请求转发:从一个servlet中启动另一个servlet。客户端浏览器地址栏不会变化,这个请求转发操作,全部在服务器内部执行。
代码演示:演示转发,重点——request.getRequestDispatcher(“/my”).forward(request, response);

package cn.igeek.web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class DemoServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String name = request.getParameter("name");
        String pwd = request.getParameter("pwd");
        if(name.equals("tom") && "111".equals(pwd)){
            request.getRequestDispatcher("/my").forward(request, response);
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}
package cn.igeek.web;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {


    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().write("<h1><font color=\"green\">login  OK!!!!</font></h1>");
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

效果:
image.png
那么如果需要显示当前用户用户名,怎么办?
使用请求对象将获取到的请求参数保存下来:
image.png
可以保存以外,还可以,获取和删除:
image.png
image.png
那么,我们可以修改成:

package cn.igeek.web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class DemoServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String name = request.getParameter("name");
        String pwd = request.getParameter("pwd");
        if(name.equals("tom") && "111".equals(pwd)){
            request.setAttribute("name", name);
            request.getRequestDispatcher("/my").forward(request, response);
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}
package cn.igeek.web;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {


    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String name = (String)request.getAttribute("name");

        response.getWriter().write("<h1><font color=\"green\">login "+name+" OK!!!!</font></h1>");
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

效果:
image.png
总结:
当一个Web资源收到客户端的请求后,如果希望服务器通知另外一个资源处理.
可以通过 转发对象 RequestDispatcher 对象的forward(request,response)方法,将当前请求传递给其他的Web资源进行处理,这种方式称为请求转发。
image.png
在这些转发的过程中,所有的Servlet共享同一个请求对象。
在转发中,客户端是感觉不到服务器内部在跳转。而且客户端的浏览器的地址栏中是不会发生任何变化的。

因为在多个Servlet中可以进行转发,导致多个Servlet之间共享同一个request对象,于是在发出转发的Servlet中,可以把request对象当做一个容器,然后给其中保存数据,在其他的Servlet中可以取出前面的Servlet给request对象中保存的数据。
request对象如果当做容器的话,它只是在当前这次请求中有效。当请求响应结束了,这个容器就消失了。

总结:
1 使用request对象,可以获取请求行
2 使用request对象,可以获取请求头
3 使用request对象,可以处理中文乱码
4 使用request对象,调用下一个servlet(请求转发)
5 使用request对象,在一个请求转发过程中,让两个servlet共享数据。

字符参数:application/x-www-form-urlencoded

请求参数乱码处理(重点):
![(]}})7]DPK08CGP98VG8LJ.png
Get限制Form表单的数据集的值必须为ASCII字符;而Post支持整个ISO10646字符集。默认是用ISO-8859-1编码

Get 提交的中文乱码解决:

<h1>GET方式</h1>
<form method="get" action="/day19/request3" accept-charset="GBK">
    帐号:<input type="text" name="username"/><br/>
    <input type="submit" value="提交"/>
</form>

第一种方案:修改tomcat默认的编码方式(推荐)

默认情况下,tomcat(8版本以后)使用的的编码方式:UTF-8
修改tomcat下的conf/server.xml文件
找到如下代码:

这段代码规定了Tomcat监听HTTP请求的端口号等信息。
可以在这里添加一个属性:URIEncoding,将该属性值设置为GBK,即可让Tomcat(默认UTF-8编码)以GBK的编码处理get请求。
修改完成后:

方法比较常用. 修改tomcat的servlet.xml,其它地方不用再做编码处理
瑕疵(一般一个tomcat都只跑一个项目):
如果两个项目: 一个是UTF-8, 另一个是GBK

POST提交的中文乱码解决:

<h1>POST方式</h1>
<form method="post" action="/day19/request3" accept-charset="utf-8">
    城市:<input type="text" name="city"/><br/>
    <input type="submit" value="提交"/>
</form>

第一种解决方案 先编码再解码(了解):

image.png

第二种解决方案 设置请求编码(重点):

这种方式只对 请求体 有效,算是post的偷懒方式,开发时最常用
image.png
注意:tomcat8 以后,默认的URL编码方式变为UTF-8
Response & Request - 图38

字节参数(上传文件):multipart/form-data

<form method="post" action="/servletJsp/test" accept-charset="UTF-8" enctype="multipart/form-data">
    帐号:<input type="text" name="username"/><br/>
        <input type="file" name="fileName" />
        <input type="file" name="fileName2" />
    <input type="submit" value="提交"/>
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.setCharacterEncoding("UTF-8");
    //创建磁盘工厂对象
    DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
    //创建servlet文件上传核心对象
    ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);

    try {
        RequestContext requestContext = new ServletRequestContext(request);
        List<FileItem> fileItemList = fileUpload.parseRequest(requestContext);
        for (FileItem fileItem : fileItemList) {
            //判断input的type 是 file类型 还是 非file类型
            if(fileItem.isFormField()){  // true 为 非file类型  false 为 file类型
                String name = fileItem.getFieldName();
                String value = fileItem.getString("UTF-8");
                System.out.println("name/value   = " + name+" / "+value);
            }else {
                String fileName = fileItem.getName();
                System.out.println(fileName + "   " + fileItem.getContentType());
                InputStream is = fileItem.getInputStream();
                FileUtils.copyToFile(is, new File("D:/" + fileName));
            }
        }

    } catch (FileUploadException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

字节参数:application/json

![C{Y}DSMCR@B$%@GX85B0.png

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    byte[] bytes = request.getInputStream().readAllBytes();
    System.out.println(new String(bytes, "UTF-8"));
}

结果:
PBW}}(95BZ649~W5R]%LM7V.png

注册案例

Response & Request - 图40
Response & Request - 图41

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(64) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL,
  `age` int DEFAULT NULL,
  `sex` varchar(16) DEFAULT NULL,
  `email` varchar(64) DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `hobby` varchar(128) DEFAULT NULL,
  `address` varchar(128) DEFAULT NULL,
  `description` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/study/registerServlet" method="post">
<table>
    <tr>
        <td>用户名<font color="red">*</font></td>
        <td><input type="text" name="username"/></td>
    </tr>
    <tr>
        <td>密码</td>
        <td><input type="password" name="password"/></td>
    </tr>
    <tr>
        <td>确认密码</td>
        <td><input type="password" name="passwordConfirm"/></td>
    </tr>
    <tr>
        <td>年龄</td>
        <td><input type="text" name="age"/></td>
    </tr>
    <tr>
        <td>性别</td>
        <td>
            <input type="radio" name="sex" value="man" />男
            <input type="radio" name="sex" value="woman" />女
        </td>
    </tr>
    <tr>
        <td>邮箱</td>
        <td><input type="text" name="email"/></td>
    </tr>
    <tr>
        <td>生日</td>
        <td><input type="text" name="birthday"/></td>
    </tr>
    <tr>
        <td>爱好</td>
        <td>
            <input type="checkbox" name="hobby" value="C"/>C
            <input type="checkbox" name="hobby" value="C++"/>C++
            <input type="checkbox" name="hobby" value="Java"/>Java
            <input type="checkbox" name="hobby" value="IOS"/>IOS
            <input type="checkbox" name="hobby" value="PHP"/>PHP
            <input type="checkbox" name="hobby" value="Android"/>Android
        </td>
    </tr>
    <tr>
        <td>地址</td>
        <td>
            <select name="address">
                <option value="">--请选择--</option>
                <option value="北京">北京</option>
                <option value="上海">上海</option>
                <option value="广州">广州</option>
                <option value="深圳">深圳</option>
            </select>
        </td>
    </tr>
    <tr>
        <td>自我描述</td>
        <td>
            <textarea name="description"></textarea>
        </td>
    </tr>
    <tr>
        <td></td>
        <td><input type="submit" value="注册"/></td>
    </tr>
</table>
</form>
</body>
</html>

Bean

package cn.igeek.domain;

import java.util.Date;

import lombok.Data;

@Data
public class User {
    private int id;

    private String username;

    private String password;

    private int age;

    private String sex;

    private String email;

    private Date birthday; 

    private String hobby;

    private String address;

    private String description;


}

应用层

package cn.igeek.web;

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

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 org.apache.tomcat.util.buf.StringUtils;

import cn.igeek.domain.User;
import cn.igeek.service.UserService;




@WebServlet("/registerServlet")
public class registerServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public registerServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().append("Served at: ").append(request.getContextPath());
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String age = request.getParameter("age");
        String sex = request.getParameter("sex");
        String email = request.getParameter("email");
        String birthday = request.getParameter("birthday");
        String address = request.getParameter("address");
        String description = request.getParameter("description");

        String[] hobbys = request.getParameterValues("hobby");
        String hobby = StringUtils.join(hobbys);

        System.out.println(username);
        System.out.println(password);
        System.out.println(age);
        System.out.println(sex);
        System.out.println(email);
        System.out.println(birthday);
        System.out.println(hobby);
        System.out.println(address);
        System.out.println(description);

        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setAge(Integer.parseInt(age));
        user.setSex(sex);
        user.setEmail(email);

        try {
            DateFormat fmt =new SimpleDateFormat("yyyy-MM-dd");
            Date date = fmt.parse(birthday);
            user.setBirthday(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }


        user.setHobby(hobby);
        user.setAddress(address);
        user.setDescription(description);

        UserService service = new UserService();
        boolean info  = service.register(user);
        if(info){
            response.getWriter().write("register OK!!!");
        }else{
            response.getWriter().write("register error!!!");
        }

    }

}

业务层

package cn.igeek.service;

import cn.igeek.dao.UserDao;
import cn.igeek.domain.User;

public class UserService {
    private UserDao userDao = new UserDao();
    /**
     * 用户登陆的方法
     * @param user
     * @return
     * @throws Exception 
     */
    public User login(User user) {
        return userDao.login(user);
    }

    public boolean register(User user) {
        User findByname = userDao.findByName(user.getUsername());
        if(findByname == null){
            userDao.register(user);
            return true;
        }else{
            return false;
        }
    }
}

数据层

package cn.igeek.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import cn.igeek.domain.User;

public class UserDao {
    private Connection conn = null;
    private QueryRunner qr = new QueryRunner();


    public UserDao() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/stock?useUnicode=true&characterEncoding=utf-8&useSSL=FALSE&serverTimezone=UTC", "root", "123456");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理用户登陆的方法
     * @param user
     * @return
     * @throws Exception 
     */
    public User login(User user) {
        String sql = "select * from user where username = ? and password = ?";
        //为什么要抓取异常?
        try {
            return qr.query(conn, sql, new BeanHandler<User>(User.class), user.getUsername(),user.getPassword());
        } catch (SQLException e) {
            e.printStackTrace();
            //对上面这些异常信息,做了一个中文注释
            throw new RuntimeException("用户登陆失败");
        }
        //try catch finally  throw  throws
    }

    public User findByName(String username) {
        String sql = "select * from user where username = ?";
        try {
            return qr.query(conn, sql, new BeanHandler<User>(User.class), username);
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    public void register(User user) {
        String sql = "insert into user values(null,?,?,?,?,?,?,?,?,?)";
        List<Object> list= new ArrayList<>();
        list.add(user.getUsername());
        list.add(user.getPassword());
        list.add(user.getAge());

        list.add(user.getSex());
        list.add(user.getEmail());
        list.add(user.getBirthday());
        list.add(user.getHobby());
        list.add(user.getAddress());
        list.add(user.getDescription());


        try {
            qr.update(conn, sql, list.toArray());
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}