![cover](https://img-blog.csdnimg.cn/b0b10ff3d09143f087556e9c1af1e5c7.png)
Servlet---GenericServlet抽象类
Java打卡:第98天javaWeb — Servlet内容导航ServletContext欢迎页面url-pattern精确路径通配路径全路径匹配优先级Servlet coreGenericServlet修改init方法: 模板方法设计模式Java EEServlet这几天servlet的进度有一点停滞,因为Mysql的理论,还有数字逻辑基本电路,包括FSM和FPGEA的学习;之前说过狭义的Se
Java打卡:第98天
javaWeb — Servlet
Java EE
Servlet
这几天servlet的进度有一点停滞,因为Mysql的理论,还有数字逻辑基本电路,包括FSM和FPGEA的学习;之前说过狭义的Servlet接口中有5个基本的方法,包括service服务,init初始化,destroy销毁Servlet对象,getServletInfo获得开发者等信息,还有就是getServletConfig可以获得配置对象,一个Servlet对象对应一个config对象,但是一个web.xml也就是一个应用程序只对应一个compex对象,就是环境【上下文】
ServletContext
一个应用程序application就只有一个Context对象;其中的Servelt对象的上下文环境都是一样的。Defines a set of methods that a servlet uses to communicate with its servlet container, for example, to get the MIME type of a file, dispatch requests, or write to a log file.
其中有很多的常用的方法比如attribute,parameter,path路径等
首先就是这里也有parameter操作,这里的参数是对应的application,所以配置的时候不是在Servlet标签中,而是在外面的标签中。
<!-- 定义所有的servlet对象可以共享的参数 -->
<context-param>
<param-name>name</param-name>
<param-value>cfeng.cn</param-value>
</context-param>
<context-param>
<param-name>address</param-name>
<param-value>西安古城墙</param-value>
</context-param>
这里就是设置的一个全局的一个参数,这里的访问和ServletConfig对象是相同的
ServletContext context = config.getServletContext();
//获取所有的初始化参数名
Enumeration<String> names = context.getInitParameterNames();
while(names.hasMoreElements()) {
String nextPara = names.nextElement();
System.out.println(nextPara + ":" + context.getInitParameter(nextPara)); //这里就是键值对,输入名称获得值
}
信息: [622]毫秒后服务器启动
address:西安古城墙
name:cfeng.cn
输出的效果和上面是相同的。这里获取的是一个Enums的一个存储了所有的键key
- 域属性attribute
域属性是全局的,任何Servlet所做的修改都是全局性的
除了参数直接在xml文件中直接定义,还可以在java程序中写入attribute域属性,同样,域属性也是可以共享的,其他的Servlet类可以访问修改
public class otherServlet implements Servlet
……
配置文件很简单
<servlet>
<servlet-name>otherServlet</servlet-name>
<servlet-class>com.cfeng.otherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>otherServlet</servlet-name>
<url-pattern>/other</url-pattern>
</servlet-mapping>
- 路径ContextPath
这个方法可以获取到的就是程序的路径,其中遵循的是HTTP的url的方式,而RealPath则是获取到遵循本地的file协议的文件的路径
//context中的参数是应用程序的,所有的servlet对象共享
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
ServletContext context = config.getServletContext();
//获取所有的初始化参数名
Enumeration<String> names = context.getInitParameterNames();
while(names.hasMoreElements()) {
String nextPara = names.nextElement();
System.out.println(nextPara + ":" + context.getInitParameter(nextPara)); //这里就是键值对,输入名称获得值
}
//设置域属性 【所有的Servlet对象是共享的】
context.setAttribute("qq", "18979697");
context.setAttribute("email", "163@com");
String attriName = (String) context.getAttribute("qq");
System.out.println(attriName);
System.out.println(context.getContextPath());
System.out.println(context.getRealPath("/webapp"));
}
address:西安古城墙
name:cfeng.cn
18979697
/proj1
D:\Java项目\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\proj1\webapp
可以看到上面的路径就是项目的路径,HTTP中URL的路径;而下面的是本地的文件的存放的位置
欢迎页面
在web.xml中可以设置欢迎页面,也即是welcome-list,包括html,jsp等
所用的标签就是welcome-file-list ,其中的子标签都是welcome-file
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
所以可以在项目下面直接建立一个html文件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>cfeng.com IT助力学习</title>
</head>
<body>
<font color="red">你好,欢迎访问本界面</font>
</body>
</html>
这样,当我们访问的时候九会直接访问该程序,其实就是web.xml中的欢迎界面
就是直接只输入项目的名称的时候,访问到的就是这个默认的界面;还可以通过将文件名改为ROOT,就可以通过域名直接访问到该程序,同时访问到的就是欢迎界面
如果有多个文件,就按顺序查找欢迎界面里面的文件,前面的HTML是先访问的,后面的HTML就不访问了;所以先访问的是html,后面的css和jsp都是会查找;查找不到的时候会从Tomcat服务器中找;找不到就404
url-pattern 精确路径 通配路径 全路径
路径的匹配有精确的路径匹配模式;一个servlet可以书写多个url-pattern和其匹配
当要访问的时候就是使用Servlet-Mapping中的标签url-pattern就可以
- 同时还可以使用通配符匹配模式
使用通配符模式
<url-pattern>/other/*</url-pattern>
这里就代表访问的时候,只要输入了路径/other,后面的就可以随意书写
- 全路径
上面的通配路径使用的是通配路径,要写上前面的,后面的任意都可以访问;全路径就是可以书写任意的都可以访问
使用全路径模式
<url-pattern>/*</url-pattern>
<url-pattern>/</url-pattern>
这里就拦截了所有的请求,包括动态或者静态的资源的访问都连接,只是执行该servlet
/* 会拦截所有的请求;但是/只是拦截静态资源请求,动态资源请求包括jsp等不会拦截
- 后缀模式
<url-pattern>*.do</url-pattern>
这里的意思是拦截所有的以.do结尾的请求;后缀名模式和路径模式不能同时使用
匹配优先级
- 路径优先后缀
也就是当都满足路径和后缀的时候,是优先访问的路径
- 精确优先通配
当输入的路径是精确的时候,会优先查找是否有精确匹配的,之后才会去找通配的;
- 最长路径优先匹配
当都是通配的时候,路径更长的自然会更精确,所以会先匹配长路径
Servlet core
GenericServlet
Generic 通用的,一般的
GenericServlet;之前定义Servlet就发现了问题,实现一个类必须实现Servlet接口,但是真正使用到的只有一个service方法,其他的方法都没有使用到;那么就构想使用一个适配器,该适配器只有一个抽象方法就是service
使用适配器设计模式中的缺省适配器模式;就是空实现一些方法,这样在开发的时候,先定义一个abstract类实现Servlet接口,之后定义的Servlet操作类都只需要继承给Generic
这里的思路和之前讲解Mysql后面为了方便操作定义一个工具类DBUtil相同,都是为了简化之后的操作
package cfeng;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.*;
public abstract class GenericServlet implements Servlet, ServletConfig {
private ServletConfig config;
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
}
@Override
public ServletConfig getServletConfig() {
return config;
}
@Override
public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
@Override
public String getServletName() {
return config.getServletName();
}
@Override
public ServletContext getServletContext() {
return config.getServletContext();
}
@Override
public String getInitParameter(String name) {
return config.getInitParameter(name);
}
@Override
public Enumeration<String> getInitParameterNames() {
return config.getInitParameterNames();
}
}
这里的GenericServlet实现这个ServletConfig的目的就是方便子类的使用,直接在其中定义一个私有的对象,然后子类直接就通过this就可以调用方法了,因为本身就是一个config对象
package cfeng;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class SomeServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
//但是如果这里想使用配置对象,那么就必须要创建才能使用,可以直接让父类实现Config接口
//但是这样子还是要先创建对象,可以直接实现接口,之后就可以直接使用方法,使用this
System.out.println(this.getInitParameter("name"));
}
}
子类的书写就没有之前的那么繁杂了,非常简洁,但是还是需要在配置文件中进行配置
修改init方法: 模板方法设计模式
上面介绍的设计模式是适配器设计模式,对于方法很多,但是经常使用的方法很少的时候,就使用适配器模式,java的源码中,特别是界面位置广泛使用了这种设计模式。这里的Generic的init方法可以修正一下
- 需求: 子类someServlet执行的时候想要在init方法中输出一个”hello world“?
这里作为一个基本的想法就是子类重写一下父类的init方法;但是容易造成的是空指针异常,因为GenericServlet中的init的一个作用就是获取到config对象;所以要想正常的使用子类就必须加上一个super
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config); //不加这一个,就会出现空指针异常
System.out.println("hello world");
}
信息: 已完成重新加载名为/proj1的上下文
hello world
cfeng
但是这里的缺点就是一定要记得加上super.init;这里因为是使用的快捷键alt + shift + s最后按下v;所以自动生成了,自己写容易忘记,如何优化呢?
这里就使用模板方法模式,对于这种父类的方法有特定功能的,就要将其作为模板方法,剥离出一个空方法,专门用来作为继承的方法
HTTP状态 500 - 内部服务器错误
类型 异常报告
消息 Cannot invoke "javax.servlet.ServletConfig.getInitParameter(String)" because "this.config" is null
描述 服务器遇到一个意外的情况,阻止它完成请求。
例外情况
java.lang.NullPointerException: Cannot invoke "javax.servlet.ServletConfig.getInitParameter(String)" because "this.config" is null
cfeng.GenericServlet.getInitParameter(GenericServlet.java:46)
cfeng.SomeServlet.service(SomeServlet.java:16)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
):注意 主要问题的全部 stack 信息可以在 server logs 里查看
Apache Tomcat/9.0.55
这里就是删除上面那行super.init(config)之后的结果
package cfeng;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class SomeServlet extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println(this.getInitParameter("name"));
}
@Override
public void init() {
System.out.println("hello world");
}
}
这里就是看到init就没有写上面那行代码,但是不报错,就使用模板方法模式
package cfeng;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.*;
public abstract class GenericServlet implements Servlet, ServletConfig {
private ServletConfig config;
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
init();
}
public void init() {
//专门用来继承
}
@Override
public ServletConfig getServletConfig() {
return config;
}
@Override
public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
@Override
public String getServletName() {
return config.getServletName();
}
@Override
public ServletContext getServletContext() {
return config.getServletContext();
}
@Override
public String getInitParameter(String name) {
return config.getInitParameter(name);
}
@Override
public Enumeration<String> getInitParameterNames() {
return config.getInitParameterNames();
}
}
模板方法模式就是基于的重载,接下来就是HTTPServlet了,虽然JSP等过时,但是为了给框架学习打基础,还是要学习的🎄
更多推荐
所有评论(0)