# Servlet概念
运行在服务器端的小程序
* Servlet就是一个接口,定义了Java类被服务器识别调用的规则。
* 我们自定义一个类,实现Servlet接口,重写方法。
# Servlet入门:
1. 创建JavaEE项目
2. 定义一个类,实现Servlet接口(继承HttpServlet类)
* public class ServletDemo1 implements Servlet
3. 实现接口中的抽象方法
4. 配置Servlet
在web.xml中配置:
<!--配置Servlet -->
<servlet>
<servlet-name>demo1</servlet-name>
<!-- 类的全路径名 -->
<servlet-class>cn.itcast.web.servlet.ServletDemo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>demo1</servlet-name>
<url-pattern>/demo1</url-pattern> <!-- 类的资源名称,随便起 -->
</servlet-mapping>
执行原理:
1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
2. 查找web.xml文件,是否有对应的<url-pattern>标签体内容。
3. 如果有,则在找到对应的<servlet-class>全类名
4. tomcat会将字节码文件加载进内存,并且创建其对象
5. 调用其service方法
file:///C:/Users/煊无〇/AppData/Local/Temp/enhtmlclip/Image.png
Servlet中的生命周期方法:
1. 被创建:执行init方法,只执行一次
* Servlet什么时候被创建?
* 默认情况下,第一次被访问时,Servlet被创建
* 可以配置执行Servlet的创建时机。
* 在<servlet>标签下配置
1. 第一次被访问时,创建
* <load-on-startup>的值为负数或不创建该标签
2. 在服务器启动时,创建
* <load-on-startup>的值为0或正整数, 正数的值越小,启动该servlet的优先级越高
* Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的
* 多个用户同时访问时,可能存在线程安全问题。
* 解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,使用final修饰
2. 提供服务:执行service方法,执行多次
* 每次访问Servlet时,Service方法都会被调用一次。
3. 被销毁:执行destroy方法,只执行一次
* Servlet被销毁时执行。服务器关闭时,Servlet被销毁
* 只有服务器正常关闭时,才会执行destroy方法。
* destroy方法在Servlet被销毁之前执行,一般用于释放资源
IDEA与Tomcat的配置
1. IDEA会为每一个tomcat部署的项目单独建立一份配置文件
* 查看控制台的log:Using CATALINA_BASE: "C:\Users\煊无〇\.IntelliJIdea2018.3\system\tomcat"
2. 工作空间项目 和 tomcat部署的web项目
* tomcat真正访问的是“tomcat部署的web项目”,"tomcat部署的web项目"对应着"工作空间项目" 的web目录下的所有资源
* WEB-INF目录下的资源不能被浏览器直接访问。
3. 断点调试:使用dubug 启动
# Servlet体系结构
Servlet -- 接口
|
GenericServlet -- 抽象类
|
HttpServlet -- 抽象类
* GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
* 将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可
* HttpServlet:对http协议的一种封装,简化操作
1. 定义类继承HttpServlet
2. 复写doGet/doPost方法
3. Tomcat调用httpServlet的service,再分发到doGet/doPost
WebServlet相关配置
1. urlPatterns:Servlet访问路径
一个Servlet可以定义多个访问路径 : @WebServlet({"/d4","/dd4","/ddd4"})
2. 路径定义规则:
1. /xxx:路径匹配
2. /xxx/xxx: 多层路径,目录结构
3. *.do:扩展名匹配 *代表任意,前面不能加/
# BaseServlet的抽取
将servlet抽取成基础servlet
优点:
1.减少servlet的数量
2.降低代码冗余,提高复用性
实现:
public class BaseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//完成方法分发
//1.获取请求路径
String uri = req.getRequestURI(); // /travel/user/add
System.out.println("请求uri:"+uri);// /travel/user/add
//2.获取方法名称
String methodName = uri.substring(uri.lastIndexOf('/') + 1);
System.out.println("方法名称:"+methodName);
//3.获取方法对象Method
System.out.println(this);
try {
//获取方法
Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);//获取的方法必须是public的
//4.执行方法
method.invoke(this,req,resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
使用:
@WebServlet("/user/*")
public class UserServlet extends BaseServlet {
//声明UserService业务对象
private UserService service = new UserServiceImpl();
public void 方法名(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
...
}
...
}
# Filter过滤器
作用:对访问服务器资源的请求和响应给浏览器的资源进行拦截并进行管理,完成一些特殊的功能
功能:完成一些通用操作,如:登录验证、统一编码处理、敏感字符过滤、打水印,session管理、权限控制....
使用步骤:
- 定义一个类实现javax.servlet.Filter接口
- 重写Filter的方法
init()、doFilter()、destory()
- 配置过滤器
- 使用web.xml配置
- 使用web.xml配置
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.bjsxt.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/资源路径</url-pattern>
</filter-mapping>
-
- 使用@WebFilter注解配置
- 使用@WebFilter注解配置
直接在Filter类上配置@WebFilter("/资源路径")
执行流程:
1.浏览器发起请求到服务器,服务器接收到请求后,根据URI信息找到对应的过滤器执行doFilter方法
2. 过滤器对请求处理后,符合要求则放行,...,执行对应的servlet
3. 执行完servlet返回的响应继续执行doFilter剩下的代码
生命周期:从服务器启动到服务器关闭
生命周期方法:
1. init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源
2. doFilter:每一次请求被过滤器拦截时,会执行。执行多次,调用 filterChain.doFilter(req,resp)放行,执行完servlet继续执行剩下代码
3. destroy:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源
配置详解:
- 拦截路径配置:
1. 具体资源路径: /index.jsp 只有访问index.jsp资源时,过滤器才会被执行
2. 拦截目录: /user/* 访问/user下的所有资源时,过滤器都会被执行
3. 后缀名拦截: *.jsp 访问所有后缀名为jsp资源时,过滤器都会被执行
4. 拦截所有资源:/* 访问所有资源时,过滤器都会被执行
- 拦截方式配置:资源被访问的方式
* 注解配置:
* 设置dispatcherTypes属性数组,可配置多个值
1. REQUEST:默认值。浏览器直接请求资源被拦
2. FORWARD:转发访问资源被拦,默认不拦
3. INCLUDE:包含访问资源被拦,默认不拦
4. ERROR:错误跳转资源被拦,默认不拦
5. ASYNC:异步访问资源被拦,默认不拦
* web.xml配置
* 在<filter-mapping>中设置<dispatcher></dispatcher>标签即可
过滤器链:
* 执行顺序:如果有n个过滤器:
1. 过滤器1
2. 过滤器2
...
3. 执行资源
...
4. 过滤器2
5. 过滤器1
* 过滤器链先后顺序问题:
1. 注解配置:按照类名的字符串比较规则比较,值小的先执行
* 如: AFilter 和 BFilter,AFilter就先执行了。
2. web.xml配置: <filter-mapping>谁定义在上边,谁先执行
# Listener
作用:监听作用域对象request、session、application的创建、销毁和内容的改变
监听机制:
事件 :一件事情
事件源 :事件发生的地方
监听器 :一个对象
注册监听:将事件、事件源、监听器绑定在一起。 当事件源上发生某个事件后,执行监听器代码
分类:
- Request监听
- ServletRequestListener 监听request对象的初始化和销毁
- ServletRequestListener 监听request对象的初始化和销毁
requestInitialized(ServletRequestEvent sre)//初始化
requestDestroyed(ServletRequestEvent sre)//销毁
注意:
形参可以获取监听的request对象
sre.getServletRequest();
-
- ServletRequestAttributeListener 监听request作用域数据的变更
- ServletRequestAttributeListener 监听request作用域数据的变更
attributeAdded(ServletRequestAttributeEvent srae) //添加attribute
attributeRemoved(ServletRequestAttributeEvent srae)//删除
attributeReplaced(ServletRequestAttributeEvent srae)//替换
注意:形参可以获取被监听的数据
srae.getName() 获取监听数据的键
srae.getValue() 获取监听数据的值
- Session监听
- HttpSessionListener 监听session的创建和销毁
- HttpSessionListener 监听session的创建和销毁
sessionCreated(HttpSessionEvent se) // 创建
sessionDestroyed(HttpSessionEvent se)// 销毁
注意:形参可以获取被监听的session对象
se.getSession();
-
- HttpSessionAttributeListener 监听session数据的变更
- HttpSessionAttributeListener 监听session数据的变更
attributeAdded(HttpSessionBindingEvent event)
attributeRemoved(HttpSessionBindingEvent event)
attributeReplaced(HttpSessionBindingEvent event)
注意:形参可以获取被监听的数据
event.getName() 获取数据的键名
event.getValue() 获取数据的值
- ServletContext监听
- ServletContextListener 监听application对象的初始化和销毁
- ServletContextListener 监听application对象的初始化和销毁
contextInitialized(ServletContextEvent sce) 初始化 服务器启动
contextDestroyed(ServletContextEvent sce) 销毁 服务器关闭
注意:
形参可以获取当前application对象。
sce.getServletContext();
-
- ServletContextAttributeListener 监听数据的变更
- ServletContextAttributeListener 监听数据的变更
attributeAdded(ServletContextAttributeEvent event)
attributeRemoved(ServletContextAttributeEvent event)
attributeReplaced(ServletContextAttributeEvent event)
注意:
形参可以获取当前监听的数据
event.getName() 获取数据的键名
event.getValue() 获取数据的值
# web.xml详解
作用:
1、启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取<listener>和<context-param>两个结点。
2、紧急着,容创建一个ServletContext(servlet上下文),这个web项目的所有部分都将共享这个上下文。
3、容器将<context-param>转换为键值对,并交给servletContext。
4、容器创建<listener>中的类实例,创建监听器。
加载顺序:
加载顺序与它们在 web.xml 文件中的先后顺序无关。即不会因为 filter 写在 listener 的前面而会先加载 filter。
最终得出的结论是:ServletContext -> listener -> filter -> servlet
同时还存在着这样一种配置节:context-param,它用于向 ServletContext 提供键值对,即应用程序上下文信息。我们的 listener, filter 等在初始化时会用到这些上下文中的信息,那么 context-param 配置节是不是应该写在 listener 配置节前呢?实际上 context-param 配置节可写在任意位置,因此真正的加载顺序为:context-param -> listener -> filter -> servlet
对于某类配置节而言,与它们出现的顺序是有关的。以 filter 为例,web.xml 中当然可以定义多个 filter,与 filter 相关的一个配置节是 filter-mapping,这里一定要注意,对于拥有相同 filter-name 的 filter 和 filter-mapping 配置节而言,filter-mapping 必须出现在 filter 之后,否则当解析到 filter-mapping 时,它所对应的 filter-name 还未定义。web 容器启动时初始化每个 filter 时,是按照 filter 配置节出现的顺序来初始化的,当请求资源匹配多个 filter-mapping 时,filter 拦截资源是按照 filter-mapping 配置节出现的顺序来依次调用 doFilter() 方法的。
servlet 同 filter 类似,此处不再赘述。
由此,可以看出,web.xml 的加载顺序是:ServletContext -> context-param -> listener -> filter -> servlet ,而同个类型之间的实际程序调用的时候的顺序是根据对应的 mapping 的顺序进行调用的。
xml标签:
<discription></discription> 是对web项目的描述
<display-name></display-name> 定义web项目的名称
<distributable/> 是指定该web项目是否可分布式处理
<context-param></context-param> 用来设定web项目的上下文参数(ServletContext),包含两个子元素:
<param-name></param-name> 用来指定参数的名称
<param-value></param-value> 用来设定参数值
<context-param>
<param-name>my_param</param-name>
<param-value>hello</param-value>
</context-param>
ServletContext.getInitParameter("my_param") 来取得
<filter></filter> 是用来声明filter的相关设定,它包含以下子元素:
<filter-name></filter-name> 指定filter的名字
<filter-class></filter-class> 定义filter的类的名称
<init-param></init-param> 用来定义参数,它有两个子元素:
<param-name></param-name> 用来指定参数的名称
<param-value></param-value> 用来设定参数值
<filter-mapping></filter-mapping> 用来定义filter所对应的URL
<filter-name></filter-name> 指定filter的名字
<url-pattern></url-pattern> 指定filter所对应的URL
<dispatcher></dispatcher> 指定拦截的方式
有 request(默认)、forward、include、error、async
<filter>
<filter-name>setCharacterEncoding</filter-name>
<filter-class>com.myTest.setCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GB2312</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>setCharacterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener></listener> 用来设定Listener接口,它的主要子元素为
<listener-class></listener-class> 定义Listener的类名称
<listener>
<listener-class>com.myTest.ContextListener</listener-class>
</listener>
<servlet></servlet> 用来声明一个servlet的数据,主要有以下子元素:
<servlet-name></servlet-name> 指定servlet的名称
<servlet-class></servlet-class> 指定servlet的类名称
<load-on-startup><load-on-startup> 指定servlet加载时机
<jsp-file></jsp-file> 指定web项目中的某个JSP网页的完整路径
<init-param></init-param> 用来定义参数,和前面的<init-param>差不多
<servlet-mapping></servlet-mapping> 用来定义servlet所对应的URL
<servlet-name></servlet-name> 指定servlet的名称
<url-pattern></url-pattern> 指定servlet所对应的URL
<servlet>
<servlet-name>ShoppingServlet</servlet-name>
<servlet-class>com.myTest.ShoppingServlet</servlet-class>
<load-on-startup>-1<load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ShoppingServlet</servlet-name>
<url-pattern>/shop/ShoppingServlet</url-pattern>
</servlet-mapping>
<session-config></session-config> 定义web中的session参数,有2个子元素:
<session-timeout></session-timeout> 用来定义这个web项目所有session的有效期限,单位为分钟,默认为30
<cookie-config></cookie-config>对cookie进行相关配置
<mime-mapping></mime-mapping> 定义某一个扩展名和某一个MIME Type做对映,包含两个子元素:
<extension></extension> 扩展名的名称
<mime-type></mime-type> MIME格式
<welcome-file-list></welcom-file-list> 用来定义首页的列单,包含一个子元素:
<welcome-file></welcome-file> 指定首页的文件名称
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
<welcome-file>login.jsp</welcome-file>
<welcome-file>login.html</welcome-file>
</welcom-file-list>
<error-page></error-page> 用来处理错误代码或异常的页面,有三个子元素:
<error-code></error-code> 错误状态码
<exception-type></exception-type> 指定一个JAVA异常类型
<location></location> 指定错误页面具体路径
<error-page>
<error-code>404</error-code>
<location>/error404.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/exception.jsp</location>
</error-page>
<resource-ref></resource-ref> 定义JNDI取得项目可利用的资源工厂,有五个子元素:
<description></description> 资源说明
<rec-ref-name></rec-ref-name> 资源名称
<res-type></res-type> 资源种类
<res-auth></res-auth> 资源经由Application或Container来许可
<res-sharing-scope></res-sharing-scope> 资源是否可以共享,有Shareable和Unshareable两个值,默认为Shareable
//配置数据库连接池
<resource-ref>
<description>JNDI JDBC DataSource of shop</description>
<res-ref-name>jdbc/sample_db</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<jsp-config> 包括<taglib> 和<jsp-property-group> 两个子元素。
其中<taglib>元素在JSP 1.2时就已经存在;而<jsp-property-group>是JSP 2.0 新增的元素。
<taglib>用来设定JSP网页所用到的Tag Library路径,有两个子元素:
<taglib-uri>定义TLD文件的URI,在JSP网页中用taglib指令便可取得该URI的TLD文件
<taglib-location>指定TLD文件相对于web项目的存放位置
<jsp-property-group>元素主要有八个子元素,它们分别为:
1.<description>:设定的说明;
2.<display-name>:设定名称;
3.<url-pattern>:设定值所影响的范围,如:/CH2 或 /*.jsp;
4.<el-ignored>:若为true,表示不支持EL 语法;
5.<scripting-invalid>:若为true,表示不支持<% scripting %>语法;
6.<page-encoding>:设定JSP 网页的编码;
7.<include-prelude>:设置JSP 网页的抬头,扩展名为.jspf;
8.<include-coda>:设置JSP 网页的结尾,扩展名为.jspf。
<jsp-config>
<taglib>
<taglib-uri>Taglib</taglib-uri>
<taglib-location>/WEB-INF/tlds/MyTaglib.tld</taglib-location>
</taglib>
<jsp-property-group>
<description>group for JSP Configuration JSP example.</description>
<display-name>JSPConfiguration</display-name>
<url-pattern>/jsp/* </url-pattern>
<el-ignored>true</el-ignored>
<page-encoding>GB2312</page-encoding>
<scripting-invalid>true</scripting-invalid>
<include-prelude>/include/prelude.jspf</include-prelude>
<include-coda>/include/coda.jspf</include-coda>
</jsp-property-group>
</jsp-config>
# Servlet3.0:
* 好处:
* 支持注解配置。可以不需要web.xml了。
* 步骤:
1. 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml
2. 定义一个类,实现Servlet接口
3. 复写方法
4. 在类上使用@WebServlet注解,进行配置
* @WebServlet("/资源路径") 配置servlet,注意一定要有斜杠/,否则服务器error!!
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
String name() default "";//相当于<Servlet-name>
String[] value() default {};//代表urlPatterns()属性配置
String[] urlPatterns() default {};//相当于<url-pattern>
int loadOnStartup() default -1;//相当于<load-on-startup>
WebInitParam[] initParams() default {};
boolean asyncSupported() default false;
String smallIcon() default "";
String largeIcon() default "";
String description() default "";
String displayName() default "";
}
@WebFilter("/资源路径") 配置过滤器
@WebListener 配置监听器
@WebInitParam(属性设置) 配置初始化属性
@MultiparttConfig 将该servlet支持文件上传
更多免费技术资料可关注:annalin1203