@nextleaf
2018-09-25T12:55:39.000000Z
字数 17102
阅读 1226
Java servlet session 四大域
相关对象:jsp隐含对象application(javax.servlet.ServletContext类的实例)
1、生命周期:当Web应用被加载进容器时创建代表整个web应用的ServletContext对象,当服务器关闭或Web应用被移除时,ServletContext对象跟着销毁。
2、作用范围:整个Web应用。
3、作用:
a)在不同Servlet 之间转发
this.getServletContext().getRequestDispatcher("/servlet/Demo10Servlet").forward(request,response);
b)读取资源文件。
1、生命周期:在service 方法调用前由服务器创建,传入service方法。整个请求结束,request生命结束。
2、作用范围:整个请求链(请求转发也存在)。
3、作用:在整个请求链中共享数据。最常用到:在Servlet中处理好的数据交给Jsp显示,此时参数就可以放置在Request域中带过去。
HttpSession在服务器中,为浏览器创建独一无二的内存空间,在其中保存会话相关的信息。
当一段时间内session没有被使用(默认为30分钟),则服务器会销毁该session。如果服务器非正常关闭(强行关闭),没有到期的session也会跟着销毁。
如果调用session提供的invalidate() ,可以立即销毁session。
注意:服务器正常关闭,再启动,Session对象会进行钝化和活化操作。同时如果服务器钝化的时间在session 默认销毁时间之内,则活化后session还是存在的。否则Session不存在。
如果JavaBean 数据在session钝化时,没有实现Serializable则当Session活化时,会消失。
相关对象:JSP引号对象pageContext(javax.servlet.jsp.PageContext类的实例)
1、生命周期:当对JSP的请求时开始,当响应结束时销毁。
2、作用范围:整个JSP页面,是四大作用域中最小的一个。
作用:
(1)获取其它八大隐式对象,可以认为是一个入口对象。
(2)获取其所有域中的数据
pageContext操作所有域中属性的方法:
public java.lang.ObjectgetAttribute(java.lang.Stringname,intscope)public void setAttribute(java.lang.String name, java.lang.Object value,intscope)public voidremoveAttribute(java.lang.Stringname,intscope)
pageContext 中代表域的常量
PageContext.APPLICATION_SCOPEPageContext.SESSION_SCOPEPageContext.REQUEST_SCOPEPageContext.PAGE_SCOPE
findAttribute方法,在四大域中搜寻属性,搜寻的顺序是page域、request域、session域、application域,从小域到大域开始搜索,如果搜索到就直接获取该值,如果所有域中都找不到,返回一个null(与el表达式不同,此处返回null,对网页是不友好的)。
(3)跳转到其他资源其身上提供了forward和include方法,简化重定向和转发的操作。
session在某server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建
浏览器发出请求
servlet判断cookie消息头中是否有sessionID
如果没有,生成一个,加入到响应头中。
如果有,servlet容器根据此标识查找对应的session对象,如果找到了,且该session对象没有过期,会将此session绑定到此次请求的request对象;如果没找到或者找到的是过期的session对象,则创建新的session,分配新的标识符,同时发送Set-cookie头通知客户端开始保持新的会话。
session是区分客户端的
服务端程序决定何时创建session
1. HttpServletRequest.getSession()被调用,生成全局唯一标识符(sessionid);
2. 开辟数据存储空间。一般会在内存中创建相应的数据结构,但这种情况下,系统一旦掉电,所有的会话数据就会丢失,如果是电子商务网站,这种事故会造成严重的后果。不过也可以写到文件里甚至存储在数据库中,这样虽然会增加I/O开销,但session可以实现某种程度的持久化,而且更有利于session的共享;
3. 将session的全局唯一标示符发送给客户端。
如果客户端禁用了cookie的话,会话保持的实现首选URL重写。
HttpServletRequest.getSession(ture)
若存在会话则返回该会话,否则新建一个会话,等同于HttpServletRequest.getSession()。
HttpServletRequest.getSession(false)
若存在会话则返回该会话,否则返回NULL;
当向Session中存取登录信息时,一般建议:HttpSession session =request.getSession();
当从Session中获取登录信息时,一般建议:HttpSession session =request.getSession(false);
cookie和session二者都能记录状态,cookie是将状态数据保存在客户端,session则保存在服务端。
cookie总数量有限制,每个域名下Cookie个数也有限制,而每个cookie的大小也有限制(通常是4K)
只要HTTP响应中包含如下形式的头,则视为服务器要求客户端设置一个cookie:
Set-cookie:name=name;expires=date;path=path;domain=domain
支持且接收cookie的客户端会创建cookie文件并保存(也可能是内存cookie),用户以后在每次发出请求时,浏览器都要判断当前所有的cookie中有没有没失效(根据expires属性判断)并且匹配了path属性的cookie信息,如果有的话,会以下面的形式加入到请求头中发回服务端:
Cookie: name="zj"; Path="/linkage"
服务端的动态脚本会对其进行分析,并做出相应的处理,当然也可以选择直接忽略。
user表结构
//mysql不支持Date类型设置默认值,这里用varchar代替CREATE TABLE `javabasedemo`.`user` (`username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`birthday` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '1970-01-01',PRIMARY KEY (`username`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
WebWork 2,一个简洁的、可扩展的Java模型 - 视图 - 控制器(MVC)框架
https://www.w3cschool.cn/struts_2/
https://www.cnblogs.com/konrad/p/6426790.html
https://www.w3cschool.cn/struts_2/
https://blog.csdn.net/qq_23703157/article/details/53576831
| 标签 | 描述 |
|---|---|
| <c:out> | 用于在JSP中显示数据,就像<%= ... > |
| <c:set> | 用于保存数据 |
| <c:remove> | 用于删除数据 |
| <c:catch> | 用来处理产生错误的异常状况,并且将错误信息储存起来 |
| <c:if> | 与我们在一般程序中用的if一样 |
| <c:choose> | 本身只当做<c:when>和<c:otherwise>的父标签 |
| <c:when> | <c:choose>的子标签,用来判断条件是否成立 |
| <c:otherwise> | <c:choose>的子标签,接在<c:when>标签后,当<c:when>标签判断为false时被执行 |
| <c:import> | 检索一个绝对或相对 URL,然后将其内容暴露给页面 |
| <c:forEach> | 基础迭代标签,接受多种集合类型 |
| <c:forTokens> | 根据指定的分隔符来分隔内容并迭代输出 |
| <c:param> | 用来给包含或重定向的页面传递参数 |
| <c:redirect> | 重定向至一个新的URL. |
| <c:url> | 使用可选的查询参数来创造一个URL |
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!--uri命名空间-->
例
<%@ page import="s.entity.User" %><%@ page import="java.time.LocalDate" %><%@ page import="java.util.ArrayList" %><%@ page import="java.util.Arrays" %><%@ page import="s.entity.Book" %><%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><html><head><title>JSTL</title><style>td{text-align: center;}.row1{background-color: gainsboro;}.row2{background-color: darkgray;}</style></head><body><%User user = new User("黄昭鸿", "密码", LocalDate.now());request.setAttribute("u1", user);ArrayList<Book> bookslist = new ArrayList<Book>(Arrays.asList(new Book("武侠小说", "天龙八部", "查良镛", 2005, 95.2, "小说以宋哲宗时代为背景,通过宋、辽、大理、西夏、吐蕃等王国之间的武林恩怨和民族矛盾,从哲学的高度对人生和社会进行审视和描写,展示了一幅波澜壮阔的生活画卷,其故事之离奇曲折、涉及人物之众多、历史背景之广泛、武侠战役之庞大、想象力之丰富当属“金书”之最。"),new Book("武侠小说", "笑傲江湖", "查良镛", 1969, 75.3, "其所折射中国人独特的政治斗争,同时也表露对斗争的哀叹,具有一定的政治寓意。"),new Book("武侠小说", "倚天屠龙记", "查良镛", 1962, 71.7, "以安徽农民朱元璋揭竿而起建立明朝天下为背景,以张无忌的成长为线索,叙写江湖上的各帮各派、各种人物的恩怨情仇,它把中国历史上元朝的兴衰和江湖道义、恩仇平行交叉起来。"),new Book("武侠小说", "神雕侠侣", "查良镛", 1961, 74.5, "“叛国贼”杨康之遗孤杨过与其师小龙女之间的爱情故事。")));request.setAttribute("bookslist", bookslist);%><div><p>姓名:${u1.username}</p><p>密码:${u1.password}</p><p>生日:${u1.birthday}</p></div><c:if test="${u1.username.length()>3}">长名字</c:if><c:if test="${u1.username.length()<=3}">短名字</c:if><c:choose><c:when test="${u1.username.length()>3}"> 长</c:when><c:otherwise> 短</c:otherwise></c:choose><hr><div><table cellspacing="0" cellpadding="0" border="1"><caption>书列表</caption><tr><td>分类</td><td>书名</td><td>作者</td><td>年份</td><td>价格</td><td width="70%">简介</td><td>下标</td><td>次数</td></tr><c:forEach var="book" items="${bookslist}" varStatus="vs"><tr class="row${(vs.index%2+1)}"><td>${book.category}</td><td>${book.title}</td><td>${book.author}</td><td>${book.year}</td><td>${book.price}</td><td>${book.synopsis}</td><td>${vs.index}</td><td>${vs.count}</td></tr></c:forEach></table></div><hr><div><p>ServerInfo:</p><p><%=request.getSession().getServletContext().getAttribute("serverInfo")%></p></div><hr></body></html>
依赖:
<!-- https://mvnrepository.com/artifact/jstl/jstl --><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!-- https://mvnrepository.com/artifact/taglibs/standard --><dependency><groupId>taglibs</groupId><artifactId>standard</artifactId><version>1.1.2</version></dependency>
<c:out>标签用来显示一个表达式的结果,与<%=%>作用相似,它们的区别就是<c:out>标签可以直接通过"."操作符来访问属性。
举例来说,如果想要访问customer.address.street,只需要这样写:<c:out value="customer.address.street">。
<c:out>标签会自动忽略XML标记字符,所以它们不会被当做标签来处理
语法:
<c:out value="<string>" default="<string>" escapeXml="<true|false>"/>
属性:
| 属性 | 描述 | 是否必要 | 默认值 |
|---|---|---|---|
| value | 要输出的内容 | 是 | 无 |
| default | 输出的默认值 | 否 | 主体中的内容 |
| escapeXml | 是否忽略XML特殊字符 | 否 | true |
语法:
<c:setvar="<string>"value="<string>"target="<string>"property="<string>"scope="<string>"/>
属性:
| 属性 | 描述 | 是否必要 | 默认值 |
|---|---|---|---|
| value | 要存储的值 | 否 | 主体的内容 |
| target | 要修改的属性所属的对象 | 否 | 无 |
| property | 要修改的属性 | 否 | 无 |
| var | 存储信息的变量 | 否 | 无 |
| scope | var属性的作用域 | 否 | Page |
如果指定了target属性,那么property属性也需要被指定。
可以指定这个变量的作用域,若未指定,则默认为变量第一次出现的作用域。
语法:
<c:remove var="<string>" scope="<string>"/>
属性:
| 属性 | 描述 | 是否必要 | 默认值 |
|---|---|---|---|
| var | 要移除的变量名称 | 是 | 无 |
| scope | 变量所属的作用域 | 否 | 所有作用域 |
判断表达式的值,如果表达式的值为 true 则执行其主体内容
语法:
<c:if test="<boolean>" var="<string>" scope="<string>">...</c:if>
属性
| 属性 | 描述 | 是否必要 | 默认值 |
|---|---|---|---|
| test | 条件 | 是 | 无 |
| var | 用于存储条件结果的变量 | 否 | 无 |
| scope | var属性的作用域 | 否 | page |
例子:模拟 if-else:
<c:if test="${salary > 2000}" var="flag" scope="session"><p>我的工资为: <c:out value="${salary}"/><p></c:if><c:if test="${not flag}"><p>我的工资为: <c:out value="${salary}"/><p></c:if>
<c:forEach>, <c:forTokens>标签
${expr}
| 操作符 | 描述 |
|---|---|
| . | 访问一个Bean属性或者一个映射条目 |
| [] | 访问一个数组或者链表的元素 |
| ( ) | 组织一个子表达式以改变优先级 |
| + | 加 |
| - | 减或负 |
| * | 乘 |
| / or div | 除 |
| % or mod | 取模 |
| == or eq | 测试是否相等 |
| != or ne | 测试是否不等 |
| < or lt | 测试是否小于 |
| > or gt | 测试是否大于 |
| <= or le | 测试是否小于等于 |
| >= or ge | 测试是否大于等于 |
| && or and | 测试逻辑与 |
| || or or | 测试逻辑或 |
| ! or not | 测试取反 |
| empty | 测试是否空值 |
(JSP九大隐式对象见https://www.zybuluo.com/nextleaf/note/1282797#jsp%E9%9A%90%E5%90%AB%E5%AF%B9%E8%B1%A1)
| 隐含对象 | 描述 |
|---|---|
| pageScope | page 作用域 |
| requestScope | request 作用域 |
| sessionScope | session 作用域 |
| applicationScope | application 作用域 |
| param | Request 对象的参数,字符串 |
| paramValues | Request对象的参数,字符串集合 |
| header | HTTP 信息头,字符串 |
| headerValues | HTTP 信息头,字符串集合 |
| initParam | 上下文初始化参数 |
| cookie | Cookie值 |
| pageContext | 当前页面的pageContext |
<%@ page import="s.entity.User" %><%@ page import="java.time.LocalDate" %><%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %><html><head><title>a</title></head><body><%request.setAttribute("user", new User("slf", "huang", LocalDate.now()));%><div>${user.username}</div><div>${user.password}</div><div>${user.birthday}</div><div>算术运算${"123"+"456"}</div><div>算术运算${"123"+456}</div><div>加号“+”不能用于字符串拼接<%--$报错{"123a"+456}--%></div><div>逻辑运算</div></body></html>
ServletContext是JavaWeb四大域对象之一每个Web项目,运行时部署在Web应用服务器(如Tomcat)下,我们称之为一个应用(Application)。
一个Web应用里可以有多个Servlet,而这里的Servlet上下文就可以理解为这些Servlet的运行环境。
当Web应用被加载进容器时创建代表整个web应用的ServletContext对象,当Web应用被移除或服务器关闭时,ServletContext对象跟着销毁。
方法执行结束,service就会返回到服务器,再有服务器去调用目标servlet,其中request会重新创建,并将之前的request的数据拷贝进去。
1、由于相对路径默认相对的是java虚拟机启动的目录,所以我们直接写相对路径将会是相对于tomcat/bin目录,所以是拿不到资源的。如果写成绝对路径,当项目发布到其他环境时,绝对路径就错了。
2、为了解决这个问题ServletContext提供了:
this.getServletContext().getRealPath("/1.properties"),给进一个资源的虚拟路径,将会返回该资源在当前环境下的真实路径。
this.getServletContext().getResourceAsStream("/1.properties"),给一个资源的虚拟路径返回到该资源真实路径的流。
3、当在非servlet下获取资源文件时,就没有ServletContext对象用了,此时只能用类加载器
classLoader.getResourceAsStream("../../1.properties"),此方法利用类加载器直接将资源加载到内存中,有更新延迟的问题,以及如果文件太大,占用内存过大。
classLoader.getResource("../1.properties").getPath(),直接返回资源的真实路径,没有更新延迟的问题。
。。。
重定向:客户端请求容器的资源A,A可以发回一个302状态码和一个location的消息头,客户端收到状态码后,立即向location指向位置发出请求。
转发:客户端请求服务器的资源A,A通知容器,由容器将控制器交给组件B继续完成后续的工作。
(1).地址栏的变化:重定向后,地址栏会发生变化,转发后地址栏不会发生变化。
(2).请求的资源:转发只能是应用内的资源,而重定向没有这个限制。
(3).转发过程中涉及到的组件共享同一对request和response,而重定向则不会。
(4).执行效率:
转发是一次请求一次响应,效率相对较高。
重定向发了多次请求,效率相对转发较低。
如何选择使用转发还是使用重定向?
转发:一件事还没有做完,需要其他组件继续做。(例如当查询这一件事中,如果有了数据为了显示则用转发)
重定向:一件事做完了,去做另外一件事.(例如,增加或删除一条员工后想显示数据则用重定向)
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head><title>登录页</title><style>td{text-align: center;}</style></head><body><div align="center"><form action="login.action" method="post"><table><tr><td><label for="user-name-label1">用户名 </label></td><td><input name="username" required="required" id="user-name-label1"></td></tr><tr><td><label for="user-name-label2">密码 </label></td><td><input type="password" name="password" required="required" id="user-name-label2"></td></tr><tr><td colspan="2"><input type="submit" value="登录"></td></tr></table></form></div></body></html>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %><%@ page import="s.entity.User,java.time.*" %><html><head><title>主页</title></head><body><%HttpSession s = request.getSession(false);if (!s.isNew() && s.getAttribute("user") != null) {User user = (User) s.getAttribute("user");MonthDay birth = MonthDay.from(user.getBirthday());MonthDay currbirth = MonthDay.from(LocalDate.now());String str;if (birth.equals(currbirth)) {str = "!今天(" + LocalDate.now().toString() +")是你的生日(" + user.getBirthday() + ")";} else {str = "!今天(" + LocalDate.now().toString() +")不是你的生日(" + user.getBirthday() + ")";}out.print("<!doctype html><html lang=\"zh\"><head><meta charset=\"UTF-8\"><title>首页</title></head><body><div align=\"center\"><h1>你好," +user.getUsername() + str + "</h1><p><a href=\"logout.action\">登出</a></p></div></body></html>");out.flush();out.close();} else {System.out.println("登录后才能访问!");out.print("<!doctype html><html lang=\"zh\"><head><script type=\"text/javascript\">alert(\"登录后才能访问!\");window.location.href=\"login.jsp\";</script></head><body></body></html>");out.flush();out.close();}%></body></html>
LoginAction.java
package s.controler;import s.dao.UserDao;import s.entity.User;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import java.io.IOException;import java.io.PrintWriter;/*** Created with IntelliJ IDEA 2018.** session(HttpSession类的实例)与cookie相比较** (1) session存在服务器端,比较安全。* (2) session存储的数据大小没有限制* (3) session中存储的数据类型没有限定,而cookie只能存储字符串。** @author: 黄昭鸿* @date: 2018-09-19* Time: 10:55*/public class LoginAction extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf-8");resp.setCharacterEncoding("utf-8");resp.setContentType("text/html;charset=UTF-8");String uri = req.getRequestURI();String reqName = uri.substring(uri.lastIndexOf('/') + 1, uri.lastIndexOf('.'));System.out.println("请求为" + reqName);UserDao userDao = new UserDao();switch (reqName) {case "login":User user = userDao.validateUser(req.getParameter("username").trim(), req.getParameter("password").trim());if (user != null) {req.getSession().setAttribute("user", user);resp.sendRedirect("index.jsp");} else {System.out.println("验证失败");PrintWriter pw = resp.getWriter();pw.println("<!doctype html><html lang=\"zh\"><head><script type=\"text/javascript\">alert(\"验证失败\");window.location.href=\"login.jsp\";</script></head><body></body></html>");//resp.sendRedirect("login.jsp");pw.flush();pw.close();}break;case "logout":HttpSession s = req.getSession(false);if (s == null || s.getAttribute("user") == null) {resp.sendRedirect("login.jsp");/* 或者PrintWriter pw = resp.getWriter();pw.println("<!doctype html><html lang=\"zh\"><head><script type=\"text/javascript\">alert(\"未登录\");window.location.href=\"login.jsp\";</script></head><body></body></html>");pw.flush();pw.close();*/} else if (s.getAttribute("user") != null) {s.invalidate();PrintWriter pw = resp.getWriter();pw.println("<!doctype html><html lang=\"zh\"><head><script type=\"text/javascript\">alert(\"已退出\");window.location.href=\"login.jsp\";</script></head><body></body></html>");pw.flush();pw.close();}break;default:System.out.println("未定义的操作:" + reqName);}}}
UserDao.java
package s.dao;import s.entity.User;import s.util.DButil;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.time.LocalDate;/*** Created with IntelliJ IDEA 2018.* Description:** @author: 黄昭鸿* @date: 2018-09-19* Time: 10:57*/public class UserDao {//validateUserpublic User validateUser(String username, String password) {Connection con = null;User user;try {con = DButil.getConnection();String sql = "SELECT birthday FROM user WHERE username=? AND password=?";PreparedStatement ps = con.prepareStatement(sql);ps.setString(1, username);ps.setString(2, password);ResultSet rs = ps.executeQuery();//SQLException: Before start of result set//在对结果集ResultSet进行操作之前,一定要先用ResultSet.next()将指针移动至结果集的第一行if (rs.next()) {user = new User(username,password, LocalDate.parse(rs.getString("birthday")));System.out.println(username+"验证成功");return user;}else {System.out.println("用户名或密码错误");return null;}} catch (Exception e) {e.printStackTrace();return null;} finally {if (con != null) {DButil.closeConnection(con);}}}//返回user或nullpublic User findById(String id) {Connection con = null;User user = null;try {con = DButil.getConnection();String sql = "SELECT username,password,birthday FROM user WHERE username=?";PreparedStatement ps = con.prepareStatement(sql);ps.setString(1, id);ResultSet rs = ps.executeQuery();//SQLException: Before start of result set//在对结果集ResultSet进行操作之前,一定要先用ResultSet.next()将指针移动至结果集的第一行if (rs.next()) {user = new User(rs.getString("username"), rs.getString("password"), LocalDate.parse(rs.getString("birthday")));System.out.println(rs.getString("birthday"));}return user;} catch (Exception e) {e.printStackTrace();return null;} finally {if (con != null) {DButil.closeConnection(con);}}}}
User.java
package s.entity;import java.time.LocalDate;/*** Created with IntelliJ IDEA 2018.* Description:实体类* API版本在1.8+才能使用LocalDate类** @author: 黄昭鸿* @date: 2018-09-19* Time: 10:58*/public class User {private String username,password;//mysql不支持Date类型设置默认值private LocalDate birthday;public User() {}public User(String username, String password, LocalDate birthday) {this.username = username;this.password = password;this.birthday = birthday;}@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", password='" + password + '\'' +", birthday=" + birthday +'}';}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public LocalDate getBirthday() {return birthday;}public void setBirthday(LocalDate birthday) {this.birthday = birthday;}}
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_4_0.xsd"version="4.0"><welcome-file-list><welcome-file>login.jsp</welcome-file></welcome-file-list><servlet><servlet-name>loginAction</servlet-name><servlet-class>s.controler.LoginAction</servlet-class></servlet><servlet-mapping><servlet-name>loginAction</servlet-name><url-pattern>*.action</url-pattern></servlet-mapping></web-app>