JavaWeb开发与代码的编写(七)

JavaWeb开发与代码的编写(七)

Jsp标签

JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护。

JSP常用标签

  jsp的常用标签有以下三个

  • <jsp:include>标签  
  • <jsp:forward>标签  
  • <jsp:param>标签

 

<jsp:include>标签 

  <jsp:include>标签用于把另外一个资源的输出内容插入进当前JSP页面的输出内容之中,这种在JSP页面执行时的引入方式称之为动态引入。
语法:
    <jsp:include page="relativeURL | <%=expression%>" flush="true|false" />
  page属性用于指定被引入资源的相对路径,它也可以通过执行一个表达式来获得。
  flush属性指定在插入其他资源的输出内容时,是否先将当前JSP页面的已输出的内容刷新到客户端。 

范例:使用jsp:include标签引入资源

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
     <title>jsp的jsp:include标签测试</title>
   </head> 
   <body>
   <%--使用jsp:include标签引入其它JSP页面--%>
   <jsp:include page="/jspfragments/head.jsp"/>
     <h1>网页主体内容</h1>
    <jsp:include page="/jspfragments/foot.jsp"/>
   </body>
</html>

运行结果:

<jsp:include>标签与include指令的区别

  <jsp:include>标签是动态引入, <jsp:include>标签涉及到的2个JSP页面会被翻译成2个servlet,这2个servlet的内容在执行时进行合并。 
  而include指令是静态引入,涉及到的2个JSP页面会被翻译成一个servlet,其内容是在源文件级别进行合并。

  通过下面的例子来说明<jsp:include>标签与include指令的区别

demo.jsp:

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <%!
     int i=1000;
 %>
 <h1>demo.jsp中i的值为:<%=i%></h1>

分别使用include指令和<jsp:include>标签两种包含语句,包含以上的demo.jsp

范例:使用@include包含内容

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <%!
     int i=10;
%>
<h1>JspIncludeTagDemo01.jsp中i的值为:<%=i%></h1>
<h1><%@include file="/jspfragments/demo.jsp"%></h1>

此时在编译jsp时就已经提示出错了,如下所示:

  

  这个错误说的是变量i已经重复定义了

  运行JspIncludeTagDemo01.jsp,结果如下:

  

  运行后发现出现了重复定义变量i的错误提示信息,因为静态包含是将全部内容包含进来之后,再进行处理,属于先包含后处理。由于被包含进来的页面demo.jsp中定义了一个变量i,而包含页面JspIncludeTagDemo01.jsp本身又定义了一个变量i,所以服务器在处理JspIncludeTagDemo01.jsp这个页面时就会发现里面有两个重复定义的变量i,因此就会报错。

而如果现在使用的是<jsp:include>动态包含的话,观察以下程序:

范例:使用动态包含

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <h1>JspIncludeTagDemo02.jsp</h1>
 <%!
     int i=10;
 %> 
 <h1>JspIncludeTagDemo02.jsp中i的值为:<%=i%></h1>
 <h1><jsp:include page="/jspfragments/demo.jsp" /></h1>

运行结果:

  

  发现结果已经可以正确地显示,而且不会互相影响,这是因为使用jsp:include属于动态包含,动态包含就是指先将各个页面分别处理,处理完之后再将处理后的结果包含进来。
  不管是<jsp:include>标签,还是include指令,它们都会把两个JSP页面内容合并输出,所以这两个页面不要出现重复的HTML全局架构标签,否则输出给客户端的内容将会是一个格式混乱的HTML文档。

*.jspf扩展名文件在jsp:include、@include和c:import中的区别

  JSP规范建议使用.jspf(JSP fragments)作为静态引入文件的扩展名。今天无意中发现,把一个JSP文件命名为jspf扩展名,然后include到另一个jsp文件中的,发现只有用"@include"指令的时候,jspf文件的内容才会被解析并执行其中的jsp指令和tag,而使用"jsp:include"和JSTL的"c:import"都没有用,jspf文件被当作纯文本文件处理了。

比如现在有一个head.jspf页面和foot.jspf页面

head.jspf

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <h1 style="color:red;">网页头部</h1>

foot.jspf

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<h1 style="color:blue;">网页尾部</h1>

首先使用"@include"指令将"head.jspf和foot.jspf" include到IncludeTagTest.jsp页面,如下所示:

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
     <title>jsp的Include指令测试</title>
   </head>
 
   <body>
    <%--使用include标签引入引入jspf页面--%>
     <%@include file="/jspfragments/head.jspf" %>
     <h1>网页主体内容</h1>
     <%@include file="/jspfragments/foot.jspf" %>
   </body>
 </html>

  运行IncludeTagTest.jsp页面,运行结果如下:

  

  jspf文件的内容会被解析并执行其中的jsp指令和tag,查看浏览器解析JspIncludeTagTest.jsp页面生成的源代码,如下所示:

  

  然后再使用<jsp:include>"标签将"head.jspf和foot.jspf" include到JspIncludeTagTest.jsp页面中,如下所示:

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
     <title>jsp的jsp:include标签测试</title>
   </head>
 
   <body>
   <%--使用jsp:include标签引入其它JSPf页面--%>
   <jsp:include page="/jspfragments/head.jspf"/>
     <h1>网页主体内容</h1>
     <jsp:include page="/jspfragments/foot.jspf"/>
   </body>
 </html>

