Select进阶

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) {
		
	}
}

监听器案例:

统计网站的访问量.并且当服务器关闭时,将当前访问量进行持久化,当服务器再次启动,将之前保存的数据读入内存中.

  1. 使用Filter进行计数累加

  2. 使用ServletContext 作为容器进行存储

  3. 监听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> 

猜你喜欢

转载自www.cnblogs.com/lyang-a/p/12563032.html