JavaWeb学习
文章目录
1、什么是JavaWeb
定义:是用Java技术来解决相关web互联网领域的技术栈。
- 静态Web
- 动态Web
Web应用程序
定义:可以提供浏览器访问得程序。由多部分组成
- html,css,js
- jsp,servlet
- Java程序
- jar包
- 配置文件(Properties)
静态Web
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存失败,源站可能有防盗链机制,建议将图片保存下来直接上传下上传(iuXGypds3VUP-1654181491979)(D:\studys\笔记\资料\JavaWeb\静态Web1.png)(https://gitee.com/elvinw/img/raw/master/mybatis缓存原理.jpg[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SqHQna0T-1654181568567)(!%5B%5D%28https://gitee.com/elvinw/img/raw/master/mybatis%E7%BC%93%E5%AD%98%E5%8E%9F%E7%90%86.jpg%29#pic_center)]
)]
- 缺点
- 无法动态更新,所有用户看到的都是同一个页面
- 无法和数据库交互
动态Web
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KDw2L9Me-1654181491981)(D:\studys\笔记\资料\JavaWeb\动态Web1.png)]
- 优点
- 可以动态更新,所有用户看到的不是同一个页面
- 可以和数据库交互
- 缺点
- 加入服务器的动态资源出现了错误,需要重新编写后台程序,停机维护。
2、Web服务器
服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应信息。
Tomcat
定义:Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat中得到体现,因为Tomcat技术先进、性能稳定,而且免费,因而深受Java爱好者的喜爱并得到了部分软件开发商的认可,成为比较流行的Web应用服务器。适合新手。Tomcat最新版本为10.0.14。
安装
- 下载地址:https://tomcat.apache.org/download-10.cgi
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kzx1ZZCN-1654181491982)(D:\studys\笔记\资料\JavaWeb\tomcat1.png)]
-
解压
-
配置Java环境变量
新建:JAVA_HOME:D:\Java\jdk1.7.0_51
新建:CLASS_PATH:.;%JAVA_HOME%\lib
编辑:PATH:在最前面加上 %JAVA_HOME%\bin;
- 启动,测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-15Ofp7dJ-1654181491984)(D:\studys\笔记\资料\JavaWeb\tomcat2.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JYxw5imv-1654181491986)(D:\studys\笔记\资料\JavaWeb\tomcat3.png)]
测试:http://localhost:8080/
- 配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WY1owLyM-1654181491987)(https://gitee.com/elvinw/img/raw/master/image-20220111104949081.png)]
高难度面试题
请你谈谈网站是如何进行访问的!
- 1、输入一个域名,回车
- 2、检查本机的C:\Windows\System32\drivers\etc\hosts配置文件下有没有这个域名映射
- 有:直接返回对应的ip地址
- 没有:去DNS服务器找,找到的话就返回,找不到就不返回。
3、Http(超文本传输协议)
Http请求
- 客户端–发送端(Request)–服务器
Request URL: 请求地址
Request Method: GET get方法/put方法
Status Code:200 ok 状态码
Remote(远程)Address:
- 请求行–get,put
- 消息头
Accept:告诉浏览器,它所支持的数据类型
Accept-Encoding:支持哪种编码格式
Accept-Language:语言环境、
Cache-Control:缓存控制
Connection:告诉浏览器,请求完成是断开还是保持连接
Host:主机地址
Http响应
服务器–响应–客户端
- 响应体
Accept:告诉浏览器,它所支持的数据类型
Accept-Encoding:支持哪种编码格式
Accept-Language:语言环境、
Cache-Control:缓存控制
Connection:告诉浏览器,请求完成是断开还是保持连接
Host:主机地址
Refresh:多久刷新一次
Location:让网页重定位
- 响应状态码
- 200:请求响应成功
- 3xx:请求重定向
- 4xx:找不到资源
- 5xx:服务器代码错误
4、Servlet
Servlet简介
- Servlet是sun公司开发动态web的一门技术
- sun公司在这些API中提供了一个接口:Srevlet。
- 开发Servlet程序的步骤
- 编写一个类,实现Srevlet接口
- 把开发好的java类部署到web服务器中
把实现了Srevlet接口的Java程序叫做:Srevlet
创建HelloSrevlet
1、构建一个普通的Maven项目:javaweb-01-servlet,删除src目录,新建Moudel。这个空的工程就是Maven主工程。
- 配置pox.xml文件,导入Servlet依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
2、创建Mvaen子工程web项目:servlet-01
- 配置子项目中的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>
- 父项目中会有:
<modules>
<module>servlet-01</module>
</modules>
父项目中的java子项目可以直接使用
3、编写一个Srevlet
- 新建HelloServelt类,继承HttpServelt
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* Author:三木
* Date:2022-01-22 16:21
* Description:<测试Servelt>
*/
public class HelloServelt extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//ServletOutputStream outputStream = resp.getOutputStream();
PrintWriter writer = resp.getWriter();//响应流
writer.print("helloServelt");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 添加Servlet映射,web.xml文件
<!--注册Servelt-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.sanmu.servlet.HelloServelt</servlet-class>
</servlet>
<!--Servelt的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
- 配置Tomcat
- 启动
http://localhost:8080/s1/
http://localhost:8080/s1/hello
Servlet原理
Servlet是由Web服务器调用,Web服务器在收到浏览器请求后,会:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FKAoV0DO-1654181491989)(D:\studys\笔记\资料\JavaWeb\Servlet原理.png)]
Mapping问题
1、一个Servlet可以指定一个映射路径
<!--Servelt的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
2、一个Servlet可以指定多个映射路径
<!--Servelt的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
3、一个Servlet可以指定通用映射路径
<!--Servelt的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
4、默认请求路径
<!--Servelt的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
5、指定一些前缀或者后缀
<!--可以自定义后缀实现请求路径
注意:*前面不能加 / -->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
6、优先级问题
指定了固有路径的映射优先级最高,如果找不到就会走默认的处理
ServletContext
Web容器在启动的时候,它会为每一个Web程序都创建一个对应的ServletContext对象,它代表了当前的Web应用。
1、共享数据
在这个Servlet创建的,可以在另一个Servlet中获得。
//设置值
public class HelloSrevlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// this.getInitParameter() 初始化参数
// this.getServletConfig() Servlet配置
// this.getServletContext() Servlet上下文
ServletContext context = this.getServletContext();
String username="sanmu";
context.setAttribute("username",username);//将数据保存在ServletContext中
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
//获取值
public class GetServlet extends HelloSrevlet{
@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");
resp.setCharacterEncoding("utf-8");
resp.getWriter().print(username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
//Servlet注册
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.sanmu.servlet.HelloSrevlet</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.sanmu.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getc</servlet-name>
<url-pattern>/getc</url-pattern>
</servlet-mapping>
2、获取初始化参数
<!--配置一些web应用初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/</param-value>
</context-param>
//读取
public class InitServlet extends HelloSrevlet{
@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 {
doGet(req, resp);
}
}
3、请求转发
public class RequestSrevlet extends HelloSrevlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
System.out.println("进入了RequestServlet");
// RequestDispatcher requestDispatcher = context.getRequestDispatcher("/init");//转发的请求路径
// requestDispatcher.forward(req,resp);//调用forward()实现请求转发
context.getRequestDispatcher("/init").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
//注册
<servlet>
<servlet-name>res</servlet-name>
<servlet-class>com.sanmu.servlet.RequestSrevlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>res</servlet-name>
<url-pattern>/res</url-pattern>
</servlet-mapping>
4、读取资源文件
Properties
- 在java目录下新建 .Properties文件
- 在resources目录下新建 .Properties文件
发现:都被打包在同一个路径下(class路径);class,俗称这个路径为classpath
解决:在pom.xml加入build,并配置resources,来防止资源导出失败问题。
思路:需要一个文件流
public class PropServlet extends HelloSrevlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/dp.properties");
Properties prop = new Properties();
prop.load(is);
String username=prop.getProperty("username");
String password=prop.getProperty("password");
resp.getWriter().print(username+":"+password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
<servlet>
<servlet-name>prop</servlet-name>
<servlet-class>com.sanmu.servlet.PropServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>prop</servlet-name>
<url-pattern>/prop</url-pattern>
</servlet-mapping>
HttpSrevletResponse(响应)
web服务器接收客户端的http请求,针对这个请求,分别创建一个代表请求的 HttpServletRequest 对象,代表响应的 HttpSrevletResponse 对象。
- 如果要获取客户端请求过来的参数:找 HttpServletRequest
- 如果要给客户端响应一些信息:找 HttpSrevletResponse
简单分类
-
负责向浏览器发送数据的方法
//ServletResponse接口 ServletOutputStream getOutputStream() throws IOException; PrintWriter getWriter() throws IOException;
-
负责向浏览器发送响应头的方法
//ServletResponse接口 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); //HttpServletRequest类 void addHeader(String var1, String var2); void setIntHeader(String var1, int var2); void addIntHeader(String var1, int var2);
-
响应状态码
//HttpServletRequest类 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;
下载文件(步骤)
- 要获取下载文件的路径
- 获取下载的文件名
- 想办法设置让浏览器能够支持下载需要的文件
- 获取下载文件的输入流
- 创建buffer缓冲区
- 获取OutputStream对象
- 将FileOutputStream流写入到buffer缓冲区
- 使用OutputStream对象将缓冲区中的数据输出到客户端
public class Response extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//- 要获取下载文件的路径,注意路径问题
String realPath = "D:\\ProgramFiles\\Java\\Project\\JavaWeb\\javaweb-01-servlet\\response\\src\\main\\resources\\1.png";
//String realPath=this.getServletContext().getRealPath("/1.png");
System.out.println("下载文件的路径:"+realPath);
//- 获取下载的文件名
String filename = realPath.substring(realPath.lastIndexOf("\\") + 1);
//- 想办法设置让浏览器能够支持下载需要的文件,中文文件名设置编码:URLEncoder.encode(filename,"utf-8")
resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(filename,"utf-8"));
//- 获取下载文件的输入流
FileInputStream in = new FileInputStream(realPath);
//- 创建buffer缓冲区
int len=0;
byte[] buffer=new byte[1024];
//- 获取OutputStream对象
ServletOutputStream out = resp.getOutputStream();
//- 将FileOutputStream流写入到buffer缓冲区, 使用OutputStream对象将缓冲区中的数据输出到客户端
while((len=in.read(buffer))>0){
out.write(buffer,0,len);
}
in.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
问题:路径问题;中文文件名乱码,设置编码:URLEncoder.encode(filename,“utf-8”);图片显示不下载,响应头符号,“Content-Disposition”,“attachment;filename=”。
验证码功能
- 前端实现
- 后端实现,需要用到 Java 的图片类,生成一个图片
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/jpg");
//网站存在缓存,不让浏览器缓存
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();
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);
}
}
<servlet>
<servlet-name>image</servlet-name>
<servlet-class>com.sanmu.response.ImageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>image</servlet-name>
<url-pattern>/img</url-pattern>
</servlet-mapping>
实现重定向
一个Web资源B收到客户端A的请求后,B会通知A客户端去访问另一个Web资源C,这个过程就是重定向。
常见场景:
-
用户登入
//HttpServletResponse类 void sendRedirect(String var1) throws IOException;
-
测试
public class Redirect extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /**原理 *resp.setHeader("Location","/r/img"); *resp.setStatus(302); */ resp.sendRedirect("/r/img");//重定向 } @Override protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
面试题:转发和重定向的区别
- 相同点:页面都实现转发
- 不同点:
- 请求转发的时候,url不会发生变化;307
- 重定向时,url地址栏会发生改变;302
用户登入案例
public class RequestText extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username+":"+password);
if (username.equals("admin")&&password.equals("123456")){
resp.sendRedirect("/r/success.jsp");
}else{
resp.sendRedirect("/r/404.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
//index.jsp
<html>
<body>
<h2>Hello 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>
<servlet>
<servlet-name>RequestText</servlet-name>
<servlet-class>com.sanmu.response.RequestText</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RequestText</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
HttpServletRequest(请求)
HttpServletRequest 代表客户端的请求,用户通过Http协议访问服务器,HTTP请求中的所有信息会被封装到 HttpServletRequest,通过这个HttpServletRequest的方法,获得客户端的所有信息
获取传递的参数,请求转发
两个方法:
//ServletRequest接口
tring getParameter(String var1);
String[] getParameterValues(String var1);
测试
public class RequestTest 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");
//通过请求转发,"/"代表当前应用
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
@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>
</head>
<body>
<div>
<form action="${pageContext.request.contextPath}/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
爱好:
<input type="checkbox" name="hobbys" value="女孩">女孩
<input type="checkbox" name="hobbys" value="电影">电影
<input type="checkbox" name="hobbys" value="音乐">音乐
<br>
<input type="submit">
</form>
</div>
</body>
</html>
<servlet>
<servlet-name>RequestTest</servlet-name>
<servlet-class>com.sanmu.servlet.RequestTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RequestTest</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
5、Cookie、Session
Cookie:有时也用其复数形式 Cookies。类型为“小型文本文件”,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。
Session:“会话控制“。Session对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web页时,如果该用户还没有会话,则Web服务器将自动创建一个 Session对象。当会话过期或被放弃后,服务器将终止该会话。
会话
当用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器。这个过程称为会话。
保存会话的两种技术
-
Cookie:客户端技术(响应、请求)
-
Session:服务器技术。把用户的会话信息保存在Session对象中。
/**
* Author:三木
* Date:2022-03-31 16:08
* Description:<保存用户上一次访问的时间>
*/
public class CookieDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
PrintWriter out = resp.getWriter();
//Cookie,服务器端从客户端获取
Cookie[] cookies = req.getCookies();
//判断Cookie是否存在
if(cookies!=null){
out.write("上一次访问时间:");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
//判断cookie的key
if(cookie.getName().equals("lastloginTime")){
//获取cookie的值
long l = Long.parseLong(cookie.getValue());
Date date=new Date(l);
out.write(date.toLocaleString());
}
}
}else{
out.write("第一次访问本站");
}
//服务器给客户端响应一个cookie
Cookie lastloginTime = new Cookie("lastloginTime", System.currentTimeMillis() + "");
//lastloginTime.setMaxAge(0);//有效期一天,秒
resp.addCookie(lastloginTime);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
乱码问题
//编码
URLDecoder.decode("你好","utf-8")
//解码
URLDecoder.decode("你好","utf-8")
Session
- 服务器会给每一个用户(浏览器)创建一个Session对象
- 一个Session对象独占一个浏览器,只要浏览器没有关闭,这个Session就存在
Session和Cookie的区别
- Cookie是把用户的数据写给用户浏览器,浏览器保存
- Session把用户的数据写到用户独占的Session中,服务器端保存
- Session对象由服务创建
使用场景
- 保存用户登入信息
- 购物车信息
- 网站中经常使用的数据
测试
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* Author:三木
* Date:2022-04-05 15:48
* Description:<描述>
*/
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;charset=utf-8");
//得到Session
HttpSession session = req.getSession();
//给Session存东西
session.setAttribute("name",new Person("三木",1));
//获得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);
}
}
<servlet>
<servlet-name>SessionDemo01</servlet-name>
<servlet-class>com.sanmu.servlet.SessionDemo01</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SessionDemo01</servlet-name>
<url-pattern>/s1</url-pattern>
</servlet-mapping>
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* Author:三木
* Date:2022-04-05 16:07
* Description:<描述>
*/
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;charset=utf-8");
//得到Session
HttpSession session = req.getSession();
//给Session存东西
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);
}
}
<servlet>
<servlet-name>SessionDemo02</servlet-name>
<servlet-class>com.sanmu.servlet.SessionDemo02</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SessionDemo02</servlet-name>
<url-pattern>/s2</url-pattern>
</servlet-mapping>
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* Author:三木
* Date:2022-04-05 16:27
* Description:<注销Session>
*/
public class SessionDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
session.removeAttribute("name");
session.invalidate();//注销ID
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
<servlet>
<servlet-name>SessionDemo03</servlet-name>
<servlet-class>com.sanmu.servlet.SessionDemo03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SessionDemo03</servlet-name>
<url-pattern>/s3</url-pattern>
</servlet-mapping>
设置Session自动失效
<!--web.xml-->
<!--设置Session失效时间,单位:分钟-->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
6、JSP
JSP原理
Java Server Pages,JSP部署于网络服务器上,可以响应客户端发送的请求,并根据请求内容动态地生成HTML、XML或其他格式文档的Web网页,然后返回给请求者。JSP技术以Java语言作为脚本语言,为用户的HTTP请求提供服务,并能与服务器上的其它Java程序共同处理复杂的业务需求。
JSP是如何执行的
- 服务器内部
- Tomcat中有一个work目录
- IDEA使用Tomcat会在IDEA中生成tomcat文件夹。页面会转变成Java程序。
- JSP本质上 就是一个Servlet
JSP基础语法
jsp表达式
<%-- JSP表达式
作用:用来将程序的输出,输出到客户端
<%= 变量或者表达式%>
--%>
<%= new java.util.Date()%>
jsp脚本片段
<%-- JSP脚本片段 --%>
<%
int sum=0;
for (int i = 1; i < 10; i++) {
sum+=i;
}
out.println("<h1>sum="+sum+"</h1>");
%>
jsp声明
<%!
static {
System.out.println("静态代码块");
}
private int t=0;
public void st(){
System.out.println(t);
}
%>
定制错误页面
-
方法一
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%--定制错误页面--%> <%@ page errorPage="error/500.jsp" %> <html> <head> <title>Title</title> </head> <body> <% int x=1/0; %>
-
方法二
<!--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">
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
</web-app>
jsp指令
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--包含文件
@include:将两个文件合二为一
--%>
<%@include file="common/header.jsp"%>
<h1>主体</h1>
<%@include file="common/footer.jsp"%>
<hr>
<%--jsp标签--%>
<jsp:include page="/common/header.jsp"/>
<h1>主体</h1>
<jsp:include page="/common/footer.jsp"/>
</body>
</html>
9大内置对象
-
PageContext
-
Request
-
Response
-
Session
-
Application
-
config
-
out
-
page
-
exception
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%--内置对象--%> <% pageContext.setAttribute("name1","01");//保存的数据只在一个页面中有效 request.setAttribute("name2","02");//保存的数据只在一次请求中有效,请求转发会携带这个数据 session.setAttribute("name3","03");//保存的数据只在一次会话中有效,从浏览器打开到关闭 application.setAttribute("name4","04");//保存的数据只在服务器中有效 %> <% //从pageContext取出值,通过findAttribute寻找方式 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表达式输出--%> <h1>取出的值</h1> <h3>${name1}</h3> <h3>${name2}</h3> <h3>${name3}</h3> <h3>${name4}</h3> <%--通过EL表达式输出,name5不会显示在客户端--%> <h3>${name5}</h3> </body> </html>
JSP标签、JSTL标签、EL表达式
导入jar包
<!-- jstl 表达式依赖 -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- standard 标签库 依赖 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
JSP标签
<%--页面跳转--%>
<jsp:forward page="/jsptag2.jsp">
<jsp:param name="name" value="sanmu"/>
<jsp:param name="age" value="12"/>
</jsp:forward>
JSTL标签
JSTL标签库的使用是为了弥补HTML标签的不足,自定义了许多标签。
使用需要引用标签库
-
核心标签
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AuMIhfPF-1654181491993)(D:\studys\笔记\资料\JavaWeb\JSTL核心标签.png)]
EL表达式:${}
-
获取数据
-
执行运算
-
获取web开发的常用对象
<%@ 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>
<h1>if测试</h1>
<form action="jstlDemo.jsp" method="get">
<%--EL表达式获取表单中的数据:${param.参数名}--%>
<input type="text" name="username" value="${param.username}">
<input type="submit" value="登入">
</form>
<%--判断提交的用户名是否是管理员,是则登入--%>
<c:if test="${param.username=='admin'}" var="isadmin">
<c:out value="管理员登入"/>
</c:if>
<c:out value="${isadmin}"/>
<hr>
<h1>choose测试</h1>
<%--定义变量score--%>
<c:set var="score" value="87"/>
<c:choose>
<c:when test="${score>=90}">
成绩优秀
</c:when>
<c:when test="${score>=70}">
成绩良好
</c:when>
<c:when test="${score<=60}">
成绩不及格
</c:when>
</c:choose>
<hr>
<h1>forEach测试</h1>
<%
ArrayList<String> list=new ArrayList<>();
list.add("01");
list.add("02");
list.add("03");
list.add("04");
request.setAttribute("list",list);
%>
<%--
var:每一次遍历出来的变量
items:要遍历的对象
begin:开始位置
end:结束位置
step:步长
--%>
<c:forEach var="list" items="${list}">
<c:out value="${list}"/><br>
</c:forEach>
<hr>
<c:forEach var="list" items="${list}" begin="1" end="3" step="2">
<c:out valu e="${list}"/><br>
</c:forEach>
</body>
</html>
JavaBean
JavaBean是一种Java语言写成的可重用组件。 用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。
JavaBean有特定的写法
- 必须有一个无参构造
- 属性必须是私有化
- 必须有对应的set、get方法
7、MVC三层构架
MVC模式代表:Model-View-Controller(模型-视图-控制器)模式。
- Model:业务模型,处理业务
- View:视图,界面展示
- Controller:控制器,处理请求,调用模型和视图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A3N3du6U-1654181491995)(D:\studys\笔记\资料\JavaWeb\mvc三层架构.png)]
三层构架
三层构架是将项目分成了三个层面:表现层、业务逻辑层、数据访问层。
作用:
- 职责单一,互不影响
- 有利于分工协作
- 有利于组件重用
- 表现层:接收请求,封装数据,调用业务逻辑层、响应数据。
- 业务逻辑层:对业务逻辑进行封装、组合数据访问层中基本功能,形成复杂的业务逻辑功能。
- 数据访问层:对数据库的CRUD基本操作。
MVC和三层架构的区别和联系
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pv6S25oM-1654181491996)(D:\studys\笔记\资料\JavaWeb\三次架构.png)]
8、Filter-过滤器
filter过滤器,可以拦截所有访问web资源的请求和响应操作。
在Filter的doFilter方法内如果没有执行chain.doFilter(request,response)那么资源是不会被访问到的。
Filter开发步骤
-
导入jar包
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> </dependency> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl-api</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version> </dependency> </dependencies>
-
编写代码
import javax.servlet.*; import java.io.IOException; /** * Author:三木 * Date:2022-04-19 14:47 * Description:<过滤器解决乱码问题> */ public class CharacterEncodingFilter implements Filter { @Override //初始化,web服务器启动,就已经初始化了,随时等待过滤对象出现 public void init(FilterConfig filterConfig) throws ServletException { System.out.println("CharacterEncodingFilter初始化"); } @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"); //filterChain:链 /* 1、过滤中的所有代码,在代码特定请求的时候都会执行 2、必须要让过滤器继续执行 */ filterChain.doFilter(servletRequest,servletResponse);//让请求继续走,如果不写,程序到这里就被拦截停止 } @Override //注销,web服务器关闭的时候,过滤会注销 public void destroy() { System.out.println("CharacterEncodingFilter注销"); } }
-
添加依赖
<?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"> <servlet> <servlet-name>ShowServlet</servlet-name> <servlet-class>com.sanmu.servlet.ShowServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ShowServlet</servlet-name> <url-pattern>/servlet/show</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>ShowServlet</servlet-name> <url-pattern>/show</url-pattern> </servlet-mapping> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.sanmu.filter.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <!--只要是 /servlet路径下的任何请求,都会经过过滤器filter--> <url-pattern>/servlet/*</url-pattern> </filter-mapping> </web-app>
9、Listener-监听器
作用:监听某个事件的发生,状态的改变
实现监听
-
实现监听器的接口
import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * Author:三木 * Date:2022-04-19 16:11 * Description:<监听器。统计网站在线人数,即统计session> */ public class OnlineCountListener implements HttpSessionListener { @Override //创建session监听 //一旦创建Session就会触发一次这个事件 public void sessionCreated(HttpSessionEvent se) { ServletContext sessionContext = se.getSession().getServletContext(); Integer onlineCount = (Integer) sessionContext.getAttribute("onlineCount"); if(onlineCount==null){ onlineCount=new Integer(1); }else{ int count=onlineCount.intValue();//类型转换 onlineCount=new Integer(count++); } sessionContext.setAttribute("onlineCount",onlineCount); } @Override //销毁session监听 //一旦销毁Session就会触发一次这个事件 public void sessionDestroyed(HttpSessionEvent se) { ServletContext sessionContext = se.getSession().getServletContext(); Integer onlineCount = (Integer) sessionContext.getAttribute("onlineCount"); if(onlineCount==null){ onlineCount=new Integer(0); }else{ int count=onlineCount.intValue();//类型转换 onlineCount=new Integer(count--); } sessionContext.setAttribute("onlineCount",onlineCount); } }
-
index.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <h2>当前有<span><%=request.getServletContext().getAttribute("onlineCount")%></span>人在线</h2> </body> </html>
-
web.xml中注册监听器
<!--注销监听器--> <listener> <listener-class>com.sanmu.listener.OnlineCountListener</listener-class> </listener>