HTTP协议就是 HTTP客户端 和 HTTP服务器之间用来进行通信的协议.
HTTP客户端就是浏览器(当然也有别的)
HTTP服务器,则是有很多种实现
而tomcat则是在Java圈子中,最知名的,最广泛使用的HTTP服务器.
另外,下面的那个webapp就是app应用也就是一个"网站",一个tomcat上可以部署多个网站,此处就被称为"webapps",这里包含的很多目录,都试做一个独立的网站,后面我们写的代码都是放在这个"webapps"里部署的.
这个就是tomcat的启动程序
看到这个就说明启动成功了!!!
在地址栏输入127.0.0.1:8080
如果没有进入成功说明8080默认端口被占用,需要关闭在8080端口运行的程序.
tomcat最大作用就是把咱们写好的网站给部署上去,前端+后端
拷贝之前的博客代码到webapp
然后这么搜索就可以了!!!(记住一定是按照路径进行访问)
这种访问方式和之前的直接右键最本质的区别是:这种环回ip访问是通过网络进行的访问,是跨主机的!!!
但是因为电脑是没有外网ip的所以只能在局域网,或者环回ip中使用,想要获得外网ip最简单的方法就是直接租一个服务器.
网站后端运用的是http服务器,但是我们的Tomcat已经把一些常用的http相关的底层操作给封装好了,而我们只需要使用Tomcat给的api即可.
这些Tomcat给java提供的进行网页开发的原生的api被称为Servlet.
动态页面:内面内容随着输入参数的不同而改变.(浏览器搜索结果页面,也就是html+数据)
静态页面:页面内容总是恒定不变的.(浏览器搜索页面,也就是只有html)
写个hello world
我们预期写个servlet程序,部署到tomcat上,通过浏览器访问,的到hello world字符串.
此处我们要创建一个maven项目
maven是一个叫做工程管理工具,它能够干得事情:
规范目录结构
管理依赖(使用了啥第三方库之类的,都能处理好)
构建
打包
测试
......
这里我们主要使用它的管理依赖以及打包的功能.
使用Maven创建项目.注意Maven直接就是idea内置的!!!
点开目录,我们能够看到一些程序.
引入servlet对应的jar包
Maven Repository: javax.servlet » javax.servlet-api » 3.1.0 (mvnrepository.com)
在这个网址,可以直接拷贝上面的代码放到
直接将Maven中的内容粘贴到dependencies中,这个标签就相当于是我们自己写的,如果有多个依赖都可以进行粘贴.第一次粘贴可能是红的,我们可以进行包的下载,下完了后也就不红了.
可以说这里我们引入的依赖就是maven仓库的坐标,以后获取的方法以及引用就是从这个坐标中获取了!!!
虽然Maven已经自动帮助我们创建了一些目录了,但是还不够.此处是需要使用maven开发一个web程序,但是还不够.
a.在main目录下,(和java,resources并列),创建一个webapp目录.
单词要一致,不能拼写错误.
b.在webapp下创建WEB-INF目录
c.再在WEB-INF目录下创建一个web.xml文件
此时我们的目录结构也就完成了!!!
注意:此处的目录名字以及结构都不能够发生错误.
d.给web.xml写点东西进去.
Archetype Created Web Application
注意:这个东西不要死记硬背,这个东西就放在手边,想要的时候直接进行复制.
当前写的Servlet程序相比以往写的代码来说,最大的区别就是没有main方法,而main方法在程序中就相当于发动机,如果想要让一辆没有发动机的车跑起来,就需要给他分配个车头,带着它走.而在这里我们的车头就是Tomcat,而写好的servlet程序就是车厢.咱们把写好的servlet代码放到webapps目录下,而哪些是需要tomcat拉着走的车厢呢?怎么识别?就是看咱们现在复制的这串web.xml
所以说现阶段不需要理解其中的含义,就当做一个影响标准就好!!!
.
注意:在这里飘红并不代表错误,因为idea能够准确的识别java代码,但是对其他代码不能够完全进行识别.(单纯就是idea识别的不准)
在main目录中的java文件夹创建一个类,然后继承HttpServlet类.
HttpServlet是servlet api里提供的现成的类,写servlet代码一般都是继承这个HttpServlet类.
然后重写doGet方法:
我们这个doGet方法,不需要我们自己手动调用,而是交给Tomcat去调用.Tomcat收到get请求.就会触发doGet方法.
Tomcat会构造好两个参数:req和resp
这里的req是TCP socket中读出来的字符串,按照HTTP协议解析出来得到的对象.
这个对象里的属性是啥?
就是和HTTP请求报文格式相对应的!!!
这里我们的resp对象是一个空的对象.这就是程序员要干得事情了.程序员需要在doGet,根据请求req,结合我们业务逻辑构造出一个resp对象来.(也就是干了服务器根据请求计算响应的工作,其中的"resp"本质上是一个输出型参数)
这里我们的surprt.doGet()只是返回了一个错误页面,和我们要求的意愿是不符的,所以一定要删除!!!
doGet的目的就是根据请求计算响应.
req是Tomcat针对请求已经解析好的字符串.
resp则是一个空的对象(就是new了一个对象,里面的属性没设置需要程序员自行设定)
此处我们的"hello world"代码这只是打印一个"hello world",不需要使用到req
这里进行的write操作其实就是网resp的body部分尽心写入.等resp对象构造好了,Tomcat会统一转成HTTP响应的格式,再写socket.
接下来,添加注解
这个是Tomcat为我们实现的注解,注解的作用就是针对这个类/方法进行额外的"解释说明"赋予这个类/方法额外的功能/含义.
此处的注解的作用就是将我们的这个HelloServlet这个类 和一个HTTP请求具体的路径进行关联.
doGet是Tomcat收到GET请求的时候就会调用.具体要不要调用doGet,会得看GET请求的路径是啥.不同的路径会触发不同的代码(比如这里的/hello就关联到HelloServlet类上)
此处的注解就相当于一个"导购员",它会根据收到的请求的种类选择具体执行哪个类.
也就是把程序编译好(得到一些.class文件)
然后再把这些.class达成一个压缩包
jar包就是一种.class压缩包.
但是我们此处是要打成一个war包,jar只是一个普通的java程序,而war则是Tomcat专属的用来描述webapps的程序.一个war就是一个webapp
这样就是打包成功了!!!
打包成功后包就在左侧的target目录下.
默认情况下,系统打的是jar包,如果想要打war包,则还需要微调一下.
在底下的pom.xml中加入一个packaging的标签:
这就是描述我们打的包的格式.
另外,还可以设置打的war包的名字:
如果不写就是生成一个比较麻烦的名字.
然后重新进行打包
此时就生成了一个全新的war包!!!
打开它在文件夹中的位置.
包刚才打包好的war拷贝到Tomcat的webapps目录中即可.
无论你的Tomcat是在当前的电脑上还是不同的电脑上,都是这样进行拷贝.(其他主机或者云服务器都是这样)
然后启动Tomcat:
打开浏览器输入url,检查一下我们写好的这个代码.
然后根据webapps里存储的路径进行访问:
第一级路径是hello_Servlet,第二级路径是我们上面在代码中利用注释确定的/hello这个路径
最终我们的hello world就出来了!!!
在刚才的浏览器地址栏输入url之后,浏览器就造就了一个对应的HTTP GET请求,发给了Tomcat.Tomcat 就根据它的第一级路径,确定了webapp.根据第二级路径确定了调用的是哪个类.
再然后通过Get还是Post确定调用的是HelloServlet的哪个方法(doGet,doPost......)
此时Tomcat就完成了对应的操作了!!!
在第5以及6步中,可以使用IDEA的Tomcat插件,把Tomcat集成到IDEA中,就省去手动打包,手动部署的过程,只需要按一下运行,就可以自动打包部署了.
但是,一般来说,手动打包部署应用在上线操作中,而自动打包部署应用在开发环境中.使用环境不同,所以说都得会!!!
IDEA中提供了一些api可以让程序员开发插件,对IDEA的功能进行扩展.
在这里进行插件的下载.
点击这个
然后添加一个Tomcat
这里主要需要进行填写的是Tomcat的绝对路径:
点击确定,此时我们的右上角就有了一个配置文件:
点击三角号运行即可.
此时显示运行失败了,仔细读一下报错信息,原因是我们的8080端口被占用了(很常见的问题)
netstat -ano|findstr 8080//这是查找8080端口是什么进行在占用
然后针对进程id进行关闭:
taskkill -pid 24168 -f
此时就启动成功了.
还是可以运行!!!
这里解释一点:smart Tomcat不是自动把war包给拷贝了,(webapps历史不变的)是通过另外一种方式来启动的tomcat.
Tomcat支持启动的时候显示指定一个特定的webapp目录.(相当于是让tomcat加载单个的webapp)没有加载的过程,也没有打包的过程,也没有拷贝的过程.
而这个页面里面没有欢迎页面:
如果你直接进行一手欢迎页面的访问,就会404
注意:这里"127.0.0.1:8080"后面的一级路径如果使用插件,是项目名称.如果不适用插件的话,采用手动部署的方式,就是war包名称.
web.xml有没有写对
如果都到了个get方法,但是代码中没有doGet就会405
super.doGet没有删除:
本质上就是代码出错了,而且日志上会告诉你哪一行出错了!!!
就是没有返回客户端信息.
也就是Tomcat没有启动.
检测方法:查看端口是不是冲突了!!!
主要掌握三个类即可:
HttpServlet
HttpServletRequest
HttpServletResponse
tomcat首次用到了和该类相关的请求时自动实例化(类似于之前的懒汉模式)
这里我们的HelloServlet2类继承了HttpServlet类,所以自然也自动实现了init(在Tomcat收到请求关联到了这里的"hello"路径的时候会调用init默认是没有东西的)
当然也是冲动重写的:
在页面调用成功的时候,控制台就会调打印 init.
这个方法会在HttpServlet实例不再使用的时候调用一次,但是在Tomcat运行的全过程中,HttpServlet都在使用,所以只有当服务器程序结束的时候才会调用.
看这里,调用已经结束:
结束程序调用destroy.
注意:这里的destroy只会在正常结束程序的时候进行调用,但是如果你采用直接杀进程的方式结束程序,那也会有可能来不及调用这个方法.(所以不太推荐使用不太靠谱)
这个方法会在收到HTTP请求的时候进行调用.
如我们的doGet方法就是其中一个
这三个方法使我们在使用HttpServlet的时候最为常用的方法:
Servlet的生命周期是怎么回事(具体来说就是什么东西什么阶段要干啥(调用哪个方法)):
程序开始的时候,执行init
每次收到请求,执行service
每次销毁之前,执行destroy
在这里我们将所有方法列举出来:
然后运行程序
发现这里直接使用url进行访问触发的只是doGet方法.
首先我们要在webapps的目录下创建一个html的前端文件
然后最好使用vscode打开
然后再引入jquery cdn引入库.并使用ajax方法
注意:
此处是相对路径写法,也可以写作称为绝对路径:
然后打开浏览器(开发者控制台):
我们发现也是可以正常调用所有方法的请求的!!!
这里我使用get方法进行发送收到的也是doGet
如果改成Post方法进行发送,获取到的请求也是doPost.以此类推(我们就可以使用postman构造出各种各样的请求)
一个HTTP请求中包含的所有部分都会在这个类中体现出来.
而HTTP请求的这个对象是由Tomcat自动构造的.Tomcat其实监听窗口、接受连接、读取请求、解析请求、构造请求对象等一系列工作.
其余的都是字面意思以及使用方法
最重要的两个方法:
query String是键值对结构,所以此处就可以通过getParameterNames( )方法来根据key获取到value
另外:
就是这些可以直接获取HTTP请求header部分内容的方法:
getHeader()就是可以直接获取header部分的值(以字符串形式)
后面的四个是因为有些内容(如字符集,长度等)比较重要,所以独自封装在了一个方法中以便调用.
而这个:
就是相当于把HTTP请求中的body给读了出来.
此时我们得到的这些结果就是这些方法得到的结果!!!
如果想要看得更加清楚,就需要让它换行显示:
这种代码风格属于迭代器遍历的方式,就是遍历完header里面最后一个元素为止.
这个就是header中的所有元素!!!
这里我们计划传送两个数字,一个是studentId一个是classId,也就是就收一个形如:
?studentId=10&classId=20的这样一个query string.
这里的Tomcat键值对会被Tomcat处理成形如Map这样的结构,后续就可以通过getParameter进行value值的获取了!!!
对于前端是from表单这样格式的数据,后端还是使用getParameter来进行获取.
通过html的from表单就可以完成这部分表格的构造.
使用from表单,就可以构造一个Post请求,然后接收浏览器用户传输过来的数据:
这是具体的表现形式
点击提交之后,因为没有进行网页跳转的页面的设置所以会显示404
此时使用fiddler进行抓包:
这里body的大小就是我们query string的值.
而这里的applocation/xx就是指这是一个from表单构造出来的请求.
此时也可以进行后端代码的编写:
依然跟刚才的代码一致但是WebServlet改成了刚刚前端指定的那个网址
点击之后会自动跳转到这个页面.(这也是一个比较简单的前后端交互了!!!)
就是类似:
{
studentId:10,
classId:20
}
我们也可以使用json把body这个部分进行组织.前端可以通过ajax的方式构造出这个内容,当然更简单的是直接使用postman进行body的构造.
当然此时如果发送因为没有这里的postParameterServlet2页面所以说会读取失败,现在我们来看后端的写法(这里我们采用之前学过的getInputStream字节流进行读取):
至于读取长度就是header里面的content-Length使用getContentLength()方法进行这个json格式的长度来规定字节流读取的长度.然后这个数组编写为字符串形式:
这个代码的执行流程和上面的from表单传参效果是类似的.只是传输的数据格式不同:
from表单是classId=10&studentId=20
而json的格式是
{
studentId:10,
classId:20
}
这三种传参都是极为常见的.
但是还有个问题:
第三种方式只是把整个的json格式body从请求中读了出来,但是还没有将其中的key与value读出来.
此时就要使用第三方库来进行json格式数据的解析:jackson(有spring给他背书)
依旧是进入Maven 存储库:搜索/浏览/探索 (mvnrepository.com)maven库
搜索并下载2.14.1版本的jackson
然后将依赖并列到之前的
此时就可以舍弃我们之前的字节流读取形式(直接使用jackson进行读取):
实例化一个objectMapper类进行jackson的使用,这里的readvalue就是把一个json格式的字符串转换成Java格式.
如果此处要使用readValue()方法,需要把要提取的key单放在一个类里面:
解释一下最后这个代码:
然后就可以进行打印了
readvalue():把json字符串转成java对象.
writevalue():把java对象转成json格式字符串.
这两个方法就是设置http响应中报头的key值
而这两个是设置http响应中的content Type的:
也就是那个resp.setContentType("text/html");
第二个是设置响应的字符编码的.
如果没有resp.setCharacterEncoding("utf8")来设置字符集,浏览器就无法识别中文:
只有设置了字符集,浏览器才能够识别中文:
其实这个content Type与字符集也是可以设置在一起的:
然后是他:
他的作用就是让浏览器自动的跳转到一个新的地址(3XX的状态码)
在正常的网页中,我们实现页面跳转是主要就是只用这个方法
点击确认:
然后就自动跳转到了百度
使用fiddle进行抓包,就会发现我们的响应:
这样是个302的状态码,而这里的Location就是我们之前在后端中设置的响应地址.
理解了上述流程,我们就可以手动设置这个sendRedirect()方法:
选择设置302状态码,然后手动添加一个header:设置键值对.
效果跟刚才也是一致的.
如果关闭页面或者刷新页面,之前写的内容就会全部清空.
如果一个机器上的数据,第二台机器上是看不到的(这些数据都是在本地的浏览器中)
让服务器来存储用户提交的数据.有服务器来保存.当心的浏览器打开页面的时候,从服务器获取数据.
(也就是存档和读档功能)
写web程序,务必要重点考虑前后端是如何交互的.也就是约定好后端交互的数据格式.
也就是规定请求是啥样响应是啥样,浏览器啥时候发的这个请求,浏览器按照啥样的格式来解析.
首先我们要确定哪些环节设计到了前后端的交互:
点击提交.浏览器把表白信息发到服务器这里
请求:
POST/message
{
from:"张三",
to:"李四",
message:"你好"
}
响应:
HTTP/1.1 200 OK
页面加载.浏览器从服务器获取到表白信息.
请求:
GET/message
响应:HTTP/1.1 200 OK
而message的格式我们就采取json的格式进行组织:
[
{
from:"张三",
to:"李四",
message:"你好"
}
{
from:"张三",
to:"李四",
message:"你好"
}
]
注意:此处的约定没有什么强制要求,都可以进行更改.
选取5.1.49:
主要就是在main目录下创建一个webapp目录,然后再webapp目录下创建WEB-INF目录,然后在WEB-INF目录下穿件web.xml文件.
注意:一步都不能错!!!
Archetype Created Web Application
这段直接复制进web.xml里!!!
在java文件夹下进行代码的创建:
注意这里的WebServlet需要和之前我们在代码设计中约定的一致(所以使用/message)
首先是连个方法,一个从服务器获取数据,一个是向服务器提交数据:
首先定义一个类
然后还是之前那一套
此时呢,我们就把收到的json格式的数据转换成了一个字符串.
我们先不使用mysql来进行存储,先使用一个变量来存储:
记得进行状态码(不设定也是默认200).
此时doPost就完成了:它的工作就是把json数据解析然后存到List里面.
根据我们的设计,返回的数据也是一个json格式,如果还要将List中存储的数据再转换成json格式(基于objectMapper的writeValue方法)然后进行发送.
objectMapper.writeValue(resp.getWriter(),messageList);
这一行代码同时完成了将java对象转换成json格式和将这个json字符串写到响应当中两步.
第一步也就是resp.getWriter规定了写出来的这个字符串要写到哪里去(流对象)
第二步也就是messageList将List中的数据转成了字符串格式.
此时doGet就完成了!!!
显示的告诉浏览器我们的数据格式是json格式的.
此时表白墙程序的后端就大功告成了!!!
注意:这里postman的作用是在模拟浏览器,浏览器用户填写数据后的交互,就相当于向服务器发送了一个post请求,然后再由后端的doPost方法进行接收
所以此时我们post后,我们的"浏览器"是不会有任何的响应的,只有切换到get进行数据的接收,才会看到结果:
将之前写的messageWall代码放到webapp文件夹里面.
要想使用前后端交互,需要使用ajax,要想使用ajax就需要首先引入jquery
这几个对象,取决于上面的变量:
相当于读取了三个输入框的数值,而这里的输入框的值就是用户输入的内容.
相较于java的需要一个jackson才能转换,html直接在标准库中内置了一个方法进行json字符串的转换.
提交一份数据
然后点开fillder
这是点击完提交后抓到的一个数据包.
主要关注一下我们的方法,url,body部分,content-type这些部分,如果和当初写前端程序之时设置的一致,就说明前端程序就没有错误了!!!(气候的所有项目都可以这样进行测试)
此时我们的body拿到的就是一个js数组了,本来服务器返回的是一个json但是jquery能够自动识别json格式自动帮我们把json转换为了js,接下来我们只是需要遍历这个数组,把元素取出来打印即可.
此处的逻辑其实跟上面打印div的逻辑是一样的只不过这个是从get到的js数组中打印.
此处要指定好我们数据的来源不要混了.
我们要知道,读档操作是读取所有的数据,而存档操作是是只存一条数据,所以说这里的body代表了全部数据,而遍历body得到的message则是其中一组js数据,而message.from则是其中我们需要的那几个属性.(所以说上面说过这里读档功能读取的是一个数组,一个装满"message"的"body"数组)
能够正常读取内容!!!
使用fiddler也可以看到数组是可以正确传输的!!!
但是,此程序还有缺点,就是如果关闭服务器,那么在服务器中存储的内容也都将被清除!
直接使用流对象写入文本文件
借助数据库
表的具体内容:message(from,to,message)
首先创建一个数据库:
然后再数据库按照上述要求建一个表:
建立连接类
断开连接类
这个类是建立连接对象的实例化.
静态成员是跟随类对象的,类对象在整个进程中只有唯一的一份.静态成员也相当于是唯一的实例.(也就是之前多线程讲过的单例模式,饿汉模式)
其实就是按照顺序进行这三个对象的关闭
此时其实这个DBUtil类就编写完成了!!!
这是存放数据:
这是取出数据:
新添操作:
查询操作:
此时数据库代码就已经完成了!!!
此时重新启动数据库,然后再提交一条数据:
我们发现此时数据就会同时出现在数据库中.
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* Description:
* User: 86139
* Date: 2023-03-24
* Time: 22:34
*/
class Message{
public String from;
public String to;
public String message;
}
@WebServlet("/message")
public class messageServlet extends HttpServlet {
//这个就可以直接换掉了
//private List messageList=new ArrayList<>();
//向服务器提交数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ObjectMapper objectMapper=new ObjectMapper();
Message message=objectMapper.readValue(req.getInputStream(),Message.class);
//messageList.add(message);
save(message);
resp.setStatus(200);
}
//从服务器获取数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ObjectMapper objectMapper=new ObjectMapper();
resp.setContentType("application/json;charset=utf8");
List messageList=load();
objectMapper.writeValue(resp.getWriter(),messageList);
}
//往数据库中存一条消息
private void save(Message message){
Connection connection=null;
PreparedStatement statement=null;
try {
//1.建立连接
connection=DBUtil.getConnection();
//2.构造sql语句
String sql="insert into message values(? ,? ,? )";
statement=connection.prepareStatement(sql);
statement.setString(1,message.from);
statement.setString(2,message.to);
statement.setString(3,message.message);
//3.执行sql
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//4.关闭连接
DBUtil.close(connection,statement,null);
}
}
//从数据库中取所有数据
private List load(){
List messageList=new ArrayList<>();
Connection connection=null;
PreparedStatement statement=null;
ResultSet resultSet=null;
try {
//1.和数据库建立连接
connection=DBUtil.getConnection();
//2.构造sql语句
String sql="select * from message";
statement=connection.prepareStatement(sql);
//3.执行sql
resultSet=statement.executeQuery();
//4.遍历结果集合
while(resultSet.next()){
Message message=new Message();
message.from=resultSet.getString("from");
message.to=resultSet.getString("to");
message.message=resultSet.getString("message");
messageList.add(message);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
//5.释放资源,断开连接.
DBUtil.close(connection,statement,resultSet);
}
return messageList;
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* Description:
* User: 86139
* Date: 2023-03-24
* Time: 22:34
*/
class Message{
public String from;
public String to;
public String message;
}
@WebServlet("/message")
public class messageServlet extends HttpServlet {
//这个就可以直接换掉了
//private List messageList=new ArrayList<>();
//向服务器提交数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ObjectMapper objectMapper=new ObjectMapper();
Message message=objectMapper.readValue(req.getInputStream(),Message.class);
//messageList.add(message);
save(message);
resp.setStatus(200);
}
//从服务器获取数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ObjectMapper objectMapper=new ObjectMapper();
resp.setContentType("application/json;charset=utf8");
List messageList=load();
objectMapper.writeValue(resp.getWriter(),messageList);
}
//往数据库中存一条消息
private void save(Message message){
Connection connection=null;
PreparedStatement statement=null;
try {
//1.建立连接
connection=DBUtil.getConnection();
//2.构造sql语句
String sql="insert into message values(? ,? ,? )";
statement=connection.prepareStatement(sql);
statement.setString(1,message.from);
statement.setString(2,message.to);
statement.setString(3,message.message);
//3.执行sql
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//4.关闭连接
DBUtil.close(connection,statement,null);
}
}
//从数据库中取所有数据
private List load(){
List messageList=new ArrayList<>();
Connection connection=null;
PreparedStatement statement=null;
ResultSet resultSet=null;
try {
//1.和数据库建立连接
connection=DBUtil.getConnection();
//2.构造sql语句
String sql="select * from message";
statement=connection.prepareStatement(sql);
//3.执行sql
resultSet=statement.executeQuery();
//4.遍历结果集合
while(resultSet.next()){
Message message=new Message();
message.from=resultSet.getString("from");
message.to=resultSet.getString("to");
message.message=resultSet.getString("message");
messageList.add(message);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
//5.释放资源,断开连接.
DBUtil.close(connection,statement,resultSet);
}
return messageList;
}
}
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Created with IntelliJ IDEA.
* Description:
* User: 86139
* Date: 2023-03-27
* Time: 19:41
*/
public class DBUtil {
private static DataSource dataSource=new MysqlDataSource();
static {
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/messageWall?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("111111");
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
html代码:
表白墙
表白墙
输入内容后点击提交,信息会显示到下方表格中
谁:
对谁:
说:
cookie是个啥:浏览器提供的可以持久化存储数据的机制.
cookie是从哪里来的:从服务器返回给浏览器的.服务器代码由程序员决定把啥样子的信息保存到客户端这边,通过HTTP响应的Set-cookie字段,把键值对写回去即可
cookie会在后续浏览器访问服务器的时候带回到请求的header中.(服务器可以通过cookie中的值确定连接服务器的这台主机的身份)
cookie存储在哪里:存储在浏览器(客户端)所在的主机硬盘中.浏览器会根据域名分别存储.
表示用户的身份信息
也就是说一但我们登录成功一次,就会在cookie中持久的保存一份我们的身份信息,有了这个身份信息,淘宝就可以直接识别出我们的登录状态了!!!而每个cookie都有一个过期时间,就是过一段时间会删除身份cookie(可能是服务器删的也可能是浏览器删的).
服务器就把这些键值对称为session(会话)
把生成的唯一身份标识称为sessionId(会话Id)
关联:在网站的登录功能中,需要配合在一起使用.
区别:cookie是客户端的存储机制.session式服务器的存储机制.
cookie里面可以存储各种键值对(还可以存别的).session则是专门用来保存用户的身份信息
cookie完全可以单独使用,不搭配session(实现登录场景下)
session也可以不搭配cookie使用(手机app登录服务器,服务器也需要session,此时就没有cookie的概念)cookie跟浏览器强相关.
cookie是属于HTTP协议的一个部分
Session则是和HTTP无关(TCP,websocket...也可以用session)
程序设计:
类似这种样子,点击按钮触发一个登录请求(LoginServlet)来验证密码是否正确.
如果登录成功,跳转到主页(另一个页面也是一个静态的html,也可以通过Servlet动态构造的页面)
登录页面
主页面
处理登录的Servlet判断用户名和密码
构造主页面的Servlet
根据设计创建.
首先把应该有的元素罗列在上面:
然后启动服务器看看效果:
也可以使用fiddler进行抓包:
发现所有值和之前缩写的前端代码都是对应的.就可以了
主要看这一个键值对:
它标志着这个前后端程序的交互是以from表单形式完成的!!!
之后就是登录成功逻辑的编写:
首先是创建一个会话,这里的getSession(true)是在判断当前是否已经有对应的会话了(拿着请求中的cookie里的sessionId查一下hash表)如果没有找到sessionId就会重新创建会话,并插入到hash表中.如果查到了,就直接会返回查到的结果.
创建过程:
创建一个HttpSession对象
构造一个唯一的SessionId
把这个键值对插入到哈希表中
把sessionId设置到响应报文,Set-cookie字段中.
注意:这里的HttpSession自己也是一个键值对(且是程序员自己自定义的键值对),愿意存啥就存啥
使用setAttribute和getAttribute来进行键值对的存取
这个true和false的意思就是如果没有账号的话是否要创建新的
首先,我们要判断用户的登录状态,如果还么登录,得先要求用户登录,如果已经登录了,则根据用户的用户名显示到页面上
就可以取出我们之前存的username
注意:
此时程序就写完了,当我们输入正确的用户名与密码之时,就能够正常跳转页面了:
后续的登录之后的操作就只需要你的sessionId了,不需要再另行登录创建.