运行JspIncludeTagTest.jsp页面,运行结果如下:

  

  查看浏览器解析JspIncludeTagTest.jsp页面生成的源代码,如下所示:

  

  可以看到,head.jspf和foot.jspf中的<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>没有解析执行,而是原封不动地作为文本内容输出到页面上了,在IE下看不到<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>的输出,在google和火狐浏览器下运行可以看到页面上输出<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>,如下所示:

  

  这说明jspf文件Tomcat服务器被当作纯文本文件处理了,没有当作jsp页面来解析执行,那么该如何解决这个问题呢?如何让tomcat服务器能够解析执行*.jspf文件中的java代码和标签呢,有如下的几种解决办法:

解决办法一:修改web.xml文件,添加对扩展名为*.jspf文件的映射

如下所示:

     <!-- 让jspf扩展名同样成为JSP Servlet处理的文件。 -->
     <servlet-mapping>
         <servlet-name>jsp</servlet-name>
         <url-pattern>*.jspf</url-pattern>
     </servlet-mapping>
     <!-- 让jsp扩展名同样成为JSP Servlet处理的文件。 -->
     <servlet-mapping>
         <servlet-name>jsp</servlet-name>
         <url-pattern>*.jsp</url-pattern>
    </servlet-mapping>

  上面的配置方式也可以简写成这样:

     <servlet-mapping>
         <servlet-name>jsp</servlet-name>
         <url-pattern>*.jsp</url-pattern>
         <!-- 让jspf扩展名同样成为JSP Servlet处理的文件。-->
         <url-pattern>*.jspf</url-pattern>
    </servlet-mapping>

  两种写法的效果都是一样的。

添加这样的配置信息后,此时tomcat服务器就可以正常解析执行*.jspf文件了,如下所示:

  

解决办法二:修改Tomcat服务器的web.xml文件,添加对扩展名为*.jspf文件的映射

找到tomcat服务器的web.xml文件,如下所示:

  

找到名字为jsp的那个Servlet,如下所示:

 <servlet>
         <servlet-name>jsp</servlet-name>
         <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
         <init-param>
             <param-name>fork</param-name>
             <param-value>false</param-value>
         </init-param>
         <init-param>
             <param-name>xpoweredBy</param-name>
             <param-value>false</param-value>
         </init-param>
         <load-on-startup>3</load-on-startup>
 </servlet>

然后根据Servlet名找到对应的servlet-mapping配置,如下所示:

     <!-- The mappings for the JSP servlet -->
     <servlet-mapping>
        <servlet-name>jsp</servlet-name>
         <url-pattern>*.jsp</url-pattern>
         <url-pattern>*.jspx</url-pattern>
     </servlet-mapping>

在这里可以看到,名字为jsp的那个Servlet只支持*.jsp和*.jspx两种扩展名,因此可以在这个地方添加多一个<url-pattern>*.jspf</url-pattern>,如下所示:

     <!-- The mappings for the JSP servlet -->
     <servlet-mapping>
         <servlet-name>jsp</servlet-name>
         <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
        <url-pattern>*.jspf</url-pattern>
     </servlet-mapping>

  经过这样的配置之后,Tomcat服务器就可以正常解析和执行*.jspf文件了。

 

<jsp:forward>标签

  <jsp:forward>标签用于把请求转发给另外一个资源。
  语法:
      <jsp:forward page="relativeURL | <%=expression%>" /> 
  page属性用于指定请求转发到的资源的相对路径,它也可以通过执行一个表达式来获得。

范例:使用<jsp:forward>标签跳转页面

forwarddemo01.jsp

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <%--使用<jsp:forward>标签跳转到forwarddemo02.jsp--%>
<jsp:forward page="/forwarddemo02.jsp"/>

forwarddemo02.jsp

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <h1>跳转之后的页面!!</h1>

运行结果如下:

 

  从页面的显示效果来看,页面已经完成了跳转,但地址栏没有变化,地址栏中显示的地址还是forwarddemo01.jsp,但页面显示的内容却是forwardemo02.jsp中的内容。因为此跳转属于服务器端跳转。只要是服务器端跳转,则地址栏永远没有变化。

 

<jsp:param>标签

  当使用<jsp:include>和<jsp:forward>标签引入或将请求转发给其它资源时,可以使用<jsp:param>标签向这个资源传递参数。
  语法1:
    <jsp:include page="relativeURL | <%=expression%>">
        <jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
    </jsp:include>
  语法2:
    <jsp:forward page="relativeURL | <%=expression%>">
        <jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
    </jsp:include>
  <jsp:param>标签的name属性用于指定参数名,value属性用于指定参数值。在<jsp:include>和<jsp:forward>标签中可以使用多个<jsp:param>标签来传递多个参数。

