梳理一下web总的一些概念

时间:2023-03-08 16:52:49

servlet中的类适合繁复翻看文档,熟悉各个类的常用方法,看一些经典的案例代码。

ServletConfig

每个项目有多个servlet,每个servlet对应一个ServletCOnfigt对象。ServletConfig中封装的是每个servlet的配置信息,具体而言就是web.xml中<servlet></servlet>中的配置内容。

可以使用HttpSerlet的this.getSerletConfig方法获得servletconfig

ServletContext:

每个项目对应一个ServletContext,ServletContext实体封装的内容对应web.xml中的配置信息,这包含的内容就比较的多了。在一个servlet中可以使用thi.getServletConfig().getServletContext()获取ServletContext也可以使用直接使用this.getServletContext()直接获取,后者中也是调用的第一个的方法。

从上面就就可以看出来,ServletContext的范围比ServletConfig的范围更大一些。


servlet中的域对象

  ServletContext,HttpServletRequest,HttpSession。

jsp中的域对象(当然都是jsp9大内置对象)

  applicaltion,HttpServletRequest,HttpSession,PageContext。application其实就是ServletContext(可以直接查看jsp翻译成的java文件)

servlet中的域对象只有三个,jsp中的域对象是servlet中的三个域对象再加一个jsp特有的pagecontext。

pageContext是使用最多的一个内置对象,可以通过pageContext获取其余八个内置对象。

#获取数据

1)默认情况下,从page域获取

pageContext.getAttribute("name")

2)可以从四个域中获取数据

pageContext.getAttribute("name",域范围常量)

域范围常量:

PageContext.PAGE_SCOPE

PageContext.REQUEST_SCOPE

PageContext.SESSION_SCOPE

PageContext.APPLICATION_SCOPE

3)自动在四个域中搜索数据

pageContext.findAttribute("name");

顺序: page域 -> request域 -> session域- > context域(application域)这展示了四个域的大小

page域: 只能在当前jsp页面中使用(当前页面)

request域: 只能在同一个请求中使用(转发)

session域: 只能在同一个会话(session对象)中使用(私有的)

context域: 只能在同一个web应用中使用。(全局的)

Servlet技术: 开发动态资源。是一个java类,最擅长写java代码

jsp技术: 开发动态资源。通过java代码最擅长输出html代码。


有个不成文的准则,尽量在jsp页面中不写java脚本,为了达到这一目的,jsp中的标签应运而生。

jsp中的标签替换java脚本。

jsp中的EL表达式替换jsp中的输出脚本。


EL表达式

其初衷是为了替换掉,jsp中向浏览器中输出内容的脚本:<%= %> <% %>

基本语法:{$变量或者表达式},集体如下:

1)输出基本数据类型变量

1.1 从四个域获取

${name},会自动按照从小到大的域搜索,相当于pageContext.findAttribute(“name”) page->request->session->application

1.2 指定域获取

${pageScope.name}

域范围: pageScoep / requestScope / sessionScope / applicationScope

分别对应于: page域 request域 session域 application域

2)输出对象的属性值

Class Student

{

String name,id;

Public void setId();

Public void setName();

Public String getId();

Public String getName();

}

{$stu.name}就是输出Student就会调用getName,一定注意el表达式中的后面应当就是getName方法去掉get的内容。

3)输出集合对象

List  和 Map,一样遵守上面的规则。

假设list和map中中存放了若干个Student,那么获取list中student的属性:

{$list[0].id} - {$list[0].name},list[0]相当于((List)pageContext.findAttribute(list)).get(0)

{$map[100.name]}

4)EL表达式计算

${10*5 }

${10!=10 }

${true && false }

判断null: ${name==null }

判断空字符: ${name=="" }


jsp中标签的分类

  • 内置标签(action动作标签): 不需要在jsp页面导入标签
  • jstl标签: 需要在jsp页面中导入标签
  • 自定义标签 : 开发者自行定义,需要在jsp页面导入标签

下面就是分别围绕这三种标签展开介绍

动作标签(内置标签)

