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());
原文地址:https://www.cnblogs.com/codingpark/p/4231112.html