Java web开发——Servlet详细介绍
一、第一個Servlet程序
1、創建Servlet程序
在webapps目錄下新建一個serfis的web應用,在serfis下新建一個WEB-INF\classes,在classes新建servlet(FirstServlet.java)
package com.shen; import java.io.*; import javax.servlet.*;public class FirstServlet extends GenericServlet{public void service(ServletRequest req,ServletResponse res)throws ServletException,java.io.IOException{String data = "hello servlet!!";OutputStream out = res.getOutputStream();out.write(data.getBytes()); } }?
2、編譯Servlet程序
? ? ?在cmd中進入classes目錄,編譯FirstServlet(cd/)
javac -d . FirstServlet.javaset classpath=%classpath%;.............(.......為servlet的jar包存放的路徑,因為默認的jar包只包含javaSE)將jar文件直接拖向cmd窗口3、配置Servlet
? ? ?在serfis\web-inf目錄,新建一個web.xml文件,對servlet進行配置
<web-app xmls="http://java.sun.com/xml/ns/javaee" ?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"version="2.5"><servlet><servlet-name>FirstServlet</servlet-name><!--自己取一個Servlet的名--><servlet-class>com.shen.FirstServlet</servlet-class></servlet><servlet-mapping><servlet-name>FirstServlet</servlet-name><url-pattern>/xxx</url-pattern><表示將該Servlet(FirstServlet)映射到xxx下(因為瀏覽器通過url訪問),/表示當前web項目根目錄></servlet-mapping></web-app>?
4、訪問
? ? ?啟動服務器,在ie輸入http://localhost:8080/serfis/xxx
?
二、Servlet的生命周期
1、詳情說明
1).構造器: 只被調用一次. 只有第一次請求 Servlet 時, 創建 Servlet 的實例. 調用構造器. (這說明 Serlvet 的單實例的!)
2). init 方法: 只被調用一次. 在創建好實例后立即被調用. 用于初始化當前 Servlet.?
3). service: 被多次調用. 每次請求都會調用 service 方法. 實際用于響應請求的.?
4). destroy: 只被調用一次. 在當前 Servlet 所在的 WEB 應用被卸載前調用. 用于釋放當前 Servlet 所占用的資源.?
?
注意:在Servlet的整個生命周期內,Servlet的init方法只被調用一次。而對一個Servlet的每次訪問請求都導致Servlet引擎調用一次servlet的service方法。service對象在servlet生命周期中服務器只創建一次,并存在Tomcat服務器中,之后再調用該service取之前創建好的對象。對于每次訪問請求,Servlet引擎都會創建一個新的HttpServletRequest請求對象和一個新的HttpServletResponse響應對象,然后將這兩個對象作為參數傳遞給它調用的Servlet的service()方法,service方法再根據請求方式分別調用doXXX方法。?
?
2、運行原理
? ??
三、Servlet接口及派生類
1、Servlet接口
1.基本概念
? ? ?Sun公司在其API中提供了一個servlet接口,用戶若想用發一個動態web資源(即開發一個Java程序向瀏覽器輸出數據),需要完成以下2個步驟:
編寫一個Java類,實現servlet接口。
把開發好的Java類部署到web服務器中。
2.程序舉例
public class Servletan implements Servlet {@Overridepublic void destroy() {//web應用被卸載時調用// TODO 自動生成的方法存根System.out.println("destroy");}@Overridepublic ServletConfig getServletConfig() {封裝了Servlet配置,并可以獲取相關內容屬性:servletcontextservletConfig...// TODO 自動生成的方法存根System.out.println("getServletConfig");return null;}@Overridepublic String getServletInfo() {// TODO 自動生成的方法存根System.out.println("getServletInfo");return null;}@Overridepublic void init(ServletConfig arg0) throws ServletException {//用于初始化,只調用一次// TODO 自動生成的方法存根System.out.println("init");}@Overridepublic void service(ServletRequest arg0, ServletResponse arg1)//實際用于響應請求throws ServletException, IOException {// TODO 自動生成的方法存根System.out.println("service");}public void hello(){System.out.println("hello");} }2、HttpServlet實現類
1.基礎概念
? ? ?HttpServlet指能夠處理HTTP請求的servlet,它在原有Servlet接口上添加了一些與HTTP協議處理方法,它比Servlet接口的功能更為強大。因此開發人員在編寫Servlet時,通常應繼承這個類,而避免直接去實現Servlet接口。
? ? ?HttpServlet在實現Servlet接口時,覆寫了service方法,該方法體內的代碼會自動判斷用戶的請求方式,如為GET請求,則調用HttpServlet的doGet方法,如為Post請求,則調用doPost方法。因此,開發人員在編寫Servlet時,通常只需要覆寫doGet或doPost方法,而不要去覆寫service方法。
2.程序舉例
public class HttpServletan extends HttpServlet {@Overridepublic void init(ServletConfig config) throws ServletException {System.out.println("hahhah!!");}public void doGet(HttpServletRequest request, HttpServletResponse response)//get請求的響應throws ServletException, IOException {response.getOutputStream().write("hahhaha".getBytes());}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);//post請求交由get的請求響應}}?
3、GenericServlet實現類
四、servlet的配置
? ? ?在web.xml文件中配置,現有web程序為javaweb,有FirstServlet.java,
1、配置servlet實例
<servlet><!-- Servlet 注冊的名字 --><servlet-name>FirstServlet</servlet-name><!-- Servlet 的全類名 --><servlet-class>com.shen.FirstServlet</servlet-class></servlet>?
注意:可以通過load-on-startup參數來設置Serlvet 被創建的時機(即init()方法被調用的時間):若為負數, 則在第一次請求時被創建.若為 0 或正數, 則在當前 WEB 應用被
Serlvet 容器加載時創建實例, 且數組越小越早被創建.
<servlet><!-- Servlet 注冊的名字 --><servlet-name>FirstServlet</servlet-name><!-- Servlet 的全類名 --><servlet-class>com.shen.FirstServlet</servlet-class><!-- 可以指定 Servlet 被創建的時機 --><load-on-startup>2</load-on-startup></servlet>2、將servlet實例映射到url
1.常規映射
<servlet-mapping><servlet-name>FirstServlet</servlet-name><url-pattern>/a.servlet</url-pattern><!---即通過訪問localhost:8080/javaweb/a.servlet來訪問該servlet--> </servlet-mapping>注意:
1). 同一個Servlet可以被映射到多個URL上,即多個<servlet-mapping>元素的<servlet-name>子元素的設置值可以是同一個Servlet的注冊名。一個Servlet僅僅是為一個頁面進行服務,它本身并不代表一個頁面。
如:
<servlet-mapping><servlet-name>FirstServlet</servlet-name><url-pattern>/a.servlet</url-pattern><!---即通過訪問localhost:8080/javaweb/a.servlet來訪問該servlet--> </servlet-mapping><servlet-mapping><servlet-name>FirstServlet</servlet-name><url-pattern>/b.servlet</url-pattern><!---即通過訪問localhost:8080/javaweb/b.servlet來訪問該servlet--> </servlet-mapping>2.通配映射
? ? ?在Servlet映射到的URL中也可以使用*通配符,但是只能有兩種固定的格式:一種格式是“*.擴展名”,另一種格式是以正斜杠(/)開頭并以“/*”結尾。
//格式1 <servlet-mapping><servlet-name>FirstServlet</servlet-name><url-pattern>*.do</url-pattern><!---即通過訪問localhost:8080/javaweb/fsdf.do來訪問該servlet--> </servlet-mapping>//格式2 <servlet-mapping><servlet-name>FirstServlet</servlet-name><url-pattern>/*</url-pattern><!---即通過訪問localhost:8080/javaweb/fhgdf來訪問該servlet--> </servlet-mapping>注意:
1).?以下的既帶 / 又帶擴展名的不合法.?
<servlet-mapping><servlet-name>secondServlet</servlet-name><url-pattern>/*.action</url-pattern> </servlet-mapping>2). 哪個長得像映射哪個,"/"的優先級高于"*"
如:Servlet1 映射到 /abc/*?
Servlet2 映射到 /*?
Servlet3 映射到 /abc?
Servlet4 映射到 *.do?
?
問題:
當請求URL為“/abc/a.html”,“/abc/*”和“/*”都匹配,哪個servlet響應?
Servlet引擎將調用Servlet1。
當請求URL為“/abc”時,“/abc/*”和“/abc”都匹配,哪個servlet響應?
Servlet引擎將調用Servlet3。
當請求URL為“/abc/a.do”時,“/abc/*”和“*.do”都匹配,哪個servlet響應?
Servlet引擎將調用Servlet1。
當請求URL為“/a.do”時,“/*”和“*.do”都匹配,哪個servlet響應?
Servlet引擎將調用Servlet2。
當請求URL為“/xxx/yyy/a.do”時,“/*”和“*.do”都匹配,哪個servlet響應?
Servlet引擎將調用Servlet2。
3.缺省映射
? ? ?如果某個Servlet的映射路徑僅僅為一個正斜杠(/),那么這個Servlet就成為當前Web應用程序的缺省Servlet。凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它們的訪問請求都將交給缺省Servlet處理,也就是說,缺省Servlet用于處理所有其他Servlet都不處理的訪問請求(如錯誤頁面的處理)。?
<servlet-mapping><servlet-name>FirstServlet</servlet-name><url-pattern>/</url-pattern><!---即可以通過訪問localhost:8080/javaweb/fhgdff'f來訪問該servlet--> </servlet-mapping>注意:在<tomcat的安裝目錄>\conf\web.xml文件中,注冊了一個名稱為org.apache.catalina.servlets.DefaultServlet的Servlet,并將這個Servlet設置為了缺省Servlet。當訪問Tomcat服務器中的某個靜態HTML文件和圖片時,實際上是在訪問這個缺省Servlet(因為一個靜態頁面無需自己再配置一個servlet對其進行進行服務)。
五、servlet線程安全
- 當多個客戶端并發訪問同一個Servlet時,web服務器會為每一個客戶端的訪問請求創建一個線程,并在這個線程上調用Servlet的service方法,因此service方法內如果訪問了同一個資源的話,就有可能引發線程安全問題。
- 如果某個Servlet實現了SingleThreadModel接口,那么Servlet引擎將以單線程模式來調用其service方法。
- SingleThreadModel接口中沒有定義任何方法,只要在Servlet類的定義中增加實現SingleThreadModel接口的聲明即可。對于實現了SingleThreadModel接口的Servlet,Servlet引擎仍然支持對該Servlet的多線程并發訪問,其采用的方式是產生多個Servlet實例對象,并發的每個線程分別調用一個獨立的Servlet實例對象。
- 實現SingleThreadModel接口并不能真正解決Servlet的線程安全問題,因為Servlet引擎會創建多個Servlet實例對象,而真正意義上解決多線程安全問題是指一個Servlet實例對象被多個線程同時調用的問題。因此大多數web是線程不安全的
六、與servlet相關的對象
1、ServletConfig對象
1.介紹
? ? ?當servlet配置了初始化參數后,web容器在創建servlet實例對象時,會自動將這些初始化參數封裝到ServletConfig對象中,并在調用servlet的init方法時,將ServletConfig對象傳遞給servlet。
2.servlet中配置初始化參數
<servlet><servlet-name>helloServlet</servlet-name><servlet-class>com.shen.HelloServlet</servlet-class><!-- 配置 Serlvet 的初始化參數。 且節點必須在 load-on-startup 節點的前面 --><init-param><!-- 參數名 --><param-name>user</param-name><!-- 參數值 --><param-value>root</param-value></init-param><init-param><param-name>password</param-name><param-value>1230</param-value></init-param><load-on-startup>-1</load-on-startup></servlet>?
3.獲取初始化參數
? ? ?從init方法中取出初始化參數
import java.io.IOException; import java.util.Enumeration;import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;public class ConfigServletDemo1 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}@Overridepublic void init(ServletConfig config) throws ServletException {//獲取指定的初始化參數的值String value = config.getInitParameter("user");System.out.printfln(value)//打印出root//獲取所有的初始化參數Enumeration e = config.getInitParameterNames();//Enumeration是一個迭代器while(e.hasMoreElements()){String name = (String) e.nextElement();value = config.getInitParameter(name);System.out.printfln((name + "=" + value + "<br/>").getBytes());//打印出user root password 1230 }}}? ? ?然而事實上大部分都在doXXX方法中取出初始化參數故
public class ConfigServletDemo1 extends HttpServlet {private ServletConfig config;public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//獲取指定的初始化參數String value = config.getInitParameter("xxx");response.getOutputStream().write(value.getBytes());//獲取所有的初始化參數Enumeration e = config.getInitParameterNames();//Enumeration是一個迭代器while(e.hasMoreElements()){String name = (String) e.nextElement();value = config.getInitParameter(name);response.getOutputStream().write((name + "=" + value + "<br/>").getBytes());}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}@Overridepublic void init(ServletConfig config) throws ServletException {this.config = config;}}? ? ?實際上在HttpServlet中重寫了init方法(HttpServler繼承于GenericServlet,GenericServlet重寫了該方法),即同上,故可以在doXXX方法中直接調用ServletConfig
public class ConfigServletDemo2 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {ServletConfig config = this.getServletConfig();System.out.println(config.getInitParameter("user"));//獲取指定的初始化參數String value = config.getInitParameter("user");response.getOutputStream().write(value.getBytes());}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}?
2、ServletContext對象
1.介紹
? ? ?WEB容器在啟動時,它會為每個WEB應用程序都創建一個對應的ServletContext對象,它代表當前web應用。ServletConfig對象中維護了ServletContext對象的引用,開發人員在編寫servlet時,可以通過ServletConfig.getServletContext方法獲得ServletContext對象。由于一個WEB應用中的所有Servlet共享同一個ServletContext對象,因此Servlet對象之間可以通過ServletContext對象來實現通訊。ServletContext對象通常也被稱之為context域對象。
2.servlet間數據共享
案例說明:有ServletDemo1,ServletDemo2,現ServletDemo1有數據data="shsj",將其共享給ServletDemo2。
//多個servlet通過servletContext實現數據共享 public class ServletDemo1 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String data = "shsj";ServletContext context = this.getServletConfig().getServletContext();//一般不用該方法context.setAttribute("datasss", data); //map,將數據data放到關鍵字datasss中}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}} public class ServletDemo2 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {ServletContext context = this.getServletContext();String data = (String) context.getAttribute("datasss");//通過關鍵字獲取數據System.out.println(data);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}3.WEB應用的初始化參數
1.全局初始化參數的配置
<context-param><param-name>url</param-name><param-value>jdbc:mysql://localhost:3306/test</param-value></context-param>?
2.全局初始化參數的獲取
//獲取整個web站點的初始化參數 public class ServletContextDemo3 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {ServletContext context = this.getServletContext();String url = context.getInitParameter("url");System.out.println(url);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}4.實現Servlet的轉發
案例說明:有ServletDemo1,ServletDemo2,現ServletDemo1有請求,將其轉發給ServletDemo2處理。其中ServletDemo2的URL映射為/demo2
//用servletContext實現請求轉發public class ServletDemo1 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {ServletContext context = this.getServletContext();RequestDispatcher rd = context.getRequestDispatcher("/demo2");rd.forward(request, response); //相當于調用ServletDemo2的doget(),故地址欄不變}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}} public class ServletDemo2 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.getOutputStream().write("servletDemo2來處理".getBytes());}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}分析:
如果ServletDemo1為:
//用servletContext實現請求轉發 public class ServletDemo1 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {ServletContext context = this.getServletContext();RequestDispatcher rd = context.getRequestDispatcher("/demo2");rd.forward(request, response); //相當于調用ServletDemo2的doget(),故地址欄不變System.out.println("我也執行了");}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);} }"我也執行了"將也會被打出,因為請求轉發僅僅相當于調用ServletDemo2的doGet方法,如果ServletDemo1為:
//用servletContext實現請求轉發 public class ServletDemo1 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {ServletContext context = this.getServletContext();RequestDispatcher rd = context.getRequestDispatcher("/demo2");rd.forward(request, response); //相當于調用ServletDemo2的doget(),故地址欄不變response.getOutputStream().write("111".getBytes());}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);} }"111"不會被瀏覽器顯示出來,因為response已經被發出一次,不會再發出,如果ServletDemo1為:
//用servletContext實現請求轉發 //注意: //1.轉發之前的所有寫入都無效 //2.轉發之前,response不能提交,否則轉發的時候服務器會拋:Cannot forward after response has been committed public class ServletDemo1 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.getOutputStream().write("111".getBytes());//轉發之前寫入,值被覆蓋/*OutputStream out=getOutputStream();response.out.write("111".getBytes());out.close //"111將會被寫出但報錯"*/ServletContext context = this.getServletContext();RequestDispatcher rd = context.getRequestDispatcher("/demo2");rd.forward(request, response); //相當于調用ServletDemo2的doget(),故地址欄不變}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);} }5.讀取資源文件
? ?有資源文件db.properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/test username=root password=root1.資源文件在src目錄下
//使用servletContext讀取資源文件 public class ServleDemo extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {test2();}//做web工程時,不建議采用傳統方式讀取文件數據public void test1() throws FileNotFoundException {FileInputStream in = new FileInputStream("db.properties");//在tomcat服務器中將db.properties文件拷貝到E:\Tomcat8.5\bin后System.out.println(in);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}//讀取web工程中資源文件的模板代碼,一般就是這個private void test2() throws IOException {InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");//源文件在src目錄下Properties prop = new Properties();prop.load(in);String driver = prop.getProperty("driver");String url = prop.getProperty("url");String username = prop.getProperty("username");String password = prop.getProperty("password");System.out.println(driver);}//通過ServletContext獲取路徑后再采用傳統方式private void test3() throws IOException {//獲取web資源的絕對路徑String path = this.getServletContext().getRealPath("/WEB-INF/classes/db.properties");//在src目錄下FileInputStream in = new FileInputStream(path);Properties prop = new Properties();prop.load(in);String driver = prop.getProperty("driver");System.out.println(driver);}2.資源文件在src目錄下com.shen包下
private void test4() throws IOException {InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/shen/db.properties");//源文件在src目錄下Properties prop = new Properties();prop.load(in);String driver = prop.getProperty("driver");System.out.println(driver);}3.資源文件在webroot目錄下
private void test5() throws IOException {//讀取webroot目錄下的資源InputStream in = this.getServletContext().getResourceAsStream("/db.properties");//在webroot目錄下System.out.println(in);}4.用類裝載器讀取
? ? ?如果一個資源文件在src下(包括包下),更常用類裝載器來讀取
//用類裝載器讀取資源文件 public class ServletContextDemo extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {test1();}private void test1() throws IOException {ClassLoader loader = ServletContextDemo.class.getClassLoader();//獲取到裝載當前類的類裝載器InputStream in = loader.getResourceAsStream("db.properties");//用類裝載器裝載db.properties文件Properties prop = new Properties();prop.load(in);String driver = prop.getProperty("driver");System.out.println(driver);}//讀取類路徑下面、包下面的資源文件public void test2(){InputStream in = ServletContextDemo7.class.getClassLoader().getResourceAsStream("com/shen/db.properties");System.out.println(in);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}注意:
1.通過類裝載器讀取資源文件的注意事項:不適合裝載大文件,否則會導致jvm內存溢出
//通過類裝載器讀取資源文件的注意事項:不適合裝載大文件,否則會導致jvm內存溢出public void test3(){InputStream in = ServletContextDemo7.class.getClassLoader().getResourceAsStream("PranavMistry_2009I_480.mp4");//如讀取一個電影System.out.println(in);}//文件太大,只能用servletContextpublic void test4() throws IOException{//讀取PranavMistry_2009I_480.mp4,并拷貝到e:\根目錄下//path=c:\asdf\adsd\add\PranavMistry_2009I_480.mp4//path=PranavMistry_2009I_480.mp4獲取文件名String path = this.getServletContext().getRealPath("/WEB-INF/classes/PranavMistry_2009I_480.mp4");String filename = path.substring(path.lastIndexOf("\\")+1);//截取到文件名【lastIndexOf("\\")+1表示截取到字符串中最后一個'\'字符后的部分】//將該文件輸入到內存(之前在web服務器)InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/PranavMistry_2009I_480.mp4");byte buffer[] = new byte[1024];int len = 0;//將該文件寫入到硬盤FileOutputStream out = new FileOutputStream("e:\\" + filename);while((len=in.read(buffer))>0){out.write(buffer,0,len);}out.close();in.close();}2.如果是一個普通的類,因為沒有ServletContext對象故只能通過類的裝載方法進行數據的讀取,Dao.java,通過ServletDemo調用
public class ServletDemo extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {Dao dao = new Dao();dao.run();}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}dao.java
public class Dao {//讀取資源文件,并更新資源文件public void run() throws IOException{URL url = this.getClass().getClassLoader().getResource("db.properties");String path = url.getPath();FileInputStream in = new FileInputStream(path);//讀取數據FileOutputStream out = new FileOutputStream(path);//寫入數據Properties prop = new Properties();prop.load(in);System.out.println(prop.size());prop.setProperty("name", "flx");prop.store(out, "");}}?
總結
以上是生活随笔為你收集整理的Java web开发——Servlet详细介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【剑桥英语I优加】剑桥pet考试适合多大
- 下一篇: Java 创建事件Event、事件监听E