范例:使用<jsp:param>标签向被包含的页面传递参数

JspIncludeTagDemo03.jsp

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <h1>JspIncludeTagDemo03.jsp</h1>
 <hr/>
 <jsp:include page="/jspfragments/Inc.jsp">
     <jsp:param name="parm1" value="hello" />
     <jsp:param name="parm2" value="gacl" />
 </jsp:include>

Inc.jsp

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <h1>接收从JspIncludeTagDemo03.jsp页面中传递过来的参数:</h1>
 <h2><%=request.getParameter("parm1")%></h2>
 <h2><%=request.getParameter("parm2")%></h2>

  在JspIncludeTagDemo03.jsp页面中使用<jsp:include>标签将Inc.jsp页面包含进来,使用<jsp:param/>标签向Inc.jsp页面传递了两个参数parm1和parm2

  JspIncludeTagDemo03.jsp页面运行结果如下:

 范例:使用<jsp:param>标签向要跳转的页面传递参数

forwarddemo03.jsp

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <%--使用<jsp:forward>标签跳转到forwarddemo04.jsp--%>
 <%--使用<jsp:param>标签向forwarddemo04.jsp传递参数--%>
 <jsp:forward page="/forwarddemo04.jsp">
     <jsp:param name="ref1" value="hello" />
     <jsp:param name="ref2" value="gacl" />
 </jsp:forward>

forwarddemo04.jsp

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <h1>跳转之后的页面!!</h1>
 <h1>接收从forwarddemo03.jsp传递过来的参数:</h1>
 <h1>ref1:<%=request.getParameter("ref1")%></h1>
<h1>ref2:<%=request.getParameter("ref2")%></h1>

运行结果如下:

 

JavaBean

 JavaBean是一个遵循特定写法的Java类,它通常具有如下特点:

  • 这个Java类必须具有一个无参的构造函数
  • 属性必须私有化。
  • 私有化的属性必须通过public类型的方法暴露给其它程序,并且方法的命名也必须遵守一定的命名规范。

javaBean范例:

 1 package gacl.javabean.study;
 2 
 3 /**
 4  * @author gacl
 5  * Person类就是一个最简单的JavaBean
 6  */
 7 public class Person {
 8 
 9     //------------------Person类封装的私有属性---------------------------------------
10     // 姓名 String类型
11     private String name;
12     // 性别 String类型
13     private String sex;
14     // 年龄 int类型
15     private int age;
16     //是否已婚 boolean类型
17     private boolean married;
18     //---------------------------------------------------------
19     
20     //------------------Person类的无参数构造方法---------------------------------------
21     /**
22      * 无参数构造方法
23      */
24     public Person() {
25         
26     }
27     //---------------------------------------------------------
28     
29     //------------------Person类对外提供的用于访问私有属性的public方法---------------------------------------
30     public String getName() {
31         return name;
32     }
33 
34     public void setName(String name) {
35         this.name = name;
36     }
37 
38     public String getSex() {
39         return sex;
40     }
41 
42     public void setSex(String sex) {
43         this.sex = sex;
44     }
45 
46     public int getAge() {
47         return age;
48     }
49 
50     public void setAge(int age) {
51         this.age = age;
52     }
53 
54     public boolean isMarried() {
55         return married;
56     }
57 
58     public void setMarried(boolean married) {
59         this.married = married;
60     }
61     //---------------------------------------------------------
62 }

  JavaBean在J2EE开发中,通常用于封装数据,对于遵循以上写法的JavaBean组件,其它程序可以通过反射技术实例化JavaBean对象,并且通过反射那些遵守命名规范的方法,从而获知JavaBean的属性,进而调用其属性保存数据。

 

JavaBean的属性

JavaBean的属性可以是任意类型,并且一个JavaBean可以有多个属性。每个属性通常都需要具有相应的setter、 getter方法,setter方法称为属性修改器,getter方法称为属性访问器。
  属性修改器必须以小写的set前缀开始,后跟属性名,且属性名的第一个字母要改为大写,例如,name属性的修改器名称为setName,password属性的修改器名称为setPassword。 
  属性访问器通常以小写的get前缀开始,后跟属性名,且属性名的第一个字母也要改为大写,例如,name属性的访问器名称为getName,password属性的访问器名称为getPassword。 
  一个JavaBean的某个属性也可以只有set方法或get方法,这样的属性通常也称之为只写、只读属性。

 

在JSP中使用JavaBean

  JSP技术提供了三个关于JavaBean组件的动作元素,即JSP标签,它们分别为:

  • <jsp:useBean>标签:用于在JSP页面中查找或实例化一个JavaBean组件。
  • <jsp:setProperty>标签:用于在JSP页面中设置一个JavaBean组件的属性。
  • <jsp:getProperty>标签:用于在JSP页面中获取一个JavaBean组件的属性。

