JavaWeb包括:Tomcat、HTTP、Maven、Servlet、Cookie、Session、JSP、JDBC。
JavaWeb
1.1 什么是JavaWeb
- web:网页的意思
- 在Java中,动态web资源开发的技术统称为JavaWeb
- 静态web:每个人看的内容都相同
- 动态web:不同的人在同样的时间看到的内容都不相同
1.1.1 静态Web
- .htm,.html这些都是网页的后缀,服务器中的这些资源可以通过网络直接读取
静态web存在的缺点
- web页面无法动态更新,所有用户看到的都是同一个页面
- 轮播图,点击特效。(伪动态)
- JavaScript: 它无法和数据库交互(数据无法持久化,用户无法和电脑交互)
1.1.2 动态Web
-
web服务器先将请求数据中的动态资源转换为静态资源后,再响应给前端页面展示。
-
页面会动态展示:web页面展示效果因人而异
动态web存在的缺点
- 假如服务器的动态web资源出现了错误,需要重新编写后台程序,重新发布,停机维护。
动态web存在的优点
- web页面可以动态更新,所有用户看到的页面都不相同
- 可以和数据库交互(数据持久化:注册,用户信息)
1.2 Web应用程序
web应用程序:
可以提供浏览器访问的程序
- a.html…多个web资源,可以被外界访问, 对外界提供服务
- 能访问的任何一个页面或资源,都存在某一台计算机中
- 通过URL来或者这个资源
- 这个统一的web资源会放在同一个文件夹下,web应用程序–TomCat
- 一个web应用应该由多部分组成(静态web,动态web)
- html,css,js
- jsp,servlrt
- java程序
- jar包
- 配置文件(xml,properties)
web应用程序编写完毕后,若想提供给外界访问,需要一个服务器(Tomcat)
来统一管理。
1.3 Web服务器
服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应信息。
Tomcat
2.1 安装Tomcat
windows系统
开启服务器后测试 :http://localhost:8080/
出现该页面表示服务器启动成功
可能遇到的问题
- Java环境变量没有配置(JAVA_HOME)
- 闪退问题:需要配置兼容性
- 乱码问题:配置文件中设置
2.2 配置Tomcat
核心配置文件
配置启动的端口号(8080)
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
配置主机的名称(localhost)
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
网站是如何进行访问的?
- 输入一个域名(对应的一个ip地址),回车
- 先检查本机的C:\Windows\System32\drivers\etc\host配置文件下有没有这个域名映射;
- 有:直接返回对应的ip地址,这个地址中有需要访问的web程序,可以直接访问。
- 没有:去DNS服务器找,找到的话就返回ip地址,找不到就返回找不到该页面。(DNS:管理着全世界的域名)
2.3 发布一个Web网站
- 将自己写的网站,放到服务器(Tomcat)中指定的web应用的文件夹(webapps)下,就可以访问了。
一个web项目的目录结构
-- webapps :tomcat服务器的web目录
--ROOT:默认项目目录
--rm:自己网站的目录名
--WEB-INF
--classes:java程序
--lib:web应用所依赖的jar包
--web.xml:配置文件
--index.html 默认的网站首页
--static:静态资源目录
-css
-js
-img
HTTP
参考图解HTTP这一博文。
3.1 什么是HTTP
HTTP(超文本传输协议)
是一个简单的请求-响应协议,通常运行在TCP之上。
- 文本:html,文字…
- 超文本:图片,视频,定位,地图…
- 默认80端口
HTTPS(安全的超文本传输协议)
- 默认443端口
- S:safe
3.2 HTTP的两个时代
-
HTTP/1.0:每一次请求响应都会建立新的连接,比较耗时和浪费资源
-
HTTP/1.1:复用连接,当第一次请求结束后,会等待一会看是否有新的请求,如果有,则复用这次申请的连接,直到没有请求数据发送为止
3.3 HTTP请求
客户端–发请求–服务器
请求行
- 请求行中的请求方式:Get,Post
- get:请求能够携带的参数比较少,大小有限制,会在浏览器地址栏显示数据内容,不安全,但高效。
- post:请求能够携带的参数没有限制,大小没有限制,不会在浏览器地址栏显示数据内容,安全,但不高效。
消息头
Accept:告诉浏览器,它所支持的数据类型
Accept-Encoding:支持哪种编码格式 GBK UTF-8 GB2312
Accept-Language:告诉浏览器,它的语言环境
Cache-Control:缓存控制
Connection:告诉浏览器,请求完毕是断开还是继续保持连接
Host:主机
3.4 HTTP响应
- 服务器–响应–客户端
响应体
Accept:告诉浏览器,它所支持的数据类型
Accept-Encoding:支持哪种编码格式 GBK UTF-8 GB2312
Accept-Language:告诉浏览器,它的语言环境
Cache-Control:缓存控制
Connection:告诉浏览器,请求完毕是断开还是继续保持连接
Host:主机
Refush:告诉客户端,多久刷新一次
Location:让网页重新定位
响应状态码
协议/版本 响应状态码 状态码描述
HTTP/1.1 200 OK
响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态。
1. 状态码都是3位数字
2. 分类:
1. 1xx:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
2. 2xx:成功。代表:200
3. 3xx:重定向。代表:302(重定向),304(访问缓存)
4. 4xx:客户端错误。
* 404(请求路径没有对应的资源)
* 405:请求方式没有对应的doXxx方法
5. 5xx:服务器端错误。代表:500(服务器内部出现异常)502(网关错误)
Maven
- Maven 是一个
项目管理工具
,可以对 Java 项目进行构建、依赖管理。 - 在JavaWeb开发中,需要使用大量的jar包,需要手动导入, Maven能够自动导入和配置这些jar包
4.1 Maven的下载
下载地址:https://maven.apache.org/download.cgi
- 解压到一个专门放环境变量的文件夹中
4.2 Maven配置
4.2.1 配置Maven环境变量
4.2.2 配置本地仓库
在setting中配置本地仓库
4.2.3 配置阿里云镜像
- 作用:加速下载jar包
在setting中配置阿里云镜像
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
4.2.4 在IDEA中配置Maven
为以后新建的项目配置Maven
4.3 Maven静态资源导出问题
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
4.4 在IDEA中使用Maven
创建一个MavenWeb项目
创建好的web项目目录结构
普通的maven项目目录结构
手动补齐web项目目录
- 在main目录下新建一个java和resouce目录,在src下新建一个test目录,test目录里面再新建一个java目录。并为其赋予属性
补齐后的一个完整的web项目目录结构
4.5 在IDEA中配置Tomcat
虚拟路径映射
4.6 Pom.xml文件
- Maven项目的核心配置文件
4.6.1 查看导入的jar包体系结构树图
Servlet
5.1 什么是Servlet
- Servlet就是sun公司开发动态web的一门技术
- Sun公司在这些API中提供了一个接口叫做Servlet
- 把实现了Servlet接口的程序叫做Servlet
- 编写一个类继承Servlet接口
- 把开发好的Java类部署到web服务器中
5.2 创建一个Servlet
Servlet接口有两个默认的实现类:HttpServlet
,GenericServlet
5.2.1 创建Maven工程
-
构建一个普通的Maven项目
-
删除src目录,这个空的工程就是主工程
-
在这个项目中创建module
-
Maven父子工程(主项目和module模块)
-
注意: 父项目中的依赖子项目可以直接使用
父项目中
<modules>
<module>servlet01</module>
</modules>
子项目中
<parent>
<artifactId>MyServlet</artifactId>
<groupId>com.rm</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
5.2.2 创建类继承HttpServlet
- 创建一个类继承HttpServlet,重写doPost,doGet方法
- 由于get或者post只是请求实现的不同的方式,可以相互调用,业务逻辑都一样
public class servlet01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
PrintWriter writer = resp.getWriter();//响应字节输出流
writer.write("Hello,Servlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req,resp);
}
}
5.2.3 配置Servlet映射
- 在web.xml中配置servlet映射
- 为什么需要映射: 我们写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以需要在web服务器中注册我们写的servlet,还需要指定一个浏览器能够访问的路径。
<servlet>
<servlet-name>servlet01</servlet-name>
<servlet-class>com.rm.servlet.servlet01</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet01</servlet-name>
<!--配置servlet访问路径-->
<url-pattern>/servlet</url-pattern>
</servlet-mapping>
5.2.4 测试
- 启动tomcat服务器,在浏览器地址栏输入http://localhost:80/servlet
5.2.5 servlet执行原理
- 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
- 查找web.xml文件,是否有对应的
<url-pattern>
标签体内容。 - 如果有,则在找到对应的
<servlet-class>
全类名 - tomcat会将字节码文件加载进内存,并且创建其对象
- 调用其方法
5.3 Servlet原理
- Servlet是由web服务器调用,web服务器在接收到浏览器请求后:
5.4 Mapping问题
- 一个Servlet可以指定一个或多个映射路径。(/aaa,/aa,/bb)
- 一个Servlet可以指定通用映射路径
- 可以在映射路径中指定一些前缀或者后缀(通配符)
优先级问题:
指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求
/ *表示默认的处理请求
<servlet>
<servlet-name>servlet01</servlet-name>
<servlet-class>com.rm.servlet.servlet01</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet01</servlet-name>
<!--/*表示默认的处理请求-->
<url-pattern>/*</url-pattern>
</servlet-mapping>
5.5 ServletContext对象
- web容器在启动的时候,会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用。(全局唯一)
5.5.1 共享数据
-
共享数据(在一个Servlet中保存的数据,可以在另一个Servlet中获取)
-
先访问存放数据的servlet,再访问获取数据的servlet才能成功获取数据。
存放数据的Servlet类
public class setServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取全局唯一对象servletContext,在其中存放数据,key:字符串。value:对象
ServletContext context = this.getServletContext();
String name = "张三";
context.setAttribute("name",name);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
}
获取数据的servlet类
public class getServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取servletContext对象
ServletContext context = this.getServletContext();
//设置响应的内容格式和编码
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
//获取context对象中的内容,并将其写在页面上
String name = (String) context.getAttribute("name");
resp.getWriter().write("名字:"+name);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
}
web.xml配置映射文件
<servlet>
<servlet-name>sets</servlet-name>
<servlet-class>com.rm.servlet.setServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>sets</servlet-name>
<url-pattern>/sets</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>gets</servlet-name>
<servlet-class>com.rm.servlet.getServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gets</servlet-name>
<url-pattern>/gets</url-pattern>
</servlet-mapping>
结果
5.5.2 获取初始化参数
配置初始化参数
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql//localhost:3306/mybatis</param-value>
</context-param>
servlet类
public class servlet02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
//获取web.xml中配置的初始化参数
String url = context.getInitParameter("url");
resp.getWriter().print(url);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req,resp);
}
}
结果
5.5.3 请求转发
- 转发的时候地址栏路径不会发生变化,只是请求的页面变化了。
servlet类
public class servlet03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
//获取转发路径,并转发,访问该servlet的映射路径时,得到的是/gets页面的内容
context.getRequestDispatcher("/gets").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req,resp);
}
}
web.xml配置
<servlet>
<servlet-name>s3</servlet-name>
<servlet-class>com.rm.servlet.servlet03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s3</servlet-name>
<url-pattern>/s3</url-pattern>
</servlet-mapping>
结果
5.5.4 读取资源文件
-
在java目录下新建properties
-
在resources目录下新建properties
-
发现都被打包到了同一个路径下,classes,通常把这个路径称为classpath。
-
如果在java目录下新建的properties文件无法被maven打包,那么需要在pom.xml中配置。
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.xml</exclude>
</excludes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
properties文件
username=zhangsan
password=123456
servlet类
public class servlet04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
//获取流对象/代表当前项目
InputStream is = context.getResourceAsStream("/WEB-INF/classes/db.properties");
//创建properties对象,加载流获取数据
Properties properties = new Properties();
properties.load(is);
String username = properties.getProperty("username");
String password = properties.getProperty("password");
//显示到页面上,设置内容和编码
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().print("username:"+username);
resp.getWriter().print("password:"+password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req,resp);
}
}
web.xml配置
<servlet>
<servlet-name>s4</servlet-name>
<servlet-class>com.rm.servlet.servlet04</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s4</servlet-name>
<url-pattern>/s4</url-pattern>
</servlet-mapping>
结果
5.6 HttpServletResponse对象
web服务器在接收到客户端的一次http请求后,针对这个请求,分别创建一个代表请求的HttpServletRequest对象和一个代表响应的HttpServletResponse对象。
- 如果要获取客户端请求过来的参数:找request
- 如果要给客户端响应一些信息:找response
负责向浏览器发送数据的方法
public ServletOutputStream getOutputStream() throws IOException;
public PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的方法
public void setCharacterEncoding(String charset);
public void setContentLength(int len);
public void setContentLengthLong(long len);
public void setContentType(String type);
public void setDateHeader(String name, long date);
public void addDateHeader(String name, long date);
public void setHeader(String name, String value);
public void addDateHeader(String name, long date);
public void setHeader(String name, String value);
public void addHeader(String name, String value);
5.6.1 下载文件
- 向浏览器输出消息
- 下载文件
- 要获取下载文件的路径
- 如何通过路径获取需要下载的文件名
- 设置响应头Content-disposition
- 获取下载文件的输入流
- 创建缓冲区
- 获取OutputStream对象
- 将FileOutputStream流写入到buffer缓冲区
- 使用OutputStream将缓冲区中的数据写到客户端。
public class servlet01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// - 要获取下载文件的路径
String file = "C:\\Users\\17312\\Pictures\\summer.jpg";
// - 如何通过路径获取需要下载的文件名
String filename =file.substring(file.lastIndexOf("\\")+1);
// - 设置响应头Content-disposition
resp.setHeader("Content-disposition", "attachment;filename=" +
URLEncoder.encode(filename,"utf-8"));
// - 获取下载文件的输入流
FileInputStream fis = new FileInputStream(file);
// - 创建缓冲区
int len =0;
byte[] buffer = new byte[1024];
// - 获取OutputStream对象
ServletOutputStream os = resp.getOutputStream();
// - 将FileOutputStream流写入到buffer缓冲区
while((len=fis.read(buffer))!=-1){
// - 使用OutputStream将缓冲区中的数据写到客户端。
os.write(buffer,0,len);
}
os.close();
fis.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
面试题:转发和重定向区别
相同点:
- 页面都会实现跳转
不同点:
- 请求转发得时候,地址栏url不会发生变化
- 重定向的时候,地址栏url会发生变化
5.7 HttpServletRequest对象
- HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,Http请求中的所有信息会被封装到HttpServletRequest对象中,通过这个HttpServletRequest对象的方法,可以获得客户端的所有信息。
获取前端传递的参数以及请求转发
public class servlet01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//设置请求编码和响应编码
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
//根据name属性获取表单提交的数据
String username = req.getParameter("username");
String password = req.getParameter("password");
//复选框使用该方法返回多个值
String[] hobbys = req.getParameterValues("hobbys");
System.out.println("username:"+username);
System.out.println("password:"+password);
System.out.println(Arrays.toString(hobbys));
//使用request对象进行重定向,不需要加虚拟路径
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
}
5.8 Cookie和Session
5.8.1 什么是会话
- 用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器。这个过程称之为会话。
有状态会话:
- 一个用户访问过该网站,下次再来的时候,我们会知道这个用户曾经来过这里。称之为有状态会话。
字符串编码和解码
//解码
URLDecoder.decode("你好","utf-8");
//编码
URLEncoder.encode("你好","utf-8");
5.8.2 Cookie
- 客户端技术(响应,请求)
常见应用:网站登录之后,下次不用再登录了,第二次可以直接访问。
- 从请求中拿到cookie信息
- 服务器响应给客户端cookie
Cookie[] cookies = req.getCookies(); //获得所有的cookie
cookie.getName(); //获得cookie中的key
cookie.getValue(); //获得cookie里面的value
new Cookie("timeCookie",System.currentTimeMillis()+""); //新建一个cookie
cookie.setMaxAge(24*60*60);//设置cookie的有效期
resp.addCookie(cookie);//给客户端响应一个cookie
cookie一般会保存在本地的用户目录下,APPdata
public class Cookie1 extends HttpServlet {
@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");
PrintWriter out = resp.getWriter();
//判断此次访问是否携带有timeCookie,如果没有,显示第一次访问,如果有,显示欢迎回来,您上次访问时间是:
Cookie[] cookies = req.getCookies();
if (cookies!=null){
//说明存在cookie,不是头一次访问,获取cookie
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
//看是否有timeCookie存在
if("timeCookie".equals(cookie.getName())){
//将上次访问时间输出到页面
//将字符串形式的时间戳先转换为long类型,再转换为date类型
Long l = Long.parseLong(cookie.getValue());
Date date = new Date(l);
out.print("您上次访问的时间是:"+date.toLocaleString());
}
}
}else {
//不存在cookie,证明首次访问
out.print("您好,欢迎首次访问");
}
//首次访问,将timeCookie交给客户端,值用时间戳表示
Cookie cookie = new Cookie("timeCookie",System.currentTimeMillis()+"");
//给cookie设置有效期,以秒为单位
cookie.setMaxAge(24*60*60);
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
5.8.3 Session(重点)
什么是Session:
- 服务器会给每一个用户(浏览器)创建一个Session对象
- 一个Session独占一个浏览器,只要浏览器没有关闭,这个Session就存在。有唯一ID
- 用户登录之后,整个网站都可以访问–>保存用户的信息
Session和Cookie的区别
- cookie是浏览器保存
- session是服务器保存,session对象由服务器创建
使用场景:
- 保存一个登录用户的信息
- 购物车信息
- 在整个网站中会经常使用的数据,将其保存在session中。
得到session,并存放数据
public class Session1 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//先设置请求和响应的编码,浏览器解析编码
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//得到请求里面的SessionID并将其输出到界面上
HttpSession session = req.getSession();
String id = session.getId();
if(session.isNew()){
resp.getWriter().write("session创建成功,ID: "+id);
}else {
resp.getWriter().write("Session已经存在服务器,ID:"+id);
}
//在Session中存入数据
Person p = new Person("小明",25);
session.setAttribute("name",p);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
}
在另一个页面获取session数据
public class Session2 extends HttpServlet {
@Override
protected void doPost(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();
Person p = (Person) session.getAttribute("name");
resp.getWriter().write(p.toString());
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
}
session手动注销和设置默认生效时间
public class Session3 extends HttpServlet {
@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对象,删除Session数据
HttpSession session = req.getSession();
session.removeAttribute("name");
//将该session注销,手动注销
session.invalidate();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
设置默认注销时间
<!-- 设置session的默认失效时间-->
<session-config>
<!--以分钟为单位,session自动失效-->
<session-timeout>30</session-timeout>
</session-config>
5.9 Filter过滤器
- 用来过滤网站的数据
- 用来处理乱码
public class FilterDemo1 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("过滤器初始化");
}
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");
//放行
filterChain.doFilter(servletRequest,servletResponse);
}
public void destroy() {
System.out.println("服务器关闭,退出过滤器");
}
}
xml中设置需要过滤的页面
<servlet>
<servlet-name>s1</servlet-name>
<servlet-class>com.rm.servlet.Servlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s1</servlet-name>
<url-pattern>/servlet/s1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>s1</servlet-name>
<url-pattern>/s1</url-pattern>
</servlet-mapping>
<!--配置过滤内容虚拟目录/servlet下的所有文件会被过滤,/s1不会被过滤-->
<filter>
<filter-name>f1</filter-name>
<filter-class>com.rm.filter.FilterDemo1</filter-class>
</filter>
<filter-mapping>
<filter-name>f1</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
5.10 监听器
- 实现监听器的接口,重写方法
- 在web.xml中注册监听器
统计网站在线人数
- 存在一个session即有一个用户在线
public class listener1 implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
//Session被创建的时候执行
HttpSession session = httpSessionEvent.getSession();
ServletContext context = session.getServletContext();
Integer Onlinecount = (Integer) context.getAttribute("count");
//在context中存数据
if(Onlinecount==null){
//证明没有用户访问
Onlinecount= new Integer(1);
}else {
int count = Onlinecount.intValue();
Onlinecount = new Integer(count+1);
}
context.setAttribute("count",Onlinecount);
}
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
//Session被销毁的时候执行
HttpSession session = httpSessionEvent.getSession();
session.invalidate();//手动销毁
ServletContext context = session.getServletContext();
Integer Onlinecount = (Integer) context.getAttribute("count");
//在context中存数据
if(Onlinecount==null){
//证明没有用户访问
Onlinecount= new Integer(0);
}else {
int count = Onlinecount.intValue();
Onlinecount = new Integer(count-1);
}
context.setAttribute("count",Onlinecount);
}
}
- 销毁session
- 手动销毁,设置session有效时间
<!--配置监听器-->
<listener>
<listener-class>com.rm.listener.listener1</listener-class>
</listener>
<!--设置session有效时间-->
<session-config>
<session-timeout>1</session-timeout>
</session-config>
5.11 过滤器常见应用
用户登录之后才能跳转到成功页面,用户注销后不能再通过url进入该页面了。
- 用户登录之后,向session中放入用户的数据
- 进入成功页面的时候要判断用户是否已经登录
//先将servletRequest强转为HttpServlet
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//然后过滤掉没有SESSION_ID的请求
if (request.getSession().getAttribute(Constant.USER_SESSIONID)==null){
response.sendRedirect("/failure.jsp");
}
filterChain.doFilter(servletRequest,servletResponse);
过滤器配置
<!--配置过滤器-->
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>com.rm.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/sys/*</url-pattern>
</filter-mapping>
JSP
6.1什么是JSP
Java Server Pages:Java服务器端页面,也和Servlet一样,用于动态web技术。
最大的特点:
- 写JSP就像写HTML
区别:
- HTML只能给用户提供静态的数据
- JSP页面中可以嵌套JAVA代码,为用户提供动态数据
6.2 JSP原理
JSP本质还是Servle
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
JSP内置了一些对象,可以直接使用
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
JSP将html标签自动生成了对应的JAVA代码
在JSP中编写的JAVA代码直接存在于Servlet中
out.write("<html>\n");
out.write("<body>\n");
out.write("<h2>Hello World!</h2>\n");
out.write("</body>\n");
out.write("</html>\n");
6.3 JSP基础语法
- 新建一个普通的mavne工程
导入项目依赖
<dependencies>
<!--servlet依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<!--jsp依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
<!--jstl表达式依赖-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--standard标签库-->
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>
</dependencies>
添加项目框架支持
配置tomcat,deployment(部署)项目
6.3.1 JSP表达式
<%--jsp表达式,用于将java结果输出到客户端--%>
<%= new java.util.Date()%>
6.3.2 JSP脚本片段
<%--jsp脚本片段,java代码--%>
<%
int sum=0;
for (int i = 1; i <= 100; i++) {
sum +=i;
}
out.println("<h1>Sum="+sum+"</h1>");
%>
JSP脚本片段再实现,JSP代码中嵌套html代码
<%--jsp脚本片段再实现--%>
<%
for (int i = 0; i < 3; i++) {
%>
<%= "Hello,World"+i%><br>
<%
}
%>
- 前面三种java代码都是在Servlet的service方法内部。
- 如果想要定义全局变量,静态代码块或者是其他方法,则需要使用JSP声明
6.3.3 JSP声明
-
JSP声明:会被编译到JSP生成的Java类中,其他的会被生成到_jspService方法中
-
在JSP页面中,嵌入JAVA代码即可
-
JSP的注释不会在客户端显示,HTML的会在客户端(查看源代码)显示。
<%--JSP声明--%>
<%!
static {
System.out.println("Servlet Loading...");
}
private String name;
public void getName(String name){
this.name =name;
}
%>
6.4 JSP指令
-
<%@ %>
-
导包import
-
定制错误界面errorPage
-
提取网页公共部分
-
本质还是三个界面,而不是将页面里面的内容合并在一起(建议使用)
<jsp:include page="common/Header.jsp"/>
<jsp:include page="common/Footer.jsp"/>
- 本质是将页面里面的内容合并在一起,如果两个页面有相同命名的变量,则会跳转到500错误页面。(不建议使用)
<%@include file="common/Header.jsp"%>
<%@include file="common/Footer.jsp"%>
定制错误界面
- 配置xml需要重启tomcat服务器
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
使用JSP指令配置
<%@ page errorPage="error/500.jsp" %>
6.5 JSP内置对象
- PageContetx 存数据
- Request [HttpServletRequest] 存数据
- Response [HttpServletResponse]
- Session [HttpSession] 存数据
- Application [ServletContext] 存数据
- config [ServletConfig]
- out [JspWriter]
- page
- exception [Throwable]
作用域从小到大
PageContext(只在当前页面有效)
Request(一次请求有效,可以通过转发在其他Servlet中有效)
Session(一次会话有效,客户端浏览器关闭,设置的Session有效期到期后失效)
Application(服务器只要一直启动,数据就一直有效)
应用场景
- request:客户端向服务器发送请求,产生的数据,用户看完就没用了,比如:新闻。
- session:客户端向服务器发送请求,产生的数据,用户用完一会还有用,比如:购物车商品。
- application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可以继续使用,比如:聊天数据
6.6 JSP标签,JSTL标签,EL表达式
EL表达式:${}
- 获取数据
- 执行运算
- 获取web开发的常用对象
JSTL表达式:
- JSTL标签的使用是为了弥补HTML标签的不足,它自定义许多标签,标签的功能和Java代码一样。
核心标签是最常用的 JSTL标签。引用核心标签库的语法如下:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
JSTL标签库使用步骤
- 引入对应的taglib
- 使用其中的方法
- 在Tomcat服务器中也需要导入jstl的包,否则会报错,jstl解析错误
c:if
<form action="coreIf.jsp" method="post">
<span>姓名:</span><input name="username" value="${param.username}">
<input type="submit" value="登录">
</form>
<%--判断如果username==admin,提示登录成功--%>
<c:if test="${param.username =='admin'}" var="isAdmin">
<c:out value="管理员,欢迎您"/>
</c:if>
<c:out value="${isAdmin}"/>
c:foreach
<%
//创建一个集合,并将其存放在当前页面中
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
pageContext.setAttribute("peoples",list);
%>
<%--使用c标签foreach方法遍历集合--%>
<c:forEach var="people" items="${peoples}" begin="1" step="2">
<c:out value="${people}"/><br/>
</c:forEach>
JDBC
7.1 什么是JDBC
Java连接数据库的原始方法
sql语句
CREATE DATABASE jdbc;
USE jdbc;
CREATE TABLE users(
id INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`password` VARCHAR(30) NOT NULL,
email VARCHAR(20),
birthday DATE
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO users(`id`,`name`,`password`,`email`,`birthday`)
VALUES
(1,"张三",'123456','zs@qq.com','2000-01-01'),
(NULL,"李四",'123456','ls@qq.com','2000-01-01'),
(NULL,"王五",'123456','ww@qq.com','2000-01-01')
SELECT*FROM users;
导入数据库依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
java代码
public class JDBC01 {
public static void main(String[] args) throws Exception {
//1.配置信息
String url= "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8";
String username="root";
String password="root";
//2.加载驱动(通过反射)
Class.forName("com.mysql.jdbc.Driver");
//3.获取数据库连接对象,代表数据库。
Connection connection = DriverManager.getConnection(url, username, password);
//获取执行sql对象
Statement statement = connection.createStatement();
//编写sql语句
String sql ="select*from users";
//获得处理后的结果
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"));
System.out.println("==============");
}
//关闭连接,释放资源
rs.close();
statement.close();
connection.close();
}
}
7.2 JDBC步骤
- 加载驱动
- 连接数据库
- 向数据库发送SQL的对象statement:CRUD
- 编写sql(不同业务,不同sql)
- 执行sql,获取查询结果集或者受影响行数
- 关闭连接
预编译SQL
public class JDBC02 {
public static void main(String[] args) throws Exception{
//预编译处理sql,防止sql注入问题
//1.配置信息
String url= "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8";
String username="root";
String password="root";
//2.加载驱动(通过反射)
Class.forName("com.mysql.jdbc.Driver");
//3.获取数据库连接对象,代表数据库。
Connection connection = DriverManager.getConnection(url, username, password);
//4.编写sql
String sql = "insert into users (id, name, password, email, birthday)values (?,?,?,?,?);";
//获取执行sql预编译对象
PreparedStatement statement = connection.prepareStatement(sql);
//为?赋值
statement.setInt(1,5);
statement.setString(2,"赵六");
statement.setString(3,"123456");
statement.setString(4,"zl@qq.com");
statement.setDate(5,new Date(new java.util.Date().getTime()));
//执行sql
int i = statement.executeUpdate();
if(i>0){
System.out.println("插入成功");
}
//关闭连接,释放资源
statement.close();
connection.close();
}
}
7.3 事务
ACID原则
开启事务
提交事务 commit()
回滚事务rollback()
关闭事务
模拟事务
–建表–
CREATE TABLE account(
id INT AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(20),
`money` FLOAT(30)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO account(`name`,`money`)VALUES
('A',1000),
('B',1000),
('C',1000)
SELECT*FROM account;
Java代码
public class JDBC03 {
public static void main(String[] args) {
//模拟事务
//1.配置信息
String url= "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8";
String username="root";
String password="root";
Connection connection=null;
PreparedStatement prep1=null;
PreparedStatement prep2=null;
try {
//2.加载驱动(通过反射)
Class.forName("com.mysql.jdbc.Driver");
//3.获取数据库连接对象,代表数据库。
connection = DriverManager.getConnection(url, username, password);
//4.开启事务
connection.setAutoCommit(false);
//5.编写sql
String sql1 ="update account set money =money-100 where name='A'";
String sql2 ="update account set money =money+100 where name='B'";
//6.获取预编译sql对象
prep1 = connection.prepareStatement(sql1);
prep2 = connection.prepareStatement(sql2);
//7.执行sql
prep1.executeUpdate();
prep2.executeUpdate();
//8.提交事务
connection.commit();
//9.将设置自动提交改回来
connection.setAutoCommit(true);
} catch (Exception e) {
//无论出现什么异常,数据回滚
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
System.out.println("数据异常,事务回滚");
} finally {
try {
if(connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(prep1 !=null){
prep1.close();
}
if(prep2!=null){
prep2.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}