目录
三、 Servlet-url如何定位到Servlet程序去访问
一、什么是Servlet
1、servlet是javaEE规范之一。规范就是接口
2、servlet就是javaweb三大组件之一。三大组件分别是:servlet程序、Filter过滤器、Listenter监听器。
3、servlet是运行在服务器上的一个java小程序,它可以接受客服端发送过来得请求,并响应数据给客服端。
手动实现Servlet程序
步骤:
1、编写一个类去实现Servlet接口
2、实现service方法,处理请求,并相应数据
3、到web.xml中配置Servlet程序的访问地址
创建一个servlet模块,和步骤之前tomcat类似
在src下创建一个类去实现Servlet接口,快捷键Alt+insert选择实现方法,回车即可
新建的这个类如是:
package com.servlet;
import javax.servlet.*;
import java.io.IOException;
public class HelloServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 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被访问了");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
3.到web.xml配置,在web-app标签里写入如下
<!--servlet标签给Tomcat配置Servlet程序-->
<servlet>
<!-- servlet-name给Servlet程序起一个别名(一般别名起为类名)-->
<servlet-name>HelloServlet</servlet-name>
<!--servlet-class是Servlet程序的全类名 -->
<servlet-class>com.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet-mapping标签是给Servlet程序配置访问地址 -->
<servlet-mapping>
<!-- servlet-name是告诉服务器我当前配置的地址是给哪一个Servlet程序使用-->
<servlet-name>HelloServlet</servlet-name>
<!--url-pattern配置访问地址
/ 斜杠在服务器解析的时候,表示地址为:http://ip:port/工程路径 <br/>
/hello 表示地址为:http://ip:port/工程路径/hello <br/>
-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
4、我们在index.jsp下写入一些内容,然后启动
结果:
前面在Tomcat也说过了,只写到工程名,没有资源名默认访问index,index目录下的内容会呈现到浏览器上
我们前面给这个配置了路径为hello,我们在加上就会访问servlet程序
二、 常见的配置错误
①起的路径名是随意起的,没有任何相关性,这虽然没有任何问题,但是不好分辨
②,路径没有以斜杆开头,如:
<url-pattern>hello</url-pattern>
这样会导致出错
所以一般起名字前得加/,正确写法:
<url-pattern>hello</url-pattern>
③、在名字不同
在idea还可以有提示,有些编辑器就不会给提示,运行之后
在servlet-mapping配置访问地址时,要和前面起的别名一致
④、标签的全类名写错、漏写
全类名是要写出实现Servlet接口那个类所在的位置,写错、少写都会报错,
圈起来的要一致
三、 Servlet-url如何定位到Servlet程序去访问
其中,一个端口号只能给一个工程,一个工程可以占用多个端口号,(工程就是文件夹,资源就是文件夹里的目录)
四、Servlet生命周期
之前的类
package com.servlet;
import javax.servlet.*;
import java.io.IOException;
public class HelloServlet implements Servlet {
public HelloServlet() {
System.out.println("1 构造器");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("2 init初始化方法");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* service方法是专门用来处理请求和响应的(只要执行这个类就会访问)
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("3 Servlet==hello servlet被访问了");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("4 destroy销毁方法");
}
}
当我们启动,访问http://localhost:8080/01_servlet/hello时
一开始出现1 2 3,后面一直刷新就一直出现3,退出程序出现4
Servlet生命周期总结
1.执行setvlet构造器方法
2.执行init初始化方法
第一和第二步是在第一次访问的时候创建servlet程序会调用,
3.执行servlet方法
第三步,每次访问都会调用
4.执行destroy销毁方法
第四步,在web工程停止的时候调用
五、Servlet 请求的分发处理
我们使用表单提交时,有get(非加密)和post(加密)两种提交方式
创建一个表单a.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/02_servlet/hello" method="post">
<input type="submit">
</form>
</body>
</html>
在实现的Servlet接口的类,中的重写的service方法中
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("3 Servlet==hello servlet被访问了");
//类型转化,因为HttpServletRequest有getMethod方法
HttpServletRequest httpServletRequest= (HttpServletRequest) servletRequest;
//getMethod识别当前提交方式是get还是post,分别返回"GET"和"POST"
String method=httpServletRequest.getMethod();
if("GET".equals(method)){
//为了防冗余和更好的维护,定义方法
// System.out.println("get请求");
doGet();
}else if ("POST".equals(method)){
// System.out.println("post请求");
doPost();
}
}
public void doGet(){
System.out.println("get请求");
}
public void doPost(){
System.out.println("post请求");
}
启动服务器,后如图所示
运行在浏览器后,每次提交都会访问service方法,并打印出对应的method
六、通过继承HttpServlet实现Servlet程序
实际开发中,一般使用继承HttpServlet类的方法去实现Servlet程序。
步骤:
1、编写一个类去继承HttpServlet类
2、根据业务需要重写doGet或doPost方法
3、到web.xml中配置Servlet程序
1、编写一个类,Alt+insert快捷键重写里一些需要的方法
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doGet(req, resp);
System.out.println("HelloServlet2的 get请求");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doPost(req, resp);
System.out.println("HelloServlet2的 post请求");
}
}
到web.xml文件中配置访问路径
<servlet>
<servlet-name>HelloServlet2</servlet-name>
<servlet-class>com.servlet.HelloServlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet2</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
将表单中的访问地址hello改变为hello2
运行提交后:
七、使用idea创建Servlet程序
选择要实现的包→Servlet程序
配置信息
勾选上用的就是3.0的注解配置
只需要在web.xml中加上路径即可(其他的已经自动生成了)
<servlet>
<servlet-name>HelloServlet2</servlet-name>
<servlet-class>com.servlet.HelloServlet3</servlet-class>
</servlet>
<!--以上自动生成了,只要写下面的 -->
<servlet-mapping>
<servlet-name>HelloServlet3</servlet-name>
<url-pattern>/hello3</url-pattern>
</servlet-mapping>
八、Servlet的继承体系
doGet和dopost源码
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_get_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_post_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
servlet方法部分源码
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
}
九、ServletConfig类
- ServletConfig是Servlet程序的配置信息类。
- Servlet程序和ServletConfig对象都是有Tomcat负责创建,我们负责使用。
- Servlet程序默认是一次访问的时候创建,ServletConfig是每个Servlet程序创建时,就创建一个对应的ServletConfig对象
ServletConfig类的三大作用
1、可以获取Servlet程序的别名(servlet-name的值)
2、获取初始化参数init-param
3、获取ServletContent对象
所处位置init方法
1、获取servlet别名
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("HelloServlet 的别名是"+servletConfig.getServletName());
}
2、获取初始化参数init-param,其他的前面写过了
现在web.xml文件中配<init-param>
<!--servlet标签给Tomcat配置Servlet程序-->
<servlet>
<!-- servlet-name给Servlet程序起一个别名(一般别名起为类名)-->
<servlet-name>HelloServlet</servlet-name>
<!--servlet-class是Servlet程序的全类名 -->
<servlet-class>com.servlet.HelloServlet</servlet-class>
<!--init-param时初始化参数,这是个键值对可以写很多对 -->
<init-param>
<!-- 参数名-->
<param-name>username</param-name>
<!--是参数的值 -->
<param-value>root</param-value>
</init-param>
<init-param>
<!-- 参数名-->
<param-name>url</param-name>
<!--是参数的值 -->
<param-value>jdbc:mysql://localhost:3306/text</param-value>
</init-param>
</servlet>
在实现Servlet接口的类中的init()下
// 2、获取初始化参数init-param
System.out.println("初始化参数username的值是"+servletConfig.getInitParameter("username"));
System.out.println("初始化参数url的值是"+servletConfig.getInitParameter("url"));
3、获取ServlertContent对象
// 3、获取ServletContent对象
System.out.println("servletcontent对象是"+servletConfig.getServletContext());
以上运行结果:
每一个ServletConfig程序独立 ,在web.xml 中每个类中信息不共享,
重写init方法时得加上super.init(config),得访问父类的init初始化方法,否则报错
继承体系可以得知ServletConfig在GenericServlet类中,该类中的init定义:
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
所以如果重写init方法,必须加上super.init(config),否则父类的init方法不会执行(父类中中的保存操作执行不了)
十、ServletContext类
什么是ServletContext?
1、ServletContent是一个接口,他表示Servlet上下文对象
2、一个web工程,只有一个ServletContext对象实例。
3、ServletContent对象是一个域对象。
4、在web工程启动后创建,在web工程结束后销毁
什么是域对象?
域对象,是可以像Map一样存取数据的对象,叫做域对象。
这里的域指的是存取数据的操作范围。
对照示意表:
存数据 | 取数据 | 删除数据 | |
Map | put() | get() | remove() |
域对象 | setAttribute() | getAttribute() | removeAttribute() |
ServletContext类的四个作用
1、获取web.xml中的配置的上下文参数context-param
2、获取当前的工程路径你,格式:/工程路径
3、获取部署后在服务器硬盘上的绝对路径
4、像Map一样存取数据
用快捷方式创建一个类ContextServlet,在web.xml中配置路径( 其余的已经自动生成了)
<servlet>
<servlet-name>ContextServlet</servlet-name>
<servlet-class>com.servlet.ContextServlet</servlet-class>
</servlet>
<!-- 上面自动生成了,下面要自己书写的路径-->
<servlet-mapping>
<servlet-name>ContextServlet</servlet-name>
<url-pattern>/contextServlet</url-pattern>
</servlet-mapping>
1、获取web.xml中的配置的上下文参数,
首先得在web.xml中配置context-param(一般写在其他servlet之上)
<!--context-param是上下文参数(他属于整个web工程)-->
<context-param>
<!--参数名 -->
<param-name>username</param-name>
<!--参数值-->
<param-value>context</param-value>
</context-param>
<!--可以写多对上下文参数-->
<context-param>
<param-name>password</param-name>
<param-value>root</param-value>
</context-param>
在ContextServlet类中doGet()方法中
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1、获取web.xml中的配置的上下文参数context-param
//获取对象
ServletContext context = getServletConfig().getServletContext();
String username = context.getInitParameter("username");
String password = context.getInitParameter("password");
System.out.println("context-param参数username的值是"+username);
System.out.println("context-param参数password的值是"+password);
}
}
运行之后结果是:
易错点:
①:在配置web.xml文件中地址中的/斜杆不要忘记,否则会报地址无效
<url-pattern>/contextServlet</url-pattern>
②:在类中获取参数是应在doGet()方法中书写,否则运行之后访问地址不会显示处对应的信息
2、获取当前工程路径
System.out.println("当前工程路径:"+context.getContextPath());
3、获取部署后在服务器硬盘上的绝对路径
System.out.println("获取工程部署的路径"+context.getRealPath("/"));
这个斜杆/表示到当前工程的路径
4、map一样存取数据
创建一个Servlet类,在web.xml文件中配置好路径
<servlet>
<servlet-name>ContextServlet1</servlet-name>
<servlet-class>com.servlet.ContextServlet1</servlet-class>
</servlet>
<!-- 以上自动配好-->
<servlet-mapping>
<servlet-name>ContextServlet1</servlet-name>
<url-pattern>/contextServlet1</url-pattern>
</servlet-mapping>
在类中:
public class ContextServlet1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取ServletContext对象
ServletContext context = getServletContext();
System.out.println("保存之前Context获取key1的值是:"+context.getAttribute("key1"));
context.setAttribute("key1","value1");
System.out.println("context获取数据key1的值为:"+context.getAttribute("key1"));
}
}
我们直接可以用getServletContext()获取对象,这样简单些,而不用getServletConfig().getServletContext();
我们ctrl+b看源码可知:
public ServletContext getServletContext() {
return this.getServletConfig().getServletContext();
}
源代码已经做好了那步,所以我们直接返回即可。
我们继续定义一个类叫ContextServlet2
public class ContextServlet2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = getServletContext();
System.out.println("ContextServlet2中 context获取数据key1的值为:"+context.getAttribute("key1"));
}
}
部署就省略了,运行之后
不难发现当ContextServlet1中的有数据存入,ContextServlet2中就可以查到该数据。也可以context下的数据是共享数据
ContextServlet对象在web工程启动后创建,在web工程结束后销毁,且共享
重启和重新部署都会导致web工程销毁
ContextServlet1、2的地址也是一样的
十一、什么是协议?
协议是指双方,或多方,相互约定好,大家都需要遵守的规则,叫做协议
而http协议就是说,客户端和服务器之间的通信时,发送的数据,需要遵守的规则,叫做HTTP协议
HTTP中的数据又叫报文。
十二、请求的HTTP协议格式
客服端给服务器发送的数据叫请求。
服务器给客服端回传数据叫响应。
请求又分为GET和POST请求两种
GET请求
1、请求行
(1)请求的方式 GET
(2)请求的资源路径[+?+请求参数]
(3)请求的协议的版本号 HTTP/1.1
2、请求头
key:value 组成 不同的键值对,表示不同的含义。
启动服务器:
图示:
POST请求
1、请求行
(1)请求的方式 POST
(2) 请求的资源路径[+?+请求参数]
(3) 请求的协议号 HTTP/1.1
2、请求头
1)key:value 不同的请求头,有不同的含义
空行
3、请求体===>>是发送给服务器的数据
表单中主要内容:
<from action="http://localhost:8080/06_servlet/hello3" method="post">
<input type="hidden" name="action" value="login"/>
<input type="hidden" name="username" value="root"/>
<input type="submit">
</from>
图示:
十三、 常用请求头说明
Accept:表示客服端可以接受的数据类型
Accpet-languege:表示客户端可以接受的语言类型
User-Agent:表示客户端浏览器的信息
Host:表示请求时的服务器ip和端口号
十四、GET和POST请求的有哪些
GET请求:
1、form标签method=get
2、a标签
3、link标签引入css
4、Script标签引入js文件
5、img标签引入图片
6、ifram引入html页面
7、在浏览器地址栏中输入地址后回车
POST请求:
1、from标签method=post
十五、响应的HTTP协议格式
1、响应行
(1)响应的协议和版本号
(2)响应的状态码1
(3)响应状态描述符
2、响应头
(1)key:value 不同的响应头,有他的不同的含义
空行
3、响应体——>>>就是回传给客户端的数据
常见的响应吗说明
200 表示请求成功
302 表示请求重定向
404 表示请求服务器已经收到了,但是你要的数据不存在(地址错误)
500 表示服务器已经收到请求,但是服务器内部错误(代码错误)
MIME类型说明
MiME是HTTP协议中数据类型。
MIME的英文全称是"Multipurpose Internet Mail Extensions"多功能Internet邮件扩充服务,MIME类型的格式是"大类型/小类型",并与某一种文件的扩展名相对应。
如:gif类型;大类型是图片,小类型就是gif,表示为image/gif
常见的MIME类型:
十六、 HttpServletRequest类
作用:
每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTp协议信息解析好封装到Request对象中,然后传递得到service方法(doGet和doPost中给我们使用,我们可以通过HttpServletRequest对象,获取到所有请求的信息)
HttpServletRequest类的常用方法
getRequestURI() 获取请求的资源路径
getRequestURL() 获取请求的统一资源定位符(绝对路径)
getRemoteHost 获取客户端的ip地址
getHeader() 获取请求头
getParameter 获取请求参数
getParameterValues() 获取请求对的参数(多个值的时候同时使用)
getMethod() 获取请求的方式GET或POST
setAttribute(key,value) 设置域数据
getAttribute(key) 获取域数据
getRequestDispatcher 获取请求转发对象
方法演示:
创建一个web工程03_servlet,在web.xml中配置
<servlet>
<servlet-name>RequestAPIServlet</servlet-name>
<servlet-class>com.servlet.RequestAPIServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RequestAPIServlet</servlet-name>
<url-pattern>/requestAPIServlet</url-pattern>
</servlet-mapping>
在src下创建一个类RequestAPIServlet继承HttpServlet
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RequestAPIServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// getRequestURI() 获取请求的资源路径
System.out.println("URI->"+req.getRequestURI());
// getRequestURL() 获取请求的统一资源定位符(绝对路径)
System.out.println("URL->"+req.getRequestURL());
// getRemoteHost 获取客户端的ip地址
System.out.println("客户端ip地址:"+req.getRemoteHost());
// getHeader() 获取请求头
System.out.println("请求头User-Agent->"+req.getHeader("User-Agent"));
// getMethod()获取请求的方式GET或POST
System.out.println("请求的方式:"+req.getMethod());
}
}
在编辑配置中修改信息,改为03_servlet之类的。
运行之后:
URI->/03_servlet/requestAPIServlet
URL->http://localhost:8080/03_servlet/requestAPIServlet
客户端ip地址:0:0:0:0:0:0:0:1
请求头User-Agent->Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36
请求的方式:GET
我们也能发现URI只是到工程名下的资源路径,而URL是全路径,可以直接访问的。
十七、Servlet获取web表单中的参数
get请求:
在src下创建一个参数类ParameterServlet继承HttpServlet类
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
public class ParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求参数
String username=req.getParameter("username");
String password=req.getParameter("password");
String[] hobby=req.getParameterValues("hobby");
System.out.println("账号:"+username);
System.out.println("密码:"+password);
//Arrays.asList()返回的是一个数组
System.out.println("爱好:"+ Arrays.asList(hobby));
}
}
在web.xml中配置参数
<servlet>
<servlet-name>ParameterServlet</servlet-name>
<servlet-class>com.servlet.ParameterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ParameterServlet</servlet-name>
<url-pattern>/parameterServlet</url-pattern>
</servlet-mapping>
在web目录下写html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/03_servlet/parameterServlet" method="get">
账号:<input type="text" name="username"><br>
密码 :<input type="password" name="password"><br>
<input type="checkbox" name="hobby" value="HTML">HTML
<input type="checkbox" name="hobby" value="Java">Java
<input type="checkbox" name="hobby" value="JavaScript">JavaScript
<input type="checkbox" name="hobby" value="Spring全家桶">Spring全家桶
<input type="checkbox" name="hobby" value="Servlet">Servlet<br>
<input type="submit">
</form>
</body>
</html>
启动运行:
填入几组信息,提交得:
post请求:
类中:
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求参数
String username=req.getParameter("username");
String password=req.getParameter("password");
String[] hobby=req.getParameterValues("hobby");
System.out.println("账号:"+username);
System.out.println("密码:"+password);
//Arrays.asList()返回的是一个数组
System.out.println("爱好:"+ Arrays.asList(hobby));
}
将method="post",post的请求中,一旦有中文就会出现乱码,
此时应在doPost方法体中加入设置字符集:
req.setCharacterEncoding("UTF-8");
注:设置的字符集得在获取参数之上,否则也会出现乱码。
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置字符集
req.setCharacterEncoding("UTF-8");
//获取请求参数
String username=req.getParameter("username");
String password=req.getParameter("password");
String[] hobby=req.getParameterValues("hobby");
System.out.println("账号:"+username);
System.out.println("密码:"+password);
//Arrays.asList()返回的是一个数组
System.out.println("爱好:"+ Arrays.asList(hobby));
}
再次运行:
十八、请求的转发
请求的转发是指从一个资源跳转到另一个资源的操作叫做请求的转发
创建两个类servlet1和servlet2继承HttpServlet
Servlet1类下:
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Servlet1 extends HttpServlet {
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怎么走
/**
* 请求转发必须要以斜杆/开头,/ 斜杆表示地址为http://ip:port/工程名/ 映射到idea中是web目录
*/
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servlet2");
//走向Servlet2(柜台2)
requestDispatcher.forward(request, response);
}
}
servlet2类下:
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Servlet2 extends HttpServlet {
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处理自己的业务");
}
}
运行访问http://localhost:8080/03_servlet/servlet1
运行结果:
在访问栏中加入参数 ?后面都是参数
回车得:
请求转发的特点
1、浏览器地址栏没有变化(一直都是工程名/servlet1)
2、他们是一次请求
3、可以共享Request域中的数据(域数据在整个工程都能访问)
4、可以转发到WEB-INF目录下(WEB-INF受服务器保护,不能通过客户端(浏览器)直接访问可以通过服务器中的资源间接访问)
5、不能访问工程以外的资源(因为他是从工程下找的,工程下没有的一律访问不了)
在类Servlet1中:
地址访问:
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/WEB-INF/form.html");
十九、base标签
演示程序不能跳回来的情况
创建一个类ForwardC继承HttpServlet类
public class ForwardC extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("经过了Forward程序");
req.getRequestDispatcher("/a/b/c.html").forward(req, resp);
}
}
在web.xml中配置
<servlet>
<servlet-name>ForwardC</servlet-name>
<servlet-class>com.servlet.ForwardC</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ForwardC</servlet-name>
<url-pattern>/forwardC</url-pattern>
</servlet-mapping>
在web目录下创建如图所示
在c目录下写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>这是一个c页面</title>
</head>
<body>
<a href="../../index.html">返回首页</a>
</body>
</html>
在index.html下写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
这是web下的index.html<br>
<a href="a/b/c.html">a/b/c.html</a><br>
<a href="http://localhost:8080/03_servlet/forwardC">请求转发:a/b/c.html</a>
</body>
</html>
运行之后:
我们前面也说过,只写到工程名默认访问index页面
我们发现点击上下两个都可以成功跳转
虽然都成功跳转了,但是地址明显不同,因为我们在c.html下写的是../../index.html,
运行结果:
到位分析:
前者(第一个),localhost:8080/03_servlet/a/b/c.html,经过../../跳转可以到web工程下,正好web下有index.html,所以会跳转成功。
后者(第二个 ),localhost:8080/03_servlet/forwardC,经过../../跳转就会跳到src目录下,而src目录下显然没有index.html页面,故会失败。(结构是:src/com/servlet/Forward)
图示:
当我们加入base标签后,浏览器就会以这个base标签的为最终地址。
base标签一般加在title之下
<base href="http://localhost:8080/03_servlet/a/b/c.html">
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>这是一个c页面</title>
<base href="http://localhost:8080/03_servlet/a/b/c.html">
</head>
<body>
<a href="../../index.html">返回首页</a>
</body>
</html>
这样就解决了后者不能调到首页的问题。
二十、Web中的相对路径和绝对路径
在javaWeb中,路径分为相对路径和绝对路径两种:
相对路径:
. 表示当前目录
.. 表示上一级目录
资源名 表示当前目录/资源名
绝对路径:
http://ip:port/工程路径/资源路径
二十一、web中/ 斜杆的不同意义
在web中/ 斜杆是一种绝对路径。
/ 斜杆如果被浏览器解析,得到的地址是:http://ip:port/
<a href="/">斜杆的意义</a>
/ 斜杆如果被服务器解析,得到的地址是:http://ip:port/工程路径
1、<url-pattern>/servlet1<url-pattern>
2、servletContext.getRealPath("/");
3、request.getRequestDispatcher("/")
特殊情况:response.sendRediect("/");把斜杆发送给浏览器解析,得到http://ip:port/
二十二、HttpServletResponse类
HttpServletResponse类的作用
HttpServletResponse类和HttpServRequest类一样。每次请求进来,Tomcat服务器都会创建一个Response对象传递给Servlet程序去使用,HttpServletRequest表示过来的信息,HttpServletResponse表示所有响应的信息,我们如果需要设置返回给客户端的信息,都可以通过HttpServletResponse对象进行设置
两个输出流的说明
字节流 getOutputStream(); 常用于下载(传递二进制数据)
字符流 getWriter(); 常用于回传字符串(常用)
两个流同时只能使用一个。否则报错
二十三、往客户端回传数据
创建一个类ResponIOServlet:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ResponseIOServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter writer=response.getWriter();
writer.write("AiQingShuiXingL");
}
}
web.xml配置,运行之后:
中文乱码问题
设置 response.setCharacterEncoding("GBK");就可以解决中文在浏览器显示乱码问题
第一种方式:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ResponseIOServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(response.getCharacterEncoding());//默认是字符集是ISO-8859-1,不支持中文
//设置字符集为GBK
response.setCharacterEncoding("GBK");
PrintWriter writer=response.getWriter();
writer.write("爱情睡醒了");
}
第二种方式:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ResponseIOServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(response.getCharacterEncoding());//默认是字符集是ISO-8859-1,不支持中文
//设置字符集为UTF—8
response.setCharacterEncoding("UTF-8");
//告诉浏览器也设置UTF-8即可
response.setHeader("Content-Type", "text/html;charset=UTF-8");
PrintWriter writer=response.getWriter();
writer.write("爱情睡醒了");
}
}
第三种方式:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ResponseIOServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(response.getCharacterEncoding());//默认是字符集是ISO-8859-1,不支持中文
//一定得在获取流对象前使用,否则无效
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer=response.getWriter();
writer.write("爱情睡醒了");
}
}
二十四、请求重定向
请求重定向的第一种方式
创建两个类response1和response2
response1
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Response1 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置响应状态码302,表示重定向(已搬迁到新处)
resp.setStatus(302);
//设置响应头,说明新地址在哪
resp.setHeader("Location","http://localhost:8080/03_servlet/response2");
}
}
response2
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Response2 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello response2");
}
}
web.xml配置 中配置访问路径
<servlet>
<servlet-name>Response1</servlet-name>
<servlet-class>com.servlet.Response1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Response1</servlet-name>
<url-pattern>/response1</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Response2</servlet-name>
<servlet-class>com.servlet.Response2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Response2</servlet-name>
<url-pattern>/response2</url-pattern>
</servlet-mapping>
运行结果:
请求重定向的特点
1、浏览器地址栏会发生变化
2、是两次请求(第一次是旧的地址,第二次是重新定到新的地址)
3、不能共享Request域中的数据(因为Tomcat会把每次请求封成一个对象,两次请求所以不同对象)
4、不能访问WEB-INF下的资源(因为也是浏览器发送的请求,浏览器不能直接访问WEB-INF)
5、可以访问工程外的资源,如www.baidu.com
请求重定向的第二种方法
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Response1 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//第二种方法(括号内直接设置新的访问地址)
resp.sendRedirect("http://www.baidu.com");
}
}
二十五、使用注解配置Servlet
Servlet要想被访问,必须配置其访问路径(urlPattern)
一个Servlet可以配置多个访问路径(urlPattern)
前面学习了在web.xml中配置,过于繁琐,在servlet3.0之后支持注解配置,在这之前只支持web.xml方式配置。
注解@WebServlet配置规则:
①精确匹配:@WebServlet("/路径")准确写路径才可访问
②目录匹配:@WebServlet("/user/*")写/user/...即可访问
③扩展名匹配:@WebServlet("*./do")写.../do即可访问
④任意匹配:@WebServlet("/")或@WebServlet("/*")写任意资源名都可访问
配置一个路径
在类之上加上@WebServlet("/路径")
配置多个路径
在类之上加上@WebServlet(urlPatterns={"/路径1","路径2"....})
一个路径:
package com;
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 java.io.IOException;
@WebServlet("/zhangsan")
public class DemoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("访问成功");
}
}
多个路径:
@WebServlet(urlPatterns = {"/zhangsan","/lisi"})
public class DemoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("访问成功");
}
}
访问运行得