<jsp:useBean>标签

  <jsp:useBean>标签用于在指定的域范围内查找指定名称的JavaBean对象,如果存在则直接返回该JavaBean对象的引用,如果不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。 
  常用语法:
    <jsp:useBean id="beanName" class="package.class" scope="page|request|session|application"/>
  "id"属性用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称。
  "class"属性用于指定JavaBean的完整类名(即必须带有包名)。
  "scope"属性用于指定JavaBean实例对象所存储的域范围,其取值只能是page、request、session和application等四个值中的一个,其默认值是page。

<jsp:useBean>标签使用范例:

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <%--
 在jsp中使用jsp:useBean标签来实例化一个Java类的对象
 <jsp:useBean id="person" class="gacl.javabean.study.Person" scope="page"/>
     ┝<jsp:useBean>:表示在JSP中要使用JavaBean。
     ┝id:表示生成的实例化对象,凡是在标签中看见了id,则肯定表示一个实例对象。
     ┝class:此对象对应的包.类名称
     ┝scope:此javaBean的保存范围,四种范围:page、request、session、application
 --%>
 <jsp:useBean id="person" class="gacl.javabean.study.Person" scope="page"/>
 <%
     //person对象在上面已经使用jsp:useBean标签实例化了,因此在这里可以直接使用person对象
     //使用setXxx方法为对象的属性赋值
     //为person对象的name属性赋值
     person.setName("孤傲苍狼");
     //为person对象的Sex属性赋值
     person.setSex("男");
     //为person对象的Age属性赋值
     person.setAge(24);
     //为person对象的married属性赋值
     person.setMarried(false);
 %>
 <!DOCTYPE HTML>
 <html>
   <head>
     <title>jsp:useBean标签使用范例</title>
   </head>
   
   <body>
     <%--使用getXxx()方法获取对象的属性值 --%>
     <h2>姓名:<%=person.getName()%></h2>
     <h2>性别:<%=person.getSex()%></h2>
     <h2>年龄:<%=person.getAge()%></h2>
     <h2>已婚:<%=person.isMarried()%></h2>
   </body>
 </html>

运行结果如下:

<jsp:useBean>执行原理

   上面我们在index.jsp中使用<jsp:useBean id="person" class="gacl.javabean.study.Person" scope="page"/>实例化了一个gacl.javabean.study.Person类的对象,那么这个peson对象是怎么实例化出来的呢?index.jsp在执行的过程中首先会翻译成一个servlet,因此我们可以通过查看index.jsp页面生成的servlet的java代码来查看peson对象的实例化过程

  找到tomcat服务器下的"work\Catalina\localhost\项目名称\org\apache\jsp"这个目录,就可以看到将index.jsp页面翻译成servlet的java源码了,如下所示:

 

  使用文本编辑器打开index_jsp.java文件,在_jspService方法中可以看到person对象的创建过程,如下所示:

      gacl.javabean.study.Person person = null;
       synchronized (_jspx_page_context) {
         person = (gacl.javabean.study.Person) _jspx_page_context.getAttribute("person", PageContext.PAGE_SCOPE);
         if (person == null){
           person = new gacl.javabean.study.Person();
           _jspx_page_context.setAttribute("person", person, PageContext.PAGE_SCOPE);
         }
       }

  下面我们来分析一下上述生成的代码:

  首先是定义一个person对象,值是null

gacl.javabean.study.Person person = null;//定义一个空的person对象

  然后是使用pageContext对象的getAttribute方法获取存储在PageContext.PAGE_SCOPE域中的Person对象

person = (gacl.javabean.study.Person) _jspx_page_context.getAttribute("person", PageContext.PAGE_SCOPE);

  如果在PageContext.PAGE_SCOPE域中的Person对象没有找到person对象,那么就创建一个新的person对象,然后使用pageContext对象的setAttribute方法将新创建的person存储在PageContext.PAGE_SCOPE域中

if (person == null){
          person = new gacl.javabean.study.Person();
          _jspx_page_context.setAttribute("person", person, PageContext.PAGE_SCOPE);
}

  也就是说,在index.jsp中使用<jsp:useBean id="person" class="gacl.javabean.study.Person" scope="page"/>来实例化person对象的过程实际上是执行了上述的java代码来实例化Person对象。这就是<jsp:useBean>标签的执行原理:"首先在指定的域范围内查找指定名称的JavaBean对象,如果存在则直接返回该JavaBean对象的引用,如果不存在则实例化一个新的JavaBean对象并将它以指定的名称存储到指定的域范围中。

 

带标签体的<jsp:useBean>标签

语法:
    <jsp:useBean ...> 
        Body 
    </jsp:useBean> 
功能:
    Body部分的内容只在<jsp:useBean>标签创建JavaBean的实例对象时才执行。这种做法用得不多,了解一下即可

 

