项目及包
解析server.xml配置文件
//端口号的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<server>
<service>
<connector port="8080"> </connector>
</service>
</server>
package com.bjpowernode.httpserver.core;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* 解析server.xml配置文件
* @author 邬郝
* @version 1.0
* @since 1.0
*/
public class ServerParser {
/**
* 获取服务器的端口号
* @return int port
*/
public static int getPort(){
//设置服务器默认端口号:8080
int port=8080;
try {
//创建解析器
SAXReader saxReader = new SAXReader();
//通过解析器的read方法将配置文件读取到内存中生成一个Document[org.dom4j]
Document document=saxReader.read("conf/server.xml");
//获取connector节点元素的路径:server->service->connector
//获取connector节点元素的xpath路径:server->service->connector
//获取connector节点元素的xpath路径:server->connector
//获取connector节点元素的xpath路径:connector
Element connectorElt=(Element)document.selectSingleNode("//connector");
//获取port属性的值
port = Integer.parseInt(connectorElt.attributeValue("port"));
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return port;
}
}
两个HTML页面
<html>
<head>
<title>OA办公系统首页</title>
<meta content="text/html;charset=utf-8"/>
</head>
<body>
<center><font size="35xp" color="blue">OA办公系统首页</font></center>
</body>
</html>
<html>
<head>
<title>用户信息-保存用户信息</title>
<meta content="text/html;charset=utf-8"/>
</head>
<body>
<form name="userForm" action="/oa/user/save" method="get">
用户名:
<input type="text" name="username"/>
<br><br>
性 别:
<input type="radio" name="gender" value="1"/>男
<input type="radio" name="gender" value="0"/>女
<br><br>
兴 趣:
<input type="checkbox" name="interest" value="music"/>音乐
<input type="checkbox" name="interest" value="sport"/>运动
<input type="checkbox" name="interest" value="food"/>美食
<input type="checkbox" name="interest" value="sleep"/>睡觉
<input type="checkbox" name="interest" value="travel"/>旅游
<br><br>
<input type="submit" value="保存"/>
<input type="reset" value="重置"/>
</form>
</body>
</html>
解析服务器中的Web.xml配置文件及处理业务类
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>loginServlet</servlet-name>
<servlet-class>org.bjpowernode.oa.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>UserSaveServlet</servlet-name>
<servlet-class>org.bjpowernode.oa.servlet.UserSaveServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserSaveServlet</servlet-name>
<url-pattern>/user/save</url-pattern>
</servlet-mapping>
</web-app>
package com.bjpowernode.httpserver.core;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* 解析服务器中的Web.xml配置文件
* @author 邬郝
* @version 1.0
* @since 1.0
*
*/
public class WebParser {
public static Map<String,Map<String,String>> servletMaps= new HashMap<String,Map<String,String>>();
/**
* 解析服务器所有应用的web.xml
* @param webAppNames 服务器中所有应用的名称
* @throws DocumentException
*/
public static void parser(String[] webAppNames) throws DocumentException{
for(String webAppName:webAppNames){
Map<String,String> servletMap=parser(webAppName);
servletMaps.put(webAppName, servletMap);
}
}
/**
* 解析单个应用的web.xml配置文件
* @param webAppName 应用名称
* @return servletMap<String,String>
* @throws DocumentException
*/
private static Map<String,String> parser(String webAppName) throws DocumentException{
//获取web.xml路径
String webPath = webAppName + "/WEB-INF/web.xml";
//创建解析器
SAXReader saxReader = new SAXReader();
//通过解析器的read方法将配置文件读取到内存中 生成一个Document[org.dom4j]对象树
Document document = saxReader.read(new File(webPath));
//获取servlet节点元素:web-app -> servlet
List<Element> servletNodes = document.selectNodes("/web-app/servlet");
//创建一个servletInfoMap集合 将servlet-name和servlet-class的值分别当作key和value存放到该集合中
Map<String,String> servletInfoMap = new HashMap<String,String>();
//开始遍历servletNodes
for(Element servletNode:servletNodes){
//获取servlet-name节点元素对象
Element servletNameElt = (Element) servletNode.selectSingleNode("servlet-name");
//获取servletNameElt节点元素对象的值
String servletName= servletNameElt.getStringValue();
//获取servlet-class节点元素对象
Element servletClassElt = (Element) servletNode.selectSingleNode("servlet-class");
//获取servletClassElt节点元素对象的值
String servletClassName= servletClassElt.getStringValue();
//将servletName和servletClassName分别当作key和value存放到servletInfoMap集合中
servletInfoMap.put(servletName, servletClassName);
}
//获取servlet--mapping节点元素对象:web-app -> servlet-mapping
List<Element> servletMappingNodes= document.selectNodes("/web-app/servlet-mapping");
//创建一个servletMappingInfoMap集合 将servlet-name和url-pattern节点元素对象的值分别当作key和value存放到该集合中
Map<String,String> servletMappingInfoMap = new HashMap<String,String>();
//开始遍历servletMappingNodes
for(Element servletMappingNode:servletMappingNodes){
//获取servlet-name节点元素对象
Element servletNameElt = (Element)servletMappingNode.selectSingleNode("servlet-name");
//获取servletNameElt节点元素对象的值
String servletName = servletNameElt.getStringValue();
//获取url-pattern节点元素对象
Element urlPatternElt = (Element)servletMappingNode.selectSingleNode("url-pattern");
//获取urlPatternElt节点元素对象的值
String urlPattern = urlPatternElt.getStringValue();
//将servletName和urlPattern分别当作key和value存放到servletMappingInfoMap集合中
servletMappingInfoMap.put(servletName, urlPattern);
}
//获取servletInfoMap或者servletMappingInfoMap任何一个可以值的集合
Set<String> servletNames = servletInfoMap.keySet();
//创建一个servletMap集合 将servletMappingInfoMap的value和servletInfoMap的value分别当作key和value存放在集合中
Map<String,String> servletMap=new HashMap<String,String>();
//开始遍历servletNames
for(String servletName:servletNames){
//获取servletMappingInfoMap集合中的value:urlPattern
String urlPattern = servletMappingInfoMap.get(servletName);
//后去servletInfoMap集合中的value:servletClass
String servletClassName = servletInfoMap.get(servletName);
//将urlPattern和servletClassName分别当作key和value存放到servletMap集合中
servletMap.put(urlPattern, servletClassName);
}
return servletMap;
}
}
package org.bjpowernode.oa.servlet;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import com.bjpowernode.httpserver.core.RequestObject;
import com.bjpowernode.httpserver.core.ResponseObject;
/**
* 处理登录业务的java程序,该java程序由webAPP开发人 由web服务器开发人员调用
* @author 邬郝
* @version 1.0
* @since 1.0
*/
public class LoginServlet implements Servlet{
//处理业务的核心类
public void service(ServletRequest request,ServletResponse response){
System.out.println("正在验证身份,请稍等.....");
//获取响应流对象
PrintWriter out = response.getWriter();
out.print("<html>");
out.print("<head>");
out.print("<title>正在验证</title>");
out.print("<meta content='text/heml;charset=utf-8'/>");
out.print("</head>");
out.print("<body>");
out.print("<center><font size='35px' color='blue'>正在验证身份,请稍等...</font></center>");
out.print("</body>");
out.print("</html>");
}
}
package org.bjpowernode.oa.servlet;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import com.bjpowernode.httpserver.core.RequestObject;
public class UserSaveServlet implements Servlet{
@Override
public void service(ServletRequest request, ServletResponse response) {
//-------获取页面请求提交的参数的值---------
String username = request.getParameterValue("username");
String gender = request.getParameterValue("gender");
String[] interest = request.getParameterValues("interest");
StringBuilder interests = new StringBuilder();
for(String interestValue:interest){
interests.append(interestValue).append(" ");
}
//获取响应流对象
PrintWriter out = response.getWriter();
out.print("<html>");
out.print("<head>");
out.print("<title>用户信息</title>");
out.print("<meta content='text/html;charset=utf-8'/>");
out.print("</head>");
out.print("<body>");
out.print("用户名:"+username+"<br>");
out.print("性别:"+gender+"<br>");
out.print("兴趣:"+interests);
out.print("</body>");
out.print("</html>");
}
}
封装请求与响应参数
package com.bjpowernode.httpserver.core;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletRequest;
/**
* 负责封装请求参数
* @author 邬郝
* @version 1.0
* @since 1.0
*/
public class RequestObject implements ServletRequest{
public Map<String,String[]> parameterMap = new HashMap<String,String[]>();
public RequestObject(String requestURI){
//requestURI有以下几种可能
//1./oa/user?
//2./oa/user?username=zhangsan
//3./oa/user?username=
//4./oa/user?username=zhangsan&gender=1
//5./oa/user?username=zhangsan&gender=1&interest=food
//6./oa/user?username=zhangsan&gender=1&interest=food&ijnterest=sleep
//判断requestURI中是否包含?号 是否包含参数
if(requestURI.contains("?")){
//将requestURI通过?号进行分割
String[] uriAndData = requestURI.split("[?]");
//再次判断requestURI是否包含参数
if(uriAndData.length>1){
//获取参数部分
String data=uriAndData[1];
//通过&符号判断requestURI中是否包含多个参数
if(data.contains("&")){//说明有多个参数
//{"username=zhansan","gender=1","interest=food","interest=music"}
//通过&符号进行分割
String[] nameAndValues = data.split("&");
//开始遍历nameAndValueAttr
for(String nameAndValue:nameAndValues){
//通过=号进行分割:{"username","zhangsan"}
String[] nameAndValueAttr = nameAndValue.split("=");
//判断key值是否在parameterMap集合中存在
//1.如果存在,说明该参数为多选框
//2.如果不存,说明为普通的标签
if(parameterMap.containsKey(nameAndValueAttr[0])){
//将之前多选框的值取出来
String[] values = parameterMap.get(nameAndValueAttr[0]);
//定义一个新的数组,新数组的长度永远比values数组的长度大1
String[] newValues = new String[values.length + 1];
System.arraycopy(values, 0, newValues, 0, values.length);
//判断该参数是否有值
if(nameAndValueAttr.length>1){
newValues[newValues.length-1]=nameAndValueAttr[1];
}else{
newValues[newValues.length-1]="";
}
parameterMap.put(nameAndValueAttr[0], newValues);
}else{
//判断该参数是否有值
if(nameAndValueAttr.length>1){
parameterMap.put(nameAndValueAttr[0],new String[]{nameAndValueAttr[1]});
}else{
parameterMap.put(nameAndValueAttr[0],new String[]{""});
}
}
}
}else{//单个参数
String[] nameAndValueAttr = data.split("=");
//data通过=号进行分割 判断参数是否有值
if(nameAndValueAttr.length>1){//有值
parameterMap.put(nameAndValueAttr[0], new String[]{nameAndValueAttr[1]});
}else{//无值
parameterMap.put(nameAndValueAttr[0], new String[]{""});
}
}
}
}
}
/**
* 获取普通标签参数的值
* @param key 标签name属性的值
* @return String 标签value值
*/
public String getParameterValue(String key){
String[] value = parameterMap.get(key);
return (value!=null && value.length != 0)?value[0]:null;
}
/**
* 获取多选框的值
* @param key 标签name属性的值
* @return String[] 多选框的值
*/
public String[] getParameterValues(String key){
return parameterMap.get(key);
}
}
package com.bjpowernode.httpserver.core;
import java.io.PrintWriter;
import javax.servlet.ServletResponse;
/**
* 负责封装响应参数对象
* @author 邬郝
* @version 1.0
* @since 1.0
*/
public class ResponseObject implements ServletResponse{
private PrintWriter out;
public void setWriter(PrintWriter out){
this.out=out;
}
public PrintWriter getWriter(){
return out;
}
}
三个接口
package javax.servlet;
/**
* 由sun公司制定的servlet接口规范 该接口由web服务器开发人员来调用 由webApp开发人来实现
* @author 邬郝
* @version 1.0
* @since 1.0
*/
public interface Servlet {
/**
* 处理业务的核心方法
* @param request
* @param response
*/
void service(ServletRequest request, ServletResponse response);
}
package javax.servlet;
/**
* 负责封装请求参数对象
* @author 邬郝
* @version 1.0
* @since 1.0
*/
public interface ServletRequest {
/**
* 获取单个参数的值
* @param key
* @return String
*/
String getParameterValue(String key);
/**
* 获取多选框的值
* @param key
* @return String[]
*/
String[] getParameterValues(String key);
}
package javax.servlet;
import java.io.PrintWriter;
/**
* 封装响应参数的接口规范
* @author 邬郝
* @version 1.0
*
* @since 1.0
*/
public interface ServletResponse {
void setWriter(PrintWriter out);
PrintWriter getWriter();
}
主程序入口与处理客户端请求
package com.bjpowernode.httpserver.core;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import com.bjpowernode.httpserver.util.Logger;
/**
* httpserver 程序主入口
* @author 邬郝
* @version 1.0
* @since 1.0
*/
public class BootStrap {
/**
* 主程序
* @param args
*/
public static void main(String[] args) {
//程序入口
start();
}
/**
* 主程序入口
*/
public static void start() {
ServerSocket serverSocket=null;
Socket clientSocket =null;
BufferedReader br=null;
try {
Logger.log("httpserver start");
//获取当前时间
long start =System.currentTimeMillis();
//解析服务器中包含的web.xml文件
String[] webAppNames = {"oa"};
WebParser.parser(webAppNames);
//获取系统的端口号
int port=ServerParser.getPort();
Logger.log("httpserver-port: "+port);
//创建服务器套接字 并且绑定端口号8080
serverSocket = new ServerSocket(port);
//获取结束时间
long end = System.currentTimeMillis();
Logger.log("httpserver started:"+(end-start)+"ms");
while(true){
//开始监听网络 此时程序处于等待状态 等待接收客户端的消息
clientSocket = serverSocket.accept();
/*//接收客户端消息
br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String temp=null;
while((temp=br.readLine())!=null){
System.out.println(temp);
}*/
new Thread(new HandlerRequest(clientSocket)).start();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if(br!=null){
br.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(clientSocket!=null){
clientSocket.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(serverSocket!=null){
serverSocket.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
package com.bjpowernode.httpserver.core;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Map;
import javax.servlet.Servlet;
import org.bjpowernode.oa.servlet.LoginServlet;
import com.bjpowernode.httpserver.util.Logger;
/**
* 处理客户端请求
* @author 邬郝
* @version 1.0
* @since 1.0
*/
public class HandlerRequest implements Runnable{
public Socket clientSocket;
public HandlerRequest(Socket clientSocket){
this.clientSocket=clientSocket;
}
@Override
public void run() {
//处理客户端请求
BufferedReader br =null;
PrintWriter out=null;
Logger.log("httpserver thread: "+ Thread.currentThread().getName());
try {
//接收客户端消息
br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
//获取响应流对象
out = new PrintWriter(clientSocket.getOutputStream());
/*//打印客户端消息
String temp=null;
while((temp=br.readLine())!=null){
System.out.println(temp);
}*/
//获取请求协议的请求行
String requestLine = br.readLine();// GET ...
//获取URI ->请求行(requestLine)->请求方式 URI 请求协议版本号
String requestURI = requestLine.split(" ")[1];//{"GET","/oa/index.html","http/1.0"}
//判断用户请求是否为一个静态页面-> 以HTML结尾的 文件
if(requestURI.endsWith(".html") || requestURI.endsWith(".htm")){
//处理静态页面的方法
responseStaticPage(requestURI,out);
}else{//动态资源 java程序 业务处理类
//requestURI :/oa/login?username=zhangsan&password=111
String servletPath=requestURI;
if(servletPath.contains("?")){
servletPath=servletPath.split("[?]")[0];// oa/login
}
// if("/oa/login".equals(servletPath)){
// LoginServlet loginServlet = new LoginServlet();
// loginServlet.service();
// }
//获取应用的名称 oa 在uri里:/oa/login
String webAppName= servletPath.split("[/]")[1];
//获取servletMaps集合中的value值->servletMap ->key:urlPattern values:servletClassName
Map<String,String> servletMap=WebParser.servletMaps.get(webAppName);
//获取servletMap集合中的key值->存在uri中/oa/login /oa/use/xxx/xxx
String urlPattern = servletPath.substring(1+webAppName.length());
//获取servletClassName
String servletClassName = servletMap.get(urlPattern);
//判断该业务处理的servlet类是否存在
if(servletClassName!=null){
//获取封装响应参数对象
ResponseObject responseObject = new ResponseObject();
responseObject.setWriter(out);
//获取封装请求参数对象
RequestObject requestObject = new RequestObject(requestURI);
out.print("HTTP/1.1 200 OK\n");
out.print("Content-Type:text/html;charset=utf-8\n\n");
//创建servlet对象之前 先从缓冲池中查找
//1.有 拿来用
//2.没有 创建servlet对象放到缓冲池中
Servlet servlet = ServletCache.get(urlPattern);
if(servlet==null){
//通过反射机制创建业务处理类
Class c =Class.forName(servletClassName);
Object obj = c.newInstance();
servlet= (Servlet)obj;
//将创建好的Servlet对象放到缓存池中
ServletCache.put(urlPattern, servlet);
}
servlet.service(requestObject,responseObject);
}else{//找不到该业务404
//404找不到资源
StringBuilder html = new StringBuilder();
html.append("HTTP/1.1 404 NotFound\n");
html.append("Content-Type:text/html;charset=utf-8\n\n");
html.append("<html>");
html.append("<head>");
html.append("<title>404-错误</title>");
html.append("<meta content='text/html;charset=utf-8'/>");
html.append("</head>");
html.append("<body>");
html.append("<center><font size='35px' color='red'>404-Not Found</font></center>");
html.append("</body>");
html.append("</html>");
out.print(html);
}
}
//强制刷新
out.flush();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//关闭
if(out != null){
out.close();
}
try {
if(br!=null){
br.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(clientSocket!=null){
clientSocket.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 处理静态页面
* @param requestURI 请求URI
* @param out 响应流对象
*/
private void responseStaticPage(String requestURI, PrintWriter out) {
//requestURI:/oa/index.html
// 静态页面的路径:oa/index.html
String htmlPath = requestURI.substring(1);
BufferedReader br=null;
try {
//读取页面
br = new BufferedReader(new FileReader(htmlPath));
StringBuilder html = new StringBuilder();
//拼接响应信息
html.append("HTTP/1.1 200 OK\n");
html.append("Content-Type:text/html;charset=utf-8\n\n");
String temp =null;
while((temp=br.readLine())!=null){
html.append(temp);
}
//输出html
out.print(html);
} catch (FileNotFoundException e) {
//404找不到资源
StringBuilder html = new StringBuilder();
html.append("HTTP/1.1 404 NotFound\n");
html.append("Content-Type:text/html;charset=utf-8\n\n");
html.append("<html>");
html.append("<head>");
html.append("<title>404-错误</title>");
html.append("<meta content='text/html;charset=utf-8'/>");
html.append("</head>");
html.append("<body>");
html.append("<center><font size='35px' color='red'>404-Not Found</font></center>");
html.append("</body>");
html.append("</html>");
out.print(html);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
日志
package com.bjpowernode.httpserver.util;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 日期工具类
* @author 邬郝
* @version 1.0
* @since 1.0
*/
public class DateUtil {
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
private DateUtil(){}
/**
* 获取系统当前时间
* @return String yyyy-MM-dd HH:mm:ss SSS
*/
public static String getCurrentTime(){
return dateFormat.format(new Date());
}
}
package com.bjpowernode.httpserver.util;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 日志记录器
* @author 邬郝
* @version 1.0
* @since 1.0
*/
public class Logger {
//工具类的方法往往是静态的 直接通过类名调用不需要去创建对象
//工具类的构造方法往往也是私有的 但不是必须的
private Logger(){
}
/**
* 普通日志记录器
* @param msg
*/
public static void log(String msg){
/*SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
Date nowTime = new Date();
String nowTimeStr = dateFormat.format(nowTime);*/
System.out.println("[INFO] "+DateUtil.getCurrentTime() + " "+msg);
}
}
缓冲池
package com.bjpowernode.httpserver.core;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.Servlet;
/**
* Servlet对象缓存池
* @author 邬郝
* @version 1.0
* @since 1.0
*/
public class ServletCache {
private static Map<String,Servlet> servletMap = new HashMap<String,Servlet>();
public static void put(String urlPattern,Servlet servlet){
servletMap.put(urlPattern, servlet);
}
public static Servlet get(String urlPattern){
return servletMap.get(urlPattern);
}
}
版权声明:本文为weixin_45209580原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。