内置标签 就是在jsp的空间里面

转发标签: <jsp:forward />

参数标签:  <jsp:pararm/>

包含标签:  <jsp:include/>

原理: 包含与被包含的页面先各自翻译成java源文件,然后再运行时合并在一起,相当于一种调用

(先翻译再合并),动态包含

静态包含  vs  动态包含的区别?

1) 语法不同

静态包含语法: <%@inclue file="被包含的页面"%>

动态包含语法: <jsp:include page="被包含的页面">

2)参数传递不同

静态包含不能向被包含页面传递参数

动态包含可以向被包含页面传递参数

3)原理不同

静态包含: 先合并再翻译

动态包含: 先翻译再合并

======================================

JSTL标签

JSTL (全名:java  standard  tag  libarary   -  java标准标签库  )

核心标签库 (c标签库) 天天用 c core

国际化标签(fmt标签库)

EL函数库(fn函数库)

xml标签库(x标签库)

sql标签库(sql标签库)

使用jstl标签的步骤

1) 导入jstl支持的jar包(标签背后隐藏的java代码)<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

注意:使用javaee5.0的项目自动导入jstl支持jar包,否则就要自己导入。

2)使用taglib指令导入标签库

<%@taglib uri="tld文件的uri名称" prefix="简写" %>

3)在jsp中使用标签

核心标签库的重点标签:

保存数据:

<c:set></c:set>

获取数据:

<c:out value=""></c:out>

单条件判断

<c:if test=""></c:if>

多条件判断

<c:choose></c:choose>

<c:when test=""></c:when>

<c:otherwise></c:otherwise>

循环数据

<c:forEach></c:forEach>

<c:forTokens items="" delims=""></c:forTokens>

重定向

<c:redirect></c:redirect>

在jsp文件的html标签之前使用tablib导入标签库

<%@taglib uri = “路径” prifix = “shotname”/>其中uri和prefix可以到对应标签包的tld文件中查看

核心标签forEach的使用实例:

<body>
    <%--使用标签 --%>
    <%--set标签 :保存数据(保存到域中)默认保存到page域 --%>
    <c:set var="name" value="rose" scope="request"></c:set>
    
    <%
        String msg = null;
        pageContext.setAttribute("msg",msg);
     %>
    
    ${msg }
    <br/>
    <%--out标签: 获取数据(从域中)
    default: 当value值为null时,使用默认值
    escapeXml: 是否对value值进行转义,false,不转义,true,转义(默认)
    --%>
    <c:out value="${msg}" default="<h3>标题3</h3>" escapeXml="true"></c:out>
    
    <hr/>
    
    <%--if标签 :单条件判断--%>
    <c:if test="${!empty msg}">
        条件成立
    </c:if>
    
    <hr/>
    <%--choose标签+when标签+otherwirse标签: 多条件判断 --%>
    <c:set var="score" value="56"></c:set>
    
    <c:choose>
        <c:when test="${score>=90 && score<=100}">
            优秀
        </c:when>
        <c:when test="${score>=80 && score<90}">
            良好
        </c:when>
        <c:when test="${score>=70 && score<80}">
            一般
        </c:when>
        <c:when test="${score>=60 && score<70}">
            及格
        </c:when>
        <c:otherwise>
            不及格
        </c:otherwise>
    </c:choose>
    
    <%-- forEach标签:循环 --%>
    <%
        //List
         List<Student>  list = new ArrayList<Student>();
         list.add(new Student("rose",18));
         list.add(new Student("jack",28));
         list.add(new Student("lucy",38));
         //放入域中
         pageContext.setAttribute("list",list);
         
         //Map
         Map<String,Student> map = new HashMap<String,Student>();
         map.put("100",new Student("mark",20));
         map.put("101",new Student("maxwell",30));
         map.put("102",new Student("narci",40));
         //放入域中
         pageContext.setAttribute("map",map);
     %>
     <hr/>
     <%--
      begin="" : 从哪个元素开始遍历,从0开始.默认从0开始
      end="":     到哪个元素结束。默认到最后一个元素
      step="" : 步长    (每次加几)  ,默认1
      items="": 需要遍历的数据(集合)
      var="": 每个元素的名称
      varStatus="": 当前正在遍历元素的状态对象。(count属性:当前位置,从1开始)
      
     --%>
    <c:forEach items="${list}" var="student" varStatus="varSta">
        序号:${varSta.count} - 姓名:${student.name } - 年龄:${student.age}<br/>
    </c:forEach>
    
    <hr/>
    
    <c:forEach items="${map}" var="entry">
        ${entry.key } - 姓名: ${entry.value.name } - 年龄:${entry.value.age }<br/>
    </c:forEach>
    <hr/>
    <%-- forToken标签: 循环特殊字符串 --%>
    <%
        String str = "java-php-net-平面";
        pageContext.setAttribute("str",str);
     %>
    
    <c:forTokens items="${str}" delims="-" var="s">
        ${s }<br/>
    </c:forTokens>
    
    <%--redrict:重定向 --%>
    <c:redirect url="http://www.baidu.com"></c:redirect>
    
  </body>

