ServletConfig
Servlet初始化配置信息.初始化参数.
ServletConfig的使用:
使用web.xml配置
<servlet>
<servlet-name>config</servlet-name>
<servlet-class>com.sxt.controller.ServletConfigDemo</servlet-class>
<init-param>
<param-name>initName1</param-name>
<param-value>initValue1</param-value>
</init-param>
<init-param>
<param-name>initName2</param-name>
<param-value>initValue2</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>config</servlet-name>
<url-pattern>/config.do</url-pattern>
</servlet-mapping>
使用注解:
package com.sxt.controller;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @ClassName: ServletConfigDemo
* @Description: ServletConfig 示例
* @author: Mr.T
* @date: 2019年11月5日 上午9:23:14
*/
@WebServlet(urlPatterns = {"/config.do"}, initParams = {@WebInitParam(name="initName1",value = "initValue1"),@WebInitParam(name="initName2",value = "initValue2")} )
public class ServletConfigDemo extends HttpServlet{
private static final long serialVersionUID = -2982195327881997238L;
/**
* 获取ServletConfig
*/
@Override
public void init(ServletConfig config) throws ServletException {
Enumeration<String> initNames = config.getInitParameterNames();
while(initNames.hasMoreElements()) {
String name = initNames.nextElement();
System.out.println(name +" "+config.getInitParameter(name));
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
Servlet监听器 Listener
什么是监听器
监听:监视、监察的器具。监察事物状态信息的变化,根据变化做出相应的反应。在Javaweb中,监听器主要监听程序的属性变化(主要是指Servlet的大三作用域),又分为:
属性的变化.
生命周期的变化.
如何使用监听器
监听器分为2类:监听属性,监听生命周期的。根据自己需要监听的类型实现相应的接口,由于监听的对象是:三大作用域,而监听的类型分2种,所以接口:6个。
属性监听接口
ServletContextAttributeListener : ServletContext 属性监听器
HttpSessionAttributeListener : session 属性监听器
ServletRequestAttributeListener : request 属性监听器
package com.sxt.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
/**
* @ClassName: MyListener
* @Description:
* 1.创建一个类
* 2.实现接口
* @author: Mr.T
* @date: 2019年11月5日 上午9:51:07
*/
public class MyListener implements ServletRequestAttributeListener,ServletContextAttributeListener,HttpSessionAttributeListener {
/**
* 新增属性时触发
*/
@Override
public void attributeAdded(ServletRequestAttributeEvent srae) {
System.out.println("========新增了属性=======");
}
/**
* 删除属性时触发
*/
@Override
public void attributeRemoved(ServletRequestAttributeEvent srae) {
System.out.println("========删除了属性=======");
}
/**
* 属性发生修改时触发
*/
@Override
public void attributeReplaced(ServletRequestAttributeEvent srae) {
System.out.println("=====修改了属性========");
String name = srae.getName();
System.out.println("被修改的属性名:"+ name);
// 获取当前 Request对象
ServletRequest servletRequest = srae.getServletRequest();
// 获取当前ServletContext
ServletContext servletContext = srae.getServletContext();
// 被修改的属性值 老值
Object value = srae.getValue();
System.out.println(value);
Object v = servletRequest.getAttribute(name);
System.out.println(v);
System.out.println("source:"+srae.getSource());
}
/**
* 当ServletContext 中新增属性时触发
*/
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
}
/**
* 当ServletContext 中删除属性时触发
*/
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
}
/**
* 当ServletContext 中修改属性时触发
*/
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
}
/**
* 当session 新增属性时触发
*/
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
}
/**
* 当session 删除属性时触发
*/
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
}
/**
* 当session 修改属性时触发
*/
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
}
}
生命周期监听接口
ServletRequestListener request 生命周期监听接口
ServletContextListener ServletContext生命周期监听接口
HttpSessionListener session生命周期监听接口
package com.sxt.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class MyListener2 implements ServletRequestListener, ServletContextListener,HttpSessionListener {
/**
* ServletContext 初始化 会在项目启动完成前初始化. 只会执行一次
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("==========初始化ServletContext 容器 =========");
/**
*可以在项目一启动时,将整个项目都需要的数据,进行数据加载.
* 例如: 加载properties配置文件
* 例如: 初始化连接池
* 例如: 全局共用的数据(例如: IP 端口之类)
* 例如: 定时任务
*/
}
/**
* 会在项目停止前执行 也只会执行一次
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("==========销毁ServletContext 容器 =========");
/**
* 将内存的中的数据 在由于服务器停止后,内存释放,数据丢失。所以可以在停止前,将内存的数据进行持久化
*/
}
/**
* 当session创建时触发
*/
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("=========session创建==========");
}
/**
* 当session销毁时触发
*/
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("=========session销毁===========");
}
/**
* 当request 对象创建时 触发
*/
@Override
public void requestDestroyed(ServletRequestEvent sre) {
}
/**
* 当request 对象销毁时 触发
*/
@Override
public void requestInitialized(ServletRequestEvent sre) {
}
}
监听器案例:
统计网站的访问量.并且当服务器关闭时,将当前访问量进行持久化,当服务器再次启动,将之前保存的数据读入内存中.
-
使用Filter进行计数累加
-
使用ServletContext 作为容器进行存储
-
监听ServletContext的生命周期,当启动时将文件中的数据读取内存中,当项目停止时,将ServletContext的数据写到文件中.
package com.sxt.listener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ApplciationListener implements ServletContextListener {
/**
* 当项目启动时触发
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
// 获取ServletContext 用于存储数据
ServletContext context = sce.getServletContext();
// 指定的文件的物理路径
String realPath = context.getRealPath("count.txt");
FileReader reader = null;
BufferedReader br = null;
try {
reader = new FileReader(realPath);
br = new BufferedReader(reader);
//读取文件中的数据
String readLine = br.readLine();
//将数据放入 ServletContext
context.setAttribute("count", Integer.parseInt(readLine.trim()));
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
br.close();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 当项目停止时触发
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
/**
* 当项目停止时 将ServletContext中访问次数 持久化到文件中
*/
// 获取ServletContext 从中取数据
ServletContext context = sce.getServletContext();
// 指定的文件的物理路径
String realPath = context.getRealPath("count.txt");
FileWriter witer = null;
try {
witer = new FileWriter(realPath);
// 获取数量
Object count = context.getAttribute("count");
witer.write(count.toString());
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
witer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package com.sxt.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* @ClassName: VisitFilter
* @Description: 访问过滤器
* @author: Mr.T
* @date: 2019年11月5日 上午11:28:18
*/
public class VisitFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//获取ServletContext 容器
ServletContext servletContext = request.getServletContext();
//获取当前count数量
int count = Integer.parseInt(servletContext.getAttribute("count").toString());
//将数量自增 然后覆盖
servletContext.setAttribute("count", ++count);
//请求放过
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>07listener2</display-name>
<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>
<listener>
<listener-class>com.sxt.listener.ApplciationListener</listener-class>
</listener>
<filter>
<filter-name>visitFilter</filter-name>
<filter-class>com.sxt.filter.VisitFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>visitFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
</web-app>
Servlet 3.0 注解
从Servlet 3.0开始,为简化servlet的web开发,内置了相关一些注解.主要用于简化配置.
Servlet : @WebServlet : name : servlet的名称
String[] value servlet的映射地址(访问地址) 返回urlPatterns
String[] urlPatterns servlet的映射地址(访问地址)
loadOnStartup : servlet 初始化时机
initParams : servlet 初始化参数
|--- WebInitParam : 具体的初始化参数
name : name 表示参数名称
value : 参数的值
Filter : @WebFilter :
name : filter名称
String[] value filter拦截的地址 返回urlPatterns
String[] urlPatterns filter拦截的地址(需要被过滤的地址)
initParams : filter初始化参数
Listener : @WebListener : 只是为了标识该类是一个listener
文件上传:@MultipartConfig : 用于处理二进制文件数据流的请求
注解版Servlet
package com.sxt.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @ClassName: TestServlet
* @Description: 使用注解的形式代替 xml servlet配置
* @author: Mr.T
* @date: 2019年11月5日 下午2:35:48
*/
@WebServlet(name="servletName",urlPatterns = {"/test.do"},initParams = {
@WebInitParam(name="name1",value = "value1"),
@WebInitParam(name="name2",value = "value2")
})
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = -4744875954442714537L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("注解版Servlet");
}
}
注解版Filter
package com.sxt.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
/**
* @ClassName: TestFilter
* @Description: 注解版的Filter
* @author: Mr.T
* @date: 2019年11月5日 下午2:40:44
*/
@WebFilter(filterName="filterName",urlPatterns = {"*.do"})
public class TestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("========注解版Filter=======");
}
@Override
public void destroy() {
}
}
注解版Listener
package com.sxt.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* @ClassName: TestListener
* @Description: 注解版Listener
* @author: Mr.T
* @date: 2019年11月5日 下午2:41:37
*/
@WebListener
public class TestListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
文件上传: @MultipartConfig : 用于处理二进制文件数据流的请求
文件上传
文件上传注解:@MultipartConfig
使用MultipartConfig注解,标识该类支持文件上传。
1.创建Servlet,一定要使用@MultipartConfig修饰
2.创建JSP,注意,form表单一定要使用post方法,且enctype="multipart/form-data"
3.若是文本数据,可以直接使用getParameter(name值)获取普通文本
4.若是文件数据,则使用getPart(name)获取
5.若是保存文件,直接使用part.write(物理地址)
注意:
在文件上传中,是没有办法直接获取文件的原始名称的。只能从其请求头中获取。
并且还需要对请求头进行特殊处理。
当表单使用:enctype="multipart/form-data"时,此时HTTP传输数据给服务器,是将数据进行分割.使用-------------线对各块数据进行分割.在使用Servlet获取表单数据时,分为2种情况,在servlet3.0以后,普通的文本数据,依然可以按照之前的方式获取.request.getParameter(name),但是获取二进制流数据时,使用request.getPart()
package com.sxt.controller;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@WebServlet("/upload.do")
@MultipartConfig
public class FileUploadServlet extends HttpServlet{
private static final long serialVersionUID = 679386554411019554L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("======FileUploadServlet=====");
String name = req.getParameter("name");
String pwd = req.getParameter("pwd");
System.out.println(name+"======"+pwd);
System.out.println(req.getParameter("fileName"));
// 根据名称 获取对应part的二进制数据
Part part = req.getPart("fileName");
//part.getName() : 提交的数据的name值
//part.getContentType : 文件类型 form表单的普通数据是 null 文件则是具体的文件信息
//part.getSize() : 文件的大小 字节
//根据请求头信息,获取文件名称
String header = "Content-Disposition";
String headerValue = part.getHeader(header);
//当存在多文件上传
Collection<Part> parts = req.getParts();
// 图片保存的地址 : 物理路径
// 图片URL地址 : 网络资源路径
for (Part part2 : parts) {
System.out.println(part2.getName());
String fileName = part2.getName();
if("fileName".equals(fileName)) {
//fileName : 保存的文件的物理路径
part2.write("d://1.jpg");
}
}
}
}
文件上传案例:
package com.sxt.controller;
import java.io.File;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@WebServlet("/upload2.do")
@MultipartConfig
public class FileUploadServlet2 extends HttpServlet{
private static final long serialVersionUID = -1168320775428499846L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
String pwd = req.getParameter("pwd");
// 获取文件
Part part = req.getPart("img");
// 将图片保存
// 1.使用IO流 自己定义
// 2.part.write(fileName); 将文件保存到磁盘 : fileName 物理路径
//img 文件夹的物理路径
String realPath = req.getServletContext().getRealPath("img");
// 创建文件名称
String headerName = "Content-Disposition";
String headerValue = part.getHeader(headerName);
System.out.println(headerValue);
// 获取文件的真实名称
String fileRealName = getFileRealName(headerValue);
System.out.println(fileRealName);
// filePath 只是 物理路径
String filePath = realPath + File.separator + fileRealName;
// 网络路径
// http://127.0.0.1:8080/07upload/img/2.jpg // 给HTML 标签使用
/* 注意: 一般网络路径一定要存储在数据库: 存储相对路径
一般而言获取文件的原名称意义不大,文件下载.
一般保存文件的物理路径时,考虑文件覆盖的问题,随机生成唯一的文件名称,用于保存,规避文件名称重复覆盖问题 */
part.write(filePath);
}
/**
* @Title: getFileRealName
* @author: Mr.T
* @date: 2019年11月5日 下午3:56:29
* @Description: 获取文件的真实名称
* @param header
* @return
* @return: String
*/
private String getFileRealName(String header) {
// form-data; name="img"; filename="1.jpg"
int index = header.lastIndexOf("filename=");
// 名字的第一个引号
int beginIndex = header.indexOf(""", index);
int endIndex = header.lastIndexOf(""");
return header.substring(beginIndex+1, endIndex);
}
}
异常页面配置
<error-page>
<!-- HTTP 错误码 -->
<error-code>404</error-code>
<!-- 发生该错误码时 内部转发的页面 -->
<location>/404.jsp</location>
</error-page>
<error-page>
<!-- HTTP 错误码 -->
<error-code>500</error-code>
<!-- 发生该错误码时 内部转发的页面 -->
<location>/500.jsp</location>
</error-page>