JavaWeb入门
1. 基本概念
1.1前言
web 开发:
- web,网页的意思
- 静态 web
- html,css
- 提供给所有人看的数据始终不会发生变化
- 动态 web
- 几乎所有网站
- 提供给所有人看的数据始终会发生变化,每个人看到的信息各不相同
- 技术栈:Servlet/Jsp
在 java 中,动态 web 资源开发的技术统称 javaWeb;
1.2 web 应用程序
web 应用程序:可以提供浏览器访问的程序
- index.html 等多个 web 资源可以,可以被外界访问,对外界提供服务
- 能访问到的任何一个页面或资源,都存在与某个服务器上
- 这个统一的 web 资源会被放在同一个文件夹下,web 应用程序依赖于 Tomcat 服务器
- 一个 web 应用由多部分组成(静态 web,动态 web)
- html,js,css
- jsp,servlet
- java 程序
- jar 包
- 配置文件(properties)
web 应用程序编写完毕,若要提供给外界访问:需要一个服务器统一管理
1.3 静态 web
- *.html,这些网页的后缀,如果服务器存在这些东西,我们就可以直接进行读取
- 静态 web 存在的缺点
- web 页面无法动态更新,所有用户看到都是同一个页面
- 轮播图,点击特效:伪动态
- JavaScript(实际开发用的最多)
- 无法和数据库交互(数据无法持久化,用户无法交互)
- web 页面无法动态更新,所有用户看到都是同一个页面
1.4 动态 web
页面会动态展示:web 页面效果因人而异
- 动态 web 存在缺点
- 服务器动态 web 资源出现错误,我们需要重新编写后台程序,重新发布
-
- 服务器动态 web 资源出现错误,我们需要重新编写后台程序,重新发布
- 优点
- 动态更新
- 与数据库交互(持久化)
2. web 服务器
2.1 技术介绍
ASP
- 微软:国内最早流行的 ASP
- 在 HTML 中嵌入 VB脚本,ASP+COM
- 在 ASP 开发中,一个页面就有几千行的业务代码,维护成本高
PHP
- 开发速度快,功能强大,跨平台,代码简单
- 无法承载大访问量的情况(局限性)
JSP/Servlet
- sun 公司主推 B/S(浏览器和服务器) 架构
- 基于 java 语言实现
- 可承载“三高问题”高并发,高性能,高可用
2.2 web 服务器
服务器是一种被动操作,用来处理用户的一些请求和给用户一些响应信息
Tomcat
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。
Tomcat 实际上运行JSP 页面和Servlet。具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。
3.Tomcat
3.1 Tomcat安装参考
3.2 启动和配置
文件夹作用
可以通过 server.xml,配置启动端口号,配置主机名称
高难度面试题
请你谈谈网站是如何访问的?
-
输入一个域名;回车;
-
检查本机 hosts 配置文件下有没有这个域名的映射
- 有:直接返回对应的 ip 地址,这个地址中,有我们需要访问的 web
127.0.0.1 localhost
- 没有:去 DNS 服务器找,找到就会返回,找不到返回找不到
4. Http
4.1 认识 Http
超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII形式给出;而消息内容则具有一个类似MIME的格式。
- 文本:html,字符串,
- 超文本:图片,音乐,视频,地图
- 默认端口:80
HTTPS:安全的,默认端口:403
4.2 两个时代
- http1.0
- HTTP/1.0:客户端与 web 服务器连接后,只能获得一个 web 资源,断开连接
- Http2.0
- Http/1.1:客户端可以与 web 服务器连接后,可以获得多个 web 资源
4.3 Http 请求(request)
- 客户端——发请求——服务器
Request URL: https://www.baidu.com/ 请求地址
Request Method: GET 请求方式 get,post
Status Code: 200 OK 状态码
Remote Address: 183.232.231.172:443
Accept:text/html
Accept-Encoding: gzip, deflate, br
Accept-Language: en,zh-CN;q=0.9,zh;q=0.8 语言
Cache-Control: max-age=0
Connection: keep-alive
- 请求行
- 请求行中的请求方式:Get
- 请求方式:Get,Post
- get:请求能够携带的参数比较少,大小有限制,会在浏览器 URL 地址栏显示数据内容,不安全,高效
- post:请求能够携带的参数比较少,大小没有限制,会在浏览器 URL 地址栏显示数据内容,安全,不高效
- 消息头
Accept:告诉浏览器,所支持的数据类型
Accept-Encoding: 支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1
Accept-Language: 告诉浏览器,它的语言环境
Cache-Control: 缓存控制
Connection: 告诉浏览器请求完成是断开还是保持连接
HOST:主机
4.4 Http 响应
- 服务器——响应——客户端
Cache-Control: private 缓存控制
Connection: keep-alive 连接
Content-Encoding: gzip 编码
Content-Type: text/html;charset=utf-8 类型
- 响应体
Accept:告诉浏览器,所支持的数据类型
Accept-Encoding: 支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1
Accept-Language: 告诉浏览器,它的语言环境
Cache-Control: 缓存控制
Connection: 告诉浏览器请求完成是断开还是保持连接
HOST:主机
Reflush: 告诉客户端多久刷新一次
Location:让网页重新定位
- 响应状态码
- 200 请求响应成功
- 3xx 请求重定向
- 重定向:你重新到给你新位置去
- 4xx:找不到资源
- 资源不存在 404
- 5xx:服务器代码错误 500 502 网关错误
常见面试题:
当浏览器中地址栏输入地址并回车的一瞬间到页面能够展示回来,经历什么?
5. Servlet
6.1 Servlet简介
- Servlet 是开发动态 web 的一门技术
- 在 API 中提供一个接口交:Servlet,如果想开发一个 Servlet 程序,只需要完成两个小步骤
- 编写一个类,实现 servlet
- 把开发好的 java 类部署到 web 服务器
把实现 servlet 接口的程序叫做 Servlet
6.2 HelloServlet
Servlet 有 2 个默认实现类 HttpServlet,GenericServlet
-
构建 Maven 项目,删除 src 目录,在该项目里面键 Module,空的工程就是主工程
-
关于 Maven 付工程的理解
父项目中有
<modules>
<module>servlet-01</module>
</modules>
子项目中有
<parent>
<artifactId>javaweb-01-servlet</artifactId>
<groupId>com.study</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
父项目中的 java 子项目可以直接使用,子类继承了父类
- 编写一个 Servlet 程序
- 编写一个普通类
- 实现HttpServlet接口
public class HelloServlet extends HttpServlet {
//由于 get 或 post 只是请求实现方式不一样,可以相互调用,业务逻辑都一样
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.print("Hello,Servlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
-
编写 servlet 的映射
为什么需要映射?我们写的是 java 程序,但是要通过浏览器访问,而浏览器需要连接 web 服务器,所以需要在 web 服务中心注册我们写的 servlet,还需要给一个浏览器能够访问的路径
<?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">
<!-- 注册 servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.study.servlet.HelloServlet</servlet-class>
</servlet>
<!-- servlet 的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
- 启动 tomcat
6.3 Servlet原理
6.4 Mappering
-
一个 Servlet 可以指定一个映射路径
<!-- servlet 的请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
一个 Servlet 可以指定多个映射路径
<!-- servlet 的请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <!-- servlet 的请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hell1</url-pattern> </servlet-mapping> -----
-
一个 Servlet 可以指定通用映射路径
<!-- servlet 的请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping>
-
默认请求路径
<!-- servlet 的默认请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
-
指定后缀
<!-- servlet 可以定义后缀 注意点 *前面不能加项目映射路径/ --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>*/.do</url-pattern> </servlet-mapping>
-
优先级问题
指定了固定路径优先级最高,找不到会走默认的处理(这里做了如下配置,可以正常访问/hello,其他路径走 404)
<!-- 注册 servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.study.servlet.HelloServlet</servlet-class>
</servlet>
<!-- servlet 的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<!-- 404-->
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>com.study.servlet.ErrorServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
6.5 ServletContext
web 容器在启动的时候,会为每个 web 程序创建一个对应的 ServletContext,代表了当前的 web 应用:
1.共享数据
我在这个 Servlet 中保存的数据,可以在另一个 servlet 获取
//设置 context 内容
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 s = "张三";
servletContext.setAttribute("username", s);//将一个数据保存到 servletContext 中
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
writer.print("设置成功");
}
}
//另一个 servlet 获取 context 的内容
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
ServletContext servletContext = this.getServletContext();
String username = (String) servletContext.getAttribute("username");
PrintWriter writer = resp.getWriter();
writer.print("姓名" + username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.study.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>get</servlet-name>
<servlet-class>com.study.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>get</servlet-name>
<url-pattern>/get</url-pattern>
</servlet-mapping>
测试结果
2. 获取初始化参数
public class ServletDemo1 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);
}
}
<!--web 应用初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>initParam</param-value>
</context-param>
<servlet>
<servlet-name>init</servlet-name>
<servlet-class>com.study.ServletDemo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>init</servlet-name>
<url-pattern>/init</url-pattern>
</servlet-mapping>
3. 请求转发(url不发生变化)
请求地址不会发生改变,请求的是我们设置的地址,但是响应的内容是设置请求路径/init 的内容
public class ServletDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/init");//请求转发路径
requestDispatcher.forward(req, resp);
}
}
<servlet>
<servlet-name>forward</servlet-name>
<servlet-class>com.study.ServletDemo2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>forward</servlet-name>
<url-pattern>/sd4</url-pattern>
</servlet-mapping>
4.读取资源
- 在 java 目录下新建 properties(需要配置 pom 文件,否则读取不到)
<build>
<!--默认就是卸载 resources 下,可以不用配-->
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.xml</exclude>
</excludes>
<filtering>false</filtering>
</resource>
<!--配置读取的资源路径-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
- 在 resources 目录下新建 properties(默认的无须配置 pom)
发现:都被打包到了同一个路径下:classes,我们俗称这个路径为classpath
- 读取 dbproperties 内容
public class ServletDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream is = this.getServletContext().getResourceAsStream("WEB-INF/classes/db.properties");//编译后的路径
Properties pt = new Properties();
pt.load(is);
String user = pt.getProperty("username");
String pwd = pt.getProperty("password");
resp.getWriter().print(user + ":" + pwd);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
<servlet>
<servlet-name>properties</servlet-name>
<servlet-class>com.study.ServletDemo3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>properties</servlet-name>
<url-pattern>/sd5</url-pattern>
</servlet-mapping>
6.6 HttpServletResponse
web 服务器接收到服务端的 http 请求,针对这个请求,分别创建一个代表请求的对象HttpServletRequest,和代表响应的HttpServletResponse
- 如果获取客户端请求过来的参数,找HttpServletRequest
- 如果要给客户端响应一些信息,找HttpServletResponse
1. 简单分类
负责向浏览器发送数据的方法
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的方法
//这是HttpServletResponse类方法
void setDateHeader(String var1, long var2);
void addDateHeader(String var1, long var2);
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setIntHeader(String var1, int var2);
void addIntHeader(String var1, int var2);
//这是实现接口方法
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
响应状态码
2.常见应用
下载文件
- 要获取下载文件路径
- 下载的文件名是?
- 设置浏览器支持下载我们需要的东西
- 获取下载文件的输入流
- 创建缓冲区
- 获取 OutputStream 对象
- 将 FileOutputStream 流写入到 buffer
- 将缓冲区数据输出客户端
public class ResponseDownloadDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//相对路径转绝对路径
String realPath = this.getServletContext().getRealPath("img/你好.png");
System.out.println(realPath);
//读文件
File file = new File(realPath);
FileInputStream fis = new FileInputStream(file);
byte[] bytes = new byte[1024];
int temp = 0;
//设置响应头,编码,以及中文文件名
resp.addHeader("content-disposition", "attachment;filename="+ URLEncoder.encode(file.getName(),"UTF-8"));
//输出
ServletOutputStream os = resp.getOutputStream();
while ((temp=fis.read(bytes))!=-1){
os.write(temp);
}
os.flush();
os.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
<servlet>
<servlet-name>filedown</servlet-name>
<servlet-class>com.study.ResponseDownloadDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>filedown</servlet-name>
<url-pattern>/down</url-pattern>
</servlet-mapping>
实现重定向(url 发生变化)
一个 web 资源受到客户端请求后,会通知客户端去访问另一个web 资源 ,url 发生变化,这个过程是重定向
常用场景;
- 用户登录
resp.sendRedirect("/s3/down");//重定向
面试题:重定向和转发的区别
-
相同点
页面都会跳转
-
不同点
请求转发 URL 不会产生变化 状态码200
重定向 URL 会发生变化 状态码302
6.7 HttpServletRequest
HttpServletRequest代表客户端的请求,用户通过 Http 协议访问服务器,HTTP 请求中的所有信息会被封装到 HttpServletRequest,通过这个HttpServletRequest的方法,获得客户端所有信息。
1.获取客户端传递参数
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String[] likes = req.getParameterValues("like");
for (String like : likes) {
System.out.println(username + "的爱好有:" + like);
}
// resp.sendRedirect("/s4/success.jsp");//这里需要加/s4
//这里/代表当前的 web 应用
req.getRequestDispatcher("/success.jsp").forward(req, resp);
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<h1>登录</h1>
<div>
<%-- 获取绝对路径,%> --%>
<form action="${pageContext.request.contextPath}/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="text" name="password"><br>
爱好:
<input type="checkbox" name="like" value="music">音乐 <br>
<input type="checkbox" name="like" value="sport">运动 <br>
<input type="checkbox" name="like" value="eat">代码 <br>
<input type="submit" >
</form>
</div>
</body>
</html>
<?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">
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.study.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
6. Session、Cookie
6.1 会话
会话:用户打开一个浏览器,点击很多超链接,访问多个web 资源,关闭浏览器,这个过程称为会话
6.2 保存会话两种技术
cookie
- cookie 是客户端技术(响应,请求)
session
- 服务器技术,利用这个技术,可保存用户的会话信息。我们可以把信息或数据放入 Session 中
常见场景:网站登录之后,下次不用在登录了
6.3 Cookie
- 请求中拿到 cookie
- 服务器响应给客户端 cookie
//保存用户上一次访问的时间
public class CookieDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决中文乱码
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
//cookie,服务器端从客户端获取
Cookie[] cookies = req.getCookies();//说明 cookie 存在多个
//判断 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 的值
String value = cookie.getValue();
long lastLoginTime = Long.parseLong(value);//将字符串转数字
Date date = new Date(lastLoginTime);
out.write(date.toLocaleString());
}
}
} else {
out.write("这是你第一次访问网站");//第一次进入没有 cookie
}
//服务端给客户端响应一个 cookie
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
//设置 cookie 有效期 1 天
cookie.setMaxAge(60*60*24);
//服务端响应给客户端 cookie
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
cookie 细节
- 一个 cookie 只能保存一个信息
- 一个 web站点可以给浏览器发送多少个 cookie,最多存放 20 个 cookie
- Cookie 大小有限制 4kb
- 300 个 cookie 浏览器上限
删除 cookie
- 不设置有效期,关闭浏览器,自动失效
- 设置有效期时间为 0
使用中文 cookie 解决乱码问题
URLEncoder.encode("张三", "utf-8");//编码
URLDecoder.decode("张三", "utf-8");//解码
6.4 Session(重点)
什么是 Session:
- 服务器会给每个用户(浏览器)创建一个 Session 对象
- 一个 Session 独占一个浏览器,只要一个浏览器没有关闭,这个 Session 就存在
- 用户登录之后,整个网站它都可以访问!场景:保存购物车信息
Session 和 Cookie 区别
- Cookie 是把用户的数据写给用户的浏览器,浏览器或系统保存,可保存多个
- Session 是把用户的数据写到用户独占的 Session(每个浏览器不一样),服务端保存(保存重要信息,减少服务器资源的浪费)
- cookie 不安全(客户端),session 安全(服务端)
使用场景:
- 保存一个登陆用户信息
- 购物车信息
- 在整个网站中经常使用的数据,保存在 Session
Session 使用
Session 保存数据
public class SessionDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//得到 session
HttpSession session = req.getSession();
//给 Session设置属性
session.setAttribute("name", new User("李四",22));
//获取 id
String id = session.getId();
//判断 session 是不是新创建的
if (session.isNew()) {
resp.getWriter().write("Session 成功,ID" + id);
} else {
resp.getWriter().write("session 存在了,ID是" + id);
}
//Session 创建时候做了什么
// Cookie cookie = new Cookie("JSESSIONID", id);
// resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Session 获取数据
public class SessionDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
//得到 session
HttpSession session = req.getSession();
User name = (User) session.getAttribute("name");
out.write("session 的值" + name);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Session 销毁
public class SessionDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
//得到 session
HttpSession session = req.getSession();
session.removeAttribute("name");
session.invalidate();
out.write("注销成功");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Session 设置自动过期 web.xml 中
<session-config>
<!-- 15 分钟后 session 自动失效。-->
<session-timeout>15</session-timeout>
</session-config>
7. jsp
7.1 什么是 JSP
java Server Pages:java 服务器端页面,也和 Servlet 一样,用于动态 web 技术
最大特点:
- 写 JSP 就像在写 HTML
- 区别:
- HTML 只给用户提供静态的数据
- JSP 页面中可以嵌入 java 代码,为用户提供动态数据
7.2 JSP 原理
思路:JSP 是怎么执行的
JSP 技术特点
JSP 和 Servlet 是本质相同的技术。当一个 JSP 文件第一次被请求时,JSP 引擎会将该 JSP 编译成一个 Servlet,并执行这个 Servlet。如果 JSP 文件被修改了,那么 JSP 引擎会重新编译 这个 JSP。
JSP 引擎对 JSP 编译时会生成两个文件分别是.java 的源文件以及编译后的.class 文件,并 放到 Tomcat 的 work 目录的 Catalina 对应的虚拟主机目录中的 org\apache\jsp 目录中。两个 文件的名称会使用 JSP 的名称加”_jsp”表示。如:index_jsp.java、index_jsp.class。
浏览器不管访问什么资源,都是在访问 servlet。jsp 最终也会被转换为 java 类
JSP 本质就是 Servlet,继承了 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; //applicationContext
final javax.servlet.ServletConfig config; //config
javax.servlet.jsp.JspWriter out = null; //out
final java.lang.Object page = this; //page:当前页
HttpServletRequest request //请求
HttpServletResponse response //响应
- 输出页面前增加的代码
response.setContentType("text/html; charset=UTF-8"); //设置响应的页面类型
pageContext = _jspxFactory.getPageContext(this, request, response,
null, false, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
out = pageContext.getOut();
_jspx_out = out;
以上这些对象我们可以在 jsp 页面中直接使用
在 jsp 页面中就会原封不动的输出,如果是 html 代码就会被转换为这样的格式输出到前端
out.write(" <html>\r\n");
7.3 基础语法
JSP 作为 java 技术的一种应用有一些自己扩充的语法,java 所有语法都支持
JSP 的原始标签在 JSP 的任何版本中都可以使用。
<%! %> 声明标签
声明标签用于在 JSP 中定义成员变量与方法的定义。标签中的内容会出现在 JSP 被编译 后的 Servlet 的 class 的{}中。
<% %>脚本标签
脚本标签用于在 JSP 中编写业务逻辑。标签中的内容会出现在 JSP 被编译后的 Servlet
的_jspService 方法体中。
<%= %>赋值标签
赋值标签用于在 JSP 中做内容输出。标签中的内容会出现在_jspService 方法的 out.print() 方法的参数中。注意我们在使用赋值标签时不需要在代码中添加 ”;”。
7.4 内置对象
- PageContext 存储
- Request 存储
- Response
- Session 存储
- Application 【ServletContext】存储
- cofig 【ServletConfig】
- out
- page
- exception
<%--内置对象--%>
<%
pageContext.setAttribute("name1", "张三1");//保存的数据只在一个页面中有效,页面关闭就没了
request.setAttribute("name2", "张三2");//保存数据在一次请求中有效,使用场景:新闻,看完就没用了
session.setAttribute("name3", "张三3");//保存数据在一次会话中有效,从打开浏览器到关闭浏览器 比如购物车
application.setAttribute("name4", "张三4");//保存数据在服务器中有效,从打开服务器到关闭服务器 比如统计聊天数据
%>
<%--使用 EL 表达式输出${}--%>
<h2>取出的值</h2>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<%--EL表达式没有的值不会显示在页面上--%>
<h3>${name5}</h3>
7.5 JSTL 标签、EL 表达式
<!-- JSTL 表达式依赖-->
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- standard标签库-->
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
EL 表达式:${}
- 获取数据
- 执行运算
- 获取 web 开发常用对象
JSTL 标签库的使用为了弥补 JSP 标签的不足,它自定义许多标签,标签功能和 java 代码一样
核心标签库
使用步骤
- 引入 taglib
- 使用其中的方法
- (这是个坑)在 tomcat 也需要引入 jstl ,standard两个 jar包,否则会报错:JSTL 错误
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h4>if 测试</h4>
<form action="coreif.jsp" method="get">
<%--
c:if 使用
EL 表达式获取表单数据
${param.参数名}
--%>
<input type="text" name="username">
<input type="submit" value="登录">
</form>
<%--判断如果提交是管理员就登录成功--%>
<c:if test="${param.username=='admin'}" var="isAdmin" >
<c:out value="管理员欢迎你" />
</c:if>
<c:out value="${isAdmin}"/>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--定义一个变量 score,值为 85--%>
<c:set var="score" value="59"/>
<c:choose>
<c:when test="${score>=90}">
你的成绩优秀
</c:when>
<c:when test="${score>=80}">
你的成绩还行
</c:when>
<c:when test="${score>=70}">
你的成绩一般
</c:when>
<c:when test="${score>=60}">
60万岁
</c:when>
<c:when test="${score<60}">
你的成绩垃圾
</c:when>
</c:choose>
</body>
</html>
<c:foreach>常用
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
ArrayList<Object> people = new ArrayList<>();
people.add("张三");
people.add("李四");
people.add("王五");
people.add("赵六");
request.setAttribute("list", people);
%>
<%--
item 要遍历的对象
var 每一次遍历出来的变量
--%>
<c:forEach items="${list}" var="people">
<c:out value="${people}"/><br>
</c:forEach>
<hr>
<%--
item 要遍历的对象
var 每一次遍历出来的变量
begin 哪里开始
end 到哪里
step 步长,每次走几步,0去了就是 2
--%>
<c:forEach items="${list}" var="people" begin="0" end="3" step="2">
<c:out value="${people}"/><br>
</c:forEach>
</body>
</html>
8. MVC三层架构
什么是 MVC:Model view Controller 模型、视图、控制器
8.1早些年框架
用户直接访问控制层,控制层就直接操作数据库
- servlet——CRUD——数据库
- 弊端:程序臃肿,不利于维护
- Servlet 代码中:处理请求、响应、视图跳转、处理业务代码、处理逻辑代码
- 架构:没有什么加一层解决不了的(如 JDBC)
8.2MVC 三层架构
-
View(视图):用户的操作界面。如:html、jsp。
-
Model(模型):具体的业务模型与数据模型。如:service、dao、pojo。
-
Controller(控制):处理从视图层发送的请求,并选取模型层的业务模型完成响应的业务实现,并产生响应。如:Servlet。
目标都是:为了解耦和、提高代码复用性。
9. Filter
Filter:过滤器,用来过滤网站的数据
- 处理中文乱码
- 登录验证
Filter 开发步骤
-
导包
-
编写过滤器
public class CharterEncodingFilter implements Filter {
//web 服务器启动就初始化了,随时等待过滤
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharterEncodingFilter.init初始化");
}
/**
*
* @param request
* @param response
* @param chain 过滤器中的所有代码,在过滤特定请求的时候都会执行
* 必须要让过滤器继续同时执行
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
System.out.println("CharterEncodingFilter.doFilter执行前");
//调用 chain 才能执行,让我们的请求继续做,不写程序就被拦截停止
chain.doFilter(request, response);
System.out.println("CharterEncodingFilter.doFilter执行前");
}
//web 服务器关闭的时候进行销毁
@Override
public void destroy() {
System.out.println("CharterEncodingFilter.destroy销毁");
}
}
- 配置 xml 文件
<filter>
<filter-name>chartEncodingFilter</filter-name>
<filter-class>com.study.filter.CharterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>chartEncodingFilter</filter-name>
<!-- 只要/servlet 的任何请求,都会经过过滤器-->
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
10. 监听器
实现一个监听器接口:(有多种)
- 实现监听器接口
//统计网站在线人数:统计 session
public class OnlineCountLister implements HttpSessionListener {
//创建session;监听一举一动
//一旦创建 Session 就会触发一次这个事件
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println(se.getSession().getId());
ServletContext servletContext = se.getSession().getServletContext();
Integer onlineCount = (Integer) servletContext.getAttribute("OnlineCount");
if (onlineCount == null) {
onlineCount = new Integer(0);//装箱
} else {
int count = onlineCount.intValue();//拆箱
onlineCount = new Integer(count + 1);
}
servletContext.setAttribute("OnlineCount", onlineCount);
}
//销毁session
//一旦创建 Session销毁 就会触发一次这个事件
@Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext servletContext = se.getSession().getServletContext();
Integer onlineCount = (Integer) servletContext.getAttribute("OnlineCount");
if (onlineCount == null) {
onlineCount = new Integer(0);
} else {
int count = onlineCount.intValue();
onlineCount = new Integer(count - 1);
}
servletContext.setAttribute("OnlineCount", onlineCount);
}
/**
* session 销毁
* 1.手动销毁 se.getSession().invalidate();
* 2.自动销毁 在 sessionConfig.xml 配置timeout
*/
}
- 配置 web.xml
<!-- 注册监听器-->
<listener>
<listener-class>com.study.listener.OnlineCountLister</listener-class>
</listener>