Java Web笔记总结
Java Web笔记总结
Java Web笔记总结Tomcat
tomcat官网地址
-
解压就可以使用了
-
启动tomcat
-
访问tomcat服务器
localhost:8080
Htpp
什么是http
-
HTTP协议(HyperText Transfer Protocol,超文本传输协议)是因特网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准。
-
HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。
-
端口号:80
-
https:是安全的;端口号:443
请求行
- 请求行中的请求方式:
GET
消息头
Accept: //告诉浏览器它所支持的数据类型 Accept-Encoding:// 编码格式 Accept-Language: //语言环境 Cache-Control: //缓存控制 Connection: //请求完成是断开还是保持连接 Host: //主机
-
客户端—>发送一个请求(request)—>服务器(web server)
-
百度:
Request URL: https://www.baidu.com/ //请求地址 Request Method: GET //请求方法 Status Code: 200 OK // 状态码:200 Remote Address: 39.156.66.14:443 //远程地址
-
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Connection: keep-alive Cookie: BIDUPSID=990D4C68CAF2A93A794BE5DE1A21F115; PSTM=1600490706; BAIDUID=990D4C68CAF2A93A6DDBD053C54EF752:FG=1; BD_UPN=12314753; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BD_HOME=1; delPer=0; BD_CK_SAM=1; PSINO=1; COOKIE_SESSION=1941_2_9_9_4_24_1_4_9_4_1_0_1967_0_32_18_1600693191_1600691236_1600693159%7C9%23421_3_1600691218%7C2; H_PS_PSSID=32617_1428_32734_7545_32327_31660_32723_7552_7629_32115_26350; H_PS_645EC=621dEvROulAHAU%2FEFNTaEzJWlG%2BxXUa6WGiwdwM6UmV575xRvnJyXQ1CCkE Host: www.baidu.com Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: none Sec-Fetch-User: ?1 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
-
-
- 服务器—>响应(response)—>客户端
- 百度:
Cache-Control: private //缓存控制 Connection: keep-alive //保持连接 Content-Encoding: gzip //编码格式 Content-Type: text/html;charset=utf-8 //编码类型 Date: Mon, 21 Sep 2020 13:04:43 GMT Expires: Mon, 21 Sep 2020 13:04:38 GMT Server: BWS/1.1 Set-Cookie: BDSVRTM=0; path=/ Set-Cookie: BD_HOME=1; path=/ Set-Cookie: H_PS_PSSID=32617_1428_32734_7566_7545_32327_31660_32723_7552_7629_32115_26350; path=/; domain=.baidu.com Strict-Transport-Security: max-age=172800 Traceid: 1600693483048351719417449089970476029083 Transfer-Encoding: chunked X-Ua-Compatible: IE=Edge,chrome=1
响应体
Accept: //告诉浏览器它所支持的数据类型 Accept-Encoding:// 编码格式 Accept-Language: //语言环境 Cache-Control: //缓存控制 Connection: //请求完成是断开还是保持连接 Host: //主机 refrush://告诉用户多久刷新一次 location://让网页重新定位
响应状态码
200
:请求响应成功
4**
:找不到资源(资源不存在)404
3**
: 请求重定向(重新到我你的位置去)
5**
:服务器代码错误 500/502(网关错误)
浏览器地址栏中输入地址回车一瞬间到页面加载出来,经历了怎样一个过程?
【HTTP请求阶段:向服务器发送请求】
1.浏览器首先向DNS域名解析服务器发送请求
2.DNS反解析:根据浏览器请求地址中的域名,到DNS服务器中找到对应的服务器外网IP地址
3.通过找到的外网IP,向对应的服务器发送请求(首先访问的是服务器的WEB站点管理工具:准确来说是我们先基于工具在服务器上创建很多服务,当有客户端访问的时候,服务器会匹配出具体是请求哪个服务)
4.通过URL地址中携带的端口号,找到服务器上对应的服务,以及服务所管理的项目源文件
【HTTP响应阶段:服务器把客户端需要的内容准备好,并且返回给客户端】
5.服务器端根据请求地址中的路径名称、问号传参或者哈希值,把客户端需要的内容进行准备和处理
6.把准备的内容响应给客户端(如果请求的是HTML或者CSS等这样的资源文件,服务器返回的是资源文件中的源代码[不是文件本身])
【浏览器渲染阶段】
7.客户端浏览器接受到服务器返回的源代码,基于自己内部的渲染引擎(内核)开始进行页面的绘制和渲染
->首先计算DOM结构,生成DOM TREE
->自上而下运行代码,加载CSS等资源内容
->根据获取的CSS生成带样式的RENDER TREE
->开始渲染和绘制
2.我们把一次完整的 请求+响应 称之为 “HTTP事务”
事务就是完整的一次操作,请求和响应缺一不可
3.一个页面完全加载完成,需要向服务器发起很多次HTTP事务操作
一般来说:首先把HTML源代码拿回来,加载HTML的时候,遇到link/script/img[src]/iframe/video和audio[没有设置preload=‘none’]…都会重新和服务器端建立HTTP事务交互
特殊情况:如果我们做了资源缓存处理(304),而且即将加载的资源在之前已经加载过了,这样的操作和传统的HTTP事务有所不一样,他们是从服务器和浏览器的缓存中读取数据,比传统的读取快很多
4.在客户端向服务器发送请求,以及服务器把内容响应给客户端的时候,中间相互传递了很多内容(客户端把一些内容传递服务器,服务器把一些内容响应给客户端),我们把传递的内容统称为“HTTP报文”
Maven
- 在javaweb整个开发过程中,需要使用大量的jar包,则需要手动导包。
- maven就解决了手动导包的问题,maven可以自动导包。
官网地址
- 配置环境变量
-
查看maven是否安装成功
-
配置阿里云镜像:
加速依赖的下载速度
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
-
本地仓库
由于maven约定大于配置,我们之后会遇到写在java目录下的配置文件无法被导出或加载,解决方案:
<!--在build中配置resource,防止资源导出失败的问题--> <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>
Servlet
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序
,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据
,生成动态Web内容
。
狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
最早支持Servlet标准的是JavaSoft的Java Web Server,此后,一些其它的基于Java的Web服务器开始支持标准的Servlet。
mapping映射
为什么需要mapping映射:
我们写的java程序需要使用浏览器访问,而浏览器需要请求web服务器,所有我们需要向web服务器中注入servlet,还需要给它一个浏览器访问的路径。
第一个Servlet程序
HelloServlet
package com.simon.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; public class HelloServlet extends HttpServlet { //get和post只是请求实现的不同方式,可以相互调用,业务逻辑是一样的; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("进入doGet方法"); PrintWriter writer = resp.getWriter(); writer.println("HelloServlet!"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <!-- 随意取个name,但是下面的映射name需要与之相同--> <servlet-name>hello</servlet-name> <!-- 文件路径--> <servlet-class>com.simon.servlet02.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <!-- 请求路径--> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
最终的执行结果:
1.共享数据
ServletContext官方叫servlet上下文。服务器会为每一个工程创建一个对象,这个对象就是ServletContext对象。ServletContext对象可以保存数据,供其他文件去获取;这个对象全局唯一,而且工程内部的所有servlet都
共享这个对象
。所以叫全局应用程序共享对象。
//存数据到servletContext中 public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("hello!"); // this.getServletConfig();servlet配置 // this.getInitParameter();初始化参数 // this.getServletContext();servlet上下文 ServletContext servletContext = this.getServletContext(); String name = "simon"; servletContext.setAttribute("name",name); } //从servletContext中读取数据 public class HelloServlet01 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); String name = (String) servletContext.getAttribute("name"); //设置编码,否则读取的读取乱码 resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); //打印 resp.getWriter().println("姓名:"+name); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
2.初始化参数
public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("helloServlet!"); ServletContext servletContext = this.getServletContext(); //获取初始化参数 String initParameter = servletContext.getInitParameter("url"); resp.getWriter().println(initParameter);//jdbc:mysql://localhost:3306/mybatis }
<!-- 初始化参数--> <context-param> <param-name>url</param-name> <param-value>jdbc:mysql://localhost:3306/mybatis</param-value> </context-param> <!--映射--> <servlet> <servlet-name>gp</servlet-name> <servlet-class>com.simon.servlet02.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>gp</servlet-name> <url-pattern>/gp</url-pattern> </servlet-mapping>
3. 请求转发
public class HelloServlet02 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("helloServlet02"); ServletContext servletContext = this.getServletContext(); //请求转发 RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/gp"); //调用forward()实现请求转发 //实现请求转发,路径是不会改变的。 requestDispatcher.forward(req,resp); }
<!-- 映射 --> <servlet> <servlet-name>hs2</servlet-name> <servlet-class>com.simon.servlet02.HelloServlet02</servlet-class> </servlet> <servlet-mapping> <servlet-name>hs2</servlet-name> <url-pattern>/hs2</url-pattern> </servlet-mapping>
4. 读取资源文件
public class HelloServlet03 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("helloServlet03"); //getResourceAsStream(),资源变成流 // 资源文件路径:/WEB-INF/classes/db.properties InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties"); //new Properties()对象 Properties prop = new Properties(); //加载流 prop.load(is); //获取资源文件属性 String username = prop.getProperty("username"); String password = prop.getProperty("password"); //打印:username:root password:root resp.getWriter().println("username:"+username+"password:"+password); }
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象
、和代表响应的response对象
。
request和response对象即然代表请求和响应
,那我们要获取客户机提交过来的数据,只需要找request对象就行了。要向客户机输出数据,只需要找response对象就行了。
常用方法
-
负责向浏览器发送数据的方法:
public PrintWriter getWriter() throws IOException; public ServletOutputStream getOutputStream() throws IOException;
-
负责向浏览器发送响应头的方法:
public void setCharacterEncoding(String charset); public void setContentLength(int len); public void setContentLengthLong(long len); public void setContentType(String type); public void setDateHeader(String name, long date); public void addDateHeader(String name, long date); public void setHeader(String name, String value); public void addHeader(String name, String value); public void setIntHeader(String name, int value); public void addIntHeader(String name, int value); public void setStatus(int sc);
-
重定向方法:
public void sendRedirect(String location) throws IOException;
实例代码:
返回需要访问的地址:
resp.sendRedirect("/servlet02_war/gp");
常见应用
-
下载文件:
package com.simon.servlet02; 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.*; import java.net.URLEncoder; public class HelloServlet04 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("helloServlet04"); //获取下载文件路径 String path = "G:\\idea\\javaweb-servlet\\servlet02\\src\\main\\resources\\timg.jpg"; //下载的文件名 String fileName = path.substring(path.indexOf("\\") + 1); //设置浏览器能够支持下载我们需要的东西 //URLEncoder.encode(fileName,"utf-8")字符集编码,使其不乱码 resp.setHeader("Content-disposition","attachment;filename"+ URLEncoder.encode(fileName,"utf-8")); //获取下载文件的输入流 FileInputStream fis = new FileInputStream(path); //创建缓冲区 int len = 0; byte[] buffer = new byte[1024]; //获取OutputStream对象 ServletOutputStream sos = resp.getOutputStream(); //将FileOutputStream流写入到buffer缓冲区 //使用OutputStream对象将缓冲区的文件输出到客户端 while ((len = fis.read(buffer)) != -1){ sos.write(buffer,0,len); } //关闭流操作 sos.close(); fis.close(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
-
验证码功能
- 前端实现:
- 后端实现:需要用到java图片类,生成一个图片
package com.simon.servlet02; import javax.imageio.ImageIO; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.Random; public class HelloServlet05 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("helloServlet05"); //如何让浏览器3s刷新一次 resp.setHeader("refresh","3"); //在内存中创建一个图片 BufferedImage image = new BufferedImage(80,30,BufferedImage.TYPE_INT_RGB); //得到图片 //画笔 Graphics2D graphics = (Graphics2D) image.getGraphics(); //设置图片的背景颜色 graphics.setBackground(Color.BLUE); graphics.fillRect(0,0,80,30); //给图片写数据 HelloServlet05 servlet05 = new HelloServlet05(); servlet05.random(); //画笔换个颜色 graphics.setColor(Color.GREEN); graphics.setFont(new Font(null,Font.BOLD,20)); graphics.drawString(random(),0,20); //告诉浏览器,这个请求用图片的打开方式 resp.setContentType("image/jpg"); //网站存在缓存,设置浏览器不让缓存 resp.setDateHeader("expires",-1); resp.setHeader("Cache-Control","no-cache"); //把图片写给浏览器 boolean b = ImageIO.write(image, "jpg", resp.getOutputStream()); } //生成随机数 private String random(){ Random random = new Random(); String s = random.nextInt(9999) + ""; StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 4 - s.length() ; i++) { buffer.append(0); } s = buffer + s; return s; } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
-
不同:
-
request.getRequestDispatcher()是容器中控制权的转向,
在客户端浏览器地址栏中不会显示出转向后的地址;服务器内部转发,整个过程处于同一个请求当中。
-
response.sendRedirect()则是完全的跳转,
浏览器将会得到跳转的地址,并重新发送请求链接。
这样,从浏览器的地址栏中可以看到跳转后的链接地址。不在同一个请求。重定向,实际上客户端会向服务器端发送两个请求。
所以转发中数据的存取可以用request作用域:request.setAttribute(), request.getAttribute()
,重定向是取不到request中的数据的。只能用session。
-
forward()更加高效
,在可以满足需要时,尽量使用RequestDispatcher.forward()方法。 -
RequestDispatcher是通过调用HttpServletRequest对象的getRequestDispatcher()方法得到的,是属于
请求对象的方法
。 -
sendRedirect()是HttpServletResponse对象的方法,即
响应对象的方法
,既然调用了响应对象的方法,那就表明整个请求过程已经结束了,服务器开始向客户端返回执行的结果。 -
重定向可以跨域访问,而转发是在web服务器内部进行的,不能跨域访问。
-
-
相同:
- 页面均可以实现跳转
-
获取前端传递的参数
String parameter = req.getParameter(); String[] parameterValues = req.getParameterValues();
package com.simon.servlet02; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Arrays; public class HelloServlet06 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("helloServlet06"); //编码字符集 req.setCharacterEncoding("utf-8"); resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); //获取前端参数 String parameter1 = req.getParameter("username"); String parameter2 = req.getParameter("pwd"); String[] parameterValues = req.getParameterValues("hobbys"); System.out.println(parameter1); System.out.println(parameter2); System.out.println(Arrays.toString(parameterValues)); //请求转发 req.getRequestDispatcher("/successful.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>index</title> </head> <body> <form action="${pageContext.request.contextPath}/hs6" method="post"> 用户名: <input type="text" name="username" placeholder="请输入用户名:"/><br/> 密码: <input type="password" name="pwd" placeholder="请输入密码:"/><br/> 爱好: <input type="checkbox" name="hobbys" value="篮球"/>篮球 <input type="checkbox" name="hobbys" value="羽毛球"/>羽毛球 <input type="checkbox" name="hobbys" value="乒乓球"/>乒乓球 <input type="checkbox" name="hobbys" value="足球"/>足球<br/> <input type="submit" name="Submit" /> </form> </body> </html>
- 请求转发
req.getRequestDispatcher("/successful.jsp").forward(req,resp);
Session&Cookie
会话
:指用户登录网站后的一系列动作,比如浏览商品添加到购物车并购买。
会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session
。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定
协议
是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则
,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。
HTTP协议是无状态的协议
。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。
Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录
在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
每个用户访问服务器都会建立一个session,那服务器是怎么标识用户的唯一身份呢?事实上,用户与服务器建立连接的同时,服务器会自动为其分配一个SessionId。
package com.simon.servlet02; import com.simon.entity.Person; 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; public class HelloServlet08 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("helloServlet08"); req.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); resp.setCharacterEncoding("utf-8"); //获取 Session HttpSession session = req.getSession(); //给session中存东西 session.setAttribute("name","simon"); //存对象 session.setAttribute("person",new Person("simon",22,"man")); //获取session中的数据 String name = (String) session.getAttribute("name"); Person person = (Person) session.getAttribute("person"); resp.getWriter().println(name); resp.getWriter().println(person); //获取id String id = session.getId(); //判断session是否是新的 boolean aNew = session.isNew(); if(aNew){ resp.getWriter().println("第一次创建:"+id); }else{ resp.getWriter().println("已经创建了:"+id); } //移除session中存在的元素 session.removeAttribute("name"); //注销session,手动失效 session.invalidate(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
session自动失效:
<session-config> <!--60min后自动失效--> <session-timeout>60</session-timeout> </session-config>
由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。服务器要想识别每个客户端,怎么办,那就给每个访问我的用户的客户的一个通行证,这样服务器就能从通行证上确认客户身份了,这个通行证就是cookie的工作原理。
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端会把Cookie保存起来。
当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
package com.simon.servlet02; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; //保存用户上次访问浏览器的时间 public class HelloServlet07 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("helloServlet07"); //解决乱码问题 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.println("上次访问的时间是:"); for (int i = 0; i < cookies.length; i++) { Cookie cookie = cookies[i]; //获取cookie的name String name = cookie.getName(); if(name.equals("datetime")){ //获取cookie的值value String value = cookie.getValue(); //时间戳转时间格式 long datetime = Long.parseLong(value); Date date = new Date(datetime); //格式化时间 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String format = dateFormat.format(date); //打印值 out.println(format); } } }else{ out.println("第一次访问!"); } System.out.println(new Date());//Wed Oct 14 14:54:47 CST 2020 //创建cookie对象 Cookie cookie = new Cookie("datetime", System.currentTimeMillis() + ""); //添加cookie resp.addCookie(cookie); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
记录用户访问次数
Java中把Cookie封装成了javax.servlet.http.Cookie类。每个Cookie都是该Cookie类的对象。服务器通过操作Cookie类对象对客户端Cookie进行操作。通过request.getCookie()
获取客户端提交的所有Cookie(以Cookie[]数组形式返回),通过response.addCookie(Cookie cookie)
向客户端设置Cookie。
Cookie对象使用key-value
属性对的形式保存用户状态,一个Cookie对象保存一个属性对,一个request或者response同时使用多个Cookie。因为Cookie类位于包javax.servlet.http.*下面,所以JSP中不需要import该类。
Cookie的不可跨域名性
很多网站都会使用Cookie。例如,Google会向客户端颁发Cookie,Baidu也会向客户端颁发Cookie。那浏览器访问Google会不会也携带上Baidu颁发的Cookie呢?或者Google能不能修改Baidu颁发的Cookie呢?
答案是否定的。Cookie具有不可跨域名性
。根据Cookie规范,浏览器访问Google只会携带Google的Cookie,而不会携带Baidu的Cookie。Google也只能操作Google的Cookie,而不能操作Baidu的Cookie。
Cookie在客户端是由浏览器来管理的。浏览器能够保证Google只会操作Google的Cookie而不会操作Baidu的Cookie,从而保证用户的隐私安全。浏览器判断一个网站是否能操作另一个网站Cookie的依据是域名。Google与Baidu的域名不一样,因此Google不能操作Baidu的Cookie。
需要注意的是,虽然网站images.google.com与网站www.google.com同属于Google,但是域名不一样,二者同样不能互相操作彼此的Cookie。
注意:用户登录网站www.google.com之后会发现访问images.google.com时登录信息仍然有效,而普通的Cookie是做不到的。这是因为Google做了特殊处理。
设置Cookie的所有属性
private String name; // NAME= ... "$Name" style is reserved private String value; // value of NAME // // Attributes encoded in the header's cookie fields. // private String comment; // ;Comment=VALUE ... describes cookie's use // ;Discard ... implied by maxAge < 0 private String domain; // ;Domain=VALUE ... domain that sees cookie private int maxAge = -1; // ;Max-Age=VALUE ... cookies auto-expire private String path; // ;Path=VALUE ... URLs that see the cookie private boolean secure; // ;Secure ... e.g. use SSL private int version = 0; // ;Version=1 ... means RFC 2109++ style private boolean isHttpOnly = false;
Cookie的有效期
Cookie的maxAge
决定着Cookie的有效期,单位为秒(Second)
。Cookie中通过getMaxAge()方法与setMaxAge(int maxAge)方法来读写maxAge属性。 如果maxAge属性为正数,则表示该Cookie会在maxAge秒之后自动失效
。浏览器会将maxAge为正数的Cookie持久化,即写到对应的Cookie文件中。无论客户关闭了浏览器还是电脑,只要还在maxAge秒之前,登录网站时该Cookie仍然有效。下面代码中的Cookie信息将永远有效。
Cookie cookie = new Cookie("username","helloweenvsfei"); // 新建Cookie cookie.setMaxAge(Integer.MAX_VALUE); // 设置生命周期为MAX_VALUE response.addCookie(cookie); // 输出到客户端
-
如果maxAge为负数,则表示该Cookie仅在本浏览器窗口以及本窗口打开的子窗口内有效,关闭窗口后该Cookie即失效。maxAge为负数的Cookie,为临时性Cookie,不会被持久化,不会被写到Cookie文件中。Cookie信息保存在浏览器内存中,因此关闭浏览器该Cookie就消失了。Cookie默认的maxAge值为–1。
-
如果maxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie的方法,因此通过设置该Cookie即时失效实现删除Cookie的效果。失效的Cookie会被浏览器从Cookie文件或者内存中删除:
Cookie的修改、删除
Cookie并不提供修改、删除操作。如果要修改某个Cookie,只需要新建一个同名的Cookie,添加到response中覆盖原来的Cookie。如果要删除某个Cookie,只需要新建一个同名的Cookie,并将maxAge设置为0,并添加到response中覆盖原来的Cookie。注意是0而不是负数。负数代表其他的意义。读者可以通过上例的程序进行验证,设置不同的属性。
注意:修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。
//设置一个同名的cookie,进行覆盖 Cookie cookie = new Cookie(""); //将失效时间设置为0 cookie.setMaxAge(0); //添加cookie resp.addCookie(cookie);
Cookie的安全属性
HTTP协议不仅是无状态的,而且是不安全的。
使用HTTP协议的数据不经过任何加密就直接在网络上传播,有被截获的可能。使用HTTP协议传输很机密的内容是一种隐患。如果不希望Cookie在HTTP等非安全协议中传输,可以设置Cookie的secure属性为true。
浏览器只会在HTTPS和SSL等安全协议中传输此类Cookie。下面的代码设置secure属性为true:
Cookie cookie = new Cookie("time", "20080808"); // 新建Cookie cookie.setSecure(true); // 设置安全属性 response.addCookie(cookie); // 输出到客户端
1、cookie数据是存储在客户的浏览器上,session数据是存储在服务器上的;
2、cookie只是一个通行证,但并不是安全的,任何安全的校验必须要在服务端上完成,cookie只是存在客户端上面的一个唯一标识它且由服务端定制的信息,本地可以改,但是不管怎么改,最后还是需要把它拿上发送给服务端进行匹配校验;
3、session和cookie的存储都存在时效性,这是很有必要的;
4、单个cookie保存的数据不能超过4kb,很多浏览器都限制了一个站点最多保存20个cookie;
JSP
JSP全称Java Server Pages
,是一种动态网页开发技术
。它使用JSP标签在HTML网页中插入Java代码。标签通常以<%开头以%>结束。
JSP是一种Java servlet,主要用于实现Java web应用程序的用户界面部分
。网页开发者们通过结合HTML代码、XHTML代码、XML元素以及嵌入JSP操作和命令来编写JSP。
JSP通过网页表单获取用户输入数据、访问数据库及其他数据源,然后动态地创建网页。
JSP标签有多种功能,比如访问数据库、记录用户选择信息、访问JavaBeans组件等,还可以在不同的网页中传递控制信息和共享信息。
依赖
<!-- jsp依赖 --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency> <!-- servlet依赖 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!-- jstl表达式 --> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- standard标签库 --> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency>
jsp表达式
<%--jsp 表达式--%> <%-- 将程序输出到客户端 <%= 变量or表达式%> --%> <%= new java.util.Date()%>
脚本片段
<%--jsp脚本片段--%> <% int sum = 0; for (int i = 0; i < 100; i++) { sum += i; } out.print(sum); %>
jsp声明
<%--jsp声明 <%! 声明的变量or方法 ;%> --%> <%! int i = 0; %> <%! int a, b, c; %> <%! Circle a = new Circle(2.0); %>
jsp注释
<%-- 该部分注释在网页中不会被显示--%>
Page指令
<%@ page attribute="value" %> <--指定当JSP页面发生异常时需要转向的错误处理页面--> <%@page errorPage="error.jsp" %>
属性:
下表列出与Page指令相关的属性:
属性 | 描述 |
---|---|
buffer | 指定out对象使用缓冲区的大小 |
autoFlush | 控制out对象的 缓存区 |
contentType | 指定当前JSP页面的MIME类型和字符编码 |
errorPage | 指定当JSP页面发生异常时需要转向的错误处理页面 |
isErrorPage | 指定当前页面是否可以作为另一个JSP页面的错误处理页面 |
extends | 指定servlet从哪一个类继承 |
import | 导入要使用的Java类 |
info | 定义JSP页面的描述信息 |
isThreadSafe | 指定对JSP页面的访问是否为线程安全 |
language | 定义JSP页面所用的脚本语言,默认是Java |
session | 指定JSP页面是否使用session |
isELIgnored | 指定是否执行EL表达式 |
isScriptingEnabled | 确定脚本元素能否被使用 |
Include指令
<%@ include file="文件相对 url 地址" %>
Taglib指令
<%@ taglib uri="uri" prefix="prefixOfTag" %>
对象 | 描述 |
---|---|
request | HttpServletRequest 接口的实例 |
response | HttpServletResponse 接口的实例 |
out | JspWriter类的实例,用于把结果输出至网页上 |
session | HttpSession类的实例 |
application | ServletContext类的实例,与应用上下文有关 |
config | ServletConfig类的实例 |
pageContext | PageContext类的实例,提供对JSP页面所有对象以及命名空间的访问 |
page | 类似于Java类中的this关键字 |
Exception | Exception类的对象,代表发生错误的JSP页面中对应的异常对象 |
EL表达式:${}
- 获取数据
- 执行运算
- 获取web开发的常用对象
jsp标签:
动作元素基本上都是预定义的函数,JSP规范定义了一系列的标准动作,它用JSP作为前缀,可用的标准动作元素如下:
语法 | 描述 |
---|---|
jsp:include | 在页面被请求的时候引入一个文件。 |
jsp:useBean | 寻找或者实例化一个JavaBean。 |
jsp:setProperty | 设置JavaBean的属性。 |
jsp:getProperty | 输出某个JavaBean的属性。 |
jsp:forward | 把请求转到一个新的页面。 |
jsp:plugin | 根据浏览器类型为Java插件生成OBJECT或EMBED标记。 |
jsp:element | 定义动态XML元素 |
jsp:attribute | 设置动态定义的XML元素属性。 |
jsp:body | 设置动态定义的XML元素内容。 |
jsp:text | 在JSP页面和文档中使用写入文本的模板 |
JSP 标准标签库(JSTL)
JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。
JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。 除了这些,它还提供了一个框架来使用集成JSTL的自定义标签。
根据JSTL标签所提供的功能,可以将其分为5个类别。
- 核心标签
核心标签是最常用的 JSTL标签。引用核心标签库的语法如下:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
标签 | 描述 |
---|---|
<c:out> | 用于在JSP中显示数据,就像<%= … > |
<c:set> | 用于保存数据 |
<c:remove> | 用于删除数据 |
<c:catch> | 用来处理产生错误的异常状况,并且将错误信息储存起来 |
<c:if> | 与我们在一般程序中用的if一样 |
<c:choose> | 本身只当做<c:when>和<c:otherwise>的父标签 |
<c:when> | <c:choose>的子标签,用来判断条件是否成立 |
<c:otherwise> | <c:choose>的子标签,接在<c:when>标签后,当<c:when>标签判断为false时被执行 |
<c:import> | 检索一个绝对或相对 URL,然后将其内容暴露给页面 |
<c:forEach> | 基础迭代标签,接受多种集合类型 |
<c:forTockens> | 根据指定的分隔符来分隔内容并迭代输出 |
<c:param> | 用来给包含或重定向的页面传递参数 |
<c:redirect> | 重定向至一个新的URL. |
<c:url> | 使用可选的查询参数来创造一个URL |
- 格式化标签
- SQL 标签
- XML 标签
- JSTL 函数
JavaBean 是特殊的 Java 类(实体类)
,使用 Java 语言书写,并且遵守 JavaBean API 规范。
接下来给出的是 JavaBean 与其它 Java 类相比而言独一无二的特征:
- 提供一个默认的无参构造函数。
- 需要被序列化并且实现了 Serializable 接口。
- 属性必须私有化。
- 必须有相应的 get 或 set方法。
一般用来和数据库的字段做映射;
实体类都是和数据库表字段一一对应;
实例:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> <title>get 和 set 属性实例</title> </head> <body> <jsp:useBean id="students" class="com.runoob.StudentsBean"> <jsp:setProperty name="students" property="firstName" value="小强"/> <jsp:setProperty name="students" property="lastName" value="王"/> <jsp:setProperty name="students" property="age" value="10"/> <p>学生名字: <jsp:getProperty name="students" property="firstName"/> </p> <p>学生姓氏: <jsp:getProperty name="students" property="lastName"/> </p> <p>学生年龄: <jsp:getProperty name="students" property="age"/> </p> </body> </html>
MVC:
模型Model
模型负责各个功能的实现(如登录、增加、删除功能)。模型用JavaBean实现。
视图View
负责页面的显示;与用户的交互。包含各种表单。 实现视图用到的技术有html/css/jsp/js等前端技术。
用户交互:用户鼠标点击页面;填写页面中各种表单…等等
控制器Controller
控制器负责将视图与模型一一对应起来。相当于一个模型分发器。所谓分发就是:①接收请求,并将该请求跳转(转发,重定向)到模型进行处理。②模型处理完毕后,再通过控制器,返回给视图中的请求处。建议使用Servlet实现控制器。
三层架构:
首先来说,三层架构与MVC的目标一致:都是为了解耦和、提高代码复用。MVC是一种设计模式,而三层架构是一种软件架构。
三层架构分为:表现层(UI)(web层)、业务逻辑层(BLL)(service层)、数据访问层(DAL)(dao层),再加上实体类库(Model)
1.实体类库(Model),在Java中,往往将其称为Entity实体类。数据库中用于存放数据,而我们通常选择会用一个专门的类来抽象出数据表的结构,类的属性就一对一的对应这表的属性。
- 一般来说,Model实体类库层需要被DAL层,BIL层和UI层引用。
2.数据访问层(DAL),主要是存放对数据类的访问,即对数据库的添加、删除、修改、更新等基本操作
- DAL就是根据业务需求,构造SQL语句,构造参数,调用帮助类,获取结果,DAL层被BIL层调用
3.业务逻辑层(BLL)
- BLL层好比是桥梁,将UI表示层与DAL数据访问层之间联系起来。所要负责的,就是处理涉及业务逻辑相关的问题,比如在调用访问数据库之前,先处理数据、判断数据。
JSP 和 Servlet 中的过滤器都是 Java 类。
过滤器可以动态地拦截请求和响应
,以变换或使用包含在请求或响应中的信息。
可以将一个或多个过滤器附加到一个 Servlet 或一组 Servlet。过滤器也可以附加到 JavaServer Pages (JSP) 文件和 HTML 页面。
过滤器是可用于 Servlet 编程的 Java 类,可以实现以下目的:
- 在客户端的请求访问后端资源之前,拦截这些请求。
- 在服务器的响应发送回客户端之前,处理这些响应。
Filter开发步骤:
-
导包
<dependencies> <!-- jsp依赖 --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency> <!-- servlet依赖 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!-- jstl表达式 --> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- standard标签库 --> <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.16</version> </dependency> </dependencies>
-
编写过滤器
import javax.servlet.*;
package com.simon.filter; import javax.servlet.*; import java.io.IOException; public class TestFilter implements Filter { //服务器启动就已经初始化了,是因为需要随时监听,等待过滤对象的出现。 @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始化参配置"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("text/html"); System.out.println("过滤前"); //让请求继续走,否则程序就在此停止了。 chain.doFilter(request,response); System.out.println("过滤后"); } //web服务器关闭的时候,过滤器会进行销毁。 @Override public void destroy() { System.out.println("销毁操作"); } }
-
配置web.xml
<servlet> <servlet-name>servlet</servlet-name> <servlet-class>com.simon.servlet03.Servlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>servlet</servlet-name> <url-pattern>/servlet/show</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>servlet</servlet-name> <url-pattern>/show</url-pattern> </servlet-mapping> <!--过滤器映射--> <filter> <filter-name>filter</filter-name> <filter-class>com.simon.filter.TestFilter</filter-class> </filter> <filter-mapping> <filter-name>filter</filter-name> <!-- 只要在servlet路径下的任何请求,都会经过过滤器--> <url-pattern>/servlet/*</url-pattern> <!-- 会过滤所有的请求--> <!-- <url-pattern>/*</url-pattern>--> </filter-mapping>
ption, ServletException {
request.setCharacterEncoding(“utf-8”);
response.setCharacterEncoding(“utf-8”);
response.setContentType(“text/html”);
System.out.println(“过滤前”);
//让请求继续走,否则程序就在此停止了。
chain.doFilter(request,response);
System.out.println(“过滤后”);
}
//web服务器关闭的时候,过滤器会进行销毁。
@Override
public void destroy() {
System.out.println(“销毁操作”);
}
}
3. 配置web.xml
```xml
<servlet>
<servlet-name>servlet</servlet-name>
<servlet-class>com.simon.servlet03.Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet</servlet-name>
<url-pattern>/servlet/show</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>servlet</servlet-name>
<url-pattern>/show</url-pattern>
</servlet-mapping>
<!--过滤器映射-->
<filter>
<filter-name>filter</filter-name>
<filter-class>com.simon.filter.TestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<!-- 只要在servlet路径下的任何请求,都会经过过滤器-->
<url-pattern>/servlet/*</url-pattern>
<!-- 会过滤所有的请求-->
<!-- <url-pattern>/*</url-pattern>-->
</filter-mapping>
Java Web笔记总结相关教程
-
Vscode Web开发 setting.json相关配置
Vscode Web开发 setting.json相关配置 ctrl+shift+p输入setting.js选首选项 setting.json配置 {liveServer.settings.donotShowInfoMsg:true,vetur.format.defaultFormatter.html:js-beautify-html,//html不换行vetur.format.defaultFormatter.js:vscode-types
-
如何优雅的使用Arthas-Java诊断工具
如何优雅的使用Arthas-Java诊断工具 官网地址:https://arthas.aliyun.com/en-us/ 注:此处演示以idea插件进行演示 点击quick start 点击IDEA Plugin idea安装arthas idea插件 curl -O https://arthas.aliyun.com/arthas-boot.jarjava -jar arthas-boot.jar
-
JAVA学习笔记—JAVA SE(五)JAVA新特性和项目
JAVA学习笔记—JAVA SE(五)JAVA新特性和项目 文章目录 五、Java新特性和项目 1. 常用设计原则和设计模式 1.1 常用的设计原则 1.1.1 软件开发的流程 1.1.2 常用的设计原则 1.2 常用的设计模式 1.2.1 基本概念 1.2.2 基本分类 1.3 设计模式详解 1.3.1 单例设
-
Java学习笔记
Java学习笔记 java 学习笔记 4.1:Java程序的编写: 在java中,如果源代码只有一个类,那么类的名称要与文件名一致,否则会出错。 Java大小写敏感,请注意! 4.2:Java文件的命名规则: 只要是Java程序就必须放在一个类中,例如 [public] class 类名称{} 首字
-
【web】JWT(Json web token)的原理、签发、验证
【web】JWT(Json web token)的原理、签发、验证 1.JWT JWT(Json web token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景 http协议本身是一种无状态的协议,
-
JavaWeb - 【Filter】表单显示
JavaWeb - 【Filter】表单显示 需求分析 程序设计 MyFilter index.jsp product_input.jsp table product_details.jsp 效果测试 一:需求分析 二:程序设计 1 MyFilter package xyz.xx.filter;import org.apache.commons.beanutils.BeanUtils;import xyz.xx.po
-
java三特性之继承
java三特性之继承 继承 龙生龙,凤生凤,老鼠的儿子会打洞 这应该就是我对对继承的理解了吧 继承就是 子类可以调用父类的成员和方法 ( 私有的除外,毕竟谁还没点小秘密 ) 父类也被称之为基类或者超类,( 其实都是一个东西 ) 格式如下?? public class 子类
-
TypeScript
TypeScript TypeScript是JavaScript超集(superset) TypeScript 安装(npm) 安装typescript依赖 npm i typescript -D 这一步安装完成之后其实就可以使用tsc命令来执行TypeScript的相关代码了 配置tsconfig.json文件 tsc --init 生成的配置文件如下: { compil