1. 我们编写一个Servlet类直接实现Servlet接口有什么缺点? 11
- 我们只需要service方法,其他方法大部分情况下是不需要使用的。代码很丑陋。
2. 适配器设计模式Adapter 11
- 手机直接插到220V的电压上,手机直接就报废了。怎么办?可以找一个充电器。这个充电器就是一个适配器。手机连接适配器。适配器连接220V的电压。这样问题就解决了。
- 编写一个GenericServlet类,这个类是一个抽象类,其中有一个抽象方法service。
- GenericServlet实现Servlet接口。
- GenericServlet是一个适配器。
- 以后编写的所有Servlet类继承GenericServlet,重写service方法即可。
代码在com.bjpowernode.javaweb.servlet.
适配器模式改造标准通用的GenericServlet
package com.bjpowernode.javaweb.servlet;
import jakarta.servlet.*;
import java.io.IOException;
//适配器模式改造Servlet 11
//编写一个标准通用的Servlet起名为GenericServlet,以后所有的Servlet类不要直接实现Servlet接口了
//以后所有的Servlet类都要继承GenericServlet类,GenericServlet就是一个适配器
public abstract class GenericServlet implements Servlet{
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
//将此方法改成一个抽象方法这个最常用,所以要求子类必须实现service方法
@Override
public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException;
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
LoginServlet
package com.bjpowernode.javaweb.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;
//这个LoginServlet去继承我们改造的GenericServlet 11
//我们的这个GenericServlet继承了Servlet接口且实现了其方法,而且将最常用的service方法抽象
//所以我们这个LoginServlet继承GenericServlet只用实现service方法即可(因为继承抽象了其抽象方法
// 必须实现,这也恰恰正合我们的意思)因为只用实现service方法显得代码更加美观不冗余
public class LoginServlet extends GenericServlet{
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
System.out.println("正在处理用户登录请求,请稍后……");
}
}
VipServlet
package com.bjpowernode.javaweb.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;
//这个VipServlet去继承我们改造的GenericServlet 11
public class VipServlet extends GenericServlet{
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
System.out.println("vip可以享受更好的服务……");
}
}
配置文件web.xml
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">
LoginServlet
com.bjpowernode.javaweb.servlet.LoginServlet
LoginServlet
/login
vipServlet
com.bjpowernode.javaweb.servlet.VipServlet
vipServlet
/vip
3. 改造GenericServlet 12
3.1 思考:GenericServlet类是否需要改造一下?怎么改造?更利于子类程序的编写? 12
- 思考第一个问题:我提供了一个GenericServlet之后, init方法还会执行吗?
- 还会执行。会执行GenericServlet类中的init方法。(即子类没有执行父类的)
- 思考第二个问题:init方法是谁调用的?
- Tomcat服务器调用的。
- 思考第三个问题:init方法中的ServletConfig对象是谁创建的?是谁传过来的?
- 都是Tomcat干的。
- Tomcat服务器先创建了ServletConfig对象,然后调用init方法,将ServletConfig对象传给了init方法。
思考一下Tomcat服务器伪代码:
public class Tomcat {
public static void main(String[] args){
// .....
// Tomcat服务器伪代码
// 创建LoginServlet对象(通过反射机制,调用无参数构造方法来实例化LoginServlet对象)
Class clazz = Class.forName("com.bjpowernode.javaweb.servlet.LoginServlet");
Object obj = clazz.newInstance();
// 向下转型
Servlet servlet = (Servlet)obj;
// 创建ServletConfig对象
// Tomcat服务器负责将ServletConfig对象实例化出来。
// 多态(Tomcat服务器完全实现了Servlet规范)
ServletConfig servletConfig = new org.apache.catalina.core.StandardWrapperFacade();
// 调用Servlet的init方法
servlet.init(servletConfig);
// 调用Servlet的service方法
// ....
}
}
3.2 改造GenericServlet案例 12
代码在com.bjpowernode.javaweb.servlet2.
GenericServlet
package com.bjpowernode.javaweb.servlet2;
import jakarta.servlet.*;
import java.io.IOException;
//适配器模式改造Servlet 12
//改造GenericServlet 12
//编写一个标准通用的Servlet起名为GenericServlet,以后所有的Servlet类不要直接实现Servlet接口了
//以后所有的Servlet类都要继承GenericServlet类,GenericServlet就是一个适配器
public abstract class GenericServlet implements Servlet{
//成员变量
private ServletConfig config;
/**
* init方法中的ServletConfig对象是小猫咪创建好的。
* 这个ServletConfig对象目前在init方法的参数上,属于局部变量。
* 那么ServletConfig对象肯定以后要在service方法中使用,怎么才能保证ServletConfig对象
* 在service方法中能够使用呢?
*/
//加final是为保证子类不能重写init方法
@Override
public final void init(ServletConfig config) throws ServletException {
//解释
//this.config指成员变量 config指参数的ServletConfig config
//将参数的config赋值为成员变量的config,就可以保证成员变量的config不为空,从而确保
//getServletConfig()方法中返回的return config不为空
this.config=config;
//调用我们写的init
this.init();
}
//我们写的init
//供子类重写的
public void init(){
}
@Override
public ServletConfig getServletConfig() {
return config;
}
//将此方法改成一个抽象方法这个最常用,所以要求子类必须实现service方法
@Override
public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException;
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
LoginServlet
package com.bjpowernode.javaweb.servlet2;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;
//这个LoginServlet去继承我们改造的GenericServlet 12
//我们的这个GenericServlet继承了Servlet接口且实现了其方法,而且将最常用的service方法抽象
//所以我们这个LoginServlet继承GenericServlet只用实现service方法即可(因为继承抽象了其抽象方法
// 必须实现,这也恰恰正合我们的意思)因为只用实现service方法显得代码更加美观不冗余
public class LoginServlet extends GenericServlet {
// 思考一个问题: 12
// 有没有一种可能,需要我在LoginServlet类中重写init方法?
// 当然有可能,于是乎就重写了init方法。
// 但是我们不想让子类重写init方法,既需要在父类的init方法加final,因为子类重写了init方法可能
// 导致在子类中使用getServletConfig()获取的config为空null(因为子类一旦重写父类的init就不会执行)
/*public void init(ServletConfig config) throws ServletException {
System.out.println("重写我自己的规则。。。。。");
}*/
// 父类将原始的init方法final了,我子类没有办法重写这个init方法了。
// 如果这个时候我还是希望能够重写init方法,该怎么办呢?
@Override
public void init(){
System.out.println("LoginServlet's init() method execute!");
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
System.out.println("正在处理用户登录请求,请稍后……");
//想在LoginServlet子类中使用ServletConfig对象
ServletConfig config = this.getServletConfig();
System.out.println("service方法中可以获取到ServletConfig对象 "+config);
}
}
配置文件web.xml
<servlet>
<servlet-name>LoginServlet2</servlet-name>
<servlet-class>com.bjpowernode.javaweb.servlet2.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet2</servlet-name>
<url-pattern>/login2</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>vipServlet2</servlet-name>
<servlet-class>com.bjpowernode.javaweb.servlet2.VipServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>vipServlet2</servlet-name>
<url-pattern>/vip2</url-pattern>
</servlet-mapping>
3.3 好消息GenericServlet不用我们自己写,原码提供了 12
3.3.1 案例演示
代码在com.bjpowernode.javaweb.servlet2.
UserServlet
package com.bjpowernode.javaweb.servlet2;
import jakarta.servlet.GenericServlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;
//演示使用系统的GenericServlet 12
public class UserServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
System.out.println("输出使用系统的GenericServlet");
}
}
配置文件web.xml
<servlet>
<servlet-name>userServlet</servlet-name>
<servlet-class>com.bjpowernode.javaweb.servlet2.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>userServlet</servlet-name>
<url-pattern>/user</url-pattern>
</servlet-mapping>