文章目錄
Servlet
1、Servlet簡介
- Servlet (Service Applet) 是在服務器上運行的小程序。
- 廣義的Servlet是指任何實現了這個Servlet接口的類,Servlet運行於支持Java的應用服務器中。從原理上講,Servlet可以響應任何類型的請求,但絕大多數情況下Servlet只用來擴展基於HTTP協議的Web服務器。
2、HelloServlet
- Java提供了兩個默認的Servlet接口實現類:
- HttpServlet
- GenericServlet
-
構建一個普通的Maven項目,刪掉裏面的src目錄,以後我們的學習就在這個項目裏面建立Moudel,這個空的工程就是Maven主工程
-
Maven父子工程
父項目中會有
<modules> <module>servlet-01</module> </modules>
子項目會有
<parent> <artifactId>javaweb</artifactId> <groupId>com.study</groupId> <version>1.0-SNAPSHOT</version> </parent>
-
-
Maven環境優化
-
修改web.xml爲最新的
<?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_4_0.xsd" version="4.0" metadata-complete="true"> </web-app>
-
將maven的結構搭建完整
創建 java和 resources 文件夾
-
-
編寫一個Servlet程序
-
定義一個類,實現Servlet接口,這裏我們直接繼承HttpServlet
public class HelloServlet extends HttpServlet { //由於get和post只是請求的不同的方式,所以doGet和doPost業務邏輯都一樣,可以相互調用 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); //響應流 writer.print("Hello Servlet"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
-
編寫Servlet的映射
<!--註冊Servlet--> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.study.servlet.HelloServlet</servlet-class> </servlet> <!--Servlet的請求路徑--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
配置Tomcat服務器
-
啓動發佈
3、Servlet原理
4、Mapping配置
- 一個Servlet可以指定一個映射路徑
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
- 一個Servlet可以指定多個映射路徑
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello3</url-pattern>
</servlet-mapping>
- 一個Servlet可以指定通配的映射路徑
<servlet-mapping>
<servlet-name>hello</servlet-name>
<!-- * 通配任意字符串-->
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
- 默認請求路徑
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
- 指定後綴或前綴等
<!--
注意點,*前面不能加項目映射的路徑
-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.study</url-pattern>
</servlet-mapping>
- 優先級問題:指定了固有的映射路徑優先級最高,如果找不到就會走默認的處理請求
5、ServletContext
web容器在啓動的時候,它會爲每個web程序都創建一個對應的ServletContext對象,它代表了當前的web應用。
5.1、共享數據
- 即在一個Servlet中保存的數據,可以在另外一個servlet中拿到
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String username = "張三"; //數據
//將一個數據保存在了ServletContext中,字段名:username 值 “張三”
context.setAttribute("username",username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 獲取保存在ServletContext中的數據
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String username = (String) context.getAttribute("username");
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().print("名字:"+username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- web.xml配置
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.study.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getc</servlet-name>
<servlet-class>com.study.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getc</servlet-name>
<url-pattern>/getc</url-pattern>
</servlet-mapping>
-
測試訪問
-
若直接訪問 http://localhost:8080/s2/getc ,由於username還未賦值,所以username=null;
-
先訪問 http://localhost:8080/s2/hello ,將數據存進ServletContext
-
再訪問 http://localhost:8080/s2/getc
-
5.2、獲取初始化參數
<!--配置一些web應用初始化參數-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mydb</param-value>
</context-param>
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
resp.getWriter().print(url);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 測試訪問:
5.3、請求轉發
public class ForwardServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
// "/url" 5.2中的Servlet
context.getRequestDispatcher("/url").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 測試訪問:
- 轉發過程:
5.4、讀取資源文件
-
在java目錄下新建properties文件
-
在resources目錄下新建properties文件
-
發現:都被打包到了同一個路徑下:classes/ ,我們俗稱這個路徑爲classpath
-
maven由於他的約定大於配置,可能出現配置文件無法被導出或者生效的問題,解決方案:
<!--在build中配置resources,來防止我們資源導出失敗的問題-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
- prop.properties
username=root
password=123456
- PropServlet.java
public class PropServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = getServletContext();
InputStream resourceAsStream = context.getResourceAsStream("WEB-INF/classes/prop.properties");
Properties properties = new Properties();
properties.load(resourceAsStream);
String username = properties.getProperty("username");
String password = properties.getProperty("password");
resp.getWriter().print("<h1>"+username+"==="+password+"</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 測試訪問:
6、Response
6.1、瀏覽器下載文件
public class FileDownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//需要下載的文件在服務器的路徑
String filePath="D:\\IdeaProjects\\maven-javaweb-01\\Servlet-03\\src\\main\\resources\\背景.png";
//文件名
String fileName=filePath.substring(filePath.lastIndexOf('\\')+1);
//設置使瀏覽器能夠支持下載(Content-Disposition)我們需要的東西,中文文件名需要設置編碼(URLEncoder.encode),否則有可能亂碼
resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
//創建讀取文件的輸入流
FileInputStream in = new FileInputStream(filePath);
//獲取輸出流
ServletOutputStream out =resp.getOutputStream();
//創建buffer緩衝區
byte[] buffer = new byte[1024 * 8];
int len=0;
//將FileOutputStream流寫入到buffer緩衝區,使用OutputStream將緩衝區中的數據輸出到瀏覽器!
while ((len=in.read(buffer))!=-1){
out.write(buffer,0,len);
}
in.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 測試訪問:
6.2、創建一張圖片,在其中生成8位隨機數,並響應給瀏覽器
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//讓瀏覽器3秒自動刷新一次
resp.setHeader("refresh","3");
//在內存中創建一個圖片
BufferedImage image = new BufferedImage(200, 40, BufferedImage.TYPE_INT_RGB);
//獲取圖片
Graphics2D g = (Graphics2D) image.getGraphics();
//設置圖片背景顏色
g.setColor(Color.cyan);
g.fillRect(0,0,200,40);
//在圖片中寫入數據
g.setColor(Color.RED);
g.setFont(new Font("華文彩雲",Font.BOLD,30));
g.drawString(getNum(),20,30);
//把圖片寫到瀏覽器
ImageIO.write(image,"png",resp.getOutputStream());
}
private String getNum() {
Random random = new Random();
StringBuilder sb = new StringBuilder(random.nextInt(99999999));
int sbLen=sb.length();
for (int i = 0; i < 8-sbLen; i++) {
sb.append(random.nextInt(10));
}
return sb.toString();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 測試訪問:
6.3、重定向
- RedirectServlet.java
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//重定向
resp.sendRedirect("/s3/success.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h1>redirect success!</h1>
</body>
</html>
-
測試訪問:
-
重定向示意圖:
-
重定向和轉發的區別:
-
重定向是兩次請求,轉發是一次請求,因此轉發的速度要快於重定向;
-
重定向之後地址欄上的地址會發生變化,變化成第二次請求的地址,轉發之後地址欄上的地址不變,還是第一次請求的地址;
-
轉發是服務器行爲,重定向是客戶端行爲;
-
重定向時的網址可以是任何網址,轉發的網址必須是本站點的網址。
-