目录
Package Explorer目录
首先先看下我的Package Explorer,就是server这个java project,其中有三个包,分别是server、servlet、WEB_INFO,用途对应是服务器、实际业务、配置文件;
server包
CloseUtil.java
按顺序来看,第一个为CloseUtil.java,该文件用于关闭文件
package server;
import java.io.Closeable;
public class CloseUtil {
/**
* 关闭IO流
*/
public static void closeAll(Closeable... io){
for(Closeable temp:io){
try {
if (null != temp) {
temp.close();
}
} catch (Exception e) {
}
}
}
/**
* 使用泛型方法实现关闭IO流
*/
public static <T extends Closeable> void closeIO(T ... io) {
for(Closeable temp:io) {
try {
if(null != temp) {
temp.close();
}
}catch(Exception e){
}
}
}
}
Dispatcher.java
package server;
import java.io.IOException;
import java.net.Socket;
import servlet.Servlet;
/**
* 一个请求与相应 就一个此对象
*/
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) {
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 {//500就再推一次
rep.pushToClient(500);
} catch (IOException e) {
e.printStackTrace();
}
CloseUtil.closeAll(client);
}
}
Entity.java
package server;
/*
<servlet>
<servlet-name>login</servlet-name>
<servlet-class> server.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;
}
}
Mapping.java
package 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;
}
}
Request.java
package 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;
/**
* 封装request
* @author DUGAN
*
*/
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;
}
}
Response.java
package 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;
/**
* 封装响应信息
* @author 84079
*
*/
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(OutputStream os) {
this();
bw = new BufferedWriter(new OutputStreamWriter(os));
}
public Response(Socket client) {
this();
try {
bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
} catch (IOException e) {
headInfo = null;
}
}
/*
* 构建正文
*/
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");
case 404:
headInfo.append("NOT FOUND");
case 500:
headInfo.append("SEVER ERROR");
}
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);
}
}
Server.java
package server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
/**
* 创建服务器,并启动
* 1.请求
* 2.响应
* @author DUGAN
*
*/
public class Server {
private ServerSocket server;
public static final String CRLF="\r\n";
public static final String BLANK=" ";
private boolean isShutDown = false;
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) {
stop();
}
}
/**
* 接收客户端
*/
private void receive(){
try {
while(!isShutDown) {
new Thread(new Dispatcher(server.accept())).start();
}
}catch(IOException e) {
stop();
}
}
/**
* 停止服务器
*/
public void stop(){
isShutDown = true;
CloseUtil.closeIO(server);
}
}
ServletContext.java
package server;
import java.util.HashMap;
import java.util.Map;
/**
* 上下文
* @author DUGAN
*
*/
public class ServletContext {
//为每个servlet取个别名
//login --> server.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;
}
}
WebApp.java
package server;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import 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();//确保空构造存在
}
}
WebHandler.java
package server;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
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("server/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;
}
}
servlet包
LoginServlet.java
package servlet;
import server.Request;
import server.Response;
public class LoginServlet extends Servlet{
@Override
public void doGet(Request req,Response rep) throws Exception {
String name = req.getParameter("uname");
String pwd = req.getParameter("pwd");
if(login(name,pwd)) {
rep.println("<html><head><title>欢迎回来</title>");
rep.println("</head><body>");
rep.println("欢迎:").println(req.getParameter("uname")).println("回来");
rep.println("</body></html>");
}else {
rep.print("登录失败");
}
}
public boolean login(String name,String pwd) {
return name.equals("DUGAN")&& pwd.equals("123456");
}
@Override
public void doPost(Request req,Response rep) throws Exception {
// TODO Auto-generated method stub
}
}
RegisterServlet.java
package servlet;
import server.Request;
import server.Response;
public class RegisterServlet extends Servlet{
@Override
public void doGet(Request req,Response rep) throws Exception {
}
@Override
public void doPost(Request req,Response rep) throws Exception {
rep.println("<html><head><title>返回注册</title>");
rep.println("</head><body>");
rep.println("你的用户名为:"+req.getParameter("uname"));
rep.println("</body></html>");
}
}
Servlet.java
package servlet;
import server.Request;
import server.Response;
/**
* 抽象为一个父类
* @author DUGAN
*
*/
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;
}
WEB_INFO包
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
<url-pattern>/log</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>reg</servlet-name>
<servlet-class>servlet.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>reg</servlet-name>
<url-pattern>/reg</url-pattern>
</servlet-mapping>
</web-app>
测试文件
text.html
<html>
<head>
<title>登录</title>
</head>
<body>
<form method="post" action="http://localhost:8888/log">
用户名:<input type="text" name="uname" id="uname"/>
密码:<input type="password" name="pwd" id="pwd"/>
<input type="submit" value="登录"/>
</form>
</body>
</html>
测试实例
首先启动server,(Server.java是main的入口,可以直接启动该文件),打开text.html
因为在servlet包中的LoginServlet.java中设置了一个唯一正确的账号和密码
所以呢,如果你输入的账号秘密不这个,点击登录会显示
否则则会是这个的页面
补充相关姿势
get/post请求方式
<html>
<head>
<title>第一个表单</title>
</head>
<body>
<pre>
method:请求方式 get/post
get: 默认方式,数据量小,安全性不高
post:量大,安全性相对高
action:请求的服务器路径
id:编号,前端区分唯一性 ,js中使用
name:名称,后端(服务器)区分唯一性 ,获取值
只要提交数据给后台,必须存在name
</pre>
<form method="post/get" action="http://localhost:8888/index.html">
用户名:<input type="text" name="uname" id="uname"/>
密码:<input type="password" name="pwd" id="pwd"/>
<input type="submit" value="登录"/>
</form>
</body>
</html>
post的请求方式:
POST /index.html HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, */*
Accept-Language: zh-CN
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240
Accept-Encoding: gzip, deflate
Host: localhost:8888
Content-Length: 17
Connection: Keep-Alive
Cache-Control: no-cache
uname=123&pwd=123
====================================================================================================================
get的请求方式:
GET /index.html?uname=bjsxt&pwd=123456 HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240
Accept-Encoding: gzip, deflate
Host: localhost:8888
Connection: Keep-Alive
HTTP响应格式及相关
HTTP响应格式
三部分:
1)HTTP协议版本、状态代码、描述
2)响应头(Response Head)
3)响应正文(Response Content)
例子:
HTTP/1.1 200 OK
Server:Apache Tomcat/6.0.12
Date:Mon,6Pct2012 16:36:42 GMT
Content-type:text/html:charset=GBK
Content-Length:112
<html><head>
<title>HTTP响应实例<title>
</head>
<body>Hello Tomcat!</body>
</html>
常见响应HTTP应答码:
200 OK
404 资源不存在
500 服务器错误
常见类型
Content-type:text/html:charset=GBK html
Content-type:text/plain:charset=GBK 纯文本
Content-type:text/cation:charset=GBK 下载 流
多请求处理——反射
上述项目中运用到了反射的方法,这里用例子表示
package reflect;
/**
* 获取结构信息Class对象(源头)
* @author DUGAN
*
*/
public class Demo01 {
public static void main(String[] args) {
String str = "abc";
//Class对象
//对象.getclass()
Class<?> clz = str.getClass();
//类.class
clz = String.class;
//完整路径
try {
clz = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
package reflect;
import server.Servlet;
/**
* 常见实例 调用空构造
* @author DUGAN
*
*/
public class Demo02 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Class<?> clz = Class.forName("server.LoginServlet");
//调用空构造 确保空构造存在
Servlet ser = (Servlet) clz.newInstance();
//return ser
}
}
xml配置文件解析
同样也是个栗子
ParseDemo01.java
package xml;
import java.io.IOException;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
public class ParseDemo01 {
/**
* @param args
* @throws SAXException
* @throws ParserConfigurationException
* @throws IOException
*/
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
//1、获取解析工厂
SAXParserFactory factory=SAXParserFactory.newInstance();
//2、从解析工厂获取解析器
SAXParser parse =factory.newSAXParser();
//3、加载文档 Document 注册处理器
//4、编写处理器
PersonHandler handler=new PersonHandler();
parse.parse(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("xml/person.xml")
,handler );
List<Person> persons =handler.getPersons();
for(Person p:persons){
System.out.println(p.getName()+"-->"+p.getAge());
}
}
}
Person.java
package xml;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
PersonHandler.java
package xml;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* 存储对象
* @author Administrator
*
*/
public class PersonHandler extends DefaultHandler {
private List<Person> persons;
private Person person;
private String tag;//记录标签名
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
//System.out.println("处理文档开始");
persons =new ArrayList<Person>();
}
@Override
public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {
System.out.println("开始一个元素" +qName);
if(null!=qName){
tag=qName;
}
if(null!=qName && qName.equals("person")){
person =new Person();
}
}
@Override
public void characters(char[] ch, int start, int length)throws SAXException {
String str =new String(ch,start,length);
if(null!=tag && tag.equals("name")){
//System.out.println(new String(ch,start,length));
person.setName(str);
}else if(null!=tag && tag.equals("age")){
Integer age = Integer.valueOf(str);
person.setAge(age);
}
}
@Override
public void endElement(String uri, String localName, String qName)throws SAXException {
//System.out.println("结束一个元素" +qName);
if(qName.equals("person")){
this.persons.add(person);
}
tag =null;
}
@Override
public void endDocument() throws SAXException {
System.out.println("文档处理结束");
}
public List<Person> getPersons() {
return persons;
}
public void setPersons(List<Person> persons) {
this.persons = persons;
}
}
person.xml
<?xml version="1.0" encoding="UTF-8" ?>
<persons>
<person>
<name>至尊宝</name>
<age>9000</age>
</person>
<person>
<name>白晶晶</name>
<age>7000</age>
</person>
</persons>