实现简单HttpServer案例
<html>
<head>
<title>第一个表单</title>
</head>
<body>
<pre>
method:请求方式 get/post
get: 默认方式,数据量小,安全性不高
post:量大,安全性相对高
action:请求的服务器路径
id:编号,前端区分唯一性 ,js中使用
name:名称,后端(服务器)区分唯一性 ,获取值
只要提交数据给后台,必须存在name
</pre>
<form method="post" action="http://localhost:8888/g">
用户名:<input type="text" name="uname" id="uname"/>
密码:<input type="password" name="pwd" id="pwd"/>
<input type="submit" value="登录"/>
</form>
</body>
</html>
index.html
配置文件:
<?xml version="1.0" encoding="UTF-8"?> <web-app>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.bjsxt.servlet.LoginWeb</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/g</url-pattern>
<url-pattern>/y</url-pattern>
</servlet-mapping>
</web-app>
web.xml
工具类:
package com.bjsxt.util; import java.io.Closeable;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.net.Socket; public class CloseUtil {
/**
* 关闭IO流
*/
/*
public static void closeIO(Closeable... io){
for(Closeable temp:io){
try {
if (null != temp) {
temp.close();
}
} catch (Exception e) {
}
}
}*/
/**
* 使用泛型方法实现关闭IO流
* @param io
*/
public static <T extends Closeable> void closeIO(T... io){
for(Closeable temp:io){
try {
if (null != temp) {
temp.close();
}
} catch (Exception e) {
}
}
}
public static void closeSocket(ServerSocket socket){
try {
if (null != socket) {
socket.close();
}
} catch (Exception e) {
}
}
public static void closeSocket(Socket socket){
try {
if (null != socket) {
socket.close();
}
} catch (Exception e) {
}
}
public static void closeSocket(DatagramSocket socket){
try {
if (null != socket) {
socket.close();
}
} catch (Exception e) {
}
}
}
CloseUtil.java
Servlet:
package com.bjsxt.servlet; import com.bjsxt.server.Request;
import com.bjsxt.server.Response; public class LoginWeb extends Servlet { @Override
public void doGet(Request req, Response rep) throws Exception {
rep.println("success.....");
} @Override
public void doPost(Request req, Response rep) throws Exception {
// TODO Auto-generated method stub } }
LoginWeb.java
package com.bjsxt.servlet; import com.bjsxt.server.Request;
import com.bjsxt.server.Response; /**
* 抽象为一个父类
* @author Administrator
*
*/
public abstract class Servlet {
public void service(Request req,Response rep) throws Exception{
this.doGet(req,rep);
this.doPost(req,rep);
} protected abstract void doGet(Request req,Response rep) throws Exception;
protected abstract void doPost(Request req,Response rep) throws Exception;
}
Servlet.java
Server:
转发类:
package com.bjsxt.server; import java.io.IOException;
import java.net.Socket; import com.bjsxt.servlet.Servlet;
import com.bjsxt.util.CloseUtil; /**
* 一个请求与响应 就一个此对象
* @author Administrator
*
*/
public class Dispatcher implements Runnable{
private Socket client;
private Request req;
private Response rep;
private int code=200;
Dispatcher(Socket client){
this.client=client;
try {
req =new Request(client.getInputStream());
rep =new Response(client.getOutputStream());
} catch (IOException e) {
//e.printStackTrace();
code =500;
return ;
}
} @Override
public void run() {
try {
Servlet serv =WebApp.getServlet(req.getUrl());
if(null==serv){
this.code=404; //找不到处理
}else{
serv.service(req, rep);
}
rep.pushToClient(code); //推送到客户端
}catch (Exception e) {
e.printStackTrace();
this.code=500;
}
try {
rep.pushToClient(500);
} catch (IOException e) {
e.printStackTrace();
}
req.close();
rep.close();
CloseUtil.closeSocket(client);
} }
Dispatcher.java
获取配置文件实体类:
package com.bjsxt.server;
/*
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.bjsxt.server.demo4.LoginServlet</servlet-class>
</servlet>
*/
public class Entity {
private String name;
private String clz;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClz() {
return clz;
}
public void setClz(String clz) {
this.clz = clz;
} }
Entity.java
映射类:
package com.bjsxt.server; import java.util.ArrayList;
import java.util.List; /*
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/log</url-pattern>
</servlet-mapping> */
public class Mapping {
private String name;
private List<String> urlPattern; public Mapping(){
urlPattern =new ArrayList<String>();
} public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getUrlPattern() {
return urlPattern;
}
public void setUrlPattern(List<String> urlPattern) {
this.urlPattern = urlPattern;
} }
Mapping.java
请求类:
package com.bjsxt.server; import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer; import com.bjsxt.util.CloseUtil; /**
* 封装request
* @author Administrator
*
*/
public class Request {
//请求方式
private String method;
//请求资源
private String url;
//请求参数
private Map<String,List<String>> parameterMapValues; //内部
public static final String CRLF="\r\n";
private InputStream is;
private String requestInfo; public Request(){
method ="";
url ="";
parameterMapValues=new HashMap<String,List<String>>();
requestInfo="";
}
public Request(InputStream is){
this();
this.is=is;
try {
byte[] data = new byte[20480];
int len = is.read(data);
requestInfo = new String(data, 0, len);
} catch (Exception e) {
return ;
}
//分析请求信息
parseRequestInfo();
}
/**
* 分析请求信息
*/
private void parseRequestInfo(){
if(null==requestInfo ||(requestInfo=requestInfo.trim()).equals("")){
return ;
}
/**
* =====================================
* 从信息的首行分解出 :请求方式 请求路径 请求参数(get可能存在)
* 如:GET /index.html?name=123&pwd=5456 HTTP/1.1
*
* 如果为post方式,请求参数可能在 最后正文中
*
* 思路:
* 1)请求方式 :找出第一个/ 截取即可
* 2)请求资源:找出第一个/ HTTP/
* =====================================
*/
String paramString =""; //接收请求参数 //1、获取请求方式
String firstLine =requestInfo.substring(0,requestInfo.indexOf(CRLF));
int idx =requestInfo.indexOf("/"); // /的位置
this.method=firstLine.substring(0, idx).trim();
String urlStr =firstLine.substring(idx,firstLine.indexOf("HTTP/")).trim();
if(this.method.equalsIgnoreCase("post")){
this.url=urlStr;
paramString=requestInfo.substring(requestInfo.lastIndexOf(CRLF)).trim(); }else if(this.method.equalsIgnoreCase("get")){
if(urlStr.contains("?")){ //是否存在参数
String[] urlArray=urlStr.split("\\?");
this.url=urlArray[0];
paramString=urlArray[1];//接收请求参数
}else{
this.url=urlStr;
}
} //不存在请求参数
if(paramString.equals("")){
return ;
}
//2、将请求参数封装到Map中
parseParams(paramString);
}
private void parseParams(String paramString){
//分割 将字符串转成数组
StringTokenizer token=new StringTokenizer(paramString,"&");
while(token.hasMoreTokens()){
String keyValue =token.nextToken();
String[] keyValues=keyValue.split("=");
if(keyValues.length==1){
keyValues =Arrays.copyOf(keyValues, 2);
keyValues[1] =null;
} String key = keyValues[0].trim();
String value = null==keyValues[1]?null:decode(keyValues[1].trim(),"gbk");
//转换成Map 分拣
if(!parameterMapValues.containsKey(key)){
parameterMapValues.put(key,new ArrayList<String>());
} List<String> values =parameterMapValues.get(key);
values.add(value);
} }
/**
* 解决中文
* @param value
* @param code
* @return
*/
private String decode(String value,String code){
try {
return java.net.URLDecoder.decode(value, code);
} catch (UnsupportedEncodingException e) {
//e.printStackTrace();
}
return null;
}
/**
* 根据页面的name 获取对应的多个值
* @param args
*/
public String[] getParameterValues(String name){
List<String> values=null;
if((values=parameterMapValues.get(name))==null){
return null;
}else{
return values.toArray(new String[0]);
}
}
/**
* 根据页面的name 获取对应的单个值
* @param args
*/
public String getParameter(String name){
String[] values =getParameterValues(name);
if(null==values){
return null;
}
return values[0];
}
public String getUrl() {
return url;
} public void close(){
CloseUtil.closeIO(is);
}
}
Request.java
响应类:
package com.bjsxt.server; import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Date; import com.bjsxt.util.CloseUtil; /**
* 封装响应信息
* @author Administrator
*
*/
public class Response {
//两个常量
public static final String CRLF="\r\n";
public static final String BLANK=" ";
//流
private BufferedWriter bw ; //正文
private StringBuilder content; //存储头信息
private StringBuilder headInfo;
//存储正文长度
private int len =0;
public Response(){
headInfo =new StringBuilder();
content =new StringBuilder();
len =0;
}
public Response(Socket client){
this();
try {
bw= new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
} catch (IOException e) {
headInfo=null;
}
}
public Response(OutputStream os){
this();
bw= new BufferedWriter(new OutputStreamWriter(os));
}
/**
* 构建正文
*/
public Response print(String info){
content.append(info);
len+=info.getBytes().length;
return this;
} /**
* 构建正文+回车
*/
public Response println(String info){
content.append(info).append(CRLF);
len+=(info+CRLF).getBytes().length;
return this;
} /**
* 构建响应头
*/
private void createHeadInfo(int code){
//1) HTTP协议版本、状态代码、描述
headInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK);
switch(code){
case 200:
headInfo.append("OK");
break;
case 404:
headInfo.append("NOT FOUND");
break;
case 505:
headInfo.append("SEVER ERROR");
break;
}
headInfo.append(CRLF);
//2) 响应头(Response Head)
headInfo.append("Server:bjsxt Server/0.0.1").append(CRLF);
headInfo.append("Date:").append(new Date()).append(CRLF);
headInfo.append("Content-type:text/html;charset=GBK").append(CRLF);
//正文长度 :字节长度
headInfo.append("Content-Length:").append(len).append(CRLF);
headInfo.append(CRLF); //分隔符
}
//推送到客户端
void pushToClient(int code) throws IOException{
if(null==headInfo){
code =500;
}
createHeadInfo(code);
//头信息+分割符
bw.append(headInfo.toString());
//正文
bw.append(content.toString());
bw.flush();
}
public void close(){
CloseUtil.closeIO(bw);
} }
Response.java
服务器:
package com.bjsxt.server; import java.io.IOException;
import java.net.ServerSocket; import com.bjsxt.util.CloseUtil; /**
* 创建服务器,并启动
*
* 1、请求
* 2、响应
* @author Administrator
*
*/
public class Server {
private ServerSocket server;
public static final String CRLF="\r\n";
public static final String BLANK=" "; private boolean isShutDown= false;
/**
* @param args
*/
public static void main(String[] args) { Server server = new Server();
server.start(); }
/**
* 启动方法
*/
public void start(){
start(8888); }
/**
* 指定端口的启动方法
*/
public void start(int port){
try {
server = new ServerSocket(port);
this.receive();
} catch (IOException e) {
//e.printStackTrace();
stop();
} }
/**
* 接收客户端
*/
private void receive(){
try {
while(!isShutDown){
new Thread(new Dispatcher(server.accept())).start();
}
} catch (IOException e) {
//e.printStackTrace();
stop();
} } /**
* 停止服务器
*/
public void stop(){
isShutDown=true;
CloseUtil.closeSocket(server);
} }
Server.java
Servlet上下文:(container)
package com.bjsxt.server; import java.util.HashMap;
import java.util.Map; /**
* 上下文
* @author Administrator
*
*/
public class ServletContext {
//为每一个servlet取个别名
// login -->com.bjsxt.server.demo03.LoginServlet
private Map<String,String> servlet ;
//url -->login
// /log -->login
// /login -->login
private Map<String,String> mapping; ServletContext(){
servlet =new HashMap<String,String>();
mapping =new HashMap<String,String>();
} public Map<String, String> getServlet() {
return servlet;
}
public void setServlet(Map<String, String> servlet) {
this.servlet = servlet;
}
public Map<String, String> getMapping() {
return mapping;
}
public void setMapping(Map<String, String> mapping) {
this.mapping = mapping;
} }
ServletContext
Webapp:
package com.bjsxt.server; import java.util.List;
import java.util.Map; import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory; import com.bjsxt.servlet.Servlet; public class WebApp {
private static ServletContext contxt;
static{
try {
//获取解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//获取解析器
SAXParser sax = factory.newSAXParser();
//指定xml+处理器
WebHandler web = new WebHandler();
sax.parse(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("WEB_INFO/web.xml"), web); //将list 转成Map
contxt =new ServletContext();
Map<String,String> servlet =contxt.getServlet(); //servlet-name servlet-class
for(Entity entity:web.getEntityList()){
servlet.put(entity.getName(), entity.getClz()); } //url-pattern servlet-name
Map<String,String> mapping =contxt.getMapping();
for(Mapping mapp:web.getMappingList()){
List<String> urls =mapp.getUrlPattern();
for(String url:urls ){
mapping.put(url, mapp.getName());
}
} } catch (Exception e) { } } public static Servlet getServlet(String url) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
if((null==url)||(url=url.trim()).equals("")){
return null;
}
//根据字符串(完整路径)创建对象 //return contxt.getServlet().get(contxt.getMapping().get(url));
String name=contxt.getServlet().get(contxt.getMapping().get(url));
return (Servlet)Class.forName(name).newInstance();//确保空构造存在
}
}
WebApp.java
WebHandler:
package com.bjsxt.server; import java.util.ArrayList;
import java.util.List; import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; public class WebHandler extends DefaultHandler{
private List<Entity> entityList;
private List<Mapping> mappingList;
private Entity entity;
private Mapping mapping;
private String beginTag ;
private boolean isMap; @Override
public void startDocument() throws SAXException {
//文档解析开始
entityList =new ArrayList<Entity>() ;
mappingList =new ArrayList<Mapping>() ; }
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
//开始元素
if(null!=qName){
beginTag=qName; if(qName.equals("servlet")){
isMap=false;
entity=new Entity();
}else if(qName.equals("servlet-mapping")){
isMap=true;
mapping=new Mapping();
} } } @Override
public void characters(char[] ch, int start, int length)
throws SAXException {
//处理内容
if(null!=beginTag){
String str =new String(ch,start,length);
if(isMap ){ if(beginTag.equals("servlet-name")){
mapping.setName(str);
}else if(beginTag.equals("url-pattern")){
mapping.getUrlPattern().add(str);
}
}else{
if(beginTag.equals("servlet-name")){
entity.setName(str);
}else if(beginTag.equals("servlet-class")){
entity.setClz(str);
}
}
}
} @Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
//结束元素
if(null!=qName){ if(qName.equals("servlet")){
entityList.add(entity);
}else if(qName.equals("servlet-mapping")){
mappingList.add(mapping);
} }
beginTag=null;
} @Override
public void endDocument() throws SAXException {
//文档解析结束
} /*public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
//获取解析工厂
SAXParserFactory factory =SAXParserFactory.newInstance();
//获取解析器
SAXParser sax =factory.newSAXParser();
//指定xml+处理器
WebHandler web = new WebHandler();
sax.parse(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("com/bjsxt/server/demo4/web.xml")
,web); System.out.println(web.getEntityList());
}*/
public List<Entity> getEntityList() {
return entityList;
}
public void setEntityList(List<Entity> entityList) {
this.entityList = entityList;
}
public List<Mapping> getMappingList() {
return mappingList;
}
public void setMappingList(List<Mapping> mappingList) {
this.mappingList = mappingList;
} }
WebHandler.java
实现简单HttpServer案例的更多相关文章
- 简单登录案例(SharedPreferences存储账户信息)&联网请求图片并下载到SD卡(文件外部存储)
新人刚学习Android两周,写一个随笔算是对两周学习成果的巩固,不足之处欢迎各位建议和完善. 这次写的是一个简单登录案例,大概功能如下: 注册的账户信息用SharedPreferences存储: 登 ...
- MyBatis学习总结(一)简单入门案例
MyBatis学习总结(一)简单入门案例 主要内容:本文主要通过对数据库中的use表进行增删改查总结mybatis的环境搭建和基本入门使用 一.需要的jar包: 1.核心包 2.依赖包 3.jdbc数 ...
- 一个简单的案例带你入门Dubbo分布式框架
相信有很多小伙伴都知道,dubbo是一个分布式.高性能.透明化的RPC服务框架,提供服务自动注册.自动发现等高效服务治理方案,dubbo的中文文档也是非常全的,中文文档可以参考这里dubbo.io.由 ...
- solr简单搜索案例
solr简单搜索案例 使用Solr实现电商网站中商品信息搜索功能,可以根据关键字搜索商品信息,根据商品分类.价格过滤搜索结果,也可以根据价格进行排序,实现分页. 架构分为: 1. solr服务器 2. ...
- springcloud+eureka简单入门案例
springcloud+eureka简单入门案例 一.服务提供者 直接提供服务,入门案例没有特别要设置的地方,注意下端口,由于要启动多个服务,可能会冲突 配置文件(src/main/resources ...
- Python 简单爬虫案例
Python 简单爬虫案例 import requests url = "https://www.sogou.com/web" # 封装参数 wd = input('enter a ...
- arduino中SCoop库的简单应用案例
转载:https://www.csdn.net/gather_27/MtTaggzsMDExMS1ibG9n.html arduino中SCoop库的简单应用案例首先这篇文章来在视频https://v ...
- ReentrantReadWriteLock读写锁简单原理案例证明
ReentrantReadWriteLock存在原因? 我们知道List的实现类ArrayList,LinkedList都是非线程安全的,Vector类通过用synchronized修饰方法保证了Li ...
- redux 的简单实用案例
redux 的简单实用案例 整体思想与结构 创建一个Action 创建一个Reducer 创建Store 在App组件开始使用 整体思想与结构 文件目录如下: 构建 action,通过创建一个函数,然 ...
随机推荐
- 命令行(一):Git
1,使用gitbash进行操作 2,初始化一个Git仓库,使用git init命令. 3,添加文件到Git仓库,分两步:使用命令git add <filename>可反复多次使用,添加多个 ...
- JAVA Feign
Feign 是一种声明式.模板化的 HTTP客户端 . 在Spring Cloud中使用 Feign, 我们可以做到使用HTTP请求远程服务时能与调用本地方法一样的编码体验,开发者完全感知不到这是远程 ...
- 5G手机来了,但这些问题让其短期内难以成为“香饽饽”
在5G手机喊了太长时间后,其终于在近日不断亮相. 此前据中国质量认证中心官网显示,共有8款5G手机获得3C认证--华为4款,一加.中兴.OPPO和vivo各有一款.随着首批5G手机通过3C认证,意味着 ...
- HBase记录
本次记录是用于:SparkStreaming对接Kafka.HBase记录 一.基本概念 1.HBase以表的形式存储数据.表有行和列族组成.列族划分为若干个列.其结构如下 2.Row Key:行键 ...
- 同步块:synchronized(同步监视器对象){同步运行代码片段}
package seday10; import seday03.Test2; /** * @author xingsir * 同步块:synchronized(同步监视器对象){需要同步运行的代码片段 ...
- shell脚本编程学习笔记(二)linux服务器启动流程
一.linux服务器启动流程 1.bios找到磁盘上的mbr主引导扇区 2.进入grub洁面选择相应的启动内核 3.读取kernel内核文件-/boot/vmlinuz-* 4.读取init的镜像文件 ...
- bodyParser.urlencoded({ })里extended: true和false区别???
- Python 多任务(线程) day2 (1)
结论:多线程全局变量是共享的 (03) 因为多线程一般是配合使用,如果不共享,那么就要等到一个线程执行完,再把变量传递给另一个线程,就变成单线程了 但是如果多个线程同时需要修改一个全局变量,就会出现资 ...
- matplotlib添加坐标轴实现性格测试可视化
一张图展示最终效果 皮一下很开心,标签名肯定不是用户想要的,所以在这里尝试了定制化功能 功能&方法: 定制化标签名/标签数量(4个/5个).实现方法:在第一个界面点击cancel按钮,进入修改 ...
- Maven - skiptest
1. 概述 maven install 中尝试跳过 单元测试 2. 背景 从别处找来的工程 改了改发现测试过不了 编译都过不了 但又要着急继续调整 就是懒 这种事本来不提倡, 但是生产里数不胜数 Ma ...