Servlet是用Java編寫的服務(wù)器端程序,是Sun公司提供的一套接口規(guī)范,用來處理基于HTTP協(xié)議的客戶端請求,響應(yīng)給瀏覽器的動態(tài)資源。
下面通過做個簡單的用戶名提交網(wǎng)頁,了解下Servlet的工作流程。
1.引入Servlet-api.jar
在Tomcat的lib文件夾中引入servlet-api.jar
項目結(jié)構(gòu)
2.實現(xiàn)Servlet
public class DemoServlet extends HttpServlet {
//Servlet是單列模式,只有一個對象
//此對象是根據(jù)web.xml的配置信息通過反射生成的
//因此一定要保證Servlet 的實現(xiàn)類有一個 public 修飾且無參的構(gòu)造函數(shù)
//因為反射生成類,需要的是無參公開的構(gòu)造函數(shù)
public DemoServlet() {
}
//用來初始化當(dāng)前Servlet,只在服務(wù)器啟動時調(diào)用一次
@Override
public void init(ServletConfig config) throws ServletException {
}
//每次連接服務(wù)器都會調(diào)用
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//獲取用戶提交的用戶名
//參數(shù)name對應(yīng),網(wǎng)頁表單里name的值
String name = req.getParameter("name");
System.out.println("用戶提交的用戶名為:" + name);
}
//銷毀,只有在停止服務(wù)器時才會調(diào)用,因此一般不將銷毀資源寫在這里
@Override
public void destroy() {
}
}
3.web.xml中配置Servlet映射
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<!-- 3. 為下面的映射定義一個可找到的名稱 -->
<servlet-name>DemoServlet</servlet-name>
<!-- 4. Tomcat通過包找到用戶寫好的Servlet -->
<servlet-class>com.servlet.DemoServlet</servlet-class>
</servlet>
<servlet-mapping>
<!-- 2.根據(jù)用戶自定義的servlet名稱找到servlet -->
<servlet-name>DemoServlet</servlet-name>
<!-- 1.表單提交時,action對應(yīng)的servlet -->
<url-pattern>/demo</url-pattern>
</servlet-mapping>
</web-app>
2.在index.jsp中編寫界面
<html>
<head>
<title>Demo</title>
</head>
<body>
<%-- action="處理此請求的servlet"--%>
<form action="/demo" method="get">
<input type="text" placeholder="用戶名" name="name">
<input type="submit" value="提交">
</form>
</body>
</html>
界面效果
Servlet的配置
1.完全匹配
請求必須完全匹配設(shè)定的url-pattern
<servlet-mapping>
<servlet-name>DemoServlet</servlet-name>
<url-pattern>/demo</url-pattern>
</servlet-mapping>
2.目錄匹配
請求(/aa/bb/ccc)都會檢索到該目錄指向的Servlet
<url-pattern>/aa/bb/cc/*</url-pattern>
3.擴(kuò)展名匹配
后綴名為.demo的就能訪問
<url-pattern>*.demo</url-pattern>
4.缺省配置
當(dāng)請求的資源地址,所有的Servlet都不匹配時,就由缺省配置的Servlet處理
<url-pattern>/</url-pattern>
其他細(xì)節(jié)
1. 一個Servlet可以有多個<url-pattern>
2.非常消耗資源的初始化操作,要放到服務(wù)器啟動時
<servlet>
<servlet-name>ServletResponseTest</servlet-name>
<servlet-class>com.w.servlet.ServletResponseTest</servlet-class>
<!-- 數(shù)字越小越先執(zhí)行初始化 -->
<load-on-startup>0</load-on-startup>
</servlet>
Servlet使用注解配置映射信息
Serlvet3.0引入了注解的方式配置映射信息
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
注意:一定要在配置清單中添加
metadata-complete="false">
</web-app>
@WebServlet(value = "/demo",
loadOnStartup = 1,
initParams = { @WebInitParam(name = "", value = "") }
)
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String name = req.getParameter("name");
System.out.println("用戶提交的用戶名為:" + name);
}
}
Servlet相關(guān)API
1.ServletConfig(javax.servlet.ServletConfig)
當(dāng)Servlet中存在硬編碼,要將其配置到 web.xml 中,以提高文件可維護(hù)性。
將配置的信息抽取出來放到web.xml文件中
<servlet>
<servlet-class>com.w.run.HellowServlet</servlet-class>
<servlet-name>HelloServlet</servlet-name>
<!-- 初始化參數(shù)配置 -->
<init-param>
<!-- 參數(shù)名稱 -->
<param-name>encoding</param-name>
<!-- 參數(shù)值 -->
<param-value>UTF-8</param-value>
</init-param>
</servlet>
public class DemoServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
ServletConfig servletConfig = getServletConfig();//獲取配置信息類
String encoding = config.getInitParameter("encoding");
System.out.println(encoding);
}
}
Config 其他API
public class DemoServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
//獲取全部初始化參數(shù)
Enumeration<String> initParameterNames = config.getInitParameterNames();
while (initParameterNames.hasMoreElements()) {
System.out.println(initParameterNames.nextElement());
}
//獲取當(dāng)前servlet的名稱
String servletName = config.getServletName();
System.out.println(servletName);
//獲取當(dāng)前servlet的上下文
ServletContext servletContext = config.getServletContext();
}
}
2.ServletContext
ServletContext對象,代表一個Web應(yīng)用,封裝了該Web應(yīng)用的信息,該對象在服務(wù)器啟動時,創(chuàng)建,該Web應(yīng)用銷毀時,銷毀。
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = getServletContext();
context.setAttribute("key", "Value");
context.getAttribute("key");
context.removeAttribute("key");
}
ServletContext重要API
配置全局參數(shù)所有Servlet中都能獲取
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<!-- 全局初始化參數(shù),在所有Servlet中都能獲取 -->
<context-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
</web-app>
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = getServletContext();
//獲取Web.xml中配置的全局參數(shù)
context.getInitParameter("encoding");
//獲取Web應(yīng)用中任何資源的絕對路徑
context.getRealPath("path");
}
Servlet的Request,Response
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
}
1.ServletRequest(子接口實現(xiàn):HttpServletRequest)
用來處理基于HTTP協(xié)議的請求,其對象在每次請求時創(chuàng)建,響應(yīng)結(jié)束后銷毀。
Request常用的API
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
/**
* 以下是獲取用戶提交的請求里參數(shù)的方法
*/
req.getParameter("name"); //獲取指定名稱的參數(shù)的值
req.getParameterMap(); //獲取所有請求參數(shù)并封裝到一個Map
req.getParameterNames(); //獲取所有請求參數(shù)的名稱
req.getParameterValues(""); //獲取多個表單的值,CheckBox的
//Request的域?qū)ο螅瑐鬟f數(shù)據(jù)
req.setAttribute("key","value");
req.getAttribute("key");
req.removeAttribute("key");
req.getContextPath(); //獲取上下文路徑
req.getHeader("User-Agent"); //獲取指定名稱的請求頭信息
req.getMethod(); //獲取請求方式
req.getRequestURI(); //獲取資源的名稱
req.getRequestURL(); //獲取請求資源的全路徑
}
BeanUtils框架的使用
表單提交的多個參數(shù),往往需要封裝成JavaBean,用傳統(tǒng)寫法太過繁瑣,這就需要借助框架幫助。
try {
/**
* BeanUtils工作原理:將Map中的數(shù)據(jù),根據(jù)Key與實體的屬性的對應(yīng)關(guān)系封裝
* 只要Key的名字與實體的屬性名字一樣就自動封裝到實體中
*/
User user = new User();
BeanUtils.populate(user, req.getParameterMap());
} catch (Exception e) {
e.printStackTrace();
}
2.ServletResponse(子接口實現(xiàn):HttpServletResponse)
用來處理基于HTTP協(xié)議的請求后的響應(yīng)信息。
Response常用API
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//Response獲得流不需要手動關(guān)閉,Tomcat會幫助我們關(guān)閉
//getWrite()和getOutputStream(); 不允許同時調(diào)用,這里只做演示
PrintWriter writer = resp.getWriter();
ServletOutputStream outs = resp.getOutputStream();
resp.setStatus(201); //設(shè)置狀態(tài)碼
resp.setHeader("key", "value"); //設(shè)置響應(yīng)頭
resp.addHeader("key", "value"); //添加響應(yīng)頭
}
Servlet請求響應(yīng)時,中文亂碼問題
Tomcat默認(rèn)使用的ISO-8859-1的方式處理請求參數(shù),不適合中文的編碼。
MIME類型(文件格式)"text/html"的響應(yīng)問題。
1.解決辦法
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
2..用解碼編碼的方式
byte[] bytes = name.getBytes("ISO-8859-1"); //解碼
name = new String(bytes, "UTF-8"); //編碼
3.. 修改Tomcat配置,但只支持get請求。
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="utf-8"/>
4.在獲取請求參數(shù)之前設(shè)置請求編碼,只支持post請求。
req.setCharacterEncoding("UTF-8");
Response響應(yīng)流程
1.客戶端發(fā)送請求到服務(wù)端Tomcat
2.服務(wù)端Tomcat引擎發(fā)送Request請求
3.服務(wù)端響應(yīng)的數(shù)據(jù)會存到Response緩沖區(qū)
4.Tomcat引擎取出Response緩沖區(qū)的內(nèi)容,與引擎自己添加的信息組裝成一個Http響應(yīng)給客戶端。