1. 程式人生 > 其它 >WEB核心技術-1

WEB核心技術-1

WEB核心技術

一個成熟的web需要運用到多種語言的書寫,這裡的資料庫連線我們已經學了使用jdbc以及mybatis的方式完成資料的獲取與修改

HTTP

請求體和i請求頭之間有空格隔開的

對應的引數存放到請求體中

GET/POST的區別

1.GET請求引數放到請求行中,沒用請求體。POST請求引數放到請求體中

2.GET請求請求引數大小有限制,POST 沒有

HTTP響應資料格式

WEB伺服器-Tomcat

這種類似的web伺服器是一個軟體,對http協議操作進行封裝,使程式設計師不必直接對協議進行操作,讓WEB開發更加快捷

可以將web專案部署到伺服器中,對外提供網上瀏覽服務

我們用的tomcat是一個輕量級web伺服器

這是一個綠色軟體直接解壓即安裝,刪除資料夾即解除安裝

開啟方式點開bin start.bat安全開啟,ctrl+c安全關閉

在idea中可以本地部署tomcat

也可以使用pom中新增配置

Servlet

Servlet快速入門

1.在pom檔案裡匯入依賴jar包,直接複製以後都是一樣的

這裡注意一定要定義一個scope為provided

2.寫一個方法完成servlet介面,重寫其方法

3.配置訪問路徑使其能被訪問到

這裡說一下我這裡困擾了一下午的tomcat頁面一直404輸入路徑也無法跳轉,最後我重新以模板的形式生成了maven新的工程,在pom中匯入tomcat就解決了,真是讓人頭疼

這裡我們的service方法裡只是寫了輸出語句,其實這是用來接收以及向伺服器返回資料的方法,之後學習了過後,會具體使用

servlet生命週期

package com.ember.web;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet(urlPatterns = "/demo1",loadOnStartup = 1)
public class ServletDemo2 implements Servlet {
   /*完成初始化的方法
   * 1.呼叫時機:預設情況下,servlet被第一次訪問時呼叫
   * loadOnStartup:預設是-1,改成正整數則訪問servlet的時候直接建立
   * (使用屬性來更改呼叫的時機使用屬性要先補全註解裡面的屬性值urlPatterns =)
   * 2.呼叫次數:1次*/
   @Override
   public void init(ServletConfig servletConfig) throws ServletException {
       System.out.println("init");
  }
   /*提供服務
   * 1.呼叫時機:每一次servlet被訪問時就呼叫
   * 2.呼叫次數:每次訪問頁面就會被呼叫*/
   @Override
   public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
       System.out.println("selevet hello world");
  }
   /*1銷燬方法
   * 呼叫時機:記憶體釋放或者伺服器關閉的時候,servlet物件會被銷燬,呼叫該方法釋放資源
   * 呼叫次數:1次*/
   @Override
   public void destroy() {
       System.out.println("destroy");
  }



   @Override
   public ServletConfig getServletConfig() {

       return null;
  }



   @Override
   public String getServletInfo() {
       return null;
  }




}

其他兩個方法在需要使用時檢視javaee api

這裡說一下要在一個方法中使用另一個方法中的成員變數,則直接提升改成與變數的作用域

servlet體系結構

@WebServlet(urlPatterns ="/demo3")
public class ServletDemo3 extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       System.out.println("get...");
  }

   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       System.out.println("post...");
  }
}

以上程式碼顯示servlet會根據頁面的訪問方式呼叫不同的方法,這裡用一個例子顯示了呼叫的是哪個方法我們通過a.html提交資料到demo3時使用的post方式則會呼叫dopost方法,直接訪問用get方式則使用doget方法

http協議裡一共有七種請求方式,對應了七種方法,用到的時候都是要複寫的

HttpServlet的使用步驟:1.寫類繼承HttpServlet2.重寫doget和dopost方法

使用原理:獲取請求方式,並且根據不同的請求方式,呼叫不同的doxxx方法

servlet urlPattern配置

一個servlet可以配置多個urlPattern,通過這些路徑都可以訪問到servlet

@WebServlet(urlPatterns ={"/demo3""/demo4"})

urlPattern的配置規則:

當一個路徑同時符合精確匹配也符和路徑匹配,則精確匹配的優先順序要高一點

一般只用前三種,第四種儘量不要使用

優先順序依次遞減

xml方式編寫servlet(舊方法,現在一般使用註解的方式配置)

1.繼承httpservlet

public class ServletDemo4 extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       System.out.println("demo4.get...");
  }

   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       System.out.println("demo4.post...");
  }
}

2、在web.xml裡面完成配置

<!--  servlet全類名-->
 <servlet>
   <servlet-name>renyi</servlet-name>
   <servlet-class>com.ember.web.ServletDemo4</servlet-class>
 </servlet>
<!-- servlet訪問路徑-->
 <servlet-mapping>
   <servlet-name>renyi</servlet-name>
   <url-pattern>/demo4</url-pattern><!-- 配置可以訪問的路徑-->
 </servlet-mapping>

很明顯註解的方式簡單多了

Request/Response

Request:獲取請求資料

Response:設定響應資料

