文章目录
前言
java高淇300集的251 - 269 知识整理
反射
反射:把java类中的各种结构(方法,属性,构造器,类名)映射成一个个的java对象
反射是框架设计的灵魂
获取class对象 三种方式
//三种方式获取class对象
//1 getClass
Iphone iphone = new Iphone();
Class clz = iphone.getClass();
//2类.class()
clz = Iphone.class;
//3.Class.forName("包名.类名");
clz = Class.forName("basic.Iphone");
推荐第三种 因为第三个传字符串即可,不需要建立一个实类然后才建立Class
可以动态创建对象
获取到Class对象后可以创建:
Iphone iphone2 = (Iphone)clz.getConstructor().newInstance();
XML解析
推荐SAX解析,流解析
解析步骤:
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
//SAX解析
//1、获取解析工厂
SAXParserFactory factory=SAXParserFactory.newInstance();
//2、从解析工厂获取解析器
SAXParser parse =factory.newSAXParser();
//3、编写处理器 对PersonHandler进行对接DefalutHandler接口
//4、加载文档 Document 注册处理器
PersonHandler handler=new PersonHandler();
//5、解析
parse.parse(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("basic/p.xml")
,handler);
}
}
class PersonHandler extends DefaultHandler{
@Override
public void startDocument() throws SAXException {
System.out.println("解析文档开始");
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
System.out.println(qName+"解析标签开始");
}
public void characters(char[] ch, int start, int length) throws SAXException {
String contens = new String (ch,start,length).trim();
if(contens.length()>0)
System.out.println("内容为:"+contens);
else
System.out.println("空");
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println(qName+"解析结束");
}
@Override
public void endDocument() throws SAXException {
System.out.println("解析文档结束");
super.endDocument();
}
}
得到解析出来的数据后:
数据处理
在处理器类中加入容器,对象,和标识
private List<Person> persons;
private Person person;
private String tag; 存储操作标签
在每一次解析开始时建立容器对象
public void startDocument() throws SAXException {
persons = new ArrayList<Person>();
}
每一次读取标签时判断是不是person对象,是则创建一个新的对象
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
tag = qName; 存储标签名
if(tag.equals("person")) 如果是对象则建立新的存入容器中
person = new Person();
}
对内容的标识也要判断,
如果是属性名,则对当前的person对象的属性赋值,如果当前的标识是空的,则不赋值
内容识别标签储存对应的属性值
public void characters(char[] ch, int start, int length) throws SAXException {
String contents = new String (ch,start,length).trim();
if(null!=tag) { 空指针就不进行赋值
if(tag.equals("name")) {
person.setName(contents);
}
else if(tag.equals("age")) {
if(contents.length()>0)
person.setAge(Integer.valueOf(contents));
}
}
}
为了防止结束语后的空字符串影响赋值,则每次结束时对当前的tag制空。而且如果是对象名,则把对象存入容器中。
public void endElement(String uri, String localName, String qName) throws SAXException {
if(qName!=null) {
if(qName.equals("person"))
persons.add(person);
}
tag = null; 丢弃掉,防止对空字符串覆盖在属性上
}
较为复杂的XML解析
XML源码:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>servlet.LoginServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>reg</servlet-name>
<servlet-class>servlet.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
<url-pattern>/g</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>reg</servlet-name>
<url-pattern>/reg</url-pattern>
</servlet-mapping>
</web-app>
像这种有两个类对象的,则需要建立两个容器,在解析的时候对标签名进行判断,建立对应的对象存入对应的属性值。
下面是处理器的代码逻辑,可以利用内置的get方法对存好的容器进行调用方便后面解析数据:
class WebHandler extends DefaultHandler{
private List<Entity> entitys;
private List<Mapping> mappings;
private Entity entity;
private Mapping mapping;
private String tag; //存储操作标签
private boolean isMapping = true;
@Override
public void startDocument() throws SAXException {
entitys = new ArrayList<Entity>();
mappings = new ArrayList<Mapping>();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
tag = qName; //存储标签名
if(tag.equals("servlet")) //如果是对象则建立新的存入容器中
{ entity = new Entity();
isMapping = false;
}
else if(tag.equals("servlet-mapping")) {
mapping = new Mapping();
isMapping = true;
}
}
//内容识别标签储存对应的属性值
public void characters(char[] ch, int start, int length) throws SAXException {
String contents = new String (ch,start,length).trim();
if(null!=tag) { //空指针就不进行赋值
if(isMapping) { //操作servlet-mapping
if(tag.equals("servlet-name")) {
mapping.setName(contents);
}
else if(tag.equals("url-pattern")) {
mapping.addPattern(contents);
}
}else { //操作serlet
if(tag.equals("servlet-name")) {
entity.setName(contents);
}
else if(tag.equals("servlet-class")) {
if(contents.length()>0)
entity.setClz(contents);
}
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if(qName!=null) {
if(qName.equals("servlet"))
entitys.add(entity);
else if(qName.equals("servlet-mapping"))
mappings.add(mapping);
}
tag = null; //丢弃掉,防止对空字符串覆盖在属性上
}
public List<Entity> getEntitys() {
return entitys;
}
public List<Mapping> getMappings() {
return mappings;
}
}
反射XML文件
解析完成的XML文件,在servlet中,
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>servlet.LoginServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>reg</servlet-name>
<servlet-class>servlet.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
<url-pattern>/g</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>reg</servlet-name>
<url-pattern>/reg</url-pattern>
</servlet-mapping>
</web-app>
一般在URL后面加入/g或则/reg,这些就是为了服务器找到对应的类对象,比如/g可以找到mapping内对应的login,login可以在上面的servlet标签内对应到servlet-class,也就是loginservelt对象。
根据输入不同的值可以找到不同的类对象,就可以调用getclassname()反射出不同的对象。
这里我们新建一个WebContext 类处理保存好的两个容器。
在类内主要逻辑是:
建立两个Map容器,把servelt和mapping这两个类存入map容器中。
servlet的Map容器的 key是servlet-name value是servlet-class
mapping的Map容器的 key是pattern value是servlet-name
然后调用关键函数就可以达到传入pattern,返回对应的类名的功能。
//通过url的路径找到对应的class
public String getClz(String pattern) {
return entityMap.get(mappingMap.get(pattern));
}
WebContents:
package servlet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class WebContext {
private List<Entity> entities =null;
private List<Mapping> mappings =null;
// servlet-name-->class路径
private Map<String, String> entityMap = new HashMap<>();
// url路径-->servlet-name
private Map<String, String> mappingMap = new HashMap<>();
public WebContext(List<Entity> entities ,List<Mapping> mappings) {
this.entities = entities;
this.mappings = mappings;
//将entityList转成对应的map
for(Entity entity : entities) {
entityMap.put(entity.getName(), entity.getClz());
}
for(Mapping mapping : mappings) {
for(String pattern : mapping.getPattern()) {
mappingMap.put(pattern, mapping.getName());
}
}
}
//通过url的路径找到对应的class
public String getClz(String pattern) {
return entityMap.get(mappingMap.get(pattern));
}
}
使用方法:
WebContext webContext = new WebContext(handler.getEntitys(), handler.getMappings());
String classForName = webContext.getClz("/reg");
Class clazz = Class.forName(classForName);
Servlet servlet = (Servlet)clazz.getConstructor().newInstance();
servlet.service();
HTML入门:
<html>
<head>
<title>登录</title>
</head>
<body>
<h1>表单的使用</h1>
<pre>
post:提交 ,基于http协议不同 量大 请求参数url不可见 安全<br/>
get: 默认,获取,基于http协议不同 量小 请求参数url可见 不安全<br/>
action: 请求web服务器的资源 URL<br/>
name:作为后端使用,区分唯一: 请求服务器,必须存在,数据不能提交<br/>
id: 作为前端使用,区分唯一<br/>
</pre>
<form method="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>
HTTP协议
HTTP:Hyper Text Transfer Protocol 超文本传输协议
请求协议
1.请求行:方法(GET/POST)URI 协议/版本
2.请求头:(Request Header)
3.请求正文
响应协议
1.状态行:协议\版本、状态码、状态描述
2.响应头:(Response Header)
3.响应正文
RESTer插件:
测试URL功能的POST和GET:
获取请求协议
Socket client = server.accept();
System.out.println("一个客户端建立了连接");
//获取请求协议
InputStream is = client.getInputStream();
byte [] datas = new byte[1024*1024];
int len = is.read(datas);
String request = new String (datas,0,len);
System.out.println(request);
发送响应协议
要按照特定的格式,注意空格和换行,响应头和正文之间有空行
StringBuilder content = new StringBuilder();
content.append("<html>");
content.append("<head>");
content.append("<title>");
content.append("服务器响应成功");
content.append("<title>");
content.append("</head>");
content.append("<body>");
content.append("server终于回来了呢");
content.append("</body>");
content.append("<html>");
必须获取字节长度
int size = content.toString().getBytes().length;
StringBuilder responselInfo = new StringBuilder();
String blank = " ";
String CRLF = "\r\n";
返回
1.响应的状态行:HTTP/1.1 200 OK
responselInfo.append("HTTP/1.1").append(blank);
responselInfo.append(200).append(blank);
responselInfo.append("OK").append(CRLF);
2.响应头:(最后一行存在空行)
responselInfo.append("Data:").append(new Date()).append(CRLF);
responselInfo.append("Server:").append("YUAN Server/0.0.1;charset=GBK").append(CRLF);
responselInfo.append("Content-type:text/html").append(CRLF);
responselInfo.append("Content-length:").append(size).append(CRLF);
responselInfo.append(CRLF);
3.正文
responselInfo.append(content.toString());
写出到客户端
BufferedWriter br = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
br.write(responselInfo.toString());
br.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("客户端错误");
}
}
响应信息封装
封装成response类,只需要关注正文内容和状态码,其他头信息不用修改。
package server;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Date;
public class Response {
BufferedWriter bw;
//正文
private StringBuilder content;
//协议头(状态行,请求,回车)信息
private StringBuilder head;
private int len;
String blank = " ";
String CRLF = "\r\n";
public Response() {
content = new StringBuilder();
head = new StringBuilder();
len = 0;
}
public Response(Socket client) {
this();
try {
bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
} catch (IOException e) {
head = null;
}
}
//动态添加内容
public Response print(String info) {
content.append(info);
len+=info.getBytes().length;
return this;
}
//构建头信息
private void creatHead(int code) {
//1.响应的状态行:HTTP/1.1 200 OK
head.append("HTTP/1.1").append(blank);
head.append(code).append(blank);
switch (code) {
case 200:head.append("OK").append(CRLF);
break;
case 404:head.append("Not Found").append(CRLF);
break;
case 505:head.append("Server Error").append(CRLF);
break;
}
//2.响应头:(最后一行存在空行)
head.append("Data:").append(new Date()).append(CRLF);
head.append("Server:").append("YUAN Server/0.0.1;charset=GBK").append(CRLF);
head.append("Content-type:text/html").append(CRLF);
head.append("Content-length:").append(len).append(CRLF);
head.append(CRLF);
}
//推送响应 消息,把head和content两个字符集传入输出流内
public void push(int code) {
if(null == head)
code = 505;
creatHead(code); //构建头信息,传入head内
try {
bw.append(head); //导入头信息到输出流
bw.append(content); //在server类内已经导入数据流入content内,所以直接导入输出流
bw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
响应协议的封装是比较容易的,同样的对获得的请求协议也需要封装,请求协议文件如下:
请求协议封装
请求协议文件如下:
POST /cacc?uname=acjefe HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Content-Length: 12
sec-ch-ua: “Google Chrome”;v=“89”, “Chromium”;v=“89”, “;Not A Brand”;v=“99”
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36
Content-Type: text/plain;charset=UTF-8
Accept: /
Origin: chrome-extension://eejfoncpjfgmeleakejdcanedmefagga
Sec-Fetch-Site: none
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
zevfd=vvbtrb
先把上面的字符存入一个字符数组,然后找指定位置切割获取不同的数据:
获取请求方式 开头 到 第一个/"
获取请求url 第一个/ 到 HTTP/
可能包含请求参数 ?后面
如果包含参数则需要对已经获取的字符串进行分割,前半部分是url后半部分是参数
post的参数不止在?后面,在正文的最后一行也有出现,所以需要判断是否为post来确定要不要切割
System.out.println("获取请求方式:开头 到 第一个/");
this.method = this.request.substring(0,this.request.indexOf("/")).toLowerCase();
this.method = this.method.trim();
System.out.println(method);
System.out.println("获取请求url:第一个/ 到 HTTP/");
System.out.println("可能包含请求参数?前面的为url");
//获取第一个/的位置
int idx1 = this.request.indexOf("/")+1;
//获取HTTP位置
int end1 = this.request.indexOf("HTTP/");
//分割字符串
this.uri = this.request.substring(idx1,end1);
System.out.println(this.uri);
//获取?的位置
int query = this.uri.indexOf("?");
if(query>=0) {//存在请求参数
String[] urlArray = this.uri.split("\\?");
this.uri = urlArray[0];
queryStr = urlArray[1].trim();
}
System.out.println(this.uri);
System.out.println("获取请求参数:如果是GET已经获取,如果是POST可能在请求体中");
if(method.equals("post")) {
String qStr = this.request.substring(this.request.lastIndexOf(CRLF)).trim();
if(null==queryStr) {
queryStr = qStr;
}else {
queryStr+="&"+qStr;
}
}
System.out.println(method+"-->"+uri+"-->"+queryStr);
获取完数据后,需要处理的是参数,因为有多个参数,所以需要存入Map内,因为可能一个name有多个属性值,所以Map的建立应该是:
private Map<String,List<String>> parameterMap;
下面在函数内对参数进行存入Map中:
private void convertMap() {
//分割字符串 按 &
String[] keyValues = this.queryStr.split("&");
for(String query:keyValues) {
//再次分割字符串 按 =
String[] kv = query.split("=");
kv = Arrays.copyOf(kv,2);
//获取key和value
String key = kv[0];
String value =kv[1]=decode(kv[1]);
//存储到Map中
if(!parameterMap.containsKey(key)) { //判断当前的key是否存在,如果不存在就新建一个容器
parameterMap.put(key, new ArrayList<String>());
}
parameterMap.get(key).add(value); //直接把value放入容器中
}
}
最后设置关键get函数以便调用此类来直接获取需要的数据:
//通过name获取对应的多个属性值 一对多,需要输出多个值
public String [] getParameterValues(String key){
List<String> list = this.parameterMap.get(key);
if(null==list||list.size()<1) {
return null;
}
return list.toArray(new String[0]);
}
public String getParameter(String key){ //处理一对一的值
String[] values = getParameterValues(key);
return values == null?null:values[0];
}
请求协议封装源码:
package server;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 封装请求协议:封装请求参数为Map
* @author Little Black
*
*/
public class Request2 {
//协议信息
private String request;
//请求方式
private String method;
//请求URI
private String uri;
//请求参数
private String queryStr;
String CRLF = "\r\n";
//储存参数
private Map<String,List<String>> parameterMap;
public Request2(Socket client) throws IOException{
this(client.getInputStream());
}
public Request2(InputStream is) {
parameterMap = new HashMap<String, List<String>>();
byte [] datas = new byte[1024*1024];
int len;
try {
len = is.read(datas);
request = new String (datas,0,len);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
//分解字符串
parseRequestInfo();
}
private void parseRequestInfo() {
System.out.println("获取请求方式:开头 到 第一个/");
this.method = this.request.substring(0,this.request.indexOf("/")).toLowerCase();
this.method = this.method.trim();
System.out.println(method);
System.out.println("获取请求url:第一个/ 到 HTTP/");
System.out.println("可能包含请求参数?前面的为url");
//获取第一个/的位置
int idx1 = this.request.indexOf("/")+1;
//获取HTTP位置
int end1 = this.request.indexOf("HTTP/");
//分割字符串
this.uri = this.request.substring(idx1,end1);
System.out.println(this.uri);
//获取?的位置
int query = this.uri.indexOf("?");
if(query>=0) {//存在请求参数
String[] urlArray = this.uri.split("\\?");
this.uri = urlArray[0];
queryStr = urlArray[1].trim();
}
System.out.println(this.uri);
System.out.println("获取请求参数:如果是GET已经获取,如果是POST可能在请求体中");
if(method.equals("post")) {
String qStr = this.request.substring(this.request.lastIndexOf(CRLF)).trim();
if(null==queryStr) {
queryStr = qStr;
}else {
queryStr+="&"+qStr;
}
}
System.out.println(method+"-->"+uri+"-->"+queryStr);
//转成Map fav=1&fav=2&uname=shx&age=18&others=
convertMap();
}
private void convertMap() {
//分割字符串 按 &
String[] keyValues = this.queryStr.split("&");
for(String query:keyValues) {
//再次分割字符串 按 =
String[] kv = query.split("=");
kv = Arrays.copyOf(kv,2);
//获取key和value
String key = kv[0];
String value =kv[1]=decode(kv[1]);
//存储到Map中
if(!parameterMap.containsKey(key)) { //判断当前的key是否存在,如果不存在就新建一个容器
parameterMap.put(key, new ArrayList<String>());
}
parameterMap.get(key).add(value); //直接把value放入容器中
}
}
private String decode(String value) { //处理中文
return java.net.URLDecoder.decode(value);
}
//通过name获取对应的多个属性值 一对多,需要输出多个值
public String [] getParameterValues(String key){
List<String> list = this.parameterMap.get(key);
if(null==list||list.size()<1) {
return null;
}
return list.toArray(new String[0]);
}
public String getParameter(String key){ //处理一对一的值
String[] values = getParameterValues(key);
return values == null?null:values[0];
}
}
结合Servlet
既然可以直接获取请求协议的参数的值,我们就可以通过判断得到的值来执行不同的代码:
先设置Login,Register两个类连接Servlet接口,内部设置不同的html画面:
然后在serlvet6中执行:
if(request.getUri().equals("login")) {
Servlet servlet = new LoginServlet();
servlet.service(request, response);
}
else if(request.getUri().equals("over")) {
Servlet servlet = new RegisterServlet();
servlet.service(request, response);
}
至此可以通过传入不同的url来跳转到不同的html中
上面对每一个URL选取不同的Servlet是非常麻烦的,在复杂的应用中,就需要利用到servlet脚本代码和反射来起到以不变应万变
先要引入之前解析xml的处理器解析器等类
Entity,Mapping,WebContext
然后建立一个WebApp类,封装调用上面的方法然后getServlet(String Url)来返回需要的Servlet
import java.lang.reflect.InvocationTargetException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class WebApp {
static WebContext webContext;
static {
try {
//SAX解析
//1、获取解析工厂
SAXParserFactory factory=SAXParserFactory.newInstance();
//2、从解析工厂获取解析器
SAXParser parse =factory.newSAXParser();
//3、编写处理器
//4、加载文档 Document 注册处理器
WebHandler handler=new WebHandler();
//5、解析
parse.parse(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("web.xml")
,handler);
webContext = new WebContext(handler.getEntitys(), handler.getMappings());
}catch(Exception e) {
System.out.println("解析错误");
}
}
通过URL获取配置文件对应的class
public static Servlet getServlet(String url) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
String classForName = webContext.getClz("/"+url);
Class clazz;
try {
clazz = Class.forName(classForName);
Servlet servlet = (Servlet)clazz.getConstructor().newInstance();
return servlet;
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
客户端封装成多线程
public class Dispatcher implements Runnable{
Socket client;
Request request;
Response response;
public Dispatcher(Socket client) {
this.client = client;
try {
//获取请求协议
request = new Request(client);
//响应协议 响应状态行 响应头 空格 正文
response = new Response(client);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
release();
}
}
@Override
public void run() {
//关注内容
try {
String s = request.getUri();
if(s.equals("") || s == null) {
s = "yuan";
}
Servlet servlet = WebApp.getServlet(s);
if(null!=servlet) {
servlet.service(request, response);
//关注状态码
response.push(200);
}
else {
response.print("访问的页面不存在");
response.push(404);
}
} catch (Exception e) {
response.print("no no no");
response.push(500);
}
release();
}
//释放资源
private void release() {
try {
client.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
在Server内就创建多线程
//接收连接
public void receive() {
while(isRunning) {
try {
Socket client = server.accept();
System.out.println("一个客户端建立了连接");
//多线程
new Thread(new Dispatcher(client)).start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("客户端错误");
}
}
至此底层的框架已经构建好了。
以后主要的开发流程就是:
新建一个html文件,在里面的
<form method="get" action="http://localhost:8888/reg">
用户名:<input type="text" name="uname" id="uname"/>
你的兴趣爱好:
<input type = "checkbox" name="like" id="fa" value="0"/>打篮球
<input type = "checkbox" name="like" id="fa" value="1"/>王者荣耀
<input type = "checkbox" name="like" id="fa" value="2"/>打飞机
<input type="submit" value="登录"/>
</form>
主要的内部运行机制:
通过发送请求协议,利用request对请求协议的文件进行字符串截取,获得url。
String s = request.getUri();
url与内部WebApp等类解析好的配置文件内的URL进行比对寻找内部的servlet-class,通过反射获取到对应的对象。
Servlet servlet = WebApp.getServlet(s);
实现已经设置好的对象的service行为,service内就是对响应协议的正文的内容的添加,添加完后就会导入到封装好的响应协议response内。
servlet.service(request, response);
响应协议写好内容后就push出去,加上状态码,其他的内容已经在response内封装好,遵守响应协议的格式,传给客户端返回内容。
response.push(200);
public void run() {
//关注内容
try {
String s = request.getUri();
if(s.equals("") || s == null) {
s = "yuan";
}
Servlet servlet = WebApp.getServlet(s);
if(null!=servlet) {
servlet.service(request, response);
//关注状态码
response.push(200);
}
以后的开发流程:
写一个用户界面的HTML,设置请求协议的URL值,在Web.xml中设置好URL要映射的servlet类名和对应的类位置,如下图。 然后就写类的内容,继承Servlet接口,重写内部方法,可调用request获取用户输入的属性的值。