zoukankan      html  css  js  c++  java
  • Java Web之Servlet入门篇(二)

    简介

    我也苦恼自己的博客书写格式很烂,标题+代码格式。因为每天课程量比较大,没时间花在书写格式上面,如看不习惯请多多见谅。我坚持每天书写博客主要是养成一个习惯,并一直延续下去,虽然内容很空泛,目的也算达到了,总之为了巩固知识点,坚持不懈

    Servlet快速入门

    0. Servlet简介

    什么是servlet
    	它其实就是java类,运行在服务器端,主要用途就是处理用户发送HTTP请求,并且作出响应
    学习两个包:javax.servlet/javax.servlet.http
    
    Servlet容器就是Tomcat,也就是Web服务器

    1. 手工部署web应用

    myapp
    	|--WEB-INF:
    		|--classes(Servlet编译之后代码放到这个包下)
    		|--lib
    		|--web.xml
    	|--css
    	|--html
    	|--img
    	|--js
    
    1.手动建立Servlet类
    package com.itheima.servlet;
    import javax.servlet.*;
    import java.io.*;
    
    public class HelloWorldServlet extends GenericServlet {
    	public void service(ServletRequest req,ServletResponse res)throws ServletException,IOException {
    		res.getWriter().write("Hello World");
    	}
    }
    
    2.编译
    	set classpath=%classapth%;C:apache-tomcat-6.0.37libservlet-api.jar
    	javac  -d . HelloWorldServlet.java
    
    3.配置文件
    	 在web.xml中添加servlet的配置
    	 <servlet>
    		<!--自己配的一个名称-->
    		<servlet-name>hello</servlet-name>
    		<!--一定是servlet类所对应全路径-->
    		<servlet-class>com.itheima.servlet.HelloWorldServlet</servlet-class>
    	 </servlet>
    	 <servlet-mapping>
    		<!--自己配的一个名称-->
    		<servlet-name>hello</servlet-name>
    		<!--映射的一个URL,一定是/开头(具体路径)-->
    		<url-pattern>/cgx/aj</url-pattern>		//配置Mapping URL路径名前面一定要加斜杠/,斜杠代表当前应用目录
    	 </servlet-mapping>
    

    2. MyEclipse项目注意事项

    注意:若项目名修改了,对应的这个project facet路径也要修改一致
    	(右键Properties-->MyEclipse-->[Project Facets]-->Web-->Context Root)
    替换servlet模版
    	*wizard*.jar-->template/Servlet.java(模板文件)

    3. doGet/doPost分析

    当用户发起请求起, 始终调用的是的是service()方法,而这个方法内部会进行判断
    并决定是调用doGet(),还是doPost()
    而咱们自己定义的Servlet又重写了doGet(),doPost()
    
    结论: 不要自己重写service()方法,因为父类有这个方法,一般重写doGet/doPost方法
    扩展:采用了模版方法设计模式
    public class A {
    	service() {
    		doGet();
    		doPost();
    	}
    	public abstract void doGet();
    	public abstract void doPost();
    }
    public class B extends A {
    	public void doGet() {
    		...
    	}
    	public void doPost() {
    		...
    	}
    }
    @Test
    public void test() {
    	A a = new B();
    	a.service();
    }

    4. Servlet生命周期

    当用户第一次访问的时候实例化/初始化/提供服务
    第二次访问只提供对外服务
    
    1. 在默认情况下,Servlet生命周期执行过程如下:
    	在用户第一次请求时:
    		1.实例化:构造方法1次
    		2.初始化:(init):1次
    		3.服务:(service),以后每次请求,都会直接执行service()  :N次
    		4.销毁:当服务器停止或应用被移除,此时销毁destory()方法执行: 1次
    		
    2. 改写生命周期
    	是通过<load-on-startup>来实现的		取值:  整数(1开始  越小优先级越高)
    		
    	改写之后
    		服务器启动时,对应的Servlet就会执行生命周期(实例化,初始化)以后每次用户执行时,走service()方法
    	优点:当用户每一次请求时,速度会变快
    	缺 点:如果load-on-startup配置太多,Tomcat启动速度会变慢

    5. web.xml中Servlet具体详细配置

    1.可以配多个映射地址
    	 <servlet-mapping>
    		<servlet-name>myfirst</servlet-name>
    		<url-pattern>/servlet/MyFirstServletDemo1</url-pattern>
    	 </servlet-mapping>
    	 <servlet-mapping>
    		<servlet-name>myfirst</servlet-name>
    		<url-pattern>/aj</url-pattern>
    	 </servlet-mapping>			
    		
    2.映射还可以使用通配符*
    	使用方式:
    	a、*.扩展名:必须以*开头,以某个扩展名结尾。比如*.do
    	b、/action/*:必须以/开头,*在末尾。比如/action/*
    	原则:b优先级比a高。如果都是a或都是b,从前往后匹配。
        完全匹配的映射优先级最高
    	不要这写成/*.action
    3.总结规律:
    	1.能精确匹配的用精确匹配
    	2./*优先级高于*.扩展名
    		
    还可以配置一个缺省的Servlet
    	1.写法:  /
    		<servlet-mapping>
    			<servlet-name>myfirst</servlet-name>
    			<url-pattern>/</url-pattern>
    		 </servlet-mapping>
    	2.当请求静态资源时,如果找不到,则执行缺省的Servlet
    		if("1.jpg"找到了){
    			显示图片
    		}else{
    			没有找到 显示404
    		}
    	3.这个缺省的Servlet一般不配置,为什么?
    		因为在Tomcat的web.xml中有

    6. 线程安全

    说明servlet不是线程安全的,而且它设计目标就是采用多线程来处理用户请求
    
    线程安全问题解决方法:
    	1.synchronized:线程同步
    	2.用单线程:就是实现SingleThreadModel接口
    
    	总结:这两种方法都不行,违背了设计意图!!!
    
    	最终解决办法:
    		程序员自己注意,不要定义成员变量,尽量用局部变量
    		合理决定在Servlet中定义的变量的作用域

     

    Servlet之ServletConfig入门

    针对某个Servlet的配置信息,一开始就需要初始化的参数

    <servlet><!--对ServletDemo3这个Servlet进行配置-->
    	<servlet-name>ServletDemo3</servlet-name>
    	<servlet-class>com.itheima.servlet.ServletDemo3</servlet-class>
    	<init-param> <!--表示aaa的值是bbb -->
    		<param-name>aaa</param-name>
    		<param-value>bbb</param-value>
    	</init-param>
    </servlet>
         
    //获取 Servlet 的配置信息,并打印
    public   void  doGet(HttpServletRequest request, HttpServletResponse response)throws  ServletException, IOException {
    	ServletConfig sc = getServletConfig();
    	String value = sc.getInitParameter( "encoding" );
    	if (value== null )
    		value =  "GBK" ;
    	response.getWriter().write(value);
    	//在控制台打印该 Servlet 所有的参数及取值
    	Enumeration  e = sc.getInitParameterNames(); //所有参数名
    	while (e.hasMoreElements()){
    		String paramName = (String)e.nextElement();
    		System. out .println(paramName+ "=" +sc.getInitParameter(paramName));
    	}     
    }

    Servlet之ServletContext入门

    1. 什么是ServletContext及作用

    它是服务器产生的一个对象,它用于实现各个Servlet之间信息共享,用于获取全局初始化参数
    1). 它是运行在web容器中,每个web应用程序都会有一个自己唯一的ServletContext对象
    2). 由web容器加载应用时,就创建好了
    3). 它跟web应用程序同生命周期,随着web应用启动而存在,随着应用的卸载而消失
    作用: 
    1). 作为一个全局的域对象来用(四大域作用范围最广),可以实现应用范围的数据共享,用于获取全局初始化参数
    	实现原理:
    		就是在全局范围内维护一个Map集合
    		setAttribute(key,Value)
    		Object obj = getAttribute(key);
    		removeAttribute(key);
    2). 获取全局初始化参数
    	getInitParameter("")
    	getInitParameterNames();

    2. 实现Servlet的转发

    1. 什么是转发?
    	A-->B--C
    	重定向
    		A----B(没有资源)
    		A----C
    	实现步骤:
    		1.得到转发器  路径一定是绝对路径
    		RequestDispatcher rd = getServletContext().getRequestDispatcher("/servlet/ServletContextDemo1");
    		2.转发
    		rd.forward(request, response);
    2.实现方式
    	//放入iphone6
    	sc.setAttribute("gift", "iphone6");
    	//转发,采用ServletContext实现转发时,不能用相对路径,只能用/开头代表一个绝对路径
    	RequestDispatcher rd = sc.getRequestDispatcher("/servlet/ServletContextDemo5");//转发器
    	
    	//rd.forward(request, response);//转发
    	
    	//在实现包含时,它会将目标对象的响应正文包含进来,如果设置有响应头也不起作用
    	  rd.include(request, response);//包含

    3. 转发与重定向区别

    转发的特点:
    	1). 地址栏不变
    	2). 说明客户端向服务器发送只有一次请求
    	3). 放在reques域中的值可以共享
    重定向
    	1). 地址栏改变
    	2). 客户端发送了2次请求
    	3). 放在request 域中的数据不能共享

    4. 读取资源文件3种方式

    //1. 根据所学的由相对路径得到绝对路径getRealPath,只适合web项目
    //String absolutePath = getServletContext().getRealPath("/WEB-INF/classes/cfg2.properties");
    //String absolutePath = getServletContext().getRealPath("/WEB-INF/classes/com/itheima/day07Servlet/cfg2.properties");
    String absolutePath = getServletContext().getRealPath("/WEB-INF/cfg3.properties");
    Properties prop = new Properties();	//得到一个Properties对象
    prop.load(new FileInputStream(absolutePath)); //加载这个文件到内存
    response.getOutputStream().write(prop.getProperty("p").getBytes());
    
    
    //2. ResourceBundle 资源文件加载器
    //适用范围: Web项目,java项目都可以,只能加载src下资源 
    //ResourceBundle rb = ResourceBundle.getBundle("cfg2"); //基名:就是不带扩展名
    ResourceBundle rb = ResourceBundle.getBundle("com.itheima.day07Servlet.cfg"); //基名:就是不带扩展名
    		
    String value = rb.getString("p");
    response.getOutputStream().write(value.getBytes());
    
    
    3. 类加载器ClassLoader
    ClassLoader cl = this.getClass().getClassLoader();
    //InputStream is = cl.getResourceAsStream("cfg2.properties");
    InputStream is = cl.getResourceAsStream("com/itheima/day07Servlet/cfg.properties");
    //InputStream is = cl.getResourceAsStream("../cfg3.properties"); //WEB-INF下
    		
    Properties prop = new Properties();
    prop.load(is);
    response.getOutputStream().write(prop.getProperty("p").getBytes());
    
  • 相关阅读:
    函数防抖和节流
    浅析事件循环(Event Loop)
    Flutter的盒子约束
    如何在Flutter中使用flutter_markdown
    关于Salesforce的15位ID与18位ID
    Salesforce的Rollback与SavePoint
    Salesforce的TestClass
    Salesforce的SplashPage(启动页)-一天一个标准功能系列
    Salesforce用Apex判断Role Hierarchy的简单代码示例
    Salesforce不登录调用Webservice的方法
  • 原文地址:https://www.cnblogs.com/codingpark/p/4231112.html
Copyright © 2011-2022 走看看