Bootstrap

JavaWeb服务器开发(精品这一套就足够)

目录

第 1 章Tomcat服务器

1.1 服务器介绍

物理服务器: 从硬件层面认识服务器:
服务器是计算机的一种,它比普通个人计算机运行更快、负云服务器: 很多公司都会去阿里云、腾讯云、百度云等公司租赁
载更高、价格更贵。
由于服务器不间断的一直运行,噪音大、需要散热,所以通常情况都不会自己购买服务器
服务器程序:跑在物理服务器上的应用程序(用编程语言边写出来的,比如java,php,js等等)

1.2 服务器程序的分类(按照功能)

web服务器,又称为网站服务器,就是给用户提供网站服务的,开发者可以把自己搭建的网站发布到web服务器上,让全世界的用户访问到。
常见的web服务器有:tomcat、nginx、iis、WebLogic

数据库服务器,就是存储数据的服务器软件

1.3 tomcat服务器

Tomcat 服务器,是Apache公司的产品,是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,中小型公司使用比较普遍,是开发和调试JSP 程序的首选。

Tomcat服务器使用教程:
https://blog.csdn.net/weixin_40396459/article/details/81706543

1.4 tomcat服务器下载、安装

下载地址:http://tomcat.apache.org/
我已经下载好,大家直接使用我下载好的即可

在这里插入图片描述

安装步骤:
1.解压
在这里插入图片描述

2.将解压之后的文件夹中的apache-tomcat-8.0.30目录拷贝到其他目录:例如D盘
在这里插入图片描述

到此,tomcat服务器以及安装好
如何启动?
进入到tomcat服务器的bin目录下,找到startup.bat并双击,启动tomcat服务器(shutdown表示关闭)
在这里插入图片描述
在这里插入图片描述

弹出上面的黑框,表示启动成功,通过在浏览器端访问进行测试
在浏览器地址栏输入:localhost:8080
localhost(本地电脑域名)—> 127.0.0.1(本地电脑的ip地址)
baidu.com(域名)----->百度的服务器地址
在这里插入图片描述

如果双击startup.bat文件时,一闪而过,没有弹出黑窗口
只需要把tomcat服务器安装路径添加到系统的环境变量即可:
在这里插入图片描述
在这里插入图片描述

将上面的变量添加到Path变量中,这样,当我们执行startup.bat命令(批处理文件)时,会自动上面的指定路径中查找
在这里插入图片描述
在这里插入图片描述

如果是win7系统,点击Path—编辑
在这里插入图片描述

如果文件没有显示后面的扩展名,执行下面的操作:
在这里插入图片描述
在这里插入图片描述

1.5 tomcat服务器目录结构

在这里插入图片描述

1.6 tomcat服务器配置

tomcat服务器默认的端口是8080,如果不喜欢,可以在配置文件中重新配置一下:
tomcat服务器的配置文件在conf目录下的server.xml
在这里插入图片描述

如果修改了端口号,需要重新启动tomcat服务器

浏览器访问时,需要输入:
在这里插入图片描述

端口,门口
tomcat默认占8080端口
mysql:3306端口
redis:6379端口

1.7 eclipse创建JavaWeb工程

什么是JavaWeb工程
web,网站(HTML+CSS+Javascript)
Java,Java语言
JavaWeb,就是使用Java和web网站进行交互,Java负责处理数据,web页面负责显示数据
执行如下步骤:
File----New—Other—Web—Dynamic Web Project—Next
在这里插入图片描述
在这里插入图片描述

1.8 eclipse中添加tomcat服务器

使用tomcat服务器运行Java Web工程,每次运行JavaWeb工程时,会自动启动tomcat服务器,不需要手动开启了
步骤:右击0316工程-----Run As—Run on Server
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在javaweb工程的WebContent目录下,创建一个index.html文件进行测试

1.9 eclipse清除tomcat缓存

1.停止tomcat服务器
在这里插入图片描述

2.右击tomcat8.0服务器-----clean
在这里插入图片描述

3.重写启动tomcat服务器

在这里插入图片描述

4.如果上面的步骤都没有清理成功,执行下面的步骤
a.关闭tomcat服务器
在这里插入图片描述

b.删除0316
c.右击tomcat v8.0,执行clean
d.点击eclipse菜单中的Project----
在这里插入图片描述
在这里插入图片描述

最后,再把Build Automatically勾选上
在这里插入图片描述
在这里插入图片描述

1.10 eclipse将web工程部署到tomcat服务器

默认代码保存eclipse的默认的工作台中
现在我们将代码部署到tomcat服务器的目录下
1.关闭tomcat服务器
在这里插入图片描述

2.删除0316工程
3.右击tomcatv8.0----clean
4.双击tomcatv8.0
在这里插入图片描述

第 2 章Servlet

2.1 Servlet介绍

Servlet是运行在服务器端的Java程序,也是sun公司提供的一个接口,用来接收客户端的HTTP请求,以及向客户端做出HTTP响应

Servlet的功能、职责包括:

  1. 接收客户端的HTTP请求
  2. 向客户端做出HTTP响应

2.2 Servlet快速入门

1.创建JavaEE项目(JavaWeb工程)
在这里插入图片描述

2.新建一个Java类,实现Servlet接口
在这里插入图片描述

3.实现Servlet接口中的抽象方法
总共有5个抽象方法
在这里插入图片描述

4.配置Servlet
在web.xml中配置(servlet 3.0没有web.xml,需要手动创建web.xml)
配置url路径和Servlet类之间的映射,
例如:请求/demo1 时,让哪个Servlet处理您的请求
在这里插入图片描述

  1. 重启tomcat服务器
    在地址栏访问:/demo1
    在这里插入图片描述
    在这里插入图片描述

2.3 Servlet执行流程

在这里插入图片描述

servlet什么时候被创建?
默认情况下,第一次访问时servlet被创建
也可以在web.xml中配置servlet的创建时机
的值为负数时,第一次访问时被创建
的值为正数时,在服务器启动时被创建
在这里插入图片描述

2.4 Servlet 3.0注解式配置

新建JavaWeb工程,指定配置文件版本为3.0
在这里插入图片描述
在这里插入图片描述

重新启动服务器,访问/demo1

在这里插入图片描述
在这里插入图片描述

2.5 ServletRequest介绍

当用户访问/demo1时,tomcat服务器将用户的请求映射到ServletDemo类上
并调用service方法,该方法就是给用户提供服务的方法
tomcat会自动传递:ServletRequest、ServletResponse对象到service方法中
其中,ServletRequest用来接收用户的请求的
其中,ServletResponse用来向用户做出相应的

快速体验一把
在这里插入图片描述

启动服务器,并在地址栏传递一些数据,检测服务器能否接收
在这里插入图片描述

2.6 课堂练习

1.创建用户注册界面
在这里插入图片描述
在这里插入图片描述

2.当用户点击提交时,将用户信息保存到文件中

2.7 课堂练习

1.创建用户登录界面
在这里插入图片描述

2.点击提交按钮时,将表单提交给/login
3.将/login 映射到LoginServlet,并在LoginServlet中接收表单内容进行用户名的验证
4.如果用户名、密码全部正确,提示登录成功,否则提示登录失败

第 3 章HTTP协议

3.1 HTTP介绍

客户端:用户操作的终端,例如:浏览器
服务器端:提供网页服务的服务器,例如:tomcat
在这里插入图片描述

客户端要想和服务器进行正常交互,需要采用一定的规范,就称为”协议”,该协议就是HTTP协议。

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。
HTTP协议版本
HTTP/1.0,发送请求,创建一次连接,获得一个web资源,断开连接
HTTP/1.1,发送请求,创建一次连接,获得多个web资源,断开连接
HTTP协议的组成:
HTTP请求协议
HTTP响应协议

3.2 请求协议

3.2.1 HTTP请求介绍

用户使用浏览器,连接上服务器,访问服务器的某个资源(网页、图片、视频等),
这个过程称为HTTP请求。