<jsp:setProperty>标签

  <jsp:setProperty>标签用于设置和访问JavaBean对象的属性。 
  语法格式一:
    <jsp:setProperty name="beanName" property="propertyName" value="string字符串"/>

  语法格式二:
    <jsp:setProperty name="beanName" property="propertyName" value="<%= expression %>" />

  语法格式三:
    <jsp:setProperty name="beanName" property="propertyName" param="parameterName"/>

  语法格式四:
    <jsp:setProperty name="beanName" property= "*" />
  name属性用于指定JavaBean对象的名称。 
  property属性用于指定JavaBean实例对象的属性名。
  value属性用于指定JavaBean对象的某个属性的值,value的值可以是字符串,也可以是表达式。为字符串时,该值会自动转化为JavaBean属性相应的类型,如果value的值是一个表达式,那么该表达式的计算结果必须与所要设置的JavaBean属性的类型一致。  
  param属性用于将JavaBean实例对象的某个属性值设置为一个请求参数值,该属性值同样会自动转换成要设置的JavaBean属性的类型。

<jsp:setProperty>标签使用范例1:使用jsp:setProperty标签设置person对象的属性值

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  <%--
  在jsp中使用jsp:useBean标签来实例化一个Java类的对象
  <jsp:useBean id="person" class="gacl.javabean.study.Person" scope="page"/>
      ┝<jsp:useBean>:表示在JSP中要使用JavaBean。
      ┝id:表示生成的实例化对象,凡是在标签中看见了id,则肯定表示一个实例对象。
      ┝class:此对象对应的包.类名称
      ┝scope:此javaBean的保存范围,四种范围:page、request、session、application
  --%>
 <jsp:useBean id="person" class="gacl.javabean.study.Person" scope="page"/>
 
 <%--
 使用jsp:setProperty标签设置person对象的属性值
 jsp:setProperty在设置对象的属性值时会自动把字符串转换成8种基本数据类型
 但是jsp:setProperty对于复合数据类型无法自动转换
 --%>
 <jsp:setProperty property="name" name="person" value="白虎神皇"/>
 <jsp:setProperty property="sex" name="person" value="男"/>
 <jsp:setProperty property="age" name="person" value="24"/>
 <jsp:setProperty property="married" name="person" value="false"/>
 <%--
birthday属性是一个Date类型,这个属于复合数据类型,因此无法将字符串自动转换成Date ,用下面这种写法是会报错的
 <jsp:setProperty property="birthday" name="person" value="1988-05-07"/>
 --%>
 <jsp:setProperty property="birthday" name="person" value="<%=new Date()%>"/>
 <!DOCTYPE HTML>
 <html>
   <head>
     <title>jsp:setProperty标签使用范例</title>
   </head>
   
   <body>
     <%--使用getXxx()方法获取对象的属性值 --%>
     <h2>姓名:<%=person.getName()%></h2>
     <h2>性别:<%=person.getSex()%></h2>
     <h2>年龄:<%=person.getAge()%></h2>
     <h2>已婚:<%=person.isMarried()%></h2>
     <h2>出生日期:<%=person.getBirthday()%></h2>
   </body>
 </html>

运行效果如下:

<jsp:setProperty>标签使用范例2:使用请求参数为bean的属性赋值

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  <%--
  在jsp中使用jsp:useBean标签来实例化一个Java类的对象
  <jsp:useBean id="person" class="gacl.javabean.study.Person" scope="page"/>
      ┝<jsp:useBean>:表示在JSP中要使用JavaBean。
      ┝id:表示生成的实例化对象,凡是在标签中看见了id,则肯定表示一个实例对象。
      ┝class:此对象对应的包.类名称
      ┝scope:此javaBean的保存范围,四种范围:page、request、session、application
  --%>
 <jsp:useBean id="person" class="gacl.javabean.study.Person" scope="page"/>
 
 <%--
     jsp:setProperty标签可以使用请求参数为bean的属性赋值
     param="param_name"用于接收参数名为param_name的参数值,然后将接收到的值赋给name属性
 --%>
 <jsp:setProperty property="name" name="person" param="param_name"/>
 <!DOCTYPE HTML>
 <html>
   <head>
     <title>jsp:setProperty标签使用范例</title>
   </head>
   
   <body>
       <%--使用getXxx()方法获取对象的属性值 --%>
        <h2>姓名:<%=person.getName()%></h2>
   </body>
 </html>

运行结果如下:

  

