1. 程式人生 > 實用技巧 >高併發系統設計(二十):分散式架構如何跟蹤排查慢請求問題?

高併發系統設計(二十):分散式架構如何跟蹤排查慢請求問題?

1 web的基本概念

狂神說【javaWeb】






進階路程

2 web伺服器




3 tomcat

下載tomcat

官網http://tomcat.apache.org/

解壓後





4 HTTP







5 maven

maven環境搭建



配置環境變數 :

/conf下的settings.xml中設定

<mirror>
    <id>aliyunmaven</id>
    <mirrorOf>*</mirrorOf>
    <name>阿里雲公共倉庫</name>
    <url>https://maven.aliyun.com/repository/public</url>
</mirror>

<1ocalRepository>D:\Environment\apache-maven-3.6.2\maven-repo</localRepository>

在IDEA中使用maven

根據模板建立maven專案

  1. 啟動idea
  2. 建立一個mavenWeb專案


  3. 等待資源載入
  4. maven本地倉庫中多了很多包
  5. IDEA中的maven設定

建立一個普通的maven專案

在IDEA中配置TomCat





maven 設定jdk版本

<properties>
	<maven.compiler.source>14</maven.compiler.source>
	<maven.compiler.target>14</maven.compiler.target>
</properties>

一些問題

IDEA全域性配置


統一javaapps版本

<?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>

6 servlet *

servlet簡介

  • sun公司開發動態Web的技術
  • 是sun公司的一個介面, 如果要開發一個servlet程式, 只需要兩個小步驟
    1 編寫一個類實現servlet介面
    2 把寫好的java類部署到web伺服器中
  • 把實現了servlet的java程式叫做, servlet

hello servlet

sun公司有兩個預設的實現類: HTTPServlet GenericServlet

  1. 構建一個普通的maven專案, 刪掉src資料夾, 以後的學習就可以在這個專案裡面
  2. 關於maven父子工程的理解
    父專案中會有
<modules>
<module>servlet-01</module>
</modules>

子專案中會有

<parent>
       <artifactId>HelloServlet</artifactId>
       <groupId>com.karl</groupId>
       <version>1.0-SNAPSHOT</version>
</parent>

父專案的java子專案可以直接使用
son extends parent

  1. Maven 環境優化
    3.1 修改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>

3.2 將Maven結構搭建完整
4. 編寫一個servlet程式
4.1 編寫一個普通類
4.2 實現Servlet介面, 繼承HTTPServlet

package com.karl.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        resp.getOutputStream();
        PrintWriter writer = resp.getWriter();//響應流
        writer.println("hello, servlet! ");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}
  1. 編寫Servlet的對映
    為什麼需要對映: 我們寫的是java程式, 但需要通過瀏覽器訪問, 瀏覽器需要連線web伺服器, 所以我們需要在web服務中註冊我們寫的Servlet, 還需要給他一個瀏覽器能訪問的路徑;
<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.karl.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>
  1. 配置tomcat
    注意配置專案釋出的目錄
  2. 啟動測試

servlet 原理

Servlet是由Web伺服器呼叫,web伺服器在收到瀏覽器請求之後,會

Maping

一個servlet可以指定多個對映
一個servlet可以指定通用路徑對映

<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/*</url-pattern>
</servlet-mapping>

指定字尾對映

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

servletContext物件

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

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

    放置資料類
package com.karl.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        this.getInitParameter();//初始化引數
//        this.getServletConfig();//servlet配置
//        this.getServletContext();//servlet上下文

        ServletContext context = this.getServletContext();
        String username = "karl";//資料
        context.setAttribute("username", username);//將一個數據儲存到了servletContext中
    }
}

讀取資料類

package com.karl.servlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

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().println("名字:"+username);
    }
}

servletContext應用

獲取初始化引數

<!--可以配置一些web應用初始化引數-->
    <context-param>
        <param-name>url</param-name>
        <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
    </context-param>
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//讀取初始化引數
        ServletContext context = this.getServletContext();
        String url = (String)context.getInitParameter("url");
        resp.getWriter().println(url);
    }

轉發和重定向

doGet(){
...
//        RequestDispatcher requestDispatcher = context.getRequestDispatcher("");//轉發的路徑
//        requestDispatcher.forward(req,resp);//實現轉發
        context.getRequestDispatcher("").forward(req, resp);
...
}


讀取資原始檔

poperties
classpath: java和resource路徑


思路: 需要一個檔案流;

response

下載檔案

HttpServletResponse

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

  • 如果要獲取客戶端請求過來的引數:找HttpServletRequest
  • 如果要給客戶端響應一些資訊:找HttpServletResponseI

簡單分類

  • 負責向瀏覽器傳送資料的方法
   public ServletOutputStream getOutputStream() throws IOException;//其他流

   public PrintWriter getWriter() throws IOException;//寫中文
  • 向瀏覽器傳送響應頭的方法
public void setDateHeader(String name, long date);

public void addDateHeader(String name, long date);

public void setHeader(String name, String value);

public void addHeader(String name, String value);

public void setIntHeader(String name, int value);

public void addIntHeader(String name, int value);

public void setCharacterEncoding(String charset);

public void setContentLength(int len);

public void setContentType(String type);

public void setBufferSize(int size);

下載檔案

//1 要下載的檔案路徑;
String realPath = "E:\\桌面快捷方式源\\code\\java\\project\\HelloServlet\\response\\src\\main\\resources\\林奚.png";
System.out.println(realPath);
//2 要下載的檔名;
String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
System.out.println(fileName);
//3 瀏覽器支援我們下載檔案, 中文檔名用URLEncoder.encoder()編碼, 否則有可能亂碼;
resp.setHeader("Content-Disposition","attachment;filename = "+ URLEncoder.encode(fileName, StandardCharsets.UTF_8));
//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);
}
//8 關閉流
in.close();
out.close();

驗證碼

前端實現驗證碼: js
後端實現: 需要用到java的圖片類

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //瀏覽器5秒重新整理
        resp.setHeader("refresh", "3");
        //在記憶體中建立一個圖片
        BufferedImage image = new BufferedImage(80, 100, BufferedImage.TYPE_INT_RGB);
        //得到圖片
        Graphics2D g = (Graphics2D)image.getGraphics();
        //設定圖片的背景顏色
        g.setColor(Color.white);
        g.fillRect(0,0,80,20);
        //給圖片寫資料
        g.setColor(Color.blue);
        g.setFont(new Font(null,Font.BOLD,20));
        g.drawString(makeNum(),0,20);
        //告訴瀏覽器這個響應用圖片的形式開啟
        resp.setContentType("image/png");
        //網站有快取, 不讓瀏覽器快取
        resp.setDateHeader("expires",-1);
        resp.setHeader("Cache-Control", "no-cache");
        resp.setHeader("Pragma", "nocache");
        //把圖片寫給瀏覽器
        boolean write = ImageIO.write(image, "png", resp.getOutputStream());

    }
    //生成隨機數
    private String makeNum(){
        Random random = new Random();
        String num = random.nextInt(9999999) + "";
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 7 - num.length(); i++){
            sb.append("0");
        }
        num = sb.toString()+num;
        return num;
    }
//生成隨機數
    private String makeNum(){
        Random random = new Random();
        String num = random.nextInt(9999999) + "";
        num = "0".repeat(Math.max(0, 7 - num.length())) +num;
        return num;
    }

重定向

B一個web資源收到客戶端A請求後,B他會通知A客戶端去訪問另外一個web資源C,這個過程叫重定向

常見場景 :

  • 使用者登入
/*
resp.setHeader("Location" , "/r/img");
resp.setstatus(302);
*/
resp.sendRedirect("/r/img");//重定向時候一定要注意路徑問題,否則404;