一个完整的HTTP请求包括3部分内容:一个请求行、多个消息头、实体内容
请求行,包括浏览器请求方式、请求的资源名称、使用的HTTP协议版本号
多个消息头,用来描述客户端浏览器的信息的(注意:不同的浏览器消息头不一样)
实体内容,浏览器请求服务器资源时,携带的内容
User-Agent
Host
请求方式:GET、POST
在这里插入图片描述

3.2.2 代码演示

1.在tomcat服务器上,部署一个网页:index.html
在这里插入图片描述
在这里插入图片描述

运行服务器:
右击0318—Run As—Run On Server
在这里插入图片描述

2.使用chrome谷歌,请求tomcat服务器上的index.html
在浏览器上右击鼠标----检查(或者F12 或 fn+f12)
在这里插入图片描述
在这里插入图片描述

3.请求服务器时,携带的实体内容
如果是GET方式请求,携带的内容,通过地址栏传递,格式为:
http://请求的资源?键名=值&键名=值…
例如:
http://localhost:8080/0318/index.html?money=200w&name=zhangsan
在这里插入图片描述

3.2.3 HTTP请求细节

HTTP请求方式除了GET方式之外,还有:POST、PUT、DELETE、TRACE、HEAD、OPTIONS
GET方式,获取资源
POST方式,提交,向服务器提交内容
PUT方式,修改服务器的某个资源
DELETE方式,删除服务器的某个资源

GET方式、POST方式的区别不仅在实际开发中常用,面试时也是常遇到
1.传递数据的位置,GET方式通过地址栏传递,POST方式通过表单方式提交
所以,POST相对来说,比GET方式安全
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2.传递的数据大小不同
因为GET方式,通过地址栏传递,IE浏览器地址栏最多能够接2K左右的数据,其他浏览器没有限制
如果数据量较大,GET方式不适合

3.默认情况下,http都是get请求 ,只有将method修改为post时,才会是post请求

3.3 响应协议

3.3.1 HTTP响应介绍

浏览器连接上服务器,请求服务器的某个资源(网页、图片、视频等),服务器将该资源响应给浏览器,就是HTTP响应
一个HTTP响应包括3部分:状态行、多个消息头、实体内容
状态行,用来告诉浏览器请求状态的,重点记住状态码
多个消息头,用来描述服务器本身的一些信息
实体内容,服务器给客户端浏览器响应的内容

代码演示:
在这里插入图片描述
在这里插入图片描述

3.3.2 状态码

状态码,用来描述服务器处理的结果的,常见的状态码有:
200,处理好请求,并把结果响应给浏览器
404,Not Found,未找到,告诉浏览器你请求的资源,我没有找到
302,重定向,你请求资源a,暂时处理不了,将你重新定向到资源b(跳转)
304,资源未修改,告诉浏览器您请求的资源,我没有修改过,请使用本地的缓存
403,Forbidden,没有权限访问
500,Internel error,服务器内部错误
3.3.3 消息头
消息头用来描述服务器的基本信息,服务器通过消息头告诉客户端浏览器如何接收稍后给你回送的数据

Location: http://www.baidu.com
Server:Apache/2.4.7 
Content-Encoding: gzip 
Content-Length: 80 
Content-Language: zh-cn 
Content-Type: text/html; charset=UTF-8 
Last-Modified: Tue, 11 Jul 2016 18:23:51 GMT 
Refresh: 5;url=http://www.baidu.com
Content-Disposition: attachment; filename=aaa.zip
Transfer-Encoding: chunked  
Set-Cookie:SS=Q0=5Lb_nQ; path=/search
Connection: close/Keep-Alive   

重点掌握的消息头有:
Location,实现重定向,服务器告诉浏览器重新定向(跳转)到其他位置
Content-Length,响应的内容的长度
Content-Type,响应的内容的类型,内容类型包括2部分:大类型/小类型
text/html,text表示大类型,文本,html小类型,表示格式
image/jpg,image表示大类型,图片,jpg小类型,表示格式

Last-Modified,最后的修改时间
Content-Disposition,通知浏览器以下载的方式接收服务器响应的内容
取值:attachment; filename=aaa.zip filename用来指定下载的内容保存到哪里
Set-Cookie,告诉浏览器在浏览器身上设置一个cookie(记号)

3.4 关于http协议的总结

1.http协议中规定浏览器端是请求发送的主动方
2.http协议中规定一次请求必然对应着一次响应
3.http协议是无状态的
4.请求的发起方是浏览器接收方是服务器,对应的响应的发送方是服务器,接收方式浏览器
5.请求中有 请求头,请求体,请求行
6.响应有 状态吗,状态文本,响应头,响应实体
7.http请求中是通过 url地址和请求方式去确定一条资源的
8.url的组成部分: 协议,域名,端口,路径,查询参数(查询参数的解析)

第 4 章HttpServlet

4.1 HttpServlet介绍

HttpServlet类实现了Servlet接口,并对Servlet进行了封装
HttpServlet子类实现了Servlet的5个抽象方法,如果我们使用HttpServlet的时候,就不用再实现5个抽象方法了

HttpServlet还提供2个通用的方法:doGet、doPost
doGet方法,用来接收用户GET方式的请求的,也就是说,当用户访问Servlet类时,如果使用GET方式,则进入到doGet方法

doPost方法,用来接收用户POST方式请求的,也就是说,当用户访问Servlet类时,如果使用POST方式,则进入到doPost方法
在这里插入图片描述

代码演示:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

4.2 HttpServletRequest

在doGet和doPost方法中,自动传递了HttpServletRequest和HttpServletResponse
其中,HttpServletRequest类获取HTTP请求协议中的消息的
其中,HttpServletResponse类做出HTTP响应的

HTTP请求协议包括哪些部分?
请求行:
消息头
实体内容

4.2.1 获取请求行

获得客户端的请求方式:String getMethod()
获得请求的资源:
String getRequestURI() 获取请求行中资源名称部分
StringBuffer getRequestURL() 获取请求的完整url地址
String getContextPath() — web应用的名称
String getRemoteAddr() — 获得访问的客户端IP地址
在这里插入图片描述

4.2.2 获取消息头:

String getHeader(String name)

4.2.3 获取实体内容

  1. String getParameter(String name)
  2. Map<String,String[]> getParameterMap(),将接收的结果以键值对的形式保存到map集合中Map:{属性名:属性值}

在这里插入图片描述
在这里插入图片描述

4.2.4 课堂练习:

  1. 创建注册表单,用户名、密码、年龄、生日4个输入框
    使用getParameterMap()获取表单项的值
  2. 创建ServletDemo2.java
  3. 创建映射,/demo2 映射到ServletDemo2类上
    4. 在doPost方法中接收表单的数据项

在这里插入图片描述

定义 /register 接收用户的请求,将用户的输入保存到文件中
在这里插入图片描述

4.2.5 请求转发

当用户请求 servlet1时,将其转发给servlet2…
请求转发特点:
1.同一次请求
2.浏览器的地址栏没有发生变化
3.请求转发只能转发到服务器内部资源
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.2.6 request域对象

request还可以作为域对象存在(存储数据的一块区域)
域对象,就是具有作用范围的对象
Request,也是一个域对象,其作用范围是一次请求中:
 setAttribute(String name, Object o)
 getAttribute(String name)
 removeAttribute(String name)
注意:request域的作用范围:一次请求中

特点:在request域对象中存储的数据,可以在请求转发的多个servlet之间共享
在这里插入图片描述

举例演示:
在 /demo2 这个servlet中定义一个数据项,然后将该请求转发给 /demo3,检查在/demo3中能否获取在/demo2定义的数据项
在这里插入图片描述
在这里插入图片描述

4.2.7 获取ServletContext对象

服务器启动的时候,为每个应用/项目创建一个单独的ServletContext对象,我们可以使用这个对象存取数据,用该对象存储的数据可以在整个web应用中获得。

获取servletContext对象:
1.request.getServletContext()
2.this.getServletContext()

代码演示:
在这里插入图片描述
在这里插入图片描述

先访问demo4: http://localhost:8080/homework/demo4
再访问demo2: http://localhost:8080/homework/demo2
在这里插入图片描述

