1、准备工作
1.1、为了模拟服务器端程序,且可以同时存在多个类似程序。故提供接口,接口中有3个方法,我们人为约定三个方法的调用顺序。
public interface MyServlet{
public void init(); //1、初始化
public void service(); //2、执行
puvlic void destory(); //3、销毁
}
1.2、再为接口编写实现类(MyServlet.java)
public class HelloServlet implements MyServlet{
@override
pubic void init(){
System.out.println("1.初始化");
}
@override
public void service(){
System.out.println("2.执行中...");
}
@override
public void destory(){
System.out.println("3.销毁");
}
}
1.3、测试,创建实现类实例对象
public class TestApp{
@Test
public void demo01(){
//手动创建执行
MyServlet myservlet = new HelloMyServlet();
myservlet.init();
myservlet.service();
myservlet.destory();
}
}
2、反射执行
测试程序我们直接new HelloServlet,这种编程方式我们称为硬编码,即代码是写死的。为了后期程序的可扩展,开发中通常使用实现类的全限定类名(cn.klh.e_web.HelloServlet),通过反射加字符串指定的类,并通过反射创建实例。
@Test
public void demo02() throws Exception{
/*反射创建执行
*1)Class.forName 返回指定接口或类的Class对象
*2)newInstance() 通过Class对象创建类的实例对象,相当于 new Xxx();
*/
String servletClass = "cn.klh.e_web.HelloMyServlet";
//3)获得字符串实现类实例
Class clazz = Class.foeName(servletClass);
MyServlet myServlet = (MyServlet) clazz.newInstance();
//4)、执行对象的方法
myServlet.init();
myServlet.service();
myServlet.destory();
}
3、解析xml
使用反射我们已经可以创建对象的实例,此时我们使用的全限定类名,在程序中仍写死了,我们将器配置到哦xml文档中。
xml文档内容:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5">
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>cn.klh.e_web.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>HelloServlet2</servlet-name>
<servlet-class>cn.klh.e_web.HelloServlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet2</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
</web-app>
解析实现:
@Test
public void demo03() throws Exception{
/*读取xml配置文件,获得<servlet-class>配置的内容,取代固定字符串*/
//1.创建解析器对象
SAXReader saxReader = new SAXReader();
//2.使用解析器加载web.xml文件得到document对象
Document document = saxReader.read(new file("src/cn/klh/e_web/web.xml"));
//3.获取根元素节点
Element rootElement = document.getRootElement();
//4.根据元素名称获取子元素节点
Element servletElement = rootElement.element("servlet");
//5.根据元素名称获取servlet-class的文本节点
String servletClass = servletElement.element("servlet-class");
//System.out.println(servletClass);
//6.通过类全名获取字节码文件
Class clazz = Class.forName(servletClass);
//7.创建实例对象
MyServlet1 my = (MyServlet1) clazz.newInstance();
//8.调用实例对象里面的方法
my.init();
my.service();
my.destory();
}
4、模拟浏览器路径
我们已经解析xml,不过我们获得的内容是固定的。我们希望如果用户访问的路径是/hello,将执行cn.klh.e_web.HelloServlet程序,如果访问的是/hello2,将执行cn.klh.e_web.HelloServle2t程序。
在执行测试前(@Before),解析xml文件,将解析的结果存放在Map中,map中的数据的格式为:路径=实现类。
解析xml思路:先解析<servlet>,将结果存放map,name=class,然后再解析<servlet-mapping> ,通过name获得class,再将url=class存放到map,最后将name=class移除。
//最终存放 key=请求路径,value=实现类
private Map<String,String> data = new HashMap<String,String>();
@Before
public void demo04Before() throws Exception{
//在执行前执行,解析xml,并将结果存放到Map<路径,实现类>中
//1.创建解析器对象
SAXReader saxReader = new SAXReader();
//2.使用解析器加载web.xml文件得到document对象
Document document = saxReader.read(new file("src/cn/klh/e_web/web.xml"));
//3.获取根元素节点
Element rootElement = document.getRootElement();
//4、获得所有的子元素<servlet>、<servlet-mapping>等
List<Element> allChildElement = rootElement.element();
//5、遍历所有
//1)解析到<servlet>,将其子标签<servlet-name>、<servlet-class>存放到Map中
//2)解析到<servlet-mapping>,获得子标签<servlet-name>、<url-pattern>,从map中获得1的内容,组合成url=class键值对
for(Element childElement : allChildElement){
//5.1获得元素名
String eleName = chileElement.getName();
//5.2如果是servlet,将解析内容存放到Map中
if("servlet".equals(eleName)){
String servletName = childElement.elementText("servlet-name");
String servletClass= childElement.elementText("servlet-class");
data.put(servletName,servletClass);
}
//5.3如果是servlet-mapping,获得之前内容,组成成key=url,value=class,并添加到到Map中
if("servlet-mapping".equals(eleName)){
String servletName = childElement.elementText("servlet-name");
String urlPattern= childElement.elementText("url-pattern");
//获得<servlet-name>之前存放在Map中<servlet-class>值
String servletClass = data.get(servletName);
//存放新的内容 url = class
data.put(urlPattern,servletClass);
//将之前存储的数据删除
data.remove(servletName);
}
//打印信息
System.uot.println(data);
}
}
模拟浏览器请求路径,通过url从map获得class,并使用反射执行实现类
@Test
public void demo04() throws Exception{
//1模拟路径
String url = "/hello";
//String url = "/hello2";
//2通过路径获得对应的实现类
String servletClass = data.get(url);
//3获得字符串实现类实例
Class clazz = Class.forMame(servletClass);
MyServlet myServlet = (MyServlet) clazz.newInstance();
//4执行对象的方法
myServlet.init();
myServlet.service();
myServlet.destory();
}