重定向和轉發的區別
相同點 : 頁面都會跳轉
不同點 : 轉發的時候URL不會變化; 重定向時URL會變化;

7 cookie和session

有狀態會話:一個同學來過教室,下次再來教室,我們會知道這個同學,曾經來過,稱之為有狀態會話;你能怎麼證明你是西開的學生?
1.發票
西開給你發票
2.學校登記
西開標記你來過了
一個網站,怎麼證明你來過?
客戶端
服務端
1.服務端給客戶端一個信件,客戶端下次訪問服務端帶上信件就可以了; cookie
2.伺服器登記你來過了,下次你來的時候我來匹配你; seesion

儲存會話的兩種技術

cookie

  • 客戶端技術(響應, 請求)

session

  • 伺服器技術,利用這個技術,可以儲存使用者的會話資訊?我們可以把資訊或者資料放在Session中!

常見:網站登入之後,你下次不用再登入了,第二次訪問直接就上去了!

1.從請求中拿到cookie資訊
2.伺服器響應給客戶端cookie

public class CookieDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //伺服器,告訴你,你來的時間,把這個時間封裝成為一個信件,你下帶來,我就知道你來了
        //解決中文亂碼
        req.setCharacterEncoding("utf-8");
        resp.setHeader("Content-type", "text/html;charset=UTF-8");
        resp.setCharacterEncoding("utf-8");
        PrintWriter out = resp.getWriter();
        Cookie[] cookies = req.getCookies();//返回陣列,cookie可能存在多個
        //判斷cookie是否存在
        if (null != cookies){
            out.write("您上一次訪問的時間: ");
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("lastLoginTime")){
                    long lastLoginTime = Long.parseLong(cookie.getValue());
                    Date date = new Date(lastLoginTime);
                    out.write(date.toString());
                }
            }
        }else {
            out.write("這是您第一次訪問本站! ");
        }
        //服務給客戶端響應一個cookie
        Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");
        //設定cookie有效期為一天, 預設為一次會話
        cookie.setMaxAge(24*60*60);
        resp.addCookie(cookie);
    }

cookie:一般會儲存在本地的使用者目錄下appdata;

一個網站cookie是否存在上限: (聊聊細節問題)

  • 一個Cookie只能儲存一個資訊;
  • 一個web站點可以給瀏覽器傳送多個cookie,最多存放20個cookie;
  • Cookie大小有限制4kb;
  • 300個cookie瀏覽器上限

刪除Cookie;

  • 不設定有效期,關閉瀏覽器,自動失效;
  • 設定有效期時間為0 ;

編碼解碼