4.2.8 ServletContext作用

  1. 获取文件的MIME类型
    网络传输时的文件类型,例如:meinv.jpg在网络中传输的类型就是:image/jpg
    在这里插入图片描述

  2. ServletContext是一个域对象,其作用范围:整个web应用都可共享
    域对象的通用的方法:
    setAtrribute(String name,Object obj);
    getAttribute(String name);
    removeAttribute(String name);

  3. 获得web应用中资源的绝对路径:
    在这里插入图片描述
    在这里插入图片描述

第 5 章HttpServletResponse

HttpServletResponse类做出HTTP响应的,服务器向浏览器响应的信息

HTTP响应协议包括哪些部分?
状态行
消息头
实体内容

5.1 响应状态码

setStatus(int sc)
该方法用于设置HTTP响应消息的状态码,并生成响应状态行
需要注意的是,正常情况下,web服务器会默认产生一个状态码为200的状态行

5.2 设置消息头

setHeader(String name, String value),设置任何响应头信息,其中name指定响应头字段的名称,value用于指定响应头字段的值。

需求:
当用户访问 /demo1 路径时,让其跳转到(重定向)http://www.baidu.com
在这里插入图片描述

重定向可以简写为:
response.sendRedirect(“目标地址”);
在这里插入图片描述

5.3 响应实体内容

响应字符流(文本内容)
response.getWriter().write(“响应的文本内容”)
获得字符输出流,通过字符流的write(String s)方法可以将字符串设置到response缓冲区中,随后Tomcat会将response缓冲区中的内容组装成Http响应返回给浏览器端。

响应字节流(图片、视频等二进制字节流)
response.getOutputStream().write(“字节数据”)
在这里插入图片描述

5.4 解决响应中文乱码

需求:服务器给浏览器响应一些中文
在这里插入图片描述
在这里插入图片描述

中文乱码的原因,在于编码不一致
tomcat服务器端默认编码是ISO-8859编码
浏览器所在的windows系统编码是GB2312编码

解决之道:
统一编码为UTF-8即可
在这里插入图片描述

5.5 文件下载

通过Content-Disposition消息头,告诉浏览器请以下载的方式接收给你响应的内容
在这里插入图片描述

第 6 章HttpServletResponse(二)

6.1 重定向VS请求转发

有哪些区别?
在这里插入图片描述
在这里插入图片描述

1.请求转发是一次请求,重定向是2次请求
2.请求转发时,浏览器地址栏不发生变化,重定向浏览器地址栏会发生变化
3.请求转发可以使用request域对象中的数据,而重定向无法使用

6.2 文件下载

思路:
当用户点击连接时,服务器先获取点击的文件的资源,然后提示用户以下载的方式接收服务器给你响应的内容
1.创建文件下载页面
在这里插入图片描述

2.在DownloadServlet中接收文件名,并下载

@WebServlet("/download")
public class DownloadServlet extends HttpServlet{

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		//1. 接收浏览器传递过来的参数
		String filename = req.getParameter("filename");  //a.mp3
		
		//2. 获取文件的绝对路径
		//D:\java_env\apache-tomcat-8.0.30\webapps\review\download\a.mp3
		ServletContext context = req.getServletContext();
		
		String filepath = context.getRealPath("/download/"+filename);
		System.out.println(filepath);
		
		//3. 响应给浏览器时,告诉浏览器以下载的方式进行接收
		String mime = context.getMimeType(filename);		// image/png
		resp.setContentType(mime);
		resp.setHeader("Content-Disposition", "attchment;filename="+filename);
		
		//4. 创建输入、输出流
		FileInputStream input = new FileInputStream(filepath);
		ServletOutputStream sos = resp.getOutputStream();
		
		//IO流获取文件的字节流,然后再响应给浏览器
		byte[] arr = new byte[1024];
		int res = 0;
		while((res = input.read(arr)) > 0){
			
			//将读取的内容输出到输出流中
			sos.write(arr, 0, res);
		}
		
		input.close();
		sos.close();		
	}
}

文件下载时中文乱码问题
解决之道:
使用DownloadUtils工具,对中文文件名进行utf-8编码
在这里插入图片描述
在这里插入图片描述

6.3 验证码

验证码:
在这里插入图片描述

思路:
servlet给客户端响应一张图片,在图片中绘制一些随机的文字

作用:
用来区别访问者,是人类还是计算机脚本的
因为人类可以很轻松的获取图片上面的文字,而计算机无法读取图片上面写的内容

package com.zhentao.utils;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/captcha")
public class Captcha extends HttpServlet{

	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		//1. 禁止浏览器缓存(告诉浏览器不要缓存)
		resp.setHeader("cache-control", "no-cache");
		
		//2. 生成一张图片(真空的图片)
		int width = 80;
		int height = 30;
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		
		//3. 创建画笔
		Graphics pen = image.getGraphics();
		
		//灰色的画笔
		pen.setColor(Color.GRAY);	
		
		//使用灰色画笔填充真空的图片
		pen.fillRect(0, 0, width, height);
				
		
		//4. 将随机字符写入到图片中
		String code = getCode();  
		pen.setColor(Color.YELLOW);
		pen.setFont(new Font("黑体", Font.BOLD, 24));
		pen.drawString(code, 15, 25);
		
		//5. 将图片响应给浏览器
		//参数1:内存中的图片资源
		//参数2:图片的格式:PNG  JPG  JPEG   GIF
		//参数3:字节输出流
		ImageIO.write(image, "PNG", resp.getOutputStream());
	}
	
	//获取随机字符
	public String getCode(){
		String base = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
		
		//随机获取4个
		Random r = new Random();
		
		int len = base.length();  // 58
		
		StringBuffer sb = new StringBuffer();
		
		for(int i=0;i<4;i++){
			//先随机产生下标
			int index = r.nextInt(len); // 0 - 58之间的随机数
			
			//根据下标获取字符
			char c = base.charAt(index);
			
			//将随机产生的字符,追加到StringBuffer
			sb.append(c);
		}
		return sb.toString();
	}
	
}

第 7 章会话机制

7.1 会话介绍

在日常生活中,从拨通电话到挂断电话之间的一连串你问我答的过程,就是一个会话/通话。Web应用中的会话过程类似于打电话过程,指的是浏览器向服务器发出请求,服务器 给浏览器回应,这个过程我们就称之为一次会话。
在这里插入图片描述

由于HTTP协议具有无状态性,在客户端与服务器端交互的过程中,也会产生一些数据,然而由于HTTP协议的无状态性,在web会话结束后,数据都会被释放掉。

我们学习会话机制,其实就是学习如何保存会话过程中产生的数据
根据数据的保存位置,会话技术分为:cookie技术、session技术

7.2 Cookie技术

7.2.1 cookie介绍

Cookie技术,又称为客户端技术,将数据保存到客户端浏览器身上,每次访问服务器时,随身携带
在这里插入图片描述

7.2.2 Cookie基本操作

1.服务器告诉浏览器:请在你自己身上设置一个cookie,以后访问服务器时,随身携带
Cookie cookie = new Cookie(key,value);
response.addCookie(cookie);
在这里插入图片描述

注意:cookie中不能直接存储中文,可以先编码之后再存储

访问:http://localhost:8080/0324/demo1
在这里插入图片描述

2.第二次请求服务器时,会随身携带cookie
定义ServletDemo2,然后访问一下
http://localhost:8080/0324/demo2
在这里插入图片描述

如何获取请求头中的cookie呢?

在这里插入图片描述
在这里插入图片描述

7.2.3 Cookie细节

1.cookie的有效期
cookie默认是会话级别的cookie,一旦浏览器关闭,则cookie失效
可以通过cookie.setMaxAge();这是有效期,单位为秒

例如:将cookie有效期设置为 1个小时
cookie.setMaxAge(60*60);
在这里插入图片描述

先访问/demo1
http://localhost:8080/0324/demo1
在这里插入图片描述

再访问/demo2

2.cookie的有效路径
默认情况下,cookie只在当前项目有效,在其他项目中无法获取
如果希望多个项目能够共享cookie,可以将有效路径设置为:/
/ 表示服务器根目录,服务器下面的所有项目都可以访问到
在这里插入图片描述
在这里插入图片描述