以下程式碼實現以下瀏覽器的互動

@WebServlet(urlPatterns ="/demo3")
public class ServletDemo3 extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
       //用request獲取請求資料
       String name=request.getParameter("name");
       resp.setHeader("content-type","text/html;charset=utf-8");
       //用response 設定響應資料
       resp.getWriter().write("<h1>"+name+",歡迎您!<h1>");
  }

   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       System.out.println("post...");
  }
}

當我們在網址後面輸入?name=xxx的時候頁面會根據名字內容更改顯示內容,這就是互動

Request繼承體系:

Tomcat需要解析請求資料,封裝為request物件,並且建立request物件傳遞到service方法中

要使用request物件,直接查閱javaee api文件的httpservletrequest介面

Request獲取請求資料

分為三步:獲取請求行&請求頭&請求體

下面寫一個例子

@WebServlet(urlPatterns = "/req1")
public class RequestDemo1 extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       String method=req.getMethod();//獲取請求方式GET
       System.out.println(method);
       String contextPath=req.getContextPath();
       System.out.println(contextPath);
       StringBuffer url=req.getRequestURL();
       System.out.println(url.toString());
       String uri = req.getRequestURI();
       System.out.println(uri);
       String queryString = req.getQueryString();//獲取請求引數(get方式)
       System.out.println(queryString);
  }

   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       super.doPost(req, resp);
  }
}

對於我們要向頁面傳入一些資訊我們可以寫一個表單完成資料傳入(注意這裡要使用get方式,應為我們是在doget方法中寫的測試)

<form name="user" action="/testtomcat2/req1" method="get">
username:<input name="uername">
  password:<input name="password">
   <input type="submit">
</form>

點選提交後會直接跳轉,資料會返回到控制檯

/*獲取請求頭
* user-agent獲取瀏覽器的版本*/
String agent = req.getHeader("user-agent");
System.out.println(agent);

以上呢get和post都會有,而請求體只有post請求才會有所以要測試請求體的方法則需要寫一個表單

<form  action="/testtomcat2/req1" method="post">
  使用者名稱: <input type="text" name="username">
  密碼:<input type="password" name="password">
   <input type="submit">
</form>
    @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//       獲取post 請求體 請求引數
//       獲取字元輸入流
       BufferedReader br = req.getReader();
       String line = br.readLine();
       System.out.println(line);
  }

通過獲取位元組流或字元流獲得資料

Request通用方式獲取請求引數

因為一個servlet根據請求方式的不同會呼叫不同的方法,但是這兩個方法中只有獲取請求的方式這一段程式碼不同其他的都是差不多的,這就造成了程式碼的重複,所以我們可以使用一種統一的獲取請求引數的方式,從而統一doget和dopost方法內的程式碼

首先我們判斷是哪種請求在呼叫相應的獲取引數的方式,系統將這些引數封裝成一個Map集合,這三個方法就是request物件提供的通用獲取請求引數的方法,以下是對三個方法的實現例子

@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//       GET請求邏輯
       System.out.println("get.....");
//       1.獲取所有引數的MAP集合(iter快捷遍歷)
       Map<String, String[]> map = req.getParameterMap();
       for (String s : map.keySet()) {
//           獲取的格式時username:zhangsan
           System.out.print(s+":");
           //       獲取值
           String[] values = map.get(s);
           for (String value : values) {
               System.out.print(value+" ");
          }
           System.out.println();
      }
       System.out.println("...............");
//       根據key獲取引數值(陣列)
       String[] hobbies = req.getParameterValues("hobby");
       for (String hobby : hobbies) {
           System.out.println(hobby);
      }
//3.根據key獲取單個的引數值
       String username = req.getParameter("username");
       String password = req.getParameter("password");
       System.out.println(username);
       System.out.println(password);

  }

將doget裡面的程式碼全部複製到doget中也是可以獲取到資料的這就是通用的三個方法

因為裡面的程式碼是完全一樣的,所以我們的dopost方法裡只用呼叫doget就可以了

    @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//       POST請求邏輯
   this.doGet(req, resp);
  }
}

使用了通用方式之後,遮蔽了get和post的請求方式的不同,則我們可以使用servlet模板來建立servlet

可以根據需要去改造模板

Request post請求引數中文亂碼處理

這是我們寫了一個例子來獲取使用者名稱,並且在html頁面中提交了中文使用者名稱導致的亂碼

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//   獲取username
       String username = request.getParameter("username");
       System.out.println(username);
  }
//        解決亂碼 POST.getReader()獲取字元流預設的編碼不是utf-8,所以post請求的中文會亂碼
       request.setCharacterEncoding("UTF-8");/*設定字元輸入流的編碼*/

在最上面加入如上程式碼,改變其編碼與html相同

GET請求解決方案

解決中文亂碼 get 亂碼原因:瀏覽器處理資料進行url編碼(UTF-8),伺服器接收資料再進行url解碼(ISO-8859-1),但是編碼解碼使用的字符集不一樣導致亂碼,只能從url編碼底層入手

以下是對get請求傳入中文的username解決辦法

        /*1.先對亂碼資料進行編碼,轉為位元組陣列*/