<jsp:setProperty>标签使用范例3:用所有的请求参数为bean的属性赋值

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <%--
  在jsp中使用jsp:useBean标签来实例化一个Java类的对象
  <jsp:useBean id="person" class="gacl.javabean.study.Person" scope="page"/>
      ┝<jsp:useBean>:表示在JSP中要使用JavaBean。
      ┝id:表示生成的实例化对象,凡是在标签中看见了id,则肯定表示一个实例对象。
      ┝class:此对象对应的包.类名称
      ┝scope:此javaBean的保存范围,四种范围:page、request、session、application
  --%>
 <jsp:useBean id="person" class="gacl.javabean.study.Person" scope="page"/>
 
 <%--
     jsp:setProperty标签用所有的请求参数为bean的属性赋值
     property="*"代表bean的所有属性
 --%>
 <jsp:setProperty property="*" name="person"/> 
 <!DOCTYPE HTML>
 <html>
   <head>
     <title>jsp:setProperty标签使用范例</title>
   </head>
   
   <body>
     <%--使用getXxx()方法获取对象的属性值 --%>
    <h2>姓名:<%=person.getName()%></h2>
     <h2>性别:<%=person.getSex()%></h2>
     <h2>年龄:<%=person.getAge()%></h2>
  </body>
 </html>

运行结果如下所示:

  

<jsp:getProperty>标签

  <jsp:getProperty>标签用于读取JavaBean对象的属性,也就是调用JavaBean对象的getter方法,然后将读取的属性值转换成字符串后插入进输出的响应正文中。
  语法:
      <jsp:getProperty name="beanInstanceName" property="PropertyName" />
    name属性用于指定JavaBean实例对象的名称,其值应与<jsp:useBean>标签的id属性值相同。 
    property属性用于指定JavaBean实例对象的属性名。
  如果一个JavaBean实例对象的某个属性的值为null,那么,使用<jsp:getProperty>标签输出该属性的结果将是一个内容为“null”的字符串。

范例:使用jsp:getProperty获取bean对象的属性值

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  <%--
  在jsp中使用jsp:useBean标签来实例化一个Java类的对象
  <jsp:useBean id="person" class="gacl.javabean.study.Person" scope="page"/>
      ┝<jsp:useBean>:表示在JSP中要使用JavaBean。
      ┝id:表示生成的实例化对象,凡是在标签中看见了id,则肯定表示一个实例对象。
      ┝class:此对象对应的包.类名称
      ┝scope:此javaBean的保存范围,四种范围:page、request、session、application
  --%>
 <jsp:useBean id="person" class="gacl.javabean.study.Person" scope="page"/> 
 <%--
 使用jsp:setProperty标签设置person对象的属性值
 jsp:setProperty在设置对象的属性值时会自动把字符串转换成8种基本数据类型
 但是jsp:setProperty对于复合数据类型无法自动转换
 --%>
 <jsp:setProperty property="name" name="person" value="白虎神皇"/>
 <jsp:setProperty property="sex" name="person" value="男"/>
 <jsp:setProperty property="age" name="person" value="24"/>
 <jsp:setProperty property="married" name="person" value="false"/>
 <%--
 birthday属性是一个Date类型,这个属于复合数据类型,因此无法将字符串自动转换成Date ,用下面这种写法是会报错的
 <jsp:setProperty property="birthday" name="person" value="1988-05-07"/>
 --%>
 <jsp:setProperty property="birthday" name="person" value="<%=new Date()%>"/>
 <!DOCTYPE HTML>
 <html>
   <head>
     <title>jsp:getProperty标签使用范例</title>
   </head>
   
   <body>
     <%--使用jsp:getProperty标签获取对象的属性值 --%>
     <h2>姓名:<jsp:getProperty property="name" name="person"/></h2>
     <h2>性别:<jsp:getProperty property="sex" name="person"/></h2>
     <h2>年龄:<jsp:getProperty property="age" name="person"/></h2>
     <h2>已婚:<jsp:getProperty property="married" name="person"/></h2>
     <h2>出生日期:<jsp:getProperty property="birthday" name="person"/></h2>
   </body>
 </html>

运行结果如下:

  关于JavaBean方面的内容基本上就这么多了,只需要掌握JavaBean的写法,以及掌握<jsp:useBean>标签,<jsp:setProperty>标签,<jsp:getProperty>标签的使用!

 

JavaWeb的两种开发模式

jsp+javabean开发模式架构

  jsp+javabean开发模式的架构图如下图(图1-1)所示

图1-1

  在jsp+javabean架构中,JSP负责控制逻辑、表现逻辑、业务对象(javabean)的调用。

  JSP+JavaBean模式适合开发业务逻辑不太复杂的web应用程序,这种模式下,JavaBean用于封装业务数据,JSP即负责处理用户请求,又显示数据。

JSP+JavaBean开发模式编写计算器

  首先分析一下jsp和javabean各自的职责,jsp负责显示计算器(calculator)页面,供用户输入计算数据,并显示计算后的结 果,javaBean负责接收用户输入的计算数据并且进行计算,JavaBean具有firstNum、secondNum、result、 operator属性,并提供一个calculate方法。

  1、编写CalculatorBean,负责接收用户输入的计算数据并且进行计算

  CalculatorBean代码如下:

