首页 > 代码库 > 【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:从有脚本到无脚本