@nextleaf
2018-09-25T20:55:39.000000Z
字数 17102
阅读 1020
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_SCOPE
PageContext.SESSION_SCOPE
PageContext.REQUEST_SCOPE
PageContext.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:set
var="<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 {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected 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 {
//validateUser
public 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或null
public 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;
}
@Override
public 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>