1. tomcat部署项目的三种方式
- 直接把项目放到tomcat下的webapps目录下即可(可以把项目打成war包,然后放入到webapp下,tomcat服务器会自动解压war包。如果项目过大的话,这种方式会节省拷贝的时间)。
- 配置conf目录下的service.xml中的< host>标签体,在标签体中添加< Context docBase=’‘本地路径’’ path=’'虚拟路径" />即可,其中docBase为项目在本地的路径,path为浏览器上访问的虚拟路径。
- 在 \conf\Catalina\localhost 目录下创建任意名称的xml配置文件,在文件中配置< Context docBase="本地地址’’ />,其中docBase属性为项目的本地路径,而创建的文件名为浏览器访问的虚拟路径名。
2. Servlet
概念: server applet,运行在服务器端的小程序
Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则
2.1 Servlet的方法
public class Servlet_Methods implements Servlet {
/**
* 初始化方法
*在Servlet被创建时执行,只会执行一次
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init");
}
/**
* 获取ServletConfig对象
* ServletConfig:Servlet的配置对象
* @return
*/
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 提供服务方法
* 每一次Servlet被访问,都会执行。执行多次
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service");
}
/**
* 获取Servlet的一些信息,版本、作者等
* @return
*/
@Override
public String getServletInfo() {
return null;
}
/**
* 销毁方法
* 每次服务器被正常关闭时执行,执行一次
*/
@Override
public void destroy() {
System.out.println("destroy");
}
}
2.2 Servlet的生命周期
- 默认情况下,Servlet在第一次被访问时创建
- 指定Servlet的创建时间
- 第一次访问时,创建的值为负数
- 在服务器启动时,创建的值为0或正整数
Servlet的init方法,只执行一次,说明一个Servlet的内存中只存在一个对象,即Servlet是单例的
多个用户同时访问时,可能存在线程安全问题
解决方法:尽量不要在Servlet中定义成员变量
2.3 Servlet注解配置
- Servlet3.0版本以上,可以不创建web.xml
- 可以通过在类上使用@WebServlet(“资源路径”)注解,进行配置
@WebServlet(urlPatterns = "/Servlet_Demo2")
public class Servlet_Demo2 implements Servlet {
...
- 如果只需要对某个url作出响应,则可以省略urlPatterns名称
@WebServlet("/Servlet_Demo2")
public class Servlet_Demo2 implements Servlet {
...
...
- 如果是响应多个 url, 用大括号包起来即可
2.4 Servlet_体系结构
-
GenericServlet: 将Servlet接口中其他方法做了默认空实现,只将service()方法作为抽象,故将来定义Servlet类时,即可继承GenericServlet类,这样就只用实现service()方法了
-
HttpServlet: 对http协议的一种封装,可以简化操作
- 相应流程
其中HttpServlet首先必须读取Http请求的内容,Servlet容器负责创建HttpServlet对象,并把Http请求直接封装到HttpServlet对象中。
- 创建HttpServlet步骤
- 继承HttpServlet抽象类
- 重写HttpServlet的部分方法,如doGet()或doPost()方法
- 相应流程
3. HTTP
3.1 HTTP请求信息
请求信息数据格式:
- 请求行
- 请求方式 请求url 请求协议/版本
- 请求方式:
- HTTP协议有7种请求方式,常用两种
- GET:请求参数在请求行中,在url后,请求的url长度有限制
- POST:请求参数在请求体中,请求的url长度没有限制
- 请求头:客户端浏览器告诉服务器一些信息
- 请求头名称:请求头值
- 常见的请求头:
- User-Agent:浏览器告诉服务器,访问使用的浏览器版本信息(可以在服务器端获取该头的信息,解决浏览器的兼容性问题)
- Referer:告诉服务器,当前请求从哪里来,可以防盗链和统计工作
- 请求空行
- 空行,用来分割POST请求的请求体和请求体的
- 请求体(正文)
- 封装POST请求信息的请求参数的
3.2 相应信息
相应信息:服务器端发送给客户端的数据
数据格式:
- 相应行
- 组成:协议/版本 响应状态码 状态码描述
- 响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态
- 状态码都是三位数字
- 分类:
- 1xx:服务器接收客户端信息,但是没有接收完成,等待一段时间后,发送1xx的状态码
- 2xx:成功,代表:200
- 3xx:重定向,代表:302(重定向),304(访问缓存)
- 4xx:客户端错误,代表:404(请求路径没有对应的资源)、405(请求方式没有对应的doXxx方法)
- 5xx:服务器端错误,代表:500(服务器内部出现异常)
- 响应头
- 格式:头名称:值
- 常见的响应头:
- Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
- Content-disposition:服务器告诉客户端以什么格式打开响应体数据
- 响应空行
- 最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头;
- 响应体
- 传输的数据
4. Request
Request对象和Response对象的原理
- request和response对象是由服务器创建的,我们来使用它
- request对象是来获取请求信息的
- response对象是用来设置相应信息的
4.1 Request功能
获取请求消息数据
-
获取请求行数据
- 举例: GET/tomcat-practice/demo1?name=123 HTTP/1.1
- 方法:
- 获取请求方式:GET,String getMethod()
- 获取虚拟目录:/tomcat-practice,String getContextPath()
- 获取Servlet路径:/demo1,String getServletPath()
- 获取get方式的请求参数:name=123,String getQueryString()
- 获取请求URI:/tomcat-practice/demo1,String getRequestURI()
- 获取请求URL:http://localhost/tomcat-practice/demo1,StringBuffer getRequestURL()
(URI:统一资源定位符 URL:统一资源标识符) - 获取协议及版本:HTTP/1.1,String getProtocol()
- 获取客户机的IP地址:String getRemoteAddr()
-
获取请求头数据
- 方法:
- String getHeader(String name):通过请求头的名称获取请求头的值
- Enumeration< String> getHeaderNames():获取所有的请求头名称
- 方法:
@WebServlet("/RequestGetHeader")
public class RequestGetHeader extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取所有的请求头数据
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String header = request.getHeader(name);
System.out.println(name + "--" + header);
}
System.out.println();
// 获取单个请求头数据
String header = request.getHeader("host");
System.out.println(header);
}
}
@WebServlet("/RequestDemo2")
public class RequestDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String referer = request.getHeader("referer");
System.out.println(referer); //http://localhost:8080/login.html
//防盗链
if(referer != null) {
if(referer.contains("login.html")) {
//正常访问
System.out.println("OK");
} else {
System.out.println("你是猪头");
}
}
}
}
- 获取请求体数据
- 请求体:只要POST请求方式,才有请求体,在请求体中封装了POST请求的请求参数
- 步骤:
- 获取流对象
BufferedReader getReader():获取字符输入流,只能操作字符数据
ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据
- 获取流对象
4.2 Request_获取请求参数
获取请求参数通用方法
- String getParameter(String name):根据参数名称获取参数值
- String[] getParameterValues(String name):根据参数名称获取参数值的数据
- Enumeration< String> getParameterNames():获取所有请求的参数名称
- Map< String, String[]> getParameterMap():获取所有参数的map集合
@WebServlet("/GetRequestParameters")
public class GetRequestParameters extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// post 获取请求参数
//根据参数名称获取
String s = request.getParameter("username");
System.out.println("post:" + s);
//根据参数名称获取字符串数组
String[] hobbies = request.getParameterValues("hobby");
/*
for (String hobby : hobbies) {
System.out.println(hobby);
}
*/
//获取所有参数的请求名称(只能获取参数的一个请求名称)
Enumeration<String> parameterNames = request.getParameterNames();
/*
while (parameterNames.hasMoreElements()) {
String s1 = parameterNames.nextElement();
System.out.println(s1);
String s2 = request.getParameter(s1);
System.out.println(s2);
System.out.println("-----------------------");
}
*/
//获取所有参数的Map集合(可以获取参数的所有请求名称)
Map<String, String[]> map = request.getParameterMap();
Set<String> keySet = map.keySet();
for (String key : keySet) {
String[] values = map.get(key);
System.out.println(key);
for (String value : values) {
System.out.println(value);
}
System.out.println("-----------------");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// get 获取请求参数
//根据参数名称获取
/*
String s = request.getParameter("username");
System.out.println("get:" + s);
*/
this.doPost(request, response);
}
}
中文乱码情况
- get方式:tomcat8已解决
- post方式:因为Http请求传输时将url以ISO-8859-1编码,服务器收到字节流后默认会以ISO-8859-1编码来解码成字符流,故会造成中文乱码,需要在获取参数前,设置request的编码request.setCharacterEncoding(“utf-8”)
4.3 Request请求转发
请求转发: 一种在服务器内部的资源跳转方式
实现方法: 通过request对象获取请求转发器对象,再使用RequestDispatcher对象进行转发
@WebServlet("/ForwardRequest")
public class ForwardRequest extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ForwardRequest被访问");
/*
RequestDispatcher requestDemo4 = request.getRequestDispatcher("/RequestDemo4");
requestDemo4.forward(request, response);
*/
request.getRequestDispatcher("RequestDemo4").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
@WebServlet("/RequestDemo4")
public class RequestDemo4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("RequestDemo4被访问了");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
特点:
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器内部资源中
- 转发只执行一次请求
4.4 Request共享数据(域对象)
域对象: 一个有作用范围的对象,可以在范围内共享数据
request域: 代表一次请求的范围,一般用于请求转发的多个资源中共享数据
方法:
- setAttribute(String name, Object obj):存储数据
- getAttitude(String name):通过键获取值
- removeAttribute(String name):通过键移除键值对
4.5 获取ServletContext
方法:
ServletContext getServletContext()
5. Response
功能:设置响应消息
- 设置响应行
- 格式:HTTP/1.1 200 ok
- 设置状态码:setStatus(int sc)
- 设置响应头:setHeader(String name, String value)
- 设置响应体
- 步骤
- 获取输出流
- 使用输出流将数据输出到客户端浏览器
- 步骤
5.1 重定向
重定向:资源跳转的方式
/*
重定向
访问responseDemo1资源会自动跳转到responseDemo2资源
*/
@WebServlet("/responseDemo1")
public class responseDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo1");
/*
// 1. 设置状态码为302
response.setStatus(302);
// 2. 设置响应头location
response.setHeader("location", "/responseDemo2");
*/
// 简单的重定向方法(可以访问别的站点的资源)
response.sendRedirect("https://www.bilibili.com/");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
重定向(redirect)的特点
- 地址栏地址发生变化
- 重定向可以访问其它站点(服务器)的资源
- 是两次请求,不能使用request对象来共享数据
转发(forward)的特点:
- 转发地址栏路径不变
- 转发只能访问当前服务器下的资源
- 转发是一次请求
5.2 路径的写法
1. 路径_相对路径
- 通过相对路径不可以确定唯一资源
- 不以/开头,以.开头的路径
- 规则:需要找到当前资源和目标资源之间的相对位置关系
- ./:当前目录
- …/:后退一级目录
2. 路径_绝对路径
- 通过绝对路径可以确定唯一资源
- 以/开头的路径
- 规则:
- 给客户端浏览器使用:需要加虚拟目录
- 给服务器使用:不需要加虚拟目录
虚拟目录建议使用request.getContextPath()动态获取
5.3 输出字符数据
步骤:
- 获取字符输出流
- 输出数据
注意: 乱码问题
@WebServlet("/OutPutChar")
public class OutPutChar extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 防止中文乱码方法
// 1. 需要在获取流之前设置默认编码为浏览器使用的解码方式,例如
//response.setCharacterEncoding("utf-8");
// 2. 浏览器使用的解码方式不一定是utf-8,故需要告诉浏览器,服务器发送的信息体的编码方式,让服务器使用该编码方式解码
//response.setHeader("content-type", "text/html;charset=utf-8");
// 方法2的简单写法
response.setContentType("text/html;charset=utf-8");
// 获取字符输出流
PrintWriter pw = response.getWriter();
// 输出数据
pw.write("你好,学习人");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
5.4 输出字节数据
@WebServlet("/OutPutByte")
public class OutPutByte extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
// 获取字节输出流
ServletOutputStream sos = response.getOutputStream();
// 输出数据
sos.write("hello,打工人".getBytes("utf-8"));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
6. ServletContext
概念: 代表整个web应用,可以和程序的容器(服务器)来通信
功能:
- 获取MIME类型
- 域对象:共享数据
- 获取文件的真实(服务器)路径
6.1 获取该对象
- 通过request对象获取,request.getServletContext();
- 通过HttpServlet获取,this.getServletContext();
6.2 功能
1. 获取MIME类型
MIME类型: 在互联网通信过程中定义的一种文件数据类型
格式: 大类型/小类型
例:text/heml、image/jpeg
获取: String getMimeType(String file)
@WebServlet("/Demo1")
public class Demo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String fileName = "a.jpg";
//获取a.jpg的MIME类型
String mimeName = context.getMimeType(fileName);
System.out.println(mimeName); //image/jpeg
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
2. 域对象
- setAttribute(String name, Object value)
- getAttribute(String name)
- removeAttribute(String name)
ServletContext对象范围:所有用户所有请求的数据
3. 获取文件服务器路径
方法:String getRealPath(String path)