##前言
注:本篇博客是基于B站遇见狂神说的JavaWeb讲解视频进行编写,如有遗漏和错误欢迎指出,原视频地址为【狂神说Java】JavaWeb入门到实战,大家记得三连啊✧(≖ ◡ ≖✿)
下面我们进入正题!
web开发:
在Java中,动态web资源开发的技术统称为JavaWeb
web应用程序:可以提供浏览器访问的程序
a.html b.html…多个web资源,这些web资源可以被外界访问,对外界提供服务
我们能访问到的任何一个页面或者资源,都存在于这个世界上的某一个角落的计算机上
URL
这些统一的web资源会被放在同一个文件夹下,web应用程序---->Tomcat:服务器
一个web应用由多部分组成(静态web 动态web)
web应用程序编写完毕后,若想提供给外界访问,需要一个服务器来统一管理
页面会动态展示:web的页面展示的效果因人而异(不同的人打开的页面是不一样的)
缺点
优点
ASP:
PHP:
JSP/Servlet:
服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应信息
IIS:
Tomcat
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,他是最佳选择
Tomcat 实际上运行JSP 页面和Servlet。另外,Tomcat和IIS等Web服务器一样,具有处理HTML页面的功能。
下载Tomcat:
在安装之前给大家提一个建议,我在学习新知识的过程中经常会到软件版本不匹配报错的问题,而且经常卸载安装好几次也不成功,
所以建议大家在安装之前先去查看以下版本匹配的问题(不是最新的版本就是最好的),我在这里使用是Tomcat9
具体的下载流程大家可以参考以下博客,tomcat安装及配置教程(保姆级)_爱你的阿白~的博客-CSDN博客_tomcat安装及配置教程
可能遇到的问题:
可以配置主机的名称
思考问题
网站应该有的结构:
--webapps : Tomcat服务器的web目录
--ROOT
--Qstudy : 网站的目录名
--index.html : 默认的首页
--static
--css
--js
--img
--...
--WEB-INF
--classes : java程序
--lib : web应用所依赖的jar包
--web.xml : 网站的配置文件
超文本传输协议(Hyper Text Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。
http端口:80 https端口:443 (s代表安全)
客户端------发请求(request)-----服务器
Request URL: https://www.baidu.com/ //请求地址(以百度为例)
Request Method: GET //GET/POST方法
Status Code: 200 OK //状态码:200代表OK
Remote Address: 110.242.68.3:443 //地址
Referrer Policy: strict-origin-when-cross-origin //协议
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//语言
Cache-Control: max-age=0
Connection: keep-alive
消息头
Accept: //告诉浏览器它所支持的数据类型
Accept-Encoding: //支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1
Accept-Language: //告诉浏览器他的语言环境
Cache-Control: //缓存控制
Connection: //告诉浏览器,请求完是断开还是保持连接
HOET: //主机
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: //告诉浏览器,请求完是断开还是保持连接
HOET: //主机
REFRESH: //告诉客户端多久刷新一次
Location: //让网页重新定位
响应头
200:请求响应成功
202:接受
3**:
400:错误的请求
404:找不到资源
5**:服务器代码错误(502网关错误)
我们目前用来就是方便导入jar包的
Maven的核心思想:约定大于配置
Maven会规定好你该如何去编写我们的Java代码,必须要按照规范
具体下载步骤大家可以参考这篇博客maven安装及配置(详细版)
这里尤其要注意Maven版本与IDEA版本对应的问题
官网;https://maven.apache.org/
这里我保存的位置是:E:\JavaBackend\Maven\apache-maven-3.5.2
在我们的系统环境变量中
配置如下配置:
setting.xml配置文件位置
<mirror>
<id>nexus-aliyunid>
<mirrorOf>centralmirrorOf>
<name>Nexus aliyunname>
<url>http://maven.aliyun.com/nexus/content/groups/publicurl>
mirror>
本地仓库 localRepository,远程仓库
建立一个仓库:
C:\Users\86134\.m2\repository
<localRepository>E:/JavaBackend/Maven/apache-maven-3.5.2/maven_repositorylocalRepository>
启动IDEA
创建一个Mavenweb项目
4.观察maven仓库中多了哪些东西
5.idea中的maven设置(idea中经常使用自带的maven,需要手动修改,退出项目在最开始的页面可以修改默认设置)
(1)
(2)
(3)警告问题:我们访问一个网站的时候,需要指定一个文件夹名字
(4)启动测试
pom.xml是maven的核心配置文件
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>Javaweb-01-mavenartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<name>Javaweb-01-maven Maven Webappname>
<url>http://www.example.comurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.7maven.compiler.source>
<maven.compiler.target>1.7maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.11version>
<scope>testscope>
dependency>
dependencies>
<build>
<finalName>Javaweb-01-mavenfinalName>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-pluginartifactId>
<version>3.1.0version>
plugin>
<plugin>
<artifactId>maven-resources-pluginartifactId>
<version>3.0.2version>
plugin>
<plugin>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.0version>
plugin>
<plugin>
<artifactId>maven-surefire-pluginartifactId>
<version>2.22.1version>
plugin>
<plugin>
<artifactId>maven-war-pluginartifactId>
<version>3.2.2version>
plugin>
<plugin>
<artifactId>maven-install-pluginartifactId>
<version>2.5.2version>
plugin>
<plugin>
<artifactId>maven-deploy-pluginartifactId>
<version>2.8.2version>
plugin>
plugins>
pluginManagement>
build>
project>
在build中配置resources,来防止我们资源导出失败的问题
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
resource>
resources>
build>
Maven仓库
maven版本与jdk版本不相容(jdk1.8 maven3.5)
Tomcat闪退
IDEA中每次都要重复配置Maven(修改全局)
Maven项目中Tomcat无法配置
<web-app metadata-complete="true" version="4.0"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee">
web-app>
通常我们把实现了Servlet接口的java程序叫做Servlet
Servlet接口Sun公司有两个默认的实现类:HttpServlet,GenericServlet
1.构建一个普通的Maven项目,删掉里面的src目录,以后我们的学习就在这个项目里面建立Moudel;这个空的工程就题Maven主工程;
关于Maven父子工程的理解
父项目中会有
servlet-01
子项目通常会有(这里如果没有可以手动添加)
javaweb-02-servlet
com.qjd
1.0-SNAPSHOT
注:父项目中的java子项目可以直接使用
3.Maven环境优化
3.1.修改web.xml为最新的
在这里可以把最新的web.xml保存下来,下次直接拿来稍微修改就可以使用
web.xml
hello
hello
/hello
3.2.将Maven的结构搭建(java,resources)
4.编写一个Servlet程序
编写一个普通类
public class HelloServlet extends HttpServlet {
//由于get或post只是请求实现的方式不同,可以相互调用,业务逻辑都一样
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入了doGet方法");
//ServletOutputStream outputStream = resp.getOutputStream();
PrintWriter writer = resp.getWriter();//响应流
writer.println("Hello,Servlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
5.编写Servlet的映射
为什么需要映射?
我们写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的Servlet,还需要给它一个浏览器能够访问的路径
<web-app metadata-complete="true" version="4.0"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee">
<servlet>
<servlet-name>helloservlet-name>
<servlet-class>com.qjd.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
web-app>
6.配置Tomcat
注意:配置项目发布的路径就可以了
7.启动测试
(2)启动Tomcat发现在服务这个模块中显示了我们在HelloServlet中编写的“进入了doGet方法“”
Servlet是由web服务器调用,web服务器在收到浏览器的请求之后,会执行以下流程:
1.一个Servlet可以指定一个映射路径
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
2.一个Servlet可以指定多个映射路径
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello2url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello3url-pattern>
servlet-mapping>
3.一个Servlet可以指定通用映射路径
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hello/*url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/*url-pattern>
servlet-mapping>
4.指定一些后缀或者前缀等
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>*.qjdurl-pattern>
servlet-mapping>
5.优先级问题
指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求
如下启动Tomcat默认进入ErrorServlet的404,但输入http://localhost:8080/s001/hello可以进入Hello.Servlet而不是404
public class ErrorServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
PrintWriter writer = resp.getWriter();
writer.println("404
");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
<servlet>
<servlet-name>helloservlet-name>
<servlet-class>com.qjd.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
<servlet>
<servlet-name>errorservlet-name>
<servlet-class>com.qjd.servlet.ErrorServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>errorservlet-name>
<url-pattern>/*url-pattern>
servlet-mapping>
web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用
我们在这个Servlet中保存的数据可以在另一个Servlet中拿到
例子:
放置username的类
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// this.getInitParameter() 初始化参数
// this.getServletConfig() Servlet配置
// this.getServletContext() Servlet上下文
ServletContext context = this.getServletContext();
String username = "ikun";//数据
context.setAttribute("username",username);//将一个数据保存在了ServletContext中,名字为:username,值为username (= "ikun";)
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
读取username 的类
public class GetServlet extends HelloServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String username =(String) context.getAttribute("username");
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().println("名字是"+username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}
配置web.xml
<servlet>
<servlet-name>helloservlet-name>
<servlet-class>com.qjd.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>helloservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
<servlet>
<servlet-name>getcservlet-name>
<servlet-class>com.qjd.servlet.GetServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>getcservlet-name>
<url-pattern>/getcurl-pattern>
servlet-mapping>
测试访问(理解6.5开始的图):
在web.xml中配置参数
<context-param>
<param-name>urlparam-name>
<param-value>jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8param-value>
context-param>
得到参数
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
resp.getWriter().println(url);
}
在web.xml中注册
<servlet>
<servlet-name>gpservlet-name>
<servlet-class>com.qjd.servlet.ServletDemo03servlet-class>
servlet>
<servlet-mapping>
<servlet-name>gpservlet-name>
<url-pattern>/gpurl-pattern>
servlet-mapping>
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入了ServletDemo04");
ServletContext context = this.getServletContext();
context.getRequestDispatcher("/gp").forward(req,resp);//转发的请求路径并调用forward实现请求转发
}
Properties
发现都被打包到同一个路径下:classes,我们俗称这个路径为classpath(类路径)
注意:如果这里没有将properties放在resources目录下,可能会导致读取不成功,我们需要在build中配置resources , 来防止我们资源导出失败的问题
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
resource>
resources>
build>
思路:需要一个文件流
db.properties
username=root
password=123456
ServletDemo05
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入了ServletDemo05");
InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
Properties prop = new Properties();
prop.load(is);
String username = prop.getProperty("username");
String password = prop.getProperty("password");
resp.getWriter().println(username+":"+password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}
web.xml
<servlet>
<servlet-name>sd5servlet-name>
<servlet-class>com.qjd.servlet.ServletDemo05servlet-class>
servlet>
<servlet-mapping>
<servlet-name>sd5servlet-name>
<url-pattern>/sd5url-pattern>
servlet-mapping>
web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象和一个代表响应的HttpServletResponse对象
负责向浏览器发送数据的方法
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的方法
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
响应的状态码常量
200:请求响应成功
202:接受
3**:
重定向:重新到我给你的新位置去
400:错误的请求
404:找不到资源
5**:服务器代码错误(502网关错误)
以下具体的状态码了解即可,重点记住以上关于Http重点的状态码
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
(前面的练习就是)
要获取下载文件的路径
下载的文件名是什么
设置想办法让浏览器能够支持下载我们需要的东西
获取下载文件的输入流
创建缓冲区
获取OutputStream对象
将FileOutputStream写入到buffer缓冲区
使用OutputStream将缓冲区中的数据输出到客户端
代码实现
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//要获取下载文件的路径
String realPath = "E:\\JavaWeb\\Javaweb\\javaweb-02-servlet\\response\\src\\main\\resources\\3.jpg";
System.out.println("下载文件的路径"+realPath);
//下载的文件名是什么
String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
//设置想办法让浏览器能够支持Content-Disposition下载我们需要的东西,中文命名的文件用
//URLEncoder.encode(fileName,"utf-8")解决乱码问题
resp.setHeader("Content-Disposition","attachment; filename="+ URLEncoder.encode(fileName,"utf-8"));
//获取下载文件的输入流
FileInputStream in = new FileInputStream(realPath);
//创建缓冲区
int len = 0;
byte[] buffer = new byte[1024];
//获取OutputStream对象
ServletOutputStream out = resp.getOutputStream();
//将FileOutputStream写入到buffer缓冲区
//使用OutputStream将缓冲区中的数据输出到客户端
while ((len = in.read(buffer))>0){
out.write(buffer,0,len);
}
in.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
验证怎么来的?
前端实现
后端实现,需要用到Java的图片类,生成一个图片
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//如何让浏览器3秒自动刷新一次
resp.setHeader("refresh","3");
//在内存中创建一个图片
BufferedImage bufferedImage = new BufferedImage(80,60,BufferedImage.TYPE_INT_RGB);
//得到图片
Graphics2D graphics =(Graphics2D) bufferedImage.getGraphics();//画笔
//设置图片的背景颜色
graphics.setColor(Color.BLUE);
graphics.fillRect(0,0,80,60);
//给图片写数据
graphics.setColor(Color.CYAN);
graphics.setFont(new Font(null,Font.BOLD,20));
graphics.drawString(makeNum(),0,20);
//告诉浏览器这个请求用图片的方式打开
resp.setContentType("image/jpg");
//网站存在缓存
resp.setDateHeader("expires",-1);
resp.setHeader("cache-control","no-cache");
//把图片写给浏览器
ImageIO.write(bufferedImage,"jpg", resp.getOutputStream());
}
//生成随机数
private String makeNum(){
Random random = new Random();
String s = random.nextInt(9999999) + "";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 7-s.length() ; i++) {
sb.append("0");
}
String s1 = sb.toString() + s;
return s;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
测试访问:每5秒钟刷新生成随机数(这个页面有点丑,大家请见谅)
一个web资源收到客户端请求后,它会通知客户端去访问另一个web资源,这个过程叫做重定向
常见场景:
用户登录
void sendRedirect(String var1) throws IOException;
测试:
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//重定向
resp.sendRedirect("/r/img");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
测试访问
注:网页404时代表代码没有问题,只是路径出错了
jsp测试
index.jsp
Hello World!
<%--这里提交的路径需要寻找到项目的路径--%>
<%--pageContext.request.contextPath代表当前的项目--%>
<%@page contentType="text/html; ISO-8859-1" pageEncoding="UTF-8" %>
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
Success
RequestTest
public class RequestTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入这个请求了");
//处理请求
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username+":"+password);
//重定向时候一定要注意,路径问题,否则404
resp.sendRedirect("/r/success.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,Http请求中的所有信息会被封装到HttpServletRequest,
通过这个HttpServletRequest的方法,获得客户端的所有信息
获取参数,请求转发
代码实现
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobby");
System.out.println("=====================================");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbies));
System.out.println("=====================================");
//通过请求转发
//注意:这里的 / 代表当前的web应用(转发不用写/ 重定向写/)
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
思考题:请你聊聊重定向和转发的区别
相同点:页面都会实现跳转
不同点:
会话:用户打开了一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话
有状态会话:记录了一些信息
大家在浏览网站的过程中有没有思考过这样一个问题,一个网站怎么证明客户访问过呢?
客户端 服务端
1.服务端给客户端一个信件,客户端下次访问服务端带上信件就可以了 : cookie
2.服务器登记客户已经来过了,下次访问的时候直接匹配登记过的客户 ; session
3.大家可以先看一下这张图,下面对Cookie与Session的讲解就是围绕这张图展开的,最后会对这张图进行详细的讲解
大部分的网站:网站登录之后,下次就不用再登录了,第二次访问直接就可以登录进去
1.cookie中常用属性的解释
2.Cookie的Http传输
Cookie的Http传输 我们会在接下来的例子中进行抓包展示
3.Cookie的生命周期
cookie有2种存储方式,一种是会话性,一种是持久性
cookie我们是可以进行设置的,我们可以人为设置cookie的有效时间,什么时候创建,什么时候销毀。
4.cookie 使用的常见方法
java中Cookie对象的方法进行讲解
HttpServletRequest和Http ServletResponse对Cookie进行操作的常见方法
从请求中拿到cookie信息
服务端响应给客户端cookie
//保存用户上一次访问的时间
public class CookieDemon01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//服务器告诉你你来的时间,把这个时间封装为一个信件,你下次来,我就知道你来了
//解决中文乱码,这里解决乱码需要根据实际情况自己进行调试
req.setCharacterEncoding("gbk");
resp.setCharacterEncoding("gbk");
PrintWriter out = resp.getWriter();
//cookie,服务器端从客户端获取
Cookie[] cookies = req.getCookies();//返回数组说明cookie可能存在多个
//判断cookie是否存在
if (cookies != null) {
//如果存在怎么办
out.write("您上一次访问的时间是:");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
//获取cookie的名字
if( cookie.getName().equals("LastLogTime")){
//获取cookie的值
long lastLogTime = Long.parseLong(cookie.getValue());
Date date = new Date(lastLogTime);
out.write(date.toLocaleString());
}
}
}else {
out.write("这是您第一次访问本站");
}
//服务器给客户端响应一个cookie
Cookie cookie = new Cookie("LastLogTime", System.currentTimeMillis()+"");
//设置cookie有效期为一天(浏览器关闭cookie还存在一天)
cookie.setMaxAge(24*60*60);
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
3.注册Servlet
<servlet>
<servlet-name>CookieDemo01servlet-name>
<servlet-class>com.qid.servlet.CookieDemon01servlet-class>
servlet>
<servlet-mapping>
<servlet-name>CookieDemo01servlet-name>
<url-pattern>/c1url-pattern>
4.测试访问
注:cookie一般会保存在本地的用户目录下AppData ,浏览器只会携带在当前请求的URL中包含了改cookie中path值的cookie
了解一下:
一个网站cookie是否存在上限?
不设置有效期,关闭浏览器,自动失效
设置有效期为0
public class CookieDemon02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建一个cookie.名字必须和要删除的名字一致
Cookie cookie = new Cookie("LastLogTime", System.currentTimeMillis()+"");
//有限期为0
cookie.setMaxAge(0);
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
这里再用上面记录访问时间的例子说一下传输中文数据的问题:
如果一直中文传输数据乱码,可以尝试以下代码:
编码解码
//编码
Cookie cookie = new Cookie("name", URLEncoder.encode("张三","utf-8"));
//解码
out.write( URLDecoder.decode(cookie.getValue(),"utf-8"));
整体代码:
//中文数据传递
public class CookieDemon03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决中文乱码
req.setCharacterEncoding("utf-16");
resp.setCharacterEncoding("utf-16");
//cookie,服务器端从客户端获取
Cookie[] cookies = req.getCookies();//返回数组说明cookie可能存在多个
PrintWriter out = resp.getWriter();
//判断cookie是否存在
if (cookies != null) {
//如果存在怎么办
out.write("您的名字是:");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
//获取cookie的名字
if( cookie.getName().equals("name")){
//获取cookie的值
System.out.println(cookie.getValue());
//解码
out.write( URLDecoder.decode(cookie.getValue(),"utf-8"));
}
}
}else {
out.write("这是您第一次访问本站");
}
//编码
Cookie cookie = new Cookie("name", URLEncoder.encode("张三","utf-8"));
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
1.什么是session
2.Session的常用方法
3.Session的生命周期
手动注销:session.invalidate();
自动注销:在web.xml 中配置
<session-config>
<session-timeout>15session-timeout>
session-config>
4.session应用:
下面这张图是服务器登记session,客户端用sessionID访问的流程图
1.保存数据:
public class Person {
private String name;
private int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class SessionDemon01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码问题
req.setCharacterEncoding("gbk");
resp.setCharacterEncoding("gbk");
resp.setContentType("text/html;charset = gbk");
//得到Session
HttpSession session = req.getSession();
//给Session中存东西
session.setAttribute("name",new Person("李四",18));
//获取session的id
String sessionId = session.getId();
//判断session是不是新创建的
if(session.isNew()){
resp.getWriter().write("session创建成功,id:"+sessionId);
}else {
resp.getWriter().write("session已经在服务器中存在了,id:"+sessionId);
}
//Session创建的时候做了什么事情
// Cookie cookie = new Cookie("JSESSIONID",sessionId);
// resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
public class SessionDemon02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码问题
req.setCharacterEncoding("gbk");
resp.setCharacterEncoding("gbk");
resp.setContentType("text/html;charset = gbk");
//得到Session
HttpSession session = req.getSession();
Person person = (Person) session.getAttribute("name");
resp.getWriter().write(person.toString());
System.out.println(person.toString());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2.会话过期
手动
public class SessionDemon03 extends HttpServlet {
//注销,移除
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
session.removeAttribute("name");
//手动注销session
session.invalidate();//一旦注销会重新产生一个sessionId
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
自动
<session-config>
<session-timeout>15session-timeout>
session-config>
思考 : Session和Cookie的区别
①cookie可以存储在浏览器或者本地,Session只能存在服务器
②session能够存储任意的java对象,cookie 只能存储String 类型的对象
③Session比tCookie更具有安全性(Cookie有安全隐患,通过拦截或本地文件找得到你的cookie后可以进行攻击)
④Session占用服务器性能,Session过多,增加服务器压力
⑤单个Cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie,Session是没有大小限制和服务器的
JavaServletPages: Java服务器端页面,也和Serlvet一样,用于动态web技术
最大的特点:
思路:JSP到底是怎么执行的
代码层面没有任何问题
服务器内部工作
Tomcat中有一个work目录:
idea中使用Tomcat会在idea的Tomcat中产生一个work目录
发现页面变成了Java程序
JSP最终也会被转成一个java类
JSP本质上就是一个Servlet
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问servlet
1.判断请求
2.内置一些对象
final javax.servlet.jsp.Pagecontext pagecontext;
//页面上下文
javax.servlet.http.Httpsession session null;
//session
final javax.servlet.Servletcontext application;
//applicationContext
final javax.servlet.servletconfig config;
//config
javax.servlet.jsp.Jspwriter out null;
//out
final java.lang.object page this;
//page:当前
HttpservletRequest request
//请求
HttpservletResponse response
//响应
3.输出页面前增加的代码
response.setcontentType("text/htm1");
//设望响应的页面类型
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;
以上的这些对象我们可以在JSP页面上直接使用
在JSP页面中,只要是Java代码就会原封不动的输出
如果是HTML代码就会被转换为:
out.write("\n");
这样的格式输出到前端
任何语言都有自己的语法,Java中有;JSP作为Java技术的一种应用,他拥有一些自己的扩充语法,Java所有的语法都支持
<%--JSP表达式
作用:用来将程序的输出,输出到客户端
<%= new 变量或者表达式%>
--%>
<%= new java.util.Date()%>
<%--jsp 脚本片段 --%>
<%
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum+=i;
}
out.println("Sum="+sum+"
");
%>
<%
int x = 10;
out.println(x);
%>
这是一个jsp文档
<%
int y = 20;
out.println(2);
%>
<%--在代码中嵌入HTML元素 --%>
<%
for (int i = 0; i < 5; i++) {
%>
hello world <%=i%>
<%
}
%>
<%!
static {
System.out.println("Loading Servlet!");
}
private int global = 0;
public void qjd(){
System.out.println("进入了方法qjd");
}
%>
JSP声明:(<%!%>)会被编译到JSP生成的Java类中!其他的(<%%>)就会被生成到jspService 方法中
在JSP中嵌入Java代码
<%----%> 注释
<%%> 片段
<%=%> 表达式输出一个值
<%!%> 全局
${} el表达式
JSP的注释(<%----%>)不会在客户端显示,HTML( )就会
<%@page args...%>
<%@ include file="" %>
1.定制错误页面<%@page args…%>
jsp2.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--定制错误页面(可以在这个jsp中引入也可以在web.xml 中配置)--%>
<%@ page errorPage="error/500.jsp" %>
Title
<%
int x = 1/0;
%>
如果在web.xml中配置
<error-page>
<error-code>500error-code>
<location>/error/500.jsplocation>
error-page>
500.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
测试
404错误:
2.共用部分<%@ include file=“” %>
Title
<%--方法一@ include会将三个页面合三为一--%>
<%@ include file="common/header.jsp" %>
网页主体
<%@ include file="common/footer.jsp" %>
<%--方法二jsp标签
jsp:include:拼接页面,本质还是3个
--%>
网页主体
测试
重点对象理解:
request:客户端向服务器发送请求,产生的数据,用户看完就没用了,比如:新闻,用户看完没用的!
session:客户端向服务器发送请求,产生的数据,用户用完一会还有用,比如:购物车;
application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如:聊天数
据;
具体实现:
pageContextDemon01.jsp(在一个页面取值)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--内置对象--%>
<%
pageContext.setAttribute("name1","张三1");//保存的数据只在一个页面中有效
request.setAttribute("name2","张三2");//保存的数据只在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name3","张三3");//保存的数据只在一次会话中有效,打开到关闭浏览器
application.setAttribute("name4","张三4");//保存的数据在服务器中有效,打开到关闭服务器
%>
<%
//通过pageContext寻找的方式取出我们保存的值
//从底层到高层(作用域): page->request->session->application->找不到
//JVM:双亲委派机制 应用->扩展类->rt.jar
String name1 =(String) pageContext.findAttribute("name1");
String name2 =(String) pageContext.findAttribute("name2");
String name3 =(String) pageContext.findAttribute("name3");
String name4 =(String) pageContext.findAttribute("name4");
String name5 =(String) pageContext.findAttribute("name5");//不存在
%>
<%--使用el表达式输出 ${}--%>
取出的值为:
${name1}
${name2}
${name3}
${name4}
${name5}
pageDemon02.jsp(在另一个页面取值)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--在另一个页面取pageContextDemon01.jsp中的值只能取到3和4
如果 request请求转发就可以取出来
--%>
<%
//通过pageContext寻找的方式取出我们保存的值
//从底层到高层(作用域)
String name1 =(String) pageContext.findAttribute("name1");
String name2 =(String) pageContext.findAttribute("name2");
String name3 =(String) pageContext.findAttribute("name3");
String name4 =(String) pageContext.findAttribute("name4");
String name5 =(String) pageContext.findAttribute("name5");//不存在
%>
<%--使用el表达式输出 ${}--%>
取出的值为:
${name1}
${name2}
${name3}
${name4}
${name5}
手动修改作用域与请求转发
//手动修改作用域,第三个参数为作用域
pageContext.setAttribute("hello","hello1",PageContext.SESSION_SCOPE);//等价于 session.setAttribute("hello","hello1");
<%
//请求转发
pageContext.forward("/index.jsp");
//等价于 request.getRequestDispatcher("/index.jsp").forward(request,response);
%>
<dependency>
<groupId>javax.servlet.jsp.jstlgroupId>
<artifactId>jstl-apiartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>taglibsgroupId>
<artifactId>standardartifactId>
<version>1.1.2version>
dependency>
EL表达式:${}
JSP标签:
<%--jsp:include --%>
1
<%--转发时添加数据--%>
<%--取出参数--%>
名字:<%=request.getParameter("name")%>
年龄:<%=request.getParameter("age")%>
JSTL表达式:
JSTL标签库的使用就是为了弥补html标签的不足;它自定义许多标签,可以供我们使用,标签的功能和Java代码一样
格式化标签
SQL标签
XML标签
JSTL标签库使用步骤:
c:if:
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
Title
if测试
<%--判断如果提交的用户名是管理员则登录成功--%>
c:choose:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入jstl核心标签库--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
Title
<%--定义一个标量scroe,值为99--%>
你的成绩为优秀
你的成绩为良好
你的成绩为一般
你的成绩为不及格
c:forEach:
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入jstl核心标签库--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
Title
<%
ArrayList people = new ArrayList<>();
people.add(0,"张三");
people.add(1,"李四");
people.add(2,"王五");
people.add(3,"赵六");
people.add(4,"田七");
request.setAttribute("list",people);
%>
<%--var:每一次遍历出来的变量
items:要遍历的对象
begin:开始
end:结束
step:步长
--%>
实体类
JavaBean有特定的写法:
一般用来和数据库字段做映射,ORM;
ORM:对象关系映射
<%@ page import="com.qjd.pojo.People" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%
// People people = new People();
// people.setId(001);
// people.setAddress("");
%>
姓名:
什么是MVC:Model View Controller (模型,视图,控制器)
用户直接访问控制层,控制层就可以直接操作数据库
servlet--CRUD--数据库
弊端:程序十分臃肿,不利于维护
servlet的代码中!处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码
架构:设有什么是加一层解决不了的!
程序调用
JDBC
Mysql oracle sqlserver ...
Model:
View:
Controller:
登录--->接收用户的登录请求--->处理用户的请求(获取用户登录的参数,username,password)--->交给业务层处理登录业务(判断用户名密码是否正确)--->Dao层查询用户名和密码是否正确--->数据库
Filter:过滤器,用来过滤网站的数据;
Filter开发步骤:
CharacterEncodingFilter:
public class CharacterEncodingFilter implements Filter {
//初始化 web服务器启动就初始化了
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharacterEncodingFilter初始化");
}
//Chain:链
/*
* 1.过滤中的所有代码,在过滤特定请求的时候都会执行
* 2.必须要让过滤器继续通行filterChain.doFilter(servletRequest,servletResponse);
* */
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html;charset=utf-8");
System.out.println("CharacterEncodingFilter执行前...");
filterChain.doFilter(servletRequest,servletResponse);//让我们的请求继续走,如果不添加,程序到这里就被拦截停止
System.out.println("CharacterEncodingFilter执行后...");
}
//销毁 web服务器关闭的时候销毁
@Override
public void destroy() {
System.out.println("CharacterEncodingFilter销毁");
}
}
web.xml:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>ShowServletservlet-name>
<servlet-class>com.qjd.servlet.ShowServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>ShowServletservlet-name>
<url-pattern>/servlet/showurl-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>ShowServletservlet-name>
<url-pattern>/showurl-pattern>
servlet-mapping>
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>com.qjd.filter.CharacterEncodingFilterfilter-class>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/servlet/*url-pattern>
filter-mapping>
web-app>
ShowServlet:
public class ShowServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// resp.setCharacterEncoding("utf-8");
// req.setCharacterEncoding("utf-8");
resp.getWriter().write("你好啊");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
实现一个监听器的接口:(有N种)
编写一个监听器(实现监听器的接口)
//统计网站在线人数:统计session
public class OnlineCountListener implements HttpSessionListener{
// 创建session监听
// 一旦创建Session就会触发一次这个事件
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println(se.getSession().getId());
ServletContext ctx = se.getSession().getServletContext();
Integer onlineCount =(Integer) ctx.getAttribute("OnlineCount");
if(onlineCount == null){
onlineCount = new Integer(1);
}else {
int count = onlineCount.intValue();
onlineCount = new Integer(count+1);
}
ctx.setAttribute("OnlineCount",onlineCount);
}
// 销毁session监听
// 一旦销毁Session就会触发一次这个事件
@Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext ctx = se.getSession().getServletContext();
Integer onlineCount =(Integer) ctx.getAttribute("OnlineCount");
if(onlineCount == null){
onlineCount = new Integer(0);
}else {
int count = onlineCount.intValue();
onlineCount = new Integer(count-1);
}
ctx.setAttribute("OnlineCount",onlineCount);
}
/*
* session 销毁
* 1.手动销毁 se.getSession().invalidate();
* 2.自动销毁 (在web.xml中配置)
*
1
* */
}
配置监听器(web.xml中注册)
<listener>
<listener-class>com.qjd.listener.OnlineCountListenerlistener-class>
listener>
根据情况是否使用
测试结果
监听关闭事件(GUI)
public class TestPanel {
public static void main(String[] args) {
Frame frame = new Frame("好好学习");//新建一个窗口
Panel panel = new Panel(null);//面板
frame.setLayout(null);//设置窗体的布局
frame.setBounds(300,300,500,500);
frame.setBackground(new Color(0, 255, 34));
panel.setBounds(50,50,300,300);
panel.setBackground(new Color(128, 0, 255));
frame.add(panel);
frame.setVisible(true);
//监听关闭事件
frame.addWindowListener(new WindowListener() {
@Override
public void windowOpened(WindowEvent e) {
System.out.println("打开");
}
@Override
public void windowClosing(WindowEvent e) {
System.out.println("正在关闭");
System.exit(0);//0是正常终止。1是非正常终止
}
@Override
public void windowClosed(WindowEvent e) {
System.out.println("已关闭");
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowActivated(WindowEvent e) {
System.out.println("激活");
}
@Override
public void windowDeactivated(WindowEvent e) {
System.out.println("未激活");
}
});
}
}
用户登录才能进入主页,用户注销后就不能进入主页(必须通过登录才能访问登录成功主页,通过直接访问登录成功主页不能进入)
用户登录之后,向Session中放入用户的数据
进入主页的时候要判断用户是否已经登录(在过滤器中实现)
public class SysFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//ServletRequest HttpServlet
HttpServletRequest request1 = (HttpServletRequest) servletRequest;
HttpServletResponse response1 = (HttpServletResponse) servletResponse;
String user_session = (String) request1.getSession().getAttribute(Constant.USER_SESSION);
if(user_session == null){
response1.sendRedirect("/error.jsp");
}
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
整体步骤:
什么是JDBC:Java DataBase Connection (Java连接数据库)
连接数据库需要jar包的支持:
JDBC 固定步骤:
1.加载驱动
2.连接数据库,代表数据库
3.向数据库发送SQL的对象Statement : CRUD
4.编写SQL (根据业务,不同的SQL)
5.执行SQL
6.关闭连接(先开的后关)
实验环境搭建:
数据库信息
导入数据库依赖
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.29version>
dependency>
IDEA中连接数据库
JDBC六步
public class TestJDBC {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//配置信息
//解决中文乱码问题useUnicode=true&characterEncoding=utf-8
String url = "jdbc:mysql://localhost:3306/jdbc? useUnicode=true&characterEncoding=utf-8&useSSL=true";
String username = "root";
String password = "123456789";
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.连接数据库,代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//3.向数据库发送SQL的对象 Statement:CRUD
Statement statement = connection.createStatement();
// PreparedStatement安全,可以防止sql注入(预编译)
//4.编写sql
String sql = "select *from jdbc.users";
//5.执行查询sql,返回一个ResultSet结果集
ResultSet rs = statement.executeQuery(sql);
while (rs.next()){
System.out.println("id="+rs.getObject("id"));
System.out.println("name="+rs.getObject("name"));
System.out.println("password="+rs.getObject("password"));
System.out.println("email="+rs.getObject("email"));
System.out.println("birthday="+rs.getObject("birthday"));
}
//6.关闭连接,释放资源(先创建的后关闭)
rs.close();
statement.close();
connection.close();
}
}
使用预编译防止sql注入
public class TestJDBC2 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//配置信息
//解决中文乱码问题useUnicode=true&characterEncoding=utf-8
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=true";
String username = "root";
String password = "123456789";
//1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.连接数据库,代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//3.编写sql
String sql = "insert into jdbc.users(id, name, password, email, birthday) VALUES (?,?,?,?,?);";
//4.预编译 PreparedStatement安全,可以防止sql注入(预编译)
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,4);//第一个占位符?的值为1
preparedStatement.setString(2,"赵六");//第二个占位符?的值为赵六
preparedStatement.setString(3,"523456");//第三个占位符?的值为123456
preparedStatement.setString(4,"[email protected]");//第四个占位符?的值为[email protected]
preparedStatement.setDate(5,new Date(System.currentTimeMillis()));//第五个占位符?的值为当前年月日
//5.执行查询sql
int i = preparedStatement.executeUpdate();
System.out.println(i);
//6.关闭连接,释放资源(先创建的后关闭)
preparedStatement.close();
connection.close();
}
}
要么都成功,要么都失败!
ACID原则:保证数据的安全
开启事务
事务提交commit
事务回滚rollback
关闭事务
junit单元测试
依赖
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
<scope>testscope>
dependency>
简单使用:
@Test注解只有在方法上有效,只要加了这个注解的方法就可以直接运行
搭建测试事务环境:
count表:
public class TestJDBC3 {
@Test
public void test() {
//配置信息
//解决中文乱码问题useUnicode=true&characterEncoding=utf-8
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=true";
String username = "root";
String password = "123456789";
Connection connection = null;
//1.加载驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//2.连接数据库,代表数据库
connection = DriverManager.getConnection(url, username, password);
//3.通知数据库开启事务(false是开启)
connection.setAutoCommit(false);
String sql = "update jdbc.account set money = money-100 where name = 'a';";
connection.prepareStatement(sql).executeUpdate();
//制造错误
int i=1/0;
String sql2 = "update jdbc.account set money = money+100 where name = 'b';";
connection.prepareStatement(sql2).executeUpdate();
connection.commit();//以上两条sql都提交成功了就提交事务
System.out.println("提交成功!");
} catch (Exception e) {
try {
//如果出现异常,就通知数据库回滚事务
connection.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
e.printStackTrace();
}finally {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
SMBMS项目是一个用JavaWeb编写的超市管理项目,大家可以在下面这个网站下载到原始项目
SMBMS项目源码
对于这个超市管理项目,大家可以结合前面学习的知识分析代码,遇到不会的可以标记,最后再看狂神的视频讲解SMBMS项目
我相信大家经过这个项目大家会对JavaWeb有更深的理解
【文件上传的注意事项】
1.为保证服务器安全,上传文件应该放在深无法直接访问的目录下,比如放于WEB-NF目录下。
2.为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
3.要限制上传文件的最大值。
4.可以限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。
【需要用到的类详解】
ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个Fileltem对象,在使用ServletFileUpload对象解析请求时需要DiskFileltemFactory对象。所以,我们需要在进行解析工作前构造好DiskFileltemFactory>对象,通过ServletFileUpload对象的构造方法或setFileltemFactory()方法设置ServletFileUpload?对象的fileltemFactory属性。
文件上传源码
/**
* Servlet implementation class FileSerlvet
*/
public class FileSerlvet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
// response.getWriter().append("Served at: ").append(request.getContextPath());
// 判断上传的文件普通表单还是带文件的表单
if (!ServletFileUpload.isMultipartContent(request)) {
return;//终止方法运行,说明这是一个普通的表单,直接返回
}
//创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访间上传的文件;
String uploadPath =this.getServletContext().getRealPath("/WEB-INF/upload");
File uploadFile = new File(uploadPath);
if (!uploadFile.exists()){
uploadFile.mkdir(); //创建这个月录
}
// 创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件
String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
File file = new File(tmpPath);
if (!file.exists()) {
file.mkdir();//创建临时目录
}
// 处理上传的文件,一般都需要通过流来获取,我们可以使用 request, getInputstream(),原生态的文件上传流获取,十分麻烦
// 但是我们都建议使用 Apache的文件上传组件来实现, common-fileupload,它需要旅 commons-io组件;
try {
// 创建DiskFileItemFactory对象,处理文件路径或者大小限制
DiskFileItemFactory factory = getDiskFileItemFactory(file);
/*
* //通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件 factory.setSizeThreshold(1024 *
* 1024); //缓存区大小为1M factory.setRepository (file);//临时目录的保存目录,需要一个File
*/
// 2、获取ServletFileUpload
ServletFileUpload upload = getServletFileUpload(factory);
// 3、处理上传文件
// 把前端请求解析,封装成FileItem对象,需要从ServletFileUpload对象中获取
String msg = uploadParseRequest(upload, request, uploadPath);
// Servlet请求转发消息
System.out.println(msg);
if(msg == "文件上传成功!") {
// Servlet请求转发消息
request.setAttribute("msg",msg);
request.getRequestDispatcher("info.jsp").forward(request, response);
}else {
msg ="请上传文件";
request.setAttribute("msg",msg);
request.getRequestDispatcher("info.jsp").forward(request, response);
}
} catch (FileUploadException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
public static DiskFileItemFactory getDiskFileItemFactory(File file) {
DiskFileItemFactory factory = new DiskFileItemFactory();
// 通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件中;
factory.setSizeThreshold(1024 * 1024);// 缓冲区大小为1M
factory.setRepository(file);// 临时目录的保存目录,需要一个file
return factory;
}
public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
ServletFileUpload upload = new ServletFileUpload(factory);
// 监听长传进度
upload.setProgressListener(new ProgressListener() {
// pBYtesRead:已读取到的文件大小
// pContextLength:文件大小
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("总大小:" + pContentLength + "已上传:" + pBytesRead);
}
});
// 处理乱码问题
upload.setHeaderEncoding("UTF-8");
// 设置单个文件的最大值
upload.setFileSizeMax(1024 * 1024 * 10);
// 设置总共能够上传文件的大小
// 1024 = 1kb * 1024 = 1M * 10 = 10м
return upload;
}
public static String uploadParseRequest(ServletFileUpload upload, HttpServletRequest request, String uploadPath)
throws FileUploadException, IOException {
String msg = "";
// 把前端请求解析,封装成FileItem对象
List<FileItem> fileItems = upload.parseRequest(request);
for (FileItem fileItem : fileItems) {
if (fileItem.isFormField()) {// 判断上传的文件是普通的表单还是带文件的表单
// getFieldName指的是前端表单控件的name;
String name = fileItem.getFieldName();
String value = fileItem.getString("UTF-8"); // 处理乱码
System.out.println(name + ": " + value);
} else {// 判断它是上传的文件
// ============处理文件==============
// 拿到文件名
String uploadFileName = fileItem.getName();
System.out.println("上传的文件名: " + uploadFileName);
if (uploadFileName.trim().equals("") || uploadFileName == null) {
continue;
}
// 获得上传的文件名/images/girl/paojie.png
String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
// 获得文件的后缀名
String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
/*
* 如果文件后缀名fileExtName不是我们所需要的 就直按return.不处理,告诉用户文件类型不对。
*/
System.out.println("文件信息[件名: " + fileName + " ---文件类型" + fileExtName + "]");
// 可以使用UID(唯一识别的通用码),保证文件名唯
// 0UID. randomUUID(),随机生一个唯一识别的通用码;
String uuidPath = UUID.randomUUID().toString();
// ================处理文件完毕==============
// 存到哪? uploadPath
// 文件真实存在的路径realPath
String realPath = uploadPath + "/" + uuidPath;
// 给每个文件创建一个对应的文件夹
File realPathFile = new File(realPath);
if (!realPathFile.exists()) {
realPathFile.mkdir();
}
// ==============存放地址完毕==============
// 获得文件上传的流
InputStream inputStream = fileItem.getInputStream();
// 创建一个文件输出流
// realPath =真实的文件夹;
// 差了一个文件;加上翰出文件的名产"/"+uuidFileName
FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);
// 创建一个缓冲区
byte[] buffer = new byte[1024 * 1024];
// 判断是否读取完毕
int len = 0;
// 如果大于0说明还存在数据;
while ((len = inputStream.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
// 关闭流
fos.close();
inputStream.close();
msg = "文件上传成功!";
fileItem.delete(); // 上传成功,清除临时文件
//=============文件传输完成=============
}
}
return msg;
}
}
<servlet>
<servlet-name>uploadservlet-name>
<servlet-class>com.qjd.FileSerlvetservlet-class>
servlet>
<servlet-mapping>
<servlet-name>uploadservlet-name>
<url-pattern>/upload.dourl-pattern>
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.4version>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.6version>
dependency>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--
GET:上传文件大小有限制
POST:上传文件大小没有限制
${pageContext.request.contextPath}
--%>
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
Insert title here
<%=request.getAttribute("msg")%>
到这里JavaWeb绝大部分的知识就结束了,但是我们的学习还没有结束哦,大家要掌握JavaWeb就要多练习几个JavaWeb的实战项目,在项目中成长并深入理解JavaWeb,最后希望大家都得到自己满意的结果(◍•ᴗ•◍)
大家觉得JavaWeb这篇文章还可以的话可以点个赞啊๐•ᴗ•๐