自定义标签

2.1 引入

需求: 向浏览器输出当前客户的IP地址 (只能使用jsp标签)

2.2 第一个自定义标签开发步骤

1)编写一个普通的java类,继承SimpleTagSupport类,叫标签处理器类

/**

* 标签处理器类

* @author APPle

* 1)继承SimpleTagSupport

*

*/

public class ShowIpTag extends SimpleTagSupport{

private JspContext context;

/**

* 传入pageContext

*/

@Override

public void setJspContext(JspContext pc) {

this.context = pc;

}

/**

* 2)覆盖doTag方法

*/

@Override

public void doTag() throws JspException, IOException {

//向浏览器输出客户的ip地址

PageContext pageContext = (PageContext)context;

HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();

String ip = request.getRemoteHost();

JspWriter out = pageContext.getOut();

out.write("使用自定义标签输出客户的IP地址:"+ip);

}

}

2)在web项目的WEB-INF目录下建立itcast.tld文件,这个tld叫标签库的声明文件。(参考核心标签库的tld文件)

<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/javaee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"

version="2.1">

<!-- 标签库的版本 -->

<tlib-version>1.1</tlib-version>

<!-- 标签库前缀 -->

<short-name>itcast</short-name>

<!-- tld文件的唯一标记 -->

<uri>http://gz.itcast.cn</uri>

<!-- 一个标签的声明 -->

<tag>

<!-- 标签名称 -->

<name>showIp</name>

<!-- 标签处理器类的全名 -->

<tag-class>gz.itcast.a_tag.ShowIpTag</tag-class>

<!-- 输出标签体内容格式 -->

<body-content>scriptless</body-content>

</tag>

</taglib>

3) 在jsp页面的头部导入自定义标签库

<%@taglib uri="http://gz.itcast.cn" prefix="itcast"%>

4) 在jsp中使用自定义标签

<itcast:showIp></itcast:showIp>

2.3 自定义标签的执行过程

问题: http://localhost:8080/day14/01.hellotag.jsp  如何访问到自定义标签?

前提: tomcat服务器启动时,加载到每个web应用,加载每个web应用的WEB-INF目录下的所有文件!!!例如。web.xml, tld文件!!!

1)访问01.hellotag.jsp资源

2)tomcat服务器把jsp文件翻译成java源文件->编译class->构造类对象->调用_jspService()方法

3)检查jsp文件的taglib指令,是否存在一个名为http://gz.itcast.cn的tld文件。如果没有,则报错

4)上一步已经读到itcast.tld文件

5)读到<itcast:showIp> 到itcast.tld文件中查询是否存在<name>为showIp的<tag>标签

6)找到对应的<tag>标签,则读到<tag-class>内容

7)得到 gz.itcast.a_tag.ShowIpTag

构造ShowIpTag对象,然后调用ShowIpTag里面的方法

2.4 自定义标签处理器类的生命周期

SimpleTag接口:

