1. 程式人生 > >【Head First Servlets and JSP】實踐記錄01:從有腳本到無腳本

【Head First Servlets and JSP】實踐記錄01:從有腳本到無腳本

view 找不到 idt import == post 判斷 attr 查找

試圖章節式的閱讀《Head First Servlets and JSP》總感覺不對勁,這本書前後的聯系性很強,有點類似於“連續劇”,而不是通常的“知識清單”。

  • 可以建立多態的bean引用嗎

  • 使用type,但沒有class

  • scope屬性默認為“page”

從有腳本到無腳本

1、快速搭建一個測試環境:輸入用戶名,返回“Hello, 用戶名”

index.html

<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <title>Title</title> <style> body { font-family:‘comic sans ms‘,sans-serif; } </style> </head> <body> <form action="checking" method="post"> <p>
Name:</p> <p><input type="text" name="name" value="admin"></p> <p>Comments: </p> <p><textarea name="comments" rows="7" cols="30">Your comments</textarea></p> <p><input type="submit"></p> </
form> </body> </html>

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_3_1.xsd"
         version="3.1">

        <servlet>
            <servlet-name>checking</servlet-name>
            <servlet-class>com.demo.checking</servlet-class>
        </servlet>

        <servlet-mapping>
            <servlet-name>checking</servlet-name>
            <url-pattern>/checking</url-pattern>
        </servlet-mapping>

</web-app>

com.demo.checking

package com.demo;

import javax.servlet.RequestDispatcher;
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 checking 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 name = req.getParameter("name");
        req.setAttribute("name", name);

        RequestDispatcher view = req.getRequestDispatcher("/index.jsp");
        view.forward(req, resp);
    }
}

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
    <style>
      body {
        font-family:‘comic sans ms‘,sans-serif;
      }
    </style>
  </head>
  <body>
    <p>Hello, <%=request.getAttribute("name")%></p>
    <%--<p>Hello, <%=request.getParameter("name")%></p>--%>
  </body>
</html>

2、把傳遞“值”改為傳遞“對象”

com.demo.Person

package com.demo;

public class Person implements java.io.Serializable {
    private String name;

    public Person() {

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

com.demo.checking

package com.demo;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class checking 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 {
        Person person = new Person();
        person.setName(req.getParameter("name"));
        req.setAttribute("person", person);

        RequestDispatcher view = req.getRequestDispatcher("/index.jsp");
        view.forward(req, resp);
    }
}

index.jsp

<%@ page import="com.demo.Person" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
    <style>
      body {
        font-family:‘comic sans ms‘,sans-serif;
      }
    </style>
  </head>
  <body>
    <p>Hello, <%=((Person)request.getAttribute("person")).getName()%></p>
  </body>
</html>

3、不過,還記得那個備忘錄嗎?可以用一句話來總結:“使用腳本則死”。所以我們需要另一種方法。

Person是一個JavaBean,所以我們使用與bean相關的標準動作

<%@ page import="com.demo.Person" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
    <style>
      body {
        font-family:‘comic sans ms‘,sans-serif;
      }
    </style>
  </head>
  <body>
    <jsp:useBean id="person" class="com.demo.Person" scope="request" />
    <p>Person created by servlet: <jsp:getProperty name="person" property="name" /></p>
  </body>
</html>

<jsp:useBean>與<jsp:getProperty>的關系

<jsp:useBean>可以用來聲明和初始化你在<jsp:getProperty>中使用的具體bean對象。

<jsp:getProperty>中的“name”值與<jsp:useBean>中的“id”值相對應;<jsp:useBean>中的“id”值與requst中的person屬性對應。// req.setAttribute("person", person);

事實上,上述代碼在_jspService()中將會變成這樣

