• Servlet进阶


    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> 
    
  • 相关阅读:
    DRF(四)
    DRF----------(三)
    DRF--------(二)
    DRF(一)
    VUE(四)
    VUE(三)
    VUE(二)
    DRF 序列化组件 模型层中参数补充
    django中基于python3.6使用容联发送短信
    django-jwt token校验源码简析
  • 原文地址:https://www.cnblogs.com/lyang-a/p/12563032.html
Copyright © 2020-2023  润新知