一、需求分析
开发Minicat V4.0,在已有Minicat基础上进⼀步扩展,模拟出webapps部署效果 磁盘上放置⼀个webapps⽬录,webapps中可以有多个项⽬,⽐如demo1,demo2,demo3… 具体的项⽬⽐如demo1中有serlvet(也即为:servlet是属于具体某⼀个项⽬的servlet),这样的话在 Minicat初始化配置加载,以及根据请求url查找对应serlvet时都需要进⼀步处理。
1.有一个文件夹作为部署的目录,不管是否是在Minicat文件夹下面。
2.webapps下面可以放置项目,一个项目一个servlet.class文件、一个web.xml配置文件。也就是说不要将项目放到Minicat里面,需要自己新建一个项目并编译。
二、实现分析
已完成功能分析
1.使用socket实现接收请求,处理请求的功能。
2.解析接受到的请求,将其封装为request和response对象,分别持有inputstream和ouputstream。
3.通过线程处理请求,根据请求地址去解析,找到相应的servlet对象。
4.在Minicat初始化的时候,读取resource中的web.xml文件,解析其中标签,存储到Map中,等待请求时使用。
待完成功能分析
1.将servlet相关代码脱离出Minicat,打包成一个jar包,供各个项目使用。
2.修改Minicat代码,使之去检查webapps目录下检查其下的文件中是否存在servlet项目。
3.解析class文件。
三、实现
1.获取webapps的路径,检查是否存在,然后遍历其中的文件夹。
URI webapps = this.getClass().getClassLoader().getResource("webapps").toURI();
File file = new File(webapps);
if(file.exists()){
//判断是否是目录,然后进行遍历
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File file2 : files) {
//解析相应的servlet文件夹下面的web.xml
if (file2.isDirectory()) {
doLoadServlet(file2);
}
}
}
}else{
System.out.println("webapps文件夹不存在!");
}
2.解析文件夹中的web.xml,在其中我们使用了自定义的类加载器来加载本文件夹下的class类。
private void doLoadServlet(File servletFile) {
FileInputStream resourceAsStream;
SAXReader saxReader = new SAXReader();
String path=servletFile.getAbsolutePath();
MyClassLoader myClassLoader=new MyClassLoader(path);
//myClassLoader.setClasspath(path);
File webxml=new File(path+File.separator+ "web.xml");
if(webxml.exists()){
try {
resourceAsStream = new FileInputStream(webxml);
Document document = saxReader.read(resourceAsStream);
Element rootElement = document.getRootElement();
List<Element> selectNodes = rootElement.selectNodes("//servlet");
for (int i = 0; i < selectNodes.size(); i++) {
Element element = selectNodes.get(i);
// <servlet-name>lagou</servlet-name>
Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
String servletName = servletnameElement.getStringValue();
// <servlet-class>LagouServlet</servlet-class>
Element servletclassElement = (Element) element.selectSingleNode("servlet-class");
String servletClass = servletclassElement.getStringValue();
// 根据servlet-name的值找到url-pattern
Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
// /lagou
String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
//将路径加入到类加载器
Class c=myClassLoader.loadClass(servletClass);
servletMap.put(urlPattern, (HttpServlet) c.newInstance());
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
MyClassLoader
package server;
import java.io.*;
public class MyClassLoader extends ClassLoader{
private String classpath;
public MyClassLoader() {
}
public MyClassLoader(String classpath) {
this.classpath = classpath;
}
public String getClasspath() {
return classpath;
}
public void setClasspath(String classpath) {
this.classpath = classpath;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException{
try {
byte [] classDate=getData(name);
if(classDate==null){}
else{
//defineClass方法将字节码转化为类
return defineClass(name,classDate,0,classDate.length); }
} catch (IOException e) {
e.printStackTrace();
}
return super.findClass(name);
}
//返回类的字节码
private byte[] getData(String className) throws IOException{
InputStream in = null;
ByteArrayOutputStream out = null;
String path=classpath + File.separatorChar + className.replace('.',File.separatorChar)+".class";
try {
in=new FileInputStream(path);
out=new ByteArrayOutputStream();
byte[] buffer=new byte[2048];
int len=0;
while((len=in.read(buffer))!=-1){
out.write(buffer,0,len);
}
return out.toByteArray();
}
catch (FileNotFoundException e) {
e.printStackTrace();
} finally{
in.close();
out.close();
}
return null;
}
}
3.在webapps文件夹中放置相应的servlet测试文件夹,配置相关的web.xml,进行请求即可。
4.我们创建了两个servlet类,打包后将文件拷贝到webapps中,分别返回不同的值,结果如下。