//       byte[] bytes = username.getBytes(StandardCharsets.ISO_8859_1);
//       /*位元組陣列解碼*/
//       username = new String(bytes, StandardCharsets.UTF_8);
       username=new String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
       System.out.println("解決亂碼後"+username);

熟練過後將上面兩行程式碼合併成一行了,這種方式是一種通用的方式同樣可以解決post亂碼

Request請求轉發

一種在伺服器內部的資源跳轉方式

//        請求轉發
       request.getRequestDispatcher("/req6").forward(request,response);

將請求轉發給另一個路徑,一般兩個路徑要共享資料

在req5頁面中請求轉發

        System.out.println("demo5''''[''");
//       儲存資料
       request.setAttribute("msg","hello");
//       請求轉發
       request.getRequestDispatcher("/req6").forward(request,response);

在req6中接收請求

       獲取資料
       Object msg = request.getAttribute("msg");
       System.out.println(msg);
       System.out.println("demo6'''''''");
  }

轉發的特點:

瀏覽器位址列路徑不發生改變

只能轉發到當前伺服器的內部資源

一次請求,可以在轉發資源間使用request共享資料

Response設定響應資料

以下是響應資料的分類以及對應的設定的方法

Response完成重定向

即當不能處理請求的時候返回其他路徑

即分為兩步:

1.返回狀態碼302

2.返回跳轉路徑

實現:

resp.setStatus(302);

resp.setHeader("location","資源b的路徑")

以下例子

resp1

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       System.out.println("resp1..........");
//       重定向
//       1.設定響應資料碼302
       response.setStatus(302);
//       2.設定響應頭Location
       response.setHeader("Location","/testtomcat2/resp2");//注意資源路徑要寫伺服器的虛擬字首
  }

resp2

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   System.out.println("resp2..........");
}

只要訪問resp1就自動跳轉到resp2

可以發現這個程式碼只有跳轉的路勁會有改變所以以後這樣寫

//        簡化方式完成重定向
       response.sendRedirect("/testtomcat2/resp2");

(注意:可以重定向到任意路徑)

對於路徑書寫

瀏覽器使用:需要加虛擬目錄(專案訪問路徑)

服務端使用:不加虛擬目錄(即不需要瀏覽器跳轉頁面訪問)

對於要加虛擬路徑的時候直接寫虛擬目錄,使得耦合性太強了,以後一改路勁就會出錯,所以我們一般採用動態路徑

//        簡化方式完成重定向
//       response.sendRedirect("/testtomcat2/resp2");
//       動態獲取虛擬目錄
       String contextPath = request.getContextPath();
       response.sendRedirect(contextPath+"resp2");

Response響應字元&位元組資料

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   /*防止設定的位元組流是中文亂碼以及能夠解析html格式和文字格式的字元流*/
   response.setContentType("text/html;charset=utf-8");
   /*1.獲取字元輸出流*/
   PrintWriter writer = response.getWriter();
   writer.write("設定的響應字元");
   writer.write("<h1>wy,你好</h1>");


}

獲取位元組流就是使用的獲取方法不一樣,用與獲取一些檔案並輸出

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//       1. 獲取檔案
       FileInputStream fis = new FileInputStream("C://Users//Ember//Desktop//icon//file.png");
//       2.獲取Response位元組輸出流
       ServletOutputStream os = response.getOutputStream();
//       3.完成流的Copy
       byte[] buff=new byte[1024];
       int len=0;
       while((len=fis.read(buff))!=-1){
           os.write(buff,0,len);
      }
       fis.close();
  }

這種複製方法是javaIO中的知識,我們一般使用工具類來簡化

先去pom裡增加依賴

<dependency>
 <groupId>commons-io</groupId>
 <artifactId>commons-io</artifactId>
 <version>2.6</version>
</dependency>

匯入後即可使用IOUtils的方法了

//        3.完成流的Copy
//       byte[] buff=new byte[1024];
//       int len=0;
//       while((len=fis.read(buff))!=-1){
//           os.write(buff,0,len);
//       }
       IOUtils.copy(fis,os);
       fis.close();

(注意:這裡選著IOUtils時要注意匯入的包是apache)

案例:使用者登入&使用者註冊

1.使用者登入

首先在我們之前建立了maven外掛以及servlet的工程裡首先配置好mybatis需要的環境

<properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <maven.compiler.source>1.7</maven.compiler.source>
 <maven.compiler.target>1.7</maven.compiler.target>
</properties>

<dependencies>
 <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.11</version>
   <scope>test</scope>
 </dependency>
 <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>3.1.0</version>
   <scope>provided</scope>
 </dependency>
 <dependency>
   <groupId>commons-io</groupId>
   <artifactId>commons-io</artifactId>
   <version>2.6</version>
 </dependency>
 <dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis</artifactId>
   <version>3.5.5</version>
 </dependency>
 <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.46</version>
 </dependency>
 <!--       junit 單元測試-->
 <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.2</version>
   <scope>test</scope>
 </dependency>
 <!-- 新增slf4j日誌api -->
 <dependency>
   <groupId>org.slf4j</groupId>