3 import java.math.BigDecimal;
 4 
 5 /**
 6  * @author gacl
 7  * CalculatorBean用于接收输入参数和计算
 8  */
 9 public class CalculatorBean {
10 
11     //用户输入的第一个数
12     private double firstNum;
13     //用户输入的第二个数
14     private double secondNum;
15     //用户选择的操作运算符
16     private char operator = '+';
17     //运算结果
18     private double result;
19 
20     public double getFirstNum() {
21         return firstNum;
22     }
23 
24     public void setFirstNum(double firstNum) {
25         this.firstNum = firstNum;
26     }
27 
28     public double getSecondNum() {
29         return secondNum;
30     }
31 
32     public void setSecondNum(double secondNum) {
33         this.secondNum = secondNum;
34     }
35 
36     public char getOperator() {
37         return operator;
38     }
39 
40     public void setOperator(char operator) {
41         this.operator = operator;
42     }
43 
44     public double getResult() {
45         return result;
46     }
47 
48     public void setResult(double result) {
49         this.result = result;
50     }
51 
52     /**
53      * 用于计算
54      */
55     public void calculate() {
56 
57         switch (this.operator) {
58             case '+': {
59                 this.result = this.firstNum + this.secondNum;
60                 break;
61             }
62             case '-': {
63                 this.result = this.firstNum - this.secondNum;
64                 break;
65             }
66             case '*': {
67                 this.result = this.firstNum * this.secondNum;
68                 break;
69             }
70             case '/': {
71                 if (this.secondNum == 0) {
72                     throw new RuntimeException("被除数不能为0!!!");
73                 }
74                 this.result = this.firstNum / this.secondNum;
75                 // 四舍五入
76                 this.result = new BigDecimal(this.result).setScale(2,
77                         BigDecimal.ROUND_HALF_UP).doubleValue();
78                 break;
79             }
80             default:
81                 throw new RuntimeException("对不起,传入的运算符非法!!");
82         }
83     }
84 }

  2、编写calculator.jsp,负责显示计算器(calculator)页面,供用户输入计算数据,并显示计算后的结果

  calculator.jsp页面代码如下:

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 <%--使用me.gacl.domain.CalculatorBean --%>
 <jsp:useBean id="calcBean" class="me.gacl.domain.CalculatorBean"/>
 <%--接收用户输入的参数 --%>
 <jsp:setProperty name="calcBean" property="*"/>
 <% 
 //使用CalculatorBean进行计算
  calcBean.calculate();
 %>
 <!DOCTYPE HTML>
 <html>
   <head>
     <title>使用【jsp+javabean开发模式】开发的简单计算器</title>
   </head>  
   <body>
      <br/>
     计算结果是:
     <jsp:getProperty name="calcBean" property="firstNum"/>
     <jsp:getProperty name="calcBean" property="operator"/>
     <jsp:getProperty name="calcBean" property="secondNum"/>
       =
     <jsp:getProperty name="calcBean" property="result"/>     
      <br/><hr> <br/>
     <form action="${pageContext.request.contextPath}/calculator.jsp" method="post">
         <table border="1px">
             <tr>
                 <td colspan="2">简单的计算器</td>
             </tr>
             <tr>
                 <td>第一个参数</td>
                 <td><input type="text" name="firstNum"></td>
             </tr>
             <tr>
                 <td>运算符</td>
                 <td><select name="operator">
                         <option value="+">+</option>
                         <option value="-">-</option>
                         <option value="*">*</option>
                         <option value="/">/</option>
                 </select></td>
             </tr>
             <tr>
                 <td>第二个参数</td>
                 <td><input type="text" name="secondNum"></td>
             </tr>
             <tr>
                 <td colspan="2"><input type="submit" value="计算"></td>
             </tr>
         </table>
    </form>
 </body>
 </html>

 

Servlet+JSP+JavaBean开发模式

  在平时的JavaWeb项目开发中,在不使用第三方mvc开发框架的情况下,通常会选择Servlet+JSP+JavaBean开发模式来开发JavaWeb项目,Servlet+JSP+JavaBean组合开发就是一种MVC开发模式了,控制器(Controller)采用Servlet、模型(Model)采用JavaBean、视图(View)采用JSP。在讲解Servlet+JSP+JavaBean开发模式之前,先简单了解一下MVC开发模式。

Web开发中的请求-响应模型

图2-1

  在Web世界里,具体步骤如下:

  1、Web浏览器(如IE)发起请求,如访问http://www.iteye.com/

  2、Web服务器(如Tomcat)接收请求,处理请求(比如用户新增,则将把用户保存一下),最后产生响应(一般为html)。

  3、web服务器处理完成后,返回内容给web客户端(一般就是我们的浏览器),客户端对接收的内容进行处理(如web浏览器将会对接收到的html内容进行渲染以展示给客户)。

  因此,在Web世界里:都是Web客户端发起请求,Web服务器接收、处理并产生响应。

  一般Web服务器是不能主动通知Web客户端更新内容。虽然现在有些技术如服务器推(如Comet)、还有现在的HTML5 websocket可以实现Web服务器主动通知Web客户端。

  到此我们了解了在web开发时的请求/响应模型,接下来我们看一下标准的MVC模型是什么。

