JavaWeb
Tomcatist 人气:2JavaWeb
Java. web
1. 基本概念
1.1 前言
web开发:
-
web:网页的意思 www.baidu.com
-
静态web
-
html. Css
-
提供给所有人看的数据始终不会发生变化!
-
-
动态web
-
淘宝等,几乎是所有的网站!
-
提供给所有人看的数据始终会发生变化,每个人在不同的时间,不同的地点看到的信息各不相同!
-
技术栈:Servlet/JSP,ASP,PHP
-
在java中,动态web资源开发的技术统称为JavaWeb
1.2 web应用程序
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
-
*.htm , *.html 这些都是网页的后缀,如果服务器上一直存在这些东西,我们就可以直接进行读取,(网络);
-
静态web存在的缺点:
-
web页面无法动态更新,所有用户看到的都是同一个页面
-
轮播图,点击特效:伪动态
-
javaScript(实际开发中用的多)
-
VBScript
-
它无法和数据库交互(数据无法持久化,用户无法交互)
-
1.4 动态web
页面会动态展示:“web展示的效果因人而异!”
缺点:
-
假如服务器的动态web资源出现了错误,我们需要重新编写我们的后台程序,重新发布;
-
重新发布=停机维护
-
优点:
-
web页面可以动态更新,所有用户看到的都不是同一个页面
-
它可以和数据库交互(数据可以持久化:注册,商品信息可以存在数据库...,用户可以交互)
2、web服务器
2.1、技术讲解
ASP:
-
微软:国内最早流行的就是ASP
-
在html中嵌入了VB的脚本:ASP+DOM;
-
在ASP开发中,基本一个页面都有几千行的业务代码,页面极其混乱(html和java写在一起)
-
维护成本高!
-
C#
-
IIS
PHP
-
PHP开发速度很快,功能很强大,跨平台,代码很简单(70%,WP)
-
无法承载大访问量的情况(局限性)
JSP/Servlet:
B/S:浏览器和服务器
C/S:客户端和服务器
-
sun公司主推的B/S架构
-
基于java语言的(所有的大公司,或者一些开源的组件,都是用Java写的)
-
可以承载三高问题带来的影响;
-
语法像ASP,方便ASP转JSP,加强市场强度;
2.2、web服务器
服务器是一种被动的操作,用来处理用户的请求和给用户一些响应信息;
iis:
微软的;ASP,,windows中自带
Tomcat:
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,他是最佳的选择。
而Tomcat 实际上运行JSP 页面和Servlet。目前Tomcat最新版本为9.0.30。
3、Tomcat
3.1、Tomcat官网
https://tomcat.apache.org
3.2、Tomcat的启动和配置
启动Tomcat: /Users/mac/Library/tomcat/bin/startup.sh
关闭Tomcat: /Users/mac/Library/tomcat/bin/shutdown.sh
可能遇到的问题:
-
java环境变量没有配置
-
闪退问题:
-
乱码问题:
3.3、配置
可以配置启动的端口号;
-
tomcat的默认端口号:8080
-
mysql:3306
-
http:80
-
https:443
可以配置主机的名称:
-
默认的主机名为:localhost-->127.0.0.1
-
默认网站应用存放的位置为:webapps
高难度面试题
请你谈谈网站是如何进行访问的:
-
输入一个域名:回车
-
检查本机的hosts配置文件下有没有这个域名的映射;
-
有:直接返回对应的ip地址,这个地址中有我们需要访问的web程序,可以直接访问
-
没有:去DNS(全世界的域名都在这里管理)服务器找,找到的话就返回找到,找不到就返回找不到...
-
3.4、发布一个web网站
不会就先模仿!
-
将自己写的网站,放到服务器(Tomcat)中指定的web应用的文件夹(webapps)下,就可以访问了
-
网站应有的结构:
--webapps : Tomcat服务器的web目录
-ROOT
-kuangstudy : 网站的目录名
-WEB-INF
-classes:java程序
-lib : web应用所依赖的jar包
-web.xml:网站的配置文件
-index.html :默认的首页
-static
-css
-style.css
-js
-img
-......
HTTP协议:面试
Maven:构建工具
-
maven安装包
Servlet入门
-
HelloWorld
-
Severlet配置
-
原理
4、Http
4.1 什么是Http
http(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上。
-
文本:html,字符串,,,,
-
超文本:图片,音乐,视频,定位,地图。。。
-
默认端口:80
Https:(加密)
-
默认端口:443
4.2、两个时代
-
Http1.0
-
HTTP/1.0:客户端可以与web服务器连接后,只能获得一个web资源,断开连接。
-
-
Http2.0
-
HTTP/1.1:客户端可以与web服务器连接后,可以获得多个web资源。
-
4.3、Http请求
-
客户端-->发请求(Request)-->服务器
Request URL:https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/js/nu_instant_search_baaa58d.js //请求地址
Request Method: GET //get方法/post方法
Status Code: 200 (from memory cache) //状态码:200
Remote(远程) Address: 183.201.233.32:443 //
:authority: dss3.baidu.com
:method: GET
:path: /-rVXeDTa2gU2pMbgoY3K/it/u=701675230,3439008724&fm=202&mola=new&crop=v1
:scheme: https
accept: image/webp,image/apng,image/*,*/*;q=0.8
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9
cookie: BIDUPSID=25FC099492B03BC6D724B99139BE7C00; PSTM=1574690755; BAIDUID=25FC099492B03BC6B769B03C4B7F8EF7:FG=1; delPer=0; H_PS_PSSID=1454_21108_30211_30283_26350_22157; PSINO=1
referer: https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=java&rsv_pq=a7b71db0000a86e7&rsv_t=d954LlVjnwQ%2F%2BDdfHsZNPH%2FZwioIqTxTYlQFPza0gJLxtdOChA9trFVS%2BbA&rqlang=cn&rsv_enter=1&rsv_dl=tb&rsv_sug3=5&rsv_sug1=3&rsv_sug7=101&rsv_sug2=0&inputT=1681&rsv_sug4=2717
sec-fetch-mode: no-cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
1、请求行
-
请求行中的请求方式:GET
-
请求方式:Get、Post、Head、Delete、Put、Tract
-
get:请求能够携带的参数比较小,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全,但高效。
-
post:请求能够携带的参数没有限制,大小有没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效。
-
2、消息头
Accept:告诉浏览器,他所支持的数据类型
Accept-Encoding:支持哪种编码格式 :GBK UTGF-8 GB2312 ISO8859-1
Accept-language:告诉浏览器,他的语言环境
Cache-Control:缓存控制
Connection:告诉浏览器,请求完成是断开还是保持连接
HOST:主机
..........
-
4.4、Http响应
-
服务器-->发请求-->客户端
cache-control: max-age=315360000 //缓存控制
Connection:keep-Alive //连接
content-encoding: gzip //编码
Content-Type:text/html //类型
1、响应体
Accept:告诉浏览器,他所支持的数据类型
Accept-Encoding:支持哪种编码格式 :GBK UTGF-8 GB2312 ISO8859-1
Accept-language:告诉浏览器,他的语言环境
Cache-Control:缓存控制
Connection:告诉浏览器,请求完成是断开还是保持连接
HOST:主机
..........
reFresh:告诉客户端,多久刷新一次
Location:让网页重新定位
2、响应状态码
200:请求响应成功。200
3xx:请求重定向
-
重定向:你重新到我指定的新位置;
4xx:找不到资源。404
-
资源不存在
5xx:服务器代码错误。500
502:网关错误
常见面试题:
当你的浏览器中地址栏输入地址并回车的一瞬间到页面能够展示回来,经历了什么?
5、Maven
我为什么要学习这个技术?
-
在Javaweb中,需要使用大量的jar包,我们需要手动导入;
-
如何能够让一个东西能够帮我们自动导入和配置这个jar包;
由此,Maven诞生!
5.1、Maven项目架构管理工具
我们目前用它来就是方便导入jar包的!
Maven的核心思想:约定大于配置
-
有约束,不要去违反
Maven会规定好你该如何去编写我们的Java代码,必须按这个规范来
5.2、Maven下载
官网:https://maven.apache.org
安装和配置请自行百度
maven由于他的约定大于配置,我们之后可能遇到我们写的配置文件,无法导出或者生效问题,解决方案:
//在build中配置resource,来防止资源导出失败的问题
<build>
<finalName>test</finalName>
<!--
这样也可以把所有的xml文件,打包到相应位置。
<resources>
<resource>
<directory>src/main/resources<https://img.qb5200.com/download-x/directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.tld</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java<https://img.qb5200.com/download-x/directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.tld</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
6、Servlet
6.1 servlet简介
-
Servlet就是sun公司开发动态web的一门技术
-
sun公司在这些API中提供了一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:
-
编写一个类,实现Servlet接口
-
把开发好的java类部署到web服务器中
-
把实现了Servlet接口的Java程序,叫做Servlet
6.2、HelloServlet
Servlet接口在Sun公司有两个默认的实现类:HttpServlet、GenericServlet
-
构建一个普通的maven项目,删掉里面的src目录,以后我们的学习就在这个项目里面建立Model;这个空的工程就叫做Maven的主工程
-
关于Maven父子工程的理解:
父项目中会有:
<modules>
<module>Servlet-02</module>
</modules>
子项目中会有:
<parent> <artifactId>javaweb-02-Servlet</artifactId> <groupId>com.yuan</groupId> <version>1.0-SNAPSHOT</version> </parent>
父项目中的jar包,子项目可以直接使用
son extends father//类似于java的多态
-
Maven环境优化
-
修改web.xml为最新的
-
将Maven的结构搭建完整
-
-
编写一个Servlet程序
-
编写一个普通类
-
实现Servlet接口,这里我们直接继承HttpServlet
public class HelloServlet extends HttpServlet { //由于get或者post只是请求实现的不同方式,可以相互调用,业务逻辑都一样 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //ServletOutputStream outputStream = resp.getOutputStream(); PrintWriter writer = resp.getWriter();//响应流 writer.println("Hello Servlet"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
-
-
编写Servlet的映射
为什么需要映射:我们写的是java程序,但是需要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的Servlet,还需要给他一个浏览器能够访问的路径;
-
配置Tomcat
注意:配置项目的发布路径就可以了
-
启动测试
-
6.3、Servlet原理
Servlet是由web服务器调用,web服务器在收到浏览器请求之后,进行一系列转化...用到service方法...
我们自己编写的实现类,重写这些方法:
-
接收并处理请求
-
给出响应的信息
6.4、Mapping问题
-
一个Servlet请求可以指定一个映射路径
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
一个Servlet请求可以指定多个映射路径
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/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> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello3</url-pattern> </servlet-mapping>
-
一个Servlet请求可以指定通用映射路径
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping>
-
默认请求路径(会把首页给覆盖)
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
-
指定一些后缀或者前缀等等...
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>*.do</url-pattern> //*前面不能加映射的路径"/" </servlet-mapping>
-
优先级问题:
指定了固有的映射路径优先级最高,如果找不到就会去走默认的处理请求;
-
//404 <servlet> <servlet-name>error</servlet-name> <url-pattern>com.yuan.servlet.ErrorServlet</url-pattern> //*前面不能加映射的路径"/" </servlet> <servlet-mapping> <servlet-name>error</servlet-name> <url-pattern>/*</url-pattern> //*前面不能加映射的路径"/" </servlet-mapping>
6.5、ServletContext
1.1. 介绍
ServletContext官方叫servlet上下文。服务器会为每一个工程创建一个对象,这个对象就是ServletContext对象。这个对象全局唯一,而且工程内部的所有servlet都共享这个对象。所以叫全局应用程序共享对象。
1.2. 作用
-
是一个域对象
-
可以读取全局配置参数
-
可以搜索当前工程目录下面的资源文件
-
可以获取当前工程名字(了解)
1.2.1. servletContext是一个域对象
1.2.1.1. 域对象介绍
域对象是服务器在内存上创建的存储空间,用于在不同动态资源(servlet)之间传递与共享数据。
1.2.1.2. 域对象方法
凡是域对象都有如下3个方法:
setAttribute(name,value);//name是String类型,value是Object类型; 往域对象里面添加数据,添加时以key-value形式添加 getAttribute(name); //根据指定的key读取域对象里面的数据 removeAttribute(name); //根据指定的key从域对象里面删除数据
1.2.1.3. 域对象功能代码
域对象存储数据AddDataServlet代码
/** * doGet */ publicvoid doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //往serlvetContext里面存数据 //1.获取ServletContext对象 //getServletContext() //2.往对象里面设置数据 getServletContext().setAttribute("username", "admin"); response.getOutputStream().write("用户名写入到servletContext成功".getBytes()); } ———————————————— 原文链接:https://blog.csdn.net/qq_36371449/articlehttps://img.qb5200.com/download-x/details/80314024
获取域对象数据GetDataServlet代码
/** * doGet */ publicvoid doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取ServletContext里面的用户名数据 Object valueObject = getServletContext().getAttribute("username"); if(valueObject!=null){ response.getOutputStream().write(("从servletContext读取到的用户名数据:"+valueObject.toString()).getBytes()); } } ———————————————— 原文链接:https://blog.csdn.net/qq_36371449/articlehttps://img.qb5200.com/download-x/details/80314024
servletContext存储数据特点:
全局共享,里面的数据所有动态资源都可以写入和获取
服务器启动的时候创建,服务器关闭的时候销毁,因为这是全局应用程序对象,全局共享对象。
1.2.2. 可以读取全局配置参数
1.2.2.1. servletContext读取全局参数核心方法
getServletContext().getInitParameter(name);//根据指定的参数名获取参数值 getServletContext().getInitParameterNames();//获取所有参数名称列表
1.2.2.2. 实现步骤:
-
在web.xml中配置全局参数
<!-- 全局配置参数,因为不属于任何一个servlet,但是所有的servlet都可以通过servletContext读取这个数据 --> <context-param> <param-name>param1</param-name> <param-value>value1</param-value> </context-param> <context-param> <param-name>param2</param-name> <param-value>value2</param-value> </context-param> ———————————————— 原文链接:https://blog.csdn.net/qq_36371449/articlehttps://img.qb5200.com/download-x/details/80314024
-
在动态资源servlet里面使用servletcontext读取全局参数代码
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //使用servletContext读取全局配置参数数据 //核心方法 /*getServletContext().getInitParameter(name);//根据指定的参数名获取参数值 getServletContext().getInitParameterNames();//获取所有参数名称列表*/ //打印所有参数 //1.先获取所有全局配置参数名称 Enumeration<String> enumeration = getServletContext().getInitParameterNames(); //2.遍历迭代器 while(enumeration.hasMoreElements()){ //获取每个元素的参数名字 String parameName = enumeration.nextElement(); //根据参数名字获取参数值 String parameValue = getServletContext().getInitParameter(parameName); //打印 System.out.println(parameName+"="+parameValue); } } ———————————————— 原文链接:https://blog.csdn.net/qq_36371449/articlehttps://img.qb5200.com/download-x/details/80314024
1.2.3. 可以搜索当前工程目录下面的资源文件
1.2.3.1. 核心方法
getServletContext().getRealPath(path)//,根据相对路径获取服务器上资源的绝对路径 getServletContext().getResourceAsStream(path)//,根据相对路径获取服务器上资源的输入字节流
1.2.4. 可以获取当前工程名字
1.2.4.1. 核心方法
getServletContext().getContextPath(); //作用:获取当前工程名字
1.2.4.2. 代码
publicvoid doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取工程名字,getServletContext().getContextPath() response.getOutputStream().write(("工程名字:"+getServletContext().getContextPath()).getBytes()); } 原文链接:https://blog.csdn.net/qq_36371449/articlehttps://img.qb5200.com/download-x/details/80314024
6.6、HttpServletResponse
参考博客:https://www.cnblogs.com/xdp-gacl/p/3789624.html
参考博客:https://www.jianshu.com/p/8bc6b82403c5
web服务器接收到客户端的http请求,会针对这个请求分别创建一个代表请求的HttpServletRequest对象,和一个代表响应的HttpServletResponse对象;
-
如果要获取客户端请求过来的参数:找HttpServletRequest
-
如果要给客户端响应一些信息:找HttpServletResponse
1、简单分类
负责向浏览器发送数据的方法:
负责向浏览器发送响应头的方法:
负责向浏览器发送响应状态码的方法:
2、常见应用
-
向浏览器输出消息
-
下载文件
-
要获取下载文件路径
-
下载的文件名是啥
-
设置想办法让浏览器能够支持下载我们需要的东西
-
获取下载文件的输入流
-
创建缓冲区
-
获取OutPutStream对象
-
将FileOutPutStream流写入到buffer缓冲区
-
使用OutPutStream将缓冲区中的数据输出到客户端
-
1 package gacl.response.study; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.URLEncoder; 10 import javax.servlet.ServletException; 11 import javax.servlet.http.HttpServlet; 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 /** 15 * @author gacl 16 * 文件下载 17 */ 18 public class ResponseDemo02 extends HttpServlet { 19 20 public void doGet(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 downloadFileByOutputStream(response);//下载文件,通过OutputStream流 23 } 24 25 /** 26 * 下载文件,通过OutputStream流 27 * @param response 28 * @throws FileNotFoundException 29 * @throws IOException 30 */ 31 private void downloadFileByOutputStream(HttpServletResponse response) 32 throws FileNotFoundException, IOException { 33 //1.获取要下载的文件的绝对路径 34 String realPath = this.getServletContext().getRealPath("https://img.qb5200.com/download-x/download/1.JPG"); 35 //2.获取要下载的文件名 36 String fileName = realPath.substring(realPath.lastIndexOf("\\")+1); 37 //3.设置content-disposition响应头控制浏览器以下载的形式打开文件 38 response.setHeader("content-disposition", "attachment;filename="+fileName); 39 //4.获取要下载的文件输入流 40 InputStream in = new FileInputStream(realPath); 41 int len = 0; 42 //5.创建数据缓冲区 43 byte[] buffer = new byte[1024]; 44 //6.通过response对象获取OutputStream流 45 OutputStream out = response.getOutputStream(); 46 //7.将FileInputStream流写入到buffer缓冲区 47 while ((len = in.read(buffer)) > 0) { 48 //8.使用OutputStream将缓冲区的数据输出到客户端浏览器 49 out.write(buffer,0,len); 50 } 51 in.close(); 52 } 53 54 public void doPost(HttpServletRequest request, HttpServletResponse response) 55 throws ServletException, IOException { 56 doGet(request, response); 57 } 58 }
下载中文文件时,需要注意的地方就是中文文件名要使用URLEncoder.encode方法进行编码(URLEncoder.encode(fileName, "字符编码")),否则会出现文件名乱码。
1 package gacl.response.study; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.URLEncoder; 10 import javax.servlet.ServletException; 11 import javax.servlet.http.HttpServlet; 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 /** 15 * @author gacl 16 * 文件下载 17 */ 18 public class ResponseDemo02 extends HttpServlet { 19 20 public void doGet(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 downloadChineseFileByOutputStream(response);//下载中文文件 23 } 24 25 /** 26 * 下载中文文件,中文文件下载时,文件名要经过URL编码,否则会出现文件名乱码 27 * @param response 28 * @throws FileNotFoundException 29 * @throws IOException 30 */ 31 private void downloadChineseFileByOutputStream(HttpServletResponse response) 32 throws FileNotFoundException, IOException { 33 String realPath = this.getServletContext().getRealPath("https://img.qb5200.com/download-x/download/张家界国家森林公园.JPG");//获取要下载的文件的绝对路径 34 String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);//获取要下载的文件名 35 //设置content-disposition响应头控制浏览器以下载的形式打开文件,中文文件名要使用URLEncoder.encode方法进行编码,否则会出现文件名乱码 36 response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8")); 37 InputStream in = new FileInputStream(realPath);//获取文件输入流 38 int len = 0; 39 byte[] buffer = new byte[1024]; 40 OutputStream out = response.getOutputStream(); 41 while ((len = in.read(buffer)) > 0) { 42 out.write(buffer,0,len);//将缓冲区的数据输出到客户端浏览器 43 } 44 in.close(); 45 } 46 47 public void doPost(HttpServletRequest request, HttpServletResponse response) 48 throws ServletException, IOException { 49 doGet(request, response); 50 } 51 }
文件下载注意事项:编写文件下载功能时推荐使用OutputStream流,避免使用PrintWriter流,因为OutputStream流是字节流,可以处理任意类型的数据,而PrintWriter流是字符流,只能处理字符数据,如果用字符流处理字节数据,会导致数据丢失。
3、验证码功能
验证怎么来的?
-
前端实现
-
后端实现,需要用到java的图片类,生成一个图片
这个可以当做一个工具类来使用,不必自己写出来,要用的时候复制,然后可以局部的改改代码,就可以变成另外的验证码了。
public class ResponseDemo4 extends HttpServlet { public static final int WIDTH = 120; // 生成的图片的宽度 public static final int HEIGHT = 35; // 生成的图片的高度 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 在内存中创建一张图片 BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); // 得到图片 Graphics g = image.getGraphics(); // 1.设置图片的背景色 setBackGround(g); // 2.设置图片的边框 setBorder(g); // 3.在图片上画干扰线 drawRandomLine(g); // 4.在图片上写随机数 String random = drawRandomNum((Graphics2D) g); request.getSession().setAttribute("checkcode", random); // 将随机数存在session中 /* * 5.图形写给浏览器 */ response.setContentType("image/jpeg") // 发响应头控制浏览器不要缓存图片 response.setDateHeader("expries", -1); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); ImageIO.write(image, "jpg", response.getOutputStream()); } /* * 设置图片的背景色 */ private void setBackGround(Graphics g) { // 设置颜色 g.setColor(Color.WHITE); // 填充区域 g.fillRect(0, 0, WIDTH, HEIGHT); } /* * 设置图片的边框 */ private void setBorder(Graphics g) { // 设置边框颜色 g.setColor(Color.BLUE); // 边框区域 g.drawRect(1, 1, WIDTH-2, HEIGHT-2); } /* * 在图片上画干扰线 */ private void drawRandomLine(Graphics g) { // 设置颜色 g.setColor(Color.GREEN); // 设置线条个数并画线 for(int i=0;i<5;i++) { // 生成干扰线随机的起始坐标 int x1 = new Random().nextInt(WIDTH); // 生成0~WIDTH(不包括WIDTH)的随机数 int y1 = new Random().nextInt(HEIGHT); // 生成干扰线随机的结束坐标 int x2 = new Random().nextInt(WIDTH); int y2 = new Random().nextInt(HEIGHT); g.drawLine(x1, y1, x2, y2); } } /* * 在图片上写随机数 */ private String drawRandomNum(Graphics2D g) { // 设置颜色 g.setColor(Color.RED); // 设置字体 g.setFont(new Font("宋体", Font.BOLD, 20)); // 常用的中国汉字(汉字区间:[\u4e00-\u9fa5]) String base = "\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a\u5730\u5230\u5927\u91cc\u8bf4\u5c31\u53bb\u5b50\u5f97\u4e5f\u548c\u90a3\u8981\u4e0b\u770b\u5929\u65f6\u8fc7\u51fa\u5c0f\u4e48\u8d77\u4f60\u90fd\u628a\u597d\u8fd8\u591a\u6ca1\u4e3a\u53c8\u53ef\u5bb6\u5b66\u53ea\u4ee5\u4e3b\u4f1a\u6837\u5e74\u60f3\u751f\u540c\u8001\u4e2d\u5341\u4ece\u81ea\u9762\u524d\u5934\u9053\u5b83\u540e\u7136\u8d70\u5f88\u50cf\u89c1\u4e24\u7528\u5979\u56fd\u52a8\u8fdb\u6210\u56de\u4ec0\u8fb9\u4f5c\u5bf9\u5f00\u800c\u5df1\u4e9b\u73b0\u5c71\u6c11\u5019\u7ecf\u53d1\u5de5\u5411\u4e8b\u547d\u7ed9\u957f\u6c34\u51e0\u4e49\u4e09\u58f0\u4e8e\u9ad8\u624b\u77e5\u7406\u773c\u5fd7\u70b9\u5fc3\u6218\u4e8c\u95ee\u4f46\u8eab\u65b9\u5b9e\u5403\u505a\u53eb\u5f53\u4f4f\u542c\u9769\u6253\u5462\u771f\u5168\u624d\u56db\u5df2\u6240\u654c\u4e4b\u6700\u5149\u4ea7\u60c5\u8def\u5206\u603b\u6761\u767d\u8bdd\u4e1c\u5e2d\u6b21\u4eb2\u5982\u88ab\u82b1\u53e3\u653e\u513f\u5e38\u6c14\u4e94\u7b2c\u4f7f\u5199\u519b\u5427\u6587\u8fd0\u518d\u679c\u600e\u5b9a\u8bb8\u5feb\u660e\u884c\u56e0\u522b\u98de\u5916\u6811\u7269\u6d3b\u90e8\u95e8\u65e0\u5f80\u8239\u671b\u65b0\u5e26\u961f\u5148\u529b\u5b8c\u5374\u7ad9\u4ee3\u5458\u673a\u66f4\u4e5d\u60a8\u6bcf\u98ce\u7ea7\u8ddf\u7b11\u554a\u5b69\u4e07\u5c11\u76f4\u610f\u591c\u6bd4\u9636\u8fde\u8f66\u91cd\u4fbf\u6597\u9a6c\u54ea\u5316\u592a\u6307\u53d8\u793e\u4f3c\u58eb\u8005\u5e72\u77f3\u6ee1\u65e5\u51b3\u767e\u539f\u62ff\u7fa4\u7a76\u5404\u516d\u672c\u601d\u89e3\u7acb\u6cb3\u6751\u516b\u96be\u65e9\u8bba\u5417\u6839\u5171\u8ba9\u76f8\u7814\u4eca\u5176\u4e66\u5750\u63a5\u5e94\u5173\u4fe1\u89c9\u6b65\u53cd\u5904\u8bb0\u5c06\u5343\u627e\u4e89\u9886\u6216\u5e08\u7ed3\u5757\u8dd1\u8c01\u8349\u8d8a\u5b57\u52a0\u811a\u7d27\u7231\u7b49\u4e60\u9635\u6015\u6708\u9752\u534a\u706b\u6cd5\u9898\u5efa\u8d76\u4f4d\u5531\u6d77\u4e03\u5973\u4efb\u4ef6\u611f\u51c6\u5f20\u56e2\u5c4b\u79bb\u8272\u8138\u7247\u79d1\u5012\u775b\u5229\u4e16\u521a\u4e14\u7531\u9001\u5207\u661f\u5bfc\u665a\u8868\u591f\u6574\u8ba4\u54cd\u96ea\u6d41\u672a\u573a\u8be5\u5e76\u5e95\u6df1\u523b\u5e73\u4f1f\u5fd9\u63d0\u786e\u8fd1\u4eae\u8f7b\u8bb2\u519c\u53e4\u9ed1\u544a\u754c\u62c9\u540d\u5440\u571f\u6e05\u9633\u7167\u529e\u53f2\u6539\u5386\u8f6c\u753b\u9020\u5634\u6b64\u6cbb\u5317\u5fc5\u670d\u96e8\u7a7f\u5185\u8bc6\u9a8c\u4f20\u4e1a\u83dc\u722c\u7761\u5174\u5f62\u91cf\u54b1\u89c2\u82e6\u4f53\u4f17\u901a\u51b2\u5408\u7834\u53cb\u5ea6\u672f\u996d\u516c\u65c1\u623f\u6781\u5357\u67aa\u8bfb\u6c99\u5c81\u7ebf\u91ce\u575a\u7a7a\u6536\u7b97\u81f3\u653f\u57ce\u52b3\u843d\u94b1\u7279\u56f4\u5f1f\u80dc\u6559\u70ed\u5c55\u5305\u6b4c\u7c7b\u6e10\u5f3a\u6570\u4e61\u547c\u6027\u97f3\u7b54\u54e5\u9645\u65e7\u795e\u5ea7\u7ae0\u5e2e\u5566\u53d7\u7cfb\u4ee4\u8df3\u975e\u4f55\u725b\u53d6\u5165\u5cb8\u6562\u6389\u5ffd\u79cd\u88c5\u9876\u6025\u6797\u505c\u606f\u53e5\u533a\u8863\u822c\u62a5\u53f6\u538b\u6162\u53d4\u80cc\u7ec6"; StringBuffer sb = new StringBuffer(); int x = 5; // 控制字数 for(int i=0;i<4;i++) { int degree = new Random().nextInt()%30; //生成-30-30范围的随机数 String ch = base.charAt(new Random().nextInt(base.length()))+""; sb.append(ch); // 写入字之前,设置好旋转 g.rotate(degree*Math.PI/180, x, 20); // 设置字体旋转角度 g.drawString(ch, x, 20); // 这次旋转不能影响下一次的旋转,所以要将上一次的旋转清掉,转回去 g.rotate(-degree*Math.PI/180, x, 20); x+=30; } return sb.toString(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
4,设置响应头控制浏览器的行为
1,定时刷新页面
response.setHeader("refresh", "5");//设置refresh响应头控制浏览器每隔5秒钟刷新一次
2,禁止缓存当前文档内容
response.setDateHeader("expries", -1); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache");
6.7、HttpServletRequest
HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,Http请求中的所有信息会被封装到HttpServletRequest,通过HttpServletRequest的方法,获得客户端的所有信息。
1、获取前端传递的参数、请求转发
参考博客:https://www.iteye.com/blog/sihailoveyan-2430052
面试题:请你聊聊重定向和转发的区别?
相同点:
-
页面都会实现跳转
不同点:
-
请求转发的时候,url不会产生变化:307
-
重定向的时候,url地址栏会发生变化:302
7、Cookie、Session
7.1、会话
会话:用户打开一个浏览器。点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话
有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学曾经来过,称之为有状态会话;
7.2、保存会话的两种技术
Cookie
-
客户端技术 (响应,请求)
Session
-
服务器技术,利用这个技术,可以保存用户的会话信息;我们可以把信息或者数据放在session中!
常见场景:网站登陆之后,你下次不用再登陆了,第二次访问直接就上去了;
7.3、Cookie
-
从请求中拿到cookie信息
-
服务器响应给客户端cookie
Cookie[] cookies = req.getCookies();//获得cookie cookie.getName()//获得cookie的key cookie.getValue()//获得cookie中的值 new Cookie("lastLoginTime",System.currentTimeMillis()+"");//新建一个cookie cookie.setMaxAge(24*60*60);//设置cookie的有效期 resp.addCookie(cookie1);//响应给客户端一个cookie
cookie:一般会保存在本地用户目录下的appdata下;
一个网站cookie是否存在上限!聊聊细节问题
-
一个cookie只能保存一个信息;
-
一个web站点可以给浏览器发送多个cookie;
-
300个cookie浏览器上限;
-
cookie大小有限制4kb;
删除cookie:
-
不设置有效期,关闭浏览器,自动失效;
-
设置有限期时间为0;
7.4、Session(重点)
什么是Session:
-
服务器会给每一个用户(浏览器)创建一个Session对象
-
一个Session独占一个浏览器,只要浏览器没有关闭,这个Session就存在;
-
用户登陆之后,整个网站它都可以访问--->保存用户的信息,保存购物车的信息...
Session和Cookie的区别:
-
Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)
-
Session是把用户的数据写到用户独占Session中,服务端保存(保存重要的信息,减少服务器资源的浪费)
-
Session对象由服务器创建;
使用场景:
-
保存一个用户登录信息;
-
购物车信息;
-
在整个网站中,经常会使用的数据我们将它保存在session中
登录页面代码实现:
SessionId: <%= session.getId() %> <br/><br/> isCreateNew:<%= session.isNew() %> <br/><br/> maxInActiveInterval:<%= session.getMaxInactiveInterval() %> <br/><br/> CreatedTime:<%= session.getCreationTime() %> <br/><br/> lastAccessedTime: <%= session.getLastAccessedTime() %> <br/><br/> <% Object username = session.getAttribute("username"); if(username == null){ username = ""; } %> <form action="<%= response.encodeURL("loginSuccess.jsp") %>" method="post"> username: <input type="text" name="username" value="<%= username%>"/><br/> <input type="submit" value="登录"/> </form>
登录成功页面:
SessionId: <%= session.getId() %> <br/><br/> isCreateNew:<%= session.isNew() %> <br/><br/> maxInActiveInterval:<%= session.getMaxInactiveInterval() %> <br/><br/> CreatedTime:<%= session.getCreationTime() %> <br/><br/> lastAccessedTime: <%= session.getLastAccessedTime() %> <br/><br/> Hello: <%= request.getParameter("username") %> <br/><br/> <% //将username存储于session之中,便于在整个会话过程中记住当前user; // 当然服务器端可以找到session还是通过cookie(URL重写)在客户端和服务器端传递JSESSIONID session.setAttribute("username", request.getParameter("username")); %> <!-- cookie被禁用的情况下使用url重写的方式传递JSSESSIONID; 重写使用:response.encodeURL或response.encodeRedirectURL()都行 --> <a href="<%= response.encodeURL("login.jsp") %>">重新登录</a> <a href="<%= response.encodeURL("loginOut.jsp") %>">注销</a>
注销:
SessionId: <%= session.getId() %> <br/><br/> isCreateNew:<%= session.isNew() %> <br/><br/> maxInActiveInterval:<%= session.getMaxInactiveInterval() %> <br/><br/> CreatedTime:<%= session.getCreationTime() %> <br/><br/> lastAccessedTime: <%= session.getLastAccessedTime() %> <br/><br/> ByeBye: <%= session.getAttribute("username") %> <br/><br/> <% //注销session session.invalidate(); %> <a href="login.jsp">重新登录</a>
8、JSP
8.1、什么是JSP
Java Server Pages :Java服务器端页面,也和Servlet一样,用于动态Web技术;
最大的特点:
-
写JSP就像在写HTML
-
区别:
-
HTML只给用户提供静态数据
-
JSP中可以嵌入Java代码,为用户提供动态数据;
-
8.2、JSP原理
思路:JSP到底是怎么执行的?
-
代码层面没有任何问题
-
服务器内部工作
-
Tomcat中有一个work目录
-
IDEA中使用Tomcat的会在IDEA的Tomcat中产生一个work目录
-
点进去发现jsp页面转变成了Java程序;
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet;
JSP最终也会转换成为JAVA类!
JSP本质上是个Servlet
运行原理:
当第一次访问jsp页面时,会向一个servlet容器(tomcat等)发出请求,servlet容器先要把 jsp页面转化为servlet代码(.java),再编译成.class 文件 再进行调用。当再次访问jsp页面时 跳过翻译和编译的过程 直接调用
执行过程:
1、 客户端发出请求
2、web容器将jsp转化为servlet代码(.java) 3、web容器将转化为servlet代码编译(.class) 4、web容器加载编译后的代码并执行 5、将执行结果响应给客户端
在jsp中:
只要是Java代码就会原封不动的输出;
如果树Html代码,就会被转换为:
out.write("<html>\r\n");
这样的格式输出出来;
8.3、JSP基础语法
任何语言都有自己的语法,java中有,那jsp作为java技术的一种应用,它拥有一些自己扩充的语法(了解即可),java所有语法都支持!
JSP表达式:
<%-- JSP表达式 作用:用来将程序的输出到客户端 <%= 变量或者表达式%>--%> <%= new java.util.Date()%>
jsp脚本片段:
<%-- jsp脚本片段--%> <% int sum = 0; for (int i = 0; i <= 100; i++) { sum+=i; } out.println("<h1>"+"Sum="+sum+"<h1>"); %>
脚本片段的再实现:
<% int x = 10; out.println(x); %> <p>这是一个jsp文档</p> <% int y = 20; out.println(y); %> <hr> <%-- 在代码中嵌入html元素 --%> <% for (int i = 0; i < 5; i++) { %> <h1>Hello,World<%=i%></h1> <% } %>
JSP声明:
<%! static { System.out.println("Loading Servlet!"); } private int globalVar = 0; public void yuan(){ System.out.println("进入了方法yuan!"); } %>
JSP声明:会被编译到jsp生成的java的类中!其他的,就会被生成到_jspService方法中!
在jsp中嵌入java代码中即可!
<% %> <%= %> <%! %> <%----%>
jsp的注释,不会在客户端显示,html的注释会被显示;
8.4、JSP指令
<%@ page ... %> | 定义网页依赖属性,比如脚本语言、error页面、缓存需求等等 |
---|---|
<%@ include ... %> | 包含其他文件 |
<%@ taglib ... %> | 引入标签库的定义 |
参考博客:https://www.runoob.com/jsp/jsp-directives.html
8.5、9大内置对象
-
PageContext 存东西
-
Request 存东西
-
Response
-
Session 存东西
-
Application 【ServletContext】 存东西
-
config 【ServletConfig】
-
out
-
page,不用了解
-
exception
<% pageContext.setAttribute("name1","智能1号");//保存的数据只在一个页面中有效 request.setAttribute("name2","智能2号");//保存的数据只在一次请求中有效,请求转发会携带这个参数 session.setAttribute("name3","智能3号");//保存的数据只在一次回话中有效,从打开浏览器到关闭浏览器 application.setAttribute("name4","智能4号");//保存的数据只在服务器中有效,从打开服务器到关闭服务器 %>
Request:客户端向服务器发送请求,产生的数据,用户看完就没用了,比如:新闻,用户看完就没用了;
Session:客户端向服务器发送请求,产生的数据,用户用完一会儿还有用,比如:购物车;
Application:客户端向服务器发送请求,产生的数据,一个用户用完其他用户还可能使用,比如:聊天数据;
8.6、JSP标签、JSTL标签、EL表达式
要导入的配置:
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl-api --> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl-api</artifactId> <version>1.2</version> <https://img.qb5200.com/download-x/dependency> <!-- https://mvnrepository.com/artifact/taglibs/standard --> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> <https://img.qb5200.com/download-x/dependency>
EL表达式:${}
-
获取数据
-
执行运算
-
获取web开发的常用对象
-
调用java方法(不用)
JSP标签:
<%--http://localhost:8080/jsptag.jsp?name=yuan&age=12--%> <h1>1</h1> <jsp:forward page="/jsptag2.jsp"> <jsp:param name="name" value="yuan"/> <jsp:param name="age" value="12"/> </jsp:forward>
JSTL表达式:
参考博客:https://www.runoob.com/jsp/jsp-jstl.html
JSTL标签库的使用就是为了弥补HTML标签的不足,他自定义了许多标签,可以供我们使用,标签的功能和java代码一样!
核心标签(掌握部分):
JSTL标签使用步骤:
-
引入对应的taglib
-
使用其中的方法
-
在tomcat中也需要引入jstl的包,否则会报错:JSTL解析错误
9、JavaBean
实体类
JavaBean有特定的写法:
-
必须要有一个无参构造
-
属性必须私有化
-
必须有对应的get/set方法
一般用来和数据库的字段做映射 ORM
ORM:对象关系映射
-
数据库的表---->Java的类
-
字段---->属性
-
行记录---->对象
10、MVC三层架构
10.1、三层架构
参考博客:https://www.jianshu.com/p/731d027b2d91
什么是MVC:Model View Controller 模型、视图、控制器
约定:
-
Servlet和JSP都可以写Java代码:为了易于维护和使用
-
Servlet专注于处理请求,以及控制视图跳转
-
JSP专注于显示数据
控制器:Controller Servlet :
-
接受用户的请求
-
响应给客户端内容(交给业务层去做)
-
重定向或者转发(视图跳转)
View:视图层:JSP
-
展示数据模型
-
提供用户操作
数据库:
-
增删改查
JavaBean
-
pojo
-
entity...
Service:
-
login登录
-
logout注销
-
查询全部用户
Model
-
业务处理:业务逻辑(Service)
-
数据持久层:CRUD(Dao)
View:
-
展示数据
-
提供链接发起Servlet请求(a,form,img...)
Controller:
-
接收用户的请求:(req:请求参数、session信息...)
-
交给业务层处理对应的代码
-
控制视图的跳转
登录--->接收用户的登录请求---->处理用户的请求(获取用户登录的参数;username,password)---->交给业务层处理登录业务(判断用户名密码是否正确:事务)---->Dao层查询用户名和密码是否正确---->数据库
10.2、早些年架构
用户直接访问控制层,控制层就可以直接访问数据库;
servlet---->CRUB(增删改查)---->数据库 弊端:程序十分臃肿,不利于维护 servlet的代码中:处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码 架构:没有什么是加一层解决不了的!如果不行,再加一层! 程序员调用: JDBC 操作: MySQL、Oracle、SQLServer....
11、Filter(重点)
Filter:过滤器,用来过滤网站的数据;
-
处理中文乱码
-
登录验证
Filter开发步骤
-
导包
-
编写过滤器
-
必须导这个Filter包
-
实现Filter接口,重写对应的接口即可
package com.yuan.filter; import javax.servlet.*; import java.io.IOException; public class CharacterEncodingFilter implements Filter { //初始化 public void init(FilterConfig filterConfig) throws ServletException { System.out.println("CharacterEncodingFilter已经初始化了"); } // 1.过滤器中的所有代码,在过滤特定请求的时候都会执行 // 2.必须要让过滤器继续执行 // 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已经销毁了"); } }
配置:
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.yuan.filter.CharacterEncodingFilter</filter-class> </filter> <!-- 只要是/Servlet的任何请求,都会经过这个过滤器--> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/Servlet/*</url-pattern> </filter-mapping>
12、监听器
实现一个监听器的接口;(有N种)
-
编写一个监听器
实现监听器的接口
-
web.xml中配置监听器
-
看情况是否使用!
13、过滤器、监听器的常见应用
监听器:GUI编程中经常使用
统一编码,统一用户认证,屏蔽非法文字,进行响应数据压缩等。
用户登陆之后才能进入主页!用户注销后就不能进入主页了!、
-
用户登陆之后,向Session中放入用户的数据;
-
进入主页的时候要判断用户是否已经登陆;要求:在过滤器中实现;
14、JDBC
什么是JDBC:java链接数据库
需要jar包支持:
-
java.sql
-
Javax.sql
-
Mysql-connect-java...(连接驱动必须要的)
实验环境搭建:
导入数据库依赖:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> <https://img.qb5200.com/download-x/dependency>
IDEA中连接数据库:
JDBC固定步骤:
-
加载驱动
-
连接数据库,代表数据库
-
向数据库发送SQL的对象Statement : CRUD
-
编写SQL(根据业务,不同的SQL)
-
执行SQL
-
关闭连接
事务:
要么都成功,要么都失败!
ACID原则:保证数据的安全。
开启事务 事务提交 commit() 事务回滚 rollback() 关闭事务 转账: A:1000 B:1000 A(900)---100--->B(1100)
Junit单元测试:
依赖:
<!--单元测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> <https://img.qb5200.com/download-x/dependency>
简单使用:
@Test注解只有在方法上有效,只要加了这个注解的方法,就可以直接运行!
@Test public void test(){ System.out.println("Hello World"); }
成功提示绿色,失败提示红色!
搭建一个环境测试一波事务!
加载全部内容