从有脚本到无脚本
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