1. 程式人生 > 其它 >Servlet、request、response等

Servlet、request、response等

5.12、Servlet的依賴

<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>

jsp的依賴

    <dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>

6、Servlet

6.1、Servlet簡介
  • Servlet就是sun公司開發動態web的一門技術

  • Sun在這些API中提供一個介面叫做:Servlet,如果你想開發一個Servlet程式,只需要完成兩個小步驟:

    • 編寫一個類,實現Servlet介面

    • 把開發好的Java類部署到web伺服器中。

把實現了Servlet介面的Java程式叫做,Servlet。

6.2、HelloServlet

Servlet介面在Sun公司有兩個預設的實現類:HttpServlet,GenericServlet

  1. 構建一個普通的Maven專案,刪掉裡面的src目錄,以後我們的學習就在這個專案裡面建立Model;這個空的工程就是Maven主工程;

  2. 關於Maven父子工程的理解:

父專案中會有

  <modules>
<module>servlet-01</module>
</modules>

子專案會有

  <parent>
<artifactId>javaweb-02-servlet</artifactId>
<groupId>com.kuang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>

父專案中的java 子專案可以直接使用

son extends father
  1. Maven環境優化

    1. 修改web.xml為最新的(Tomcat中拿來)

    2. 將maven的結構搭建完整

  2. 編寫一個Servlet程式

    1. 編寫一個普通類

    2. 實現Servlet介面,這裡我們直接繼承HttpServlet

    public class HelloServlet extends HttpServlet {

    //由於get或者post只是請求實現的不同的方式,可以相互呼叫,業務邏輯都一樣;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    PrintWriter writer = resp.getWriter(); //響應流
    writer.println("Hello,Servlet!");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    super.doPost(req, resp);
    }
    1. 編寫Servlet的對映

    為什麼需要對映:我們寫的是java程式,但是要通過瀏覽器訪問,而瀏覽器需要連線web伺服器,所以我們需要在web服務中註冊我們寫的Servlet,還需要給他一個瀏覽器能夠訪問的路徑;

    <!--   註冊Servlet-->
    <servlet>
    <servlet-name>hello</servlet-name>
    <!-- 一個Servlet對應一個class-->
    <servlet-class>com.kuang.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    </web-app>
    1. 配置Tomcat

    注意:配置專案釋出的路徑就可以了

    1. 啟動測試,OK!

    6.3、Servlet原理

    Servlet是由Web伺服器呼叫,web

6.4、Mapping問題
  1. 一個Servlet可以指定一個對映路徑

  <servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
  1. 一個Servlet可以指定多個對映路徑

  <servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<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>
  1. 一個Servlet可以指定通用對映路徑

  <servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
  1. 預設請求路徑

// 預設請求路徑,會走Servlet,不會走index.jsp 
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
  1. 指定一些字尾或者字首等等...

<!--   可以自定義字尾實現請求對映
注意點:*前面不能加專案對映的路徑
/sakldjaks.qinjiang
-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.qinjiang</url-pattern>
</servlet-mapping>
  1. 優先順序問題

指定了固有的對映路徑優先順序更高,如果找不到就會走預設的處理請求;

<!--  404  -->
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>com.kuang.servlet.ErrorServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
6.5、ServletContext

web容器在啟動的時候,它會為每個web程式都建立一個對應的ServletContext物件,它代表了當前的web應用;

1、共享資料

我在這個Servlet中儲存的資料,可以在另外一個servlet中拿到;

public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//this.getServletContext() Servlet上下文
ServletContext context = this.getServletContext();

String username = "qinjiang"; //資料
context.setAttribute("username",username); //將一個數據儲存在了ServletContext中,名字為:username,值 username
}
}
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
ServletContext context = this.getServletContext();
String username = (String)context.getAttribute("username");
PrintWriter writer = resp.getWriter();
writer.println(username);
//上面兩步等於resp.getWriter().println(username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
  <servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.kuang.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern> //用來瀏覽器訪問的
</servlet-mapping>

<servlet>
<servlet-name>hello1</servlet-name>
<servlet-class>com.kuang.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello1</servlet-name>
<url-pattern>/hello1</url-pattern>
</servlet-mapping>

測試訪問結果;(hello1要獲取hello的資料,瀏覽器需要先進入hello的頁面,然後在進入hello1的頁面才能能獲取到,否則會出現null)

2、獲取初始化引數
  <context-param>  //XML裡配置
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306</param-value>
</context-param>
  @Override 
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();

String url = context.getInitParameter("url");
resp.getWriter().print(url);
}
3、請求轉發
  @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
System.out.println("進入了Demo04");
// RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp"); //轉發的請求路徑
// requestDispatcher.forward(req,resp);//呼叫forward實現請求轉發;
context.getRequestDispatcher("/gp").forward(req,resp);
}
上面的是請求轉發的方式(通過B在找C),下面的是重定位(B返回後直接去找C)。

4、 讀取資原始檔

Properties

  • 在java目錄下新建properties

  • 在resources目錄下新建properties

發現:都被打包到了同一個路徑下:classes,我們俗稱這個路徑為classpath:

思路:需要一個檔案流;

username=root
password=123456
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");// /代表當前web應用

Properties prop = new Properties();
prop.load(is);
String user = prop.getProperty("username");
String pwd = prop.getProperty("password");
resp.getWriter().print(user+":"+pwd);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
6.6、HttpServletResponse

