- ServletContext接口
- response介绍(服务器 ——》客户端浏览器)
- response的状态码和响应头设置
- 常用的响应头演示:
- http://www.jd.com (页面自动刷新)">Refresh: 3;url=http://www.jd.com (页面自动刷新)
- http://www.it315.org/index.jsp">Location: http://www.it315.org/index.jsp
- Content-Type: text/html; charset=utf-8 告诉浏览器以什么样的方式打开资源,和使用编码集
- (3CKQ`F1N.png">![(ZZWKSBZIE$7Q(3CKQ`F1N.png
- 设置响应体
- 下载介绍
- request获取头信息
- Request容器(存取删)和请求转发(重点)
- 字符参数:application/x-www-form-urlencoded
- 字节参数(上传文件):multipart/form-data
- 字节参数:application/json
- 注册案例
ServletContext接口
场景:
在线人数:xxx万,吸引用户来注册。
当用户进入系统,应该当前在线人数加一——servlet处理
当用户退出系统,应该当前在线人数减一——servlet处理
需求:
有在线人数的数据,必须,可以让两个servlet都可以获取使用。
希望:有这么一个容器(保存数据),这个容器可以被多个servlet同时使用。
这个就是我们ServletContext容器:
ServletContext示意图:他是一个存储数据的容器
总结:
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个方法:
代码演示:
package cn.igeek.web;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;
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 {
ServletContext servletContext = getServletContext();
servletContext.setAttribute("hehe", "呵呵");
String hehe = (String) servletContext.getAttribute("hehe");
System.out.println("hehe:"+hehe);
servletContext.removeAttribute("hehe");
String hehe2 = (String) servletContext.getAttribute("hehe");
System.out.println("hehe:"+hehe2);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
读取全局(整个项目)配置参数(读取项目在web.xml中的配置信息)
我们在web.xml文件中是可以配置项目的初始化信息:
项目的配置信息需要在当前这个web.xml的全局位置配置:
需求: 设置项目全局参数 公司=极客营 地址=常武中路888号 |
---|
1、在web.xml中配置全局(项目)参数信息
<context-param>
<param-name>company</param-name>
<param-value>极客营</param-value>
</context-param>
<context-param>
<param-name>address</param-name>
<param-value>常武中路888号</param-value>
</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工程中资源文件路径
要读取资源,必须先找到这个文件:
第一个要介绍的方法是:
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);
}
解析获取到的资源的文件类型:
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对象:
ServletResponse定义了基本的响应数据的方法
response的状态码和响应头设置
设置状态码:
int sc 是状态码(200,302,404,500),不要设置不存在的响应状态码
默认是200;
设置响应头信息:
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 ");
重定向的细节:
浏览器发送了两次请求,第一次请求中:
指定了让浏览器再次发送请求的地址
转发
request.setAttribute("name","zhangsan");
RequestDispatcher dispatcher = request.getRequestDispatcher("/TestServlet");
dispatcher.forward(request, response);//执行转发
请求转发和重定向的区别:
重定向和转发的区别:
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>");
效果:
如果设置普通文本形式:text/plain
response.setContentType("text/plain;charset=utf-8");
response.getWriter().write("<h1>哈哈哈<h1>");
效果:
如果设置普通文本形式: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);
}
}
下载介绍
下载方式介绍
文件的下载有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());
效果:
请求的路径:
System.out.println(request.getRequestURI());
System.out.println(request.getRequestURL());
效果:
uri: 统一资源标识符,用来标识一个资源,资源路径。(相当于身份证)
url: 统一资源定位符,是一种具体的URI,可以用来标识一个资源.并且指明了如何定位一个资源.(相当于身份证中的地址)
获取请求的协议类型: 如 http/1.1
System.out.println(request.getProtocol());
效果:
其他细节:
获取IP地址
访问地址:http://localhost:9090/aa/DemoServlet
访问地址:http://127.0.0.1:9090/aa/DemoServlet
注意,服务器解析的时候,效果虽然一致,但是,底层具体内容不一样
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
需求:获取所有的请求头信息
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);
}
}
效果:
那么如果需要显示当前用户用户名,怎么办?
使用请求对象将获取到的请求参数保存下来:
可以保存以外,还可以,获取和删除:
那么,我们可以修改成:
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);
}
}
效果:
总结:
当一个Web资源收到客户端的请求后,如果希望服务器通知另外一个资源处理.
可以通过 转发对象 RequestDispatcher 对象的forward(request,response)方法,将当前请求传递给其他的Web资源进行处理,这种方式称为请求转发。
在这些转发的过程中,所有的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>
第一种解决方案 先编码再解码(了解):
第二种解决方案 设置请求编码(重点):
这种方式只对 请求体 有效,算是post的偷懒方式,开发时最常用
注意:tomcat8 以后,默认的URL编码方式变为UTF-8
字节参数(上传文件):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"));
}
注册案例
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();
}
}
}