JavaWeb笔记

作者:@冰山醉酒
本文为作者原创,转载请注明出处:https://www.cnblogs.com/douFrank/p/16117840.html


1|0JavaWeb

1|1基本概念

  • web,网页的意思,www.baiud.com

  • 静态web

    • html.,css

    • 提供给所有人看的数据始终不会发生变化!

  • 动态web

    • 淘宝,几乎所有的网站

    • 提供给所有人看的数据据始终会发生变化

    • 技术栈:Servlet/JSP,ASP,PHP

在Java中,动态web资源开发的技术统称为JavaWeb;

1|2web应用程序

web应用程序:可以提供浏览器访问的程序

  • a.html,b.html……多个web资源,这些web资源可以被外界访问,对外界提供服务

  • 你们能访问到的任意一个网页或者资源,都存在世界的某一个角落的计算机上

  • URL

  • 这个统一的web资源会被放在同一个文件夹下,web应用程序-->Tomcat:服务器

  • 一个web应用由多部分组成()静态web,动态web)

    • html,css,js

    • jsp,servlet

    • Java程序

    • jar包

    • 配置文件(properties)

web应用程序编写完毕后,若想提供给外界访问:需要一个服务器统一管理

1|3静态web

  • 静态web存在的缺点

    • web页面无法动态刷新,所有的用户看到的都是同一个页面

      • 轮播图,点击特效:伪动态

      • JavScript【实际开发中,它用的最多】

      • VBScript

    • 它无法和数据库交互(数据库无法持久化,用户无法交互)

1|4动态web

页面会动态展示:web的页面展示的效果因人而异

缺点:

  • 加入服务器的动态web资源出现了错误,我们需要重新编写我们的后台程序,重新发布

    • 停机维护

优点:

  • web页面可以动态更新,所有用户看到的不是同一个页面

  • 它可以与数据库交互(数据持久化,注册,商品信息,用户信息……)

2|0web服务器

2|1编程工具

ASP:

  • 微软

  • 页面过于混乱

php:

  • PHP开发速度块,功能很强大,跨平台,diamagnetic很简单(70%,)

  • 无法承载大访问量的情况

JSP/Servlet:

  • B/S:浏览器和服务器

  • C/S:客户端和服务器

  • sun控死主推的B/S架构

  • 可以承载三高问题带来的影响

2|2web服务器

服务器是一种被动的操作,用来处理用户的一些请求和给用户的一些响应信息

IIS

微软的,ASP windows中自带的

Tomcat

3|0TomCat

3|1基础配置

文件夹的作用:

启动:start.bat,关闭shutdown.bat

测试:loacalhost:8080

可以更改配置的端口号

  • tomcat的默认端口号:8080

  • mysql:3306

  • http:80

  • https:443

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/>

可以更改主机名称

  • 默认的主机名为:localhost-->127.0.0.1

  • 默认网站应用存放的位置:webapps

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">

高难度面试题

谈谈网站是如何进行访问的

1,输入一个域名;回车

2,检查本机的C:\Windows\System32\drivers\etc\hosts配置文件下有没有这个域名映射:

1,有:直接返回对应的IP地址,这个地址中,由我们需要访问的web程序,可以直接访问

 127.0.0.1 localhost

2,没有:去DNS服务器找,找到的话就返回,找不到就返回找不到;

3,可以配置一些环境变量

3|2发布一个网站

不会就模仿

  • 将自己写的网址,放到服务器(TomCat)中指定的web应用的文件夹(webapps)下,就可以访问了

网站应该有的结构

-- webapps:tomCat服务器的web目录 - Root - XXX :网站的目录名 - WEB-INF - classes:java程序 - lib:web应用所依赖的jar包 - web.xml:网站的配置文件 - index.html 默认的首页 - static - css - img - ……

4|0Http

4|1什么是HTTP

