JavaWeb
Java Web
基本概念
web开发:
-
web,网页的意思,www.baidu.com
-
静态web
-
html,css
-
提供给所有人看的数据始终不会发生变化
-
-
动态web
-
淘宝....几乎是所有的网站
-
提供给所有人看的数据始终会发生变化,每个人在不同的时间,不同的地点看得到数据各不相同!
-
技术栈:Servlet/JSP,ASP,PHP
-
在Java中,动态web资源开发的技术统称为JavaWeb
Web应用程序
web应用程序:可以提供浏览器访问的程序;
-
a.html、b.html....多个web资源,这些web资源可以被外界访问,对外界提供服务;
-
能访问到的任何一个页面或者资源,都存在于这个世界的某一个角落的计算机上。
-
URL
-
这个统一的web资源会被放在同一个文件夹下,web应用程序-》Tomcat:服务器
-
一个web应用由多部分组成(静态web,动态web)
-
html,css,js
-
jsp,servlet
-
Java程序
-
jar包
-
配置文件(Properties)
-
web应用程序编写完毕后,若想提供给外界访问:需要一个服务器来统一管理;
静态web
-
*.htm, *.html,这些都是网页的后缀,如果服务器上一直存在这些东西,我们就可以直接进行读取,通过网络
- 正在上传…重新上传取消
-
静态web存在的缺点
-
Web页面无法动态更新,所有用户看到都是同一个页面
-
轮播图,点击特效:伪动态
-
JavaScript【实际开发中,它用的最多】
-
VBScript
-
-
它无法和数据库交互(数据无法持久化,用户无法交互)
-
动态web
页面会动态展示:web的页面展示的效果因人而异
正在上传…重新上传取消
缺点
-
加入服务器的动态web资源出现了错误,我们需要重新编写我们的后台程序,重新发布;
-
停机维护
-
优点:
-
Web页面可以动态更新,所有用户看到都不是同一个页面
-
他可以与数据库交互(数据持久化:注册,商品信息,用户信息)
正在上传…重新上传取消
web服务器
技术讲解
ASP:
-
微软:国内最早流行的就是ASP
-
在HTML中嵌入了VB的脚本,ASP+COM
-
在ASP开发中,基本一个页面都有几千行的业务,页面极其混乱
-
维护成本高
-
window服务器用的是IIS
<% System.out.println("hellow") %>
php
-
PHP开发速度很快,功能很强大,跨平台,代码简单(70%,wp)
-
缺点:无法承载大访问的情况(局限性)
-
JSP/Servlet
B/S:浏览和服务器
C/S:客服端和服务器
-
sun公司主推的B/S架构
-
基于Java语言的(所有的大公司,或者一些开源的组件,都是用java写的)
-
可以承载三高问题带来的影响;
-
语法想ASP,ASP-->JSP,加强市场强度;
.......
web服务器讲解
服务器是一种被动的而操作,用来处理用户的一些请求和给用户一些响应信息;
IIS
微软的;ASP...,Windows中自带的
Tomcat
面向百度编程
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,他是最佳的选择
诀窍是,当配置正确时,Apache 为HTML页面服务,而Tomcat 实际上运行JSP 页面和Servlet。另外,Tomcat和IIS等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。不过,Tomcat处理静态HTML的能力不如Apache服务器。Tomcat最新版本为10.0.14。
Tomcat
安装tomcat
tomcat官网Apache Tomcat® - Apache Tomcat 10 Software Downloads
Tomcat启动和配置
可能遇到的问题:
-
Java环境变量没有配置
-
闪退问题:需要配置兼容性
-
乱码问题:配置文件中设置
配置
可以配置启动的端口号
-
tomcat的默认端口号为:8080
-
mysql:3306
-
http:80
-
https:443
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
可以配置主机的名称
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
高难度面试题
请你谈谈网站是如何进行访问的!
1.输入一个域名;回车
2.检查本机的C:Windows\System32\drivers\etc\hosts配置文件下有没有这个域名映射;
1.有直接返回对应的ip地址,这个地址中,有我们需要访问的web程序,可以直接访问
127.0.0.1 www.qinjiang.com
2.没有:去DNS服务器找,找到的话就返回,找不到就返回找不到
发布一个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
什么是HTTP
HTTP(超文本传输协议)是一个简单的请求-响应协议,他通常运行在tcp之上
-
文本:html,字符串,~.....
-
超文本:图片,音乐,视频,定位,地图,超文本(Hyper text)是用超链接的方法,将各种不同空间的文字信息组织在一起的网状文本
-
80(默认端口)
Https:安全的
-
443(端口)
两个时代
-
http1.0
-
HTTP/1.0:客户端可以与web服务器连接后,只能获得一个web资源,断开连接
-
-
http2.0
-
HTTP/1.1:客户端可以与web服务器连接后,可以获得多个web资源
-
Http请求
-
客户端---发请求(Request)---服务器
百度:
Request URL: https://www.baidu.com/ 请求地址 Request Method: GET get方法/post方法 Status Code: 200 OK 状态码:200 Remote(远程) Address: 110.242.68.3:443 远程地址 和端口号
Accept: text/html Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 语言环境zh-CN表示中文 Connection: keep-alive(保持连接) Host(主机): www.baidu.com
请求行
-
请求行中的请求方式:GET
-
请求方式:Get,Post,HEAD,DELETE,PUT,TRACT
-
get:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址显示数据内容,不安全,但高效
-
post:请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效
-
消息头
Accept:告诉浏览器,他所支持的数据类型 Accept-Encoding:支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1 Accept-Language: 告诉浏览器,它的语言环境 Connection:告诉浏览器,请求完成是断开还是保持连接 Host(主机)
Http响应
-
服务器---响应---客户端
百度:
Cache-Control:private 缓冲控制 Connection:Keep-Alive 连接 Content-Encoding:gzip 编码 Content-Type:text/html 类型
响应体
Accept:告诉浏览器,他所支持的数据类型 Accept-Encoding:支持哪种编码格式 GBK UTF-8 GB2312 ISO8859-1 Accept-Language: 告诉浏览器,它的语言环境 Cache-Control:缓存控制 Connection:告诉浏览器,请求完成是断开还是保持连接 Host(主机) Refresh:告诉客户端,多久刷新一次; Location:让网页重新定位
响应状态码
200:请求响应成功200
3xx:请求重定向
-
重定向:你重新到我给你新位置去
4xx:找不到资源404
-
资源不存在;
5xx:服务器代码错误 500 502:网关错误
常见面试题:
当你的浏览器中地址栏输入地址并回车的一瞬间到页面能够展示回来,经历了什么?
Maven
我们为什么学习这个技术?
-
在Javaweb开发中,需要使用大量的jar包,我们手动去导入;
-
如何能够让一个东西自动帮我导入和配置这个jar包。
由此,Maven诞生了!
Maven项目架构工具
我们目前用来导入jar包
Maven的核心思想:约定大于配置
-
有约束不要去违反
Maven会规定好你该如何去编写我们的java代码,必须要按照这个规范来!
下载安转Maven
下载完成后,解压即可;
建议:电脑上的所有环境都放在一个文件夹下,方便管理;
配置环境变量
在我们的系统环境变量中
配置如下配置:
-
M2_HOME maven目录下的bin目录
-
MAVEN_HOME maven的目录
-
在系统的path中配置%MAVEN_HOME%\bin
测试Maven是否安装成功,必须保证配置完毕
阿里云镜像
-
镜像:mirrors
-
作用:加速我们的下载
-
-
国内建议使用阿里云的镜像
<mirror> <id>aliyunmaven</id> <mirrorOf>*</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>
本地仓库
在本地的仓库,远程仓库
建立一个本地仓库:localRepository
新建一个文件夹起名为maven-repo
<localRepository>D:\ImportantDocuments\Maven\apache-maven-3.8.6\maven-repo</localRepository>
在IDEA中使用Maven
-
启动IDEA
-
创建一个MavenWeb项目
Idea中的Maven设置
注意: IDEA项目创建成功后,看一眼Maven的配置
到这里,Maven在IDEA中的配置和使用就OK了
创建一个普通的Maven项目
这个只有在Web里面才有
标记文件夹功能
第二种方式:
在IDEA中配置Tomcat
Local:本地
Remote:远程
解决警告问题
必须要的配置:为什么会有这个问题:我们访问一个网站,需要指定一个文件夹名字
pom文件
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <!--Maven版本和头文件--> <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.0</modelVersion> <!--这里就是我们刚才配置的GAV--> <groupId>org.example</groupId> <artifactId>javaweb_maven</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <!--Package:项目的打包方式 jar:java应用 war:javaweb应用 --> <name>javaweb_maven Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <!--配置--> <properties> <!--项目的默认构建编码--> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!--编码版本--> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <!--项目依赖--> <dependencies> <!--具体依赖的jar包配置文件--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies> <!--项目构建用的东西--> <build> <finalName>javaweb_maven</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
这里可以看Maven中jar包的一个联系体系
Maven资源导出问题:直接在配置文件里面写
<!--在 build 中配置 resources,解决资源导出失败问题--> <!--include 标签指定哪些文件将被匹配,以*作为通配符--> <!--exclude 标签指定哪些文件将被忽略,以*作为通配符--> <!--filtering 构建过程中是否对资源进行过滤,默认false--> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
问题:IDEA每次都要重复配置Maven
解决:
Servlet
简介
-
Servlet简介就是sun公司开发动态web的一门技术
-
Sun在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:
-
编写一个类,实现Servlet接口
-
把开发好的java类部署到web服务器中。
-
把实现了Servlet接口的Java程序叫做,Servlet
HellowServlet
Serlvet接口Sun公司有两个默认的实现类:HttpServlet,GenericServlet
-
构建一个普通的Maven项目,删掉里面的src目录,以后就在这个项目里面建立Mondel;这个空的工程就是Maven的主工程
-
关于Maven父子工程的理解:
父项目中会有
<modules> <module>serlvet_01</module> </modules>
子项目中会有
<parent> <artifactId>javaweb_servlet</artifactId> <groupId>com.kuang</groupId> <version>1.0-SNAPSHOT</version> </parent>
父项目中的jar(依赖)子项目可以直接使用
相当于:son extends father
3.优化Maven环境
-
修改web.xml为最新的
-
将maven的结构搭建完整
4.编写一个Serlvet程序
5.编写Servlet的映射
为什么需要映射:我们写的是Java程序,但是要通过浏览器访问,二浏览器需要链接web服务器所以我们需要在web服务器中注册我们写的Servlet,还需要给他一个浏览器能够访问的路径
<!--注册select--> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.kuang.serlvet.HelloServlet</servlet-class> </servlet> <!--servlet的请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
6.配置Tomcat
注意:配置项目发布的路径就可以了
7.启动测试,OK
Servlet原理
Servlet是由Web服务器调用,web服务器在收到浏览器请求之后,会:
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可以指定通用映射路径
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping>
-
指定一些后缀或者前缀等等
可以自定义后缀实现请求映射 注意点:*前面不能加项目映射的路径 hello/sajd. <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>*.qinjiang</url-pattern> </servlet-mapping>
-
默认请求路径
<servlet-mapping> <!--默认请求路径--> <servlet-name>hello</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
ServletContext
web容器在启动的时候,他会为每个web程序都创建一个对应的ServletContext对象,他代表了当前的web应用;
共享数据
我在这个Servlet中保存的数据,可以在另一个servlet中拿到:
public class HellowServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //this.getInitParameter() 初始化参数 //this.getServletConfig() Servlet配置 //this.getServletCintext() Servlet上下文 ServletContext context = this.getServletContext(); //用来连接Servlet上下文 String username = "秦江"; context.setAttribute("username",username);//将一个数据保存在了ServletConText中,名字为username,值为username } }
public class GetServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); String username = (String)servletContext.getAttribute("username");//将取出的值强转为String类型 resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8");//编码格式 resp.getWriter().print(username); } }
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.kuang.servlet.HellowServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <servlet> <servlet-name>getc</servlet-name> <servlet-class>com.kuang.servlet.GetServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>getc</servlet-name> <url-pattern>/getc</url-pattern> </servlet-mapping>
初始化数据
<!--设置初始化参数--> <context-param> <param-name>url</param-name> <param-value>jdbc:mysql://localhost:3306/mybatis</param-value> </context-param>
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext();//获取上下文对象 String url = servletContext.getInitParameter("url");//获取初始化参数 resp.getWriter().print(url); }
请求转发
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("进入了ServletDemo02"); ServletContext servletContext = this.getServletContext(); //RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/dp3");//设置转发路径 //requestDispatcher.forward(req,resp);//调用worward实现请求转发 //简写;输入dp3直接跳转到dp3 servletContext.getRequestDispatcher("/dp3").forward(req,resp); }
读取资源文件
Properties
-
在java目录下新建properties
-
在resources目录下新建properties
发现:都被打包到了同一个路径下:classes,我们俗称为calsspath:
思路:需要一个文件流
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); InputStream is = servletContext.getResourceAsStream("/WEB-INF/classes/db.properties"); Properties prop = new Properties(); prop.load(is); String username = prop.getProperty("username"); String pwd = prop.getProperty("password"); resp.getWriter().print(username); resp.getWriter().print(pwd); }
HttpServletResponse
web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletResponse;
-
如果要获取客户端请求过来的参数:找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); void setDateHeader(String var1, long var2); void addDateHeader(String var1, long var2); void setHeader(String var1, String var2); void addHeader(String var1, String var2); void setIntHeader(String var1, int var2); void addIntHeader(String var1, int var2); void setStatus(int var1);//设置状态码
常见应用
1.向浏览器输出消息(getWrite,....)
下载文件
-
要获取下载文件的路径
-
下载的文件名是啥
-
设置想办法让浏览器能够支持下载我们需要的东西
-
获取下载文件的输入流
-
创建缓冲区
-
获取OutputStream对象
-
将FileOutputStream流写入到buffer缓冲区
-
使用OutputStream将缓冲区中的数据输入到客户端!
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.要获取下载文件的路径 //String realPath = this.getServletContext().getRealPath("/1.png"); String realPath = "D:\\IDEA\\javaweb_servlettest\\response\\target\\classes\\1.png"; System.out.println("下载文件路径"+realPath); //2.下载的文件是啥 获取最后一个字符串的最后一个 String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1); //3.设置想办法让浏览器能够支持(Content-Disposition)web下载文件的头信息Content-Disposition","attachment;" filename:文件名 下载我们需要的东西,中文文件名URLEncoder.encoder编码,否则有可能乱码 resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8")); //4.获取下载文件的输入流 FileInputStream is = new FileInputStream(realPath); //5.创建缓冲区 int len = 0; byte[] buffer = new byte[1024]; //6.获取OutputStream ServletOutputStream outputStream = resp.getOutputStream(); //7.将FileOutStream流写入到buffer缓冲区,使用OutputStream将缓冲区中的数据输出到客户端! while((len = is.read(buffer))!=-1){ outputStream.write(buffer,0,len); } }
验证码功能
验证码怎么来的?
-
前端实现
-
后端实现,需要用到Java的图片类,生产一个图片
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //如何让浏览器3秒自动刷新一次 resp.setHeader("refresh","3"); //在内存中创建一个图片 BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_BGR); //得到图片 Graphics2D g = (Graphics2D) image.getGraphics();//笔 //设置图片的背景颜色 g.setColor(Color.white); g.fillRect(0,0,80,20); //给图片写数据 g.setColor(Color.BLUE); g.setFont(new Font(null,Font.BOLD,20)); g.drawString(makeNum(),0,20); //告诉浏览器,这个请求用图片的方式打开 resp.setContentType("image/jpeg"); //网站存在缓存,不让浏览器缓存 resp.setDateHeader("expires",-1); resp.setHeader("Cache-Control","no-cache"); resp.setHeader("Pragma","no-cache"); //吧图片写给浏览器 ImageIO.write(image,"jpg",resp.getOutputStream()); } private String makeNum(){ Random random = new Random(); String num = random.nextInt(9999999) + ""; StringBuffer sb = new StringBuffer(); for(int i = 0;i<7-num.length();i++){ sb.append("0"); } num = sb.toString() + num; return num; }
重定向
B一个web资源收到客户端A请求后,B他会通知A客户端去访问另一个web资源C,这个过程叫做重定向
常见场景:
-
用户登录
void sendRedirect(String var1) throws IOException;
测试:
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /* 相当于: resp.setHeader("Location","/r/img"); resp.setStatus(302);//设置状态码 */ resp.sendRedirect("/r/image");//设置重定向 }
面试题:请你聊聊重定向和转发的区别?
相同点
-
页面都会实现跳转
不同点
-
请求转发的时候,URL路径不会变化 状态码:307
-
重定向,URL地址栏会变 状态码:302
HttpServletRequest
HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,HTTP请求中的所有信息会被封装到HttpServletRequest,通过HttpServletRequest的方法,获得客户端的所有信息
获取参数,请求转发
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf8"); //获取账号 String username = req.getParameter("username"); //获取密码 String password = req.getParameter("password"); //获取爱好 String[] hobbys = req.getParameterValues("hobbys"); //输出到控制台 System.out.println("--------------------------"); System.out.println("账号为:"+username); System.out.println("密码为:"+password); System.out.println("爱好为:"+ Arrays.toString(hobbys)); System.out.println("--------------------------"); //通过请求转发req.getContextPath() req.getRequestDispatcher("/success.jsp").forward(req,resp); //通过响应重定向 resp.sendRedirect(req.getContextPath()+"/success.jsp"); }
<body> <h1>登陆</h1> <div style="text-align: center"> <%--这里表单表示的意思:以post方式提交表单,提交到我们的login请求--%> <%--${pageContext.request.contextPath}代表当前的项目--%> <form action="${pageContext.request.contextPath}/login" method="post"> 账号:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> 爱好: <input type="checkbox" name="hobbys" value="足球"> <input type="checkbox" name="hobbys" value="篮球"> <input type="checkbox" name="hobbys" value="乒乓球"> <input type="checkbox" name="hobbys" value="电影"> <br> <input type="submit"> </form> </div> </body>
Cookie、Session
会话
会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话
有状态会话:一个同学曾经来过教室,我们会知道这个同学,曾经来过,称之为有状态会话
你怎么证明你是西开的学生?
你 西开
1.发票 西开给你发票
2.学校登记 西开标记你来过了
一个网站,怎么证明你来过?
客户端 服务端
-
服务端给客户端一个信件,客户端下次访问服务端带上信件就可以了;cookie
-
服务器登记你来过了,下次你来的时候我来匹配你;seesion
保存会话的两种技术
cookie
-
客户端技术(响应,请求)
session
-
服务器技术,利用这个技术,可以保存用户的会话信息
常见:网页登录上去之后,你下次就不用在登陆了,第二次访问直接就上去了
Cookie
从请求中拿到cookie信息
服务器响应给客户端cookie
Cookie[] cookies = req.getCookies();//获得Cookie cookie.getName();//获得cookie中的key cookie.getValue();//获得cookie中的value new Cookie("lastLoginTime",System.currentTimeMillis()+"")//新建一个cookie
cookie:一般会保存在本地的 用户目录下appdata;
一个网站cookie是否存在上限!细节问题
-
一个Cookie只能保存一个信息;
-
一个web站点可以给浏览器发送多个cookie,最多存放20个cookie;
-
Cookie大小有限制4kb
-
300个cookie浏览器上限
删除Cookie
-
不设置有效期,关闭浏览器,自动是失效
-
设置有效期时间为0;
//创建一个cookie,名字必须要和要删除的名字一致 Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + ""); cookie.setMaxAge(0); resp.addCookie(cookie);
编码和解码
URLEncoder.encode("秦江","utf-8"); URLDecoder.decode(cookie.getValue(),"utf-8");
Session(重点)
什么是Session:
-
服务器会给每一个用户(浏览器)创建一个Session对象;
-
一个Session独占一个浏览器,只要浏览器没有关闭,这个Session就存在
-
用户登录之后,整个网站他都可以访问!--》保存用户的信息;保存购物车的信息。。。
Session和Cookie的区别
-
Cookie是把用户的数据写给用户的浏览器,浏览器保存
-
Session把用户的数据写到用户独占Session中,服务器端保存(保存重要的信息,减少服务器资源 的浪费)
-
Session对象由服务器创建;
使用场景:
-
保存一个登陆用户的信息;
-
购物车信息;
-
在整个网站中经常会使用的数据,我们将它保存在Session中
使用Session:
存数据和获取ID
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置字符集编码 req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); //获得Session HttpSession session = req.getSession(); //获取ID String id = session.getId(); //往session中存数据 session.setAttribute("name",new Person("秦江",1)); //判断是不是新创建的 if(session.isNew()){ resp.getWriter().write("创建成功ID为:"+id); }else{ resp.getWriter().write("session已存在ID为:"+id); } }
取数据
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); //往session中存入数据 Person person = (Person) session.getAttribute("name"); //输出到控制台 System.out.println(person); System.out.println(person.toString()); }
删除数据和注销Session
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); session.removeAttribute("name");//删除name这个数据 session.invalidate();//注销Session }
设置自动注销session
</servlet-mapping> <!--设置Session默认的失效时间--> <session-config> <!--1分钟后Session自动失效,以分钟为单位--> <session-timeout>1</session-timeout> </session-config>
JSP
什么是JSP
Java Servlet Pages:Java服务器端页面,也和Servlet一样,用户动态Web技术!
最大的特点
-
写JSP就像在写HTML
-
区别:
-
HTML只给用户提供静态的数据
-
JSP页面中可以嵌入JAVA代码,为用户提供动态数据
-
JSP原理:
思路:JSP到底怎么执行的!
-
代码层面没有任何问题
-
服务器内部工作
tomcat中有一个work目录
IDEA中使用Tomact的会在IDEA的tomcat中生产一个work目录
我电脑的地址:
C:\Users\86180\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\Unnamed_java_cookie_session\work\Catalina\localhost\ROOT\org\apache\jsp
发现页面转变成了Java程序
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet
JSP最终也会被转换为一个Java类
JSP本质就是一个Servlet
//初始化 public void _jspInit() { } //销毁 public void _jspDestroy() { } //JSP服务 public void _jspService(HttpServletRequest request,HttpServletResponse response)
1.判断请求
if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) { final java.lang.String _jspx_method = request.getMethod(); if ("OPTIONS".equals(_jspx_method)) { response.setHeader("Allow","GET, HEAD, POST, OPTIONS"); return; } if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) { response.setHeader("Allow","GET, HEAD, POST, OPTIONS"); response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS"); return; } }
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:当前
3.输出页面前增加的代码
response.setContentType("text/html");//设置 pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out;
4.以上的这些个对象我们可以在JSP页面中直接使用
在JSP页面中;
只要是JAVA代码就会原封不动的输出;
如果是HTML代码,就会转换为:
out.write("<html>\r\n");
这样的格式,输出到前端!
JSP基础语法
任何语言都有自己的语法,JAVA中有。JSP作为java技术的一种应用,他拥有一些自己补充的语法(了解),JAVA所有语法都支持!
JSP表达式
<%-- 作用:用来将程序的输出,输出到客户端 <%= 变量或者表达式%> --%> <%= new java.util.Date()%>
jsp脚本片段
<%--jsp脚本片段 --%> <% int sum =0; for (int i = 0; i <= 100; i++) { sum+=i; } out.println("<h1>"+sum+"</h1>"); %>
脚本片段的再实现
<% int x = 10; out.println(x); %> <p>这是一个JSP文档</p> <% int y = 2; out.print(y); %> <hr> <%--在代码中嵌入HTML元素--%> <%for (int i = 0; i < 5; i++) {%> <h1>Hellow,World</h1> <% }%>
JSP声明
<%! static{ System.out.println("abc"); } public void menthod(){ System.out.println("方法"); } %>
JSP声明:会被编译到JSP生成的JAVA类中!其他的,就会被生成到_jspService方法中
在JSP,嵌入Java代码即可
<%%>片段 <%=%>表达式输出一个值 <%!%>定义全局 <%----%>注释
JSP的注释,不会在客户端显示,HTML的就会!
jsp指令
<%--定制错误页面 ,报错就会跳到这个指定页面(500.jsp)--%> <%@ page errorPage="error/500.jsp" %> <%--声明这是一个错误页面--%> <%@ page isErrorPage="true" %> <%--编码--%> <%@ page pageEncoding="UTF-8" %> <%--导包--%> <%@ page import="java.util.*" %> <%--写在body标签中 include会将两个页面合二为一--%> <%@ include file="common/header.jsp"%> <h1>网页主题</h1> <%@ include file="common/footer.jsp"%> <%--jsp标签 jsp:include:拼接页面,本质还是三个 --%> <jsp:include page="/common/header.jsp"/> <h1>主体</h1> <jsp:include page="/common/footer.jsp"/>
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号");//保存的数据只在服务器中有效,从打开服务器到关闭服务器
//从pageContext取出,我们通过寻找的方式来 //从底层到高层(作用域):page->request->session->application 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表达式输出 ${} }--%> <h1>取出的值为</h1> <h3>${name1}</h3> <h3>${name2}</h3> <h3>${name3}</h3> <h3>${name4}</h3> <h3>${name5}</h3>
requst:客户端向服务器发送请求,产生的数据,用户看完就没了,比如:新闻,用户看完没用的!
session:客户端向服务器发送请求,产生的数据,用户用完一会还有用,比如:购物车
application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如:聊天数据;
JSP标签、JSTL标签、EL表达式
<!--jstl表达式依赖--> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl-api</artifactId> <version>1.2</version> </dependency> <!--standard标签库--> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1..2</version> </dependency>
JSP标签、JSTL标签、EL表达式
EL表达式: ${ }
-
获取数据
-
执行运算
-
获取web开发的常用对象
JSP标签
<%--<jsp:include page="pageContextDemo01.jsp"/> --%> <jsp:forward page="/jsp2.jsp"> <jsp:param name="name" value="kuangshen"></jsp:param> <jsp:param name="age" value="12"></jsp:param> </jsp:forward>
JSTL表达式
JSTL标签库的使用就是为了弥补HTML标签的不足;它自定义许多标签,可以供我们使用,标签的功能和java代码一样
格式化标签
SQL标签
XML标签
核心标签(掌握部分)
JSTL标签使用步骤
-
引入对应的taglib
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
-
使用其中的方法
-
在Tomcat也需要引入jstl的包,否则会报错:JSTL解析错误
if判断
<head> <title>Title</title> </head> <body> <form action="jstltest.jsp" method="get"> <%-- EL表达式获取表单中的数据 ${param.参数名} --%> 账户: <input type="text" name="username" value="${param.username}"> <input type="submit" value="登陆"> </form> <%--判断如果提交的用户是管理员则登陆成功--%> <c:if test="${param.username=='admin'}" var="isAdmin"> <c:out value="管理员欢迎你"/> </c:if> <%--自闭合标签 单列标签--%> <c:out value="${isAdmin}"/> </body>
choose
when
<%--定义一个变量名为 core 值为90--%> <c:set var="core" value="90"/> <c:choose> <c:when test="${core>=90}"> 你的成绩为优秀 </c:when> <c:when test="${core>=80}"> 你的成绩为一般 </c:when> <c:when test="${core>=70}"> 你的成绩为社会 </c:when> </c:choose>
forEach
<% ArrayList<String> strings = new ArrayList<>(); strings.add(0,"张三"); strings.add(1,"李四"); strings.add(2,"王五"); strings.add(3,"赵六"); request.setAttribute("list",strings); %> <%-- var,每一次遍历出来的变量 items,要遍历的对象 begin,哪里开始 end,到哪里结束 step,步长 --%> <c:forEach var="people" items="${list}"> <c:out value="${people}"/> </c:forEach> <c:forEach var="people" items="${list}" begin="0" end="2" step="1"> <c:out value="${people}"/> </c:forEach>
JavaBean
实体类
实体类,我们一般都是和数据库中的表结构一一对应!
JavaBean有特定的写法
-
必须要有一个无参构造
-
属性必须私有化
-
必须有对应的get/set方法;
一般用来和数据库的字段做映射ORM;
ORM:对象映射
-
表---》类
-
字段---》属性
-
行记录---》对象
people表
id | name | age | address |
---|---|---|---|
1 | 社会人1号 | 3 | 北京 |
2 | 社会人2号 | 18 | 北京 |
class People{ private int id; private String name; private int id; private String address; /* 无参构造、get/set方法、toString方法 */ } class A{ new People(1,"社会人1号",3,"北京"); new People(2,"社会人2号",18,"北京") }
<% People people = new People(); people.setAddress("北京"); people.setId(2); people.setAge(13); people.setName("社会人一号"); %> <%--获取ID--%> <%=people.getId()%> <%--上面写法与下面写法等价--%> <%-- ------------------------------------------------------ --%> <%--等同于People people = new People(); page表示作用域--%> <jsp:useBean id="people" class="com.kuang.pojo.People" scope="page"/> <jsp:setProperty name="people" property="address" value="北京"/> <jsp:setProperty name="people" property="id" value="1"/> <jsp:setProperty name="people" property="age" value="13"/> <jsp:setProperty name="people" property="name" value="社会人一号"/> 姓名:<jsp:getProperty name="people" property="id"/> id:<jsp:getProperty name="people" property="name"/> 年龄:<jsp:getProperty name="people" property="age"/> 地址:<jsp:getProperty name="people" property="address"/>
MVC三层架构
什么是MVC:model view Controller 模型、视图、控制器
早些年架构
用户直接访问控制层,控制层就可以直接操作数据库
servlet -- CRUD -->数据库 弊端:不利于维护 servlet的代码中:处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码 架构:没有什么是加一层解决不了的!
三层架构
Model
-
业务处理:业务逻辑(Servive)
-
数据持久层:CRUD(Dao)
View
-
展示数据
-
提供连接发起Servlet请求(a,form,img...)
Controller(Servlet)
-
接收用户的请求:(req:请求参数、Session信息)
-
交给业务层处理对应的代码
-
控制视图层的跳转
登陆--》接收用户的登陆请求--》处理用户的请求(获取用户登陆的参数,username,password)--》交给业务层处理登陆业务(判断用户名密码是否正确:事务)--》Dao层查询用户名和密码是否正确--》数据库
Filter过滤器
Filter:过滤器,用来过滤网站的数据;
-
处理中文乱码
-
登陆验证....
Filter开发步骤
1.导包
2.编写过滤器
1.导包不要错
实现Filter接口,重写对应的方法即可
public class CharacterEncodingFilter implements Filter { //初始化:web服务器启动,就已经初始化了,随时等待过滤对象出现! public void init(FilterConfig filterConfig) throws ServletException { System.out.println("CharacterEncodingFilter初始化"); } //Chain:链 /* 1.过滤中的所有代码,在过滤特定请求的时候都会执行 2.必须要让过滤器继续执行 chain.do */ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); servletResponse.setContentType("text/html"); //让请求继续走,如果不写,程序到这里就被拦截停止! filterChain.doFilter(servletRequest,servletResponse); } //销毁 public void destroy() { System.out.println("销毁"); } }
3.在web.xml中配置Filter
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.kuang.filter.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <!--只要是/Servlet的任何请求,会经过这个过滤器--> <url-pattern>/servlet/*</url-pattern> </filter-mapping>
过滤器、监听器常见应用
监听器:GUI编程中经常使用
案例:用户登陆之后才能进入主页
负责登陆界面的servlet
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取前端的参数 req.getAttribute(); String username = req.getParameter("username"); //如果输入的值为admin则重定向到主页 if(username.equals("admin")){ req.getSession().setAttribute("USER_NAME",req.getSession().getId()); resp.sendRedirect("/sys/success.jsp"); }else{//登陆失败 resp.sendRedirect("/error.jsp"); } }
负责注销的servlet
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取Session的key Object name = req.getSession().getAttribute("USER_NAME"); //如果他的值不为空则删除他 并且重定向到登陆界面 if(name!=null){ req.getSession().removeAttribute("USER_NAME"); resp.sendRedirect("/Login.jsp"); } }
过滤 如果没有登陆 则不能进入主页
//过滤 如果没有登陆 就不能进入主页 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest; HttpServletResponse response = (HttpServletResponse)servletResponse; if(request.getSession().getAttribute("USER_NAME")==null){ response.sendRedirect("/error.jsp"); } filterChain.doFilter(servletRequest,servletResponse); }
报错界面
<body> <h1>错误</h1> <h3>可能是路径错误</h3> <a href="Login.jsp">返回登录页面</a> </body>
登陆界面
<body> <form action="/servlet/Login" method="get"> <input type="text" name="username"> <input type="submit"> </form> </body>
主页
<body> <h1>主页</h1> <a href="/servlet/LogoutServlet">注销</a> </body>
JDBC
什么是JDBC:Java连接数据库!
需要jar包的支持:
-
java.sql
-
javax.sql
-
mysql-conneter-java...连接驱动(必须要导入)
导入数据库依赖
<!--MySql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency>
JDBC固定步骤:
-
加载驱动
-
连接数据库,代表数据库
-
想数据库发送SQL的对象Statement:CRUD
-
编写SQL(根据业务,不同的SQL)
-
查询SQL返回一个ResultSet:结果集
-
关闭连接
Statement
//userUdnicode=true&characterEncoding=utf-8 解决中文乱码 String url = "jdbc:mysql://localhost:3306/jdbc?userUdnicode=true&characterEncoding=utf-8"; String username = "root"; String password = "123456"; //加载驱动 Class.forName("com.mysql.jdbc.Driver"); //连接数据库,connection代表数据库 Connection connection = DriverManager.getConnection(url, username, password); //向数据库发送sql的对象Statement:CRUD Statement statement = connection.createStatement(); //编写sql String sql = "select * from users"; //执行查询SQL,返回一个ResulSet:结果集 ResultSet rs = statement.executeQuery(sql); //遍历数据 while(rs.next()){ System.out.println(rs.getObject("id")); System.out.println(rs.getObject("name")); System.out.println(rs.getObject("password")); System.out.println(rs.getObject("email")); System.out.println(rs.getObject("birthday")); }
prepareStatement
//userUdnicode=true&characterEncoding=utf-8 解决中文乱码 String url = "jdbc:mysql://localhost:3306/jdbc?userUdnicode=true&characterEncoding=utf-8"; String username = "root"; String password = "123456"; //加载驱动 Class.forName("com.mysql.jdbc.Driver"); //获取数据库 Connection connection = DriverManager.getConnection(url, username, password); //编写sql String sql = "insert into users (id, name, password, email, birthday) values (?,?,?,?,?);"; //预编译 PreparedStatement ps = connection.prepareStatement(sql); ps.setInt(1,4);//给第一个占位符赋值为4 ps.setObject(2,"李四"); ps.setObject(3,"123321"); ps.setObject(4,"2938475@"); ps.setObject(5,new Date(new java.util.Date().getTime())); int i = ps.executeUpdate(); if(i>0){ System.out.println("插入成功"); }
事务
要么都成功,要么都失败
ACID原则:保证数据的安全
开启事务 事务提交 commit(); 事务回滚 rollback(); 关闭事务 //userUdnicode=true&characterEncoding=utf-8 解决中文乱码 String url = "jdbc:mysql://localhost:3306/jdbc?userUdnicode=true&characterEncoding=utf-8"; String username = "root"; String password = "123456"; Connection connection = null; //加载驱动 try { Class.forName("com.mysql.jdbc.Driver"); //获取数据库 connection = DriverManager.getConnection(url, username, password); //通知数据库开启事务,false开启 connection.setAutoCommit(false); //编写sql String sql = "update account set money=money-100 where name = 'A'"; //预编译 connection.prepareStatement(sql).executeUpdate(); String sql1 = "update account set money=money+100 where name = 'B'"; connection.prepareStatement(sql1).executeUpdate(); //提交事务 connection.commit(); System.out.println("surcce"); } catch (Exception e) { //如果出现异常,就会通知数据库回滚 try { connection.rollback(); } catch (SQLException throwables) { throwables.printStackTrace(); } e.printStackTrace(); }