再访问/0321/demo1:
http://localhost:8080/0321/demo1
在这里插入图片描述

7.2.4 练习

定义 /index 页面,如果用户是第一次访问,则提示:”欢迎光临”,否则提示”您上次访问的时间”

package com.zhentao.huihua;

@WebServlet("/index")
public class ServletDemo3 extends HttpServlet{

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		resp.setContentType("text/html;charset=utf-8");
		
		//1. 获取当前的时间
		Date date = new Date();	//获取当前的日期对象(西方格式)
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String currentTime = sdf.format(date);
		
		//2. 先将当前的时间保存到cookie中
		Cookie cookie = new Cookie("lastTime", currentTime);
		cookie.setMaxAge(3600);
		resp.addCookie(cookie);
		
		//3. 获取所有cookie
		Cookie[] cookies = req.getCookies();
		String flag = null;
		if(cookies != null){
			for(Cookie c:cookies){
				if(c.getName().equals("lastTime")){
					flag = c.getValue();
				}
			}
		}
		
		//如果for循环结束了,flag = null说明第一次访问,没有携带lastTime
		if(flag == null){
			resp.getWriter().write("您是第一次访问");
		}else{
			resp.getWriter().write("您上次访问时间为:"+flag);
		}
		
	}
}

7.2.1 session技术

7.3.1 session介绍

session技术,又称为服务器端技术,将会话过程产生的数据保存到服务器内存中
工作流程:
在这里插入图片描述

浏览器第一次访问服务器时,服务器会在服务器端创建session文件
然后,将session文件名称(想象成钥匙)以cookie的形式响应给浏览器
当浏览器第二次访问服务器时,只需要随身携带钥匙(session文件名),再通过该钥匙找到内容

7.3.2 session基本操作

  1. 服务器创建session
    在这里插入图片描述

http://localhost:8080/0324/session1
在这里插入图片描述

第二次请求服务器时,会随身携带cookie(SESSID钥匙)
在这里插入图片描述

  1. 获取session中的内容
    在这里插入图片描述

7.3.3 session有效期

session有效期的设置有3种方式:

  1. 在web.xml中设置

  2. 在tomcat服务器的配置文件中设置
    在这里插入图片描述

session-config,默认值为:30分钟
<session-config> 
<session-timeout>30</session-timeout> 
</session-config>
  1. 在Java程序中设置
    在这里插入图片描述

7.3 面试题

1.浏览器关闭后,能否获取session中的数据?为什么?
不能
服务器通过set-cookie的形式将session文件名告诉浏览器,该cookie是会话级别,一旦浏览器关闭则失效,无法找到对应的session文件
2.cookie和session的区别?
保存位置不同,cookie保存在浏览器,session保存在服务器
安全性不同,session比cookie的安全性高
有效期不同,cookie有效期默认0,通过setMaxAge设置;session有效期默认是30分钟,tomcat服务器、Java程序中设置

3.如果浏览器禁用了cookie,能否获取到session数据?

通过URL重写、表单隐藏域提交cookie
在这里插入图片描述

7.4 练习

1.将验证码中的随机字符,保存到session中
在这里插入图片描述

2.在登录表单中显示验证码图片
在这里插入图片描述

3.点击登录时,先验证用户输入的验证码和生成的验证码是否一致,如果一致才允许登录,如果不一致,则重新登录
在这里插入图片描述

4.登录成功之后跳转到/index 页面,并在该页面显示登录成功的用户

