目录
- Servlet接口:定义Servlet基础规范:初始化,销毁,获取配置信息 ,Service()方法提供服务
- GenericServlet:实现Service接口,提供初始化,销毁,获取配置信息的默认实现
- HttpServlet:专门处理HTTP请求的Servlet,里面主要根据HTTP协议的特点实现Service规范
- HttpServletRequest:代表客户端的请求,里面保存了客户端请求的所有信息,当一个请求处理方法被调用时服务器会创建这个对象
返回值 | 方法声明 | 说明 |
---|---|---|
String | getParameter(String name) | 根据请求参数名称获取请求参数值,若该参数不存在,则返回一个null |
void | setAttribute(String name,Object value) | 向请求对象(作用域)存一个键值 |
Object | getAttribute(String name) | 通过键从请求对象(作用域)获取一个值 |
void | setCharacterEncoding(String encoding) | 设置请求的字符集 |
Cookie[] | getCookies() | 获取客户端的所有Cookie |
RequestDispatcher | getRequestDispatcher(Stirng path) | 获取请求转发对象 |
- HttpServletResponse:代表服务器向客户端的相应,里面可以保存响应的信息,当一个请求处理方法被调用时服务器会创建这个对象
返回值 | 方法声明 | 说明 |
---|---|---|
void | sendRedirect(java.lang.String location) | 转向(重定向)到指定的资源location |
void | addCookie(Cookie c) | 向客户端保存有个Cookie |
void | setContentType(String type) | 设置响应文档类型 |
一、Servlet的生命周期
1.1 什么是生命周期
/**
* Created by Intellij IDEA
*
* @author 王俊凯
* @Date: 2022/8/31 19:05
* @Version 1.0
*/
package com.wjk.service;
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 LifeServlet extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("2.这是Servlet初始化 ");
}
public LifeServlet() {
System.out.println("1.这是Servlet的构造方法,当Servlet被调用时创建");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("3.当Servlet处理请求时使用");
}
@Override
public void destroy() {
System.out.println("4.当Servlet销毁时");
}
}
就是servlet从创建到初始化再到服务最后到销毁的过程。就是servlet的生命周期。
servlet会在不同的阶段执行不同的方法。
(1)构造方法---->servlet被创建时执行
(2)初始化方法--->servlet创建完成后要初始化一些参数时该方法会被执行。
(3)执行方法--->servlet被调用时。
(4)销毁方法--->servlet被关闭。
浏览器访问的结果
发现:无论发送多少次请求,构造方法和初始化方法只会执行一次。而service每次请求都会被执行。
证明servlet为单例模式. 节约内存空间。
当服务器tomcat重启或者重写部署项目,那么servlet就会被销毁
二、处理请求
一、 以注册为例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<!--method用来设置请求方式,默认是get,如果要使用post请求,必须设置-->
<!--
这里的/带表服务器的根路径,把应用路径给去掉了
解决:加上应用路径/javaweb/RegServlet
1.以/开头的路径称为绝对路径
2.不以/或http协议开头称为相对路径(相对于地址栏)
-->
<form action="RegServlet" method="post">
邮箱:<input name="email"><br>
密码:<input type="password" name="password"><br>
昵称:<input name="nk"><br>
<input type="submit" value="注册">
</form>
</body>
</html>
二、处理注册的Servlet,用来处理注册请求
public class RegServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取请求参数
//请求页面表单里input的name值
String email = req.getParameter("email");
String password = req.getParameter("password");
String nikename = req.getParameter("nk");
//2.业务处理
UserDao userDao = new UserDaoImpl();
User user = new User();
user.setNikename(nikename) ;
user.setEmail(email);
user.setPassword(password);
int rows = userDao.saveUser(user);
//3.转向
//根据业务处理结果给用户响应(一般用转向)
if(rows > 0){
//注册成功,跳转到登录页面
resp.sendRedirect("login.html");
} else {
//注册失败,从新注册
resp.sendRedirect("reg.html");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
三、转向页面
发送是post请求,但是servlet重写的是doGet方法,出现
三、Get请求和Post请求
3.1 get请求
- 参数会直接放到了地址栏里http://localhost:8080/javaweb08_31_01/main.html?email=wjk%40qq.com&password=3510 这样太不安全了
- 地址栏不可以存放大量数据 参数大小也有限制
- 优点是天生会使用浏览器缓存
3.2 Post请求
- 参数不在地址栏中,安全性增加
- 参数在请求体中,可以存放大量的数据
- 缺点是不使用缓存 每次都需要重新加载
四、JSP的使用
一、jsp的概念
JSP(Java Server Page): Java服务器页面,运行在服务器里实现动态网页。就是在HTML里面嵌入Java代码。把JSP里面的代码分成量部分,一部分是静态HTML代码,一部分Java代码。
HTML代码
<%
java代码
%>
分成两部分,但是JSP运行需要经过 翻译(把JSP变成Java代码,第一次请求翻译,如果内容没有改变,不用再翻译,当改变内容要重新翻译)->编译(.class)->运行。
JSP本质上就是一个Servlet,里面的HTML代码直接使用out.write()输出,Java代码在服务器运行。
二、语法
嵌入的Java代码称为JSP脚本
- 脚本段(一段脚本)
<%
//脚本段:一段Java代码,只要原来方法里能写的代码都可以
for (int i = 0; i < 10; i++) {
}
%>
- 表达式:输出一个变量的值
<%= %>
=后面是一个变量或表达式,不能加 ; 号
- 声明
<%!
//声明变量,方法
%>
三、指令
<%@ 指令名称 %>
<%@ page %> 设置JSP页面
<%@ include %> 包含其他JSP页面
<%@ taglib %> 导标签库
内置对象
在JSP里不用声明就可以直接使用的对象。
1、out 来源于Java.io.Writer类,它用于发送输出流到客户端。
2、request 来源于javax.servlet.http.HttpServletRequest接口。它被关联到每一个HTTP请求。
3、response 来源于javax.servlet.http.HttpServletResponse。response对象用于把取得的数据返回到客户端。
4、pageContext 提供访问JSP页面的命名空间。它也提供用来访问其他的JSP隐含对象。
5、session 来源于javax.servlet.http.HttpSession。它用于存储客户端请求的信息,因此它是有状态交互式的。
6、application 来源于javax.servlet.ServletContext。
7、config 来源于ServletConfig,它包含了当前JSP/Servlet所在的WEB应用的配置信息。
8、page 来源于当前被访问JSP页面的实例化。它实际使用的是JSP转换成的Servlet。
9、exception 用于捕获JSP抛出的异常。它只有在JSP页面属性isErrorPage=true时才可用。
四、改造类别列表实现
4.1 Servlet
@WebServlet("/CategoryListServlet2") //使用注解配置访问路径
public class CategoryListServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
CategoryDao categoryDao = new CategoryDaoImpl();
List<Category> categories = categoryDao.queryAll();
//要想办法送到JSP里
//先存到作用域里(page->request->session->application)
request.setAttribute("clist", categories);
//转发
request.getRequestDispatcher("account_book.jsp").forward(request, response);
}
}
4.2 JSP页面遍历类别列表
<%@ page import="com.aaa.javaweb.entity.Category" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>帐单列表</title>
</head>
<body>
<table>
<tr>
<th>编号</th>
<th>名称</th>
<th>图片</th>
<th>类型</th>
</tr>
<%
List<Category> list = (List<Category>) request.getAttribute("clist");
for (Category c : list) {
%>
<tr>
<td><%=c.getCid()%></td>
<td><%=c.getName()%></td>
<td>
<img width="40" src="res/images/cat/<%=c.getPic()%>_1.png">
</td>
<td><%=c.getType() == 0 ? "支出" : "收入" %></td>
</tr>
<%
}
%>
</table>
</body>
</html>
五、EL表达式
EL(expression language):表达式语言,在JSP里面取值(一般是作用域里的值),现在服务器都支持EL,所以使用它不需要任何配置和导入。
1.1 核心语法
${ 表达式 }
1.2 Servlet代码
/**
* Created by Intellij IDEA
*
* @author 王俊凯
* @Date: 2022/9/1 19:34
* @Version 1.0
*/
package com.wjk.service;
import com.wjk.entity.AccountBook;
import com.wjk.entity.Category;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Random;
@WebServlet("/ElServlet")
public class ElServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
//简单的字符串
req.setAttribute("nstr","普通字符串");
req.getSession().setAttribute("nstr","session里的字符串");
//特殊的字符串
req.setAttribute("fstr","<font color='red'>AAA欢迎你</font>");
//自定义对象
AccountBook ab = new AccountBook();
ab.setDetails("喝酒钱");
ab.setMoney(new BigDecimal("900"));
Category c = new Category();
c.setName("娱乐");
ab.setCategory(c);
req.setAttribute("accountBook",ab);
//自定义对象List
ArrayList<AccountBook> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
AccountBook book = new AccountBook();
book.setDetails("详情"+i);
book.setMoney(BigDecimal.valueOf(new Random().nextLong()));
book.setCategory(c);
list.add(book);
}
req.setAttribute("booklist",list);
//计算
req.setAttribute("num",100);
//判断是否为空
req.setAttribute("a2","");
req.setAttribute("a3",new ArrayList<>());
req.setAttribute("a4",new Object());
req.getRequestDispatcher("el.jsp").forward(req,resp);
}
}
1.3 el.jsp
<%--
Created by IntelliJ IDEA.
User: 王俊凯
Date: 2022/9/1
Time: 19:36
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<fieldset>
<legend>EL取值</legend>
${nstr}
</fieldset>
<fieldset>
<legend>特殊的字符串</legend>
${fstr}
</fieldset>
<fieldset>
<legend>自定义对象:通过.取属性值</legend>
${accountBook.details},${accountBook.money},${accountBook.category.name}
</fieldset>
<fieldset>
<legend>自定义List</legend>
${booklist[0].details},${booklist[0].money},${booklist[0].category.name}<br>
${booklist[1].details},${booklist[1].money},${booklist[1].category.name}<br>
</fieldset>
<fieldset>
<legend>计算</legend>
num:${num*100}
</fieldset>
<fieldset>
<legend>判断是否为空</legend>
a1:${empty a1}<br>
a2:${empty a2}<br>
a3:${empty a3}<br>
a4:${empty a4}<br>
</fieldset>
</body>
</html>
六、JSTL
这里需要下载 jar 包 jstl-1.2.jar
(JSTL)(Java server pages standarded tag library,即JSP标准标签库)JSP标准标签库是一个JSP标签集合,它封装了JSP应用的通用核心功能。
JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。 除了这些,它还提供了一个框架来使用集成JSTL的自定义标签。
根据JSTL标签所提供的功能,可以将其分为5个类别。
- 核心标签
- 格式化标签
- SQL标签
- XML标签
- JSTL标签
1.1 JstlServlet代码
/**
* Created by Intellij IDEA
*
* @author 王俊凯
* @Date: 2022/9/1 20:15
* @Version 1.0
*/
package com.wjk.service;
import com.wjk.entity.AccountBook;
import com.wjk.entity.Category;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Random;
@WebServlet("/JstlServlet")
public class JstlServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
//特殊字符串
req.setAttribute("ystr","<font color='red'>八嘎八嘎</font>");
//判断
req.setAttribute("num",200);
//多重判断
req.setAttribute("haha",15);
//循环遍历
ArrayList<AccountBook> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
AccountBook book = new AccountBook();
Category category = new Category();
book.setDetails("详情"+i);
book.setMoney(BigDecimal.valueOf(new Random().nextLong()));
book.setCategory(category);
list.add(book);
}
req.setAttribute("booklist",list);
req.getRequestDispatcher("jstl.jsp").forward(req,resp);
}
}
1.2 jstl 的 jsp
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: 王俊凯
Date: 2022/9/1
Time: 20:13
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<fieldset>
<legend>特殊字符</legend>
<c:out value="${ystr}"></c:out>
</fieldset>
<fieldset>
<legend>判断</legend>
<c:if test="${num>100}">
num大于1
</c:if>
</fieldset>
<fieldset>
<legend>多重判断</legend>
<c:choose>
<c:when test="${haha<3}">
haha小于3
</c:when>
<c:when test="${haha>10}">
haha大于10
</c:when>
</c:choose>
</fieldset>
<fieldset>
<legend>循环遍历</legend>
<c:forEach items="${booklist}" var="a">
${a.details},${a.money},${a.category.name}<br>
</c:forEach>
</fieldset>
</body>
</html>
七、会话跟踪
为什么要会话跟踪
HTTP是一种短连接、无状态的协议。
会话:客户端打开到关闭和服务器一系列(多次)请求和响应过程。
会话跟踪:记录下客户端的状态。
怎么实现会话跟踪
Cookie 由服务器生产保存到客户端的一段文本信息
1.服务器生成
Cookie c = new Cookie(字符串名字,字符串值);
2.保存到客户端
resp.addCookie(c);
3.一般服务器在客户端保存了Cookie,那么客户端在请求必须Cookie,服务器可以取得这些所有Cookie
Cookie[] cookies = req.getCookies();
示例:
1. 设置Cookie
@WebServlet("/SetCookie")
public class SetCookie extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.服务器生成
//第一种:临时Cookie,浏览器一关就失效了
Cookie c = new Cookie("c1","hellocookie");
//第二章:长久有效,设置一个有效时间,单位是秒
c.setMaxAge(60*60*24*7);
//2.发送到客户端
resp.addCookie(c);
resp.getWriter().println("设置Cookie成功");
}
}
2. 读取Cookie
@WebServlet("/GetCookie")
public class GetCookie extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
//3.读取客户端所有的Cookie
Cookie[] cookies = req.getCookies();
for (Cookie cookie : cookies) {
out.println(cookie.getName()+":"+cookie.getValue());
}
}
}
经典案例:免登录
1.登陆页面
<%
//获取Cookie
Cookie[] cookies = request.getCookies();
for (Cookie c : cookies){
String name = c.getName();
//已经记录下了登录用户的Cookie
if(name.equals("loginUser") && !c.getValue().trim().equals("")){
response.sendRedirect("CategoryListServlet2");
}
}
%>
<!--method用来设置请求方式,默认是get,如果要使用post请求,必须设置-->
<form action="AutoLoginServlet" method="post">
邮箱:<input name="email"><br>
密码:<input type="password" name="password"><br>
<input type="checkbox" name="rememberMe"> 两周内自动登录
<hr>
<input type="submit" value="登录"> <input type="reset" value="取消"><br>
没有账号?请<a href="reg.html">注册</a>
</form>
2. 登陆处理Servlet
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取请求参数
//请求页面表单里input的name值
//获取请求参数中文乱码
//解决:设置请求字符集为请求页面的字符集且要支持中文,这行代码必须在获取任意参数前
req.setCharacterEncoding("UTF-8");
String email = req.getParameter("email");
String password = req.getParameter("password");
String rememberMe = req.getParameter("rememberMe");
//System.out.println("rememberMe = " + rememberMe);
//2.业务处理
UserDao userDao = new UserDaoImpl();
User user = userDao.queryByEmailAndPassword(email, password);
//3.转向
//根据业务处理结果给用户响应(一般用转向)
if(user != null){
//登录成功,跳转到主页面
//用户选择了自动登录
if(rememberMe != null){
Cookie c = new Cookie("loginUser", user.getEmail());
c.setMaxAge(60*60*24*14);
resp.addCookie(c);
}
resp.sendRedirect("CategoryListServlet2");
} else {
//登录失败,从新登录
resp.sendRedirect("login.jsp");
}
}
3. 退出Servlt
@WebServlet("/LogoutServlet")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//删除记录登录信息的Cookie
//获取Cookie
Cookie[] cookies = req.getCookies();
for (Cookie c : cookies) {
String name = c.getName();
if(name.equals("loginUser")){
//让Cookie失效
c.setMaxAge(0);
//再次写到客户端
resp.addCookie(c);
}
}
resp.sendRedirect("login.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
Session
会话:从会话创建到销毁过程中多次请求响应过程就是一次会话,在一个会话里存的对象只要Session不失效都可以取出来。
销毁:1. 浏览器关闭Session销毁 2.到了最大有效时间(默认是30分钟) 3.也可以通过代码让session失效。
session一般记录的是一些用户信息。
很多功能需要判断登录用户:主页、添加帐单、帐单列表。
session数据保存在服务器里,比较安全。
经典案例:控制用户访问
1. 登录Sevlet
@WebServlet("/AutoLoginServlet")
public class AutoLoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取请求参数
//请求页面表单里input的name值
//获取请求参数中文乱码
//解决:设置请求字符集为请求页面的字符集且要支持中文,这行代码必须在获取任意参数前
req.setCharacterEncoding("UTF-8");
String email = req.getParameter("email");
String password = req.getParameter("password");
String rememberMe = req.getParameter("rememberMe");
//System.out.println("rememberMe = " + rememberMe);
//2.业务处理
UserDao userDao = new UserDaoImpl();
User user = userDao.queryByEmailAndPassword(email, password);
//3.转向
//根据业务处理结果给用户响应(一般用转向)
if(user != null){
//登录成功,跳转到主页面
//用户选择了自动登录
if(rememberMe != null){
Cookie c = new Cookie("loginUser", user.getEmail());
c.setMaxAge(60*60*24*14);
resp.addCookie(c);
}
//后面能够从session取到
HttpSession session = req.getSession();
//把登录用户对象存到sesion里
session.setAttribute("loginUser", user);
resp.sendRedirect("CategoryListServlet2");
} else {
//登录失败,从新登录
resp.sendRedirect("login.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
2. 登录用户判断,没有登录返回登录页面,登陆后才执行业务代码
@WebServlet("/CategoryListServlet2")
public class CategoryListServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取session
HttpSession session = request.getSession();
//获取登录用户对象
User loginUser = (User) session.getAttribute("loginUser");
//如果返回是null以为着session中没有
if(loginUser == null){
request.setAttribute("errorInfo", "请登录后再访问");
request.getRequestDispatcher("login.jsp").forward(request, response);
} else {
//已经登录
CategoryDao categoryDao = new CategoryDaoImpl();
List<Category> categories = categoryDao.queryAll();
//要想办法送到JSP里
//先存到作用域里(page->request->session->application)
request.setAttribute("clist", categories);
//转发
request.getRequestDispatcher("account_book_jstl.jsp").forward(request, response);
}
}
}
总结:
为什么需要会话跟踪,http协议是无状态的
实现技术:
1. Cookie
*保存在客户端
*里面只能在文本
*大小数量限制
*域名的限制
2. Session
*保存在服务器端
*任意对象
*大小无限制
*无域名限制