Servlet是JavaEE规范之一。规范就是接口。
Servlet是JavaWeb三大组件之一,三大组件分别是Servlet程序、Filter过滤器、Listener监听器。
Servlet是运行在服务器上的一个Java小程序,它可以接受客户端发送过来的请求,并响应数据给客户端。
流程:
重写service方法后,编辑web.xml配置文件。内容:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>HelloServletservlet-name>
<servlet-class>com.code.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>HelloServletservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
web-app>
启动Tomcat实例后,在url后加/hello即可在控制台看到Sevlet程序的输出。
☀url地址如何定位到的Servlet程序并访问
☀Tip:
无法实现Servlet接口或者import javax.servlet.*报错时,在lib目录中导入jsp和servlet的jar包
其中,前两步在第一次访问Servler程序的时候调用。第三步是每次访问都会调用。第四步是在web工程停止的时候会去调用
/**
* service方法是用来处理请求和响应的
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("Hello Servlet被访问了!");
//类型转换,因为getMethod是子类特有的方法
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String method = httpServletRequest.getMethod();
if("GET".equals(method)){
//System.out.println("这里写收到GET请求的code");
doGet();
}else if("POST".equals(method)){
System.out.println("这里写收到POST请求的code");
}
}
/**
* 把收到GET请求要做的事定义成一个方法
* 从而避免service方法中代码臃肿
*/
public void doGet(){
}
写个HTML文档表单提交到servlet
<body>
<form action="http://localhost:8080/web/hello" method="get">
<input type="submit" value="提交"/>
form>
body>
点击提交,在控制台就可看到不同请求被分发给不同的IF分支了。
实际的开发中,很少通过实现Servlet接口去实现Servlet程序,而是直接继承Servlert接口的子类,如HttpServlet:
public class ServletHello extends HttpServlet{
...
Alt+Insert
}
这样可以直接生成xx.java和修改好web.xml文件。
整理Servlet类的继承体系:
.
.
顾名思义即Servlet程序的配置信息类。有大三作用:
☀代码实现:
System.out.println("Servlet别名"+servletConfig.getServletName());
System.out.println("Servlet程序初始化参数username的值是" + servletConfig.getInitParameter("username");
System.out.println(servletConfig.getServletContext());
另外:
Servlet程序和ServletConfig对象都是由Tomcat服务器负责创建,我们负责使用。Servlet程序默认第一次访问的时候创建,ServletConfig是每个Servlet程序创建时,就创建一个对应的Servletconfig对象。
☀
因此,每个servletConfig对象只能获取它自己对应的那个servlet程序的信息,获取不了其他servlet程序
在其他方法中,可以这样获取servletConfig对象:
//也可以这样获取servletConfig对象
ServlerConfig servletConfig = getServletConfig();
常见错误–servletConfig对象空指针异常
重写init方法后,出现servletConfig对象空指针异常,加这一句:
@Override
public void init(ServletConfig config) throws ServletException{
super.init(config);
...
}
☀介绍
域对象是指可以像Map一样存取数据的对象,这里的域是指存取数据的操作范围,即整个Web工程
存数据 | 取数据 | 删数据 | |
---|---|---|---|
Map | put() | get() | remove() |
域对象 | setAttribute() | getAttribute() | removeAttribute() |
☀作用
public void doSome(){
ServletContext context = getServletConfig().getServletContext();
//获取context上下文参数
String username = context.getInitParameter("username");
//获取当前的工程路径
String path = context.getContextPath();
/**
* 获取工程在服务器硬盘上的绝对路径
* 斜杠/即会被服务器解析地址为http://ip:port/工程名
*/
String realPath = context.getRealPath("/"); //工程部署路径
String realImgPath = context.getRealPath("/img"); //img目录的绝对路径
context.setAttribute("key1","value1");
System.out.println("context中获取域数据key1的值是:"+context.getAttribute("key1"));
}
另外,获取ServletContext对象也可直接调用getServletContext()方法,看底层源码:
☀协议
协议,即双方或多方相互约定好的、大家都需要遵守的规则。
HTTP协议,指客户端和服务端之间通信时,发送的数据要遵守的规则,就是HTTP协议。HTTP协议中的数据又叫报文。
☀请求
客户端给服务端发送数据叫请求,服务端给客户端回传数据叫响应。请求有GET和POST两种:
请求行:
如:
GET /web/submit.html HTTP/1.1
请求头:
请求行:
如:
POST /web/submit HTTP:1.1
请求头:
一组组key:value。空行后接着是请求体
Cache-Control表示如何控制缓存,no-cache即不缓存
请求体:
☀场景区分
GET请求常包括:
请求常包括:
☀响应
响应行:
如:
HTTP/1.1 200 OK
常见的响应码有:
响应头:
响应体:
☀MIME类型
MIME即HTTP协议中的数据类型,起全称Multipurpose Internet Mail Extensions,多功能Internet邮件扩充给服务。MIME类型的格式是“大类型/小类型”,并与某一种文件的扩展名相对应。
每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Request对象中,然后传递到service方法(doGet、doPost)中
HttpServletRequest类的常用方法
示例代码:
package com.llg.web;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Arrays;
public class HttpServlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
String[] hobby = request.getParameterValues("hobby");
System.out.println("username:" + username);
System.out.println("password:" + password);
System.out.println("hobby:" + Arrays.asList(hobby));
System.out.println("URI:" + request.getRequestURI());
System.out.println("URL:" + request.getRequestURL());
System.out.println("Client_IP:"+request.getRemoteHost());
System.out.println("User-Agent:" + request.getHeader("User-Agent"));
System.out.println("Request-Method:" + request.getMethod());
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* setCharacterEncoding方法设置请求的字符集为UTF-8,解决post请求的中文乱码问题
* 注意要在获取请求参数之前调用
*/
request.setCharacterEncoding("UTF-8");
System.out.println("-----POST-----");
String username = request.getParameter("username");
String password = request.getParameter("password");
String[] hobby = request.getParameterValues("hobby");
System.out.println("username:" + username);
System.out.println("password:" + password);
System.out.println("hobby:" + Arrays.asList(hobby));
}
}
写个form用来提交信息:
<body>
<form action="http://localhost:8080/web1/s1" method="post">
用户名:<input type="text" name="username">br>
密码:<input type="text" name="password">br>
兴趣爱好:<input type="checkbox" name="hobby" value="c">C
<input type="checkbox" name="hobby" value="java">Java
<input type="checkbox" name="hobby" value="js">JavaScript
<input type="submit">
form>
body>
Servlet1的代码:
package com.llg.web;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet(name = "Servlet1", value = "/Servlet1")
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* 获取请求参数(办事的材料)
*/
String username = request.getParameter("username");
System.out.println("在Servlet1(柜台1)中查看参数(材料):" + username);
/**
* 给材料盖一个章,并传递到Servlet2(柜台2)取查看
*/
request.setAttribute("key1","柜台1的章");
/**
* 问路Servlet2(柜台2)怎么走
* 请求的转发必须要以斜杠打头,斜杠表示地址为:http://ip:port/工程名,映射到IDEA的web目录
*/
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servlet2");
/**
* 走向Servlet2(柜台2)
*/
requestDispatcher.forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
Servlet2的代码:
package com.llg.web;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet(name = "Servlet2", value = "/Servlet2")
public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* 获取请求参数(办事的材料)
*/
String username = request.getParameter("username");
System.out.println("在Servlet2(柜台2)中查看参数(材料):" + username);
/**
* 查看柜台1是否有盖章
*/
Object key1 = request.getAttribute("key1");
System.out.println("柜台1是否有章:" + key1);
/**
* 处理自己的业务
*/
System.out.println("Servlet2在这里干它的业务");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
配置web.xml
请求转发的特点:
实验前期准备:
先在web项目下建立这样一个目录结构,以便后续实验:
c.html和index.html的内容:
启动项目,就先单单利用a标签实现了跳转的效果:
使用Servlet转发:
编写ForWardC类,重写doGet方法:
http://localhost:8080/web1/forwardC
即会转发到a/b/c.html。在首页html中加入上面的链接,和之前做比较:
重新部署后:
跳转成功:
再点击跳回首页,报错404,注意这时的路径:
原因分析:
跳回首页时a标签的路径是…/…/index.html,是一个相对路径。而 所有相对路径在工作的时候都会参照当前浏览器地址栏中的地址来跳转 。
用a标签的时候成功原因的分析:
base标签
base标签可以设置当前页面中所有相对路径工作时,参照哪个路径来进行跳转
加入base后,每次相对路径跳转时参考的就不再是浏览器中的地址栏url,而是base的href,进而转发后的页面也能跳成功
在JavaWeb中,关于相对路径和绝对路径,相对路径有:
绝对路径是:
http://ip:port/工程路径/资源路径
而在web中,斜杠/是一种绝对路径:
常见的地方有:
- xml中的<url-pattern>/servlet1<url-pattern>
- servletContext.getRealPath("/");
- request.getRequestDispatcher("/");
response.sendRediect("/");
是把斜杠发送给浏览器解析,得到http://ip:port/输出流
HttpServletResponse和HttpServletRequest类一样,每次请求进来,Tomcat服务器都会创建一个Response对象传给Servlet程序使用。
HttpServletRequest表示请求过来的信息,HttpServletResponse表示所有响应的信息,如果需要设置返回给客户端的信息,则可通过HttpServletResponse对象来设置。
关于两个输出流:
两个流不能同时使用。
给客户端回传字符串
response.setHeader("Content-Type","text/html; charset=UTF-8");
请求重定向,是指客户端给服务器发请求,然后服务器告诉客户端说:我给你一个新地址,你去新地址访问。这就是请求的重定向(因为之前的地址可能已经废弃)。这就像生活中某旺铺搬迁,会在门口贴告示:新店已搬迁至南京路300弄
代码实现:
Response1:
package com.llg.web;
import ...
public class Response1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("曾到Response1一游");
/**
* 设置响应状态码302,表示重定向(已搬迁)
*/
resp.setStatus(302);
/**
* 设置响应头,说明新的地址在哪儿
*/
resp.setHeader("Location","http://localhost:8080/web1/response2");
//resp.sendRedirect("http://localhost:8080/web1/response2");
}
}
Response2:
package com.llg.web;
import ...
public class Response2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("this is Response2's result!!");
}
}
访问已废弃的localhost:8080/web1/response1:
请求重定向的特点:(注意和之前的转发做区分)
请求重定向,除了以上的:
resp.setStatus(302);
resp.setHeader("Location","http//localhost:8080/web1/response2");
还可直接调用方法sendRedirect()
resp.sendRedirect("http//localhost:8080/web1/response2");
两种重定向方式的效果都一样: