在上一篇《Java实现简单的服务器--访问静态HTML页面》的基础上进行修改,实现浏览器对Java文件的访问。没有使用Servlet,但大致呈现了Servlet的运行原理。
项目的目录结构修改如下图:
一、修改服务器StaticWebServer代码
package imitatetomcat;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class StaticWebServer {
//定义网页所在的目录位置
public static final String WEB_ROOT=System.getProperty("user.dir") + File.separator+ "webroot";
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(8080);
while(true) {
Socket socket = server.accept();
//在控制台输出浏览器的IP地址和端口号
System.out.println(socket.getInetAddress()+":"+socket.getPort());
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
//把处理请求和响应的工作交给类Request和Response
Request request=new Request(in);
request.parse();
Response response=new Response(out);
response.setRequest(request);
//判断是否是静态页面(假如静态请求资源中有".",动态页面的只写文件名)
if(request.getUri().contains(".")) {
response.sendStaticResource();
}
else {
try {
String[] fileName=request.getUri().split("\\?");
response.sendDynamicResource(request,response,fileName[0]);
} catch (Exception e) {
e.printStackTrace();
}
}
in.close();
out.close();
socket.close();
}
//server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
二、修改请求类Request类
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
/*处理请求信息的类,该类只简单获取首行中请求资源名*/
public class Request{
private InputStream input;
//存放请求资源文件的字符串
private String uri;
//存放请求参数(简单处理下,只能放字符串)
private Map<String, String> map=new HashMap<String, String>();
public Request(InputStream input) {
this.input = input;
}
public void parse() {
int i;
byte[] buf = new byte[1048];
try {
i = input.read(buf);
}
catch (IOException e) {
e.printStackTrace();
i = -1;
}
String str=new String(buf);
//在控制台输出请求信息
System.out.print(str);
//截取请求Url
uri = parseUri(str);
if(uri.contains("?")) {
//对请求参数进行分割并放到map中
String parameters=parseParameters(str);
String paras[]=parameters.split("\\&");
for (int j = 0; j < paras.length; j++) {
String para[]=paras[j].split("\\=");
System.out.println(para[0]+":"+para[1]);
if (para[0]!=null) {
map.put(para[0],para[1]);
}
}
}
}
//从请求信息中截取请求Url,即首行的中间部分
private String parseUri(String requestString) {
int index1, index2;
index1 = requestString.indexOf(' ');
if (index1 != -1) {
index2 = requestString.indexOf(' ', index1 + 1);
if (index2 > index1)
return requestString.substring(index1 +2, index2);
}
return null;
}
//从请求信息中截取请求Url后的请求参数(?name=zhangsan&password=123),先实现只取GET方法的
private String parseParameters(String requestString) {
int index1, index2;
index1 = requestString.indexOf('?');
if (index1 != -1) {
index2 = requestString.indexOf(' ', index1 + 1);
//取出?后的所有参数
if (index2 > index1)
return requestString.substring(index1 + 1, index2);
}
return null;
}
public String getUri() {
return uri;
}
public Map<String, String> getMap() {
return map;
}
}
三、修改请求类Response类
package imitatetomcat;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
/* 处理响应信息的类 */
public class Response{
Request request;
OutputStream output;
public Response(OutputStream output) {
this.output = output;
}
public OutputStream getOutput() {
return this.output;
}
public void setRequest(Request request) {
this.request = request;
}
//1.加响应头
//2.读取文件
public void sendStaticResource() throws IOException {
byte[] bytes = new byte[1024*1024];//响应的内容假如不超过1024*1024个字节
FileInputStream fis = null;
try {
System.out.println(StaticWebServer.WEB_ROOT+File.separator+request.getUri());
File file = new File(StaticWebServer.WEB_ROOT+File.separator+request.getUri());
if (file.exists()) {
fis = new FileInputStream(file);
int ch = fis.read(bytes, 0, 1024*1024);
String str="http/1.1 200 ok\r\n\r\n";
output.write(str.getBytes());
output.write(bytes, 0, ch);
}
else {
//如果没有发现文件,返回404错误
String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: 23\r\n" +
"\r\n" +
"<h1>File Not Found</h1>";
output.write(errorMessage.getBytes());
}
}
catch (Exception e) {
System.out.println(e.toString() );
}
finally {
if (fis!=null)
fis.close();
}
}
//1.加响应头
//2.编译并执行文件
public void sendDynamicResource(Request request,Response response,String dynamicFile) throws Exception{
try {
File file = new File(System.getProperty("user.dir")+File.separator+"src"+File.separator+"test\\"+dynamicFile+".java");
if (file.exists()) {
//Runtime.getRuntime()调用javac命令,编译Java文件到class文件
String javaAbsolutePath = System.getProperty("user.dir")+"\\src\\test\\"+dynamicFile+".java";
Process process = Runtime.getRuntime().exec("javac "+ javaAbsolutePath);
//加载.class文件
Class<?> forName = Class.forName("test."+dynamicFile);
Servleter newInstance = (Servleter)forName.newInstance();
newInstance.service(request,response);
}
else {
//如果没有发现文件,返回404错误
String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: 23\r\n" +
"\r\n" +
"<h1>File Not Found</h1>";
output.write(errorMessage.getBytes());
}
}
catch (Exception e) {
System.out.println(e.toString() );
}
}
}
四、制定可访问Java类文件的标准--接口Servleter
package imitatetomcat;
public interface Servleter {
public void service(Request request,Response response);
}
五、测试时用的可访问的Java类
package test;
import java.io.IOException;
import java.util.Map;
import imitatetomcat.Request;
import imitatetomcat.Response;
import imitatetomcat.Servleter;
public class TestJavaFile implements Servleter{
@Override
public void service(Request request, Response response) {
Map<String, String> map=request.getMap();
String name=map.get("name");
String password=map.get("password");
String respString="hello!"+name+"; your password is:"+password;
String str="http/1.1 200 ok\r\n\r\n";
try {
response.getOutput().write(str.getBytes());
response.getOutput().write(respString.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果:
浏览器访问时的url和访问结果,如下图:
实现了服务器对浏览器的请求信息进行了处理,并把处理结果发给浏览器。只要在test包中(位置固定,为了代码实现简单)编写任意一个实现了Servleter接口的类,浏览器都可以访问了。