void setJspContext(JspContext pc)  --设置pageContext对象,传入pageContext(一定调用)

通过getJspCotext()方法得到pageContext对象

void setParent(JspTag parent)  --设置父标签对象,传入父标签对象,如果没有父标签,则不 调用此方法。通过getParent()方法得到父标签对象。

void     setXXX(值)             --设置属性值。

void setJspBody(JspFragment jspBody) --设置标签体内容。标签体内容封装到JspFragment对象 中,然后传入JspFragment对象。通过getJspBody()方法 得到标签体内容。如果没有标签体内容,则不会调 用此方法

void doTag()                     --执行标签时调用的方法。(一定调用)

2.5 自定义标签的作用

1)控制标签体内容是否输出

2)控制标签余下内容是否输出

3)控制重复输出标签体内容

4)改变标签体内容

5)带属性的标签

步骤:

5.1 在标签处理器中添加一个成语变量和setter方法

//1.声明属性的成员变量

private Integer num;

//2.关键点: 必须提供公开的setter方法,用于给属性赋值

public void setNum(Integer num) {

this.num = num;

}

2.6 输出标签体内容格式

JSP:   在传统标签中使用的。可以写和执行jsp的java代码。

scriptless:  标签体不可以写jsp的java代码

empty:    必须是空标签。

tagdependent : 标签体内容可以写jsp的java代码,但不会执行。

 案例

核心标签库: c:if   c:choose+c:when+c:otherwise   c:forEach

高仿核心标签库

在Myeclipse中,alt+shift+z可以进入一种选择模式

选中一块内容,然后ctrl+f,使用正则表达式 ^(.*)$ ^表示行首,$表示行为,.代表任意字符,*表示至少一次。替换为\1;其中\1表示前面组()的引用,表示把前面的内容后面替换为;

制作<itcast:login>标签:

对应的标签处理器类LoginTag.class

public class LoginTag extends SimpleTagSupport{

private String username;

private String password;

public void setUsername(String username) {

this.username = username;

}

public void setPassword(String password) {

this.password = password;

}

@Override

public void doTag() throws JspException, IOException {

HttpServletResponse response = (HttpServletResponse)((PageContext)this.getJspContext()).getResponse();

//设置输出内容类型和编码

response.setContentType("text/html;charset=utf-8");

String html = "";

html += "<center><h3>用户登陆页面</h3></center>";

html += "<table border='1' align='center' width='400px'>";

html += " <tr>";

html += " <th>用户名:</th>";

html += " <td><input type='text' name='"+username+"'/></td>";

html += " </tr>";

html += " <tr>";

html += " <th>密码:</th>";

html += " <td><input type='password' name='"+password+"'/></td>";

html += " </tr>";

html += " <tr>";

html += " <td colspan='2' align='center'><input type='submit' value='登陆'/> <input type='reset' value='重置'/></td>";

html += " </tr>";

html += "</table>";

JspWriter out = this.getJspContext().getOut();

out.write(html);

}

}

对应的tld文件

<tag>

<name>login</name>

<tag-class>gz.itcast.b_cases.LoginTag</tag-class>

<body-content>scriptless</body-content>

<attribute>

<name>username</name>

<required>true</required>

<rtexprvalue>false</rtexprvalue>

</attribute>

<attribute>

<name>password</name>

<required>true</required>

<rtexprvalue>false</rtexprvalue>

</attribute>

</tag>

实现自己的<itcast:choose><itcast:when><itcast:otherwise>标签。注意对应的编前处理类中的设计技巧,这里的choose标签是when和otherwise的父标签,我们给父标签处理类中设置一个变量用来在子标签之间传递信息,但是注意父标签中的这个变量不是父标签的属性。

先看自定义标签的使用:

<body>

<itcast:choose>

<itcast:when test="${10<5}">

条件成立

</itcast:when>

<itcast:otherwise>

条件不成立

</itcast:otherwise>

</itcast:choose>

</body>

各个标签处理类的设计