标准MVC模型概述

  MVC模型是一种架构型的模式,本身不引入新功能,只是帮助我们将开发的结构组织的更加合理,使展示与模型分离、流程控制逻辑、业务逻辑调用与展示逻辑分离。如下图(图2-2)所示:

图2-2

MVC(Model-View-Controller)的概念

  首先让我们了解下MVC(Model-View-Controller)的概念:

  Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型(domain)或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据) 和 服务层(行为)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。

  View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。

  Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。 也就是说控制器做了个调度员的工作。

  从图2-1我们还看到,在标准的MVC中模型能主动推数据给视图进行更新(观察者设计模式,在模型上注册视图,当模型更新时自动更新视图),但在Web开发中模型是无法主动推给视图(无法主动更新用户界面),因为在Web开发是请求-响应模型。

  那接下来我们看一下在Web里MVC是什么样子,我们称其为 Web MVC 来区别标准的MVC。

Web MVC概述

  Web MVC中的M(模型)-V(视图)-C(控制器)概念和标准MVC概念一样,我们再看一下Web MVC标准架构,如下图(图2-3)所示:

图2-3

  在Web MVC模式下,模型无法主动推数据给视图,如果用户想要视图更新,需要再发送一次请求(即请求-响应模型)。

Servlet+JSP+JavaBean开发模式介绍

    Servlet+JSP+JavaBean架构其实可以认为就是我们所说的Web MVC模型,只是控制器采用Servlet、模型采用JavaBean、视图采用JSP,如图2-3

图2-4

具体示例代码:

1、模型(model)

2、视图(View)

3、控制器(controller)

从Servlet+JSP+JavaBean(Web MVC)架构可以看出,视图和模型分离了,控制逻辑和展示逻辑分离了。

 

Servlet+JSP+JavaBean开发模式的缺点

  Servlet+JSP+JavaBean(Web MVC)架构虽然实现了视图和模型分离以及控制逻辑和展示逻辑分离,但也有一些比较严重的缺点

Servlet作为控制器的缺点、

  此处的控制器使用Servlet,使用Servlet作为控制器有以下几个缺点:

  1、控制逻辑可能比较复杂,其实我们可以按照规约,如请求参数submitFlag=toLogin,我们其实可以直接调用toLogin方法,来简化控制逻辑;而且每个模块基本需要一个控制器,造成控制逻辑可能很复杂。现在流行的Web MVC框架(如Struts2)都支持"请求参数submitFlag=toAdd,就可以直接调用toAdd方法"这样的处理机制,在Struts2中类似这样的处理机制就称为"动态方法调用"

  2、请求参数到模型的封装比较麻烦,如果能交给框架来做这件事情,我们可以从中得到解放。

  请求参数到模型的封装代码:

 // 1收集参数
 String username = req.getParameter("username");
 String password = req.getParameter("password");
 // 2封装参数
 UserBean user = new UserBean();
 user.setUsername(username);
 user.setPassword(password);

 当有几十个甚至上百个参数需要封装到模型中时,这样写恐怕就痛苦万分了,要写几十次甚至上百次这样的代码,估计写到吐了,所以现在流行的Web MVC框架(如Struts2)都提供了非常方便的获取参数,封装参数到模型的机制,减少这些繁琐的工作。

  3、选择下一个视图,严重依赖Servlet API,这样很难或基本不可能更换视图。

例如:使用Servlet API提供的request对象的getRequestDispatcher方法选择要展示给用户看的视图

  private void toLogin(HttpServletRequest req, HttpServletResponse resp)
             throws ServletException, IOException {
     //使用Servlet API提供的request对象的getRequestDispatcher方法选择视图
      // 此处和JSP视图技术紧密耦合,更换其他视图技术几乎不可能 
     request.getRequestDispatcher("/mvc/login.jsp").forward(request, response);
 }

  4、给视图传输要展示的模型数据,也需要使用Servlet API,更换视图技术也要一起更换,很麻烦。

例如:使用Servlet API提供的request对象给视图传输要展示的模型数据

//使用Servlet API提供的request对象给视图login.jsp传输要展示的模型数据(user)
request.setAttribute("user", user);
request.getRequestDispatcher("/mvc/login.jsp").forward(request, response)

 

JavaBean作为模型的缺点

  此处模型使用JavaBean,JavaBean组件类既负责收集封装数据,又要进行业务逻辑处理,这样可能造成JavaBean组件类很庞大,所以一般现在项目都是采用三层架构,而不直接采用JavaBean。

视图的缺点

  现在被绑定在JSP,很难更换视图,比如Velocity、FreeMarker;比如我要支持Excel、PDF视图等等。

  关于JavaWeb的两种开发模式的讲解就介绍到这里,下一篇将使用servlet+jsp+javabean来开发一个用户登录注册功能,以此来加深servlet+jsp+javabean开发模式的理解。

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wespten

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值