首页 > 代码库 > 【Head First Servlets and JSP】实践记录01:从有脚本到无脚本

【Head First Servlets and JSP】实践记录01:从有脚本到无脚本

试图章节式的阅读《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="http://www.mamicode.com/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="http://www.mamicode.com/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="http://www.mamicode.com/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:从有脚本到无脚本