HTTP(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上

  • 80

https:安全的

  • 443

4|2http请求

  • 客户端--发请求(Request)==服务器

百度:

请求 URL: https://www.baidu.com/ 请求方法: GET 状态代码: 200 OK 远程地址: 110.242.68.4:443 引用站点策略: strict-origin-when-cross-origin
Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 Cache-Control: max-age=0 Connection: keep-alive

请求行

  • 请求行的请求方式:GET

  • 请求方式 get,post,head,delete,put.tract

    • get:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏中显示数据内容,不安全,但高效

    • post:请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏中显示数据内容,安全,但不高效

消息头

Accept:告诉浏览器,它所支持的数据类型 Accept-Encoding: 支持哪种编码方式 GBK,UTF-8 GB2312 ISO8859-1 Accept-Language: 告诉浏览器,他的语言环境 Cache-Control: 缓存控制 Connection:告诉浏览器,请求完成是都拿开还是保持连接 

4|3http响应

  • 服务器==响应---客户端

百度:

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:主机..../ Refresh:告诉客户端,多久刷新一次 Location:让网页重新定位;

响应状态码

200:请求响应成功

3xx:请求重新相应

  • 重定向:重新到给的新地址

4xx:找不到资源 404

  • 资源不存在

5xx:服务器代码错误 500 502网关错误

常见面试题

当你的浏览器中地址栏输入地址并回车的一瞬间到页面能够展示回来,经历了什么?

5|0Maven

1,在JavaWeb开发中,需要使用大量的jar包,我们手动去导入

2,如何能够让一个东西自动帮助导入和配置这个jar包,由此,Maven诞生了

5|1Maven项目框架管理工具

我们目前用来就是方便导入Jar包的

Maven的核心思想:约定大于配置

  • 有约定,不要去违反

maven会规定号你该如何去编写我们的Java代码,必须要按照这个规范来

5|2阿里云镜像

  • 镜像:mirrors

    • 作用:加速我们的下载

  • 国内建议使用阿里云的镜像

<mirror> <id>nexus-aliyun</id> <mirrorOf>central</mirrorOf> <name>Nexus aliyun</name> <url>https://maven.aliyun.com/nexus/content/groups/public</url> </mirror>

5|3本地仓库

在本地的仓库,远程仓库

建立一个本地仓库:localRepository

<localRepository>D:\Maven\apache-maven-3.8.5\maven-repo</localRepository>

5|4在IDEA中创建Maven项目

创建Maven项目;

5|5在IDEA中创建TomCat项目

5|6pom文件时Maven的核心配置文件

1 <?xml version="1.0" encoding="UTF-8"?> 2 <!--Maven版本和头文件--> 3 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 <!--这里就是我们仓才配置的GAV--> 7 <groupId>org.example</groupId> 8 <artifactId>Maven</artifactId> 9 <version>1.0-SNAPSHOT</version> 10 <!-- Package:项目的打包方式 11 jar:java应用 12 war:javaWeb应用--> 13 <packaging>war</packaging> 14 15 <name>Maven Maven Webapp</name> 16 <!-- FIXME change it to the project's website --> 17 <url>http://www.example.com</url> 18 <!--配置--> 19 <properties> 20 <!--项目的默认构建编码--> 21 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 22 <!--编码版本--> 23 <maven.compiler.source>1.8</maven.compiler.source> 24 <maven.compiler.target>1.8</maven.compiler.target> 25 </properties> 26 <!--项目依赖--> 27 <dependencies> 28 <!--具体项目依赖的jar包配置文件--> 29 <dependency> 30 <groupId>junit</groupId> 31 <artifactId>junit</artifactId> 32 <version>4.11</version> 33 <scope>test</scope> 34 </dependency> 35 </dependencies> 36 37 <build> 38 <finalName>Maven</finalName> 39 <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> 40 <plugins> 41 <plugin> 42 <artifactId>maven-clean-plugin</artifactId> 43 <version>3.1.0</version> 44 </plugin> 45 <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> 46 <plugin> 47 <artifactId>maven-resources-plugin</artifactId> 48 <version>3.0.2</version> 49 </plugin> 50 <plugin> 51 <artifactId>maven-compiler-plugin</artifactId> 52 <version>3.8.0</version> 53 </plugin> 54 <plugin> 55 <artifactId>maven-surefire-plugin</artifactId> 56 <version>2.22.1</version> 57 </plugin> 58 <plugin> 59 <artifactId>maven-war-plugin</artifactId> 60 <version>3.2.2</version> 61 </plugin> 62 <plugin> 63 <artifactId>maven-install-plugin</artifactId> 64 <version>2.5.2</version> 65 </plugin> 66 <plugin> 67 <artifactId>maven-deploy-plugin</artifactId> 68 <version>2.8.2</version> 69 </plugin> 70 </plugins> 71 </pluginManagement> 72 </build> 73 </project>

maven由于它的约定大于配置,我们之后可能遇到我们写的配置文件,无法导出或者生效的问题,解决方案:

1 <!--在build中配置resources,来防止我们资源导出失败的问题--> 2 <build> 3 <resources> 4 <resource> 5 <directory>src/main/resources</directory> 6 <includes> 7 <include>**/*.properties</include> 8 <include>**/*.xml</include> 9 </includes> 10 </resource> 11 <resource> 12 <directory>src/main/java</directory> 13 <includes> 14 <include>**/*.properties</include> 15 <include>**/*.xml</include> 16 </includes> 17 <filtering>true</filtering> 18 </resource> 19 </resources> 20 </build>

5|7IDEA操作

目录树

6|0maven仓库的使用

用来下载或者导入jar的依赖

网址:Maven Repository: Search/Browse/Explore (mvnrepository.com)

7|0servlet简介

  • servlet就是sun公司开发动态web的一门技术

  • sun在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:

    • 编写一个类,实现Servlet接口

    • 把开发好的Java类部署到web服务器中

把实现了Servlet接口的程序叫做Servlet

7|1HelloServlet

  1. 构建一个普通Maven的项目,删除里面的src目录,以后我们的学习就在这个项目里面建立moudel;这个空空城就是Maven的主工程;

  2. 关于Maven父子工程的理解

    父项目中会有

<modules> <module>servlet-01</module> </modules>

子项目中会有

<parent> <artifactId>javaweb-02-maven</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent>

父项目中的Java子项目可以直接使用

son extends father
  1. Maven环境优化

    1. 修改web.xml为最新的

    2. 将Maven的结构搭建完整

  2. 编写一个Servlet程序

    1. 编写一个普通类

    2. 实现Servlet接口,这里我们直接继承HttpServlet

      1 public class HelloServlet extends HttpServlet { 2 @Override 3 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 4 //ServletOutputStream outputStream = resp.getOutputStream(); 5 PrintWriter writer = resp.getWriter();//响应流 6 writer.print("Hello,Servlet!"); 7 } 8 9 @Override 10 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 11 doGet(req, resp); 12 } 13 }
    3. 编写Servlet的映射

      为什么需要映射:我们写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务器中注册我们写的Servlet,还需要给它有一个浏览器能够访问的路径。

      <!--web.xml中是配置我们web的核心应用--> <servlet> <servlet-name>s1</servlet-name> <servlet-class>com.study.servlet.HelloServlet</servlet-class> </servlet> <!--注册Servlet--> <servlet-mapping> <servlet-name>s1</servlet-name> <url-pattern>/study</url-pattern> </servlet-mapping>
    4. 配置Tomcat

      注意:配置项目发布的路径就可以了

    5. 启动测试

7|2Tomcat 10版本的坑

Tomacat 10 之后servlet依赖包名不是 javax.servlet,而是jakarta.servlet

需要加载jakarta包

1 <dependencies> 2 <!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api --> 3 <dependency> 4 <groupId>jakarta.servlet</groupId> 5 <artifactId>jakarta.servlet-api</artifactId> 6 <version>5.0.0</version> 7 <scope>provided</scope> 8 </dependency> 9 10 <!-- https://mvnrepository.com/artifact/jakarta.servlet.jsp/jakarta.servlet.jsp-api --> 11 <dependency> 12 <groupId>jakarta.servlet.jsp</groupId> 13 <artifactId>jakarta.servlet.jsp-api</artifactId> 14 <version>3.0.0</version> 15 <scope>provided</scope> 16 </dependency> 17 18 </dependencies>

7|3Srvlet原理

Servlet是由web服务器调用的,web服务器在收到浏览器的请求后,会:

7|4Mapping问题

  1. 一个Servlet可以指定一个映射路径

    <servlet-mapping> <servlet-name>s1</servlet-name> <url-pattern>/study</url-pattern> </servlet-mapping>
  2. 一个Servlet可以指定多个映射路径

    <servlet-mapping> <servlet-name>s1</servlet-name> <url-pattern>/study</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>s1</servlet-name> <url-pattern>/study1</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>s1</servlet-name> <url-pattern>/study2</url-pattern> </servlet-mapping>
  3. 一个Servlet可以指定通用映射路径

    <servlet-mapping> <servlet-name>s1</servlet-name> <!-- 可以干掉index.jsp --> <url-pattern>/*</url-pattern> </servlet-mapping>
  4. 一个Servlet可以指定前缀或后缀映射路径

    <servlet-mapping> <servlet-name>s1</servlet-name> <!-- 不能加斜线/ --> <url-pattern>*.do</url-pattern> </servlet-mapping>
  5. 优先级问题

    知道你过来固有的映射路径优先级最高,入股找不到就走默认的处理请求。

    <!-- 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>

7|5ServletContext

web容器在启动的时候,他会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用

1|01、共享数据

我再这个Servlet中保存的数据,可以在另一个servlet中拿到

ServletContent:全局唯一

 

 

 

package com.study.servlet; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); servletContext.setAttribute("姓名:","曜"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } } package com.study.servlet; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; public class GetServlet extends HelloServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); String username = (String) servletContext.getAttribute("姓名:"); 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-name>hello</servlet-name> <servlet-class>com.study.servlet.HelloServlet</servlet-class> </servlet> <!--一个Servlet对应一个Mapping:映射--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <servlet> <servlet-name>getc</servlet-name> <servlet-class>com.study.servlet.GetServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>getc</servlet-name> <url-pattern>/getc</url-pattern> </servlet-mapping>

1|02,获取初始化参数

1 package com.study.servlet; 2 3 import jakarta.servlet.ServletContext; 4 import jakarta.servlet.ServletException; 5 import jakarta.servlet.http.HttpServletRequest; 6 import jakarta.servlet.http.HttpServletResponse; 7 8 import java.io.IOException; 9 10 public class ServletDemo03 extends HelloServlet{ 11 @Override 12 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 13 ServletContext context = this.getServletContext(); 14 String url = context.getInitParameter("url"); 15 resp.getWriter().print(url); 16 } 17 18 @Override 19 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 20 doGet(req, resp); 21 } 22 } 23 //web.xml中注册 24 <!-- 配置一些web应用的初始化参数 --> 25 <context-param> 26 <param-name>url</param-name> 27 <param-value>jdbc:mysql://localhost:3306/mybatis</param-value> 28 </context-param>

1|03,请求转发

1 package com.study.servlet; 2 3 import jakarta.servlet.RequestDispatcher; 4 import jakarta.servlet.ServletContext; 5 import jakarta.servlet.ServletException; 6 import jakarta.servlet.http.HttpServletRequest; 7 import jakarta.servlet.http.HttpServletResponse; 8 9 import java.io.IOException; 10 11 public class ServletDemo04 extends HelloServlet{ 12 @Override 13 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 14 ServletContext context = this.getServletContext(); 15 // RequestDispatcher requestDispatcher = context.getRequestDispatcher("/s3");//请求路径 16 // requestDispatcher.forward(req,resp); //请求转发 17 context.getRequestDispatcher("/s3").forward(req,resp); 18 } 19 20 @Override 21 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 22 doGet(req, resp); 23 } 24 } 25 //web.xml中注册

 

 

 

1|04,读取资源文件

Properties

  • 在Java目录下新建properties

  • 在rescoures目录下新建properties

发现:都被打包到同一个路径下:classes,我们俗称这个路径为classpath;

1 package com.study.servlet; 2 3 import jakarta.servlet.ServletException; 4 import jakarta.servlet.http.HttpServletRequest; 5 import jakarta.servlet.http.HttpServletResponse; 6 7 import java.io.IOException; 8 import java.io.InputStream; 9 import java.util.Properties; 10 11 public class ServletDemo05 extends HelloServlet{ 12 @Override 13 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 14 InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/study/servlet/aa.properties"); 15 Properties prop = new Properties(); 16 prop.load(is); 17 String user = prop.getProperty("username"); 18 String pwd = prop.getProperty("password"); 19 resp.getWriter().print(user + ":" + pwd); 20 } 21 @Override 22 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 23 doGet(req, resp); 24 } 25 } 26 //web.xml中注册

7|6HttpServletResponse

web服务器收到服务器的http请求,针对这个请求,分别创建一个代表请求的HTTP Servlet Request对象,代表响应的一个HttpServlet

  • 如果要获取客户端请求过来的参数找Httpserverletrequest

  • 如果要给客户端响应一些信息找HttpServiceResponse

1|01、简单分类

负责向浏览器发送数据的方法

1|02、下载文件

  1. 向浏览器输出信息

  2. 下载文件

    1. 要获取下载文件的路径

    2. 下载的文件名是啥?

    3. 设置想办法让浏览器能够支持下载我们需要的东西

    4. 获取下载文件的输入流

    5. 创建缓冲区

    6. 获取OutputStream对象

    7. 将FileOutputStream流写入到buffer缓冲区

    8. 使用OutputStream将缓冲区中的数据输出到客户端

    1 package com.study.servlet; 2 3 import jakarta.servlet.ServletException; 4 import jakarta.servlet.ServletOutputStream; 5 import jakarta.servlet.http.HttpServlet; 6 import jakarta.servlet.http.HttpServletRequest; 7 import jakarta.servlet.http.HttpServletResponse; 8 9 import java.io.FileInputStream; 10 import java.io.IOException; 11 import java.net.URLEncoder; 12 13 public class response extends HttpServlet { 14 @Override 15 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 16 // 1. 要获取下载文件的路径 17 //String realPath = this.getServletContext().getRealPath("/美女.jpg"); 18 //realPath=D:\TomCat\apache-tomcat-10.0.18\webapps\respose_war\美女.jpg 19 20 String realPath = "F:\\个人资料(C盘移动)\\Maven\\javaweb-02-maven\\response\\src\\main\\resources\\美女.jpg"; 21 System.out.println("下载文件的路径"+realPath); 22 // 2. 下载的文件名是啥? 23 String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1); 24 // 3. 设置想办法让浏览器能够支持(Content-Disposition)下载我们需要的东西,中文文件名URLEncoder.encode编码,否则可能有乱码 25 resp.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(fileName,"UTF-8")); 26 // 4. 获取下载文件的输入流 27 FileInputStream in = new FileInputStream(realPath); 28 // 5. 创建缓冲区 29 int len = 0; 30 byte[] buffer = new byte[1024]; 31 // 6. 获取OutputStream对象 32 ServletOutputStream out = resp.getOutputStream(); 33 // 7. 将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区中的数据输出到客户端 34 while ((len=in.read(buffer))>0){ 35 out.write(buffer,0,len); 36 } 37 in.close(); 38 out.close(); 39 } 40 41 @Override 42 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 43 doGet(req, resp); 44 } 45 }

1|03、验证码功能

1 package com.study.servlet; 2 3 import jakarta.servlet.ServletException; 4 import jakarta.servlet.http.HttpServlet; 5 import jakarta.servlet.http.HttpServletRequest; 6 import jakarta.servlet.http.HttpServletResponse; 7 8 import javax.imageio.ImageIO; 9 import java.awt.*; 10 import java.awt.image.BufferedImage; 11 import java.io.IOException; 12 import java.util.Random; 13 14 public class ImageServlet extends HttpServlet{ 15 @Override 16 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 17 //如恶化让浏览器3秒自动刷新一次 18 resp.setHeader("refresh","5"); 19 //在内存中创建一张图片 20 BufferedImage image = new BufferedImage(90, 20, BufferedImage.TYPE_INT_RGB); 21 //得到图片 22 Graphics2D g = (Graphics2D) image.getGraphics();//23 //设置图片的背景颜色 24 g.setColor(Color.white); 25 g.fillRect(0,0,90,20); 26 //给图片写数据 27 g.setColor(Color.blue); 28 g.setFont(new Font(null,Font.BOLD,20)); 29 g.drawString(makeNum(),0,20); 30 //告诉浏览器,这个请求用图片的方式打开 31 resp.setContentType("image/jpeg"); 32 //网站存在缓存,不让浏览器缓存 33 resp.setDateHeader("expires",-1); 34 resp.setHeader("Cache-Control","no-cache"); 35 resp.setHeader("Pragma","no-cache"); 36 //把图片写给浏览器 37 ImageIO.write(image,"jpg",resp.getOutputStream()); 38 } 39 //生成随机数 40 public String makeNum(){ 41 Random random = new Random(); 42 String num = random.nextInt(99999999) + ""; 43 StringBuffer sb = new StringBuffer(); 44 for (int i = 0; i < 7 - num.length(); i++) { 45 sb.append("0"); 46 } 47 num = sb.toString() + num; 48 return num; 49 } 50 51 @Override 52 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 53 doGet(req, resp); 54 } 55 }

1|04,实现重定向

 

 

 

B一个web资源收到客户端A请求后,Bhi通知客户端去访问例外一个web资源,这个过程叫重定向

/* *resp.setHeader("Location","/respose_war/image"); * resp.setStatus(302); * */ resp.sendRedirect("/respose_war/image");//重定向

面试题:请你聊聊重定向和转发的区别

相同点

  • 页面都会实现跳转

不同点

  • 请求转发的时候,url不会发生变化 307

  • 重定向的时候,url地址栏会发生变化 302

7|7HttpServletRequest

HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,Http请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,获得客户端的所有信息

获取参数,请求转发

1 package com.study.servlet; 2 3 import jakarta.servlet.ServletException; 4 import jakarta.servlet.http.HttpServlet; 5 import jakarta.servlet.http.HttpServletRequest; 6 import jakarta.servlet.http.HttpServletResponse; 7 8 import java.io.IOException; 9 import java.util.Arrays; 10 11 public class LoginTest extends HttpServlet { 12 @Override 13 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 14 req.setCharacterEncoding("utf-8"); 15 resp.setCharacterEncoding("utf-8"); 16 17 String username = req.getParameter("username"); 18 String password = req.getParameter("password"); 19 String[] hobbys = req.getParameterValues("hobbys"); 20 System.out.println("========================"); 21 System.out.println(username); 22 System.out.println(password); 23 System.out.println(Arrays.toString(hobbys)); 24 System.out.println("========================"); 25 //请求转发 26 req.getRequestDispatcher("/success.jsp").forward(req,resp); 27 } 28 29 @Override 30 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 31 doGet(req, resp); 32 } 33 }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <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="唱歌">唱歌 <input type="checkbox" name="hobbys" value="电影">电影 <br> <input type="submit"> </form> </body> </html>

8|0Cookie、Session

8|1会话

会话:用户打开一个浏览器,点击了很多超链接,关闭浏览器,这个过程可以称之为会话。

有状态会话:一个同学来过教室,下次在来教室,我们知道这个同学,曾经来过,称之为有状态会话 一个网站,怎么证明你来过 客服端 客户端

  1. 服务端给客户端一个信件,客户端下次访问服务器带上新建就可以了 cookie

  2. 服务器等级你来过了,下次你来的时候我来匹配你 session

8|2保存会话的两种技术

cookie

  • 客户端技术 (响应,请求)

session

  • 服务器技术,利用这个技术,可以保存用户的会话信息?

  • 我们可以把信息或者数据放在Session中!

常见:网站登录之后,你下次不用再登录了,第二次访问直接就上去了!

8|3Cookie

  1. 从请求中拿到cookie信息

  2. 服务器响应给客户端cookie

    Cookie[] cookies = req.getcookies();//cookie cookie.getName();//获得cookie中的key cookie.getvalue();//获得cookie中的vlaue new Cookie("lastLoginTime",System.currentTimeMi11is)+"");//新建一个cookie cookie,setMaxAge(24*60*60);//设置cookie的有效期 resp.addcookie(cookie);//响应给客户一个cookie

cookie:一般会保存在本地的用户目录下appdata;

一个网站cookie是否存在上限!聊聊细节问题

  • 一个Cookie只能保存一个信息;

  • 一个web站点可以给浏览器发送多个cookie,最多存放20个cookie;

  • Cookie大小有限制4kb:

  • 300个cookie浏览器上限

删除Cookie;

  • 不设置有效期,关闭浏览器,自动失效;

  • 设置有效期时间为0:

编码解码:

URLEncoder.encode("韩小信","UTF-8");
URLDecoder.decode(cookie.getValue(),"UTF-8)";

8|4Session(重点)

什么是Session:

  • 服务器会给每一个用户(浏览器)创建一个Seesion对象;

  • 一个Seesion独占一个浏览器,只要浏览器没有关闭,这个Session就存在:

  • 用户登录之后,整个网站它都可以访问! 保存用户的信息;保存购物车的信息

Session和cookie的区别:

  • Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)

  • Session把用户的数据写到用户独占Session中,服务器端保存(保存重要的信息,减少服务器资源的浪费)

  • Session对象由服务创建;

使用场景:

  • 保存一个登录用户的信息;

  • 购物车信息;

  • 在整个网站中经常会使用的数据,我们将它保存在Session中:

Seeion的使用

1 package com.study.servlet; 2 3 import com.study.pojo.Person; 4 import jakarta.servlet.ServletException; 5 import jakarta.servlet.http.*; 6 7 import java.io.IOException; 8 9 public class SessionDemo01 extends HttpServlet { 10 @Override 11 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 12 //解决乱码问题 13 req.setCharacterEncoding("utf-8"); 14 resp.setCharacterEncoding("utf-8"); 15 resp.setContentType("text/html;charset=utf-8"); 16 //获得session 17 HttpSession session = req.getSession(); 18 //给session存东西 19 session.setAttribute("name",new Person("豆明占",21)); 20 //等到sessionID 21 String sessionId = session.getId(); 22 //判断是不是新创建的 23 if(session.isNew()){ 24 resp.getWriter().write("session是新创建的,ID:"+sessionId); 25 }else { 26 resp.getWriter().write("session已经创建,ID:"+sessionId); 27 } 28 //Session创建的时候做了什么事情: 29 // Cookie cookie = new Cookie("JSESSIONID","sessionId"); 30 // resp.addCookie(cookie); 31 } 32 33 34 35 36 @Override 37 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 38 doGet(req, resp); 39 } 40 } 41 42 //获得session 43 HttpSession session = req.getSession(); 44 Person person = (Person) session.getAttribute("name"); 45 System.out.println(person); 46 47 48 HttpSession session = req.getSession(); 49 session.removeAttribute("name"); 50 //手动注销 51 session.invalidate();

会话自动过期:在web.xml中配置

<!-- 设置session的失效时间 --> <session-config> <!-- 2分钟后失效,以分钟为单位 --> <session-timeout>2</session-timeout> </session-config>

9|0JSP

9|1什么是SP

Java Server Pages:Java服务器端页面,也和Servlet一样,用于动态Web技术!

最大的特点:

  • 写JSP就像在写HTML

  • 区别:

    • HTML只给用户提供静态的数据

    • JSP页面中可以嵌入JAVA代码,为用户提供动态数据:

9|2JSP原理

思路:JSP到底是怎样运行的

  • 代码层面没有任何问题

  • 服务器内部工作

    tomcat中有一个work目录;

    IDEA中使用tomcat的会在IDEA的tomcat中生产一个work目录

我电脑的目录

C:\Users\ASUS\AppData\Local\JetBrains\IntelliJIdea2021.3\tomcat\54be4500-6417-469b-a683-dbf21220b246\work\Catalina\localhost\ROOT\org\apache\jsp

发现页面转变成了Java程序

浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet

JSP最终也会被转变为Java类

JSP本质就是一个Servlet

//初始化 public void _jspInit() { } //销毁 public void _jspDestroy() { } //JSPserver public void _jspService(final jakarta.servlet.http.HttpServletRequest request, final jakarta.servlet.http.HttpServletResponse response)
  1. 判断请求

  2. 内置一些对象

    final jakarta.servlet.jsp.PageContext pageContext;//页面上下文 jakarta.servlet.http.HttpSession session = null;//session final jakarta.servlet.ServletContext application;//applicationContext final jakarta.servlet.ServletConfig config; //config jakarta.servlet.jsp.JspWriter out = null; //out final java.lang.Object page = this; //page:当前 HttpServletRequest request //请求 HttpServletResponse response //响应
  3. 输出页面前增加的代码

    response.setContentType("text/html");//设置相应的页面类型 pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out;
  4. 以上的对象我们可以在JSP页面中直接使用!

    

 

 

 

在JSP页面中:

只要是JAVA代码就会原封不动的输出;

如果是HTML代码,就会被转换为:

out.write("<html>\n");

这样的格式,输出到前端!

9|3JSP基础语法

任何语言都有自己的语法,JAVA中也有。JSP作为Java技术的一种应用,它拥有一些自己扩充的语法(了解,知道 即可!),Java所有语法都支持!

JSP表达式

<%-- JSP表达式 作用:用来将程序的输出,输出都客户端 <%= 变量或表达式%> --%> <%= new java.util.Date() %>

JSP脚本片段

<% int sum = 0; for (int i = 1; i <= 100; i++) { sum+=i; } out.println("<h1>Sum="+sum+"</h1>"); %>

脚本片段的再实现

<%-- 在代码嵌入HTML元素--%> <% for (int i = 0; i < 5; i++) { %> <h1>Fuck,God <%=i%> </h1> <% } %>

jsp声明

<%! static{ System.out.println("Loading Servlet"); } %>

JSP声明:会被编译到JSP生成Java的类中!其他的,就会被生成到jspService方法中!

在SP,嵌入Java代码即可! <%%> <%=%> <%!%> <%--注释--%

JSP的注释,不会在客户端显示,HTML就会!

9|4JSP指令

<%@page args....%> <%include file=""%> <%-- @include会将两个页面合二为一 --%> <%@ include file="common/header.jsp"%> <h1>网页主体</h1> <%@ include file="common/footer.jsp"%> <hr> <%-- jsp标签 jsp:include:拼接页面,本质还是三个 有相同的参数不会报错 --%> <jsp:include page="common/header.jsp"/> <h1>网页主体</h1> <jsp:include page="common/footer.jsp"/>

9|59大内置对象

  • PageContext 存东西

  • Request 存东西

  • Response

  • Session 存东西

  • Application [SerlvetContext] 存东西

  • config [servletConfig]

  • out

  • page

  • exception

pageContext.setAttribute("name1","机器人1号");//保存的数据只在一个页面中有效 request.setAttribute("name2","机器人2号");//保存的数据只在一次请求中有效,请求转发会携带这个数据 session.setAttribute("name3","机器人3号");//保存的数据只在一次会活中有效,从打开浏览器到关闭浏览器 application.setAttribute("name4","机器人4号");//保存的数据只在服务器中有效,从打开服务器到关闭服务器

request:客户端向服务器发送请求,产生的数据,用户看完就没用了,比如:新闻,用户看完没用的!

session:客户端向服务器发送请求,产生的数据,用户用完一会还有用,比如:购物车;

application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如:聊天数

9|6JSP标签、JSTL标签、EL表达式

导入依赖包

1 <dependencies> 2 <!--Servlet依赖--> 3 <dependency> 4 <groupId>jakarta.servlet</groupId> 5 <artifactId>jakarta.servlet-api</artifactId> 6 <version>5.0.0</version> 7 </dependency> 8 <!--JSP依赖--> 9 <dependency> 10 <groupId>jakarta.servlet.jsp</groupId> 11 <artifactId>jakarta.servlet.jsp-api</artifactId> 12 <version>3.0.0</version> 13 </dependency> 14 <!--JSTL标签依赖--> 15 <dependency> 16 <groupId>jakarta.servlet.jsp.jstl</groupId> 17 <artifactId>jakarta.servlet.jsp.jstl-api</artifactId> 18 <version>2.0.0</version> 19 </dependency> 20 <!--JSTL表达式依赖--> 21 <dependency> 22 <groupId>org.glassfish.web</groupId> 23 <artifactId>jakarta.servlet.jsp.jstl</artifactId> 24 <version>2.0.0</version> 25 </dependency> 26 27 </dependencies>

EL表达式:${}

  • 获取数据

  • 执行运算

  • 获取web开发的常用对象

jsp标签

<%--<jsp:include page=""></jsp:include>--%> <%-- http://localhost:8080/jsptag.jsp?name=豆明占&age=18--%> <jsp:forward page="/jsptag2.jsp"> <jsp:param name="name" value="豆明占"/> <jsp:param name="age" value="18"/> </jsp:forward>

JSTL表达式

JSTL标签库的使用就是为了弥补HTM标签的不足:它自定义许多标签,可以供我们使用,标签的功能和va代码

一样!

格式化标签

SQL标签

XML 标签

核心标签(核心掌握)

JSTL标签库使用步骤

  • 引入对应的taglib

  • 使用其中的方法

  • 在Tomcat也需要引入jst的包,否则会报错:JSTL解析错误

<jsp: tag>

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>1</h1> <%--<jsp:include page=""></jsp:include>--%> <%-- http://localhost:8080/jsptag.jsp?name=豆明占&age=18--%> <jsp:forward page="/jsptag2.jsp"> <jsp:param name="name" value="豆明占"/> <jsp:param name="age" value="18"/> </jsp:forward> </body> </html>

<c: if>

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%--引入JSTL核心标签库,我们才能使用的STL标签core--%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Title</title> </head> <body> <h4>if测试</h4> <hr> <form action="coreif.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:out> </c:if> <%--判断如果是交的用户名是管理员,则登录成功--%> <c:out value="${isAdmin}"></c:out> </body> </html>

<c: when>

1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 <html> 4 <head> 5 <title>Title</title> 6 </head> 7 <body> 8 <%-- 定义一个变量score,值为85 --%> 9 <c:set var="score" value="85"></c:set> 10 <c:choose> 11 <c:when test="${score>=90}"> 12 你的成绩为优秀 13 </c:when> 14 <c:when test="${score>=80}"> 15 你的成绩为良好 16 </c:when> 17 <c:when test="${score>=70}"> 18 你的成绩为一般 19 </c:when> 20 <c:when test="${score<=60}"> 21 你的成绩为不及格 22 </c:when> 23 </c:choose> 24 </body> 25 </html>

<c: forEach>

1 <%@ page import="java.util.ArrayList" %> 2 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 3 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 4 <html> 5 <head> 6 <title>Title</title> 7 </head> 8 <body> 9 <% 10 ArrayList<String> people = new ArrayList<>(); 11 people.add(0,"张三"); 12 people.add(1,"李四"); 13 people.add(2,"王五"); 14 people.add(3,"赵六"); 15 people.add(4,"田七"); 16 request.setAttribute("list",people); 17 %> 18 <%-- 19 var,每一次遍历出来的变最 20 items,要遍历的对象 21 step:步长 22 --%> 23 <c:forEach var="people" items="${list}"> 24 <c:out value="${people}"></c:out> <br> 25 </c:forEach> 26 27 <c:forEach var="people" items="${list}" begin="1" end="4" step="2"> 28 <c:out value="${people}"></c:out> <br> <%--李四 赵六--%> 29 </c:forEach> 30 </body> 31 </html>

10|0JavaBean

实体类

JavaBean有特定的写法:

  • 必须要有一个无参构造

  • 属性必须私有化

  • 必须有对应的get/set方法

一般用来和数据库的字段做映射 ORM;

ORM:对象关系映射

  • 表-->类

  • 字段-->属性

  • 行记录-->对象

idnameageaddress
1 机器人1号 12 河南
2 机器人2号 13 河北
3 机器人3号 14 河西
class Person { private int id; private String name; private int age; private String address; } class A{ new Peop1e(1,"机器人1号",3,"河南"); new People(2,"机器人2号",3,"河北"); new Peop1e(3,"机器人3号",3,"河西");
<%@ page import="com.study.pojo.Person" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <% // Person person = new Person(); // person.setId(); // person.setName(); // person.setAge(); // person.setAddress(); %> <jsp:useBean id="people" class="com.study.pojo.Person" scope="page"> <jsp:setProperty name="people" property="id" value="1"/> <jsp:setProperty name="people" property="name" value="机器人1号"/> <jsp:setProperty name="people" property="age" value="12"/> <jsp:setProperty name="people" property="address" value="河南"/> <%--person.getID()--%> ID: <jsp:getProperty name="people" property="id"/> 姓名:<jsp:getProperty name="people" property="name"/> 年龄:<jsp:getProperty name="people" property="age"/> 地址:<jsp:getProperty name="people" property="address"/> </jsp:useBean> </body> </html>

11|0MVC三层框架

什么是MVC:model view controller 模型,视图,控制器

11|1早些年

用户直接访问控制层,控制层就可以直接操作数据库:

servlet--CRUD-->数据库 弊端:程序十分臃肿,不利于维护 serv1et的代码中:处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码 架构:没有什么是加一层解决不了的! 程序猿调用 | JDBC | Mysql oracle Sqlserver ...

11|2MVC三层框架

 

 

Model

  • 业务处理:业务逻辑(Service)

  • 数据持久层:CRUD (Dao)

View

  • 展示数据

  • 提供链接发起Servlet请求(a,form,img……)

Controller (Servlet)

  • 接受用户的请求:(req:请求参数,Session信息……)

  • 交给业务层处理对应的代码

  • 控制视图的跳转

登录--->接收用户的登录请求--->处理用户的请求(获取用户登录的参数,username,password)--->交给业务处理登录业务(判断用户名密码是否正确:事务)--->Dao层查询用户名和密码是否正确--->数据库

12|0Filter (重点)

filter 过滤器:用来过滤网站的数据

  • 处理中文乱码

  • 登陆验证……

  • 敏感信息显示为***

12|1Filter的使用

  1. 导包

  2. 编写过滤器

    1. 导报不要导错(Jakarta.servlet.Filter)

    2. 实现Filter接口,重写对应的的方法即可

    package com.study.filter; import jakarta.servlet.*; import java.io.IOException; public class CharacterEncodingFilter implements Filter { //初始化:web服务器启动,就已经初始化了,随时等待过滤对象出现! public void init(FilterConfig filterConfig) throws ServletException { System.out.println("CharacterEncodingFilter初始化"); } //filterChain:链 /* * 1,过滤中的所有的代码,在过滤特定请求的时候都会执行 * 必须要让过滤器继续执行 * filterChain.doFilter(servletRequest,servletResponse); * */ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); servletResponse.setContentType("text/html;charset=UTF-8"); System.out.println("CharacterEncodingFilter执行前....."); filterChain.doFilter(servletRequest,servletResponse);//让我们的请求继续走,如果不写,程序到这里就会被拦截停止 System.out.println("CharacterEncodingFilter执行后....."); } //销毁:web服务器关闭的时候,过滤会销毁 public void destroy() { System.out.println("CharacterEncodingFilter销毁"); } }
    1. 在web.xml中配置filter

    <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.study.filter.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <!-- 只要是/servlet的任何请求,都会经过这个过滤器 --> <url-pattern>/servlet/*</url-pattern> </filter-mapping>

    13|0Listener

    监听器有N多种

  3. 编写一个监听器

    1 package com.study.Listener; 2 3 import jakarta.servlet.ServletContext; 4 import jakarta.servlet.http.HttpSessionEvent; 5 import jakarta.servlet.http.HttpSessionListener; 6 7 //统计网站在线人数;同级session 8 public class onlineCountListener implements HttpSessionListener { 9 //创建session监听:看你的一举一动 10 //一旦船舰session就会触发一次这个事件! 11 public void sessionCreated(HttpSessionEvent se) { 12 ServletContext ctx = se.getSession().getServletContext(); 13 System.out.println(se.getSession().getId()); 14 Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount"); 15 if(onlineCount==null){ 16 onlineCount =new Integer(1); 17 }else{ 18 onlineCount = new Integer(onlineCount+1); 19 } 20 ctx.setAttribute("OnlineCount",onlineCount); 21 22 } 23 //销魂session监听 24 //一旦销毁session就会触发一次这个事件! 25 public void sessionDestroyed(HttpSessionEvent se) { 26 ServletContext ctx = se.getSession().getServletContext(); 27 Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount"); 28 if(onlineCount==null){ 29 onlineCount =new Integer(1); 30 }else{ 31 onlineCount = new Integer(onlineCount-1); 32 } 33 ctx.setAttribute("OnlineCount",onlineCount); 34 } 35 }
  4. 在web.xml中注册

    <!-- 注册监听器 --> <listener> <listener-class>com.study.Listener.onlineCountListener</listener-class> </listener>
  5. 看情况是否需要销毁

    /*Session销毁 * 手动销毁:getSession().invalidate(); * 自动销毁:在xml中设置过期的时间 * */

    过滤器监听器的常用应用

    监听器:页面关闭时的监听

    用户登录之后才能进入主页!用户注销后就不能进入主页了! 1.用户登录之后,向Session中放入用户的数据 2.进入主页的时候要判断用户是否已经登录:

    //ServletRequest HttpServletRequest 为了拿到session HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; if(request.getSession().getAttribute(Constant.USER_SESSION)==null){ response.sendRedirect("/error.jsp"); } filterChain.doFilter(req,resp);

     

 


__EOF__

本文作者冰山醉酒
本文链接https://www.cnblogs.com/douFrank/p/16117840.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   冰山醉酒  阅读(98)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示