public class ChooseTag extends SimpleTagSupport {

//不是属性,而是临时变量,用于在子标签之间传递数据

private boolean flag;

public boolean isFlag() {

return flag;

}

public void setFlag(boolean flag) {

this.flag = flag;

}

@Override

public void doTag() throws JspException, IOException {

//输出标签体内容,可能是when或者otherwise中的内容

this.getJspBody().invoke(null);

}

}

public class WhenTag extends SimpleTagSupport {

private boolean test;

public void setTest(boolean test) {

this.test = test;

}

@Override

public void doTag() throws JspException, IOException {

//根据test的返回值决定是否输出标签体内容

if(test){

this.getJspBody().invoke(null);

}

//获取父标签

ChooseTag parent = (ChooseTag)this.getParent();

parent.setFlag(test);

}

}

public class OtherwiseTag extends SimpleTagSupport {

@Override

public void doTag() throws JspException, IOException {

//通过父标签传递,when标签中test的值

//获取父标签

ChooseTag parent = (ChooseTag)this.getParent();

boolean test = parent.isFlag();

if(!test){

this.getJspBody().invoke(null);

}

}

}

线面是自定义的foreach标签

Tld文件

<tag>

<name>forEach</name>

<tag-class>myjstl.ForEachTag</tag-class>

<body-content>scriptless</body-content>

<attribute>

<!-- 标签名称 -->

<name>var</name>

<!-- 这个属性是不是必须的 -->

<required>true</required>

<!-- 是否支持el表达式 -->

<rtexprvalue>false</rtexprvalue>

</attribute>

<attribute>

<name>items</name>

<required>true</required>

<rtexprvalue>true</rtexprvalue>

</attribute>

</tag>

标签处理类

public class ForEachTag extends SimpleTagSupport

{

private Object items; // 需要遍历的数据,list或者map

private String var; // 遍历的变量的名称

public void setItems(Object items) {

this.items = items;

}

public void setVar(String var) {

this.var = var;

}

@Override

public void doTag() throws JspException, IOException {

PageContext context =  (PageContext) this.getJspBody().getJspContext();

Collection coll = null;

if(items instanceof List){

coll = (Collection) items;

}

if(items instanceof Map){

Map map = (Map) items;

coll = map.entrySet();

}

for(Object obj : coll){

context.setAttribute(var, obj);

//每次循环 都显示 标签体的内容

this.getJspBody().invoke(null);

}

}

}

Jsp页面中的使用

<%@taglib uri="http://gz.itcast.cn" prefix="itcast" %>

<%

List<Student> list = new ArrayList<Student>();

list.add(new Student("100", "mike"));

list.add(new Student("101", "jane"));

list.add(new Student("102", "mary"));

list.add(new Student("103", "jordan"));

pageContext.setAttribute("list", list);

Map <String, Student> map = new HashMap<String, Student>();

map.put("001", new Student("101", "mike"));

map.put("002", new Student("102", "kang"));

map.put("003", new Student("103", "mary"));

map.put("004", new Student("104", "jane"));

pageContext.setAttribute("map", map);

%>

<itcast:forEach var = "stu" items = "${list }">

${stu.id }--${stu.name }<br/>

</itcast:forEach>

<itcast:forEach var = "entry" items = "${map}">

${entry.key }--${entry.value.id}--${entry.value.name }<br/>

</itcast:forEach>


JavaBean

JavaBean,  咖啡豆。 JavaBean是一种开发规范,可以说是一种技术。

JavaBean就是一个普通的java类。只有符合以下规定才能称之为javabean:

1)必须提供无参数的构造方法

  2)类中属性都必须私有化(private)

  3)该类提供公开的getter 和 setter方法

JavaBean的作用: 用于封装数据,保存数据。

访问javabean只能使用getter和setter方法

以下方法哪些属于javabean的规范的方法? 答案 :( 1,3,5,6  )

注意: boolean类型的get方法名称叫 isXXX()方法

1)getName()    2)getName(String name)

3)setName(String name)   4)setName()

5) setFlag(boolean flag)   6)isFlag()