配置Servlet映射
<servlet> <servlet-name>TestServlet</servlet-name> <servlet-class>servlet.TestServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>TestServlet</servlet-name> <url-pattern>/TestServlet</url-pattern> </servlet-mapping>
只能使用/TestServlet來訪問,使用其他的比如/TestServlet/xxx是訪問不了的。
url-pattern必須以/開始,引用時引用url-pattern中/后面的部分。比如<url-pattern>/handlerServlet</url-pattern>,表單action="handlerServlet";比如<url-pattern>/servlet/handlerServlet</url-pattern>,表單action="servlet/handlerServlet"。
引用的是url-pattern,不是servlet-name。
可以使用.
<url-pattern>/servlet.TestServlet</url-pattern>
訪問時以 /servlet.TestServlet 來訪問。注意不是通過/servlet/TestServlet來訪問。
可以使用/
<url-pattern>/servlet/TestServlet</url-pattern>
訪問時以 /servlet/TestServlet 來訪問
可以使用通配符*
<url-pattern>/*</url-pattern>
匹配所有請求。
多重映射:一個Servlet配置多個<url-pattern>,可通過多個路徑來訪問。
<servlet-mapping> <servlet-name>TestServlet</servlet-name> <url-pattern>/TestServlet1</url-pattern> <url-pattern>/TestServlet2</url-pattern> </servlet-mapping>
既可通過/TestServlet1來訪問,又可通過/TestServlet2來訪問。
配置 load-on-startup
<servlet> <servlet-name>TestServlet</servlet-name> <servlet-class>servlet.TestServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet>
配置了<load-on-startup></load-on-startup>的Servlet會在Servlet容器(比如Tomcat)啟動時就創建此Servlet的實例。
參數是一個整數,值越小的越先創建(初始化)。
默認Servlet
<url-pattern>/</url-pattern>
只有一個/,當找不到匹配的Servlet時,就執行這個默認的Servlet(用默認的Servlet來響應)。
注意默認Servlet是/,不是/*。
默認Servlet與Tomcat處理靜態資源有很大聯系。
Tomcat處理請求的流程
瀏覽器要訪問某個web資源(頁面),Tomcat是如何處理這個請求的呢?
(1)Tomcat先在此WebApp的web.xml中根據<url-pattern>找有沒有匹配的Servlet,有就調用來處理這個請求
(2)如果沒有,就查找此WebApp的web.xml中有沒有配置默認Servlet,有就調用默認的Servlet來處理這個請求。
這個就很有意思了,比如瀏覽器請求的是xxx.html,此WebApp下也有這個xxx.html,但你配置了一個默認的Servlet,那Tomcat會調用默認的Servlet來響應,而不是調用xxx.html來響應!
(3)如果此WebApp沒有配置默認的Servlet,那就到Tomcat -> conf -> web.xml 中查找,這個web.xml是Tomcat的全局配置,對所有WebApp均有效。
先根據<url-pattern>找有沒有匹配的Servlet,全局的web.xml中自然是找不到匹配的Servlet的;
然后找有沒有默認的Servlet,全局的web.xml中配置了一個默認的Servlet,此Servlet的處理方式是:在當前WebApp的資源找有沒有請求的這個資源|文件,有就用這個資源|文件來響應,比如請求的是xxx.html,就在當前這個WebApp的資源中找有沒有xxx.html這個資源|文件,有就用它來響應。如果當前WebApp中沒有這個資源|文件,就報404錯誤。
如果瀏覽器請求的是靜態資源,比如xxx.html,這要走完整個流程。
人家請求的是靜態資源,你遍歷2個web.xml,在一堆Servlet配置中找!簡直傻X。
所以說Tomcat處理靜態資源不給力。處理靜態資源一般用Nginx,不用Tomcat。
配置某個Servlet的初始化參數
<servlet> <servlet-name>TestServlet</servlet-name> <servlet-class>servlet.TestServlet</servlet-class> <init-param> <param-name>name</param-name> <param-value>張三</param-value> </init-param> <init-param> <param-name>age</param-name> <param-value>18</param-value> </init-param> </servlet>
一個<init-param>設置一個參數。可以設置多個。
在Servlet中使用ServletConfig獲取當前Servlet的初始化參數
1 public class TestServlet extends HttpServlet { 2 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 3 doGet(request, response); 4 } 5 6 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 7 response.setContentType("text/html;charset=utf-8"); // //設置響應輸出流的編碼格式。若不設置,中文會亂碼。 8 PrintWriter writer = response.getWriter(); //獲取響應輸出流 9 ServletConfig servletConfig=this.getServletConfig(); //this表示當前Servlet。可缺省this,直接調用getServletContext() 10 11 //獲取單個參數值 12 String name = servletConfig.getInitParameter("name"); //返回值是String 13 String age = servletConfig.getInitParameter("age"); 14 writer.write("name:"+name+"<br />"); //輸出會以html的形式顯示,所以可以使用html標簽。 15 writer.write("age:"+age); 16 17 writer.write("<hr />"); 18 19 //遍歷 20 Enumeration<String> initParameterNames = servletConfig.getInitParameterNames(); //里面的元素是參數名 21 while (initParameterNames.hasMoreElements()){ 22 String paramName=initParameterNames.nextElement(); //參數名 23 String paramValue=servletConfig.getInitParameter(paramName); //參數值 24 writer.write(paramName+":"+paramValue+"<br />"); 25 } 26 27 28 } 29 }
說明
-
如果響應中包含中文,需要設置設置響應的編碼字符集。有2種設置方式
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
這兩種方式都可以解決響應中文亂碼的問題(准確來說不是亂碼,是顯示為?識別不了)。區別是:第一種設置了輸出文檔是html,所以可以輸出html文檔中的內容,比如:
PrintWriter writer = response.getWriter(); writer.write("<h2>hello</h2>"); writer.write("<script>alert('hello')</script>");
這些html標簽都會被解析,js腳本是有效的。
第二種只設置了響應字符集為utf-8,並沒有設置響應是html文檔,解析不了響應中的html標簽。
-
設置響應字符集的這句代碼必須放在獲取響應輸出流的代碼之前。
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
如果放在了獲取響應輸出流的代碼之后,則設置的字符集無效。
-
解決請求參數中的中文亂碼
request.setCharacterEncoding("utf-8");
習慣上把設置request、response字符集的這兩句代碼放在doGet() | doPost() 里的最前面。
-
如果我們想在響應輸出流中輸出換行,使用<br />,而非\n。
response.setContentType("text/html;charset=utf-8"); PrintWriter writer = response.getWriter(); writer.write("hello<br />");
設置響應輸出流是html文檔,換行自然要用<br />,\n在html中換不了行。
配置整個web應用的初始化參數,所有Servlet共享
既然是所有servlet公有的,那就應該直接放在<web-app>下。
<context-param> <param-name>name</param-name> <param-value>chy</param-value> </context-param> <context-param> <param-name>age</param-name> <param-value>20</param-value> </context-param>
一個<context-param>配置一個參數,可配置多個參數。
在servlet中獲取參數值
1 response.setContentType("text/html;charset=utf-8"); 2 PrintWriter writer = response.getWriter(); 3 ServletContext context=this.getServletContext(); //可缺省this,直接調用getServletContext() 4 5 //獲取單個參數值 6 String name = context.getInitParameter("name"); 7 String age = context.getInitParameter("age"); 8 writer.write("name:"+name+"<br />"); 9 writer.write("age:"+age); 10 11 writer.write("<hr />"); 12 13 //遍歷 14 Enumeration<String> initParameterNames =context.getInitParameterNames(); //里面的元素是參數名 15 while (initParameterNames.hasMoreElements()){ 16 String paramName=initParameterNames.nextElement(); //參數名 17 String paramValue=context.getInitParameter(paramName); //參數值 18 writer.write(paramName+":"+paramValue+"<br />"); 19 }
我們注意到通過ServletContext對象獲取東西參數名、參數值、Enumeration對象的三個方法都是getInitParameterXxx()。為什么是init?
ServletConfig表示當前Servlet的初始化配置。
ServletContext表示整個Web應用中所有Servlet的共享數據。共享數據有2個部分:
- 在xml中通過<context-param>配置的初始化參數,這部分數據要通過ServletContext實例的getInitParameterXxx()來獲取
- 另一部分共享數據是在web應用運行中通過setAttribute()添加|設置的,需要使用getAttribute()來獲取。
這2部分數據是分開的、獨立的,操作數據的方法也是獨立的一套。
整個Web應用的共享數據
在一個Servlet中:
ServletContext context=getServletContext(); //可缺省this context.setAttribute("name","chy"); context.setAttribute("age",20);
設置的數據是所有Servlet共享的,在其他Servlet中可以修改、獲取這些數據。
在另一個Servlet中使用:
//獲取單個屬性值 String name= (String) servletContext.getAttribute("name"); //獲取的是屬性值都是Object,需要強轉 int age= (int) servletContext.getAttribute("age"); //遍歷 Enumeration<String> attributeNames = servletContext.getAttributeNames(); while (attributeNames.hasMoreElements()){ String attributeName=attributeNames.nextElement(); //屬性名是String Object attributeValue = servletContext.getAttribute(attributeName); //屬性值是Object,需要強轉 //... }
需要先訪問前一個Servlet。先設置了數據,才取得出來。
如果要移除某個共享數據,可以使用 removeAttribute(String name) 。
獲取ServletConfig對象、ServletContext對象,可以使用this,也可以缺省this,直接寫getServletConfig|Context()。
因為getServletConfig()獲取的只能是當前Servlet的初始化配置,是唯一的;
getServletContext()獲取的只能是當前WebApp中的共享數據,也是唯一的;
不需要this。
獲取當前Servlet的初始化參數時,可以不要ServletConfig對象,直接寫 getInitParameter()、getInitParameterNames()。
因為當前的Servlet是唯一的、確定的。
使用ServletContext讀取資源文件
1 ServletContext servletContext = getServletContext(); 2 InputStream is = servletContext.getResourceAsStream("/test.properties"); 3 Properties properties = new Properties(); 4 properties.load(is);
配置Tomcat數據源
1、在tomcat->conf->context.xml中配置數據源
<Context> <WatchedResource>WEB-INF/web.xml</WatchedResource> <WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource> <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> <Resource name="jdbc/mysql" type="javax.sql.DataSource" driverClassName="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://localhost:3306/my_db?serverTimezone=GMT" username="chy" password="abcd" /> </Context>
<WatchedResource>是自帶的,不用管。
一個<Resource>配置一個資源,可同時配置多個資源。<Resource>的name屬性唯一標識此資源,數據源的name常用jdbc/xxx來命名。Tomcat中配置的資源是全局的,所有webapp都可以通過name引用。
type指定資源類型是數據源。Tomcat的內置數據源是DBCP,所以參數要是DBCP的參數,可在<Resource>中配置DBCP中可配置的所有參數。
需要把數據庫驅動添加到tomat的lib中。
說明:tomcat自帶java web常用的jar包。使用tomcat運行webapp時,默認會自動使用tomcat\lib下的servlet-api.jar、jsp-api.jar這2個包,所以我們不必手動添加這2個包的依賴。當然把java ee的jar包添加進來也行。
2、在WebApp的web.xml中引用Tomcat數據源
<resource-ref> <res-ref-name>jdbc/mysql</res-ref-name> <res-type>javax.sql.DataSource</res-type> </resource-ref>
配置在<web-app>中,一個<resource-ref>配置一個資源引用,<res-ref-name>指定要引用的資源的name(對應tomcat中資源的name),res-type指定所引用資源的類型。
這2個子元素的位置可以互換,但在某些版本的IDEA中,如果type寫在前,name寫在后,type會報紅,這是IDEA本身的問題,代碼沒有錯。
3、在Servlet中使用數據源
InitialContext initialContext = new InitialContext(); Context context = (Context) initialContext.lookup("java:comp/env"); //返回值是Object,需要強轉。參數是固定的。 DataSource dataSource = (DataSource)context.lookup("jdbc/mysql"); //獲取數據源,參數是資源的name。返回值是Object,需要強轉 Connection connection = dataSource.getConnection();
使用注解配置Servlet
使用注解配置Servlet最常用,也最方便。
@WebServlet(
name = "testServlet",
urlPatterns = { "/servlet/testServlet" },
loadOnStartup = 1,
initParams = {@WebInitParam(name = "name", value = "張三"),@WebInitParam(name="age",value="12")}
)
public class TestServlet extends HttpServlet {
//......
}
name指定此Servlet的name,缺省時默認為此Servlet的全限定類名。
urlPatterns、value指定映射,二者完全等價。多重映射寫成字符串數組的形式,如果只有一個映射關系,可以直接寫成字符串。
loadOnStartup,即<load-on-startup>。
initParams指定此Servlet的初始化參數,數組形式。一個@WebInitParam配置一個初始化參數,name、value均為String。
以上參數均可缺省,但一般都要配置value | urlPatterns。
參數只有value | urlPatterns時可以缺省value | urlPatterns,直接寫參數值。
@WebServlet("/servlet/testServlet")
配置項目首頁
<welcome-file-list> <welcome-file>/login.jsp</welcome-file> </welcome-file-list>
缺省時默認是index.xxx。