1.基本概念
Web开发
-
静态网页
- 提供给所有人看的数据始终不会发生变化
-
动态网页
- 提供给所有人看的数据始终会发生变化,每个人在不同的时间,不同的地点看到的信息各不相同。
在java中,动态Web资源开发的技术统称为javaWeb。
web应用程序:可以提供浏览器访问的程序;
a.html、b.html.….多个web资源,这些web资源可以被外界访问,对外界提供服务;们能访问到的任何一个页面或者资源,都存在于这个世界的某一个角落的计算机上。
URL 即统一资源定位符,它是用来表示互联网上的某个资源地址,互联网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。URL 最初是由蒂姆·伯纳斯·李发明的,并使用它作为万维网的地址,现在它已经被万维网联盟编制为互联网标准 RFC1738。
静态Web
在网站设计中,纯粹HTML格式的网页通常被称为“静态网页”,静态网页是标准的HTML文件,它的文件扩展名是.htm、.html,可以包含文本、图像、声音、flash动画、客户端脚本和ActiveX控件及JAVA小程序等。
静态网页是网站建设的基础,早期的网站一般都是由静态网页制作的。静态网页是相对于动态网页而言,是指没有后台数据库、不含程序和不可交互的网页。静态网页相对更新起来比较麻烦,适用于一般更新较少的展示型网站。
容易误解的是静态页面都是htm这类页面,实际上静态也不是完全静态,他也可以出现各种动态的效果,如GIF格式的动画、FLASH、滚动字幕等。
动态Web
所谓的动态网页,是指跟静态网页相对的一种网页编程技术。静态网页,随着html代码的生成,页面的内容和显示效果就基本上不会发生变化了——除非你修改页面代码。而动态网页则不然,页面代码虽然没有变,但是显示的内容却是可以随着时间、环境或者数据库操作的结果而发生改变的。
缺点
- 加入服务器的动态Web资源出现了错误,我们需要重新编写我们的后台程序,重新发布。
优点
- Web页面可以动态更新。
- 它可以和数据库交互(数据持久化:注册,商品信息,用户信息………)
2.web服务器
技术讲解
ASP即Active Server Pages,是Microsoft公司开发的服务器端脚本环境,可用来创建动态交互式网页并建立强大的web应用程序。当服务器收到对ASP文件的请求时,它会处理包含在用于构建发送给浏览器的HTML(Hyper Text Markup Language,超文本标记语言)网页文件中的服务器端脚本代码。除服务器端脚本代码外,ASP文件也可以包含文本、HTML(包括相关的客户端脚本)和com组件调用
php(PHP: Hypertext Preprocessor)即“超文本预处理器”,是在服务器端执行的脚本语言,尤其适用于Web开发并可嵌入HTML中。PHP语法学习了C语言,吸纳java和rerl多个语言的特色发展出自己的特色语法,并根据它们的长项持续改进提升自己,无法承载大访问量的情况。
JSP/Servlet
B/S: 浏览和服务器 C/S:客户端和服务器
sun公司主推的B/S架构。基于java语言的,可以承载三高问题带来的影响,语法像ASP,加强市场强度。
Web服务器
Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,可以处理浏览器等Web客户端的请求并返回相应响应,也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载。最主流的三个Web服务器是Apache、 Nginx 、IIS。
Tomcat
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。因为Tomcat 技术先进、性能稳定,而且免费,
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,是最优选。
Tomcat最新版本为10.0.14。
Tomcat安装
官网:https://tomcat.apache.org/download-90.cgi
步骤一:下载
步骤二:解压
启动和配置
启动、关闭Tomcat
启动:
关闭:
访问测试:http://localhost:8080/
配置
可以配置启动的端口号
- tomcat的默认端口号为:8080
- mysql:3306
- http:80
- https:443
<Connector port="8081" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
可以配置主机的名称
- 默认的主机名为:localhost->127.0.0.1
- 默认网站应用存放的位置为:webapps
<Host name="www.qinjiang.com" appBase="webapps"
unpackWARs="true" autoDeploy="true">
访问网站是如何进行访问的?
- 输入一个域名,回车。
- 检查本机的C:\Windows\System32\drivers\etc\hosts配置文件下有没有这个域名映射;
- 有,直接返回对应的ip地址,这个地址中,有我们需要访问的web程序,可以直接访问
- 没有,去DNS服务器找,找到的话就返回,找不到就返回找不到;
3.Http
什么是Http
超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。
- 文本:html,字符串,…
- 超文本:图片,音乐,视频,定位,地图.……
- 80
https: 安全的
- 443
两个时代
http1.0 客户端可以与Web服务器连接后,只能获得一个Web资源,断开连接。
http1.1 客户端可以与Web服务器连接后,可以获得多个Web资源。
http请求
- 客户端–发请求(Request)–服务器
百度:
Request URL:https://www.baidu.com/ 请求地址
Request Method:GET get方法/post方法
Status Code:200 OK 状态码:200
Remote(远程) Address:14.215.177.39:443
Accept:text/html
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.9 语言
Cache-Control:max-age=0
Connection:keep-alive
1、请求行
请求行中的请求方式:GET
请求方式:Get,Post,HEAD,DELETE,PUT,TRACT.…
- get:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全,但高效
- post:请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效。
2. 消息头
Accept:告诉浏览器,它所支持的数据类型
Accept-Encoding:支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1
Accept-Language:告诉浏览器,它的语言环境
Cache-Control:缓存控制
Connection:告诉浏览器,请求完成是断开还是保持连接
HOST:主机..../.
Http响应
Cache-Control:private 缓存控制
Connection:Keep-Alive 连接
Content-Encoding:gzip 编码
Content-Type:text/html 类型
1. 响应体
Accept:告诉浏览器,它所支持的数据类型
Accept-Encoding:支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1
Accept-Language:告诉浏览器,它的语言环境
Cache-Control:缓存控制
Connection:告诉浏览器,请求完成是断开还是保持连接
HOST:主机..../.
Refresh:告诉客户端,多久刷新一次;
Location:让网页重新定位;
2. 相应状态码
200:请求相应成功
3xx:请求重定向
- 重定向:你重新到我给你的新位置去
4xx:找不到资源
5xx:服务器代码错误 502:网关错误
当你的浏览器中地址栏输入地址并回车的一瞬间到页面能够展示回来,经历了什么?
-
域名解析
-
发起TCP的三次握手
-
建立起TCP连接后发起http请求
-
服务器响应http请求,浏览器得到html代码
-
浏览器解析html代码,并请求html代码中的资源(css JavaScript 图片)
-
浏览器对页面进行渲染呈现
4.Maven
我们为什么要学习这个技术?
- 在java开发中,需要使用大量的jar包,我们需要手动导入。
- Maven 自动帮我们导入和配置这些jar包。
Maven 项目架构管理工具
我们目前用来就是方便导入jar包的!
Maven 的核心思想:约定大于配置
- 有约束,不要去违反。
下载安装Maven
https://maven.apache.org/download.cgi
下载完成后,解压即可;
配置环境变量
在高级系统设置-环境变量中配置
- MAVEN_HOME maven的目录
- 在系统的path中配置 %MAVEN_HOME%\bin
测试Mavne是否安装成功
阿里云镜像
在conf中配置
镜像:mirrors 作用:加速我们的下载
国内建议使用阿里云镜像
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*</mirrorOf>
<name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
本地仓库
建立一个本地仓库:localRepository
确定maven-repo的地址,将其粘到中。
<localRepository>F:\Maven\apache-maven-3.8.6\maven-repo</localRepository>
在IDEA中使用Maven
- 启动IDEA
- 创建一个MavenWeb项目
- 等待项目初始化完毕
- IDEA中的Maven设置
IDEA项目创建成功后,看一眼Maven的配置。
创建一个普通的MAVEN项目
标记文件夹功能
方式一:
方式二:
在IDEA中配置Tomcat
解决警告问题:
我们访问一个网站,需要制定一个文件夹名字。
pom文件
pom.xml 是Maven的核心配置文件
maven由于约定大于配置,配置文件无法导出或生效的问题,解救办法:
<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
5.Servlet
Servlet就是sun公司开发动态web的一门技术.Sun在这些API中提供一个接口叫做:Servlet
如果开发一个Servlet程序,只需要完成两个小步骤:
- 编写一个类,实现Servlet接口。
- 把开发好的Java类部署到Web服务器中。
把实现了Servlet接口的Java程序叫做,Servlet。
HelloServlet
Servlet接口Sun公司有两个默认的实现类:HttpServlet,GenericServlet
1. 构建一个普通的Maven项目,删掉里面的src目录,以后的项目建立Moudel(使用模板)。
在pom中导入依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
2. 关于Maven父子工程的理解
父项目中会有
<modules>
<module>servlet-01</module>
</modules>
子项目中会有
<parent>
<artifactId>Java-01-maven03</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
父项目中的jar,子项目可以直接使用
3. Maven 环境优化
修改WEB-INF下的web.xml为最新的
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
</web-app>
4. 编写一个Servlet程序
public class HelloServlet extends HttpServlet {
//由于get或者post只是请求实现的不同的方式,可以相互调用,业务逻辑都一样。
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//ServletOutputStream outputStream = resp.getOutputStream();
System.out.println("调用了doPost方法");
PrintWriter writer = resp.getWriter();
writer.print("Hello servlet");
}
}
5. 重写Servlet的映射
为何需要映射? 我们写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器, 所以我们 需要在web服务中注册我们写的Servlet,还需要给他一个浏览器访问的路径。
<!--注册Servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.taiyuan.servlet.HelloServlet</servlet-class>
</servlet>
<!--Servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
6. 配置Tomcat, 启动测试
Servlet原理
当Web服务器接收到一个HTTP请求时,它会先判断请求内容——如果是静态网页数据,Web服务器将会自行处理,然后产生响应信息;如果牵涉到动态数据,Web服务器会将请求转交给Servlet容器。此时Servlet容器会找到对应的处理该请求的Servlet实例来处理,结果会送回Web服务器,再由Web服务器传回用户端。
针对同一个Servlet,Servlet容器会在第一次收到http请求时建立一个Servlet实例,然后启动一个线程。第二次收到http请求时,Servlet容器无须建立相同的Servlet实例,而是启动第二个线程来服务客户端请求。所以多线程方式不但可以提高Web应用程序的执行效率,也可以降低Web服务器的系统负担。
Mapping问题
1. 一个Servlet可以确定一个映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
2.一个Servlet可以指定多个映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello3</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello4</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello5</url-pattern>
</servlet-mapping>
3.一个Servlet可以指定通用映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
4.默认请求路径
<!--默认请求路径,优先级高于index.jsp,尽量不使用默认请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
5.指定后缀或前缀
<!--可以自定义后缀实现请求映射
注意点,*前面不能加项目映射的路径
hello/sajdlkajda.qinjiang
-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.qinjiang</url-pattern>
</servlet-mapping>
6.优先级问题
指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求。
//编写ErrorServlet,自定义404
public class ErrorServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
writer.print("<h1>404</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
<!-- servlet注册 404 -->
<servlet>
<servlet-name>404</servlet-name>
<servlet-class>com.taiyuan.servlet.ErrorServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>404</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
ServletContext
web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用;
数据共享
1.在这个Servlet中保存的数据,可以在例外一个Servlet中拿到。
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//this.getInitParameter() 初始化参数
//this.getServletConfig() Servlet配置
//this.getServletContext() Servlet上下文
ServletContext servletContext = this.getServletContext();
//数据
String username = "陈培学";
//将一个数据保存在了ServletContext中,名字为:username 。值 username
servletContext.setAttribute("username",username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2.编写GetServlet类,获取HelloServlet中的数据:
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String username = (String)servletContext.getAttribute("username");
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().print(username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
3.注册Servlet
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.taiyuan.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getc</servlet-name>
<servlet-class>com.taiyuan.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getc</servlet-name>
<url-pattern>/getc</url-pattern>
</servlet-mapping>
4.测试访问结果;
获取初始化参数
1.在web.xml中配置
<!--配置一些web应用初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
2.编写Getinfo类后,初始化参数
public class Getinfo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String url = servletContext.getInitParameter("url");
resp.getWriter().print(url);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
3.注册Servlet
<servlet>
<servlet-name>gp</servlet-name>
<servlet-class>com.taiyuan.servlet.Getinfo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gp</servlet-name>
<url-pattern>/gp</url-pattern>
</servlet-mapping>
4.测试
请求转发
步骤
- 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
- 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
1.编写Servlet类,实现请求转发
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
System.out.println("进入了ServletDemo04");
//RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp"); //转发的请求路径
//requestDispatcher.forward(req,resp); //调用forward实现请求转发;
context.getRequestDispatcher("/gp").forward(req,resp);
}
2.注册Servlet
<servlet>
<servlet-name>Dispatcher</servlet-name>
<servlet-class>com.taiyuan.servlet.ServletDemo04</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Dispatcher</servlet-name>
<url-pattern>/Dispatcher</url-pattern>
</servlet-mapping>
3.测试
读取资源文件
1.在resources下新建db.properties
username=root12312
password=zxczxczxc
在java目录下新建properties
发现:都被打包到了同一个路径下:classes,我们俗称这个路径为classpath:
1.编写ServletDemo05类,读取资源文件
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//"/WEB-INF/classes/com/kuang/servlet/aa.properties"的第一个/ 不能省略,他代表我们的当前web项目
InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/kuang/servlet/aa.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);
}
}
2.注册Servlet
<servlet>
<servlet-name>getResourceAsStream</servlet-name>
<servlet-class>com.taiyuan.servlet.ServletDemo05</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getResourceAsStream</servlet-name>
<url-pattern>/getResourceAsStream</url-pattern>
</servlet-mapping>
3.测试
6.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 setDateHeader(String var1, long var2);
void addDateHeader(String var1, long var2);
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
响应状态码
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;
文件下载
1.编写FileServlet类
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.读取文件路径
String realPath = "D:\\programme\\java\\Java-01-maven03\\response-01\\target\\classes\\1.png";
System.out.println("下载的路径:"+realPath);
//2.下载的文件名
String filename = realPath.substring(realPath.lastIndexOf("\\") + 1);
//3. 设置想办法让浏览器能够支持(Content-Disposition)下载我们需要的东西,中文文件名URLEncoder.encode编码,否则有可能乱码
//resp.setHeader("Content-Disposition","attachment;filename="+URLEncoder.encode(fileName,"UTF-8"));
//Disposition:配置 attachment 附件
resp.setHeader("Content-Disposition","attachment;filename="+filename);
//4.获取下载文件的输入流
FileInputStream fileInputStream = new FileInputStream(realPath);
//5.设置缓冲区
int len =0;
byte[] buffer = new byte[1024];
//6.获取OutputStream对象
ServletOutputStream out = resp.getOutputStream();
//7.将FileinputStream流写入缓冲区,用OutPutStream将数据输出到客户端
while ((len= fileInputStream.read(buffer))>0){
out.write(buffer,0,len);
}
fileInputStream.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2.注册Servlet
3.测试
验证码功能
1.编写ImageServlet类
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//如何让浏览器3秒自动刷新一次;
resp.setHeader("refresh","3");
//在内存中创建一个图片
BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
//得到图片
Graphics2D g = (Graphics2D) image.getGraphics(); //笔
//设置图片的背景颜色
g.setColor(Color.white);
g.fillRect(0,0,80,20);
//给图片写数据
g.setColor(Color.BLUE);
g.setFont(new Font(null,Font.BOLD,20));
g.drawString(makeNum(),0,20);
//告诉浏览器,这个请求用图片的方式打开
resp.setContentType("image/jpeg");
//网站存在缓存,不让浏览器缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");
//把图片写给浏览器
ImageIO.write(image,"jpg", resp.getOutputStream());
}
//生成随机数
private String makeNum(){
Random random = new Random();
String num = random.nextInt(9999999) + "";
StringBuffer sb = new StringBuffer();
//保证随机数为7位数
for (int i = 0; i < 7-num.length() ; i++) {
sb.append("0");
}
num = sb.toString() + num;
return num;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2.注册Servlet
<servlet>
<servlet-name>ImageServlet</servlet-name>
<servlet-class>com.kuang.servlet.ImageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Imageservlet</servlet-name>
<url-pattern>/img</url-pattern>
</servlet-mapping>
3.测试
重定向【重要】
常见场景:
- 用户登录
void sendRedirect(String var1) throws IOException;
测试
@override
protected void doGet(HttpservletRequest req, HttpservletResponse resp) throws ServletException, IOException {
resp. sendRedirect("/r/img");//重定向
/*
resp. setHeader("Location","/r/img");
resp. setstatus (302);
*
}
面试题:请你聊聊重定向和转发的区别
相同点:页面都会跳转
转发和重定向的区别是:
1、请求次数不同;重定向是浏览器向服务器发送一个请求并收到响应后再次向一个新地址发出请求,转发是服务器收到请求后为了完成响应跳转到一个新的地址;重定向至少请求两次,转发请求一次;
2、重定向时地址栏会发生变化,而转发时地址栏不会发生变化;
3、重定向两次请求不共享数据,转发一次请求共享数据。
4、跳转限制: 重定向可以跳转到任意URL,转发只能跳转本站点资源;
5、发生行为不同: 重定向是客户端行为,转发是服务器端行为;
index.jsp
<html>
<body>
<h2>Hel1o World!</h2>
《%--这里超交的路径,需要寻找到项目的路径--%>
<%--${pageContext. request, contextPath}代表当前的项目--%>
<form action="${pageContext. request.contextPath}/login" method="get">
用户名: <input type="text" name="username"> <br>
密码: <input type="password" name="password"> <br>
<input type="submit">
</form>
</body>
</html>
编写RequsetTest类
public class RequsetTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入这个请求");
resp.getWriter().print("success");
String username = req.getParameter("username");
String passward = req.getParameter("passward");
System.out.println(username+passward);
resp.sendRedirect("/r1/success.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注册Servlet
<servlet>
<servlet-name>requset</servlet-name>
<servlet-class>com.taiyuan.servlet.RequsetTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>requset</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
重定向页面success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Success</h1>
</body>
</html>
7.HttpServletRequst
httpServletRequset代表客户端的请求,用户用过http协议来访问服务器,Http请求中的所有信息会被封装到httpServletRequset,通过这个httpServletRequset的方法,获得客户端的所有信息。
获取前端参数, 请求转发
public class RequsetTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入这个请求");
req. setcharacterEncoding("utf-8");
resp.setcharacterEncoding("utf-8");
String username = req.getParameter("username");
String passward = req.getParameter("passward");
String[] hobbys = req.getParameterValues("hobbies");
System.out.println(username+passward);
System.out.println(Arrays.tostring(hobby));
resp.sendRedirect("/r1/success.jsp");
//请求转发
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
index.jsp
<html>
<body>
<h2>Hello World!</h2>
<h1>登录</h1>
<div style="text-align: center">
<form action="${pageContext.request.contextPath}/login" method="post">
用户名:<input type="username" name="username"><br>
密码:<input type="password" name="password"><br>
爱好:<input type="checkbox" name="hobbies" value="girl">
<input type="checkbox" name="hobbies" value="car">
<input type="checkbox" name="hobbies" value="apple">
<input type="checkbox" name="hobbies" value="books">
<br>
登录:<input type="submit">
</form>
</div>
</body>
</html>
success.jsp
<html>
<body>
<h2>Hello World!</h2>
<h1>登录成功</h1>
</body>
</html>
8.Cookie\Session
会话:用户打开了一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话。
有状态会话:一个同学来过教室,下次再来教室,我们会知道他来过。
一个网站,怎么证明你来过?
客户端 服务端
- 服务端给客户端一个信件,客户端下次访问服务器带上信件就可。(cookie)
- 服务器登记你来过,下次你来的时候我来匹配你。(session)
Cookie
工作原理
(1)浏览器端第一次发送请求到服务器端
(2)服务器端创建Cookie,该Cookie中包含用户的信息,然后将该Cookie发送到浏览器端
(3)浏览器端再次访问服务器端时会携带服务器端创建的Cookie
(4)服务器端通过Cookie中携带的数据区分不同的用户
1. 编写CookieDemo01类
public class CookieDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决中文乱码问题
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
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];
if("lastLoginTime".equals(cookie.getName())){
long l = Long.parseLong(cookie.getValue());
Date date = new Date(l);
out.write(date.toLocaleString());
}
}
}else{
out.write("这是第一次访问浏览器");
}
//服务给客户响应
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
//有效期为1天——不安全
cookie.setMaxAge(24*60*60);
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2.注册Servlet
3.测试
cookie:一般会保存在本地的 用户目录下 appdata;
一个网站cookie是否存在上限!细节问题
- 一个Cookie只能保存一个信息
- 不同浏览器所含cookie的最大个数不同,一般30到50个
- Cookie 大小有限制 3kb
删除Cookie
- 不设置有效期,关闭浏览器,自动失败。
- 设置有效期时间为0。
编码解码
URLEncoder.encode("秦疆","utf-8")
URLDecoder.decode(cookie.getValue(),"UTF-8")
Session(重点)
(1)浏览器端第一次发送请求到服务器端,服务器端创建一个Session,同时会创建一个特殊的Cookie(name为JSESSIONID的固定值,value为session对象的ID),然后将该Cookie发送至浏览器端
(2)浏览器端发送第N(N>1)次请求到服务器端,浏览器端访问服务器端时就会携带该name为JSESSIONID的Cookie对象
(3)服务器端根据name为JSESSIONID的Cookie的value(sessionId),去查询Session对象,从而区分不同用户。
name为JSESSIONID的Cookie不存在(关闭或更换浏览器),返回1中重新去创建Session与特殊的Cookie
name为JSESSIONID的Cookie存在,根据value中的SessionId去寻找session对象
value为SessionId不存在**(Session对象默认存活30分钟)**,返回1中重新去创建Session与特殊的Cookie
value为SessionId存在,返回session对象
1.编写实体类
2.编写SessionDemo01类
public class SessionDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码问题
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;chatest=utf-8");
//得到Session
HttpSession session = req.getSession();
//给Session中存东西
session.setAttribute("name",new Person("秦疆",1));
//获取Session的ID
String sessionId = session.getId();
//判断Session是不是新创建
if(session.isNew()){
resp.getWriter().write("Session创建成功 ID:"+sessionId);
}else{
resp.getWriter().write("Session已存在 ID:"+sessionId);
}
//Session创建的时候做了什么事情;
// Cookie cookie = new Cookie("JSESSIONID",sessionId);
// resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
3.编写SessionDemo02类
public class SessionDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码问题
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;chatest=utf-8");
//得到Session
HttpSession session = req.getSession();
Person person = (Person)session.getAttribute("name");
System.out.println(person.toString());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
4.注册Servlet
5.测试
Session注销
HttpSession session = req.getSession();
session.removeAttribute("name");
//手动注销Session
session.invalidate();
会话自动过期:web.xml配置
<!--设置Session默认的失效时间-->
<session-config>
<!--15分钟后Session自动失效,以分钟为单位-->
<session-timeout>15</session-timeout>
</session-config>
cookie数据保存在客户端,session数据保存在服务端。
简单的说,当你登陆一个网站的时候,如果web服务器端使用的是session,那么所有的数据都保存在服务器上,客户端每次请求服务器的时候会发送当前会话sessionid,服务器根据当前sessionid判断相应的用户数据标志,以确定用户是否登陆或具有某种权限。由于数据是存储在服务器上面,所以你不能伪造。
如果浏览器使用的是cookie,那么所有数据都保存在浏览器端,比如你登陆以后,服务器设置了cookie用户名,那么当你再次请求服务器的时候,浏览器会将用户名一块发送给服务器,这些变量有一定的特殊标记。服务器会解释为cookie变量,所以只要不关闭浏览器,那么cookie变量一直是有效的,所以能够保证长时间不掉线。
如果你能够截获某个用户的cookie变量,然后伪造一个数据包发送过去,那么服务器还是 认为你是合法的。所以,使用cookie被攻击的可能性比较大。
cookie和session区别对比:
作用范围不同: cookie数据存放在客户的浏览器上,session数据放在服务器上
存取方式的不同: Cookie 只能保存 ASCII,Session 可以存任意数据类型,
隐私策略不同: cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,Session 存储在服务端,如果主要考虑到安全应当使用session
session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用COOKIE
单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K。Session 可存储数据远高于 Cookie。
9.JSP
什么是jsp?java Server Pages :java 服务器端动态页面,也和Servlet一样,用于动态Web技术。
特点:写的像HTML 区别: HTML只能给用户提供静态的数据, jsp页面中可以嵌入java 代码,为用户提供动态数据
jsp原理
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet
- 客户端发出请求,请求为JSP,web容器就会找出相应的servlet进行处理
- 将servlet转成字节码文件
- 将字节码文件加载到web容器里
- 这时会在web容器里建立实例
- 进行初始化
- 通过service接受请求
- 然后web容器会自动产生两个对象servlet和service最后进行销毁
jsp基础语法
jsp 表达式
<html>
<body>
<h2>Hello World!</h2>
<%--JSP表达式--%>
<%=new java.util.Date()%>
</body>
</html>
jsp脚本片段
<%
int i =0;
for (int j = 0; j <100 ; j++) {
i+=j;
}
out.write("<h1>i="+i+"</h1>");
%>
脚本片段的再实现
<%
int x = 10;
out.println(x);
%>
<p>这是一个JSP文档</p>
<%
int y = 2;
out.println(y);
%>
<hr>
<%--在代码嵌入HTML元素--%>
<%
for (int i = 0; i < 5; i++) {
%>
<h1>Hello,World <%=i%> </h1>
<%
}
%>
JSP声明
<%!
static {
System.out.println("Loading Servlet!");
}
private int globalVar = 0;
public void kuang(){
System.out.println("进入了方法Kuang!");
}
%>
JSP声明:会被编译到JSP生成java的类中,其他的,就会被生成到JspServlet方法中。
Jsp的注释,不会在客户端显示,HTML会。
9大内置对象
- PageContext
- Request
- Response
- Session
- Application ( ServletContext)
- config (ServletConfig )
- out
- page
- exception
<%
pageContext.setAttribute("name01","陈培学01");//保存的数据只在一个页面中有效
request.setAttribute("name02","陈培学02");//保留的数据只在一次请求中有效,请求转发推荐这个数据
session.setAttribute("naem03","陈培学03");//保存的数据旨在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name04","陈培学04");//保存的数据只在服务器中有效,从打开服务器到关闭服务器
%>
10.Filler
Filler:过滤器,过滤网站的数据
- 处理中文乱码
- 登录验证
实现Filter接口
public class CharacterEconing implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化=============");
}
@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;cherest=uft-8");
System.out.println("CharacterEconing执行前");
filterChain.doFilter(servletRequest,servletResponse);//让请求继续走
System.out.println("CharacterEconing执行后");
}
@Override
public void destroy() {
System.out.println("销毁===================");
}
}
- 配置filter
<filter>
<filter-name>CharacterEconing</filter-name>
<filter-class>com.kuang.filter.CharacterEconing</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEconing</filter-name>
<!--只要是 /servlet的任何请求,会经过这个过滤器-->
<url-pattern>/servlet/*</url-pattern>
<!--<url-pattern>/*</url-pattern>-->
<!-- 别偷懒写个 /* -->
</filter-mapping>
监听器
- 实现监听器的接口
public class OnlineCountListener implements HttpSessionListener {
//创建Session监听
@Override
public void sessionCreated(HttpSessionEvent se) {
ServletContext context = se.getSession().getServletContext();
Integer count = (Integer) context.getAttribute("OnlineCount");
System.out.println(se.getSession().getId());
if(count == null){
count = new Integer(1);
}else{
int c = count.intValue();
count = new Integer(c++);
}
context.setAttribute("OnlineCount",count);
}
//销毁Session监听
@Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext context = se.getSession().getServletContext();
Integer count = (Integer) context.getAttribute("OnlineCount");
if(count == null){
count = new Integer(0);
}else{
int c = count.intValue();
count = new Integer(c--);
}
context.setAttribute("OnlineCount",count);
}
}
- 注册监听器
<listener>
<listener-class>com.taiyuan.listener.OnlineCountListener</listener-class>
</listener>
Filter实现权限拦截
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("/fail.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>SUCCESS主页</h1>
<p><a href="/servlet/loginout">注销</a></p>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Fail</h1>
<p><a href="Login.jsp">返回登录页面</a></p>
</body>
</html>
public class LoginServletOut 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){
//若Session存在,将Session移除
req.getSession().removeAttribute("USER_SESSION");
resp.sendRedirect("/Login.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
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 {
//ServletRequset HttpServletRequest
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if(request.getSession().getAttribute("USER_SESSION") == null){
response.sendRedirect("/fail.jsp");
}
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {}
}
11.JDBC
CREATE TABLE users(
id INT PRIMARY KEY,
`name` VARCHAR(40),
`password` VARCHAR(40),
email VARCHAR(60),
birthday DATE
);
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(1,"张三","1234565","zs@qq.com","2022-02-14");
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(2,"李四","1234565","ls@qq.com","2022-02-14");
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(3,"王五","1234565","ww@qq.com","2022-02-14");
SELECT * from users;
public class TestJdbc {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//配置信息
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=true";
String user ="root";
String password ="cpx147258";
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.连接数据库
Connection connection = DriverManager.getConnection(url, user, password);
//3.向数据库发送sql对象
Statement statement = connection.createStatement();
//4.编写
String sql ="select * from users";
//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"));
}
resultSet.close();
statement.close();
connection.close();
}
}