web开发基础
C/S架构
服务器-客户机,即Client-Server(C/S)结构。C/S结构通常采取两层结构。服务器负责数据的管理,客户机负责完成与用户的交互任务。
例如我们需要下载QQ、微信、电脑版吃鸡,如果该客户端软件需要升级,用户需要重新下载最新版本的客户端下载安装。
C(客户端Client)/S(Server)架构
C(客户端Client)/S(Server)架构 桌面应用程序
java swing 、 c#
下载对应的安装包
安装成功之后
才可以使用
B/S架构
什么是web开发
Web:全球广域网,也称为万维网(www),也就是能够通过浏览器访问的网站
例如 通过浏览器访问 www.mayikt.com 、www.baidu.com、www.taobao.com。
JavaWeb开发:是使用java技术栈开发Web项目。
什么是B/S架构
B/S架构的全称为Browser/Server,即浏览器/服务器结构,Browser指的是Web浏览器
它的特点是 客户端只需要安装浏览器,应用程序的逻辑和数据都存放在服务器端共享访问。
优点:易于维护升级:服务器端升级后,客户端(浏览器端无需升级)就获取最新的版本
静态web资源(如html 页面、js、css、images):指web页面中供人们浏览的数据始终是不变。
动态web资源:指web页面中供人们浏览的数据是由程序产生的,不同时间点访问web页面看到的内容各不相同。
静态web资源开发技术:Html js、css、images
常用动态web资源开发技术:JSP/Servlet、ASP、PHP等
在Java中,动态web资源开发技术统称为Javaweb。
B/S体系架构的软件 版本升级的时候 客户端是无需升级的 只需要重新刷新网页即可。
缺陷:会占用服务器端带宽资源。
Http协议原理
Http基本概念
基于HTTP传输协议(超文本传输协议)客户端与服务器端之间数据传输规则。
HTTP特点:
1.底层基于TCP协议实现 ,面向连接方式安全;
2.基于请求(request)与响应(response)模型
3.Http协议是无状态协议,对于事务处理是没有任何记忆功能
4.Http协议多次请求无法共享,在javaweb开发中我们可以通过cookie、session解决该问题
5.http协议数据传输过程中 属于同步的过程;如果客户端发送请求达到服务器端,服务器端已经不响应 可能会导致 客户端会一直阻塞等待 对于用户体验是不好的 所以客户端发送请求达到服务器时会设置超时时间 例如5s。
Http请求格式
请求数据格式:
1.请求行 请求方法(get、post)、url (/首页) http协议版本1.1版本 请求第一行
GET /front/showcoulist HTTP/1.1
2.请求头 (键值对的形式)
Host: www.mayikt.com Connection: keep-alive Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://www.mayikt.com/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: __yjs_duid=1_92c8557b9791d34466e53ea75410e2c01649305342102; JSESSIONID=B303350E58BA0F1230E0B66A9ADCD35F; Hm_lvt_eaa952b8610db6f155ab0febd442e89a=1649305345,1649313679; Hm_lpvt_eaa952b8610db6f155ab0febd442e89a=1649316541
请求体
1.请求行:请求数据第一行
1.1由3部分组成,分别为:请求方法、URL 以及协议版本,之间由空格分隔
1.2请求方法包括GET、HEAD、PUT、POST、TRACE、OPTIONS、DELETE以及扩展方法,当然并不是所有的服务器都实现了所有的方法,部分方法即便支持,处于安全性的考虑也是不可用的
1.3协议版本的格式为:HTTP/主版本号.次版本号,常用的有HTTP/1.0和HTTP/1.1
2.请求头:
第二行开始,格式 key:value形式
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: X-Log, X-Reqid
Access-Control-Max-Age: 2592000
常见http协议请求头
Host:接受请求的服务器地址,可以是IP:端口号,也可以是域名
User-Agent:发送请求的应用程序名称
Connection:指定与连接相关的属性,如Connection:Keep-Alive
Accept-Charset:通知服务端可以发送的编码格式
Accept-Encoding:通知服务端可以发送的数据压缩格式
Accept-Language:通知服务端可以发送的语言
3.请求体:
post请求的最后一部分,存放发送请求的参数
userName=mayikt&age=26
get与post请求区别
1.get请求请求的参数在请求行中,没有请求体;
2.post请求请求参数在请求体中;
3.get请求请求参数有大小限制,post请求没有
测试html
<!DOCTYPE html>
<html>
<head>
<title>登录测试页面</title>
<form action="login.html" method="get">
<label>用户名: </label><input type="text" name="username" /><br>
<label>密 码 : </label><input type="password" name="password" /><br>
<input type="submit" value="登录 " />
</form>
</head>
</html>
Http响应格式
响应格式分为3个部分
1.响应行:响应数据第一行 http协议版本1.1版本
200表示响应状态码 ok为 成功状态
2.响应头:第二行开始 格式 key value
Location: http://www.baidu.com(服务端需要客户端访问的页面路径)
Server:apache tomcat(服务端的Web服务端名)
Content-Encoding: gzip(服务端能够发送压缩编码类型)
Content-Length: 80(服务端发送的压缩数据的长度)
Content-Language: zh-cn(服务端发送的语言类型)
Content-Type: text/html; charset=GB2312(服务端发送的类型及采用的编码方式)
Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT(服务端对该资源最后修改的时间)
Refresh: 1;url=http://www.mayikt.com(服务端要求客户端1秒钟后,刷新,然后访问指定的页面路径)
Content-Disposition: attachment; filename=aaa.zip(服务端要求客户端以下载文件的方式打开该文件)
Transfer-Encoding: chunked(分块传递数据到客户端)
Set-Cookie:SS=Q0=5Lb_nQ; path=/search(服务端发送到客户端的暂存数据)
Expires: date(Cache-Control过期时间)
Cache-Control: no-cache(服务端禁止客户端缓存页面数据) max-age=xx(通知浏览器:xx秒之内别来烦我,自己从缓冲区中刷新)
Pragma: no-***(服务端禁止客户端缓存页面数据)
Connection: close(1.0)/(1.1)Keep-Alive(维护客户端和服务端的连接关系)
Date: Tue, 11 Jul 2000 18:23:51 GMT(服务端响应客户端的时间)
服务器端响应结果给客户端类型:
1.text/html;charset=UTF-8
2.image类型
3.响应体 存放服务器响应给客户端的内容
http协议常见响应状态
1.404----客户端发送请求达到服务器端地址填写错了
2.500---服务器端 发生了错误
Http响应状态码
HTTP状态码说明
1xx(临时响应)
表示临时响应并需要请求者继续执行操作的状态代码。
100: (继续) 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
101: (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。
2xx (成功)
200: (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
201: (已创建) 请求成功并且服务器创建了新的资源。
202: (已接受) 服务器已接受请求,但尚未处理。
203: (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
204: (无内容) 服务器成功处理了请求,但没有返回任何内容。
205: (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206: (部分内容) 服务器成功处理了部分 GET 请求。
3xx (重定向)
表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。
300: (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301: (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302: (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303: (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
304: (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
305: (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
307: (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
4xx(请求错误,一般是客户端问题)
这些状态代码表示请求可能出错,妨碍了服务器的处理。
400: (错误请求) 服务器不理解请求的语法。
401: (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403: (禁止) 服务器拒绝请求。
404: (未找到) 服务器找不到请求的网页。
405: (方法禁用) 禁用请求中指定的方法。
406: (不接受) 无法使用请求的内容特性响应请求的网页。
407: (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
408: (请求超时) 服务器等候请求时发生超时。
409: (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
410: (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
411: (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
412: (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
413: (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414: (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
415: (不支持的媒体类型) 请求的格式不受请求页面的支持。
416: (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
417: (未满足期望值) 服务器未满足"期望"请求标头字段的要求。
5xx(服务器错误,一般是服务端问题)
这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。
500: (服务器内部错误) 服务器遇到错误,无法完成请求。
501: (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502: (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503: (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504: (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505: (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
socket
概述
1、计算机网络是通过传输介质、通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来,实现资源共享和数据传输的系统。网络编程就就是编写程序使联网的两个(或多个)设备(例如计算机)之间进行数据传输。Java语言对网络编程提供了良好的支持,通过其提供的接口我们可以很方便地进行网络编程。例如我们的QQ聊天
2、Java是 Internet 上的语言,它从语言级上提供了对网络应用程 序的支持,程序员能够很容易开发常见的网络应用程序。
3、Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在 Java 的本机安装系统里,由 JVM 进行控制。并 且 Java 实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。
网络通讯三要素
IP地址
端口号
协议
1、我们需要知道的是主机间通过网络进行通信是需要遵循网络通信协议,是通过IP地址准确定位主机,通过端口号准确定位主机上的应用,例如IP地址和端口号 192.168.110.1:80
2、如何实现网络中的主机互相通信?
① 通信双方地址:IP和端口号
② 一定的规则协议。 tcp或者udp
IP地址和端口号码
IP地址准确定位主机
1.IP 地址:InetAddress(在Java中使用InetAddress类代表IP)
一的标识 Internet 上的计算机(通信实体)
2.本地回环地址(hostAddress):127.0.0.1 主机名(hostName):localhost
3.IP地址分类方式1:IPV4 和 IPV6
3.1 IPV4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已 经用尽。以点分十进制表示,如192.168.0.1
3.2 IPV6:128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位表示, 数之间用冒号(:)分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
4.IP地址分类方式2:公网地址(万维网使用)和私有地址(局域网使用)。192.168. 开头的就是私有址址,范围即为192.168.0.0–192.168.255.255,专门为组织机 构内部使用
特点:不易记忆
端口号就是标识正在计算机上运行的进程(程序)
不同的进程有不同的端口号
被规定为一个 16 位的整数 0~65535。
InetAddress
在JDK中提供了一个与IP地址相关的InetAddress类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法。
InetAddress类的常用方法
方法声明 | 功能描述 |
InetAddress getByName(String host) | 获取给定主机名的的IP地址,host参数表示指定主机 |
InetAddress getLocalHost() | 获取本地主机地址 |
String getHostName() | 获取本地IP地址的主机名 |
boolean isReachable(int timeout) | 判断在限定时间内指定的IP地址是否可以访问 |
String getHostAddress() | 获取字符串格式的原始IP地址 |
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author 余胜军
* @ClassName Test01
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class Test01 {
public static void main(String[] args) throws UnknownHostException {
// 获取给定主机名的的IP地址,host参数表示指定主机
InetAddress inetAddress = InetAddress.getByName("192.168.0.106");
// 获取获取本地IP地址的主机名
String hostName = inetAddress.getHostName();
// 获取IP地址
String address = inetAddress.getHostAddress();
System.out.println("hostName:" + hostName);
System.out.println("address:" + address);
}
}
ipconfig 获取本机的ip地址
1.127.0.0.1 (电脑自己访问自己)
2.localhost (电脑自己访问自己)
3.192.168.0.106 直接获取到局域网的ip (让别人访问电脑)
dns域名解析
hostName 就是我们的域名
hostName 主机名称 其实就是 域名
mayikt.com---域名
taobao.com---域名
localhost--域名 dns解析ip地址
为了方便记忆 我们会使用域名在通过dns解析成我们的ip地址。
C:\Windows\System32\drivers\etc 配置我们本地dns域名解析。
www.mayikt.com 配置公网ip地址 刷新到电信运营
UDP协议
什么是UDP
UDP协议 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据报的方法,俗称面向无连接
。通俗易懂讲解 UDP协议会把数据打包发送给目标地址, 这个数据包能不能发送给目标地址就不管了,所以我们的udp协议 它是不可靠协议、安全性低,容易丢包 但是速度非常快 无需类似于 tcp协议三次握手。
核心特点:面向无连接、不可靠的协议 、安全系数很低 容易丢包 但是传输速度是非常快 不需要类似于tcp协议三次握手。 聊天工具
发送数据
1.创建发送端socket对象;
2.提供数据,并将数据封装到数据包中;
3.通过socket服务的发送功能,将数据包发出去;
4.释放资源;
在windows 操作系统中,C:\Windows\System32\drivers\etc\HOSTS 文件中 新增
127.0.0.1 test.mayikt.com
相关代码:
import java.io.IOException;
import java.net.*;
/**
* @author 余胜军
* @ClassName UdpClient
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class UdpClient {
public static void main(String[] args) throws IOException {
//1.创建发送端socket对象;
DatagramSocket datagramSocket = new DatagramSocket();
//2.提供数据,并将数据封装到数据包中;
byte[] msg = "mayikt".getBytes();
InetAddress inetAddress = InetAddress.getByName("test.mayikt.com");
int port = 8848;
DatagramPacket datagramPacket = new DatagramPacket(msg, msg.length, inetAddress, port);
//3.通过socket服务的发送功能,将数据包发出去;
datagramSocket.send(datagramPacket);
//4.释放资源;
datagramSocket.close();
}
}
接受数据
1.创建接收端socket对象;
2.接收数据;
3.解析数据;
4.输出数据;
5.释放资源;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
* @author 余胜军
* @ClassName UdpServer
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class UdpServer {
public static void main(String[] args) throws IOException {
//创建接收端socket对象
DatagramSocket datagramSocket = new DatagramSocket(8848);
//接收数据;
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
//解析数据;
System.out.println("开始接受数据.");
datagramSocket.receive(datagramPacket);
System.out.println("接受到数据.");
//输出数据;
String msg = new String(datagramPacket.getData());
System.out.println(msg);
//释放资源;
datagramSocket.close();
}
}
练习题
使用udp协议 客户端可以一直发送数据给服务器端,服务器端可以一直接受到客户端发送的数据。
如果客户端输入 666 就会直接退出程序。
public class UdpClient {
public static void main(String[] args) throws IOException {
// 创建DatagramSocket发送者
DatagramSocket ds =
new DatagramSocket();
// 创建Scanner
while (true) {
System.out.println("客户端:请输入发送的内容");
Scanner sc = new Scanner(System.in);
String context = sc.nextLine();
if ("666".equals(context)) {
System.out.println("退出程序...");
break;
}
byte[] data = context.getBytes();
// 封装数据包
DatagramPacket dp =
new DatagramPacket(data, data.length, InetAddress.getByName("mayikt.server.com"), 8080);
ds.send(dp);
System.out.println("发送数据成功...");
}
ds.close();
}
}
public class UdpServer {
public static void main(String[] args) throws IOException {
// 创建DatagramSocket接受
DatagramSocket ds =
new DatagramSocket(8080);
// 创建Scanner
while (true) {
//2.接收数据
byte[] bytes = new byte[1024];
// 数据包的形式接受
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
ds.receive(dp);
System.out.println("服务器端接受到数据:" + new String(dp.getData()));
}
// ds.close();
}
}
TCP协议
三次握手
TCP是面向连接的可靠协议、通过三次握手建立连接,通讯完成时拆除连接
UDP是面向无连接通讯协议,udp通讯时不需要接受方确定,属于不可靠传输,可能会存在丢包的现象。
tcp协议 需要先经历三次握手成功之后 在将数据发送给服务器端 确保服务器端是在 在将数据
发送给服务器端。三次握手、四次挥手。
udp协议直接将数据发送给服务器端-----传输效率高 缺陷 没有验证服务器端
是否存在 如果不在的情况下 直接传输数据 可能丢失数据
数据连接池 目的tcp协议连接复用
jdbc
首先我们要知道在tcp建立连接中,有一些名词表示:
比如:syn就是建立连接、ack就是确认标志、fin终止标志
第一次握手:客户端会向服务器端发送码为syn=1,随机产生一个seq_number=x的数据包到服务器端 (syn)
第二次握手:服务端接受到客户端请求之后,确认ack=x+1, 于是就向客户端发送syn(服务端独立生成 随机生成数字Y)+ack
第三次握手:客户端接受syn+ack,向服务器端发送ack=y+1,此包发送完毕即可 建立tcp连接。
白话文翻译:
第一次握手:客户端向服务器端发送 问服务器你在不在?
第二次握手:服务器端回应客户端说:我在的。
第三次握手:客户端发送给服务器端:ok,那我开始建立连接的
关闭连接:
第一次挥手: 客户端向服务器端发送释放的报文,停止发送数据fin=1、生成一个序列号seq=u;
第二次挥手: 服务器端接受到释放的报文后,发送ack=u+1;随机生成的seq=v给客户端;当前状态为关闭等待状态
客户端收到了服务器确认通知之后,此时客户端就会进入到终止状态,等待服务器端发送释放报文。
第三次挥手:服务器端最后数据发送完毕之后,就向客户端发送连接释放报文,FIN=1,ack=u+1 当前为半关闭状态,随机生成一个随机树w
第四次挥手,客户端必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
白话文翻译四次挥手:
第一次挥手 客户端向服务端发送一个释放连接通知;
第二次挥手 服务端接受到释放通知之后,告诉给客户端说等待一下,因为可能存在有其他的数据没有发送完毕,等待数据全部传输完毕之后就开始 关闭连接;
第三次挥手 服务器端所有的数据发送完毕之后,就告诉客户端说现在可以释放连接了。
第四次挥手: 客户端确认是最终释放连接通知,ok 就开始 就向服务区端发送我们可以开始关闭连接啦;
客户端
1.创建发送端Socket对象(创建连接)
2.获取输出流对象;
3.发送数据;
4.释放资源;
public class TcpClient {
public static void main(String[] args) throws IOException {
//创建socket连接Socket
Socket s = new Socket(InetAddress.getByName("mayikt.server.com"), 8090);
//获取数据流对象
OutputStream outputStream = s.getOutputStream();
String data = "mayikt tcp";
// 写入数据
outputStream.write(data.getBytes());
// 关闭资源
outputStream.close();
s.close();
}
}
服务器端
1.创建接收端Socket对象;
2.监听(阻塞:如果建立连接失败,程序会一直阻塞,不往下执行;
3.获取输入流对象;
4.获取数据;
5.输出数据;
6.释放资源;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 余胜军
* @ClassName TcpServer
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class TcpServer {
public static void main(String[] args) throws IOException {
// 创建serverSocket
ServerSocket serverSocket = new ServerSocket(8090);
// 监听客户端数据
Socket socket = serverSocket.accept();
// 获取到客户端发送的数据
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
System.out.println("客户端发送的数据:" + new String(bytes, 0, len));
// 关闭资源
inputStream.close();
serverSocket.close();
}
}
Exception in thread "main" java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:75)
at java.net.AbstractPlainSocketImpl
客户端连接不上服务器端 javaweb开发 http协议 底层就是基于 tcp协议封装
tomcat 报错:Connection refused: connect
原因:
1.ip 访问不同 防火墙 没有关闭 或者 只能够在局域网访问
练习题1
使用tcp协议 客户端可以一直发送数据给服务器端,服务器端可以一直接受到客户端发送的数据。
如果客户端输入 666 就会直接退出程序。
服务器端代码:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
/**
* @author 余胜军
* @ClassName TcpServer
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class TcpServer {
public static void main(String[] args) throws IOException {
// 创建serversocket对象
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服务器端启动成功....");
while (true) {
// 接受客户端数据
Socket socket = serverSocket.accept();
//inputStream
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
System.out.println("服务器端接受客户端:" + new String(bytes, 0, len));
// 服务端响应数据给客户端
OutputStream outputStream = socket.getOutputStream();
String resp = "我收到啦" + UUID.randomUUID().toString();
outputStream.write(resp.getBytes());
inputStream.close();
outputStream.close();
socket.close();
}
}
}
客户端:
package com.mayikt.test04;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* @author 余胜军
* @ClassName TcpClinet
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class TcpClinet {
public static void main(String[] args) throws IOException {
while (true) {
// 创建socket对象
Socket socket = new Socket("127.0.0.1", 8080);
System.out.println("客户端:请输入发送数据的内容");
Scanner sc = new Scanner(System.in);
String context = sc.nextLine();
if (context.equals("666")) {
break;// 退出循环
}
// 获取getOutputStream
OutputStream outputStream = socket.getOutputStream();
// 写入数据给服务器端
outputStream.write(context.getBytes());
// 接受服务器端响应的内容
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
System.out.println("服务端响应数据给客户端:" + new String(bytes, 0, len));
outputStream.close();
socket.close();
}
}
}
改造成多线程方式:
练习题2
使用tcp协议 实现登录
tcp服务器端代码
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
/**
* @author 余胜军
* @ClassName TcpServer
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class TcpServer {
public static void main(String[] args) throws IOException {
// 服务器端可以一直接受 客户端数据
// 创建监听端口号码 ServerSocket
ServerSocket serverSocket = new ServerSocket(8080);
System.out.println("服务器端启动成功...");
while (true) {
// 监听客户端发送过来的数据注意 我们的客户端没有发送数据给服务器端 该方法就会在这里一直阻塞
Socket socket = serverSocket.accept();
//不允许单独new线程 线程池来维护线程----java进阶
new Thread(new Runnable() {
@Override
public void run() {
try {
// 接受客户端数据
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
// userName=mayikt&userPwd=123456
String text = new String(bytes, 0, len);
String[] split = text.split("&");
String userName = split[0].split("=")[1];
String userPwd = split[1].split("=")[1];
// 回应数据给客户端
OutputStream outputStream = socket.getOutputStream();
if (("mayikt".equals(userName) && "123456".equals(userPwd))) {
outputStream.write("ok".getBytes());
} else {
outputStream.write("fails".getBytes());
}
// 关闭资源
inputStream.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}
tcp客户端代码
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* @author 余胜军
* @ClassName TcpClient
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class TcpClient {
public static void main(String[] args) throws IOException {
// 客户端是可以一直发送数据给服务器端
while (true) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户的名称:");
String userName = sc.nextLine();
System.out.println("请输入用户的密码:");
String userPwd = sc.nextLine();
Socket socket = new Socket("127.0.0.1", 8080);
// 获取到我们的outputStream
OutputStream outputStream = socket.getOutputStream();
// 发送数据
String text = "userName=" + userName + "&userPwd=" + userPwd;
outputStream.write(text.getBytes());
// 接受服务器端响应数据给客户端
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
String resp = new String(bytes, 0, len
);
if ("ok".equals(resp)) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
// 关闭资源
outputStream.close();
socket.close();
}
}
}
练习题3
使用tcp协议 web服务器
package com.mayikt.test06;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 余胜军
* @ClassName HttpTcpServer
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class HttpTcpServer {
public static void main(String[] args) throws IOException {
// 服务器端可以一直接受 客户端数据
// 创建监听端口号码 ServerSocket
ServerSocket serverSocket = new ServerSocket(80);
System.out.println("服务器端启动成功...");
while (true) {
// 监听客户端发送过来的数据注意 我们的客户端没有发送数据给服务器端 该方法就会在这里一直阻塞
Socket socket = serverSocket.accept();
//不允许单独new线程 线程池来维护线程----java进阶
new Thread(new Runnable() {
@Override
public void run() {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
// 获取请求地址
byte[] reqByte = new byte[1024];
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
int reqLen = inputStream.read(reqByte);
String reqUrl = new String(reqByte, 0, reqLen);
String url = reqUrl.split("\r\n")[0].split(" ")[1];
File file = new File("D:\\mayikt\\html" + url);
byte[] bytes = new byte[20480];
FileInputStream fileInputStream = new FileInputStream(file);
//从硬盘中读取数据到内存中
int len = fileInputStream.read(bytes);
//返回数据给浏览器
outputStream.write(bytes, 0, len);
} catch (Exception e) {
e.printStackTrace();
if (outputStream != null) {
try {
outputStream.write("404".getBytes());
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
} finally {
// 关闭资源
try {
outputStream.close();
inputStream.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}
}
}
总结
web服务器使用
Tomcat:由Apache组织提供的一种Web服务器,提供对jsp和Servlet的支持。它是一种轻量级的javaWeb容器(服务器),也是当前应用最广的JavaWeb服务器(免费)。
Jboss:是一个遵从JavaEE规范的、开放源代码的、纯Java的EJB服务器,它支持所有的JavaEE规范(免费)。
GlassFish: 由Oracle公司开发的一款JavaWeb服务器,是一款强健的商业服务器,达到产品级质量(应用很少,收费)。
Resin:是CAUCHO公司的产品,是一个非常流行的应用服务器 的支持,性能也比较优良,resin自身采用JAVA语言开发(收费,应用比较多)。
WebLogic:是Oracle公司的产品,是目前应用最广泛的Web服务器,支持JavaEE规范,而且不断的完善以适应新的开发要求,适合大型项目(收费,用的不多,适合大公司)。
web服务器 底层是如何实现 基于tcp协议封装 http协议、springboot框架 底层内嵌入我们的 Tomcat服务器
web服务器简介
web服务器是一个应用程序(软件),对http协议的进行封装,让web开发更加便捷。
我们在上节课谈到手写http服务器框架,底层是基于socket tcp实现。
tomcat下载地址:Apache Tomcat® - Apache Tomcat 10 Software Downloads
Apache Tomcat最早是由Sun Microsystems开发的一个Servlet容器,在1999年被捐献给ASF(Apache Software Foundation),隶属于Jakarta项目,现在已经独立为一个顶级项目。Tomcat主要实现了Java EE中的Servlet、JSP规范,同时也提供HTTP服务,是市场上非常流行的Java Web容器。
Tomcat服务器基本使用
1.bin(文件夹)例如启动tomcat 或者停止tomcat --------可执行文件
*.bat---运行在windows批处理文件
*.sh-----linux环境中运行文件
startup.bat ----启动tomcat
shutdown.bat---停止tomcat
如果tomcat启动成功之后 tomcat控制台界面 是不会停止的。
如果tomcat启动失败的话,则tomcat控制台界面会闪退。
tomcat 启动之后默认端口号码:8080
tomcat欢迎界面。
2.conf 存放全局配置文件 修改tomcat启动端口号码
logging.properties
3.webapps 存放运行程序 部署war包、jar包、静态资源。
http://127.0.0.1:8080/mayikt/ 默认就是查找tomcat webapps 目录中
mayikt文件夹中 index.html
4.lib tomcat 需要依赖一些jar包
5.logs 存放 tomcat一些日志
6.temp存放临时文件
7.work
1.bin:主要存放tomcat的操作命令,根据操作系统可以分为两大类:一是以.bat结尾(Windows);二是以.sh结尾(Linux)。比如可以通过startup启动,shutdown关闭Tomcat。
2.conf:全局配置文件
2一个策略文件:catalina.policy 定义了安全策略。
两个属性文件:catalina.properties 和 logging.properties 。
四个XML配置文件:
server.xml:Tomcat的主要配置文件,配置整个服务器信息,如修改连接器端口号(默认为8080)。不能动态重加载,文件修改之后必须重启服务器才能生效。
web.xml:全局的web应用程序部署描述文件,如可以设置tomcat支持的文件类型。
context.xml:Tomcat的一些特定配置项,针对所有应用程序生效。
tomcat-users.xml:配置Tomcat的用户名、密码,管理身份验证以及访问控制权限。
3.lib:Tomcat运行依赖的一些Jar文件,比如常见的servlet-api.jar、jsp-api.jar。所有的应用程序可用,可以放置一些公用的Jar文件,如MySQL JDBC驱动(mysql-connector-java-5.1.{xx}-bin.jar)。
4.logs:运行中产生的日志文件。包含引擎(engine)日志文件 Catalina.{yyyy-mm-dd}.log,主机日志文件localhost.{yyyy-mm-dd}.log,以及一些其他应用日志文件如manager、host-manager。访问日志也保存在此目录下。
5.temp:临时文件目录,清空不会影响Tomcat运行
6.webapps:默认的应用程序根目录,Tomcat启动时会自动加载该目录下的应用程序,可以以文件夹、war包、jar包的形式发布(启动时会自动解压成相应的文件夹)。也可以把应用程序放置在其他路径下,需要在文件中配置路径映射。
7.work:用来存放tomcat在运行时的编译后文件,如JSP编译后的文件。清空work目录,然后重启tomcat,可以达到清除存的作用。
-----------------------------------------------------------------------------------
bin:可以执行文件。
conf:tomcat服务器的配置文件
lib:tomcat启动后需要依赖的jar包
logs:tomcat工作之后的日志文件
webapps:是tomcat部署工程的目录。
work:jsp文件在被翻译之后,保存在当前这个目录下,session对象被序列化之后保存的位置
tomcat下载:
双击启动:startup.bat 访问:http://127.0.0.1:8080/
注意 如果大家下载好了tomcat安装包之后 ,tomcat安装位置 不要带中文、不要带任何空格路径。
纯英文路径下运行tomcat。
启动tomcat常见问题
启动tomcat控制台乱码
双击启动:startup.bat
D:\path\Tomcat\tomcat10\apache-tomcat-10.0.20-windows-x64\apache-tomcat-10.0.20\conf
logging.properties
删除掉,在启动就好了。
启动tomcat闪退问题
启动tomcat直接闪退,注意检查下jdk安装的环境变量
如何关闭Tomcat服务器
第一种:Ctrl+C键 关闭Tomcat服务器
第二种:点击Tomcat窗口的右上角关闭按钮 (暴力停止服务器)
第三种:找到tomcat目录/shutdown.bat文件,双击执行关闭Tomcat。
发生启动tomcat服务器直接闪退----说明jdk环境没有好
Tomcat服务器配置
修改端口号码
1.找到tomcat目录/conf/server.xml
2.修改port的值,将port端口的值修改为80
Tomcat服务器部署项目
方式1:直接在tomcat webapps 目录创建一个文件夹
方式2:在tomcat目录/conf/server.xml 配置
127.0.0.1:8080/mayikt----D:\mayikt目录中查找info.html
host标签中:
<Context path="/mayikt" docBase="D:\mayikt"/>
<Context path=”浏览器要访问的目录---虚拟目录” docBase=网站所在磁盘目录”/>
方式3:将项目打成war包 放入到tomcat webapps目录中 自动解压
方式4:webapps目录下/ROOT工程的访问
当我们在浏览器中直接输入http://ip地址:端口号 那么 默认访问的是Tomcat目录/webapps/ROOT目录如果webapps下面有一个ROOT的项目。那么在访问的时候,直接可以省略项目的名字/ 表示找到root目录
----tomcat欢迎页面部署 ----webapps root 目录中
Tomcat web开发项目结构
idea 先创建一个普通java项目
在将该java项目 变成web项目
整合tomcat
idea创建web项目
1.选择创建项目
2.创建java项目
3.填写项目名称
4.新增 add framework support
5.选择web application
6.多了web-inf文件夹
7.新增tomcat
8.点击新增tomcat
8.选择tomcat server
9.添加tomcat 路径
10.添加当前java项目
11.点击运行项目
12.自动弹出界面
web项目目录结构说明
web
html ---js、images html --外界都可以访问
web-inf 目录 该目录外界是无法访问的
classes 目录
lib
web.xml
web项目结构
src------java代码 核心的配置文件(例如 spring配置文件等) servlet
web-----静态资源 或者jsp等
html--html、js、css、images等 静态资源 外部都可以直接访问的。
web-inf ------外界是无法访问的。
web.xml------servlet相关配置
index.jsp
servlet
什么是servlet
Servlet定义:Servlet是基于Java技术的Web组件,由容器管理并产生动态的内容。Servlet与客户端通过Servlet容器实现的请求/响应模型进行交互。
springmvc----底层基于Servlet
演示代码:
http://localhost:8081/mayikt_tomcat04_war_exploded/mayikt?userName=mayikt
package com.mayikt.servlet;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author 余胜军
* @ClassName IndexServlet
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/mayikt")
public class IndexServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
String userName = servletRequest.getParameter("userName");
servletResponse.setContentType("text/html;charset=utf-8");
PrintWriter writer = servletResponse.getWriter();
if ("mayikt".equals(userName)) {
writer.println("可以访问");
} else {
writer.println("无法访问");
}
writer.close();
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
课程安排
1.servlet 环境搭建
2.servlet 执行流程
3.servlet 生命周期
4.servlet 方法介绍
5.xml方式配置servlet
6.httprequest/httpresponse
7.httprequest获取请求数据
8.httphttpresponse 响应数据
9.解决httprequest获取乱码问题
10.jdbc+servlet实现登录和注册
servlet 环境搭建
1.在我们的项目中创建libs目录存放第三方的jar包
2.项目中导入servlet-api.jar libs目录中
就在我们tomcat安装的目录 中 lib 目录中
servlet-api.jar 讲完课之后上传到 文档中可以直接下载
3.创建servlet包 专门存放就是我们的servlet
4.创建IndexServlet 实现Servlet 重写方法
5.IndexServlet 类上加上@WebServlet("/mayikt")注解定义 URL访问的路径
6.重写Servlet 类中service 在service中编写 动态资源
package com.mayikt.servlet;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author 余胜军
* @ClassName IndexServlet
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/mayikt")
public class IndexServlet implements Servlet {
/**
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* tomcat启动完成
* 127.0.0.1:8080/项目名称/mayikt 执行 service 通过service方法获取servletRequest、servletResponse
*
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("mayikt644");
// 需要通过servletRequest对象获取到客户端传递参数到服务器端
String userName = servletRequest.getParameter("userName");
PrintWriter writer = servletResponse.getWriter();
if ("mayikt".equals(userName)) {
// 返回数据 ok
writer.println("ok");
} else {
// fail
writer.println("fail");
}
writer.close();// 关闭资源
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
servlet debug调试
养成习惯 学会通过 debug模式 运行项目---非常重要
f8---下一步
f9---跳到下一个断点
servlet 执行流程
思考点:
1.servlet是谁创建的?我们的service是谁在调用?
servlet tomcatweb服务器创建
service tomcatweb服务器创建
2.tomcat服务器如何执行到servlet中的service方法?
我们自己创建的servlet 必须实现servlet接口重写service方法。
Caused by: java.lang.IllegalArgumentException: 名为 [com.mayikt.servlet.MayiktServlet]和 [com.mayikt.servlet.MeiteServlet] 的servlet不能映射为一个url模式(url-pattern) [/mayiktmeite]
at org.apache.tomcat.util.descriptor.web.WebXml.addServletMappingDecoded(WebXml.java:346)
at org.apache.tomcat.util.descriptor.web.WebXml.addServletMapping(WebXml.ja
servleturl 映射路径不要重复哦!
1.servlet是谁创建的?我们的service是谁在调用?
servlet是由我们的 web服务器(tomcat)创建、该方法是由我们的 web服务器(tomcat)调用
断点分析
2.tomcat服务器如何执行到servlet中的service方法?
这是因为我们创建的servlet实现httpservlet接口 重写了service方法
servlet 生命周期(重点)
1.创建servlet 被 服务器(tomcat)加载servlet
选择创建servlet ?
如果是第一次访问servlet 才会创建servlet ---优点
第一次访问到servlet (单例模式) 线程安全问题
先创建servlet
在执行service方法
该servlet 创建好了以后 在jvm内存中只会存在一份。
如果是第二次访问servlet
在执行service方法
提前创建servlet 或者当你第一次访问servlet 创建servlet 对象
提前创建servlet ----优点可以 第一次访问的时候就不需要创建
servlet 对象可以提高效率、但是 项目启动时提前创建servlet
这样就会导致tomcat启动变得比较慢了。 浪费内存---
2.执行servlet类中init---初始化方法
当我们的servlet类被创建时,执行servlet类初始化方法init 代码初始化
该方法只会执行一次。
3.servlet类---service-----执行每次请求
每次客户端发送请求达到服务器端 都会执行到 servlet类service方法
4.servlet类---destroy---当我们tomcat容器停止时卸载servlet
存放销毁相关代码
1. 创建Servlet实例
web容器负责加载Servlet,当web容器启动时或者是在第一次使用这个Servlet时,容器会负责创建Servlet实例,但是用户必须通过部署描述符(web.xml)指定Servlet的位置,或者在类上加上@WebServlet,成功加载后,web容器会通过反射的方式对Servlet进行实例化。
@WebServlet(urlPatterns = "/mayiktmeite",loadOnStartup = 1)
负数---第一次被访问时创建Servlet对象 @WebServlet(urlPatterns = "/mayiktmeite",loadOnStartup = -1)
0或者正数:服务器启动时创建Servlet对象 数字越小优先级越高
MeiteServlet loadOnStartup = 1
YushengjunServlet loadOnStartup = 2
底层会根据loadOnStartup (从0开始)值排序 越小越优先加载创建
2. WEB容器调用Servlet的init()方法,对Servlet进行初始化
在Servlet实例化之后,Servlet容器会调用init()方法,来初始化该对象,主要是为了让Servlet对象在处理客户请求前可以完成一些初始化的工作,例如,建立数据库的连接,获取配置信息等。对于每一个Servlet实例,init()方法只能被调用一次。init()方法有一个类型为ServletConfig的参数,Servlet容器通过这个参数向Servlet传递配置信息。Servlet使用ServletConfig对象从Web应用程序的配置信息中获取以名-值对形式提供的初始化参数。另外,在Servlet中,还可以通过ServletConfig对象获取描述Servlet运行环境的ServletContext对象,使用该对象,Servlet可以和它的Servlet容器进行通信。无论有多少客户机访问Servlet,都不会重复执行init()。
3. Servlet初始化之后,将一直存在于容器中,service()响应客户端请求
1. 如果客户端发送GET请求,容器调用Servlet的doGet方法处理并响应请求
2. 如果客户端发送POST请求,容器调用Servlet的doPost方法处理并响应请求
3. 或者统一用service()方法处理来响应用户请求
service()是Servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。要注意的是,在service()方法被容器调用之前,必须确保init()方法正确完成。容器会构造一个表示客户端请求信息的请求对象(类型为ServletRequest)和一个用于对客户端进行响应的响应对象(类型为ServletResponse)作为参数传递给service()方法。在service()方法中,Servlet对象通过ServletRequest对象得到客户端的相关信息和请求信息,在对请求进行处理后,调用ServletResponse对象的方法设置响应信息。
4. WEB容器决定销毁Servlet时,先调用Servlet的destroy()方法,通常在关闭web应用之前销毁Servlet
destroy()仅执行一次,在服务器端停止且卸载Servlet时执行该方法。当容器检测到一个Servlet对象应该从服务中被移除的时候,容器会调用该对象的destroy()方法,以便让Servlet对象可以释放它所使用的资源,保存数据到持久存储设备中,例如,将内存中的数据保存到数据库中,关闭数据库的连接等。当需要释放内存或者容器关闭时,容器就会调用Servlet对象的destroy()方法。在Servlet容器调用destroy()方法前,如果还有其他的线程正在service()方法中执行,容器会等待这些线程执行完毕或等待服务器设定的超时值到达。一旦Servlet对象的destroy()方法被调用,容器不会再把其他的请求发送给该对象。如果需要该Servlet再次为客户端服务,容器将会重新产生一个Servlet对象来处理客户端的请求。在destroy()方法调用之后,容器会释放这个Servlet对象,在随后的时间内,该对象会被Java的垃圾收集器所回收。
servlet 线程是否安全?
servlet 对象默认是单例 在jvm内存中只会存在一份
当多个线程如果共享到同一个全局变量可能会存在线程安全性问题
需求:需要统计 你是第一个人访问网站?
package com.mayikt.servlet;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author 余胜军
* @ClassName CountServlet
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/count")
public class CountServlet implements Servlet {
private Integer count = 1;
public CountServlet() {
System.out.println("CountServlet 对象被创建");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
servletResponse.setContentType("text/html;charset=utf-8");
PrintWriter writer = servletResponse.getWriter();
writer.println("您是第" + count + "个人访问网站!");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
writer.close();
synchronized (this) {
count++;
}
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
servlet 方法介绍
Servlet接口定义了5种方法:
init()
service()
destroy()
getServletConfig()
getServletInfo()
1.init()
在Servlet实例化后,Servlet容器会调用init()方法来初始化该对象,主要是为了让Servlet对象在处理客户请求前可以完成一些初始化工作,例如:建立数据库的连接,获取配置信息等。对于每一个Servlet实例,init()方法只能被调用一次。init()方法有一个类型为ServletConfig的参数,Servlet容器通过这个参数向Servlet传递配置信息。Servlet使用ServletConfig对象从Web应用程序的配置信息中获取以名-值对形式提供的初始化参数。另外,在Servlet中,还可以通过ServletConfig对象获取描述Servlet运行环境的ServletContext对象,使用该对象,Servlet可以和它的Servlet容器进行通信。
2.service()
容器调用service()方法来处理客户端的请求。要注意的是,在service()方法被容器调用之前,必须确保init()方法正确完成。容器会构造一个表示客户端请求信息的请求对象(类型为ServletRequest)和一个用于对客户端进行响应的响应对象(类型为ServletResponse)作为参数传递给service()。在service()方法中,Servlet对象通过ServletRequest对象得到客户端的相关信息和请求信息,在对请求进行处理后,调用ServletResponse对象的方法设置响应信息。
3.destroy
当容器检测到一个Servlet对象应该从服务中被移除的时候,容器会调用该对象的destroy()方法,以便让Servlet对象可以释放它所使用的资源,保存数据到持久存储设备中,例如将内存中的数据保存到数据库中,关闭数据库的连接等。当需要释放内存或者容器关闭时,容器就会调用Servlet对象的destroy()方法,在Servlet容器调用destroy()方法前,如果还有其他的线程正在service()方法中执行容器会等待这些线程执行完毕或者等待服务器设定的超时值到达。一旦Servlet对象的destroy()方法被调用,容器不回再把请求发送给该对象。如果需要改Servlet再次为客户端服务,容器将会重新产生一个Servlet对象来处理客户端的请求。在destroy()方法调用之后,容器会释放这个Servlet对象,在随后的时间内,该对象会被java的垃圾收集器所回收。
4.getServletInfo()
返回一个String类型的字符串,其中包括了关于Servlet的信息,例如,作者、版本和版权。该方法返回的应该是纯文本字符串,而不是任何类型的标记。
5.getServletConfig()
该方法返回容器调用init()方法时传递给Servlet对象的ServletConfig对象,ServletConfig对象包含了Servlet的初始化参数。
package com.mayikt.servlet;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebInitParam;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author 余胜军
* @ClassName ServletConfigServlet
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet(urlPatterns = "/servletConfig", initParams = {@WebInitParam(name = "p1", value = "mayikt")})
public class ServletConfigServlet implements Servlet {
private ServletConfig servletConfig;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig;
}
@Override
public ServletConfig getServletConfig() {
return servletConfig;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
String value = getServletConfig().getInitParameter("p1");
PrintWriter writer = servletResponse.getWriter();
writer.println(value);
writer.close();
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
servlet 体系结构
HttpServlet 对的servlet接口包装 提供 get/post等方法
request与response对象
request与response对象
request:获取客户端发送数据给服务器端
response:返回对应的数据给客户端(浏览器)
http协议基于 请求(request)与响应的模型(response)
package com.mayikt.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author 余胜军
* @ClassName ServletDemo05
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/servletDemo05")
public class ServletDemo05 extends HttpServlet {
/**
* 获取到HttpServletRequest、HttpServletResponse对象
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// req 获取到客户端发送数据给服务器()
// http://localhost:8081/mayikt_tomcat04_war_exploded/servletDemo05?userName=mayikt&userPwd=123
String userName = req.getParameter("userName");//userName=mayikt
String userPwd = req.getParameter("userPwd");//userPwd=123456
PrintWriter writer = resp.getWriter();
// 判断用户传递的 用户名称和密码 如果是为zhangsan 644064 则 登录成功
if ("zhangsan".equals(userName) && "644064".equals(userPwd)) {
// 服务器端处理完数据之后 返回对应的数据给客户端 告诉给客户端说 响应的是一个 html或者是文本
resp.setHeader("Content-Type", "text/html;charset=UTF-8");
writer.write("<html> <meta charset=\"utf-8\"/><body><h1>恭喜您登录成功,用户名称是:" + userName + "</h1></body></html>");
} else {
writer.write("<html><meta charset=\"utf-8\"/><body><h1>很遗憾密码错误</h1></body></html>");
}
// 关闭资源
writer.close();
}
}
request与response继承模型
ServletRequest ------ 接口 java提供的请求对象根接口
HttpServletRequest ------ 接口(继承ServletRequest) java提供的对http协议封装请求对象接口
org.apache.catalina.connnector.RequestFacade —— 类(Tomcat编写的,实现HttpServletRequest )
request获取请求数据
http://localhost:8080/mayikt-tomcat04/servletDemo06
1. 请求行部分
String getMethod() // 获取请求方式
String getContextPath() // 获取项目访问路径 /mayikt-tomcat04
StringBuffer getRequestURL() // 获取 URL 统一资源定位符 http://localhost:8080/mayikt-tomcat04/servletDemo06
String getRequestURI() // 获取 URI 统一资源标识符 /mayikt-tomcat04/servletDemo06
String getQueryString() // 获取请求参数(Get 方式) username=mayikt&password=123
2.请求头部分
String getHeader(String name) // 根据请求头名称, 获取值
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36
3.请求体部分 (Post 才有)
通过 流读取 来获取 Post请求的参数 userName=mayikt&password=123
ServletInputStream getInputStream() // 字节输入流
BufferedReader getReader() // 字符输入流 readLine();
request获取请求参数
Request对象里封装好了一个 Map集合,Map集合里放的就是所有的参数
Map<String,String[]> getParameterMap() // 返回这个 Map 集合
String[] getParameterValues(String name) // 根据 键名 获取值
String getParameter(String name) // 根据 键名 获取值
?age=18&age=22
Map<String, String[]> map = req.getParameterMap();
for(String key : map.keySet()){
System.out.print(key + ":");
String[] values = map.get(key);
for(String value : values){
System.out.print(value + " ");
}
System.out.println();
}
package com.mayikt.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashMap;
/**
* @author 余胜军
* @ClassName HttpServletDemo06
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/httpServletDemo06")
public class HttpServletDemo06 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 {
// 判断请求是get还是post请求
String method = req.getMethod();
String parameters = null;
switch (method) {
case "GET":
parameters = req.getQueryString();
break;
case "POST":
BufferedReader reader = req.getReader();
parameters = reader.readLine();
reader.close();
break;
}
HashMap<String, String> parametersMap = new HashMap<>();
String[] sp1 = parameters.split("&");
for (int i = 0; i < sp1.length; i++) {
String[] sp2 = sp1[i].split("=");
String key = sp2[0];
String value = sp2[1];
parametersMap.put(key, value);
}
System.out.println(parametersMap);
}
}
1
request请求转发
请求转发:一种在服务器内部的资源跳转方式
1.通过request对象获取请求转发器对象 :
RequestDispatcher getRequestDispatcher(String path)
2.使用RequestDispatcher对象来进行转发:
forward(ServletRequest request, ServletResponse response)
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/requestDemo6");
requestDispatcher.forward(request,response);
浏览器地址栏路径不发生变化;
只能转发到当前服务器内部资源中;
转发是一次请求;
1、request.setAttribute("name",value); 数据共享
有效范围是一个请求范围,不发送请求的界面无法获取到value的值,jsp界面获取使用EL表达式${num};
只能在一个request内有效,如果重定向客户端,将取不到值。
request在当次的请求的URL之间有效,比如,你在请求某个servlet,那么你提交的信息,可以使用request.getAttribute()方式获得,而当你再次跳转之后,这些信息将不存在。
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author 余胜军
* @ClassName HttpServletDemo09
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/httpServletDemo09")
public class HttpServletDemo09 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("name", "mayikt");
req.getRequestDispatcher("/httpServletDemo10").forward(req, resp);
}
}
package com.mayikt.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author 余胜军
* @ClassName HttpServletDemo10
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/httpServletDemo10")
public class HttpServletDemo10 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = (String) req.getAttribute("name");
System.out.println(name);
System.out.println("httpServletDemo10");
}
}
response响应数据
response是Servlet.service方法的一个参数,类型为javax.servlet.http.HttpServletResponse。在客户端发出每个请求时,服务器都会创建一个response对象,并传入给Servlet.service()方法。response对象是用来对客户端进行响应的,这说明在service()方法中使用response对象可以完成对客户端的响应工作。
//设置服务端的编码
resp.setCharacterEncoding("UTF-8");
//通过设置响应头设置客户端(浏览器的编码)
resp.setHeader("Content-type","text/html;utf-8");
//这个方法可以同时设置客户端和服务端,因为它会调用setCharacterEncoding方法
resp.setContentType("text/html;charset=utf-8");
resp.setContentType("text/html;charset=utf-8");
响应格式分为3个部分
1.响应行:响应数据第一行 http协议版本1.1版本
200表示响应状态码 ok为 成功状态
2.响应头:第二行开始 格式 key value
3.响应体
response是响应对象,向客户端输出响应正文(响应体)可以使用response的响应流,repsonse一共提供了两个响应流对象:
PrintWriter out = response.getWriter():获取字符流;
ServletOutputStream out = response.getOutputStream():获取字节流;
如果响应正文内容为字符,那么使用response.getWriter(),如果响应内容是字节,例如下载时,那么可以使用response.getOutputStream()。
//设置错误的响应码
resp.setError(404,"未找到请求的资源!");
//设置正确的响应码
resp.setStatus(200);
HttpServletResponse
ServletResponse
ServletResponse------ 接口 java提供的响应对象根接口
HttpServletResponse ------ 接口(继承ServletResponse) java提供的对http协议封装响应对象接口
org.apache.catalina.connnector.ResponseFacade —— 类(Tomcat编写的,实现HttpServletResponse )
response重定向
重定向原理
当我们的客户端发送请求达到服务器端,我们的服务器端响应状态码302 ,同时在响应头中
设置重定向地址(resp.setHeader("Location","www.mayikt.com");) ;
客户端(浏览器)收到结果之后,在浏览器解析Location www.mayikt.com 在直接重定向到
www.mayikt.com
两次请求。
地址栏有发生变化的。
首先客户浏览器发送http请求,当web服务器接受后发送302状态码响应及对应新的location给客 户浏览器,客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location 地址,服务器根据此请求寻找资源并发送给客户。
void sendRedirect(String location) 使用指定的重定向位置URL,向客户端发送临时重定向响应
resp.setStatus(302);
resp.setHeader("Location","www.mayikt.com");
1.重定向之后,浏览器地址栏的URL会发生改变
2.重定向过程中会将前面Request对象销毁,然后创建一个新的Request对象
3.重定向的URL可以是其它项目工程
重定向与转发区别
1.转发只能将请求转发给同一个web应用(项目工程)中的其他组件(servlet程序);重定向可以重定向到任意的地址,网络地址或是文件地址(跨项目文件夹 www.mayikt.com)
2.重定向访问结束后,浏览器地址栏URL发生变化,变成了重定向后的URL;转发则不变
重定向对浏览器的请求直接做出响应,结果就是告诉浏览器去重新发出另一个新的URL访问请求;请求转发在服务器端内部将请求转发给另一个资源,浏览器不知道服务器程序内部发生了转发过程
3.请求转发调用者与被调用者之间共享相同的请求对象,属于同一个请求和响应过程;重定向则是不同的请求和响应过程
jdbc+servlet登录和注册
初始化数据库表结构
CREATE TABLE `mayikt_users` (
`id` int NOT NULL AUTO_INCREMENT,
`userName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`userPwd` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
jdbc+servlet用户注册
1.添加jar包
commons-lang3-3.4----常用工具包
mysql-connector-java-8.0.13.jar ----mysql驱动包
servlet-api.jar ----servlet-api.jar
该jar上传 该位置--- 点击下载jar包
文档:javaweb开发相关资料下载.note
链接:有道云笔记
2.mayikt jdbc工具类
package com.mayikt.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* @author 余胜军
* @ClassName MayiktJdbcUtils
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class MayiktJdbcUtils {
/**
* 1.需要将我们的构造方法私有化 ---工具类 不需要 new出来 是通过类名称.方法名称访问
*/
private MayiktJdbcUtils() {
}
/**
* 2.定义工具类 需要 声明 变量
*/
private static String driverClass;
private static String url;
private static String user;
private static String password;
/**
*3.使用静态代码快 来给我们声明好 jdbc变量赋值(读取config.properties)
*/
static {
try {
// 1.读取config.properties IO 路径 相对路径
InputStream resourceAsStream = MayiktJdbcUtils.class.getClassLoader().
getResourceAsStream("config.properties");
// 2.赋值给我们声明好的变量
Properties properties = new Properties();
properties.load(resourceAsStream);
driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
// 3.注册驱动类
Class.forName(driverClass);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 4.封装连接方法
*/
public static Connection getConnection() throws SQLException {
Connection connection = DriverManager.getConnection(url, user, password);
return connection;
}
/**
* 5.封装释放连接方法 (重载)
*/
public static void closeConnection(ResultSet resultSet, Statement statement, Connection connection) {
// 1.查询 释放连接 resultSet statement connection
try {
if (resultSet != null)
resultSet.close();
if (statement != null)
statement.close();
if (connection != null)
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 增删改---释放jdbc资源
*
* @param statement
* @param connection
*/
public static void closeConnection(Statement statement, Connection connection) {
// 1.查询 释放连接 resultSet statement connection
closeConnection(null, statement, connection);
}
/**
* 开启事务
*
* @param connection
* @throws SQLException
*/
public static void beginTransaction(Connection connection) throws SQLException {
connection.setAutoCommit(false);
}
/**
* 提交事务
*
* @param connection
* @throws SQLException
*/
public static void commitTransaction(Connection connection) throws SQLException {
connection.commit();
}
/**
* 回滚事务
*
* @param connection
*/
public static void rollBackTransaction(Connection connection) {
if (connection != null) {
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭事务
*
* @param connection
*/
public static void endTransaction(Connection connection) {
if (connection != null) {
try {
connection.setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
拷贝 config.properties
driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mayikt?serverTimezone=UTC
user=root
password=root
3.编写注册 servlet
package com.mayikt.servlet;
import com.mayikt.utils.MayiktJdbcUtils;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
* @author 余胜军
* @ClassName RegisterServlet
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
resp.setContentType("text/html;charset=utf-8");
//1.获取参数
String userName = req.getParameter("userName");
if (StringUtils.isEmpty(userName)) {
writer.print("userName不能为空!");
return;
}
String userPwd = req.getParameter("userPwd");
if (StringUtils.isEmpty(userPwd)) {
writer.print("userPwd不能为空!");
return;
}
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = MayiktJdbcUtils.getConnection();
//2.验证用户名称和密码
MayiktJdbcUtils.beginTransaction(connection);// 开启事务
String insertSql = "INSERT INTO `mayikt`.`mayikt_users` (`id`, `userName`, `userPwd`) VALUES (null, ?,?); ";
preparedStatement = connection.prepareStatement(insertSql);
preparedStatement.setString(1, userName);
preparedStatement.setString(2, userPwd);
int insertResult = preparedStatement.executeUpdate();
MayiktJdbcUtils.commitTransaction(connection);
String result = insertResult > 0 ? "注册成功" : "注册失败";
writer.println(result);
} catch (Exception e) {
e.printStackTrace();
writer.println("error");
// 回滚事务
if (connection != null)
MayiktJdbcUtils.rollBackTransaction(connection);
} finally {
if (writer != null) {
writer.close();
}
MayiktJdbcUtils.closeConnection(null, preparedStatement, connection);
}
}
}
4.编写注册html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>蚂蚁课堂-用户注册</title>
</head>
<body>
<h1>用户注册</h1>
<form action="/mayikt_web_login_war_exploded/register" method="post">
<!--name=mayikt&age=12 -->
<span>用户名称:</span> <input type="text" name="userName"> <br>
<span>密 码:</span> <input type="text" name="userPwd" value=""><br>
<input type="submit">
</form>
</body>
</html>
jdbc+servlet用户登录
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>蚂蚁课堂-用户登录</title>
</head>
<body>
<h1>用户登录</h1>
<form action="/mayikt_web_login_war_exploded/login" method="post">
<!--name=mayikt&age=12 -->
<span>名称:</span> <input type="text" name="userName"> <br>
<span>密 码:</span> <input type="text" name="userPwd" value=""><br>
<input type="submit">
</form>
</body>
</html>
package com.mayikt.servlet;
import com.mayikt.utils.MayiktJdbcUtils;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
/**
* @author 余胜军
* @ClassName LoginServlet
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取参数
String userName = req.getParameter("userName");
String userPwd = req.getParameter("userPwd");
PrintWriter writer = resp.getWriter();
resp.setContentType("text/html;charset=utf-8");
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//2.验证用户名称和密码
connection = MayiktJdbcUtils.getConnection();
String loginSql = "SELECT * FROM mayikt_users where userName=? and userPwd=? ";
preparedStatement = connection.prepareStatement(loginSql);
preparedStatement.setString(1, userName);
preparedStatement.setString(2, userPwd);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
String dbUserName = resultSet.getString(1);
writer.println("恭喜" + userName + "登录成功");
} else {
writer.println("登录失败");
}
} catch (Exception e) {
e.printStackTrace();
writer.println("error");
// 回滚事务
if (connection != null)
MayiktJdbcUtils.rollBackTransaction(connection);
} finally {
if (writer != null) {
writer.close();
}
MayiktJdbcUtils.closeConnection(null, preparedStatement, connection);
}
}
}
常见问题
我们在使用tomcat 运行 web项目时 启动项目报错
java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver
原因1:没有引入 mysql驱动jar包
原因2:tomcat 在运行过程中 会在lib目录中查找jar包 发现没有 就会报该错误。
但是我们在编译阶段是在项目中lib 查找jar包,编译阶段没有报错。
将该 jar包拷贝到 tomcat -lib 目录中即可
jsp(淘汰)
1.jsp的概述
2.jsp脚本
3.jsp优缺点
4.el表达式
5.jstl、if forreach
6.jsp+servlet开发航班系统
7.jsp+servlet开发航班系统-查询所有
8.jsp+servlet开发航班系统-修改数据
9.jsp+servlet开发航班系统-删除数据
10.jsp+servlet开发航班系统 逻辑删除数据
jsp的概述
1.什么是JSP=Java Server Pages java服务器端页面
2.程序员在开发过程中,发现Servlet做界面非常不方便,所以产生了jsp技术,JSP其实是对Servlet进行了包装而已。
3.为什么会出现JSP(Java Server Pages)技术?
jsp + java类(service、javabean)+ servlet,就会构成mvc的开发模式,mvc模式是目前软件公司中相当通用的开发模式。
jsp底层是基于Servlet封装。
mvc架构模式
jsp 可以编写java代码
jsp转化成 servlet
index.jsp----底层变成 index.java(servlet)-----class index.class
jsp的原理
1.jsp运行在服务器
2.jsp的基础是Servlet(相当于对Servlet进行了一个包装而已)
3.jsp就是根据: html + java片段 + JSP标签(语法) + javascript(css)
jsp的特点
1.JSP的全称是Java Server Pages,它和Servlet技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。
2.jsp这门技术的最大的特点在于,写jsp就像在写HTML,但:它相对于html而言,html只能为用户提供静态数据,而jsp技术允许在页面中嵌套java代码,为用户提供动态数据。
3.相比Servlet而言,Servlet很难对数据进行排版,而jsp除了可以用java代码产生动态数据的同时,也很容易对数据进行排版。
ersionLoggerListener.log CATALINA_BASE: C:\Users\mayikt\AppData\Local\JetBrains\IntelliJIdea2020.2\tomcat\Unnamed_mayikt-web-jsp
jsp的入门
<%@ page import="java.util.Date" %><%--
Created by IntelliJ IDEA.
User: mayikt
Date: 2022/5/17
Time: 10:07
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户信息页面</title>
</head>
<body>
<h1>用户名称:{}</h1>
<a href="https://jiadian.jd.com/">家用电器</a>
<a href="https://shouji.jd.com/">手机数码</a>
<a href="https://channel.jd.com/furniture.html">家居家电</a>
<%
System.out.println("mayikt 666");
%>
</body>
</html>
package com.mayikt;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author 余胜军
* @ClassName LoginServlet
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
resp.setContentType("text/html;charset=utf-8");
writer.println("<html>");
writer.println("<html>");
writer.println("<body>");
String userName = req.getParameter("userName");
writer.println("<h1>用户名称:{" + userName + "}</h1>");
writer.println("<a href=\"https://jiadian.jd.com/\">家用电器</a>");
writer.println("<a href=\"https://shouji.jd.com/\">手机数码</a>");
writer.println("<a href=\"https://channel.jd.com/furniture.html\">家居家电</a>");
writer.println("</body>");
System.out.println("6666");
writer.close();
}
}
jsp的脚本
jsp底层 基于servlet实现
在jsp中定义java代码
1.<% ... %>∶内容会直接放到_jspService()方法之中
2.<%=..%>∶内容会放到out.print()中,作为out.print()的参数
3.<%!...%>:内容会放到_jspService()方法之外,被类直接包含
<%--
Created by IntelliJ IDEA.
User: mayikt
Date: 2022/5/17
Time: 11:54
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>电商项目</title>
</head>
<body>
<h1>用户名称:{}</h1>
<a href="https://jiadian.jd.com/">家用电器</a>
<a href="https://shouji.jd.com/">手机数码</a>
<a href="https://channel.jd.com/furniture.html">家居家电</a>
<%
System.out.println("我是定义在jspservice方法之中....");
int j = 20;
mayikt();
%>
<%="直接输出 string类型 " + j %>
<%!
void mayikt() {
System.out.println("我是mayikt 我是定义在jspservice方法之外");
}
String userName = "mayikt";
%>
</body>
</html>
el表达式
Expression Language表达式语言,用于简化JSP页面内的Java代码
主要功能:获取数据
语法:${expression}
例:${users}获取域中存储的key为users的数据
1. page:当前页面有效
2. request:当前请求有效
3. session:当前会话有效
4. application:当前应用有效
jstl标签
apache对EL表达式的扩展(也就是说JSTL依赖EL),JSTL是标签语言!JSTL标签使用以来非常方便,它与JSP动作标签一样,只不过它不是JSP内置的标签,需要我们自己导包,以及指定标签库而已
f标签的test属性必须是一个boolean类型的值,如果test的值为true,那么执行if标签的内容,否则不执行。
<c:if test="${age>18}">
<h1>年龄大于18岁</h1>
</c:if>
<c:if test="${age<18}">
<h1>年龄小于18岁</h1>
</c:if>
<% if(age)>18 out.print("<h1>年龄大于18岁</h1>") %>
用于在JSP中显示数据,就像<%= ... > | |
用于保存数据 | |
用于删除数据 | |
用来处理产生错误的异常状况,并且将错误信息储存起来 | |
与我们在一般程序中用的if一样 | |
本身只当做<c:when>和<c:otherwise>的父标签 | |
<c:choose>的子标签,用来判断条件是否成立 | |
<c:choose>的子标签,接在<c:when>标签后,当<c:when>标签判断为false时被执行 | |
检索一个绝对或相对 URL,然后将其内容暴露给页面 | |
基础迭代标签,接受多种集合类型 | |
根据指定的分隔符来分隔内容并迭代输出 | |
用来给包含或重定向的页面传递参数 | |
重定向至一个新的URL. | |
使用可选的查询参数来创造一个URL |
我们在jsp学习过中 重点谈到2个标签
<c:if>、<c:forEach>
环境步骤:
1.导入JSTL的core标签库
2.<%@ taglib prefix="c"uri="http://java.sun.com/jstl/core" %>
prefix="c":指定标签库的前缀,这个前缀可以随便给值,但大家都会在使用core标签库时指定前缀为c;
uri="http://java.sun.com/jstl/core":指定标签库的uri,它不一定是真实存在的网址,但它可以让JSP找到标签库的描述文件;
模板html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="1" align="center" style="border-collapse: collapse;width: 30%">
<tr align="center">
<th align="center">序号</th>
<th align="center">名称</th>
<th align="center">年龄</th>
<th align="center">冻结</th>
<th align="center">操作</th>
</tr>
<tr align="center">
<td align="center">0</td>
<td align="center">mayikt</td>
<td align="center">22</td>
<td align="center">未冻结</td>
<td align="center"><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<tr align="center">
<td align="center">0</td>
<td align="center">lisi</td>
<td align="center">11</td>
<td align="center">未冻结</td>
<td align="center"><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<tr align="center">
<td align="center">0</td>
<td align="center">xiaojun</td>
<td align="center">33</td>
<td align="center">冻结</td>
<td align="center"><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<tr align="center">
<td align="center">0</td>
<td align="center">mayikt</td>
<td align="center">22</td>
<td align="center">未冻结</td>
<td align="center"><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
</table>
</body>
</html>
package com.mayikt.servlet;
import com.mayikt.entity.UserEntity;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.jsp.jstl.fmt.LocalizationContext;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author 余胜军
* @ClassName UserListServlet2
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/userListServlet2")
public class UserListServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ArrayList<UserEntity> userEntities = new ArrayList<>();
userEntities.add(new UserEntity("mayikt", 22, 0));
userEntities.add(new UserEntity("meite", 32, 1));
userEntities.add(new UserEntity("xiaowei", 31, 0));
req.setAttribute("userEntities", userEntities);
req.getRequestDispatcher("userList.jsp").forward(req, resp);
}
}
package com.mayikt.entity;
/**
* @author 余胜军
* @ClassName UserEntity
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class UserEntity {
private String userName;
private Integer age;
private Integer state;
public UserEntity(String userName, Integer age, Integer state) {
this.userName = userName;
this.age = age;
this.state = state;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
}
导入jar包
文档:javaweb开发相关资料下载.note
链接:有道云笔记
jsp 中定义c标签
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
MVC架构模式
jsp+servlet+jdbc开发航班系统
需求分析数据准备
需求分析
数据准备
CREATE TABLE `mayikt_flight` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'id列',
`flight_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '航号',
`company` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '航空公司',
`departure_airport` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '出发机场',
`arrive_airport` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '达到机场',
`departure_time` datetime DEFAULT NULL COMMENT '出发时间',
`arrive_time` datetime DEFAULT NULL COMMENT '到达时间',
`model` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '机型',
`is_delete` int DEFAULT NULL COMMENT '是否隐藏0显示 1隐藏',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3;
测试数据
INSERT INTO `flight`.`mayikt_flight` (`id`, `flight_id`, `company`, `departure_airport`, `arrive_airport`, `departure_time`, `arrive_time`, `model`, `is_delete`) VALUES ('1', 'MYKT001', '中国东方航空公司', '武汉天河机场', '北京首都机场', '2022-05-20 03:08:24', '2022-05-21 03:08:31', '735', '0');
静态模板页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="1" align="center" style="border-collapse: collapse;width: 80%">
<tr align="center">
<th align="center">航号</th>
<th align="center">航空公司</th>
<th align="center">出发机场</th>
<th align="center">达到机场</th>
<th align="center">出发时间</th>
<th align="center">到达时间</th>
<th align="center">机型</th>
<th align="center">操作</th>
</tr>
<tr align="center">
<td align="center">MYKT001</td>
<td align="center">中国东方航空</td>
<td align="center">武汉天河机场</td>
<td align="center">北京首都机场</td>
<td align="center">2022年5月25日 12:00</td>
<td align="center">2022年5月25日 14:00</td>
<td align="center">735</td>
<td align="center"><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
</table>
</body>
</html>
需要的相关依赖jar包
文档:javaweb开发相关资料下载.note
链接:有道云笔记
jdbc配置文件
config.properties
driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/flight?serverTimezone=UTC
user=root
password=root
工具类
package com.mayikt.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* @author 余胜军
* @ClassName MayiktJdbcUtils
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class MayiktJdbcUtils {
/**
* 1.需要将我们的构造方法私有化 ---工具类 不需要 new出来 是通过类名称.方法名称访问
*/
private MayiktJdbcUtils() {
}
/**
* 2.定义工具类 需要 声明 变量
*/
private static String driverClass;
private static String url;
private static String user;
private static String password;
/**
*3.使用静态代码快 来给我们声明好 jdbc变量赋值(读取config.properties)
*/
static {
try {
// 1.读取config.properties IO 路径 相对路径
InputStream resourceAsStream = MayiktJdbcUtils.class.getClassLoader().
getResourceAsStream("config.properties");
// 2.赋值给我们声明好的变量
Properties properties = new Properties();
properties.load(resourceAsStream);
driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
// 3.注册驱动类
Class.forName(driverClass);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 4.封装连接方法
*/
public static Connection getConnection() throws SQLException {
Connection connection = DriverManager.getConnection(url, user, password);
return connection;
}
/**
* 5.封装释放连接方法 (重载)
*/
public static void closeConnection(ResultSet resultSet, Statement statement, Connection connection) {
// 1.查询 释放连接 resultSet statement connection
try {
if (resultSet != null)
resultSet.close();
if (statement != null)
statement.close();
if (connection != null)
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 增删改---释放jdbc资源
*
* @param statement
* @param connection
*/
public static void closeConnection(Statement statement, Connection connection) {
// 1.查询 释放连接 resultSet statement connection
closeConnection(null, statement, connection);
}
/**
* 开启事务
*
* @param connection
* @throws SQLException
*/
public static void beginTransaction(Connection connection) throws SQLException {
connection.setAutoCommit(false);
}
/**
* 提交事务
*
* @param connection
* @throws SQLException
*/
public static void commitTransaction(Connection connection) throws SQLException {
connection.commit();
}
/**
* 回滚事务
*
* @param connection
*/
public static void rollBackTransaction(Connection connection) {
if (connection != null) {
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭事务
*
* @param connection
*/
public static void endTransaction(Connection connection) {
if (connection != null) {
try {
connection.setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
MVC架构模式
MVC是一个架构模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型、视图、控制器。他们各自处理自己的任务。
1.视图
视图是用户看到并与之交互的界面 jsp
2.模型
模型表示企业数据(数据模型:dao)和业务规划及操作(业务模型:service)
3.控制器
控制器表示用户的输入并调用模型和视图去完成用户的需求。
常见的MVC组件:Struts,Spring MVC,JSF
MVC架构模式
视图层
控制层
业务逻辑层
数据库访问层
查询所有航班信息
实体类
package com.mayikt.entity;
import java.util.Date;
/**
* @author 余胜军
* @ClassName FlightEntity
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class FlightEntity {
/**
* CREATE TABLE `mayikt_flight` (
* `id` int NOT NULL AUTO_INCREMENT COMMENT 'id列',
* `flight_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '航号',
* `company` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '航空公司',
* `departure_airport` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '出发机场',
* `arrive_airport` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '达到机场',
* `departure_time` datetime DEFAULT NULL COMMENT '出发时间',
* `arrive_time` datetime DEFAULT NULL COMMENT '到达时间',
* `model` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '机型',
* `is_delete` int DEFAULT NULL COMMENT '是否隐藏0显示 1隐藏',
* PRIMARY KEY (`id`)
* ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3;
*/
private Integer id;
private String flightId;
private String company;
private String departureAirport;
private String arriveAirport;
private Date departureTime;
private Date arriveTime;
private String model;
private Integer isDelete;
public FlightEntity(Integer id, String flightId, String company, String departureAirport, String arriveAirport, Date departureTime, Date arriveTime, String model, Integer isDelete) {
this.id = id;
this.flightId = flightId;
this.company = company;
this.departureAirport = departureAirport;
this.arriveAirport = arriveAirport;
this.departureTime = departureTime;
this.arriveTime = arriveTime;
this.model = model;
this.isDelete = isDelete;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFlightId() {
return flightId;
}
public void setFlightId(String flightId) {
this.flightId = flightId;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getDepartureAirport() {
return departureAirport;
}
public void setDepartureAirport(String departureAirport) {
this.departureAirport = departureAirport;
}
public String getArriveAirport() {
return arriveAirport;
}
public void setArriveAirport(String arriveAirport) {
this.arriveAirport = arriveAirport;
}
public Date getDepartureTime() {
return departureTime;
}
public void setDepartureTime(Date departureTime) {
this.departureTime = departureTime;
}
public Date getArriveTime() {
return arriveTime;
}
public void setArriveTime(Date arriveTime) {
this.arriveTime = arriveTime;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public Integer getIsDelete() {
return isDelete;
}
public void setIsDelete(Integer isDelete) {
this.isDelete = isDelete;
}
}
数据库访问层
package com.mayikt.dao;
import com.mayikt.entity.FlightEntity;
import com.mayikt.utils.MayiktJdbcUtils;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
/**
* @author 余胜军
* @ClassName FlightDao
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class FlightDao {
/**
* 查询所有的航班信息
*
* @return
*/
public List<FlightEntity> getByAll() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 1.获取连接
connection = MayiktJdbcUtils.getConnection();
//2.获取执行者对象
preparedStatement = connection.prepareStatement("select * from mayikt_flight");
resultSet = preparedStatement.executeQuery();
ArrayList<FlightEntity> flightEntities = new ArrayList<>();
while (resultSet.next()) {
Integer id = resultSet.getInt("id");
String flightId = resultSet.getString("flight_id");
String company = resultSet.getString("company");
String departureAirport = resultSet.getString("departure_airport");
String arriveAirport = resultSet.getString("arrive_airport");
Date departureTime = resultSet.getDate("departure_time");
Date arriveTime = resultSet.getDate("arrive_time");
String model = resultSet.getString("model");
Integer isDelete = resultSet.getInt("is_delete");
FlightEntity flightEntity = new FlightEntity(id, flightId, company, departureAirport, arriveAirport, departureTime, arriveTime, model,
isDelete);
// 存入到集合中
flightEntities.add(flightEntity);
}
return flightEntities;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
// 释放资源
MayiktJdbcUtils.closeConnection(resultSet, preparedStatement, connection);
}
}
}
业务逻辑层
package com.mayikt.service;
import com.mayikt.dao.FlightDao;
import com.mayikt.entity.FlightEntity;
import java.util.List;
/**
* @author 余胜军
* @ClassName FlightService
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
public class FlightService {
// 业务逻辑调用数据库访问层获取数据
private FlightDao flightDao = new FlightDao();
/**
* 查询所有的航班信息
*
* @return
*/
public List<FlightEntity> getByAll() {
return flightDao.getByAll();
}
}
控制层
package com.mayikt.servlet;
import com.mayikt.entity.FlightEntity;
import com.mayikt.service.FlightService;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* @author 余胜军
* @ClassName FlightServlet
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/show")
public class FlightServlet extends HttpServlet {
private FlightService flightService = new FlightService();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 控制层调用业务逻辑层获取数据
List<FlightEntity> flightEntitys = flightService.getByAll();
// 转发到jsp中
req.setAttribute("flights", flightEntitys);
req.getRequestDispatcher("show.jsp").forward(req, resp);
}
}
视图层
<%--
Created by IntelliJ IDEA.
User: mayikt
Date: 2022/5/20
Time: 18:26
To change this template use File | Settings | File Templates.
--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>航班系统</title>
</head>
<body>
<table border="1" align="center" style="border-collapse: collapse;width: 80%">
<tr align="center">
<th align="center">航号</th>
<th align="center">航空公司</th>
<th align="center">出发机场</th>
<th align="center">达到机场</th>
<th align="center">出发时间</th>
<th align="center">到达时间</th>
<th align="center">机型</th>
<th align="center">操作</th>
</tr>
<c:forEach items="${flights}" var="f">
<tr align="center">
<td align="center">${f.flightId}</td>
<td align="center">${f.company}</td>
<td align="center">${f.departureAirport}</td>
<td align="center">${f.arriveAirport}</td>
<td align="center">${f.departureTime}</td>
<td align="center">${f.arriveTime}</td>
<td align="center">${f.model}</td>
<td align="center"><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
</c:forEach>
</table>
</body>
</html>
修改航班信息
数据回显
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div >
<h1>修改数据</h1>
<form>
<label>航 号: <input type="text"></label><br>
<label>航空公司: <input type="text"></label><br>
<label>出发机场: <input type="text"></label><br>
<label>达到机场: <input type="text"></label><br>
<label>出发时间: <input type="text"></label><br>
<label>到达时间: <input type="text"></label><br>
<label>机 型: <input type="text"></label><br>
<input type="submit" value="提交">
</form>
</div>
</body>
</html>
dao层
/**
* 根据id查询航班信息
*
* @return
*/
public FlightEntity getByIdFlight(Integer id) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 1.获取连接
connection = MayiktJdbcUtils.getConnection();
//2.获取执行者对象
preparedStatement = connection.prepareStatement("select * from mayikt_flight where id=?");
preparedStatement.setInt(1, id);
resultSet = preparedStatement.executeQuery();
if (!resultSet.next()) {
return null;
}
// 连接到db查询数据
Integer dbId = resultSet.getInt("id");
String flightId = resultSet.getString("flight_id");
String company = resultSet.getString("company");
String departureAirport = resultSet.getString("departure_airport");
String arriveAirport = resultSet.getString("arrive_airport");
Date departureTime = resultSet.getDate("departure_time");
Date arriveTime = resultSet.getDate("arrive_time");
String model = resultSet.getString("model");
Integer isDelete = resultSet.getInt("is_delete");
FlightEntity flightEntity = new FlightEntity(dbId, flightId, company, departureAirport, arriveAirport, departureTime, arriveTime, model,
isDelete);
return flightEntity;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
// 释放资源
MayiktJdbcUtils.closeConnection(resultSet, preparedStatement, connection);
}
}
业务逻辑层
public FlightEntity getByIdFlight(Integer id) {
return flightDao.getByIdFlight(id);
}
package com.mayikt.servlet;
import com.mayikt.entity.FlightEntity;
import com.mayikt.service.FlightService;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author 余胜军
* @ClassName UpdateFlightServlet
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/updateFlight")
public class UpdateFlightServlet extends HttpServlet {
private FlightService flightService = new FlightService();
/**
* doGet 用户点击修改该条数据-------需要查询到该条数据(回显)
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取需要修改的id值
String idStr = req.getParameter("id");
if (idStr == null || idStr == "") {
// 跳转到错误页面 客户端传递参数有问题
/// 转发到错误jsp中
req.setAttribute("errorMsg", "id的值是为空!");
req.getRequestDispatcher("error.jsp").forward(req, resp);
return;
}
try {
// mayikt1
Integer id = Integer.parseInt(idStr);
FlightEntity flightEntity = flightService.getByIdFlight(id);
if (flightEntity == null) {
/// 转发到错误jsp中
req.setAttribute("errorMsg", "该id在db中无法查询到数据");
req.getRequestDispatcher("error.jsp").forward(req, resp);
return;
}
//转发到修改航班信息页面
req.setAttribute("flight", flightEntity);
req.getRequestDispatcher("updateFlight.jsp").forward(req, resp);
} catch (Exception e) {
req.setAttribute("errorMsg", "系统错误!");
req.getRequestDispatcher("error.jsp").forward(req, resp);
}
}
/**
* 接受用户需要修改的数据
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
视图层
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>修改航班信息</title>
</head>
<body>
<div>
<h1>修改数据</h1>
<form>
<label>航 号: <input type="text" value="${flight.flightId}"></label><br>
<label>航空公司: <input type="text" value="${flight.company}"></label><br>
<label>出发机场: <input type="text" value="${flight.departureAirport}"></label><br>
<label>达到机场: <input type="text" value="${flight.arriveAirport}"></label><br>
<label>出发时间: <input type="text" value="${flight.departureTime}"></label><br>
<label>到达时间: <input type="text" value="${flight.arriveTime}"></label><br>
<label>机 型: <input type="text" value="${flight.model}"></label><br>
<input type="submit" value="提交">
</form>
</div>
</body>
</html>
修改数据
工具类
package com.mayikt.utils;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
public class DateUtils {
/**
* 预定的日期格式
*/
public static final String[] DATEFORMAT = {"yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss", "yyyy年MM月dd日HH时mm分ss秒", "yyyy-MM-dd", "yyyy/MM/dd", "yy-MM-dd", "yy/MM/dd", "yyyy年MM月dd日", "HH:mm:ss",
"yyyyMMddHHmmss", "yyyyMMdd", "yyyy.MM.dd", "yy.MM.dd", "yyyyMMddHHmmssSSS", "yyyy-MM-dd HH:mm:ss:SSS", "yyyy-MM-dd HH:mm:ss.SSS", "yyyy", "yyyyMM", "yyyyMMdd HH", "yyyyMMdd HH:mm",
"yyyyMMdd HH:mm:ss", "yyyy-MM" };
/**
* 线程绑定的日期格式转换器缓存
*/
private static final ThreadLocal<Map<String, SimpleDateFormat>> DATEFORMATERSCACHE = new ThreadLocal<Map<String, SimpleDateFormat>>();
/**
* 获取当前系统时间
*/
public static Calendar getSystemCurrentTime() {
final Calendar currentTime = Calendar.getInstance();
return currentTime;
}
/**
* 获取当前系统时间
*/
public static String getSystemCurrentTime(int format) {
return toDateStrByFormatIndex(getSystemCurrentTime(), format);
}
/**
* 获取系统当前date类型时间
*/
public static Date getCurrentDate() {
return new Date();
}
/**
* 获取系统当前日期和时间,格式为yyyy-MM-dd HH:mm:ss
*/
public static String getCurrentDateTime() {
return getFormatCurrentDate("yyyy-MM-dd HH:mm:ss");
}
/**
* 返回格式化的当前日期/时间
*/
public static String getFormatCurrentDate(String strFormat) {
return msFormatDateTime(getCurrentDate(), strFormat);
}
/**
* 日期/时间格式化显示(年、月、日、时、分、秒、毫秒、星期)
*/
public static String msFormatDateTime(Date dtmDate, String strFormat) {
if (strFormat.equals("")) {
strFormat = "yyyy-MM-dd HH:mm:ss";
}
final SimpleDateFormat myFormat = new SimpleDateFormat(strFormat);
return myFormat.format(dtmDate.getTime());
}
/**
* 日期/时间格式化显示(年、月、日)
*/
public static String msFormatDate(Date dtmDate, String strFormat) {
if (strFormat.equals("")) {
strFormat = "yyyy-MM-dd";
}
final SimpleDateFormat myFormat = new SimpleDateFormat(strFormat);
return myFormat.format(dtmDate.getTime());
}
/**
* 获取当前系统时间
*/
public static String getSystemCurrentTime(String format) {
return toDateStrByFormat(getSystemCurrentTime(), format);
}
// ======================日期转字符串基础格式化方法======================================================================================
/**
* @name 中文名称
*/
private static SimpleDateFormat getDateFormater(String format) {
Map<String, SimpleDateFormat> dateFormaters = DATEFORMATERSCACHE.get();
SimpleDateFormat dateFormater = null;
boolean formatersIsNull = false;
if (dateFormaters == null) {
dateFormaters = new HashMap<String, SimpleDateFormat>(3, 0.2f);
DATEFORMATERSCACHE.set(dateFormaters);
formatersIsNull = true;
}
dateFormater = dateFormaters.get(format);
if (formatersIsNull || dateFormater == null) {
dateFormater = new SimpleDateFormat(format);
dateFormaters.put(format, dateFormater);
}
return dateFormater;
}
private static SimpleDateFormat getDateFormater(int format) {
return getDateFormater(DATEFORMAT[format]);
}
// ======================日期转字符串基础方法======================================================================================
/**
*
* Calendar日期转指定日期格式的字符串
*/
public static String toDateStrByFormat(Calendar date, String format) {
if (date == null) {
return null;
}
return getDateFormater(format).format(date.getTime());
}
/**
*
* Calendar日期转指定日期格式的字符串
*/
public static String toDateStrByFormatIndex(Calendar date, int format) {
return toDateStrByFormat(date, DATEFORMAT[format]);
}
/**
* java.util.Date日期转指定日期格式的字符串
*/
public static String toDateStrByFormat(Date date, String format) {
if (date == null) {
return null;
}
return getDateFormater(format).format(date.getTime());
}
/**
* java.util.Date日期转指定格式的字符串
*/
public static String toDateStrByFormatIndex(Date date, int format) {
return toDateStrByFormat(date, DATEFORMAT[format]);
}
// ======================日期转字符串方法======================================================================================
/**
* Calendar日期转日期字符串
*/
public static String toDateTimeStr(Calendar date) {
return toDateStrByFormatIndex(date, 0);
}
/**
* Calendar日期转指定日期格式的字符串
*/
public static String toDateTimeStr(int format, Calendar date) {
return toDateStrByFormatIndex(date, format);
}
/**
* Calendar日期转日期字符串
*/
public static String toDateStr(Calendar date) {
return toDateStrByFormatIndex(date, 3);
}
/**
* java.util.Date日期转指定格式的日期字符串
*/
public static String dateToString(Date date, int format) {
return toDateStrByFormatIndex(date, format);
}
/**
* java.util.Date日期转日期字符串
*/
public static String dateToString(Date date) {
return toDateStrByFormatIndex(date, 3);
}
// ======================xx转Date方法======================================================================================
/**
* Calendar日期转java.util.Date日期
*/
public static Date convertCalendarToDate(Calendar c) {
final Date d = new Date();
d.setTime(c.getTimeInMillis());
return d;
}
/**
* 日期字符串转java.util.Date日期
*/
public static Date stringToDate(String dateStr) throws Exception {
return parseDate(dateStr, 3);
}
/**
* 日期字符串转指定格式的java.util.Date日期
*/
public static Date parseDate(String dateStr, int format) throws Exception {
if (dateStr == null || dateStr.length() == 0) {
return null;
}
try {
return getDateFormater(format).parse(dateStr);
} catch (ParseException ex) {
return parseDate(dateStr, format + 1);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new Exception("UT-07001:日志字符串" + dateStr + "格式不支持", ex);
}
}
// ======================xx转Calendar方法======================================================================================
/**
* java.util.Date转Calendar
*/
public static Calendar convUtilDateToUtilCalendar(Date date) {
if (date == null) {
return null;
}
final GregorianCalendar gc = new GregorianCalendar();
gc.setTimeInMillis(date.getTime());
return gc;
}
/**
* java.sql.Timestamp转Calendar
*/
public static Calendar convSqlTimestampToUtilCalendar(Timestamp date) {
if (date == null) {
return null;
}
final GregorianCalendar gc = new GregorianCalendar();
gc.setTimeInMillis(date.getTime());
return gc;
}
/**
* 日期字符串转Calendar
*/
public static Calendar parseDate(String dateStr) throws Exception {
final Date result = parseDate(dateStr, 0);
Calendar cal = null;
if (result != null) {
cal = new GregorianCalendar(0, 0, 0, 0, 0, 0);
cal.setTime(result);
}
return cal;
}
// ======================日期转Timestamp方法======================================================================================
/**
* java.util.Date转java.sql.Timestamp
*/
public static Timestamp convUtilDateToSqlTimestamp(Date date) {
if (date == null) {
return null;
}
return new Timestamp(date.getTime());
}
/**
* Calendar日期对象转Timestamp日期对象
*/
public static Timestamp convUtilCalendarToSqlTimestamp(Calendar date) {
if (date == null) {
return null;
}
return new Timestamp(date.getTimeInMillis());
}
/**
* Calendar日期对象转Timestamp日期对象
*/
public static Timestamp parseTimestamp(Calendar calendar) {
return new Timestamp(calendar.getTimeInMillis());
}
/**
* 日期字符串转java.sql.Timestamp
*/
public static Timestamp parseTimestamp(String dateStr) throws Exception {
try {
return new Timestamp(getDateFormater(3).parse(dateStr).getTime());
} catch (ParseException ex) {
throw new Exception("UT-07001:日志字符串" + dateStr + "格式不正确,格式:" + DATEFORMAT[3], ex);
}
}
/**
* 根据指定日期格式,日期字符串转java.sql.Timestamp
*/
public static Timestamp parseTimestamp(String dateStr, int format) throws Exception {
try {
return new Timestamp(getDateFormater(format).parse(dateStr).getTime());
} catch (ParseException ex) {
throw new Exception("UT-07001:日志字符串" + dateStr + "格式不支持", ex);
}
}
// ======================日期计算方法======================================================================================
/**
* 获取两个Calendar日期对象的天数差
*/
public static int calendarMinus(Calendar d1, Calendar d2) {
if (d1 == null || d2 == null) {
return 0;
}
d1.set(11, 0);
d1.set(12, 0);
d1.set(13, 0);
d1.set(14, 0);
d2.set(11, 0);
d2.set(12, 0);
d2.set(13, 0);
d2.set(14, 0);
long t1 = d1.getTimeInMillis();
long t2 = d2.getTimeInMillis();
final long daylong = 86400000L;
t1 -= t1 % daylong;
t2 -= t2 % daylong;
final long t = t1 - t2;
final int value = (int) (t / daylong);
return value;
}
/**
* 获取两个Calendar日期对象的天数差
*/
public static long calendarminus(Calendar d1, Calendar d2) {
if (d1 == null || d2 == null) {
return 0L;
}
return (d1.getTimeInMillis() - d2.getTimeInMillis()) / 86400000L;
}
/**
* 给定任意日期Calendar对象,计算所在月天数
*/
public static int calcMonthDays(Calendar date) {
final Calendar t1 = (Calendar) date.clone();
final Calendar t2 = (Calendar) date.clone();
final int year = date.get(1);
final int month = date.get(2);
t1.set(year, month, 1);
t2.set(year, month + 1, 1);
t2.add(6, -1);
return calendarMinus(t2, t1) + 1;
}
private static int calcDays(long t1, long t2) {
final long millis = t1 - t2;
if (millis == 0) {
return 0;
}
return (int) (millis / (24 * 3600 * 1000));
}
/**
* 获取两个Calendar日期对象的天数差
*/
public static int calcDays(Calendar c1, Calendar c2) {
return calcDays(c1.getTimeInMillis(), c2.getTimeInMillis());
}
/**
* 获取两个java.util.Date日期对象的天数差
*/
public static int calcDays(Date d1, Date d2) {
return calcDays(d1.getTime(), d2.getTime());
}
/**
* 给定任意日期Calendar对象,计算所在月的最后一天
*/
public static Calendar lastDay(Calendar c) {
final Calendar t = (Calendar) c.clone();
t.set(Calendar.DAY_OF_MONTH, 1);
t.add(Calendar.MONTH, 1);
t.add(Calendar.DAY_OF_MONTH, -1);
return t;
}
/**
* 给定任意日期字符串,计算所在月的最后一天
*/
public static Calendar lastDay(String dateStr) throws Exception {
final Calendar t = parseDate(dateStr);
t.set(Calendar.DAY_OF_MONTH, 1);
t.add(Calendar.MONTH, 1);
t.add(Calendar.DAY_OF_MONTH, -1);
return t;
}
/**
* 给定任意日期,计算所在季的季起日期和季终日期
*/
public static Calendar[] calcAQuarter(Calendar day) {
final Calendar[] quarter = new Calendar[2];
int month = 0;
quarter[0] = (Calendar) day.clone();
month = quarter[0].get(Calendar.MONTH);
if (month < 3) {
month = 0;
} else if (month < 6) {
month = 3;
} else if (month < 9) {
month = 6;
} else {
month = 9;
}
quarter[0].set(Calendar.MONTH, month);
quarter[0].set(Calendar.DAY_OF_MONTH, 1);
quarter[1] = (Calendar) quarter[0].clone();
quarter[1].set(Calendar.MONTH, month + 2);
quarter[1] = lastDay(quarter[1]);
return quarter;
}
/**
* 获取年、月、日、时、分、秒、毫秒
*/
public static int[] getYearMonthDayHH24MiMM(Calendar calendar) {
return new int[] {calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE),
calendar.get(Calendar.SECOND), calendar.get(Calendar.MILLISECOND) };
}
/**
* 获取年、月、日、时、分、秒、毫秒
*/
public static int[] getYearMonthDayHH24MiMM(Date date) {
final Calendar calendar = getSystemCurrentTime();
calendar.setTime(date);
return getYearMonthDayHH24MiMM(calendar);
}
/**
* 好微妙转毫秒
*/
public static long nsToMs(long nsTime) {
return nsTime / 1000000;
}
}
增加航班信息
解决后台传输date数据的日期少一天问题 # serverTimezone=GMT%2B8解决传输date数据时间少一天问题
/**
* 添加航班信息
*
* @param flightEntity
* @return
*/
public int insertFlight(FlightEntity flightEntity) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
// 1.获取连接
connection = MayiktJdbcUtils.getConnection();
// 开启事务
MayiktJdbcUtils.beginTransaction(connection);
//2.获取执行者对象
preparedStatement = connection.prepareStatement("INSERT INTO `flight`.`mayikt_flight`" +
" (`id`, `flight_id`, `company`, `departure_airport`, `arrive_airport`, `departure_time`, " +
"`arrive_time`, `model`, `is_delete`) VALUES (null, ?, ?,?, ?," +
" ?, ?, ?, " +
"'0');");
preparedStatement.setString(1, flightEntity.getFlightId());
preparedStatement.setString(2, flightEntity.getCompany());
preparedStatement.setString(3, flightEntity.getDepartureAirport());
preparedStatement.setString(4, flightEntity.getArriveAirport());
//date java.sql.date java.util.date
//new Date(flightEntity.getDepartureTime().getTime()) 将java.util.date 转化成 java.sql.date
preparedStatement.setDate(5, new Date(flightEntity.getDepartureTime().getTime()));
preparedStatement.setDate(6, new Date(flightEntity.getArriveTime().getTime()));
preparedStatement.setString(7, flightEntity.getModel());
int result = preparedStatement.executeUpdate();
// 代码执行没有问题的情况下 则直接提交事务
MayiktJdbcUtils.commitTransaction(connection);
return result;
} catch (Exception e) {
e.printStackTrace();
// 回滚事务
MayiktJdbcUtils.rollBackTransaction(connection);
return 0;
} finally {
// 释放资源
MayiktJdbcUtils.closeConnection(preparedStatement, connection);
}
}
package com.mayikt.servlet;
import com.mayikt.entity.FlightEntity;
import com.mayikt.service.FlightService;
import com.mayikt.utils.DateUtils;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.Date;
/**
* @author 余胜军
* @ClassName InsertFlightServlet
* @qq 644064779
* @addres www.mayikt.com
* 微信:yushengjun644
*/
@WebServlet("/insertFlight")
public class InsertFlightServlet extends HttpServlet {
private FlightService flightService = new FlightService();
/**
* 跳转到 添加 航班数据页面
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getRequestDispatcher("InsertFlight.jsp").forward(req, resp);
}
/**
* 接受 插入航班数据请求
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
String flightId = req.getParameter("flightId");
if (StringUtils.isEmpty(flightId)) {
req.setAttribute("errorMsg", "flightId的值不能够为空!");
req.getRequestDispatcher("error.jsp").forward(req, resp);
return;
}
String company = req.getParameter("company");
if (StringUtils.isEmpty(company)) {
req.setAttribute("errorMsg", "company的值不能够为空!");
req.getRequestDispatcher("error.jsp").forward(req, resp);
return;
}
String departureAirport = req.getParameter("departureAirport");
if (StringUtils.isEmpty(departureAirport)) {
req.setAttribute("errorMsg", "departureAirport的值不能够为空!");
req.getRequestDispatcher("error.jsp").forward(req, resp);
return;
}
String arriveAirport = req.getParameter("arriveAirport");
if (StringUtils.isEmpty(departureAirport)) {
req.setAttribute("errorMsg", "arriveAirport的值不能够为空!");
req.getRequestDispatcher("error.jsp").forward(req, resp);
return;
}
// 将日期string类型转化成date
String departureTimeStr = req.getParameter("departureTime");
if (StringUtils.isEmpty(departureTimeStr)) {
req.setAttribute("errorMsg", "departureTime的值不能够为空!");
req.getRequestDispatcher("error.jsp").forward(req, resp);
return;
}
Date departureTime = DateUtils.stringToDate(departureTimeStr);
String arriveTimeStr = req.getParameter("arriveTime");
if (StringUtils.isEmpty(departureTimeStr)) {
req.setAttribute("errorMsg", "arriveTime的值不能够为空!");
req.getRequestDispatcher("error.jsp").forward(req, resp);
return;
}
Date arriveTime = DateUtils.stringToDate(arriveTimeStr);
String model = req.getParameter("model");
FlightEntity flightEntity = new FlightEntity();
flightEntity.setFlightId(flightId);
flightEntity.setDepartureAirport(departureAirport);
flightEntity.setArriveAirport(arriveAirport);
flightEntity.setDepartureTime(departureTime);
flightEntity.setArriveTime(arriveTime);
flightEntity.setModel(model);
flightEntity.setCompany(company);
int result = flightService.insertFlight(flightEntity);
if (result <= 0) {
// 修改失败的情况下
req.setAttribute("errorMsg", "插入失败!");
req.getRequestDispatcher("error.jsp").forward(req, resp);
return;
}
// 如果插入成功的情况下 则重定向到showFlight 查询航班信息
resp.sendRedirect("showFlight");
} catch (Exception e) {
e.printStackTrace();
// 修改失败的情况下
req.setAttribute("errorMsg", "系统错误!");
req.getRequestDispatcher("error.jsp").forward(req, resp);
}
}
}
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>插入航班信息</title>
</head>
<body>
<div>
<h1>插入数据</h1>
<form action="insertFlight" method="post">
<label>航 号: <input type="text"
name="flightId"></label><br>
<label>航空公司: <input type="text" name="company"></label><br>
<label>出发机场: <input type="text" name="departureAirport"></label><br>
<label>达到机场: <input type="text" name="arriveAirport"></label><br>
<label>出发时间: <input type="text" name="departureTime"></label><br>
<label>到达时间: <input type="text" name="arriveTime"></label><br>
<label>机 型: <input type="text"
name="model"></label><br>
<input type="submit" value="提交">
</form>
</div>
</body>
</html>
逻辑删除航班信息
企业实际开发中 不会真正物理删除数据。
执行deletesql语句 物理将数据进行删除。
企业实际开发中逻辑删除 字段is_delete=0 则显示该行数据is_delete=1 则隐藏
该行数据
逻辑删除本质就是 update is_delete=1----隐藏数据
select where is_delete=0--------显示的数据