@WebServlet("/login")
public class LoginServlet extends HttpServlet{

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		try{
			req.setCharacterEncoding("utf-8");
			//1. 接收表单提交过来的内容
			String username = req.getParameter("user");
			String password = req.getParameter("pass");
			String inputCaptcha = req.getParameter("captcha");
			
			//2. 验证用户输入的验证码和图片里面的验证是否一致
			HttpSession session = req.getSession();
			String sessCaptcha = (String) session.getAttribute("captcha");
			
			//比较时不区分大小写
			if(inputCaptcha.equalsIgnoreCase(sessCaptcha)){
				
				System.out.println("验证码正确");
				
				//用户名、密码校验
				String sql = "select * from user where username=? and password=?";
				
				QueryRunner runner = new QueryRunner(JDBCUtils.getDataSource());
				
				User user = runner.query(sql, new BeanHandler<User>(User.class), username,password);
				
				if(user != null){
					System.out.println("登录成功");
					
					//将用户信息保存到session中
					session.setAttribute("user", user);
					
					resp.sendRedirect("/review/index");
				}else{
					System.out.println("账号或密码错误");
				}
				
			}else{
				System.out.println("验证码错误");
			}
		
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

5.增加防跳墙的功能:要求用户只能通过登录成功之后才能进入/index,如果用户直接访问/index则重定向到登录页面
在这里插入图片描述

第 8 章JSP

8.1 JSP介绍

JSP,Java Server Pages,Java服务器端页面(网页)技术
在JSP页面中,Java代码可以和HTML代码共存,其中Java代码负责处理数据,HTML代码负责显示数据

创建JSP页面
右击WebContent—New—JSP File—输入文件名
或者:右击WebContent—New—Other—Web—JSP File—输入文件名
在这里插入图片描述

修改jsp页面的编码为UTF-8
Window—Preferences----搜索JSP—Templates----
在这里插入图片描述

8.2 JSP基本语法

代码块
在JSP页面中可以将Java代码块写到:
<% Java代码块 %>
在这里插入图片描述

输出变量/表达式结果:
<%=变量 或 表达式%>
在这里插入图片描述

8.3JSP注释

HTML代码注释:
JSP代码注释: <%-- 注释的内容 --%>
注释的快捷键:ctrl + shift + /
在这里插入图片描述

8.4 JSP指令

在jsp2.0中共定义了page、include和taglib三种指令。
page指令, 配置JSP页面信息的。
include指令,页面包含的,导入页面的。
<%@include file=“top.jsp”%>
taglib指令, 导入资源,格式:
<%@ taglib prefix=“c” uri=“http://java.sun.com/jsp/jstl/core” %>
* prefix:前缀,自定义的
在这里插入图片描述

8.5 JSP内置对象

为了提升开发效率,JSP给我们提供了9大内置对象,不需要定义,我们在JSP脚本中可以直接使用。我们重点掌握下面红色字体标识的
在这里插入图片描述

重点掌握4大域对象
request域对象
session域对象
application域对象
pageContext域对象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第 9 章EL

在JSP页面开发中,为了获取Servlet域对象中存储的数据,经常需要书写很多Java代码,这样的做法会使JSP页面混乱,难以维护,为此,在JSP2.0规范中提供了EL表达式。
EL是Expression Language的缩写,它是一种简单的数据访问语言。
EL的目的:简化JSP脚本的书写。
EL语法格式:${EL表达式}

9.1 EL表达式获取数据

EL用来简化jsp操作
使用EL表达式获取四大域对象中的数据
${key}
如果获取域中的数据时,如果没有指定所在的域,会按照下面的顺序依次查找
—依次从pageContext域,request域,session域,application域中获取属性,在某个域中获取后将不在向后寻找
在这里插入图片描述

9.1.1 获取基本类型的数据

在这里插入图片描述
在这里插入图片描述

9.1.2 获取对象类型数据

对象:${域名称.键名.属性名}

  • 本质上会去调用对象的getter方法
    在这里插入图片描述

9.1.3 获取List集合中的数据

List集合:${域名称.键名[索引]}
在这里插入图片描述

9.1.4 获取Map集合中的数据

Map集合:
${域名称.键名.key名称}
${域名称.键名[“key名称”]}
在这里插入图片描述

9.2 EL中的运算符

在这里插入图片描述

9.3 JSTL介绍

JSTL,JSP Standard Tag Lib,JSP标准标签库,提供了一些标签(<c:if> <c:forEach>),能够在JSP页面完成更加复杂的业务逻辑,总之用于简化和替换jsp页面上的java代码

使用步骤:
1. 导入jstl相关jar包
2. 引入标签库:taglib指令: <%@ taglib %>
<%@ taglib uri=“http://java.sun.com/jsp/jstl/core” prefix=“c”%>
3. 使用标签:
在这里插入图片描述

Java的标签库,常见的标签有:
<c:if></c:if>
<c:forEach></c:forEach>
<c:choose></c:choose>
在这里插入图片描述

使用步骤:
1.导包
将jstl相关的jar包拷贝到WebContent/WEB-INF/lib目录下

2.在jsp页面引入标签库
<%@ taglib uri=“http://java.sun.com/jsp/jstl/core” prefix=“c”%>

3.c:if标签

9.4作业

在 /list 中查询所有的用户列表,然后将请求转发给 /list.jsp页面,并在list.jsp页面中遍历用户列表

1.编写UserBean,用来封装用户表单中的用户信息
在这里插入图片描述

2.编写 /list 页面
在这里插入图片描述

3.在list.jsp页面遍历用户列表
在这里插入图片描述

4.访问 /list
http://localhost:8080/review/list

第 10 章注册功能

10.1 搭建用户注册界面

1.搭建register.jsp界面,核心代码如下:

<div id="info">
	<h1>用户注册</h1>
	<form action="${pageContext.request.contextPath}/user/register" method="post">
		<table>
			<tr>
				<td align="right" width="42%">账号:</td>
				<td><input type="text" name="username" /><font size="2" color="red" >${exist }</font></td>
			</tr>
			<tr>
				<td align="right">密码:</td>
				<td><input type="password" name="password"/></td>
			</tr>
			<tr>
				<td align="right">真实姓名:</td>
				<td><input type="text" name="realname" /></td>
			</tr>
			<tr>
				<td align="right">性别:</td>
				<td>
					<input type="radio" name="gender" value="" checked/><input type="radio" name="gender" value=""/></td>
			</tr>
			<tr>
				<td align="right">手机号:</td>
				<td><input type="text" name="phone" /></td>
			</tr>
			<tr>
				<td align="right">邮箱:</td>
				<td><input type="text" name="email" /></td>
			</tr>
			<tr>
				<td align="right">出生日期:</td>
				<td><input type="text" name="birthday" /></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<input type="submit" value="注册" />
					<input type="reset" value="重置" />
				</td>
			</tr>
		</table>
	</form>
</div>

10.2 servlet接收表单数据

将注册页面form表单控件中的数据提交至后台servlet,
servlet接收前台用户所有提交的数据后,封装为用户对象并返回
//获取前台传递的参数
String username = request.getParameter(“username”);
Map<String, String[]> map = request.getParameterMap();

	//调用工具类方法,判断用户名是否存在
	boolean exist = userService.checkUserNameExist(username);
	if(exist){
		//存在,向request域中存储信息,提示用户用户名存在,将请求转发回register.jsp页面
		request.setAttribute("exist", "*该用户名已被注册");
		request.getRequestDispatcher("/register.jsp").forward(request, response);
	}else{
		//用户名可用,调用业务逻辑添加用户方法,将用户信息写入文件
		try {
			userService.addUser(map);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

10.3 将接收的表单数据保存到文件中
用户注册时,需要判断用户名是否已经注册
封装一个工具类:判断用户名是否存在


```xml
public boolean checkUserNameExist(String username){
		//调用工具类UserFileUtil方法读取文件并将用户信息封装为集合返回
		List<User> userList = UserFileUtil.getUserList(UserFileUtil.ROOT_PATH+UserFileUtil.FILE_PATH);
		//遍历集合,把每个对象身上的用户名拿出来做匹配
		for (User user : userList) {
			if(user.getUsername().equals(username)){
				//用户名存在则返回true
				return true;
			}
		}
		//用户名不存在返回false
		return false;
	}

2.调用业务逻辑类方法添加用户信息至文件

```xml
public void addUser(Map<String, String[]> map) throws Exception{
		//调用工具类方法将从请求对象中获取到的map集合里的参数直接封装为User类对象
		User user = UserFileUtil.getUser(map, User.class);
		//调用工具类方法将对象写入到文件
		UserFileUtil.writeUserToFile(user, UserFileUtil.ROOT_PATH+UserFileUtil.FILE_PATH);
	}

注:上图中的User user = UserFileUtil.getUser(map, User.class);可替换为原生方式.
例如:

String username = request.getParameter("username");
		String password = request.getParameter("password");
		String realname = request.getParameter("realname");
		String gender = request.getParameter("gender");
		String phone = request.getParameter("phone");
		String email = request.getParameter("email");
		String birthday = request.getParameterValues("birthday");
        User user = new User(new Date().getTime(),username, password, realname, gender, phone, email, birthday);

3.使用工具类方法将对象写入到文件

public static void writeUserToFile(User user,String path){
		try {
			//创建字符流的输出流对象
			FileWriter fw = new FileWriter(path, true);
			//向文件内写入的是一个字符串的用户信息,所以在写入之前,要将用户的所有信息拿出来拼接成一个完整的字符串再进行写入操作
			String userMsg = user.toString();
			//向文件内写入对象的字符串信息
			fw.write(userMsg);
			//刷新
			fw.flush();
			//关闭
			fw.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

第 11 章登录功能

11.1 搭建用户登录界面

创建前台login.jsp页面

<div id="info">
	<h1>用户登录</h1>
	<form action="${pageContext.request.contextPath }/user/login" method="post">
		<table>
			<tr>
				<td align="right" width="42%">账号:</td>
				<td><input type="text" name="username" />
<font size="2" color="red" >${flag }</font>
</td>
			</tr>
			<tr>
				<td align="right">密码:</td>
				<td><input type="password" name="password" value=""/></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<input type="checkbox" name="autoLogin" value="autoLogin"/>自动登录
					<a href="${pageContext.request.contextPath}/jsp/user/register.jsp">没有账号?</a>
				</td>
			</tr>
			<tr>
				<td colspan="2" align="center" >
					<input type="submit" value="登录" />
					<input type="reset"  />
				</td>
				
			</tr>
		</table>
		
	</form>
</div>

11.2 servlet接收登录表单提交的数据

将登录页面的信息提交至处理登录请求的servlet
//从前台页面获取提交过来的账号和密码

String username = request.getParameter("username");
		String password = request.getParameter("password");
		
		//获取前台是否是自动登录
		String autoLogin = request.getParameter("autoLogin");
         //调用业务逻辑层检测是否需要自动登录功能
		userService.checkAutoLogin(username, password, autoLogin, request, response);
		
		//获取session对象
		HttpSession session = request.getSession();
         //获取ServletContext对象
		ServletContext application = request.getServletContext();
		//调用业务逻辑层用户登录方法验证用户正好密码是否正确,正确则重定向至用户列表页面,失败则转发至登录页面
		User user = userService.login(username,password);
		if(user != null){
              //在session中保存当前登录用户对象
			session.setAttribute("user", user);
              //通过工具类方法读取文件获取用户信息集合
			List<User> userList = UserFileUtil.getUserList(UserFileUtil.ROOT_PATH+UserFileUtil.FILE_PATH);
              //将用户信息集合添加至application作用域中
			application.setAttribute("userList", userList);
			response.sendRedirect(request.getContextPath()+"/jsp/user/list.jsp");
		}else{
              //若前台提交的账号密码错误,则在请求域中存入错误信息,在前台页面中通过EL表达式提示用户
			request.setAttribute("flag", "*账号或密码错误");
			request.getRequestDispatcher("/login.jsp").forward(request, response);
		}

11.3 用户自动登录

1.检测用户是否需要自动登录功能

public void checkAutoLogin(String username,String password,String autoLogin,HttpServletRequest request,HttpServletResponse response){
		if(autoLogin != null){
			//创建Cookie对象保存账号密码
			Cookie userCookie = new Cookie("username", username);
			Cookie passCookie = new Cookie("password", password);
			//设置Cookie对象的有效期为7天
			userCookie.setMaxAge(60*60*24*7);
			passCookie.setMaxAge(60*60*24*7);
			//设置浏览器访问哪些web应用资源时需要带着Cookie回来
			userCookie.setPath(request.getContextPath()+"/");
			passCookie.setPath(request.getContextPath()+"/");
			//将Cookie对象添加到响应对象身上,打给浏览器进行存储
			response.addCookie(userCookie);
			response.addCookie(passCookie);
		}
	}

2.用户登录方法:

public User login(String username,String password){
		//利用工具类获取用户信息文件中的数据组成集合
		List<User> userList = UserFileUtil.getUserList(UserFileUtil.ROOT_PATH+UserFileUtil.FILE_PATH);
		//遍历集合拿着参数中的账号和密码跟集合中的用户对象进行匹配
		for (User user : userList) {
			if(user.getUsername().equals(username)&&user.getPassword().equals(password)){
				//符合条件,返回用户对象
				return user;
			}
		}
		//不符合条件则返回null
		return null;
	}

3.优化自动登录功能,在访问用户列表jsp页面时,添加java脚本代码:

/*
		 * 实现思路:
		 *request.getSession();作为服务器端,如果能够从Cookie中获取到JSESSIONID,那么服务器端将不再创建新的
		 *session对象,而是通过JSESSIONID找到对应的session为浏览器服务
		 *Path=/java_user_project   request.getContextPath()
		 *创建Cookie,键名是JSESSIONID,Path是/java_user_project,浏览器会自动识别这个Cookie,将之前的覆盖掉
		 *在这里将JSESSIONID这个Cookie设置一下有效期,目的是将其在浏览器端进行保存,如果一旦关闭了浏览器
		 *再次打开浏览器访问服务器时,仍旧会带着JSESSIONID回来,这样的话作为服务器端可以从Cookie中获取到JSESSIONID
		 *的话,服务器就不会再创建新的session对象
		 *list.jsp页面中可以直接通过session对象获取到存在其内部的用户对象,从而实现自动登录
		 */
		//创建session对象
		HttpSession session = req.getSession();
		//获取session的id
		String JSESSIONID = session.getId();
		//覆盖服务器帮我们生成的"JESSIONID"-Cookie
		Cookie cj = new Cookie("JSESSIONID", JSESSIONID);
		cj.setPath(req.getContextPath());
		cj.setMaxAge(60*30);
		resp.addCookie(cj);
		
		//验证session中是否有用户,如果没有session则验证Cookie中有没有账号密码,如果都没有则将页面打回登录页面
		//在这里我们需要访问这个页面时作为浏览器端必须要带着JSESSIONID回来,才能让下面的session对象生效
		User user = (User)session.getAttribute("user");
		System.out.println(user);
		if(user==null){
			//若session已经超时,则会通过请求对象获取Cookie
			Cookie[] cookies = req.getCookies();
			String username = "";
			String password = "";
			if(cookies != null){
				//获取Cookie中存储的账号密码
				for(Cookie c:cookies){
					if(c.getName().equals("username")){
						username = c.getValue();
					}
					if(c.getName().equals("password")){
						password = c.getValue();
					}
				}
			}
			//调用业务逻辑登录方法获取登录的用户对象
			UserService userService = new UserService();
			user = userService.login(username, password);
			//账号密码错误则对象为空,页面重定向至登录页面,若账号不为空则显示用户信息JSP页面
			if(user==null){
				resp.sendRedirect(req.getContextPath()+"/login.jsp");
			}
		}

第 12 章查看已注册的用户列表

实现思路:
1.在登录成功或自动登录成功后可以查看到所有用户信息列表,需创建list.js页面

<div id="info">
	<h1>用户信息列表</h1>
	<table border="1">
		<tr>
			<th>编号</th>
			<th>账号</th>
			<th>密码</th>
			<th>真实姓名</th>
			<th>性别</th>
			<th>手机号码</th>
			<th>邮箱</th>
			<th>出生日期</th>
			<th>操作</th>
		</tr>
		<!-- 通过jstl+EL表达式的方式将后台存储在application域对象中的用户信息集合遍历渲染在表格中 -->
		<c:forEach items="${userList }" var="user">
			<tr>
				<td align="center">${user.user_id }</td>
				<td>${user.username }</td>
				<td>${user.password }</td>
				<td align="center">${user.realname }</td>
				<td align="center">${user.gender }</td>
				<td align="center">${user.phone }</td>
				<td align="center">${user.email }</td>
				<td>${user.birthday }</td>
				<td align="center">
					<a href="${pageContext.request.contextPath }/user/delUser?user_id=${user.user_id }">删除</a>
					<a href="${pageContext.request.contextPath }/user/findOneUser?user_id=${user.user_id }">修改</a>
				</td>
			</tr>
		</c:forEach>
	</table>
</div>

第 13 章用户列表的防跳墙(过滤器)

13.1 过滤器介绍

生活中的过滤器:净水器、空气净化器、过滤嘴香烟…

在web开发中的过滤器:当访问服务器的某个资源时,过滤器可以将用户的请求拦截,从而完成一些特殊的功能

过滤器的作用:
完成通用的操作:统一登录验证、统一编码处理

13.2 过滤器快速入门

1.自定义类,实现Filter接口
2.实现/重写接口中的抽象方法
在这里插入图片描述

3.配置拦截路径
在这里插入图片描述

13.3 过滤器细节

1.执行流程
访问服务器的某个资源时,先执行过滤器,如果过滤器放行,则继续执行后续代码
在这里插入图片描述

2.生命周期
当服务器启动后,会先创建Filter对象,然后调用init方法进行初始化(只执行1次)
服务器关闭后,filter对象被销毁
每次请求被拦截的资源时,doFilter都会执行

3.过滤器拦截路径配置
@WebFilter(“/index.jsp”),当访问index.jsp资源时,才会被过滤器拦截
@WebFilter(“/user/”),拦截目录,当访问/user目录下的资源时,过滤器都执行
@WebFilter(“
.jsp”),当访问后缀名为.jsp的资源时,才会被过滤器拦截
@WebFilter(“/*”),当访问所有资源时,都会被过滤器拦截

13.4 过滤器案例-自动登录

分析登录的流程:
在这里插入图片描述

防跳墙的登录验证功能描述:
1.先验证用户是否已经登录
2.如果已经登录了,则直接放行
3.如果没有登录,则跳转到登录页面,并提示”请先登录”
在这里插入图片描述

@WebFilter("/*")	//使用该过滤器对所有的请求进行拦截
public class LoginFilter implements Filter{
@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
			throws IOException, ServletException {
		
		//将ServletRequest强转为HttpServletRequest
		HttpServletRequest request = (HttpServletRequest) req;
		
		//获取请求的资源名称
		String uri = request.getRequestURI();
		
		//排除css、js、image等静态资源 以及 和登录相关的操作
		if(uri.contains("/login.jsp") || 
				uri.contains("/loginServlet")||
				uri.contains("/css/")||
				uri.contains("/fonts/")||
				uri.contains("/images/")||
				uri.contains("/captcha/")
		){
			chain.doFilter(req, resp);
		}else{
			//判断是否登录
			HttpSession session = request.getSession();
			Object user = session.getAttribute("user");
			if(user != null){
				//登录成功
				chain.doFilter(req, resp);
			}else{
				//没有登录,跳转到登录页面
				request.setAttribute("login_msg", "请先登录");
				request.getRequestDispatcher("/admin/login.jsp").forward(req, resp);
			}
		}
	}

在这里插入图片描述
在这里插入图片描述

第 14 章多条件搜索用户

实现思路:

  1. 在列表页面添加表单元素,提供相应的搜索条件的显示,当用户单击查询按钮后,服务器接收请求并作出响应。
    在列表页面添加表单元素
    在这里插入图片描述

  2. 在列表Servlet中,接收用户的请求、处理数据、将数据存储域对象中,在列表中显示数据。
    在这里插入图片描述
    在这里插入图片描述

第 15 章用户删除和修改

15.1删除功能
实现思路:
当用户单击“删除”超链接后,服务器接收到请求及请求中的数据、处理数据、然后页面跳转到列表页面。

  1. 修改列表页面“删除”超链接的herf属性的值,传递需要删除的一条数据的id值,id值要求必须唯一、不能重复,然后根据id进行删除。
    在这里插入图片描述

2.创建处理删除请求的Servlet。
在这里插入图片描述

15.2修改功能

在修改数据的时候,需要给用户显示原数据,以提高用户体验。
实现思路:
1.数据回显:当用户单击“修改”超链接后,访问接收请求,获取数据id,如何根据id查询用户需要修改的数据,将数据存储到域对象中,页面跳转到修改页面,回显数据。
2.数据修改:当用户修改完数据后,单击“修改”按钮,服务器接收到请求,从请求中获取数据,处理数据,将数据持久化到文件中,然后页面转发到列表页面。

数据回显
修改列表页面“删除”超链接的herf属性的值。
在这里插入图片描述

创建servlet处理用户的请求,获取用户需要修改的数据。
在这里插入图片描述

在修改页面使用EL进行数据回显。

在这里插入图片描述

2.修改数据
创建处理修改请求的Servlet,将修改后的数据持久化到文件中,页面跳转到列表页面。
在这里插入图片描述

第 16 章查看个人详细信息

  1. 打开用户列表,给每条用户信息后增加链接,点击后携带编号(id)信息访问Servlet。目的是查询出该用户在文件中存储的详细信息。
    在这里插入图片描述

“查看详情”链接对应的代码是:

<table>
   <tr>   
<th>姓名</th>
	   <th>性别</th>
	   <th>年龄</th>
	   <th>电话</th>            
	   <th>地址</th>
	   <th>爱好</th>
	   <th>操作</th>
</tr> 
<c:forEach items="${pagerlist.list }" var="user">
    <tr>
      <td>${user.name }</td>
      <td>${user.sex }</td>
      <td>${user.age }</td>
      <td>${user.telphone }</td>
      <td>${user.address }</td>
      <td>${user.like }</td>
      <td>
<a href="">修改</a>
<a href="">删除</a>
<a href="<%=request.getContextPath()%>/DetailServlet?id=${user.id}">查看详情</a>      </td>
      </tr>
      </c:forEach>    
</table>
  1. DetailServlet中获取链接中传来的id,根据此id从文件中查询该用户的详细信息,并将该信息放到请求域中转发到详情界面。
DetailServlet
//获取链接中传过来的name值
String name = request.getParameter("id");
UserService  um = new UserService();
//按照id查询出用户对象
User user = um.getUserById(id);
//请求域中存放用户对象,转发到/main/showOneUser.jsp
request.setAttribute("user", user);
request.getRequestDispatcher("/main/showOneUser.jsp").forward(request, response);

3.DetailServlet中调用UserService类中方法根据id获取用户对象。
UserService类

/**
	 * 按照id获取用户详细信息
	 */
	public User getUserById(Long id){
         //通过工具类将文件中所有信息转为User集合
		List<User> list = UserFileUtil.getUserListFromFile();
		for (User user : list) {//遍历User集合
			if(user.getId()==id){//如果找到该用户则返回它
				 return user;
			}
		}
		return null;
	}

4.详情界面(showOneUser.jsp)中获取请求域中的值(user),显示到界面上。

<div class="container cus-container">
        <h3 class="text-center">详情页</h3>
            <div class="form-group"> 姓名: ${user.name } </div>
            <div class="form-group">  密码:${user.pass }</div>
            <div class="form-group">  性别:${user.sex}</div>
            <div class="form-group">  年龄:${user.age}</div>
            <div class="form-group">  电话:${user.telphone }</div>
            <div class="form-group">  地址:${user.address }</div>
            <div class="form-group">  爱好:${user.like } </div>
            <div class="form-group">  其它:${user.remarks } </div>
    </div>

5.运行,列表界面点击“查看详情”链接查看效果。
在这里插入图片描述

第 17 章完善个人信息(只能修改自己的)

在这里插入图片描述

1.用户登陆时,Servelt中把个人信息加入到session域中。

HttpSession session = request.getSession();//获得session
session.setAttribute("loginUser", loginUser);//将登陆成功的用户对象

在这里插入图片描述

加入到session域中

2.登陆成功后,列表页面点击”个人中心”链接进入PersonalServlet,根据session中存储的当前登陆人的ID,查看当前登陆人的详细信息,并放入请求域转发到个人中心页面。

PersonalServlet代码
HttpSession session = request.getSession();
//获取session中登陆人对象User
User user = (User) session.getAttribute("loginUser");
UserService um = new UserService();
//按照id查询出用户对象
User user = um.getUserById(user.getId());
//将用户对象放入到请求域中,转发到个人中心页面。
request.setAttribute("user", user);
request.getRequestDispatcher("/main/mypages.jsp").forward(request, response);

3.个人中心界面获取请求域中的信息使用JSTL+EL回显信息。

  <div class="container cus-container">
        <h3 class="text-center">个人中心</h3>
        <form action="<%=request.getContextPath()%>/modifyServlet" method="POST">
           <!—通过隐藏域存储id值-->
<input type="hidden" name="id" value="${user.id}"/>
 <div class="form-group">
              <label for="user">姓名:</label>
              <input type="text" class="form-control" name="name" id="name" value="${user.name }" placeholder="请输入姓名">
            </div>
            
            <div class="form-group">
              <label for="pass">密码:</label>
              <input type="text" class="form-control" name="pass" id="pass" value="${user.pass }" placeholder="请输入密码">
            </div>  
             <div class="form-group">
                <label for="gender">性别:</label>
                <label class="radio-inline">
                   <input type="radio" name="sex" id="gender1" value="" <c:if test="${user.sex eq ''}">checked</c:if>> 男 
                </label>
                <label class="radio-inline">
                   <input type="radio" name="sex" id="gender2" value="" <c:if test="${user.sex ==''}">checked</c:if>> 女 
                </label>
            </div>
            <div class="form-group">
                <label for="age">年龄:</label>
<select name="age">
                <option value="">请选择年龄</option>
                <c:forEach begin="0" end="150" var="i">
                <option value="${i }" <c:if test="${user.age==i }">selected</c:if>>${i }</option>
                </c:forEach>
                </select>
            </div>
            <div class="form-group">
                <label for="telphone">电话:</label>
                <input type="text" class="form-control" name="telphone" id="telphone" value="${user.telphone }" placeholder="请输入电话">
            </div>
            <div class="form-group">
                <label for="address">地址:</label>
                <input type="text" class="form-control" name="address" id="address" value="${user.address }" placeholder="请输入地址">
            </div>
            <div class="form-group">
                <label for="address">爱好:</label>
   <% User user = (User)request.getAttribute("user");
                		String like ="";
                		if(user!=null){
                		 like = user.getLike(); 		 
                		}%>
                     <input type="checkbox" name="like" value="旅游" <%if(like.contains("旅游")){ %> checked <%} %>/>旅游
                 <input type="checkbox" name="like" value="唱歌"  <%if(like.contains("唱歌")){ %> checked <%} %>/>唱歌
                  <input type="checkbox" name="like" value="读书" <%if(like.contains("读书")){ %> checked <%} %> />读书
                   <input type="checkbox" name="like" value="游泳" <%if(like.contains("游泳")){ %> checked <%} %> />游泳
                    <input type="checkbox" name="like" value="玩球" <%if(like.contains("玩球")){ %> checked <%} %> />玩球
            </div>
            <div class="form-group">
                <label for="remarks">其它:</label> 
                <textarea rows="5" name="remarks" cols="80">${user.remarks }</textarea> 
            </div>
            <div class="text-center">            	
                <button type="submit" class="btn btn-primary">修改</button>
                <button type="reset" class="btn btn-default">重置</button>   
            </div>         
          </form>
    </div>

在这里插入图片描述

4.个人中心界面点击“修改”进入ModifyServlet修改信息。(修改省略)
5.运行即可。

第 18 章用户列表分页功能

1.使用工具类读出到文件中所有的User的集合。
2.多条件搜索界面点击“搜索”按钮后也需要能够分页,所以下面封装工具类及方法。
3.定义工具类Pager用来存放分页需要的所有数据。

import java.io.Serializable;
import java.util.List;
/**
 * <b> 分页通用类 </b>
 * @param <T>
 *
 */
public class Pager<T> implements Serializable {
	private static final long serialVersionUID = 4542617637761955078L;
	/**
	 * currentPage 当前页
	 */
	private int currentPage = 1;
	/**
	 * pageSize 每页大小
	 */
	private int pageSize = 10;
	/**
	 * pageTotal 总页数
	 */
	private int pageTotal;
	/**
	 * recordTotal 总条数
	 */
	private int recordTotal = 0;
	/**
	 * content 每页的内容
	 */
	private List<T> list;
 
	/**
	 * 设置当前页 <br>
	 * @param currentPage
	 */
	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	/**
	 * 设置每页大小,也可以不用赋值,默认大小为10条 <br>
	 *
	 * @param pageSize
	 */
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	/**
	 * 设置总条数,默认为0 <br>
	 * @param recordTotal
	 */
	public void setRecordTotal(int recordTotal) {
		this.recordTotal = recordTotal;
		// 总页数
 		this.pageTotal = this.recordTotal % this.pageSize > 0 ? this.recordTotal / this.pageSize + 1
 				: this.recordTotal / this.pageSize;
 		
	}

	/**
	 * 设置分页内容 <br>
	 * @param content
	 */
	public void setList(List<T> list) {
		this.list = list;
	}
 
	// 放开私有属性
	public int getCurrentPage() {
		return currentPage;
	}

	public int getPageSize() {
		return pageSize;
	}

	public int getPageTotal() {
		return pageTotal;
	}
 

	public List<T> getList() {
		return list;
	}

	@Override
	public String toString() {
		return "Pager [currentPage=" + currentPage + ", pageSize=" + pageSize + ", pageTotal=" + pageTotal + ", list="
				+ list + "]";
	}
}

4.封装分页及多条件查询方法

  /**
     * 获取当前应该显示的集合信息 ,多条件及分页查询方法
     * @param currentPage 当前页
     * @param pageSize 每页显示条数
     * @param name 要查询的姓名
     * @param address 要查询的地址 模糊查询
     * @param sex 要查询的性别
     * @return Pager 
     */
	public Pager<User> getContentList(Pager pager,String name,String sex,String address){
		//多条件查询,按照填写的条件查询,如果都不填写,默认查询所有
		List<User> result = new ArrayList<>() ;//存放最终返回数据的集合
		List<User> list = new ArrayList<>() ;//存放所有满足条件的数据
		try {
			BufferedReader br  = new BufferedReader(new FileReader(FileManager.basePath+FileManager.userInfoFile));
			String line;
			while((line=br.readLine())!=null){
				String msgs[] = line.split("-");
				boolean fname = false;
				boolean fsex = false;
				boolean faddress = false;
				if(name==null||name.trim().length()==0||msgs[0].equals(name.trim())){//如果没有填名字,或者姓名满足条件都设置标志为true
					fname=true;
				}
				if(sex==null||sex.trim().length()==0||msgs[2].equals(sex.trim())){//如果没有填sex,或者sex满足条件都设置标志为true
					fsex=true;
				}
				if(address==null||address.trim().length()==0||msgs[5].contains(address.trim())){//如果没有填address,或者address满足条件都设置标志为true
					faddress=true;
				}
				if(fname&&fsex&&faddress){//如果三个条件都满足 则该行满足要求加入集合。
					User user = new User(msgs[0], msgs[1], msgs[2], Integer.parseInt(msgs[3]), msgs[4], msgs[5], msgs[6], msgs[7]);
					list.add(user);
				}
				 
			}
			
			br.close();
			int begin = (pager.getCurrentPage()-1)*pager.getPageSize();//开始条数      
			int end = (pager.getCurrentPage()*pager.getPageSize()<list.size())?pager.getCurrentPage()*pager.getPageSize():list.size();//结束条数
			for (int i =begin; i < end; i++) {
				result.add(list.get(i));//将指定数目的数据加入结果集合。
			}
			pager.setRecordTotal(list.size());//设置总条数
			pager.setList(result);//设置要显示的数据
		}catch (Exception e) {
			e.printStackTrace();
		} 
		return pager;
		
	}

4.搜索界面,点击“搜索”后进入Servlet,Servlet中获取查询条件,从页面上获取分页相关数据,调用封装好的方法,获取页面要显示的数据,放入请求域中,重新转发到列表界面。
Servlet代码如下:

String name = request.getParameter("name");//获取查询的姓名
	String sex = request.getParameter("sex");//获取查询的性别
	String address = request.getParameter("address");//获取查询的地址
	String currentPage = request.getParameter("currentPage");//获取当前页的值
		String pageSize = request.getParameter("pageSize");
		UserManager um = new UserManager();
		Pager<User> pager = new Pager<User>();
		if(currentPage!=null){
			pager.setCurrentPage(Integer.parseInt(currentPage));
		}
		if(pageSize!=null){
			pager.setPageSize(Integer.parseInt(pageSize));
		}
		//获得结果数据
		pager = (Pager<User>) um.getContentList(pager, name, sex, address);
		request.setAttribute("pagerlist",pager );//从文件中获取集合数据
		request.setAttribute("name", name);//为了不丢失搜索条件
		request.setAttribute("sex", sex); 
		request.setAttribute("address", address);
		request.getRequestDispatcher("/main/list.jsp").forward(request, response);     //forward是跳转的方法
4.页面上获取数据显示,同时显示分页导航

     <!-- 分页导航 -->
        <nav style="float: left;">
            <ul class="pagination">
            <%	
            Pager pager = (Pager)request.getAttribute("pagerlist");  
			if(pager.getCurrentPage() > 1){%>
			
   				<li><a href="<%=request.getContextPath() %>/index/list?currentPage=<%=pager.getCurrentPage()-1%>&name=${name}&sex=${sex}&address=${address}" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
   				
   			<%}else{%>   			
   				<li><a href="javascript:void(0)" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
   			<%} 
   			//循环生成中间的数字导航
   			//始终显示10页,显示当前页的前5页、后4页
            int begin;
   			int end;	
   			if(pager.getPageTotal() <= 10){
   				// 总的页数 <= 10
   				begin = 1;
   				end = pager.getPageTotal();
   			}else{
   				//大于10页,例如:总18页 ,当前7页   2 3 4 5 6 7 8 9 10 11
   				//显示当前页的前5页、后4页
   				begin = pager.getCurrentPage() - 5;
   				end = pager.getCurrentPage() + 4;
   				
   				//有2种特殊情况
   				//当前页前面不够5页: 例如当前是第4页:1 2 3 4 5 6 7 8 9 10
   				if(pager.getCurrentPage() <= 5){
   					begin = 1;
   					end = 10;
   				}
   				//当前页后面不够4页, 例如:总18页 ,当前第16页:9 10 11 12 13 14 15 16 17 18 
   				if(end > pager.getPageTotal()){
   					begin = pager.getPageTotal() - 9;
   					end = pager.getPageTotal();
   				}   				
   			}
   			
   			for(int i=begin;i<=end;i++){
   				if(pager.getCurrentPage() == i){ %>
   					<li class="active"><a href="<%=request.getContextPath() %>/index/list?currentPage=<%=i%>&name=${name}&sex=${sex}&address=${address}"><%=i%></a></li>
   				<% }else{%>
   					<li><a href="<%=request.getContextPath() %>/index/list?currentPage=<%=i%>&name=${name}&sex=${sex}&address=${address}"><%=i%></a></li>
   				<% } 				
   			}
          	
   			if(pager.getCurrentPage() < pager.getPageTotal()){%>
   				<li><a href="<%=request.getContextPath() %>/index/list?currentPage=<%=pager.getCurrentPage()+1%>&name=${name}&sex=${sex}&address=${address}" aria-label="下一页"><span aria-hidden="true">&raquo;</span></a></li>
   			<% }else{%>
   				<li class="disabled"><a href="javascript:void(0)" aria-label="下一页"><span aria-hidden="true">&raquo;</span></a></li>
   			<%  } %>
            </ul>
        </nav>
;