web伺服器接收到客戶端的http請求,針對這個請求,分別建立一個代表請求的HttpServletRequest物件,代表響應的一個HttpServletResponse;

  • 如果要獲取客戶端請求過來的引數:找HttpServletRequest

  • 如果要給客戶端響應一些資訊:找HttpServletRequest

1、簡單分類

負責向瀏覽器傳送資料的方法

  ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;

負責像瀏覽器傳送響應頭的方法

  void setCharacterEncoding(String var1);

void setContentLength(int var1);

void setContentLengthLong(long var1);

void setContentType(String var1);

void setDateHeader(String var1, long var2);

void addDateHeader(String var1, long var2);

void setHeader(String var1, String var2);

void addHeader(String var1, String var2);

void setIntHeader(String var1, int var2);

void addIntHeader(String var1, int var2);

響應的狀態碼:

2、常見應用
  1. 向瀏覽器輸出訊息

  2. 下載檔案

    1. 要獲取下載檔案的路徑

    2. 下載的檔名是啥?

    3. 設定想辦法讓瀏覽器能夠支援下載我們需要的東西

    4. 獲取下載檔案的輸入流

    5. 建立緩衝區

    6. 獲取OutputStream物件

    7. 將FileOutputStream流寫入到buffer緩衝區

    8. 使用OutputStream將緩衝區中的資料輸出到客戶端!

    public class FileServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // 1. 要獲取下載檔案的路徑 這裡需要classes下面的路徑
    String realPath = "D:\\ideaPractice\\javaWeb\\javaweb-nnew02-servlet\\response\\target\\classes\\1.png";
    System.out.println("下載檔案的路徑:"+realPath);

    // 2. 下載的檔名是啥?
    String filename = realPath.substring(realPath.lastIndexOf("\\") + 1);
    // 3. 設定想辦法讓瀏覽器能夠支援下載我們需要的東西
    resp.setHeader("Content-Disposition","attachment; filename="+filename);
    // 4. 獲取下載檔案的輸入流
    FileInputStream in = new FileInputStream(realPath);
    // 5. 建立緩衝區
    int len = 0;
    byte[] buffer = new byte[1024];
    // 6. 獲取OutputStream物件
    ServletOutputStream out = resp.getOutputStream();
    // 7. 將FileOutputStream流寫入到buffer緩衝區,使用OutputStream將緩衝區中的資料輸出到客戶端!
    while ((len=in.read(buffer))>0){
    out.write(buffer,0,len);
    }
    in.close();
    out.close();
    3、隨機數
    public class ImageServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    //如何讓瀏覽器5秒自動重新整理一次;
    resp.setHeader("refresh","3");
    //在記憶體中建立一個圖片
    BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
    //得到圖片
    Graphics2D g = (Graphics2D)image.getGraphics(); //筆
    //設定圖片的背景顏色
    // g.setColor(Color.white);
    g.fillRect(0,0,150,20);
    //給圖片寫資料
    g.setColor(Color.blue);
    g.setFont(new Font(null,Font.BOLD,20));
    g.drawString(makeNum(),0,20);
    //告訴瀏覽器,這個請求用圖片的方式開啟
    resp.setContentType("image/jpg");
    //網站存在快取,不讓瀏覽器快取
    resp.setDateHeader("expires",-1);
    resp.setHeader("Cache-Control","no-cache");
    resp.setHeader("Pragma","no-cache");

    //把圖片寫給瀏覽器
    ImageIO.write(image,"jpg",resp.getOutputStream());

    }
    //生成隨機數
    private String makeNum(){
    Random random = new Random();
    String num = random.nextInt(99999999) + "";
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < 7 - num.length(); i++) {
    sb.append("0");
    }
    num = sb.toString() + num;
    return num;
    }
    4、實現重定向

void secdRedirect(String var1) throws IOException;

測試:

  @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
resp.setHeader("location","/r/img");
resp.setStatus(302);
*/
resp.sendRedirect("/r/img"); //重定向
}

面試題:聊聊重定向和轉發的區別?

相同點

  • 頁面都會實現跳轉

不同點

  • 請求轉發的時候,url不會變化 307

  • 重定向時候,url位址列會發生變化 302

 resp.sendRedirect("/r/success.jsp");  //重定向路徑要注意
req.getRequestDispatcher("/success.jsp").forward(req,resp); //跟上面結果一樣

6.7、HttpServletRequest

HttpServletRequest代表客戶端的請求,使用者通過Http協議訪問伺服器,HTTP請求中的所有資訊會被封裝到HttpServletRequest,通過這個HttpServletRequest的方法,獲得客戶端的所有資訊

1、獲取前端傳遞的引數

2、請求轉發
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbys = req.getParameterValues("hobbys");
System.out.println("=======================");
//後臺接受中文亂碼問題
System.out.println(username+":"+password);
System.out.println(Arrays.toString(hobbys));
System.out.println("=======================");

// 通過請求轉發
System.out.println(req.getContextPath());
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
}
<div>
<%-- 這裡表單表示的意思:以post方式提交表單,提交到login請求--%>
<form action="${pageContext.request.contextPath}/login" method="post">
使用者名稱:<input type="text" name="username"><br>
密碼:<input type="password" name="password"><br>
愛好:
<input type="checkbox" name="hobbys" value="女孩">女孩
<input type="checkbox" name="hobbys" value="程式碼">程式碼
<input type="checkbox" name="hobbys" value="唱歌">唱歌
<input type="checkbox" name="hobbys" value="電影">電影
<br>
<input type="submit">
</form>
</div>