反射入門
- 把java類中的各種結構(方法、屬性、構造器、類名)映射成一個個的Java對象,利用反射技術可以對一個類進行剖析。框架設計常用反射
- 可以通過字符串的方式或得類,創建對象
- 獲得Class對象Class.forName(“包名.類名”),
- 使用無參構造器創建對象 (Iphone) classObj.getConstructor().newInstance();
package server.basic;
import java.lang.reflect.InvocationTargetException;
public class TestReflection {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//獲取Class對象 三種方式
// 1 對象.getClass
Iphone r = new Iphone();
Class classObj = r.getClass();
System.out.println(classObj);
//2 類.class
classObj = Iphone.class;
//3 Class.forName("包名.類名")
classObj = Class.forName("server.basic.Iphone");
//解析Class對象
//1 創建對象,java9不推薦
Iphone t = (Iphone) classObj.newInstance();
//2 創建對象的另一種方式,使用構造器,無參數構造器和帶參數構造器
Iphone iphone7 = (Iphone) classObj.getConstructor().newInstance();
System.out.println(iphone7);
iphone7 = (Iphone) classObj.getConstructor(double.class).newInstance(1000);
System.out.println(iphone7);
}
}
class Iphone{
double price;
public Iphone(){
}
public Iphone(double price) {
this.price = price;
}
@Override
public String toString() {
return "Price is "+price;
}
}
XML解析
- 可擴展標記語言
- 解析方式SAX流解析、DOM文檔解析樹。
解析簡單的xml文件
- SAX解析示例,一個xml有person的標籤,分別有name和age兩個字段。將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>
- SAX解析
package server.basic;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class TestXml1 {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
//1 獲取解析工廠
SAXParserFactory factory = SAXParserFactory.newInstance();
//2 從解析工廠獲取解析器
SAXParser parse = factory.newSAXParser();
//3 編寫處理器
//4 加載文檔Document註冊處理器
PersonHandler handler = new PersonHandler();
//5 解析server/basic/p.xml
String xmlPath = "src/main/java/server/basic/p.xml";
FileInputStream fis = new FileInputStream(xmlPath);
parse.parse(fis,handler);
List<Person> persons = handler.getPersons();
for(Person p:persons){
System.out.println(p.getName()+"--->"+p.getAge());
}
}
}
class PersonHandler extends DefaultHandler{
private List<Person> persons; //多個Person的容器
private Person person;
private String tag; //當前操作的標籤
@Override //開始解析xml文檔
public void startDocument() throws SAXException {
System.out.println("開始解析");
persons = new ArrayList<Person>(); //初始化容器
}
@Override //開始解析元素,qName是標籤名稱
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println(qName+"解析開始");
if(null != qName){ //保存tag
tag = qName;
if(tag.equals("person")){ //如果是person標籤就創建person對象
person = new Person();
}
}
}
@Override //讀取內容
public void characters(char[] ch, int start, int length) throws SAXException {
String str = new String(ch,start,length).trim();
// if(str.length()>0) {
// System.out.println("內容爲----->" + str.trim());
// }else {
// System.out.println("內容爲空---");
// }
if(tag != null) {
if (tag.equals("name")) {
person.setName(str);
} else if (tag.equals("age")) {
person.setAge(Integer.valueOf(str));
}
}
}
@Override //結束解析元素
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println(qName+"解析結束");
if(qName != null){
if(qName.equals("person")){ //如果再次碰到person標籤就添加到容器中
persons.add(person);
}
}
tag = null; //解析完成爲了防止後一個標籤的空格的影響,將tag賦值爲null
}
@Override //結束解析文檔
public void endDocument() throws SAXException {
System.out.println("解析結束");;
}
//獲取存數據的容器
public List<Person> getPersons() {
return persons;
}
}
class Person{
private String name;
private int age;
public Person(){
}
public Person(String name, int age) {
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;
}
}
解析webxml
- 根據不同的pattern找到對應的類.servlet-mapping的url-pattern爲網址的後綴,根據這個找到servlet-name,再根據servlet-name找到servlet下的servlet-class標籤裏的包.類名,再利用反射根據這個類創建對象,執行相應的操作
- web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>server.basic2.LoginServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>reg</servlet-name>
<servlet-class>server.basic2.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>
- Entity.java。對應servlet
package server.basic2;
/**
* <servlet>
* <servlet-name>login</servlet-name>
* <servlet-class>com.sxt.server.basic.servlet.LoginServlet</servlet-class>
* </servlet>
*/
public class Entity {
private String name;
private String clz;
public Entity(){
}
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對應xml中的servlet-mapping,pattern可能有多個,因此pattern放到集合中
package server.basic2;
import java.util.HashSet;
import java.util.Set;
public class Mapping {
private String name;
private Set<String> patterns;
public Mapping(){
patterns = new HashSet<>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<String> getPatterns() {
return patterns;
}
public void setPatterns(Set<String> patterns) {
this.patterns = patterns;
}
public void addPattern(String pattern){
this.patterns.add(pattern);
}
}
- TestXml2.java負責解析xml並完成響應,主要
package server.basic2;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class TestXml2 {
public static void main(String[] args) throws Exception {
//1 獲取解析工廠
SAXParserFactory factory = SAXParserFactory.newInstance();
//2 從解析工廠獲取解析器
SAXParser parse = factory.newSAXParser();
//3 編寫處理器
//4 加載文檔Document註冊處理器
WebHandler handler = new WebHandler();
//5 解析server/basic/p.xml
String xmlPath = "src/main/java/server/basic2/web.xml";
FileInputStream fis = new FileInputStream(xmlPath);
parse.parse(fis,handler);
List<Entity> entities = handler.getEntities();
List<Mapping> mappings = handler.getMappings();
//打印內容
for(Entity p:entities){
System.out.println(p.getName()+"--->"+p.getClz());
//login--->server.basic2.LoginServlet
//reg--->server.basic2.RegisterServlet
}
for(Mapping m:mappings){
System.out.println(m.getName()+"--->"+m.getPatterns());
//login--->[/login, /g]
//reg--->[/reg]
}
//下面開始操作
//獲取映射關係
WebContent web = new WebContent(entities,mappings);
//模擬輸入,假設輸入了/login /g或者 /reg
String className = web.getClz("/reg");
System.out.println(className);
//利用反射獲取到類
Class clz = Class.forName(className);
//實例化,使用接口類型
Serverlet servlet = (Serverlet)clz.getConstructor().newInstance();
//提供服務
servlet.service();
}
}
class WebHandler extends DefaultHandler{
private List<Entity> entities = new ArrayList<>();; //多個Person的容器
private List<Mapping> mappings = new ArrayList<>(); //多個Person的容器
private Entity entity;
private Mapping mapping;
private String tag; //當前操作的標籤
private boolean isMapping = false; //操作serverlet還是mapping
@Override //開始解析元素,qName是標籤名稱
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println(qName+"解析開始");
if(null != qName){ //保存tag
tag = qName;
if(tag.equals("servlet")){ //如果是servlet標籤就創建eneity對象
entity = new Entity();
isMapping = false;
}else if(tag.equals("servlet-mapping")){
mapping = new Mapping();
isMapping = true;
}
}
}
@Override //讀取內容
public void characters(char[] ch, int start, int length) throws SAXException {
String str = new String(ch,start,length).trim();
// if(str.length()>0) {
// System.out.println("內容爲----->" + str.trim());
// }else {
// System.out.println("內容爲空---");
// }
if(tag != null) {
if (isMapping) { //操作mapping
if(tag.equals("servlet-name")){
mapping.setName(str);
}else if(tag.equals("url-pattern")){
mapping.addPattern(str);
}
} else { //操作servlet
if(tag.equals("servlet-name")){
entity.setName(str);
}else if(tag.equals("servlet-class")){
entity.setClz(str);
}
}
}
}
@Override //結束解析元素
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println(qName+"解析結束");
if(qName != null){
if(qName.equals("servlet")){ //如果再次碰到person標籤就添加到容器中
entities.add(entity);
}else if(qName.equals("servlet-mapping")){
mappings.add(mapping);
}
}
tag = null; //解析完成爲了防止後一個標籤的空格的影響,將tag賦值爲null
}
//生成getter方法
public List<Entity> getEntities() {
return entities;
}
public List<Mapping> getMappings() {
return mappings;
}
}
- Serverlet.java接口,xml中的類servlet-class對應的接口
package server.basic2;
public interface Serverlet {
void service();
}
- 兩個實現類,servlet-class的兩個類
- LoginServlet.java
package server.basic2;
public class LoginServlet implements Serverlet {
@Override
public void service() {
System.out.println("登錄");
}
}
- RegisterServlet
package server.basic2;
public class RegisterServlet implements Serverlet {
@Override
public void service() {
System.out.println("註冊");
}
}
html
- 超文本標記語言,瀏覽器用
<html>
<head>
<title>第一個html登錄</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協議
獲取請求協議
- 獲取get或post的請求協議
package server.myserver;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 瀏覽器輸入http://locolhost:8889
* 端口號,接收
*/
public class Server01 {
ServerSocket serverSocket;
public static void main(String[] args) throws IOException {
Server01 server = new Server01();
server.start();
}
//啓動服務
public void start() throws IOException {
serverSocket = new ServerSocket(8889);
receive();
}
//接受
public void receive() throws IOException {
Socket client = serverSocket.accept();
System.out.println("一個客戶端建立了連接");
//獲取請求協議,get方式可以通過瀏覽器直接訪問,get/post方式通過運行login.html訪問
InputStream is = client.getInputStream();
byte[] data = new byte[1024*1024];
int len = is.read(data); //一次性讀取存入data
String requestinfo = new String(data,0,len);
System.out.println(requestinfo);
}
//停止服務
public void stop(){
}
}
- get的請求協議
GET /index.html?uname=123&paswrd=10000 HTTP/1.1
Host: localhost:8889
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3314.0 Safari/537.36 SE 2.X MetaSr 1.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _ga=GA1.1.1809456532.1578749380
- post的請求協議,數據在最後空白行後面
POST /index.html HTTP/1.1
Host: localhost:8889
Connection: keep-alive
Content-Length: 19
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3706.400 SLBrowser/10.0.3974.400
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _ga=GA1.1.2136018396.1577101129
uname=fda&pwd=34567
返回響應協議
- 主要處理responseInfo,包括響應行,響應頭和正文。正文前面空一行。
BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
bw.write(responseInfo.toString());
bw.flush();
package server.myserver;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
/**
* 返回響應協議
* 瀏覽器輸入http://locolhost:8889/index.html?uname=werg&passwd=2344
* 創建ServerSocket,建立連接獲取Socket,通過輸入流獲取請求協議
*/
public class Server02 {
ServerSocket serverSocket;
public static void main(String[] args) throws IOException {
Server02 server = new Server02();
server.start();
}
//啓動服務
public void start() throws IOException {
serverSocket = new ServerSocket(8889);
receive();
}
//接受
public void receive() throws IOException {
Socket client = serverSocket.accept();
System.out.println("一個客戶端建立了連接");
//獲取請求協議,get方式可以通過瀏覽器直接訪問,get/post方式通過運行login.html訪問
InputStream is = client.getInputStream();
byte[] data = new byte[1024*1024];
int len = is.read(data); //一次性讀取存入data
String requestinfo = new String(data,0,len);
System.out.println(requestinfo);
//返回響應信息
//1 響應行
//2 響應頭,最後一行是空行
//3 正文
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("中國必勝,武漢必勝。。。。");
content.append("</body>");
content.append("</html>");
int size = content.toString().getBytes().length; //必須獲取字節長度
StringBuilder responseInfo =new StringBuilder();
String blank =" ";
String CRLF = "\r\n";
//返回
//1、響應行: HTTP/1.1 200 OK
responseInfo.append("HTTP/1.1").append(blank);
responseInfo.append(200).append(blank);
responseInfo.append("OK").append(CRLF);
//2、響應頭(最後一行存在空行):
/*
Date:Mon,31Dec209904:25:57GMT
Server:shsxt Server/0.0.1;charset=GBK
Content-type:text/html
Content-length:39725426
*/
responseInfo.append("Date:").append(new Date()).append(CRLF);
responseInfo.append("Server:").append("myserver Server/0.0.1;charset=GBK").append(CRLF);
responseInfo.append("Content-type:text/html").append(CRLF);
responseInfo.append("Content-length:").append(size).append(CRLF);
responseInfo.append(CRLF);
//3、正文
responseInfo.append(content.toString());
//寫出到客戶端
BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
bw.write(responseInfo.toString());
bw.flush();
}
//停止服務
public void stop(){
}
}
封裝的響應
- 將響應頭放到一個類中,直接傳遞響應代碼和相應內容,進行響應。使用時只關注內容和狀態碼
- Response.java
package server.myserver;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Date;
public class Response {
//用於返回
private BufferedWriter bw;
//正文
private StringBuilder content;
//協議頭
private StringBuilder headInfo;
private int len; //正文的字節長度
private final String BLANK = " ";
private final String CRLF = "\r\n";
private Response(){ //這個構造器私有,只能自己調用
content = new StringBuilder();
headInfo = new StringBuilder();
len = 0;
}
public Response(Socket client) throws IOException {
this();
bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
}
public Response(OutputStream os){
this();
bw = new BufferedWriter(new OutputStreamWriter(os));
}
//構建頭信息,包括響應行和響應頭
private void createHeadInfo(int code){
//1 響應行
headInfo.append("HTTP/1.1").append(BLANK);
headInfo.append(code).append(BLANK);
switch (code){
case 200:
headInfo.append("OK").append(CRLF);
break;
case 404:
headInfo.append("NOT FOUND").append(CRLF);
break;
case 505:
headInfo.append("SERVER ERROR").append(CRLF);
break;
}
//2 響應頭,最後是個空行
headInfo.append("Date:").append(new Date()).append(CRLF);
headInfo.append("Server:").append("shsxt Server/0.0.1;charset=GBK").append(CRLF);
headInfo.append("Content-type:text/html").append(CRLF);
headInfo.append("Content-length:").append(len).append(CRLF);
headInfo.append(CRLF);
}
//動態添加 3內容,返回對象本身,可以鏈式調用
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;
}
// 推送信息,返回到瀏覽器,
public void pushToBrowser(int code) throws IOException {
if(null == headInfo){
code = 505;
}
createHeadInfo(code);
bw.append(headInfo);
bw.append(content);
bw.flush();
}
}
- 使用
package server.myserver;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 封裝響應協議
* 瀏覽器輸入http://locolhost:8889/index.html?uname=werg&passwd=2344
* 創建ServerSocket,建立連接獲取Socket,通過輸入流獲取請求協議
*/
public class Server03 {
ServerSocket serverSocket;
public static void main(String[] args) throws IOException {
Server03 server = new Server03();
server.start();
}
//啓動服務
public void start() throws IOException {
serverSocket = new ServerSocket(8889);
receive();
}
//接受
public void receive() throws IOException {
Socket client = serverSocket.accept();
System.out.println("一個客戶端建立了連接");
//返回響應信息
Response response = new Response(client);
response.print("<html>");
response.print("<head>");
response.print("<title>");
response.print("服務器響應成功");
response.print("</title>");
response.print("</head>");
response.print("<body>");
response.print("中國必勝,武漢必勝。。。。");
response.print("</body>");
response.print("</html>");
response.pushToBrowser(200);
}
//停止服務
public void stop(){
}
}