web开发:
在Java中,动态web资源开发的技术统称为JavaWeb。
web应用程序:可以提供浏览器访问的程序:
web应用程序编写完毕后,若想提供给外界访问,需要一个服务器来统一管理。
*.htm, *.html,这些都是网页的后缀,如果服务器上一直存在这些东西,我们就可以直接通过网络进行读取。
静态web存在的缺点
页面会动态展示:web页面的展示效果因人而异。
缺点:
优点:
ASP:Active Server Pages 动态服务器页面
微软:国内最早流行的就是ASP;
在html中嵌入了VB的脚本,ASP+COM;
在ASP开发中,基本上一个页面要嵌入大量的业务逻辑代码,页面混乱
<h1>
<h1>
<h1>
<h1>
<%
System.out.println("Hello")
%>
h1>
h1>
h1>
h1>
维护成本高!
ASP主要使用C#
IIS,(Internet Information Services ,互联网信息服务 )
PHP:
JSP/Servlet:
B/S:浏览器和服务器
C/S:客户端和服务器
服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应信息。
ISS:
Tomcat:
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个Java初学者来说,它是最佳的选择。
Tomcat 实际上运行JSP 页面和Servlet。截止至2023年7月20日,Tomcat最新版本为11.0.0**。**
…
tomcat官网:https://tomcat.apache.org/
这里我安装了10.1.11版本。
文件夹的作用
启动和关闭Tomcat
config目录下的server.xml文件为服务器核心配置文件。
在该文件中,我们可以修改启动默认的端口号,可以配置主机的名称,可以配置web存放webapps的目录。
修改端口号:
Tomcat 的默认端口号:8080
MySQL的默认端口号:3306
http的默认端口号:80
https的默认端口号:443
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
配置主机名称:
默认主机名为:localhost,相当于电脑ip
默认网站应用存放的目录为:webapps
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
面试题:
请你谈一谈网站是如何进行访问的:
一位前辈写的很详细的过程可供参考:访问一个网页的全过程(超详细版)_访问原网页_小包同学666的博客-CSDN博客
输入域名后,发送http请求
服务器查找域名对应的IP地址
先检查本地hosts配置文件中或者本机的DNS缓存中有没有这个域名的映射,有则直接返回对应的IP地址,这个地址中,有我们需要访问的web程序,可以直接进行访问。相当于一把钥匙。
本地没找到的话,浏览器会发出一个DNS请求到本地DNS服务器,本地DNS服务器一般都是我们网络接入服务商提供的,比如中国移动、电信……,请求到达本地DNS服务器后,本地DNS服务器开始查缓存记录(递归查询),查到了,直接返回,没查到,继续向上一级查询,上一级为DNS根服务器,继续查询,DNS根服务器没有记录具体的域名和IP地址的对应关系,于是告诉本地DNS服务器,你可以到域服务器上去继续查询,并给出域服务器的地址(迭代)。
本地DNS服务器继续向域服务器发出请求,如果请求的对象是.com域服务器。.com域服务器收到请求之后,也不会直接返回域名和IP地址的对应关系,而是告诉本地DNS服务器,你的域名的解析服务器的地址。
最后,本地DNS服务器向域名的解析服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不仅要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备下次别的用户查询时,可以直接返回结果,加快网络访问。如果url里不包含端口号,则会使用该协议的默认端口号。
浏览器访问这个ip地址
ip地址所在的服务器发送响应页面给客户端
访问成功
配置一个Tomcat的环境变量(可选)
--webapps:Tomcat服务器的web目录
-root:网站的目录名
-WEB-INF
-classes:java程序
-lib:web应用所依赖的jar包
-web.xml:网站的配置文件
-index.html 默认的首页
-static
-css
-js
-img
-...
超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII形式给出;而消息内容则具有一个类似MIME的格式。
客户端发送请求至服务器
以百度主页为例
Request URL:https://www.baidu.com/ //请求地址
Request Method:GET //请求方法:get 或 post
Status Code:200 OK //状态码:200
Remote Address:36.152.44.95:443 //远程地址:ip
Referrer Policy:unsafe-url
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.7
Accept-Encoding:
gzip, deflate, br
Accept-Language:
zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection:
keep-alive
Cookie:
BAIDUID=7983DB4511EA3BD8A34711321AD384FB:FG=1; BIDUPSID=7983DB4511EA3BD8A34711321AD384FB; PSTM=1686188034; BAIDUID_BFESS=7983DB4511EA3BD8A34711321AD384FB:FG=1; channel=baidu.yni84.com; COOKIE_SESSION=154_0_2_1_0_11_1_0_2_2_1_6_0_0_0_0_0_0_1686408302%7C2%230_0_1686408371%7C1%7C1; BAIDU_WISE_UID=wapp_1686448323979_511; BDUSS=lvaEN2M0lldFlkdFFxc0o3Q0FTZGRXdFNkfnZOZkJWbzF1NzJEZHNHVXF1YXhrSVFBQUFBJCQAAAAAAQAAAAEAAACeoSEgbHVjazF5NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACoshWQqLIVkQk; BDUSS_BFESS=lvaEN2M0lldFlkdFFxc0o3Q0FTZGRXdFNkfnZOZkJWbzF1NzJEZHNHVXF1YXhrSVFBQUFBJCQAAAAAAQAAAAEAAACeoSEgbHVjazF5NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACoshWQqLIVkQk; baikeVisitId=ac871edd-42b2-469b-ab00-d9dc2a5064b0; __bid_n=185f85e53f13290fc64207; FPTOKEN=3EIy0QGw9botoUZIl8A6aTU/WYaM4KfDD8TLNLcHyk0s53EgFCpaLbdeL7gpe9OwcXtiSfjgx4qpWRnC2xRuEqS1WxvoxvanyXTFiNQieYYYZmssKsx9M9cLlr5JxrCF5EuaNrjlfgyPQlcZn/Wl1zRRdBqGXRIvsMty7oqK1FlSTahNoaLzIyT0J7nB+4u5gB0v/DGqq3fKavjtgQyAdQiIxNP4/QsX8yJxU+wnL7twFBskXuA3lyGO2S5ygx6fhX+8LCNHjTMTL8y0uUECPcJXTOPn1Vr0QIjNch3qG10VRkAADXNzPHJHz/jUPA9pOejdWUbVak4IV7fCGJkQDlcSewFrG3qtKrlEwpXL1Kxv5Kh1ZsMUOpuSZqpBOXRs0hSmgXDYL9FN5yJq5iynTQ==|NKdyZ+1W0N6+VylwwZLQNQL3M2oLgR2G7CrVyMJA3q4=|10|1ad2b263ca26ac684ba4962355326c70; BD_UPN=12314753; ZFY=CXvPIk3AByRXnNlRy3JsNyWO:A7v1tOY7obm6IOMGn8A:C; RT="z=1&dm=baidu.com&si=d32fd009-95a5-4b3e-827b-1520f83b64d1&ss=lkala4io&sl=4&tt=2yg&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ld=kk8&ul=296j&hd=297o"; BDRCVFR[s5kaJWTb083]=OjjlczwSj8nXy4Grjf8mvqV; BD_HOME=1; H_PS_PSSID=26350; BA_HECTOR=0g848g2la4018ha4a5058h8c1ibkagg1o; WWW_ST=1689922231816
Host:
www.baidu.com
Referer:
https://www.baidu.com/?tn=88093251_87_hao_pg
Sec-Ch-Ua:
"Not/A)Brand";v="99", "Google Chrome";v="115", "Chromium";v="115"
Sec-Ch-Ua-Mobile:
?0
Sec-Ch-Ua-Platform:
"Windows"
Sec-Fetch-Dest:
document
Sec-Fetch-Mode:
navigate
Sec-Fetch-Site:
same-origin
Sec-Fetch-User:
?1
Upgrade-Insecure-Requests:
1
User-Agent:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36
请求行:
消息头:
Accept: //告诉浏览器,它所支持的数据类型
Accept-Encoding: gzip, deflate, br //支持哪种编码格式
Accept-Language: zh-CN,zh;q=0.9 //告诉浏览器语言环境
Cache-Control: max-age=0 //缓存控制
Connection: keep-alive //告诉浏览器请求完成是断开还是保持连接
HOST:主机
服务器响应客户端
以百度为例:
Bdpagetype:
2
Bdqid:
0xb6f1197f00094b34
Connection:
keep-alive
Content-Encoding:
gzip
Content-Security-Policy:
frame-ancestors 'self' https://chat.baidu.com http://mirror-chat.baidu.com https://fj-chat.baidu.com https://hba-chat.baidu.com https://hbe-chat.baidu.com https://njjs-chat.baidu.com https://nj-chat.baidu.com https://hna-chat.baidu.com https://hnb-chat.baidu.com http://debug.baidu-int.com;
Content-Type:
text/html; charset=utf-8
Date:
Fri, 21 Jul 2023 06:50:32 GMT
Isprivate:
1
Server:
BWS/1.1
Set-Cookie:
BDSVRTM=368; path=/
Set-Cookie:
BD_HOME=1; path=/
Set-Cookie:
H_PS_PSSID=36555_38642_38831_39026_39024_38943_39007_39114_39120_39087_26350_39094_39100_39043_38953; path=/; domain=.baidu.com
Strict-Transport-Security:
max-age=172800
Traceid:
1689922232095451905013182345617542302516
Transfer-Encoding:
chunked
X-Ua-Compatible:
IE=Edge,chrome=1
响应体
Accept: //告诉浏览器,它所支持的数据类型
Accept-Encoding: gzip, deflate, br //支持哪种编码格式
Accept-Language: zh-CN,zh;q=0.9 //告诉浏览器语言环境
Cache-Control: max-age=0 //缓存控制
Connection: keep-alive //告诉浏览器请求完成是断开还是保持连接
HOST:主机
Refresh: //告诉客户端,多久刷新一次
Location: //让网页重写定位
响应状态码
200:请求响应成功
3XX:请求重定向,转到一个新位置
4XX:找不到资源,资源不存在(404)
5XX:服务器代码错误(500)
502:网关错误
常见面试题:
为什么要学习这个技术?
所以,Maven诞生了!
目前用Maven就是便于导入jar包。
Maven核心思想:约定大于配置
Maven规定了我们如何按照一定的目录结构来编写我们的Java代码。
在系统环境变量中,配置如下:
完成后:在控制台输入mvn -version 检查是否安装成功 mvn其实是bin目录中的一个命令
镜像:mirrors
国内建议使用阿里云镜像
在setting.xml文件下的mirrors中粘贴以下内容:
<mirror>
<id>aliyun-publicid>
<mirrorOf>*mirrorOf>
<name>aliyun publicname>
<url>https://maven.aliyun.com/repository/publicurl>
mirror>
<mirror>
<id>aliyun-centralid>
<mirrorOf>*mirrorOf>
<name>aliyun centralname>
<url>https://maven.aliyun.com/repository/centralurl>
mirror>
<mirror>
<id>aliyun-springid>
<mirrorOf>*mirrorOf>
<name>aliyun springname>
<url>https://maven.aliyun.com/repository/springurl>
mirror>
<mirror>
<id>aliyun-spring-pluginid>
<mirrorOf>*mirrorOf>
<name>aliyun spring-pluginname>
<url>https://maven.aliyun.com/repository/spring-pluginurl>
mirror>
<mirror>
<id>aliyun-apache-snapshotsid>
<mirrorOf>*mirrorOf>
<name>aliyun apache-snapshotsname>
<url>https://maven.aliyun.com/repository/apache-snapshotsurl>
mirror>
<mirror>
<id>aliyun-googleid>
<mirrorOf>*mirrorOf>
<name>aliyun googlename>
<url>https://maven.aliyun.com/repository/googleurl>
mirror>
<mirror>
<id>aliyun-gradle-pluginid>
<mirrorOf>*mirrorOf>
<name>aliyun gradle-pluginname>
<url>https://maven.aliyun.com/repository/gradle-pluginurl>
mirror>
<mirror>
<id>aliyun-jcenterid>
<mirrorOf>*mirrorOf>
<name>aliyun jcentername>
<url>https://maven.aliyun.com/repository/jcenterurl>
mirror>
<mirror>
<id>aliyun-releasesid>
<mirrorOf>*mirrorOf>
<name>aliyun releasesname>
<url>https://maven.aliyun.com/repository/releasesurl>
mirror>
<mirror>
<id>aliyun-snapshotsid>
<mirrorOf>*mirrorOf>
<name>aliyun snapshotsname>
<url>https://maven.aliyun.com/repository/snapshotsurl>
mirror>
<mirror>
<id>aliyun-grails-coreid>
<mirrorOf>*mirrorOf>
<name>aliyun grails-corename>
<url>https://maven.aliyun.com/repository/grails-coreurl>
mirror>
<mirror>
<id>aliyun-mapr-publicid>
<mirrorOf>*mirrorOf>
<name>aliyun mapr-publicname>
<url>https://maven.aliyun.com/repository/mapr-publicurl>
mirror>
本地仓库和远程仓库;
建立本地仓库:不用每次都去网上下载各种包
在maven下新建一个文件夹,命名为maven-repo,复制这个地址,在setting.xml文件中进行粘贴
<localRepository>E:\Java environment\apache-maven-3.9.3\maven-repolocalRepository>
创建普通maven项目(无模板项目)
注意设置中的maven设置
每种路径都要设置到自己maven文件夹的路径,否则默认为IDEA自带的maven版本,每次新开的项目要留意看一下。
本地仓库中可以看到多了很多包
一个干净的maven项目
新建项目时选择左侧Maven Archetype,在Catalog中选择Internal,在Archetype中选择……webapp,我用的是2023版本,新建项目时和前面的版本略有不同。
pom.xml是maven的核心文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>xyz.luck1ygroupId>
<artifactId>javaweb-01-mavenartifactId>
<packaging>warpackaging>
<version>1.0-SNAPSHOTversion>
<name>javaweb-01-maven Maven Webappname>
<url>http://maven.apache.orgurl>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>3.8.1version>
<scope>testscope>
dependency>
dependencies>
<build>
<finalName>javaweb-01-mavenfinalName>
build>
project>
maven的高级之处在于它会帮我们导入某个jar包所依赖的其他jar包
如果遇到maven项目中的配置文件无法被导出或者生效的问题,在配置文件中加上以下内容:
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>
maven仓库官网:https://mvnrepository.com/
找到想用的jar包,选好版本后进去就能看见maven的代码配置,复制粘贴到dependencys下就好了,在maven结构目录刷新一下,就能导入jar包,非常方便。
Servlet接口在Sun公司有两个默认的实现类:HttpServlet、GenericServlet
构建一个普通Maven项目,删掉里面的src目录,以后的学习就在这个项目里简历许多的module;这个空的项目就是Maven的主项目(工程),所以我们把需要的依赖都导入到主工程的pom.xml中
右键该工程,新建module,勾选Maven自带的webapps模板框架,创建新的Maven子工程。关于Maven父子工程的理解:
父项目的pom.xml中会有以下内容:
<modules>
<module>servlet-01module>
modules>
子项目的pom.xml中会有以下内容:
<parent>
<groupId>xyz.luck1ygroupId>
<artifactId>javaweb-02-servletartifactId>
<version>1.0-SNAPSHOTversion>
parent>
父项目中的Java子项目可以直接使用父项目中的包
Maven环境优化
将web.xml中的配置内容更换为最新的
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
web-app>
注意pom.xml中的Servlet依赖:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>xyz.luck1ygroupId>
<artifactId>javaweb-session-cookieartifactId>
<packaging>warpackaging>
<version>1.0-SNAPSHOTversion>
<name>javaweb-session-cookie Maven Webappname>
<url>http://maven.apache.orgurl>
<dependencies>
<dependency>
<groupId>org.apache.tomcatgroupId>
<artifactId>tomcat-servlet-apiartifactId>
<version>10.0.4version>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>javax.servlet.jsp-apiartifactId>
<version>2.3.3version>
<scope>providedscope>
dependency>
dependencies>
<build>
<finalName>javaweb-session-cookiefinalName>
build>
project>
servlet-api:
Maven Repository: org.apache.tomcat » tomcat-jsp-api (mvnrepository.com)
<dependency>
<groupId>org.apache.tomcatgroupId>
<artifactId>tomcat-servlet-apiartifactId>
<version>10.0.4version>
dependency>
学到后面发现还是有些问题,比如在jsp中写Java代码不会自动补充,比如out.println爆红,于是更换依赖就好了,Tomcat10怎么到处都是坑!!!!
<dependency>
<groupId>jakarta.servletgroupId>
<artifactId>jakarta.servlet-apiartifactId>
<version>4.0.4version>
<scope>providedscope>
dependency>
将Maven项目的目录结构搭建完整,新建java目录(和resource目录)
编写一个Servlet程序
编写一个普通类
实现Servlet接口,这里我们直接继承HttpServlet
进入源码查看:Servlet --> GenericServlet --> HttpServlet --> 我们自己定义的类,Servlet接口有个service方法,HTTPServlet对其进行了重写,重写后其中包括了很多方法,而我们常用的就是doGet和doPost,所以在自己定义的类中,需要重写这两个方法。
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloServlet extends HttpServlet {
// 由于get或者post只是请求实现的不同方式,可以相互调用,业务逻辑都一样
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 可以得到输入输出流
// ServletInputStream inputStream = req.getInputStream();
// ServletOutputStream outputStream = resp.getOutputStream();
System.out.println("进入doGet方法");
// 响应流
PrintWriter writer = resp.getWriter();
writer.print("Hello,Servlet!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
编写Servlet的映射
为什么需要映射?我们写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的Servlet,还需要给它一个浏览器能够访问的路径。
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>helloservlet-name>
<servlet-class>xyz.luck1y.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
web-app>
配置Tomcat
注意项目发布的路径
注意每个子项目添加进artifact的时候,去掉上一个残留的,尽量只存在一个
启动项目测试
Servlet是由web服务器调用,web服务器在收到浏览器请求之后的原理图如下,
一个Servlet可以指定一个映射路径
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
一个Servlet可以指定多个映射路径
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello1url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello2url-pattern>
servlet-mapping>
一个Servlet可以指定通用映射路径
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello/*url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/*url-pattern>
servlet-mapping>
指定一些后缀等等…
注意:*前面不能加项目映射的路径
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>*.dourl-pattern>
servlet-mapping>
扩展:如果出错,网页404跳转error界面
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ErrorServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
PrintWriter writer = resp.getWriter();
writer.print("404 网页找不到咯
");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
<servlet>
<servlet-name>errorservlet-name>
<servlet-class>xyz.luck1y.servlet.ErrorServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>errorservlet-name>
<url-pattern>/*url-pattern>
servlet-mapping>
优先级问题:
指定了固有的映射路径:越准确优先级越高,如果找不到就会走默认的处理请求。
精准匹配>扩展匹配>模糊匹配>通配匹配
web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用。
全局唯一,只有一个,所有servlet公用。
应用:
在这个Servlet中保存的数据,可以在另一个Servlet中拿到。
创建数据的类:
package xyz.luck1y.servlet;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// this.getInitParameter(); 初始化参数
// this.getServletConfig(); Servlet配置
// this.getServletContext(); 上下文,第三方
resp.setContentType("text/html;charset=utf-8");
ServletContext context = this.getServletContext();
// 数据
String username = "Luck1y";
// 将一个数据保存到了ServletContext中。名字为:username,值为:username
context.setAttribute("username", username);
System.out.println("存放值");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
读取数据的类:
package xyz.luck1y.servlet;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String username = (String) context.getAttribute("username");
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().print("名字:" + username);
System.out.println("取值");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
web.xml:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>helloservlet-name>
<servlet-class>xyz.luck1y.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
<servlet>
<servlet-name>getcservlet-name>
<servlet-class>xyz.luck1y.servlet.GetServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>getcservlet-name>
<url-pattern>/getcurl-pattern>
servlet-mapping>
web-app>
运行结果:
没存值进去的时候(没有进入hello),null
存了值进去(进入hello)之后
web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<context-param>
<param-name>urlparam-name>
<param-value>jdbc:mysql://localhost:3066/mybatisparam-value>
context-param>
<servlet>
<servlet-name>helloservlet-name>
<servlet-class>xyz.luck1y.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
<servlet>
<servlet-name>getcservlet-name>
<servlet-class>xyz.luck1y.servlet.GetServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>getcservlet-name>
<url-pattern>/getcurl-pattern>
servlet-mapping>
<servlet>
<servlet-name>gpservlet-name>
<servlet-class>xyz.luck1y.servlet.ServletDemo03servlet-class>
servlet>
<servlet-mapping>
<servlet-name>gpservlet-name>
<url-pattern>/gpurl-pattern>
servlet-mapping>
web-app>
获取类:
package xyz.luck1y.servlet;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
resp.getWriter().print(url);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
运行结果:
转发不是重定向,路径不会变,但是页面内容会改变
web.xml
<servlet>
<servlet-name>sd4servlet-name>
<servlet-class>xyz.luck1y.servlet.ServletDemo04servlet-class>
servlet>
<servlet-mapping>
<servlet-name>sd4servlet-name>
<url-pattern>/sd4url-pattern>
servlet-mapping>
转发类(将ServletDemo03页面的内容转发到ServletDemo04)
package xyz.luck1y.servlet;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
resp.getWriter().print(url);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
运行结果:
可以看出,路径是/sd4但是打开的内容还是/gp的内容,其结构原理类似下图:
A想连接到C的资源,要通过B来实现,所以A向B发送请求,要C的资源,B将C的资源转发给A。在这个例子中,A就是ServletDemo04,B就是ServletContext,C就是ServeltDemo03。
重定向的话是这样的:
A需要发送两次请求,过程为:A告诉B我要C的资源,B回答说:你去找C要,然后A向C发送请求。即重定向。
Properties
新建一个db.properties文件,放在resources目录下,运行服务器,查看target目录,发现生成了对应的db.properties文件
新建一个aa.properties文件,放在java目录下,运行服务器,查看target目录,发现不没有生成对应的aa.properties文件,这就是Maven中提到的资源导出问题
我们在该module下的配置文件中的build部分加入以下内容:
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>
对比打包的项目target和原本的main,我们可以发现一条java和resources目录的内容都被打包到了classes,我们俗称这个路径为类路径,classpath。
db.properties:
username=root
password=123456
获取类:
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream is = this.getServletContext().getResourceAsStream("WEB-INF/classes/db.properties");
Properties prop = new Properties();
prop.load(is);
String user = prop.getProperty("username");
String pwd = prop.getProperty("password");
resp.getWriter().print(user + ":" + pwd);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml:
<servlet>
<servlet-name>sd5servlet-name>
<servlet-class>xyz.luck1y.servlet.ServletDemo05servlet-class>
servlet>
<servlet-mapping>
<servlet-name>sd5servlet-name>
<url-pattern>/sd5url-pattern>
servlet-mapping>
运行结果:
web服务器接收到客户端的Http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,和代表响应的一个HttpServletResponse对象。
负责向浏览器发送数据的方法:
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的方法:
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
void setBufferSize(int var1);
响应的状态码:
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
向浏览器输出消息(前面已使用过)
下载文件
下载类:
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1.要获取下载文件的路径
// String realPath = this.getServletContext().getRealPath("/1.png");
String realPath = "E:\\Java\\学习记录\\JavaWeb\\图片.png";
System.out.println("下载文件的路径" + realPath);
// 2.下载的文件名
String filename = realPath.substring(realPath.lastIndexOf("\\") + 1);
// 3.想办法让浏览器能够支持下载我们需要的东西
// URLEncoder.encode(filename,"UTF-8") 使用中文文件名也不会出现乱码问题
resp.setHeader("Content-Disposition", "attachment;filename=" + filename + URLEncoder.encode(filename,"UTF-8"));
// 4.获取下载文件的输入流
FileInputStream in = new FileInputStream(realPath);
// 5.创建缓冲区
int len = 0;
byte[] buffer = new byte[1024];
// 6.获取OutputStream对象
ServletOutputStream out = resp.getOutputStream();
// 7.将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区中的数据输出到客户端
while ((in.read(buffer) != -1)) {
out.write(buffer, 0, len);
}
// 8.关闭资源
out.close();
in.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>filedownloadservlet-name>
<servlet-class>xyz.luck1y.servlet.FileServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>filedownloadservlet-name>
<url-pattern>/downurl-pattern>
servlet-mapping>
web-app>
验证码功能
验证码是怎么来的?
前端实现
后端实现,需要用到java的图片类,生成一个图片
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 如何让浏览器3秒自动刷新一次
resp.setHeader("refresh", "3");
// 在内存中创建一个图片
BufferedImage bufferedImage = new BufferedImage(60,30,BufferedImage.TYPE_3BYTE_BGR);
// 得到图片
Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics();
// 设置图片的背景颜色
graphics.setColor(Color.white);
graphics.fillRect(0,0,60,30);
// 给图片写数据
graphics.setColor(Color.blue);
graphics.setFont(new Font(null, Font.BOLD, 20));
graphics.drawString(makeNum(), 0, 20);
// 告诉浏览器这个请求用图片的方式打开
resp.setContentType("image/png");
// 网站存在缓存,不让浏览器缓存
resp.setDateHeader("expires", -1);
resp.setHeader("Cache-Control", "no-cache");
resp.setHeader("Prpgram", "no-cache");
// 把图片写给浏览器
ImageIO.write(bufferedImage, "png", resp.getOutputStream());
}
// 生成随机数
private String makeNum(){
Random random = new Random();
String num = random.nextInt(99999) + "";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 5 - num.length(); i++) {
sb.append("0");
}
num = sb + num;
return num;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml:
<servlet>
<servlet-name>imageservlet-name>
<servlet-class>xyz.luck1y.servlet.ImageServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>imageservlet-name>
<url-pattern>/imgurl-pattern>
servlet-mapping>
实现效果:
实现重定向
一个Web资源收到客户端请求后,通知他去访问另一个web资源,这个过程叫做重定向。
常见场景:
用户登录
void sendRedirect(String var1) throws IOException;
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("img");
// 等价于302
// resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml
<servlet>
<servlet-name>RedirectServletservlet-name>
<servlet-class>xyz.luck1y.servlet.RedirectServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>RedirectServletservlet-name>
<url-pattern>/redurl-pattern>
servlet-mapping>
聊一聊重定向和转发的区别(面试题)
相同点:
不同点:
去maven仓库导入一个jsp包
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>javax.servlet.jsp-apiartifactId>
<version>2.3.3version>
dependency>
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RequestTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入这个请求了");
// 处理请求
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username + ":" + password);
resp.sendRedirect("success.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml
<servlet>
<servlet-name>requestservlet-name>
<servlet-class>xyz.luck1y.servlet.RequestTestservlet-class>
servlet>
<servlet-mapping>
<servlet-name>requestservlet-name>
<url-pattern>/loginurl-pattern>
servlet-mapping>
index.jsp
Hello World!
<%--设置中文编码--%>
<%@page pageEncoding="utf-8"%>
<%--这里提交的路径,需要寻找到项目的路径--%>
<%--${pageContext.request.contextPath} 代表当前的项目--%>
success.jsp(点击提交后跳转界面)
<%--
Created by IntelliJ IDEA.
User: 刘嘉奇
Date: 2023/7/24
Time: 19:24
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
Success!
运行效果:
HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,Http请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest对象的方法,可以获得客户端的所有信息。
获取前段传递的参数
// 返回String
requset.getParameter(String s);
// 返回数组String[]
request.getParameterValues(String s);
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 防止中文乱码
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbys = req.getParameterValues("hobbys");
System.out.println("===========================");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbys));
System.out.println("===========================");
// 通过请求转发或重定向跳转到其他页面
req.getRequestDispatcher("success.jsp").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>LoginServletservlet-name>
<servlet-class>xyz.luck1y.servlet.LoginServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>LoginServletservlet-name>
<url-pattern>/loginurl-pattern>
servlet-mapping>
web-app>
index.jsp:
<%--
Created by IntelliJ IDEA.
User: 刘嘉奇
Date: 2023/7/24
Time: 20:19
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
登陆页
登录
<%--表单表示的意思是以post方式提交表单,提交到我们的login请求--%>
success.jsp:
<%--
Created by IntelliJ IDEA.
User: 刘嘉奇
Date: 2023/7/24
Time: 20:26
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
成功!
登陆成功!
运行效果:
会话:用户打开一个浏览器,点击一个或多个超链接,访问多个web资源,关闭浏览器,这个过程称之为会话
有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学曾经来过,称之有状态会话。
无状态会话:访问一次后就断开连接,没有留下信息
Cookie:
Session:
常见场景:网站登陆一次后,下次不用再次登录。
// 获得Cookie
Cookie[] cookies = req.getCookies();
// 获得Cookie中的key
cookie.getName();
// 获得Cookie中的值
cookie.getValue();
// 新建一个Cookie
Cookie cookie = new Cookie("lastLoginTime",System.currentTimeMillis() + "");
// 设置Cookie的有效期 (24*60*60 有效期为一天)
cookie.setMaxAge(24*60*60);
// 响应给客户端一个Cookie
resp.addCookie(cookie);
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
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.util.Date;
public class CookieDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决中文乱码
req.setCharacterEncoding("utf-16");
resp.setCharacterEncoding("utf-16");
PrintWriter out = resp.getWriter();
// Cookie,服务器端从客户端获取
// 返回数组,说明Cookie可能存在多个
Cookie[] cookies = req.getCookies();
// 判断Cookie是否存在
if (cookies != null) {
// 如果存在
out.write("您上一次访问的时间是:");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
// 获取cookie的名字
if (cookie.getName().equals("lastLoginTime")) {
// 获取cookie中的值
long lastLoginTime = Long.parseLong(cookie.getValue());
Date date = new Date(lastLoginTime);
out.write(date.toLocaleString());
}
}
} else {
out.write("这是您第一次访问本站");
}
// 服务器给客户端响应一个Cookie
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
resp.addCookie(cookie);
// 设置有效期 (24*60*60 有效期为一天)
cookie.setMaxAge(24*60*60);
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>CookieDemo01servlet-name>
<servlet-class>xyz.luck1y.servlet.CookieDemo01servlet-class>
servlet>
<servlet-mapping>
<servlet-name>CookieDemo01servlet-name>
<url-pattern>/c1url-pattern>
servlet-mapping>
web-app>
Cookie一般会保存在本地的用户目录下 appdata;
一个网站的Cookie是否存在上限?存在!
删除cookie:
不设置有效期,关闭浏览器,自动失效;
设置有效期时间为0
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
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.util.Date;
public class CookieDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决中文乱码
req.setCharacterEncoding("utf-16");
resp.setCharacterEncoding("utf-16");
// 创建一个cookie,,名字必须要和要删除的名字一致
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
// 将cookie有效期设置为0
cookie.setMaxAge(0);
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml
<servlet>
<servlet-name>CookieDemo02servlet-name>
<servlet-class>xyz.luck1y.servlet.CookieDemo02servlet-class>
servlet>
<servlet-mapping>
<servlet-name>CookieDemo02servlet-name>
<url-pattern>/c2url-pattern>
servlet-mapping>
cookie中文乱码问题(解码和编码)
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
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.net.URLDecoder;
import java.net.URLEncoder;
/**
* 中文数据传递
*/
public class CookieDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决中文乱码
req.setCharacterEncoding("utf-16");
resp.setCharacterEncoding("utf-16");
// Cookie,服务器端从客户端获取
// 返回数组,说明Cookie可能存在多个
Cookie[] cookies = req.getCookies();
PrintWriter out = resp.getWriter();
// 判断Cookie是否存在
if (cookies != null) {
// 如果存在
out.write("您上一次访问的时间是:");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
// 获取cookie的名字
if (cookie.getName().equals("name")) {
// System.out.println(cookie.getValue());
// 解码
URLDecoder.decode(cookie.getValue(), "UTF-8");
}
}
} else {
out.write("这是您第一次访问本站");
}
// 编码
Cookie cookie = new Cookie("name", URLEncoder.encode("刘子", "utf-8"));
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml
<servlet>
<servlet-name>CookieDemo03servlet-name>
<servlet-class>xyz.luck1y.servlet.CookieDemo03servlet-class>
servlet>
<servlet-mapping>
<servlet-name>CookieDemo03servlet-name>
<url-pattern>/c3url-pattern>
servlet-mapping>
什么是Session:
Session和Cookie的区别:
在网站中经常使用的信息,保存在session中,方便使用。
Session存放普通键值对
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
public class SessionDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决乱码问题
resp.setCharacterEncoding("UTF-8");
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=utf-8");
// 得到Session
HttpSession session = req.getSession();
// 给Session中存东西
session.setAttribute("name", "刘子");
// 获取Session的ID
String id = session.getId();
// 判断是不是新的Session
if (session.isNew()) {
resp.getWriter().write("Session创建成功,ID:" + id);
} else {
resp.getWriter().write("Session已经在服务器中存在了,ID:" + id);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml:
<servlet>
<servlet-name>SessionDemo01servlet-name>
<servlet-class>xyz.luck1y.servlet.SessionDemo01servlet-class>
servlet>
<servlet-mapping>
<servlet-name>SessionDemo01servlet-name>
<url-pattern>/s1url-pattern>
servlet-mapping>
运行结果:
session存放对象
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.*;
import xyz.luck1y.servlet.pojo.Person;
import java.io.IOException;
public class SessionDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决乱码问题
resp.setCharacterEncoding("UTF-8");
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=utf-8");
// 得到Session
HttpSession session = req.getSession();
Person name = (Person) session.getAttribute("name");
System.out.println(name);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
可以看到控制台可以获取到session的值:
清除session的两种方法:
手动清除
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
public class SessionDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
session.removeAttribute("name");
// 手动注销session
session.invalidate();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml中清除session(会话自动过期)
<session-config>
<session-timeout>15session-timeout>
session-config>
Java Server Pages:Java服务器页面,和Servlet一样,用于开发动态web技术,假如用Servlet类实现JSP功能(心态大崩)很麻烦!
于是JSP出现,其最大的特点是:
思路:JSP到底怎么执行的?
代码层面没有任何不同
服务器内部:
Tomcat中有一个work目录,在IDEA中使用Tomcat会在IDEA的Tomcat中产生一个work目录,进去可以发现.java文件和.class文件。查找方法(IDEA导航栏–>help–>Show Log In Explorer,这个路径的上级路径中有个tomcat目录)
也就是说:页面转换为了java程序
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!
即JSP最终会被转换为一个Java类,所以JSP本质上还是一个Servlet!
在源码中可以看到这样的三个方法:
//初始化
public void _jspINit(){
}
//销毁
public void _jspDestroy(){
}
//JSPService
public void _jspService(HttpServletRequest request,HttpServletResponse response)
判断请求属于哪种类型
内置了一些对象
final javax.servlet.jsp.PageContext pageContext; // 页面上下文
javax.servlet.http.HttpSession session = null; // session
final javax.servlet.ServletContext application; // application
final javax.servlet.ServletConfig config; // 配置
javax.servlet.jsp.JspWriter out = null; // 输出
final java.lang.Object page = this; // page 当前页
HttpServletRequest request; // 请求
HttpServletResponse response; // 响应
输出页面前增加的代码
response.setContentType("text/html"); // 设置响应的页面类型
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
以上的这些对象,我们可以直接在jsp页面中使用
jsp中还可以直接写Java代码
使用<% %>就可以在里面写java代码
使用<%= %>就可以获取某个字段的值
在jsp页面中,只要是Java代码,就会原封不动的输出;
如果是HTML代码,就会转换为以下格式输出到前端:
out.write("\r\n")
导包:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>xyz.luck1ygroupId>
<artifactId>javaweb-jspartifactId>
<version>1.0-SNAPSHOTversion>
<properties>
<maven.compiler.source>17maven.compiler.source>
<maven.compiler.target>17maven.compiler.target>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>jakarta.servletgroupId>
<artifactId>jakarta.servlet-apiartifactId>
<version>4.0.4version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>javax.servlet.jsp-apiartifactId>
<version>2.3.3version>
dependency>
<dependency>
<groupId>javax.servlet.jsp.jstlgroupId>
<artifactId>jstl-apiartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>org.apache.taglibsgroupId>
<artifactId>taglibs-standard-implartifactId>
<version>1.2.5version>
<scope>runtimescope>
dependency>
dependencies>
project>
JSP基础语法
任何语言都有自己的语法,Java有,JSP也有,作为Java技术的一种应用,它拥有一些自己扩充的语法(了解)Java中的所有语法JSP都支持。
JSP表达式:
<%--JSP表达式
作用:用来将程序的输出,输出到客户端
<%= 变量或者表达式%>
--%>
<%= new java.util.Date()%>
JSP脚本片段:
<%--JSP脚本片段--%>
<%
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
out.println("SUM = " + sum + "");
%>
脚本片段的再实现
<%--
Created by IntelliJ IDEA.
User: 刘嘉奇
Date: 2023/7/27
Time: 21:01
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--JSP表达式
作用:用来将程序的输出,输出到客户端
<%= 变量或者表达式%>
--%>
<%= new java.util.Date()%>
<%--JSP脚本片段--%>
<%
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
out.println("SUM = " + sum + "");
%>
<%
int x = 10;
out.println(x);
%>
这是一个JSP文档
<%
int y = 2;
out.println(y);
%>
<%--在代码中嵌入HTML元素--%>
<%
for (int i = 0; i < 5; i++) {
%>
Hello,刘子 <%=i%>
<%
}
%>
效果:
查看转换后的Java文件代码可以发现,这些所有的标签等等都被转换在_jspService这个方法中
JSP声明
<%!
static {
System.out.println("Loading Servlet!");
}
private int globalVar = 0;
public void Liu(){
System.out.println("进入了刘子写的方法!");
}
%>
jsp声明:会被编译到JSP生成的Java文件的类中,而其他的(表达式、脚本片段)会被生成到_jspService方法中!
在JSP中嵌入Java代码即可
如何使JSP变得简洁?—> EL表达式
<%--使用EL表达式对上面代码进行简化--%>
<%--注意跟JQuery进行区分:
JQuery:$()
EL表达式:${}
--%>
<%
for (int i = 0; i < 5; i++) {
%>
Hello,World! ${pageContext.request}
<%
}
%>
JSP语法总结:
<% 脚本片段 %>
<%! JSP声明 %>
<%= JSP表达式 %>
<%-- 注释 --%>
补充:HTML的注释:
通过在浏览器中查看源代码,可以发现HTML的注释依旧会显示出来,但是JSP的就不会被显示,提高了网页的安全性。
错误页面的定制
<%--
Created by IntelliJ IDEA.
User: 刘嘉奇
Date: 2023/7/27
Time: 21:42
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--导包--%>
<%@ page import="java.util.*" %>
<%--定制错误页面--%>
<%@ page errorPage="error/500.jsp" %>
Title
<%
int x = 1 / 0;
%>
<%
new Date();
%>
500错误页面:
<%--
Created by IntelliJ IDEA.
User: 刘嘉奇
Date: 2023/7/27
Time: 21:43
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
500错误页面
404错误页面:
<%--
Created by IntelliJ IDEA.
User: 刘嘉奇
Date: 2023/7/27
Time: 21:51
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
404错误页面
在错误页面中使用了
标签来加载图片到网页上。
在web.xml文件中配置错误页面,需要重启Tomcat。
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<error-page>
<error-code>404error-code>
<location>/error/404.jsplocation>
error-page>
<error-page>
<error-code>500error-code>
<location>/error/500.jsplocation>
error-page>
web-app>
common包:一般用来存放相同的界面,比如一个网站不同界面的头部导航栏是一样的
<%--
Created by IntelliJ IDEA.
User: 刘嘉奇
Date: 2023/7/27
Time: 22:22
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--@include指令:会将三个页面合为一,都使用out.write()转成html代码--%>
<%@include file="common/header.jsp"%>
网页主体
<%@include file="common/footer.jsp"%>
<%--JSP标签:会将公共页面提取出来拼接起来,本质还是三个页面--%>
网页主体
<%--建议使用后者,代码互不影响,比如说在公共页面有个变量i,那么使用jsp标签是不会报错的,但是使用@include会报错500,说已经定义过了--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
我是header
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
我是footer
Maven是约定大于配置的,所以文件目录不要乱搞,会出现问题。
<%--
Created by IntelliJ IDEA.
User: 刘嘉奇
Date: 2023/7/29
Time: 9:35
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--内置对象--%>
<%
// 保存的数据只在一个页面中有效
pageContext.setAttribute("name1", "1号");
// 保存的数据只在一次请求中有效,请求转发会携带这个数据
request.setAttribute("name2", "2号");
// 保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
session.setAttribute("name3", "3号");
// 保存的数据在服务器中有效,从打开服务器到关闭服务器
application.setAttribute("name4", "4号");
%>
<%--脚本片段中的代码,会被原封不动的生成到 jsp.java中国
要求:这里的代码,必须保证Java语法的正确性
--%>
<%
// 通过pageContext取出我们保存的值,我们通过寻找的方式来
// 从底层到高层(作用域)
String name1 = (String) pageContext.findAttribute("name1");
String name2 = (String) pageContext.findAttribute("name2");
String name3 = (String) pageContext.findAttribute("name3");
String name4 = (String) pageContext.findAttribute("name4");
// 不存在
String name5 = (String) pageContext.findAttribute("name5");
%>
<%--使用EL表达式输出 ${} --%>
取出的值为:
${name1}
${name2}
${name3}
${name4}
<%--使用EL表达式会自动过滤掉不存在的--%>
${name5}
<%--使用jsp表达式会把不存在的显示为null--%>
<%=name5%>
在另一个页面中获取同样的内容,作用域不同导致获取不到
<%--
Created by IntelliJ IDEA.
User: 刘嘉奇
Date: 2023/7/29
Time: 9:35
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--脚本片段中的代码,会被原封不动的生成到 jsp.java中国
要求:这里的代码,必须保证Java语法的正确性
--%>
<%
// 通过pageContext取出我们保存的值,我们通过寻找的方式来
// 从底层到高层(作用域)
String name1 = (String) pageContext.findAttribute("name1");
String name2 = (String) pageContext.findAttribute("name2");
String name3 = (String) pageContext.findAttribute("name3");
String name4 = (String) pageContext.findAttribute("name4");
// 不存在
String name5 = (String) pageContext.findAttribute("name5");
%>
<%--使用EL表达式输出 ${} --%>
取出的值为:
${name1}
${name2}
${name3}
${name4}
<%--使用EL表达式会自动过滤掉不存在的--%>
${name5}
<%--使用jsp表达式会把不存在的显示为null--%>
<%=name5%>
部分源码分析
<%--
Created by IntelliJ IDEA.
User: 刘嘉奇
Date: 2023/7/29
Time: 9:58
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--
//scope:作用域
public static final int PAGE_SCOPE = 1;
public static final int REQUEST_SCOPE = 2;
public static final int SESSION_SCOPE = 3;
public static final int APPLICATION_SCOPE = 4;
public void setAttribute(String name, Object attribute, int scope) {
switch(scope) {
case 1:
this.mPage.put(name, attribute);
break;
case 2:
this.mRequest.put(name, attribute);
break;
case 3:
this.mSession.put(name, attribute);
break;
case 4:
this.mApp.put(name, attribute);
break;
default:
throw new IllegalArgumentException("Bad scope " + scope);
}
}
--%>
<%
// 可以手动设置作用域等价于:session.setAttribute();
pageContext.setAttribute("hello1","hello1",PageContext.SESSION_SCOPE);
%>
以下这个查找过程类似于:双亲委派机制中类的加载过程
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%
// 访问该页面地址栏不会有变化(转发)
pageContext.forward("/index.jsp");
// 后端实现
// request.getRequestDispatcher("/index.jsp").forward(request, response);
%>
如果在存放数据的页面,存完数据后转发到其他取数据的页面,那么request存的数据也能取到,因为转发是一次请求。
分场景理解
EL表达式:${}
,记得导包
<dependency>
<groupId>javax.servlet.jsp.jstlgroupId>
<artifactId>jstl-apiartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>org.apache.taglibsgroupId>
<artifactId>taglibs-standard-implartifactId>
<version>1.2.5version>
<scope>runtimescope>
dependency>
JSP标签
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
2
<%--取出参数--%>
名字:<%=request.getParameter("name")%>
年龄:<%=request.getParameter("age")%>
效果:
JSTL表达式:
JSTL标签库的使用就是为了弥补HTML标签的不足;它自定义了许多的标签,可以供我们使用,标签的功能和Java代码一样~
核心标签:
引入核心标签库
<%--引入核心标签库才能够使用核心标签 core--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
引入库后还要在pom.xml中导入依赖
<dependency>
<groupId>org.glassfish.webgroupId>
<artifactId>jakarta.servlet.jsp.jstlartifactId>
<version>2.0.0version>
dependency>
<dependency>
<groupId>org.apache.taglibsgroupId>
<artifactId>taglibs-standard-implartifactId>
<version>1.2.5version>
<scope>runtimescope>
dependency>
经测试后,发现jakarta.servlet.jsp.jstl
依赖用这个版本才行,maven仓库下的最新版本不行,可能是因为我用的Tomcat10,从一开始的Servlet到现在一直有各种各样的问题,Tomcat10一生之敌。
这两个依赖被我注掉了,不注掉就跑不出来!
测试:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入核心标签库才能够使用核心标签 core--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Title
<%--if测试--%>
哼哼终于跑出来了
结果:
核心标签:
分别测试
if标签
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入核心标签库才能够使用核心标签 core--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Title
<%--if测试--%>
哼哼终于跑出来了
<%--判断如果提交的用户名是管理员,则登陆成功--%>
测试结果:
输入 admin 登录后:
when标签:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Title
<%--定义一个变量score,值为85--%>
<%--按照先后顺序判断,满足就会跳出--%>
你的成绩为:优秀
你的成绩为:良好
你的成绩为:一般
测试结果:
for-each标签:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="java.util.ArrayList" %>
Title
<%--要遍历的对象:items--%>
<%--遍历出来的对象:var--%>
<%--从哪里开始:begin--%>
<%--到哪里结束:end--%>
<%--步长:step--%>
<%
ArrayList people = new ArrayList<>();
people.add(0, "张三");
people.add(1, "李四");
people.add(2, "王五");
people.add(3, "赵六");
people.add(4, "田七");
request.setAttribute("list", people);
%>
测试结果:
格式化标签:了解
SQL标签:了解
XML标签:了解
通常称JavaBean为实体类
JavaBean有特定的写法:
ORM:对象关系映射
id | name | age | address |
---|---|---|---|
1 | 张三 | 15 | 南京 |
2 | 李四 | 18 | 上海 |
3 | 王五 | 21 | 广州 |
class People{
private int id;
private String name;
private int age;
private String address;
}
class A{
new People(1,"张三",15,"北京");
...
}
javabean演示:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="xyz.luck1y.pojo.People" %>
Title
<%
// 和下面的写法是等价的
// People people = new People();
// people.setAddress();
// people.setId();
// people.setAge();
// people.setName();
%>
结果:
这里有个小插曲,运行Tomcat时突然又给我报错:
不再支持源选项6。请使用7或更高版本
在网上冲浪一番后,得到解决方案:
先检查Project Structures中,JDK版本是否是自己的JDK版本
然后看Settings中JDK版本
还是不行就将以下内容添加到pom.xml文件中properties
标签内,我的JDK版本是17.0.6,所以根据自己JDK的版本进行相应的更改。
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8maven.compiler.encoding>
<java.version>17.0.6java.version>
<maven.compiler.source>17.0.6maven.compiler.source>
<maven.compiler.target>17.0.6maven.compiler.target>
properties>
还有一种就是修改maven配置文件setting.xml,在setting.xml中添加以下信息到profiles
标签中:
也是根据自己JDK版本进行相应的更改。
<profile>
<id>jdk-17.0.6id>
<activation>
<activeByDefault>trueactiveByDefault>
<jdk>17.0.6jdk>
activation>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>17.0.6maven.compiler.source>
<maven.compiler.target>17.0.6maven.compiler.target>
properties>
profile>
顺便把setting.xml里面这个部分也改一下吧,感觉统一版本应该没什么问题
<profile>
<id>jdk-17.0.6id>
<activation>
<jdk>17.0.6jdk>
activation>
<repositories>
<repository>
<id>jdk14id>
<name>Repository for JDK 17.0.6 buildsname>
<url>http://www.myhost.com/maven/jdk14url>
<layout>defaultlayout>
<snapshotPolicy>alwayssnapshotPolicy>
repository>
repositories>
profile>
什么是MVC:Model,View,Controller;模型,视图,控制器。
用户直接访问控制层,控制层直接操作数据库;
Servlet–>CRUD–>数据库
这样程序很臃肿,不利于维护
在架构的思想中,没有什么是多加一层解决不了的一层不够再加一层JDBC也是如此!
Model:
View:
Controller(Servlet):
登陆 --> 接收用户的登陆请求 --> 处理用户的请求(获取用户登陆的参数,username、password) --> 交给业务层处理登陆业务(判断用户名和密码是否正确)–> Dao层查询用户名和密码信息是否正确 --> 数据库
Filter:过滤器,用来过滤网站的数据,后续的一些框架都会用到
导入相关依赖包
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>xyz.luck1ygroupId>
<artifactId>javaweb-filterartifactId>
<packaging>warpackaging>
<version>1.0-SNAPSHOTversion>
<name>javaweb-filter Maven Webappname>
<url>http://maven.apache.orgurl>
<dependencies>
<dependency>
<groupId>jakarta.servletgroupId>
<artifactId>jakarta.servlet-apiartifactId>
<version>6.0.0version>
dependency>
<dependency>
<groupId>javax.servlet.jsp.jstlgroupId>
<artifactId>jstl-apiartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>org.glassfish.webgroupId>
<artifactId>jakarta.servlet.jsp.jstlartifactId>
<version>2.0.0version>
dependency>
<dependency>
<groupId>org.apache.taglibsgroupId>
<artifactId>taglibs-standard-implartifactId>
<version>1.2.5version>
<scope>runtimescope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
dependencies>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8maven.compiler.encoding>
<java.version>17.0.6java.version>
<maven.compiler.source>17.0.6maven.compiler.source>
<maven.compiler.target>17.0.6maven.compiler.target>
properties>
<build>
<finalName>javaweb-filterfinalName>
build>
project>
编写过滤器,实现Filter接口,重写方法。
package xyz.luck1y.filter;
import jakarta.servlet.*;
import java.io.IOException;
public class CharacterEncodingFilter implements Filter {
// 初始化
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("过滤器初始化:");
}
/*
chain:链
1.过滤器中的所有代码,在过滤特定请求的时候都会执行
2.必须要让过滤器继续通行,固定的
filterChain.doFilter(servletRequest, servletResponse);
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html;charset=UTF-8");
System.out.println("CharacterEncodingFilter执行前......");
// 让我们的请求继续走,如果不写,程序到这里就被拦截停止了
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("CharacterEncodingFilter执行后......");
}
// 销毁: web服务关闭的时候,过滤会销毁
@Override
public void destroy() {
System.out.println("CharacterEncodingFilter已销毁");
}
}
配置web.xml中的filter
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>ShowServletservlet-name>
<servlet-class>xyz.luck1y.servlet.ShowServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>ShowServletservlet-name>
<url-pattern>/showurl-pattern>
servlet-mapping>
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>xyz.luck1y.filter.CharacterEncodingFilterfilter-class>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/servlet/*url-pattern>
filter-mapping>
web-app>
测试结果:
实现一个监听器的接口,有N种,很多~
编写一个监听器,实现监听器接口
package xyz.luck1y.listener;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;
/**
* 统计网站在线人数:统计session
*/
public class OnlineCountListener implements HttpSessionListener {
// 创建session监听,一举一动
// 一旦创建一个session,就会触发一次这个事件
@Override
public void sessionCreated(HttpSessionEvent se) {
ServletContext ctx = se.getSession().getServletContext();
System.out.println(se.getSession().getId());
Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
if (onlineCount == null) {
onlineCount = new Integer(1);
} else {
int count = onlineCount.intValue();
onlineCount = new Integer(count + 1);
}
ctx.setAttribute("OnlineCount", onlineCount);
}
// 销毁session监听
// 一旦销毁session,就会触发一次这个事件
@Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext ctx = se.getSession().getServletContext();
System.out.println(se.getSession().getId());
Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
if (onlineCount == null) {
onlineCount = new Integer(0);
} else {
int count = onlineCount.intValue();
onlineCount = new Integer(count - 1);
}
ctx.setAttribute("OnlineCount", onlineCount);
}
/*
Session销毁:
1.手动销毁
se.getSession().invalidate();
2.自动销毁
1
*/
}
配置监听器,在web.xml中
<listener>
<listener-class>xyz.luck1y.listener.OnlineCountListenerlistener-class>
listener>
<session-config>
<session-timeout>1session-timeout>
session-config>
可以配置自动销毁
看情况是否使用,一般不怎么用。
监听器:GUI编程中经常使用
package xyz.luck1y.listener;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class TestPane1 {
public static void main(String[] args) {
// 新建一个窗体
Frame frame = new Frame("为爱发电!");
// 面板
Panel panel = new Panel(null);
// 设置窗体的布局
frame.setLayout(null);
frame.setBounds(300, 300, 500, 500);
// 设置背景颜色
frame.setBackground(new Color(0, 0, 255));
panel.setBounds(50, 50, 300, 300);
panel.setBackground(new Color(0, 255, 0));
frame.add(panel);
frame.setVisible(true);
// 监听事件,监听关闭事件
frame.addWindowListener(new WindowListener() {
@Override
public void windowOpened(WindowEvent e) {
System.out.println("打开");
}
@Override
public void windowClosing(WindowEvent e) {
System.out.println("关闭中");
// 0和其他非0的int参数的区别:0是正常终止,其他为异常终止,根据情况使用,结合 try catch
System.exit(1);
}
@Override
public void windowClosed(WindowEvent e) {
System.out.println("已关闭");
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowActivated(WindowEvent e) {
System.out.println("已激活");
}
@Override
public void windowDeactivated(WindowEvent e) {
System.out.println("未激活");
}
});
// 适配器模式:只需要重写一个子类即可
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
实现登录监听
场景:用户登录之后才能进入主页!用户注销之后就不能进入主页了。
登录页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
登陆页
登陆
主页(登录成功):
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
主页
<%-- 就在jsp这实现了,使用过滤器
<%
Object userSession = request.getSession().getAttribute("USER_SESSION");
if (userSession == null) {
response.sendRedirect("/login.jsp");
}
%>
--%>
主页
错误页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
错误
错误
没有权限,用户名错误
返回登录页面
登录Servlet:
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取前端请求的参数
String username = req.getParameter("username");
if (username.equals("admin")) {
// 登陆成功
req.getSession().setAttribute("USER_SESSION", req.getSession().getId());
resp.sendRedirect("/sys/success.jsp");
} else {
// 登陆失败
resp.sendRedirect("/error.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注销Servlet:
package xyz.luck1y.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object user_session = req.getSession().getAttribute("USER_SESSION");
if (user_session != null) {
req.getSession().removeAttribute("USER_SESSION");
resp.sendRedirect("/login.jsp");
} else {
resp.sendRedirect("/login.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
过滤器:
package xyz.luck1y.filter;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SysFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (request.getSession().getAttribute("USER_SESSION") == null) {
response.sendRedirect("/login.jsp");
}
filterChain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
常量类:
package xyz.luck1y.util;
public class Constant {
// 这样写后面需要改动时直接到这改,一次即可全部修改
public static final String USER_SESSION = "USER_SESSION";
}
web.xml:
<servlet>
<servlet-name>LoginServletservlet-name>
<servlet-class>xyz.luck1y.servlet.LoginServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>LoginServletservlet-name>
<url-pattern>/servlet/loginurl-pattern>
servlet-mapping>
<servlet>
<servlet-name>LogoutServletservlet-name>
<servlet-class>xyz.luck1y.servlet.LogoutServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>LogoutServletservlet-name>
<url-pattern>/servlet/logouturl-pattern>
servlet-mapping>
<filter>
<filter-name>SysFilterfilter-name>
<filter-class>xyz.luck1y.filter.SysFilterfilter-class>
filter>
<filter-mapping>
<filter-name>SysFilterfilter-name>
<url-pattern>/sys/*url-pattern>
filter-mapping>
总结:
具体可以回顾MySQL笔记
JDBC:Java DataBase Connection;Java连接数据库
需要jar包的支持:
环境搭建:
创建数据库表
CREATE TABLE users(
id INT(10) PRIMARY KEY NOT NULL AUTO_INCREMENT,
`name` VARCHAR(40) NOT NULL,
`password` VARCHAR(40) NOT NULL,
email VARCHAR(60),
birthday DATE
)ENGINE=INNODB CHARSET=utf8;
INSERT INTO users(id, `name`, `password`, email, birthday)
VALUES (1,'张三','123456','zs@123','2001-10-5');
INSERT INTO users(id, `name`, `password`, email, birthday)
VALUES (2,'李四','123456','ls@123','2001-01-5');
INSERT INTO users(id, `name`, `password`, email, birthday)
VALUES (3,'王五','123456','ww@123','2001-02-15');
SELECT * FROM users;
导入包
连接数据库
勾选数据库
看见表了说明连接成功
web.xml导入依赖包
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>xyz.luck1ygroupId>
<artifactId>javaweb-jdbcartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
dependencies>
<properties>
<maven.compiler.source>17maven.compiler.source>
<maven.compiler.target>17maven.compiler.target>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
project>
编写JDBC程序
普通Statement对象:
package xyz.luck1y.test;
import java.sql.*;
public class TestJdbc {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 配置信息
// useUnicode=true&characterEncoding=utf8 解决中文乱码
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC";
String username = "root";
String password = "123456";
// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.连接数据库,conn可以理解为数据库;conn代表数据库
Connection conn = DriverManager.getConnection(url, username, password);
// 3.向数据库发送sql的对象
Statement statement = conn.createStatement();
// 4.编写SQL
String sql = "select * from users;";
// String sql = "delete from users where id = 4;";
// 受影响的行数,增删改都使用executeUpdate即可
// int i = statement.executeUpdate(sql);
// 5.执行查询SQL,返回结果集
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println("id:" + resultSet.getObject("id"));
System.out.println("name:" + resultSet.getObject("name"));
System.out.println("password:" + resultSet.getObject("password"));
System.out.println("email:" + resultSet.getObject("email"));
System.out.println("birthday:" + resultSet.getObject("birthday"));
}
// 6.关闭连接,释放资源,先开后关
resultSet.close();
statement.close();
conn.close();
}
}
JDBC固定步骤:
预编译PrepareStatement对象(防止SQL注入):
package xyz.luck1y.test;
import java.sql.*;
public class TestJdbc2 {
public static void main(String[] args) throws Exception{
// 配置信息
// useUnicode=true&characterEncoding=utf8 解决中文乱码
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC";
String username = "root";
String password = "123456";
// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.连接数据库,conn可以理解为数据库;conn代表数据库
Connection conn = DriverManager.getConnection(url, username, password);
// 3.编写SQL
String sql = "insert into users(id, name, password, email, birthday) values (?,?,?,?,?);";
// 4.预编译
PreparedStatement preparedStatement = conn.prepareStatement(sql);
// 给第一个占位符 ? 的值赋值为 1
preparedStatement.setInt(1, 4);
// 给第二个占位符 ? 的值赋值为 1
preparedStatement.setString(2, "刘子");
// 给第三个占位符 ? 的值赋值为 1
preparedStatement.setString(3, "123456");
// 给第四个占位符 ? 的值赋值为 1
preparedStatement.setString(4, "[email protected]");
// 给第五个占位符 ? 的值赋值为 1
preparedStatement.setDate(5, new Date(new java.util.Date().getTime()));
// 5.执行SQL
int i = preparedStatement.executeUpdate();
if (i > 0) {
System.out.println("插入成功!");
}
// 6.关闭连接,释放资源,先开后关
preparedStatement.close();
conn.close();
}
}
事务
要么都成功,要么都失败~
ACID原则:保证数据的安全
经典转账例子,查看MySQL事务笔记即可~
事务、索引、权限管理和备份_Luck1y的博客-CSDN博客
单元测试Junit
如果需要测试一个方法,我们一般都要在main方法里新建这个方法的类的一个对象,然后用这个对象调用要测试的方法。
导入junit依赖:
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.1version>
dependency>
单元测试:
package xyz.luck1y.test;
import org.junit.Test;
public class TestJdbc3 {
// 不需要写main方法就可以执行测试结果
@Test
public void test() {
// 测试内容
System.out.println("Hello");
}
}
注解内容:
package org.junit;
import org.junit.function.ThrowingRunnable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 声明运行时有效
@Retention(RetentionPolicy.RUNTIME)
// 声明该注解只在方法上有效
@Target({ElementType.METHOD})
public @interface Test {
/**
* Default empty exception.
*/
static class None extends Throwable {
private static final long serialVersionUID = 1L;
private None() {
}
}
Class<? extends Throwable> expected() default None.class;
long timeout() default 0L;
}
失败时状态:
成功时状态: