Servlet笔记
Servlet概述
1.什么是Servlet
Servlet是Javaweb的三大组件之一,它属于动态资源。servlet的作用是处理请求,服务器会把接收到的请求交给servlet来处理,在servlet中通常需要:
- 接收请求数据﹔
- 处理请求;
- 完成响应。
例如客户端发出登录请求,或者输出注册请求,这些请求都应该由servlet来完成处理! servlet需要我们自己来编写,每个 servlet必须实现javax.servlet.Servlet接口。
2.实现Servlet的方式
实现servlet,有三种方式:
- 实现javax.servlet.Servlet接口;
- 继承 javax.servlet.GenericServlet类;
- 继承 javax.servlet.http.HttpServlet类;
通常我们会去继承 HttpServlet类来完成我们的Servlet ,但学习Servlet还要从javax.servlet.Servlet,接口开始学习。
1.Servlet
Servlet.java代码
-
public class 类名 implements Servlet { /** * 它是生命周期方法 * 它会在servlet对象创建之后马上执行,并只执行一次!(出生之后) */ public void init (ServletConfig servletconfig) throws ServletException { System.out.println("init...."); }; /** *可以用来获取Servlet的配置信息 */ public ServletConfig getServletConfig(){ return null; }; /** *它是生命周期方法,它会被调用多次!!! * 每次处理请求都是在调用这个方法 */ public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {}; /** *获取Servlet的信息 */ public String getServletInfo(){ return null; }; /** * 它也是生命周期方法 * 它会在Servlet被销毁之前调用,并且它只会被调用一次! */ public void destroy(){ System.out.println("destroy...."); }; }
1.如何让浏览器访问Servlet
(1)给Servlet指定一个Servlet路径(让Servlet与一个路径绑定在一起)
(2)浏览器访问Servlet路径
(3)给Servlet配置Servlet路径,这需要在web.xml中对Servlet进行配置
<servlet>
<servlet-name>xxx</servlet-name>
<servlet-class>cn.web.servlet.AServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>xxx</servlet-name>
<url-pattern>/AServlet</url-pattern>
</servlet-mapping>
(4)解释浏览器是如何访问的
- 浏览器通过网址:http://localhost:8080/Servlet/AServlet 中“/AServlet“在
标签去寻找到这个 /AServlet ,然后通过xxx 这里面”xxx“再去找到标签下的 xxx ,最后去访问标签下的”cn.web.servlet.AServlet”这个路径。
2.生命周期
Servlet有5个方法,其中三个是生命周期方法
生命周期方法:
-
void init(Servlatconfig):出生之后(1次)
-
void service( ServletRequest request,ServletResponse response):每次处理请求时都会被调用;
-
void destroy():被销毁之前(1次)
特性:
-
单例,一个类只有一个对象﹔当然可能存在多个SerMlet,类!
-
线程不安全的,所以它的效率是高的
Serlet类由我们来写,但对象由服务器来创建,并且由服务器来调用相应的方法。
2.HttpServlet
1、下面截图展示的是HttpServlet的执行方式
2、下面展示的HttpServlet的时序图
3、了解405错误
405错误是HTTP协议中的一个状态码,表明服务器已经理解了请求方法,但是拒绝执行它。这种情况通常发生在你尝试使用一个特定URL不支持的请求方法时,比如GET或POST。这可能是由于网站开发者有意设置的某些限制,以防止客户端执行特定类型的操作,或者是由于服务器配置错误导致的。
分析405错误的原因
- HTTP请求方法不正确:最常见的原因是使用的HTTP请求方法(如GET、POST、PUT、DELETE等)不被服务器接受或支持。如果你向服务器发送的请求方法不被允许,服务器将返回405错误。
- 服务器配置问题:如果服务器配置不正确,它可能无法正确处理请求。例如,Web服务器软件的配置文件中可能存在无意的处理说明,导致405错误。
- 防火墙或安全软件限制:某些防火墙或安全软件可能阻止某些请求方法,如PUT和DELETE。这可能导致405错误。
- 插件或主题问题:如果你在使用一个内容管理系统(如WordPress),某些插件或主题可能与服务器配置不兼容,导致405错误。
3.ServletConfig简介
演示代码
public void init (ServletConfig servletconfig) throws ServletException {
System.out.println("init....");
// 获取初始化参数
System.out.println(servletconfig.getInitParameter("p1"));
System.out.println(servletconfig.getInitParameter("p2"));
// 获取初始化参数的名称
Enumeration<String> e = servletconfig.getInitParameterNames();
while (e.hasMoreElements()){
System.out.println(e.nextElement());
}
};
4.Servlet细节
4.1 Servlet与线程安全
因为一个类型的serlet.只有一个实例对象,那么就有可能会现时出一个Servlet同时处理多个请求
那么Servlet,是否为线程安全的呢?答案是:“不是线程安全的”,这说明servlet,的工作效率很高,但也存在线程安全问题
所以我们不应该在servlet中创建成员变量,因为可能会存在一个线程对这个成员变量进行写操作,另一个线程对这个成员变量进行读操作。
如果实在需要创建变量可以使用下面三种方法:
- 不要在Servlet中创建成员,创建局部变量即可;
- 可以创建无状态成员;
- 可以创建有状态成员,但状态必须为只读的。
4.2 让服务器在启动时就创建Servlet
默认情况下,服务器会在某个Servlet第一次收到请求时创建它。也可以在web.xml 中对Servlet进行配置,使服务器启动时就创建Servlet。
通过
<servlet>
<servlet-name>hello1</servlet-name>
<servlet-class>cn.web.servlet.Hello1Servlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet>
<servlet-name>hello2</servlet-name>
<servlet-class>cn.web.servlet.Hello2Servlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>hello3</servlet-name>
<servlet-class>cn.web.servlet.Hello3Servlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
4.3 url-pattern标签
(1)可以在
<servlet-mapping>
<servlet-name>xxx</servlet-name>
<url-pattern>/AServlet</url-pattern>
<url-pattern>/do</url-pattern>
</servlet-mapping>
那么这说明一个Servlet,绑定了两个 URL,无论访问/AServlet,还是/Servlet,访问的都是AServlet
(2)还可以在
-
<url-pattern>/servlet/*<url-patter>
- servlet/a、/servlet/b,都匹配/servlet/*; 这为匹配路径
-
<url-pattern>*.do</url-pattern>
- /abc/def/ghi.do、/a.do,都匹配*.do; 这为匹配扩展名
-
<url-pattern>/*<url-pattern>
- 匹配所有URL;
-
请注意,通配符要么为前缀,要么为后缀,不能出现在URL中间位置,也不能只有通配符。例如:
/*.do 错误的 一个 URL中最多只能出现一个通配符
4 web.xml文件的继承(了解)
每个完整的Javaweb.应用中都需要有web.xml,但我们不知道所有的web.xml文件都有一个共同的父文件,它在 Tomcat的conf/web.xml路径。
5.ServletContext对象(重要)
- 一个项目只有一个ServletContext对象!
- 我们可以在N多个Servlet中来获取这个唯一的对象,使用它可以给多个 Servlet传递数据。
- 这个对象在Tomcat启动时就创建,在Tomcat关闭时才会死去
5.1 SerxletContext概述
- 概述:ServletContext对象是一个应用上下文对象,也是一个域对象。表示Servlet应用程序,**每个web应用程序都只有一个ServletContext对象 **。
- ServletContext对象的作用:
(1)有了ServletContext对象,就可以共享从应用程序中的所有资源访问到的数据信息,并且可以动态注册web对象。
(2)可以获得应用域的全局初始化参数,以及达到Servlet之间的数据共享;
(3)可以作为域对象在整个应用中共享数据;域对象即在一定的作用范围内实现资源共享;
(4)可以用来获取应用中的资源在服务器上的绝对路径;
(5)获取文件的mime类型: 在网络传输中,并不是以扩展名来区分文件的类型,都是以mime类型;如:text/html;表示一个html文件。 - 生命周期: 应用一加载则创建,应用被停止则销毁
- 创建时间: 加载web应用时,创建ServletContext对象。
总结:
- 服务器会为每个应用创建一个 ServletContext对象;
- ServletContext对象的创建是在服务器启动时完成的;
- ServletContext对象的销毁是在服务器关闭时完成的。
- ServletContext对象的作用是在整个 web应用的动态资源之间共享数据!例如在 AServlet,中向ServletContext,对象中保存一个值,然后在BServlet.中就可以获取这个值,这就是共享数据了。
5.2 获取ServletContext对象
- Servletconfig接口有getServletContext()方法;
- GenaricServlet接口有getServletContext()方法;
- Httpsession接口有getServletContext()方法;
- ServletContextEvent接口有getServletContext()方法
在Servlet中获取ServletContext对象:
-
在void init(ServletConfig config)中:
ServletContext context = config.getServletContext();
- ServletConfig类的 getServletContext()方法可以用来获取Servletcontext对象;
- 在GenericeServlet 或 HttpServlet中获取ServletContext对象:
-
GenericServlet 类有 getServletContext()方法,所以可以直接使用this.getServletContext()来获取;
public class Myserlet implements Serylet {
public void init(ServletConfig config){
ServletContext context = config.getServletContext();
}
}
5.3 域对象的功能
- 域对象指的是对象有作用域,即有作用范围。域对象可以实现数据的共享,不同作用范围对象,共享数据的范围能力也不同。
- 在Servlet规范中,一共有4个域对象。ServletContext就是其中的一个。是web应用中最大的作用域,也叫application应用域,可以实现整个应用之间的数据共享!
ServletContext是Javaweb,四大域对象之一:
- PageContext; -- PageContext页面域
- ServletReguest ; -- request请求域
- Httpsession; -- session会话域
- ServletContext; -- application应用域
所有域对象都有存取数据的功能,因为域对象内部有一个 Map,用来存储数据,下面是ServletContext对象用来操作数据的方法:
-
void setAttribute(String name, object value):用来存储一个对象,也可以称之为存储一个域属性,例如: servletContext.setAttribute("xxx" , "XXX"),在ServletContext中保存了一个域属性,域属性名称为xxx ,域属性的值为.XXX。请注意,如果多次调用该方法,并且使用相同的name,那么会覆盖上一次的值,这一特性与Map相同;
-
object getAttribute(String name):用来获取 ServletContext中的数据,当前在获取之前需要先去存储才行,例如:
String value = (String)servletContext.getAttribute("xxx");
,获取名为xxx的域属性;
-
void removeAttribute(String name):用来移除 ServletContext中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;
-
Enumeration getAttributeNames():获取所有域属性的名称;
示例
创建两个Servlet分别为存储数据的BServlet和获取数据的CServlet。
BServlet.java文件
/**
* 演示从servletcontext中保存数据
*/
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
* 1.获取SevletContext对象
* 2.调用其setAttribute()方法完成保存数据
*/
ServletContext application = this.getServletContext();
application.setAttribute("name", "张三");
}
}
CServlet.java文件
/**
* 演示从servletcontext中获取数据出
*/
public class CServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
*1.获取SevletContext对象
*2.调用其getAttribute()方法完成获取数据
*/
ServletContext appplication = this.getServletContext();
String name = (String) appplication.getAttribute("name");
System.out.println(name);
}
}
5.4 ServletConfig接口
5.4.1 ServletConfig介绍
概述:ServletConfig是Servlet的配置参数对象,在Servlet的规范中,允许为每一个Servlet都提供一些初始化的配置,所以每一个Servlet都有一个ServletConfig。
作用: 当Servlet容器初始化Servlet时,Servlet容器会给S** **,即传入一些配置信息给Servlet。
生命周期: 应用一加载则创建,应用停止则被销毁;
创建时间: 创建完Servlet对象时,接着创建Servletconfig对象。
5.4.2 ServletConfig常用方法
5.4.3 ServletConfig的配置方式
-
在
标签种,通过 标签来配置。有两个子标 -
:代表初始化参数的key; -
: 代表初始化参数的value。 -
<servlet> <servlet-name>BServlet</servlet-name> <servlet-class>cn.web.servlet.BServlet</servlet-class> <init-param> <param-name>init-name</param-name> <param-value>init-value<</param-value> </init-param> </servlet>
-
5.5 ServletContext配置方式
-
ServletContext不像ServletConfig接口在Servlet标签里配置,而是针对于整个应用的配置,也叫全局的初始化参数;
-
在
标签中,通过 标签来配置,有两个子标签: -
: 代表全局初始化参数的key。 -
: 代表全局初始化参数的value。 -
<context-param> <param-name>context-Name</param-name> <param-value>context-Value</param-value> </context-param>
-
5.6 ServletContext常用方法
5.7 ServletContext获取初始化参数
- Servlet也可以获取初始化参数,但它是局部的参数,也就是说一个Servlet只能获取自己的初始化参数,不能获取别人的,即初始化参数只为一个 Servlet准备!
- 可以配嚣公共的初始化参数,为所有Servlet而用!这需要使用SerxletContext()方法才能使用!
还可以使用ServletContext来获取在web.xml文件中配置的应用初始化参数!注意,应用初始化参数与Servlet初始化参数不同:
示例,已有一个web.xml文件和一个DServlet项目文件
ServletContext实现步骤
-
1.定义一个类,继承 HttpServlet。
-
2.重写doGet和doPost方法。
-
3.在web.xml文件中配置Servlet和ServletContext。
-
4.获取ServletContext对象。
-
5.测试相关方法的使用。
-
6.部署并启动项目。
-
7.通过浏览器测试。
-
web.xml文件
<?xml version="1.0" encoding="UTF-8"?> <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-name>DServlet</servlet-name> <servlet-class>cn.web.servlet.DServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DServlet</servlet-name> <url-pattern>/DServlet</url-pattern> <context-param> <param-name>context-Name</param-name> <param-value>context-Value</param-value> </context-param> </web-app>
-
DServlet.java
/** * 演示ServletContext获取公告的初始化参数 */ public class DServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /** * 1.得到ServletContext * 2.调用它getInitParamter(String)得到初始化参数 */ ServletContext application = this.getServletContext(); String value = application.getInitParameter("context-Name"); System.out.println(value); } }
5.8 获取资源相关方法
5.8.1 获取真实路径String getRealPath(String)
可以使用ServletContext对象来获取web应用下的资源,
例如在 hello应用的根目录下创建a.txt文件,现在想在Servlet中获取这个资源,就可以使用ServletContext来获取。
-
获取a.txt的真实路径:
String realPath = ServletContext.getRealPath("/a.txt")
realPath.的值为a.txt文件的绝对路经:F:\tomcat6\webapps\hellola.txt ;
-
获取b.txt的真实路径:
String realPath = ServletContext.getRealPath("/WEB-INF/b.txt");
5.8.2 获取资源流
可以通过ServletContext获取资源流,即把资源以输入流的方式获取:
-
获取a.txt资源流:
InputStream in = ServletContext.getResourceAsStream("/a.txt");
-
获取b.txt资源流:
InputStream in = ServletContext.getResourceAsStream("/WEB-INF/b.txt");
5.8.3 获取指定目录下所有的资源路径
可以使用ServletContext获取指定目录下所有资源路径,例如获取/WEB-INF下所有资源的路径:
Set<String> paths = this.getServletContext().getResourcePaths("/WEB-INF");
实现三种获取资源的代码
/**
* 使用ServletContext获取资源路径
*/
public class EServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取真实路径 D:\learning\aliyun_Servlet\Servlet1\out\artifacts\Servlet1_war_exploded\index.jsp
String realPath = this.getServletContext().getRealPath("/index.jsp");
System.out.println(realPath);
// 获取资源流的路径后,在创建出输入流对象!
InputStream input = this.getServletContext().getResourceAsStream("/index.jsp");
// 获取指定目录下的所有资源路径
Set<String> paths = this.getServletContext().getResourcePaths("/WEB-INF");
System.out.println(paths);
}
}
案例
案例一:访问量统计
—个项目中所有的资源被访问都要对访问量进行累加。
创建一个 int,类型的变量,用来保存访问量,然后把它保存到ServletContext的域中,这样可以保存所有的Servlet都可以访问到.
-
最初时,ServletContext中没有保存访问量相关的属性;
-
当本站第一次被访问时,创建一个变量,设置其值为1,保存到ServletContext中;当以后的访问时,就可以从ServletContext中获取这个变量,然后在其基础之上加1。'
-
获取 ServletContext对象,查看是否存在名为count的属性,如果存在,说明不是第一次访问,如果不存在,说明是第一次访问;
- 第一次访问:调用ServletContext的setAttribute()传递一个属性,名为count,值为1;
- 第2~N次访问:调用ServletContext的get.attribute()方法获取原来的访问量,给访问量加1,再调用ServletContext的setstribute()方法完成数据保存。
程序代码
public class FServlet extends HttpServlet {
/**
* 1.获取ServletContext对象
* 2.从ServletContext对象中获取名为 count的变量
* 3.如果存在,访问量count+1,然后保存;
* 4.如果不存在,说明是第一次访问,向ServletContext中保存名为count的属性设值为1
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext app = this.getServletContext();
Integer count = (Integer) app.getAttribute("count");
if (count == null){
app.setAttribute("count",1);
}else {
app.setAttribute("count",count+1);
}
// 向浏览器中输出,需要响应对象
PrintWriter pw = resp.getWriter();
pw.println("<h3>" + count + "<h3>");
}
}
6.获取类路径下的资源
类路径对一个 javaWeb 项目而言,就是/WEB-INF/classes 和 /WEB-INF/lib/每个jar包。
两种获取方式:
- Class
- ClassLoader
6.1 得到Class
Class c = this.getClass();
6.2 得到ClassLoader
ClassLoader classLoader = this.getClass().getClassLoader();
6.3 实例代码
/**
* 演示获取 类 路径下的资源
*/
public class GServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
* 1.得到ClassLoader --> 先得到Class,在得到ClassLoader
* 2.调用其getResourceAsStream(),得到一个输入流InputStream
* 3.使用第三方commons-io.jar
*/
//相对当前/classes下面的绝对路径
//获取a.txt的内容,IOUtils是一个jar工具包
ClassLoader classLoader = this.getClass().getClassLoader();
InputStream input = classLoader.getResourceAsStream("cn/web/servlet/a.txt");
String s = IOUtils. toString(input);//读取输入流内容,转换成字符串返回
System.out.println("========获取classes文件里servlet下的a.txt==========");
System. out.println(s);
//相对.classes下文件所在的目录,a.txt是当前类编译以后所在的包下面
Class c = this.getClass();
InputStream input1 = c.getResourceAsStream("a.txt");
String s1 = IOUtils. toString(input1);//读取输入流内容,转换成字符串返回
System.out.println("========获取当前classes文件下的a.txt==========");
System. out.println(s1);
//相对于classes,b.txt是相对于编译以后classes文件夹下的位置下面,与上面不同的是添加了“ / ”
InputStream input2 = c.getResourceAsStream("/a.txt");
String s2 = IOUtils. toString(input2);//读取输入流内容,转换成字符串返回
System.out.println("========获取当前classes文件下的/a.txt==========");
System. out.println(s2);
}
}
7.BaseServlet
7.1 BaseServlet 的作用
让一个Servlet可以处理多种不同的请求,不同的请求调用Servlet的不同方法。
7.2 实现原理
客户端发送请求时, 必须多给出一个参数, 用来说明要调用的方法!! 这样BaseServlet 通过该参数来调用目标方法。
http://localhost:8080/xxx/AServlet?m=addUser // m=addUser就是其中的参数用来说明调用addUser方法
请求处理方法的签名必须与 service 相同, 即方法的返回值和参数,以及声明的异常都相同.
7.3 代码演示
7.3.1 客户端必须传递名为method的参数
public class AServlet extends HttpServlet {
/**
* 在这里给出多个请求处理方法 请求处理方法:除了名称以外,都与service方法相同!
*/
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*
* 1.获取参数,用来识别用户想请求的方法
* 2.然后判断是哪一个方法,是哪一个我们就调用哪一个方法
*/
String methodName = request.getParameter("method");
if(methodName == null || methodName.trim().isEmpty()){
throw new RuntimeException("您没有传递method参数!无法确定您想调用的方法。");
}
/*
* 得到方法名称,是否可通过反射来调用方法?
* 1.得到方法名,通过方法名在得到Method类的对象!
* >需要得到Class,然后调用它的方法进行查询!得到Method
* >我们要查询的是当前类的方法,所以我们需要得到当前类的Class
*/
Class c = this.getClass();//得到当前类的class对象
//查询方法-->参数:1.方法名 2.两个需要用到的对象的类
Method method = null;
try {
method = c.getMethod(methodName,
HttpServletRequest.class,HttpServletResponse.class);//方法名,参数
} catch (Exception e) {
throw new RuntimeException("您要调用的方法:"+methodName+",它不存在。");
}
/*
* 反射调用
* 调用method表示的方法--参数
*/
try {
method.invoke(this, request,response);
} catch (Exception e) {
System.out.println("您调用的方法:"+methodName+",它内部抛出了异常!");
throw new RuntimeException(e);//继续向外抛,让用户看到抛出的异常
}
/*//这段代码不可重用。每增加一个方法,这里就需要判断一下
if(method.equals("addUser")){
addUser(request,response);
}else if(method.equals("editUser")){
editUser(request,response);
}else if(method.equals("deleteUser")){
deleteUser(request, response);
}*/
}
public void addUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
public void editUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
public void deleteUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
public void selectUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
}
7.3.2 上边的代码封装到一个抽象类BaseServlet中
BaseServlet.java:--> 一个继承HttpServlet的抽象类(Class不是Servlet),不需要在web.xml中配置。
public abstract class BaseServlet extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*
* 1.获取参数,用来识别用户想请求的方法
* 2.然后判断是哪一个方法,是哪一个我们就调用哪一个方法
*/
String methodName = request.getParameter("method");
if(methodName == null || methodName.trim().isEmpty()){
throw new RuntimeException("您没有传递method参数!无法确定您想调用的方法。");
}
/*
* 得到方法名称,是否可通过反射来调用方法?
* 1.得到方法名,通过方法名在得到Method类的对象!
* >需要得到Class,然后调用它的方法进行查询!得到Method
* >我们要查询的是当前类的方法,所以我们需要得到当前类的Class
*/
Class c=this.getClass();//得到当前类的class对象
//查询方法-->参数:1.方法名 2.两个需要用到的对象的类
Method method = null;
try {
method=c.getMethod(methodName,
HttpServletRequest.class,HttpServletResponse.class);//方法名,参数
} catch (Exception e) {
throw new RuntimeException("您要调用的方法:"+methodName+",它不存在。");
}
/*
* 反射调用
* 调用method表示的方法--参数
*/
try {
method.invoke(this, request,response);
} catch (Exception e) {
System.out.println("您调用的方法:"+methodName+",它内部抛出了异常!");
throw new RuntimeException(e);//继续向外抛,让用户看到抛出的异常
}
}
}
7.3.3 实现一个Servlet中有多个请求处理方法
AServlet继承BaseServlet抽象类
public class AServlet extends BaseServlet{
public void addUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
public void editUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
public void deleteUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
public void selectUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
}
7.3.4 通过BaseServlet实现Servlet完成转发或从重定向
修改BaseServlet抽象类文件
public abstract class BaseServlet extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String methodName = request.getParameter("method");
if(methodName == null || methodName.trim().isEmpty()){
throw new RuntimeException("您没有传递method参数!无法确定您想调用的方法。");
}
//得到当前类的class对象
Class c=this.getClass();
//查询方法-->参数:1.方法名 2.两个需要用到的对象的类
Method method = null;
try {
method=c.getMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);//方法名,参数
} catch (Exception e) {
throw new RuntimeException("您要调用的方法:"+methodName+",它不存在。");
}
/*
* 反射调用
* 调用method表示的方法--参数
*/
try {
String result = (String)method.invoke(this, request,response);
/*
* 获取请求处理方法执行后返回的字符串,它表示转发或者重定向的路径!
* 帮它完成转发或者重定向!
*/
//如果用户返回的字符串为null,或为"",那么我们什么也不做!
if(result == null || result.trim().isEmpty()){
return;//方法结束
}
/*
* 查看返回字符串中是否包含冒号,如果没有,表示转发
* 如果有,使用冒号分割字符串,得到前缀和后缀!
* 其中前缀如果是f,表示转发,如果是r表示重定向,后缀就是要转发或重定向的路径
*/
if(result.contains(":")){
//使用冒号分割字符串,得到前缀和后缀
int index=result.indexOf(":");//获取冒号的位置
String s = result.substring(0, index);//截取前缀,表示操作
String path = result.substring(index+1);//截取后缀,表示路径
if(s.equalsIgnoreCase("r")){//前缀r,重定向
response.sendRedirect(request.getContextPath()+path);
}else if(s.equalsIgnoreCase("f")){//前缀f,转发
request.getRequestDispatcher(path).forward(request, response);
}else{
throw new RuntimeException("你指定的操作:"+s+",当前版本不支持!");
}
}else{//没有冒号,默认为转发!
request.getRequestDispatcher(result).forward(request, response);
}
} catch (Exception e) {
System.out.println("您调用的方法:"+methodName+",它内部抛出了异常!");
throw new RuntimeException(e);//继续向外抛,让用户看到抛出的异常
}
}
}
只需自己写的Servlet(在这是BServlet)继承BaseServlet就行(则子类就有多个处理方法,以及转发和重定向的功能了)。
public class BServlet extends BaseServlet {
public String fun1(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("fun1()...");
return "/index.jsp";
}
public String fun2(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("fun2()...");
return "r:/index.jsp";
}
public String fun3(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("fun3()...");
return null;
}
}
本文作者:粤先生
本文链接:https://www.cnblogs.com/magicYue/p/18173456
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步