      com.demo.Person person = null;
      person = (com.demo.Person) _jspx_page_context.getAttribute("person", javax.servlet.jsp.PageContext.REQUEST_SCOPE);
      if (person == null){
        person = new com.demo.Person();
        _jspx_page_context.setAttribute("person", person, javax.servlet.jsp.PageContext.REQUEST_SCOPE);
      }

技術分享

關於PageContext可以參考這裏。

4、使用JavaBean標準動作設置對象的成員值。

<%@ page import="com.demo.Person" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
    <style>
      body {

        font-family:‘comic sans ms‘,sans-serif;
      }
    </style>
  </head>
  <body>
    <%-- id值對應request的實例域中的person --%>
    <jsp:useBean id="person" class="com.demo.Person" scope="request" />
    <jsp:setProperty name="person" property="name" value="fuck_admin" />
    <p>Person created by servlet: <jsp:getProperty name="person" property="name" /></p>
  </body>
</html>

5、但是,上述代碼有一個問題:覆蓋了用戶輸入的name。而我們只想在查找不到用戶輸入的時候,自行創建bean並設置實例域的值。

也就是說,我們希望_jspService()中是這樣的:

技術分享

對應的JavaBean標準動作就是:

  <body>
    <%-- id值對應request的實例域中的person成員 --%>
    <jsp:useBean id="person" class="com.demo.Person" scope="request">
      <jsp:setProperty name="person" property="name" value="fuck_admin" />
    </jsp:useBean>
    <p>Person created by servlet: <jsp:getProperty name="person" property="name" /></p>
  </body>

可以建立多態的bean引用嗎?——為<jsp:useBean>增加一個type屬性

也就是說,我們希望用一個父類引用持有子類對象。類似於:

        Person p = new Employee();

首先,我們把Person改為抽象類(這樣就無法創建Person類對象了),然後實現一個Employee類:

package com.demo;

public class Employee extends Person {
    private int empID;

    public int getEmpID() {
        return empID;
    }

    public void setEmpID(int empID) {
        this.empID = empID;
    }
}

接著修改servlet和JSP,如下所示:

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Person person = new Employee();
        person.setName(req.getParameter("name"));
        req.setAttribute("person", person);

        RequestDispatcher view = req.getRequestDispatcher("/index.jsp");
        view.forward(req, resp);
    }

技術分享<<<<——IDE報錯,修改:

  <body>
    <%-- id值對應request的實例域中的person成員 --%>
    <jsp:useBean id="person" type="com.demo.Person" class="com.demo.Employee" scope="request">
      <jsp:setProperty name="person" property="name" value="fuck_admin" />
    </jsp:useBean>
    <p>Person created by servlet: <jsp:getProperty name="person" property="name" /></p>
  </body>

技術分享

type不僅可以是抽象類,也可以是接口類型、普通類。(共同點是都可以作為實現類or子類的持有者)

使用type,但沒有class

試一下就知道了,修改一下JSP;

  <body>
    <%-- id值對應request的實例域中的person成員 --%>
    <jsp:useBean id="person" type="com.demo.Person" scope="request">
      <jsp:setProperty name="person" property="name" value="fuck_admin" />
      <%-- 通過這個體內語句我們可以判斷bean是不是新創建的 --%>
    </jsp:useBean>
    <p>Person created by servlet: <jsp:getProperty name="person" property="name" /></p>
  </body>

完全修改servlet;

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Employee employee = new Employee();
        employee.setName(req.getParameter("name"));
        req.setAttribute("person", employee);

        RequestDispatcher view = req.getRequestDispatcher("/index.jsp");
        view.forward(req, resp);
    }

重新部署,輸出結果仍是admin,證明Person引用正確持有了Employee對象因此“使用type,但沒有class”是可行的這個時候如果我把

上面的一句代碼註釋掉;

        // req.setAttribute("person", employee);

將無法正常運行(並不會輸出fuck_admin),所以,只有type的前提是bean已經在指定作用域存在。

技術分享

scope屬性默認為page

技術分享

【Head First Servlets and JSP】實踐記錄01:從有腳本到無腳本