zoukankan      html  css  js  c++  java
  • Servlet



    Servlet

    Servlet是一个java接口,为我们封装好了处理HTTP请求的各种方法,而从达到浏览器和服务器的交互的目的,主要是处理Http请求并返回响应
    Servlet是单例的,多用户访问创建多线程执行,即参数是栈内存独享,而成员变量有线程安全问题,需要加synchonized锁



    Tomcat

    Tomcat是一个Servlet容器,能运行.class文件,也是Jsp容器能处理动态资源,还是Web服务器也就是说能处理Hmlt,Css等,Tomcat启动时读取webapps下各站点web.xml文件里的信息,加载对应类,然后反射的实例化他们


    web.xml常用的xml元素

    <web-app> 
        <display-name></display-name> 定义了WEB应用的名字 
        <description></description> 声明WEB应用的描述信息 
        <context-param></context-param> 声明站点范围内的初始化参数
    
        <filter></filter> 声明一个过滤器
        <filter-mapping></filter-mapping> 与声明的filter关联来映射url
        
        <listener></listener> 声明一个listener
        
        <servlet></servlet> 声明一个servlet
        <servlet-mapping></servlet-mapping> 与声明的servlet关联来映射url
     
        <welcome-file-list></welcome-file-list> 指示服务器在收到引用一个目录名而不是文件名的URL时,使用哪个文件
        
        <error-page></error-page> 在返回特定HTTP状态代码时,或者特定类型的异常被抛出时,能够制定将要显示的页面
    </web-app>
    

    元素的配置

    <listener> 
        <listerner-class>listener.SessionListener</listener-class> 
    </listener>
    
    
    <context-param> 
        <param-name>ContextParameter</para-name> 
        <param-value>test</param-value> 
        <description>It is a test parameter.</description> 
    </context-param> 
    
    
    <servlet>
        <servlet-name>ServletConfigTest</servlet-name>
        <servlet-class>pratices.ServletConfigTest</servlet-class>  // 完整限定类名
        <init-param>
        	<param-name>name</param-name>
        	<param-value>Howl</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>ServletConfigTest</servlet-name>
        <url-pattern>/ServletConfigTest</url-pattern>
    </servlet-mapping>
    
    
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
    
    
    <error-page> 
    	<error-code>404</error-code> 
    	<location>/404.html</location> 
    </error-page> 
    
    
    <filter>
    	<filter-name>CharacterEncodingFilter</filter-name>
    	<filter-class>
    		org.springframework.web.filter.CharacterEncodingFilter
        </filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    其中映射url通配符,容器会减去站点的上下文路径才去匹配

    • 路径匹配:/ 开头,/* 结尾,即 /Howl/*
    • 扩展名匹配: *. 开头,即 *.html
    • 缺省匹配:/ ,即都没找到的就来这个,访问任何资源都是在访问Servlet,缺省就会找图片或网页,再找不到就404(小猫页面)

    其中

    • 在web站点启动时就加载创建实例及调用init()方法,可用于定时任务,eg:日志与备份
    • 正数一般是1表示加载实例化,不写或负数则第一次请求才实例化


    1. 使用流程


    1.1 创建测试类实现Servlet接口,其中有五个方法

    public class ServletTest implements Servlet {
    
    	public void destroy() {
    
    	}
    
    	public ServletConfig getServletConfig() {
    		return null;
    	}
    
    	public String getServletInfo() {
    		return null;
    	}
    
    	public void init(ServletConfig arg0) throws ServletException {
    
    	}
    
    	public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
    
    	}
    }
    

    1.2 显然service() 是我们处理请求的地方,所以我们在Service()方法里面写入

    arg1.getWriter().write("Hello World");  //字符流
    

    1.3 写完Service()是不够的,我们还需要让Tomcat知道怎么调用,何时调用该Servlet,即要在web.xml钟配置他

    配置web.xml

    <servlet>
        <!-- 配置一个名字 -->
    	<servlet-name>ServletTest</servlet-name>
        <!-- 对应的Servlet类 -->
    	<servlet-class>com.howl.controller.ServletTest</servlet-class>
    </servlet>
    <servlet-mapping>
        <!-- 需要映射的Servlet名字 -->
    	<servlet-name>ServletTest</servlet-name>
        <!-- 映射地址 -->
    	<url-pattern>/HelloWorld</url-pattern>
    </servlet-mapping>
    

    1.4 输入对应的映射地址访问



    2. Servlet生命周期

    • 加载:Tomcat第一次访问该Servlet时加载对应的Class并且创建该实例,属于单例,并发访问则创建多线程

    • 初始化:实例化后调用Servlet内部的init()函数初始化

    • 处理服务:浏览器访问该类时调用service()方法

    • 销毁:Tomcat关闭或者主动调用destory该类会被销毁

    • 卸载:等待GC,如果有需要再次使用这个Servlet,会重新调用init()方法进行初始化操作。



    3. HttpServlet

    我们开发时直接继承HttpServlet类,该类实现了Servlet的所有方法,并且增加了HTTP协议的处理方法,比Servlet更有优势,我么只需要重写doGet()和doPost()就可以了

    public class ServletTest extends HttpServlet {
    
        //处理Get请求
    	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    	}
    
        //处理Post请求
    	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    	}
    }
    


    4. ServletConfig

    每个HttpServlet都有这个对象,用来获取在web.xml里面的单独配置的初始化参数,在web.xml中更加灵活,修改数据不用改动代码 <init-param>

    public class servletAuth extends HttpServlet {
        ServletConfig servletConfig = this.getServletConfig();
        String value = servletConfig.getInitParameter("name");
    }
    


    5. ServletContext

    代表着当前web站点,所有servlet共享该资源,可以直接获取,这里this指代HttpServlet

    public class servletAuth extends HttpServlet {
        ServletContext servletContext = this.getServletContext();
        servletContext.getInitParameter("name");
    }
    

    可用于Servlet间通信、可获取站点信息/资源

    servletContext.setAttribute("name", "object"); //设置域属性,可设置对象
    servletContext.getResourceAsStream("address"); //因为代表本站点,所以从根目录开始即与WEB-INF同级
    

    以前类文件和资源文件同级可以直接访问,因为是JVM运行,而现在是Tomcat运行要遵守其目录规则
    src下的资源要去classes下访问
    与WEB-INF同级可直接访问



    6. HttpServletResponse响应

    Response向浏览器输出内容,Tomcat每收到一个Http请求就会为其创建request和response对象
    Servlet流用完之后,Servlet引擎会从response中取数据,将数据当成响应正文处理


    返回数据,Tomcat使用ISO 8859-1,不支持中文

    // 响应二进制
    response.setHeader("Content-Type", "text/html;charset=UTF-8");     // 设置网页请求头接收编码,
    response.getOutputStream().write("你好世界".getBytes("UTF-8"));    // Stream类传输二进制,中文要先变成二进制,不写编码默认用系统的gbk2312,因为调用的是java函数
    
    // 响应字符串
    response.setCharacterEncoding("UTF-8");    // 设置响应对象编码
    response.getWriter().write("你好世界")    // 此时调用Tomcat的writer会使用自带的ISO编码,需要在前设置
    
    // 简化设置,第一个代表了上面两个
    response.setContentType("text/html;charset=UTF-8")
    
    response.setHeader("Content-Type", "text/html;charset=UTF-8");
    response.setCharacterEncoding("UTF-8");
    

    下载

    File file = new File("/download/test.png");
    
    FileInputStream fileInputStream = new FileInputStream(file);
    ServletOutputStream servletOutputStream = response.getOutputStream();
    
    //设置响应头为下载,后面url编码为了文件名中文能适应
    response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
    
    int length = 0;
    byte[] bytes = new byte[1024];
    while( (length = fileInputStream.read(bytes)) != -1 ){
    	servletOutputStream.write(bytes, 0, length);
    }
    servletOutputStream.close();
    fileInputStream.close();
    

    重定向

    response.sendRedirect("/404.html");//本地发生的,地址栏发生了变化(302)
    

    压缩响应数据,这是浏览器解码

    response.setHeader("Content-Encoding","gzip")
    

    自动刷新+跳转

    response.setHeader("Refresh","3;url=index.html")
    

    禁止缓存

    response.setHeader("Cache-Control","no-cache")
    

    设置Cookie,Cookie后面会介绍

    void  addCookie(Cookie cookie)
    


    7. HttpServletRequest

    常用方法

    request.setCharacterEncoding("UTF-8"); // 设置request编码,针对POST表单,get在url上,不在request中不起作用
    request.getRemoteAddr()	// 获取发送请求的IP
    request.getRemotePort()   // 获取发送请求的端口
    request.getRequestURL()   // 获取请求的完整地址
    request.getMethod()      // 获取请求方法,应再补上.equalsIgnoreCase
    request.getHeader("请求头参数")   // 获取请求头
    request.getPathInfo()    // 获取 / 开头的额外信息,servlet之后,请求参数之前的数据
    request.getParameter("userId");		// 获取参数
    request.getParameterValues(String name)  // 获取复选框那种多数据的
    request.getAttribute()   // 在request对象域上存放数据,可用于转发
    request.getRequestDispatcher("/index.html").forward(request,response) // 实现转发,带上域数据,服务器发生的,本地地址栏没变化,而且 / 代表该站点根目录,即WEB-INF同级
    

    获取Cookie

    Request.getCookies();  //获得一个数组,里面包含所有对象
    Request.getSession();	//获取当前浏览器的Session
    

    get请求中文乱码,Tomcat使用了ISO

    byte[] bytes = request.getParameter("name").getBytes("ISO8858-1");
    String reallyValue = new String(bytes,"UTF-8");
    


    Http是无状态的,但Cookie会话技术就可以解决这个问题,当浏览器访问服务器时,服务器给浏览器颁发一个Cookie里面记录了SessionId,当浏览器再次访问该服务器时就会带上对应的Cookie,这样服务器就会认识你拉。一个网站可以有多个cookie,每个cookie就是键值对加上必要的信息 eg:过期时间等

    构造函数

    Cookie(java.lang.String name, java.lang.String value)
    

    常见方法

    String	getName()
    String  getValue()
    void    setValue(java.lang.String newValue)
    int	    getMaxAge()
    void setSecure(true)  // https才带上
    void    setMaxAge(int expiry)    // 负数本次会有有效,0代表删除,因无对应方法,本地也删除,默认-1
    String  getPath()
    void	setPath()    // 设置资源可以访问的地址,默认是整个页面可以使用,设置之后只有指定path才能使用
    String	getDomain()
    void    setDomain(java.lang.String pattern)  // 设置域
    

    常见操作

    // 设置response的编码
    response.setContentType("text/html;charset=UTF-8");
    
    // 实例化一个Cookie,注意导包是导入javax.servlet.http.Cookie,这个包在tomcat下
    // URLEncoder在java.net包下,单参构造函数已废弃,中文属于Unicode编码四字节,英文ASCII两字节,需要转码,与早期打印机相关
    Cookie cookie = new Cookie("name", URLEncoder.encode("我爱中国", "UTF-8"));
    
    // 设置过期时间,单位为秒,-1有效到浏览器关闭
    cookie.setMaxAge(1000);
    
    // 设置额外二级域
    cookie.setDomain("a.com");
    
    // 响应头添加set-cookie
    response.addCookie(cookie);
    
    // 设置路径,一般cookie整个站点都可以用,但也可以只限制该地址可用
    //cookie.setPath("/ServletConfigTest");
    
    /*************************************/
    
    
    // 返回包含所有对象的数组
    Cookie[] cookies = request.getCookies();
    
    for(Cookie cookieLoop : cookies){
    	String name = cookieLoop.getName();
    	String value = URLDecoder.decode(cookieLoop.getValue(), "UTF-8");
    	System.out.println(name + "----" + value);
    }
    


    9. HttpSession

    Session是记录浏览器状态的机制,解决http无状态的另一种方式,Session能存放对象,并且Session是存在服务器端的,cookie只存字符串,所以Servlet能共享属于某个浏览器的Session

    当浏览器访问服务器的Servlet,并且使用了response.getSession()才会自动给该浏览器颁发一个带JESSIONID的Cookie,JESSIONID就是唯一标识浏览器Session的id,该cookie默认生命周期为当前浏览器,所以关闭了浏览器Session就会失效

    Session的有效期是访问一次就重置,而cookie的是累计,Session存放于服务器内存,超时会自动删除,默认超时为30min,一般存用户级别数据,即当前会话有效的

    Session的活化和钝化下篇Listener有提及
    钝化:服务器关闭时还有正常的Session存在并未超时,就会以文件的形式存储起来

    活化:服务器再次开启时,恢复存储起来的Session对象

    实现该功能的对象需要实现Serializable接口,涉及了序列化


    方法

    long getCreationTime()		//获取Session被创建时间
    String getId() 				//获取Session的id
    long getLastAccessedTime() 			//返回Session最后活跃的时间
    ServletContext getServletContext() 			//获取ServletContext站点对象
    void setMaxInactiveInterval(int var1) 	//设置Session超时时间
    int getMaxInactiveInterval() 	//获取Session超时时间
    Object getAttribute(String var1) 	//获取Session属性,代替了getValue
    Enumeration getAttributeNames() 		//获取Session所有的属性名
    void setAttribute(String var1, Object var2) 	//设置Session属性,可存对象,在于域中
    void removeAttribute(String var1) 		//移除Session属性
    void invalidate() 		//销毁该Session
    boolean isNew() 		//该Session是否为新的
    

    常见操作

    HttpSession httpSession = request.getSession();
    httpSession.setAttribute("Session", "Howl");
    		
    System.out.println(request.getSession().getAttribute("Session"));
    
    //当浏览器禁止了Cookie的时候,encodeURL的另一个功能,带上JESSIONID访问即URL地址重写,会自动判断浏览器是是否支持的
    //通过在其中包含会话ID对指定的URL进行编码,或者,如果不需要编码,则返回不变的URL
    //之后服务器端会自动获取该ID
    response.sendRedirect(response.encodeURL(url));
    

    验证码

    //getCode()获取验证码存入Session
    request.getSession.setAttribute("code", getCode());
    
    //然后和requset获取的对比
    request.getParameter("code") == request.getSession.getAttribute("code")
    


    10. Servlet访问流程,网络图来自java3y




    API参考 oracle官网文档

    Web.xml参考 思否







  • 相关阅读:
    Linux Shell 下的输出重定向
    解决 Scrapy-Redis 空跑问题,链接跑完后自动关闭爬虫
    数据清洗基本概念
    前端常见的跨域请求解决方案
    Pandas模块:表计算与数据分析
    Matplotlib模块:绘图和可视化
    numpy如何使用
    Gerapy 使用详解
    MySQL常见数据库引擎及比较
    基于scrapy-redis组件的分布式爬虫
  • 原文地址:https://www.cnblogs.com/Howlet/p/12038728.html
Copyright © 2011-2022 走看看