URLEncoder.encode("卡爾", "utf-8")
URLDecoder. decode(cookie.getvalue(, "utf-8")

session

什麼是Session:

  • 伺服器會給每一個使用者(瀏覽器)建立一個Seesion物件;
  • 一個Seesion獨佔一個瀏覽器,只要瀏覽器沒有關閉,這個Session就存在;
  • 使用者登入之後,整個網站它都可以訪問! -->儲存使用者的資訊;儲存購物車的資訊....

session: 會話:

使用者開啟一個瀏覽器,點選了很多超連結,訪問多個web資源,關閉瀏覽器,這個過程可以稱之為會話 ;

session 存入鍵值對

//解決亂碼問題
req.setCharacterEncoding( "UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType( "text/html;charset=utf-8");
//得到Session
Httpsession session = req.getSession();
//給Session中存東西
session.setAttribute( name: "name" , value: "秦疆");
//獲取Session 的ID
string sessionId = session.getId();
//判斷session是不是新建立
if (session.isNew()){
resp.getwriter().write( s: "session建立成功,ID: "+sessionId);
}else {
resp.getwriter().write( s: "session以及在伺服器中存在了,ID: "+sessionId);
}

session 存入物件

person類

public class Person {
    private String name;
    private int age;
    public Person() {
    }
    public Person( String name,int age) {
        this.name = name;
        this.age = age;
    }
    public string getName() {
        return name;
    }
    public void setName ( String name) {
        this.name = name;
    }
    public int getAge( ) {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

將person物件存入session

//得到Session
Httpsession session = req.getsession();
//給Session中存東西
session.setAttribute( name: "name" ,new Person( name:"秦疆" , age: 1));

取出person物件

//解決亂碼問題
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setcontentType( "text/htm1;charset=utf-8");
//得到Session
Httpsession session = req.getsession( );
Person person = (Person) session.getAttribute( name: "name" );
system.out.println(person.toString());

移除session物件和登出session

Httpsession session = req.getSession();
session.removeAttribute(name: "name");//移除session物件
session.invalidate();  //手動登出session

web.xml

<!--設定session預設的失效時間-->
<session-config>
    <!--15分鐘後session自動失效,以分鐘為單位-->
    <session-timeout>15</session-timeout>
</session-config>

使用場景:

  • 儲存一個登入使用者的資訊;·購物車資訊;
  • 在整個網站中經常會使用的資料,我們將它儲存在Session中;

Session和cookie的區別:

  • Cookie是把使用者的資料寫給使用者的瀏覽器,瀏覽器儲存(可以儲存多個)
  • Session把使用者的資料寫到使用者獨佔Session中,伺服器端儲存(儲存重要的資訊,減少伺服器資源的浪費).
  • Session物件由伺服器建立;

8 JSP

什麼是Jsp?

java servlet pages : Java伺服器端頁面,也和Servlet—樣,用於動態Web技術!

最大的特點:

  • 寫JSP就像在寫HTML

區別:

  • HTML只給使用者提供靜態的資料
  • JSP頁面中可以嵌入JAVA程式碼,為使用者提供動態資料;

Jsp原理

思路:JSP到底怎麼執行的!

  • 程式碼層面沒有任何問題

  • 伺服器內部工作

    • tomcat中有一個work目錄;
    • IDEA中使用Tomcat的會在IDEA的tomcat中生產一個work目

      地址:c: \users \Administrator\.Inte1liJIdea2018.1\system\tomcat\Unnamed_javaweb-session-cookie\work \catalina\ loca1host\RooT\org\apache jsp

發現頁面轉變成了java程式

瀏覽器向伺服器傳送請求,不管訪問什麼資源,其實都是在訪問Servlet!
JSP最終也會被轉換成為一個Java類!

JSP本質上就是一個Servlet

//初始化
public void _jspinit() {
}
//銷燬
public void _jspDestroy() {
}
/ / JSPservice
public void _jspservice(.HttpservletRequest request,HttpservletResponse resp){
}

1.判斷請求
2.內建一些物件

final javax.servlet.jsp. Pagecontext pagecontext;       //頁面上下文
javax.servlet.http.Httpsession session = nu71;          //session
final javax.serv1et.servletcontext application;         //app1ication contextfinal 
javax.servlet.serv1etconfig config;                     // config
javax.servlet.jsp . 3spwriter out = nu17;               // out
fina7 java.1ang. object page = this;                    //page:當前
HttpservletRequest request                              //請求
HttpservletResponse response                            //響應

3.輸出頁面前增加的程式碼

response. setcontentType( "text/html");                                                           //設定響應的頁面型別
pagecontext = _jspxFactory.getPagecontext(this, request, response, nu71, true, 8192, true);
_jspx_page_context = pagecontext;
application = pagecontext. getservletcontext();
config = pagecontext.getservletconfig();
session = pagecontext.getsession();
out = pagecontext.getout();
_jspx_out = out;

4.以上的這些個物件我們可以在JSP頁面中直接使用!

在JSP頁面中;
只要是JAVA程式碼就會原封不動的輸出;
如果是HTML程式碼,就會被轉換為: out.write( "<html> \r\n "); 這樣的格式輸出到前端;

JSP基礎語法和指令

maven的依賴

pom.xml
-------
<dependencies>
  <!--Servlet依賴-->
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
  </dependency>
  <!--JSP依賴-->
  <dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>javax.servlet.jsp-api</artifactId>
    <version>2.3.3</version>
  </dependency>
  <!--JSTL表示式的依賴-->
  <dependency>
    <groupId>javax.servlet.jsp.jstl</groupId>
    <artifactId>jst1-api</artifactId>
    <version>1.2</version>
  </dependency>
  <!-- standard -->
  <dependency>
    <groupid>taglibs</groupId>
    <artifactId>standard</artifactId><version>1.1.2</version>
  </dependency>
</dependencies>

JSP基礎語法

任何語言都有自己的語法,JAVA中有,JSP作為java技術的一種應用,支援Java所有語法,它還擁有一些自己擴充的語法 !(瞭解,知道即可! )

<%--
--JSP表示式
--作用:用來將程式的輸出,輸出到客戶端<%=變數或者表示式%>
--%>

<%= new java.util.Date();%>
<%--jsp指令碼片段--%>

<%
int sum = ;
for (int i = 1; i <=100 ; i++) {
sum+=i;
}
out.println( "<h1>Sum="+sum+"</h1>");
%>
<%--在程式碼嵌入HTML元素--%>
<% for ( int i = 0; i < 5; i++){ %>
<h1>Hello,world<%=i %></h1>
<% } %>

jsp宣告 : 會被編譯到JSP生成Java的類中! 其他的,就會被生成到_jspService方法中!
在JSP,嵌入Java程式碼即可!

<% %>
<%= %>
<%! %>
<%--註釋--%>

JSP的註釋,不會在客戶端顯示,HTML就會!

JSP指令

<%apage args. . .. %>
<%@include file=""%>

<%--@include會將兩個頁面合二為一—-%>
<%@include file="common/header.jsp "%>
<h1>網頁主體</h1>
<%ainclude file="common/footer.jsp"%>

<%--jsP標籤
--jsp:include:拼接頁面,本質還是三個
--%>
<jsp:include page="/common/header.jsp" />
<h1>網頁主體</h1>
<jsp:include page="/common/footer.jsp" />

內建物件及作用域

9大內建物件

  • PageContext 存內容
  • Request 存內容
  • Response
  • Session 存內容
  • Application 【SerlvetContext】存內容
  • config【SerlvetConfig】
  • out
  • page
  • exception

儲存內容的內建物件

<%--儲存內容的內建物件--%>
<%
  pageContext.setAttribute("name1", "秦疆1號");    //儲存的資料只在一個頁面中有效
  request.setAttribute("name2" ,"秦疆2號");        //儲存的資料只在一次請求中有效,請求轉發會攜帶這個資料
  session.setAttribute("name3" , "秦疆3號");       //儲存的資料只在一次會話中有效,從開啟瀏覽器到關閉瀏覽版多結經
  application.setAttribute("name4" , "秦疆4號");   //儲存的資料只在伺服器中有效,從開啟伺服器到關團
%>

<%--指令碼片段中的程式碼,會被原封不動生成到xxx_JSP.java: 要求 : 這裡面的程式碼必須保證Java語法正確--%>
<%
  //從pageContext取出,我們通過尋找的方式來
  //從底層到高層(作用域):
  String name1 = (String) pageContext.findAttribute("name1");
  String name2 = (string);pageContext.findAttribute("name2");
  string name3 = (String) pageContext.findAttribute( "name3");
  string name4 = (String) pageContext.findAttribute("name4");
  string name5 = (String) pageContext.findAttribute( "name5");//不存在
%>
<%--使用EL表示式輸出${}--%>
<h1>取出的值為:</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<h3>${name5}</h3>

request: 客戶端向伺服器傳送請求,產生的資料,使用者看完就沒用了,比如:新聞,使用者看完沒用的!
session: 客戶端向伺服器傳送請求,產生的資料,使用者用完一會還有用,比如:購物車;
application: 客戶端向伺服器傳送請求,產生的資料,一個使用者用完了,其他使用者還可能使用,比如:聊夫資料;

JSP標籤, JSTL標籤, EL表示式

pom.xml
-------
<!-- STL表示式的依賴-->
<dependency>
  <groupId>javax.servlet.jsp.jstl</groupId>
  <artifactId>jst1-api</artifactId>
  <version>1.2</version>
</dependency>
<!-- standard標籤庫-->
<dependency>
  <groupId>taglibs</groupId>
  <artifactId>standard</artifactId>
  <version>1.1.2</version>
</dependency>

EL表示式

  • 獲取資料
  • 執行運算
  • 獲取web開發的常用物件

jsp標籤

<%--jsp:incLude--%>
<%-- http://LocaLhost:8080/jsptag.jsp?name=kuangshen&age=12 --%>
<jsp: forward page="/jsptag2.jsp">
  <jsp: param name="name" value="kuangshen"></jsp:param><jsp:param name="age" value="12"></jsp:param>
</jsp:forward>

JSTL標籤

JSTL標籤庫的使用就是為了彌補HTML標籤的不足;它自定義許多標籤,可以供我們使用,標籤的功能和Java程式碼一樣!

JSTL標籤庫使用步驟:

  • 引入對應的taglib
  • 使用其中的方法
  • 在Tomcat也需要引入jstl的包,否則會報錯:JSTL解析錯誤
<%--引入JSTL核心標籤庫,我們才能使用JSTL標籤-%>
<%taglib prefix="c" uri="http://java.sun.com/jsp/jst1/core"%>

<form action="coreif.jsp" method="get">
  <%-- EL表示式獲取表單中的資料${param.引數名} --%>
  <input type="text" name="username" value="${param.username}">
  <input type="submit" value="登入">
</form>
<%--判斷如果提交的使用者名稱是管理員,則登入成功--%>
<c :if test="${param.username== 'admin'}" var="isAdmin">
<c :out value="管理員歡迎您!"/>
</c:if>
<%--自閉合標籤--%>
<c :out value="${isAdmin}" />
<%--定義一個變數score,值為85--%>
<c:set var="score" value="55"/>
<c:choose>
  <c :when test="${score>=90}">
    你的成績為優秀
  </c :when>
  <c : when test="${score>=80}">
    你的成績為一般
  </c:when>
  <c :when test="${score>=70}">
    你的成績為良好
  </c :when>
  <c :when test="${score<=60}">
    你的成績為不及格
  </c :when>
</c:choose>
<%
  ArrayList<String> people = new ArrayList>;
  people.add(O, "張三");
  people.add(1, "李四");
  people.add(2 , "王五");
  people.add(3 , "趙六");
  people.add(4, "田七");
  request.setAttribute("list" , people);
%>

<%--
--var ,每一次遍歷出來的變數
--items,要遍歷的物件
--begin,哪裡開始
--end,到哪裡
--step,步長
--%>
<c:forEach var="people" items="${7ist}">
  <c:out Value="${people}"/> br>
</c:forEach>
<hr>
<c:forEach var="people" items="${list}" begin="1" end="3" step="1" >
  <c:out value="${people}"/><br>
</c:forEach>

9 javaBean

實體類
JavaBean有特定的寫法:

  • 必須要有一個無參構造屬性必須私有化
  • 必須有對應的get/set方法;
  • 一般用來和資料庫的欄位做對映ORM;
    ORM:物件關係對映
<%
  //People peopLe = new People();peoplLe.setAddress( );
  //people.setId();
  //people.setAge();
  //peopLe.setName();
%>
<jsp:useBean id="people" class="com.kuang.pojo.People" scope="page"/>
<jsp:setProperty name="people" property="address" value="西安"/>
<jsp:setProperty name="people" property="id" value="1"/>
<jsp:setProperty name="people" property="age" value="3"/>
<jsp:setProperty name="people" property="name" value="小小"/>

<%--<%=people.getAddress( )%>--%>
姓名: <jsp:getProperty name="people" property="name"/>
id: <jsp:getProperty name="people" property="id" />
年齡:<jsp:getProperty name="people" property="age" />
地址:<jsp:getProperty name="people" property="address" />

10 MVC三層架構

什麼是MVC: Model view Controller模型、檢視、控制器

10.1 早些年

使用者直接訪問控制層,控制層就可以直接操作資料庫;

servlet--CRUD-->資料庫弊端:程式十分臃腫,不利於維護
servlet的程式碼中:處理請求、響應、檢視跳轉、處理JDBC、處理業務程式碼、處理邏輯程式碼
架構:沒有什麼是加一層解決不了的!
程式猿呼叫
JDBC
Mysql oracle sqlserver ....

10.2 MVC三層架構

Model

  • 業務處理:業務邏輯(Service)·資料持久層:CRUD(Dao)View

  • 展示資料提供連結發起Servlet請求(a,form, img...)

controller (Servlet)

  • 接收使用者的請求: (req:請求引數、Session資訊....)

  • 交給業務層處理對應的程式碼

  • 控制檢視的跳轉

    登入--->接收使用者的登入請求--->處理使用者的請求(獲取使用者登入的引數,username,password)---->交給業務層處理登入業務(判斷使用者名稱密碼是否正確:事務)--->Dao層查詢使用者名稱和密碼是否正確-->資料庫
    

11 過濾器(Filter)

什麼是過濾器(Filter)

Filter:過濾器,用來過濾網站的資料;

  • 處理中文亂碼
  • 登入驗證....

Filter開發步驟:

  1. 導包

    <dependencies>
    <!--        servlet依賴-->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
            </dependency>
    <!--        JSP依賴-->
            <dependency>
                <groupId>javax.servlet.jsp</groupId>
                <artifactId>jsp-api</artifactId>
                <version>2.1</version>
            </dependency>
    <!--        JSTL表示式依賴-->
            <dependency>
                <groupId>javax.servlet.jsp.jstl</groupId>
                <artifactId>jstl-api</artifactId>
                <version>1.2</version>
            </dependency>
    <!--        standard標籤庫-->
            <dependency>
                <groupId>taglibs</groupId>
                <artifactId>standard</artifactId>
                <version>1.1.2</version>
            </dependency>
    <!--        連線資料庫-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.49</version>
            </dependency>
        </dependencies>
    
  2. 編寫過濾器

    1. 注意: 導包 import javax.servlet.*;​

    2. 實現Filter介面, 重寫對應的方法

      package com.karl.filter;
      
      import javax.servlet.*;
      import java.io.IOException;
      
      public class CharacterEncodingFilter implements Filter {
          //初始化:web伺服器啟動,就以及初始化了,隨時等待過濾物件出現!
          public void init(FilterConfig filterConfig) throws ServletException {
              System.out.println("CharacterEncodingFilter初始化");
          }
          // Chain :鏈
          /*
              1.過濾中的所有程式碼,在過濾特定請求的機候都會執行
              2.必須要讓過濾器繼續通行
              chain.doFilter( request,response);
          */
      
          public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
              request.setCharacterEncoding("utf-8");
              response.setCharacterEncoding("utf-8");
              response.setContentType("text/html;charset=utf-8");
              System.out.println("doFilter! 1");
              chain.doFilter(request,response);//讓請求繼續走,如果不寫,程式到這裡就被攔截停止!
              System.out.println("doFilter! 2");
          }
      
          //銷燬: web伺服器關閉的時候,過濾會銷燬
          public void destroy() {
              System.out.println("CharacterEncodingFilter銷燬");
          }
      }
      
    3. web.xml 中配置 filter

      <filter>
          <filter-name>CharacterEncodingFilter</filter-name>
          <filter-class>com.karl.filter.CharacterEncodingFilter</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>CharacterEncodingFilter</filter-name>
          <url-pattern>/servlet/*</url-pattern>
      </filter-mapping>
      

12 監聽器

實現一個監聽器的介面

  1. 編寫一個監聽器

    package com.karl.listener;
    
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    //統計網站線上人數: 統計session
    public class OnlineCountListener implements HttpSessionListener {
        @Override
        //建立session監聽:看你的一舉一動
        //一旦建立Session就會觸發一次這個事件!
        public void sessionCreated(HttpSessionEvent httpSessionEvent) {
            ServletContext servletContext = httpSessionEvent.getSession().getServletContext();
            Integer onlineCount = (Integer)servletContext.getAttribute("OnlineCount");
            if (null == onlineCount){
                onlineCount = 1;
            }else {
                int count = onlineCount;
                onlineCount = count + 1;
            }
            servletContext.setAttribute("OnlineCount", onlineCount);
        }
    
        @Override
        //銷燬session監聽
        //一旦銷燬Session就會觸發一次這個事件!
        public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        }
    }
    
  2. web.xml中配置監聽器

    <listener>
        <listener-class>com.karl.listener.OnlineCountListener</listener-class>
    </listener>
    
  3. 看情況使用

13 過濾器的常見使用

登入: 使用者登入之後才能進入主頁!使用者登出後就不能進入主頁了!

  1. 使用者登入之後,向Sesison中放入使用者的資料

    package com.karl.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class LoginServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //獲取前端請求的引數
            String username = req.getParameter("username");
            if (username.equals("admin")){//登入成功
                req.getSession().setAttribute("USER_SESSION",req.getSession().getId());
                resp.sendRedirect(req.getContextPath()+"/sys/success.jsp");
            }else {
                resp.sendRedirect(req.getContextPath()+"/error.jsp");
            }
        }
    }
    
  2. 進入主頁的時候要判斷使用者是否已經登入; 要求:在過濾器中實現!

    package com.karl.filter;
    
    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class SysFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest servletReq = (HttpServletRequest)servletRequest;
            HttpServletResponse servletResp = (HttpServletResponse) servletResponse;
    
            if(null == servletReq.getSession().getAttribute("USER_SESSION")){
                servletResp.sendRedirect(servletReq.getContextPath()+"/error.jsp");
            }
    
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        @Override
        public void destroy() {
    
        }
    }
    
  3. 登出

    package com.karl.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.HashMap;
    
    public class LogoutServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            Object user_session = req.getSession().getAttribute("USER_SESSION");
            if (null != user_session){
                req.getSession().removeAttribute("USER_SESSION");
                resp.sendRedirect(req.getContextPath()+"/index.jsp");
            }else {
                resp.sendRedirect(req.getContextPath()+"/index.jsp");
            }
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    

14 JDBC

什麼是JDBC : Java連線資料庫!

需要jar包的支援:

  • java.sql
  • javax.sql
  • mysql-conneter-java.... 連線驅動((必須要匯入)

匯入資料庫依賴

<! --mysq1的驅動-->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysq1-connector-java</artifactId>
	<version>5.1.47</version>
</dependency>
CREATE TABLE users(
	id lNT PRIMARY KEY,
    `name` VARCHAR(40),
    `password` VARCHAR(40),
    email VARCHAR(60),
    birthday DATE
);
INSERT INTO users(id, `name`, `password` ,email, birthday)
VALUES(1,'張三','123456','[email protected]', '2000-01-01');
INSERT INTO users(id, `name`, `password` ,email, birthday)
VALUES(2,'李四';'123456', '[email protected]'; '2000-01-01');
NSERT INTO users(id, `name`, `password`, email, birthday)
VALUES(3,'王五','123456','[email protected]' ; '2000-01-01'");
package com.karl.test;
import java.sql.*;
public class TestJdbc {
	public static void main(String[] args) throws ClassNotFoundException,sQLException {
	//配置資訊
	//useUnicode=true&characterEncoding=utf-8解決中文亂碼
	String url="jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
	String username = "root";
	String password = "123456";
	//1.載入驅動
	Class.forName("com.mysql.jdbc.Driver" );
	//2.連線資料庫,代表資料庫
	Connection connection = DriverManager.getConnection(url,username,password);
	//3.向資料庫傳送SQL的物件Statement : CRUD
	Statement statement = connection.createstatement();
	//4.編寫SQL
	string sql = "select * from users";
	//5.執行查詢SQL,返回一個Resultset :結果集
	Resultset rs = statement.executeQuery(sql);
	while (rs.next()){
		system.out.println("id="+rs.getobject("id"));
		system.out.println("name="+rs.getobject("name"));
		system.out.println("password="+rs.getobject("password"));
		system.out.println("email="+rs.getobject("email"));
        system.out.println("birthday="+rs.getobject("birthday"));
	}
	//6.關閉連線,釋放資源(一定要做)先開後關
	rs.close();
	statement.close();
	connection.close();

IDEA中連線資料庫

JDBC固定步驟:

  1. 載入驅動
  2. 連線資料庫,代表資料庫
  3. 向資料庫傳送SQL的物件Statement : CRUD
  4. 編寫SQL(根據業務,不同的SQL)
  5. 執行SQL
  6. 關閉連線

預編譯

//1.載入驅動
class.forName( "com.mysq1.jdbc.Driver" ) ;
//2.連線資料庫,代表資料庫
Connection connection = DriverManager.getConnection(url,username,password);
//3.編寫SQL
string sql = "insert into users(id,name,password,email, birthday) values (?,?,?,?,?);";
//4.預編譯
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt( parameterIndex: 1, x: 4);//給第一個佔位符?的值賦值為1;
preparedStatement.setString( parameterlndex: 2,x:"狂神說Java");//給第二個佔位符?的值賦值為狂神說Java;
preparedStatement.setString( parameterlndex: 3, x:"123456");//給第三個佔位符?的值賦值為123456;
preparedStatement . setString( parameterlndex: 4, x:"[email protected]");//給第四個佔位符?的值賦值;
preparedStatement.setDate( parameterlndex: 5,new Date(new java.util.Date().getTime()));
//5.執行SQL
int i = preparedstatement.executeUpdate();
if (i>0){
	system.out.print1n("插入成功@");
}
//6.關閉連線,釋放資源(一定要做)先開後關
preparedStatement.close();
connection.close();

遇到的問題

java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.

SMBMS系統

資料庫

專案如何搭建?

專案搭建準備工作

  1. 搭建一個maven web專案

  2. 配置Tomcat

  3. 測試專案是否能夠跑起來

  4. 匯入專案中會遇到的jar包;

    jsp,Servlet,mysql驅動,jstl,stand...5.

    <dependencies>
      <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
      </dependency>
      <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2.1-b03</version>
      </dependency>
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.49</version>
      </dependency>
        <dependency>
      <groupId>taglibs</groupId>
      <artifactId>standard</artifactId>
      <version>1.1.2</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp.jstl</groupId>
      <artifactId>jstl-api</artifactId>
      <version>1.2</version>
    </dependency>
    </dependencies>
    
  5. 建立專案包結構

  6. 編寫實體類;
    ORM對映:表-類對映

  7. 編寫基礎公共類

    1. 資料庫配置檔案

      driver = com.mysql.jdbc.Driver
      url = jdbc:mysql://localhost:3306?useUnicode=true&charEncoding=utf-8
      username = root
      password = root
      
    2. 資料庫公共類

      package com.karl.dao;
      
      import java.io.IOException;
      import java.io.InputStream;
      import java.sql.*;
      import java.util.Properties;
      
      //操作資料庫的公共類
      public class BaseDao {
          public static String driver;
          public static String url;
          public static String username;
          public static String password;
      
          //靜態程式碼塊,類載入的時候就初始化了
          {
              Properties properties = new Properties();
              //通過類載入器讀取對應的資源
              InputStream is = BaseDao.class.getClassLoader().getResourceAsStream("db.properties");
              try {
                  properties.load(is);
              } catch (IOException e) {
                  e.printStackTrace();
              }
      
              driver = properties.getProperty("driver");
              url = properties.getProperty("url");
              username = properties.getProperty("username");
              password = properties.getProperty("password");
          }
      
          //獲取資料庫的連線
          public static Connection getConnection(){
              Connection connection = null;
              try {
                  Class.forName(driver);
                  connection = DriverManager.getConnection(url, username,password);
              } catch (Exception e) {
                  e.printStackTrace();
              }
              return connection;
          }
      
          //查詢公共方法
          public static ResultSet execute(Connection connection, String sql, Object[] params, ResultSet resultSet, PreparedStatement preparedStatement) throws SQLException {
              //碩編譯的saL.在後面直接執行就可以了
              preparedStatement = connection.prepareStatement(sql);
              for (int i = 0; i < params.length; i++) {
                  //setObject,佔位符從1開始,但是我們的陣列是從e開始!
                  preparedStatement.setObject(i+1, params);
              }
              resultSet = preparedStatement.executeQuery();
              return resultSet;
          }
      
          //增刪改公共方法
          public static int execute(Connection connection, String sql, Object[] params, PreparedStatement preparedStatement) throws SQLException {
              preparedStatement = connection.prepareStatement(sql);
              for (int i = 0; i < params.length; i++) {
                  //setObject,佔位符從1開始,但是我們的陣列是從e開始!
                  preparedStatement.setObject(i+1, params);
              }
              int updateRows = preparedStatement.executeUpdate();
              return updateRows;
          }
      
          //釋放資源
          public static boolean closeResource(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet){
              boolean flag = true;
              if (null != resultSet){
                  try {
                      resultSet.close();
                      //GC回收
                      resultSet = null;
                  } catch (SQLException throwable) {
                      throwable.printStackTrace();
                      flag = false;
                  }
              }
              if (null != connection){
                  try {
                      connection.close();
                      //GC回收
                      connection = null;
                  } catch (SQLException throwable) {
                      throwable.printStackTrace();
                      flag = false;
                  }
              }
              if (null != preparedStatement){
                  try {
                      preparedStatement.close();
                      //GC回收
                      preparedStatement = null;
                  } catch (SQLException throwable) {
                      throwable.printStackTrace();
                      flag = false;
                  }
              }
              return flag;
          }
      }
      
    3. 字元編碼過濾器

      package com.karl.filter;
      
      
      import javax.servlet.*;
      import java.io.IOException;
      
      public class CharacterEncodingFilter implements Filter {
          @Override
          public void init(FilterConfig filterConfig) throws ServletException {
      
          }
      
          @Override
          public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
              request.setCharacterEncoding("utf-8");
              response.setCharacterEncoding("utf-8");
      
              chain.doFilter(request,response);
          }
      
          @Override
          public void destroy() {
      
          }
      }
      

      web.xml

      <filter>
          <filter-name>CharacterEncodingFilter</filter-name>
          <filter-class>com.karl.filter.CharacterEncodingFilter</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>CharacterEncodingFilter</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
      
  8. 匯入靜態資原始檔

登入功能實現

  1. 編寫前端頁面

  2. 設定首頁

    <!--歡迎頁面-->
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>
    
  3. 編寫Dao層登入使用者登入的介面

    package com.karl.dao.user;
    
    import com.karl.pojo.User;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    public interface UserDao {
        //得到要登入的使用者
        public User getLoginUser(Connection connection, String userCode) throws SQLException;
    
    }
    
  4. 編寫Dao介面的實現類

    package com.karl.dao.user;
    
    import com.karl.dao.BaseDao;
    import com.karl.pojo.User;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class UserDaoImpl implements UserDao {
        @Override
        public User getLoginUser(Connection connection, String userCode) throws SQLException {
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
            User user = null;
            if (null != connection){
                String sql = "select * from smbms_user where userCode=?";
                Object[] params = {userCode};
    
    
                resultSet = BaseDao.execute(connection,preparedStatement,resultSet,sql,params);
                if (resultSet.next()){
                    user = new User();
                    user.setId(resultSet.getInt("id"));
                    user.setUserCode(resultSet.getString("userCode"));
                    user.setUserName(resultSet.getString( "userName"));
                    user.setUserPassword(resultSet.getString("userPassword" ));
                    user.setGender(resultSet.getInt("gender" ));
                    user.setBirthday(resultSet.getDate("birthday" ));
                    user.setPhone(resultSet.getString("phone" ));
                    user.setAddress(resultSet.getString("address"));
                    user.setUserRole(resultSet.getInt("userRole"));
                    user.setCreatedBy(resultSet.getInt("createdBy" ));
                    user.setCreationDate(resultSet.getTimestamp("creationDate"));
                    user. setModifyBy(resultSet.getInt("modifyBy" ));
                    user.setModifyDate(resultSet.getTimestamp("modifyDate"));
                }
                BaseDao.closeResource(null, preparedStatement,resultSet);
            }
            return user;
        }
    }
    
  5. 業務層介面

    public User login (String userCode, String password);
    
  6. 業務層實現類

    public class UserServiceImpl implements UserService{
        //業務層都會呼叫dao層,所以我們要引入Dao層;
        private UserDao userDao;
    
        public UserServiceImpl() {
            userDao = new UserDaoImpl();
        }
    
        @Override
        public User login(String userCode, String password) {
            Connection connection = null;
            User user = null;
            try {
                connection = BaseDao.getConnection();
                //通過業務層呼叫對應的具體資料庫操作
                user = userDao.getLoginUser(connection, userCode);
    
            } catch (SQLException throwable) {
                throwable.printStackTrace();
            }finally {
                BaseDao.closeResource(connection,null,null);
            }
            return user;
        }
    
  7. 登入servlet

    package com.karl.servlet.user;
    
    import com.karl.pojo.User;
    import com.karl.service.user.UserService;
    import com.karl.service.user.UserServiceImpl;
    import com.karl.util.Constants;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class LoginServlet extends HttpServlet {
        //servlet: 控制層業務層 service
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("LoginServlet start...");
            String userCode = req.getParameter("userCode");
            String userPassword = req.getParameter("userPassword");
    
            //和資料庫中的密碼對比, 呼叫業務層
            UserService userService = new UserServiceImpl();
            User user = userService.login(userCode, userPassword);//查出登入的人了
            if (null != user && userPassword.equals(user.getUserPassword())){//有此人且密碼正確, 可以登入
                //將資訊放入session中
                req.getSession().setAttribute(Constants.USER_SESSION, user);
                resp.sendRedirect(req.getContextPath() + "/jsp/frame.jsp");//重定向
            }else{//使用者名稱或者密碼錯誤, 不可登入
                //轉發回登入頁面,順帶提示它,使用者名稱或者密碼錯誤;
                req.setAttribute("error", "使用者名稱或密碼不正確");
                req.getRequestDispatcher("/login.jsp").forward(req,resp);//轉發
            }
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
  8. 登入servlet的web.xml配置

        <!--登入servlet-->
        <servlet>
            <servlet-name>LoginServlet</servlet-name>
            <servlet-class>com.karl.servlet.user.LoginServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>LoginServlet</servlet-name>
            <url-pattern>/login.do</url-pattern>
        </servlet-mapping>
    
  9. 登出servlet和servlet配置

    package com.karl.servlet.user;
    
    import com.karl.util.Constants;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class LogoutServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //移除使用者的Constants. USER_SESSION
            req.getSession().removeAttribute(Constants.USER_SESSION);
            //返回登入頁面
            resp.sendRedirect(req.getContextPath()+"/login.jsp");//重定向
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    <!--    登出servlet-->
        <servlet>
            <servlet-name>LogoutServlet</servlet-name>
            <servlet-class>com.karl.servlet.user.LogoutServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>LogoutServlet</servlet-name>
            <url-pattern>/jsp/logout.do</url-pattern>
        </servlet-mapping>
    
  10. 未登入過濾

    package com.karl.filter;
    
    import com.karl.pojo.User;
    import com.karl.util.Constants;
    
    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.net.http.HttpRequest;
    
    public class SysFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
            User user = (User)req.getSession().getAttribute(Constants.USER_SESSION);//過濾器,從session中獲取使用者,
            if (null == user){
                resp.sendRedirect(req.getContextPath()+"/error.jsp");
            }
            else{
                chain.doFilter(request, response);
            }
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

    web.xml

    <!--    未登陸過濾-->
        <filter>
            <filter-name>SysFilter</filter-name>
            <filter-class>com.karl.filter.SysFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>SysFilter</filter-name>
            <url-pattern>/jsp/*</url-pattern>
        </filter-mapping>
    

修改密碼

  1. 匯入前端素材

    <li><a href="${pagecontext.request.contextPath }/jsp/pwdmodify.jsp">密碼修改</a></1i>
    
  2. 寫專案,建議從底層向上寫

  3. UserDao介面

        //修改當前使用者密碼
        int updatePwd(Connection connection, String id, String password) throws SQLException;
    
  4. UserDao介面實現類

        //修改當前使用者密碼
        @Override
        public int updatePwd(Connection connection, String id, String password) throws SQLException {
            String sql = "update smbms_user set userPassword = ? where id = ?";
            Object[] params = {password, id};
            return BaseDao.executeU(connection, sql, params);
        }
    
  5. UserService介面

        //修改密碼業務
        public int updatePwd(String id, String pwd);
    
  6. UserService實現類

        //修改密碼業務
        @Override
        public boolean updatePwd(String id, String pwd) throws SQLException {
            boolean flag = false;
            Connection connection = null;
            connection = BaseDao.getConnection();
            if (userDao.updatePwd(connection, id, pwd)>0){
                flag = true;
            }
    
            BaseDao.closeResource(connection,null,null);
            return flag;
        }
    
  7. servlet配置

    <!--    使用者操作-->
        <servlet>
            <servlet-name>UserServlet</servlet-name>
            <servlet-class>com.karl.servlet.user.UserServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>UserServlet</servlet-name>
            <url-pattern>/jsp/user.do</url-pattern>
        </servlet-mapping>
    
  8. servlet

  9. 實現複用需要提取方法

修改密碼的js(Ajax)

var oldpassword = null;
var newpassword = null;
var rnewpassword = null;
var saveBtn = null;

$(function(){
	oldpassword = $("#oldpassword");
	newpassword = $("#newpassword");
	rnewpassword = $("#rnewpassword");
	saveBtn = $("#save");
	
	oldpassword.next().html("*");
	newpassword.next().html("*");
	rnewpassword.next().html("*");
	
	oldpassword.on("blur",function(){
		$.ajax({
			type:"GET",
			url:path+"/jsp/user.do",
			data:{method:"pwdmodify",oldpassword:oldpassword.val()},
			dataType:"json",
			success:function(data){
				if(data.result === "true"){//舊密碼正確
					validateTip(oldpassword.next(),{"color":"green"},imgYes,true);
				}else if(data.result === "false"){//舊密碼輸入不正確
					validateTip(oldpassword.next(),{"color":"red"},imgNo + " 原密碼輸入不正確",false);
				}else if(data.result === "sessionerror"){//當前使用者session過期,請重新登入
					validateTip(oldpassword.next(),{"color":"red"},imgNo + " 當前使用者session過期,請重新登入",false);
				}else if(data.result === "error"){//舊密碼輸入為空
					validateTip(oldpassword.next(),{"color":"red"},imgNo + " 請輸入舊密碼",false);
				}
			},
			error:function(data){
				//請求出錯
				validateTip(oldpassword.next(),{"color":"red"},imgNo + " 請求錯誤",false);
			}
		});
		
		
	}).on("focus",function(){
		validateTip(oldpassword.next(),{"color":"#666666"},"* 請輸入原密碼",false);
	});
	
	newpassword.on("focus",function(){
		validateTip(newpassword.next(),{"color":"#666666"},"* 密碼長度必須是大於6小於20",false);
	}).on("blur",function(){
		if(newpassword.val() != null && newpassword.val().length > 5
				&& newpassword.val().length < 20 ){
			validateTip(newpassword.next(),{"color":"green"},imgYes,true);
		}else{
			validateTip(newpassword.next(),{"color":"red"},imgNo + " 密碼輸入不符合規範,請重新輸入",false);
		}
	});
	
	
	rnewpassword.on("focus",function(){
		validateTip(rnewpassword.next(),{"color":"#666666"},"* 請輸入與上面一致的密碼",false);
	}).on("blur",function(){
		if(rnewpassword.val() != null && rnewpassword.val().length > 5
				&& rnewpassword.val().length < 20 && newpassword.val() === rnewpassword.val()){
			validateTip(rnewpassword.next(),{"color":"green"},imgYes,true);
		}else{
			validateTip(rnewpassword.next(),{"color":"red"},imgNo + " 兩次密碼輸入不一致,請重新輸入",false);
		}
	});
	
	
	saveBtn.on("click",function(){
		oldpassword.blur();
		newpassword.blur();
		rnewpassword.blur();
		if(oldpassword.attr("validateStatus") === "true"
			&& newpassword.attr("validateStatus") === "true"
			&& rnewpassword.attr("validateStatus") === "true"){
			if(confirm("確定要修改密碼?")){
				$("#userForm").submit();
			}
		}
		
	});
});
//js(Ajax)驗證
    private void pwdmodifyServlet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String oldpassword = req.getParameter("oldpassword");
        //從session裡面拿密碼
        User user = (User) req.getSession().getAttribute(Constants.USER_SESSION);
        //用map傳遞引數 結果集
        HashMap<String, String> resultHashMap = new HashMap<>();

        if (null == user){      //session過期
            resultHashMap.put("result", "sessionerror");
        }else if (oldpassword.isEmpty()){       //得到的密碼為空
            resultHashMap.put("result", "error");
        }else {     //密碼不為空
            if (oldpassword.equals(user.getUserPassword())){        //密碼正確
                resultHashMap.put("result", "true");
            }else {     //密碼錯誤
                resultHashMap.put("result", "false");
            }
        }
        resp.setContentType("application/json");
        PrintWriter writer = resp.getWriter();
        writer.write(JSONArray.toJSONString(resultHashMap));
        writer.flush();
        writer.close();
    }

使用者管理實現

  1. 匯入分頁的工具類

    package com.karl.util;
    
    public class PageSupport {
    	//當前頁碼-來自於使用者輸入
    	private int currentPageNo = 1;
    	
    	//總數量(表)
    	private int totalCount = 0;
    	
    	//頁面容量
    	private int pageSize = 0;
    	
    	//總頁數-totalCount/pageSize(+1)
    	private int totalPageCount = 1;
    
    	public int getCurrentPageNo() {
    		return currentPageNo;
    	}
    
    	public void setCurrentPageNo(int currentPageNo) {
    		if(currentPageNo > 0){
    			this.currentPageNo = currentPageNo;
    		}
    	}
    
    	public int getTotalCount() {
    		return totalCount;
    	}
    
    	public void setTotalCount(int totalCount) {
    		if(totalCount > 0){
    			this.totalCount = totalCount;
    			//設定總頁數
    			this.setTotalPageCountByRs();
    		}
    	}
    	public int getPageSize() {
    		return pageSize;
    	}
    
    	public void setPageSize(int pageSize) {
    		if(pageSize > 0){
    			this.pageSize = pageSize;
    		}
    	}
    
    	public int getTotalPageCount() {
    		return totalPageCount;
    	}
    
    	public void setTotalPageCount(int totalPageCount) {
    		this.totalPageCount = totalPageCount;
    	}
    	
    	public void setTotalPageCountByRs(){
    		if(this.totalCount % this.pageSize == 0){
    			this.totalPageCount = this.totalCount / this.pageSize;
    		}else if(this.totalCount % this.pageSize > 0){
    			this.totalPageCount = this.totalCount / this.pageSize + 1;
    		}else{
    			this.totalPageCount = 0;
    		}
    	}
    	
    }
    
  2. 匯入使用者列表頁

獲取使用者數量

  1. UserDaoImpl

    
        /**
         * 根據使用者名稱或者角色名得到使用者的總數
         *
         * @param connection 資料庫的連線
         * @param username   使用者名稱
         * @param userRole   使用者角色
         * @return int 數量
         */
        @Override
        public int getUserCont(Connection connection, String username, int userRole) throws SQLException {
            int count = 0;//使用者數量
            if (null == connection) {
                return 0;
            }
            StringBuilder sql = new StringBuilder();//新建字串緩衝區用來儲存SQL語句
            sql.append("select count(1) as count from smbms_user u, smbms_role r where u.userRole = r.id ");
            ArrayList<Object> list = new ArrayList<>();//index由0開始
            if (!username.isEmpty()){
                sql.append("and u.userName like ? ");
                list.add("%"+username+"%");//sql中使用like模糊查詢時引數需要%%包裹
            }
            if (!username.isEmpty()){
                sql.append("and u.userRole = ? ");
                list.add(userRole);
            }
            // 把list轉化為陣列
            Object[] objects = list.toArray();
            ResultSet resultSet = BaseDao.executeQ(connection, sql.toString(), objects);//查詢, 並捕獲sql異常
    
            if (resultSet.next()){
                count = resultSet.getInt("count");//從結果集中的到的數量
            }
            BaseDao.closeResource(connection,null,resultSet);
            return count;
        }
    
  2. UserServiceIpml