1.AddServlet
AddServlet的功能:
1.获取用户(客户端)发送的数据
2.调用DAO中的方法完成添加功能
3.在控制台打印添加完成
1.1 接受客户端发送的信息
在webapp下创建“Add.html”文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="add" method="post">
名称:<input type="text" name="fname"><br>
价格:<input type="text" name="price"><br>
库存:<input type="text" name="fcount"><br>
备注:<input type="text" name="remark"><br>
<input type="submit" value="添加">
</form>
</body>
</html>
创建java包下
package com.example.servlets;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AddServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
Integer fcount = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
System.out.println("fname = " + fname);
System.out.println("price = " + price);
System.out.println("fcount = " + fcount);
System.out.println("remaker = " + remark);
}
}
在webapp/WEB-INF/web.xml中添加
<?xml version="1.0" encoding="UTF-8"?>
<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>AddServlet</servlet-name>
<servlet-class>com.example.servlets.AddServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AddServlet</servlet-name>
<url-pattern>/add</url-pattern>
</servlet-mapping>
<!--
1.用户发请求,action=add
2.项目中,web.xml中找到url-pattern = /add -> 12行
3.找第11行的servlet-name = AddServlet
4.找和servlet-mapping中servlet-name一直的servlet,找到第7行
5.找到第8行servlet-class -> com.example.servlets.AddServlet
6.用户发送的是post请求(method=post),因此tomcat会执行AddServlet中的doPost方法
-->
</web-app>
运行html,在浏览器中打开http://localhost:8080/add.html
在网页中输入信息,然后添加,可以在idea中接受到信息
15-May-2022 14:45:29.776 信息 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory D:\Tomcat\webapps\manager has finished in 63 ms
fname = apple
price = 5
fcount = 50
remaker = OK
1.2 调用DAO中的方法完成添加功能
1)下载fruit并在com.example下导入(链接:https://pan.baidu.com/s/1-7PUdud7oDlmzlVLQLfR2w 提取码:wnki)
#mysql建表
CREATE DATABASE fruitdb CHARSET utf8;
USE fruitdb ;
CREATE TABLE `t_fruit` (
`fid` INT(11) NOT NULL AUTO_INCREMENT,
`fname` VARCHAR(20) NOT NULL,
`price` INT(11) DEFAULT NULL,
`fcount` INT(11) DEFAULT NULL,
`remark` VARCHAR(50) DEFAULT NULL,
PRIMARY KEY (`fid`)
) ENGINE=INNODB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
INSERT INTO `t_fruit`(`fid`,`fname`,`price`,`fcount`,`remark`)
VALUES
(1,'红富士',5,16,'红富士也是苹果!'),
(2,'大瓜',5,100,'王校长的瓜真香'),
(3,'南瓜',4,456,'水果真好吃'),
(4,'苦瓜',5,55,'苦瓜很好吃'),
(5,'莲雾',9,99,'莲雾是一种神奇的水果'),
(6,'羊角蜜',4,30,'羊角蜜是一种神奇的瓜'),
(7,'啃大瓜',13,123,'孤瓜');
2)修改AddServlet
package com.example.servlets;
import com.example.fruit.dao.FruitDAO;
import com.example.fruit.dao.impl.FruitDAOImpl;
import com.example.fruit.pojo.Fruit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AddServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
Integer fcount = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
FruitDAO fruitDAO = new FruitDAOImpl();
boolean flag = fruitDAO.addFruit(new Fruit(0,fname,price,fcount,remark));
System.out.println(flag ? "添加成功" : "添加失败");
}
}
3)导入mysql的jar包
4)修改fruit/dao/base/BaseDao.java(根据自己的数据库更改信息)
5)然后点左上角的“File”接着点“Project Structure”,根据如下步骤选择“Artfacts”,删除原来的项目重新导入,然后确认
6)删除“target”文件夹后运行html,接着在网页上输入信息添加到数据库中
mysql> select * from t_fruit;
+-----+-----------+-------+--------+--------------------------------+
| fid | fname | price | fcount | remark |
+-----+-----------+-------+--------+--------------------------------+
| 1 | 红富士 | 5 | 16 | 红富士也是苹果! |
| 2 | 大瓜 | 5 | 100 | 王校长的瓜真香 |
| 3 | 南瓜 | 4 | 456 | 水果真好吃 |
| 4 | 苦瓜 | 5 | 55 | 苦瓜很好吃 |
| 5 | 莲雾 | 9 | 99 | 莲雾是一种神奇的水果 |
| 6 | 羊角蜜 | 4 | 30 | 羊角蜜是一种神奇的瓜 |
| 7 | 啃大瓜 | 13 | 123 | 孤瓜 |
| 38 | apple | 5 | 50 | OK |
+-----+-----------+-------+--------+--------------------------------+
8 rows in set (0.00 sec)
2.中文乱码问题
tomcat8之前:
1)get请求:
//get方式目前不支持设置编码(基于tomcat8)
//如果是get请求发送的中文数据,转码稍微有点麻烦(tomcat8之前)
String fname = req.getParameter(“fname”);
//1.将字符串打散成字节数组
byte[] bytes = fname.getBytes(“ISO-8859-1”);
//2.将字节数组按照设定的编码重新组装成字符串
fname = new String(bytes,“utf-8”);
2)post请求:
req.setCharacterEncoding(“utf-8”);
tomcat8开始,设置编码,只需针对post方式
req.setCharacterEncoding(“utf-8”);
注意:设置编码这一行代码必须在所有的获取参数动作之前
**get
如果添加中文时出现乱码
mysql> select * from t_fruit;
+-----+--------------------------------+-------+--------+--------------------------------------------------+
| fid | fname | price | fcount | remark |
+-----+--------------------------------+-------+--------+--------------------------------------------------+
| 1 | 红富士 | 5 | 16 | 红富士也是苹果! |
| 2 | 大瓜 | 5 | 100 | 王校长的瓜真香 |
| 3 | 南瓜 | 4 | 456 | 水果真好吃 |
| 4 | 苦瓜 | 5 | 55 | 苦瓜很好吃 |
| 5 | 莲雾 | 9 | 99 | 莲雾是一种神奇的水果 |
| 6 | 羊角蜜 | 4 | 30 | 羊角蜜是一种神奇的瓜 |
| 7 | 啃大瓜 | 13 | 123 | 孤瓜 |
| 38 | apple | 5 | 50 | OK |
| 39 | apple | 5 | 50 | OK |
| 40 | ����� | 6 | 50 | �����好�� |
+-----+--------------------------------+-------+--------+--------------------------------------------------+
10 rows in set (0.00 sec)
修改AddServlet(解决中文乱码问题)
package com.example.servlets;
import com.example.fruit.dao.FruitDAO;
import com.example.fruit.dao.impl.FruitDAOImpl;
import com.example.fruit.pojo.Fruit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class AddServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//post方式下,设置编码,防止乱码
//注意:设置编码这一行代码必须在所有的获取参数动作之前
req.setCharacterEncoding("utf-8");
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
Integer fcount = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
/*
//get方式目前不支持设置编码(基于tomcat8)
//如果是get请求发送的中文数据,转码稍微有点麻烦(tomcat8之前)
String fname = req.getParameter("fname");
//1.将字符串打散成字节数组
byte[] bytes = fname.getBytes("ISO-8859-1");
//2.将字节数组按照设定的编码重新组装成字符串
fname = new String(bytes,"utf-8");
*/
FruitDAO fruitDAO = new FruitDAOImpl();
boolean flag = fruitDAO.addFruit(new Fruit(0,fname,price,fcount,remark));
System.out.println(flag ? "添加成功" : "添加失败");
}
}
结果正常
mysql> select * from t_fruit;
+-----+--------------------------------+-------+--------+--------------------------------------------------+
| fid | fname | price | fcount | remark |
+-----+--------------------------------+-------+--------+--------------------------------------------------+
| 1 | 红富士 | 5 | 16 | 红富士也是苹果! |
| 2 | 大瓜 | 5 | 100 | 王校长的瓜真香 |
| 3 | 南瓜 | 4 | 456 | 水果真好吃 |
| 4 | 苦瓜 | 5 | 55 | 苦瓜很好吃 |
| 5 | 莲雾 | 9 | 99 | 莲雾是一种神奇的水果 |
| 6 | 羊角蜜 | 4 | 30 | 羊角蜜是一种神奇的瓜 |
| 7 | 啃大瓜 | 13 | 123 | 孤瓜 |
| 38 | apple | 5 | 50 | OK |
| 39 | apple | 5 | 50 | OK |
| 40 | ����� | 6 | 50 | �����好�� |
| 41 | 阿克苏苹果 | 6 | 50 | 阿克苏苹果好吃! |
+-----+--------------------------------+-------+--------+--------------------------------------------------+
11 rows in set (0.00 sec)
3.Servlet的继承关系(重点查看服务方法service())
1)继承关系
javax.servlet.Servlet接口
javax.servlet.GenericServlet抽象类
javax.servlet.http.HttpServlet抽象子类
2)相关方法
javax.servlet.Servlet接口:
void init(config) 初始化方法
void service(request,response) 服务方法
void destroy() 销毁方法
javax.servlet.GenericServlet抽象类:
void service(request,response) 仍然是抽象类
javax.servlet.http.HttpServlet抽象子类
void service(request,response) 不是抽象的
1.String method = req.getMethod(); 获取请求的方式
2.各种if判断,根据请求方式不用,决定去调用不同的do方法
if (method.equals("GET")) {
this.doGet(req, resp);
} else if (method.equals("HEAD")) {
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
}
3.在HttpServlet这个抽象类中,do方法都差不多
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
3)小结
1.继承关系:HttpServlet -> GenericServlet -> Servlet
2.Servlet中的核心方法:init()、service()、destroy()
3.服务方法:当由请求过来时,service方法会自动相应(其实是tomcat容器调用的)
在HttpServlet中我们会去分析请求的方式:到底是get、post、head还是delete等等
然后再决定调用的是哪个do开头的方法
name在HttpServlet中这些do方法默认都是405的实现风格——要我们子类去实现对应的方法,否则会报405错误
4.因此,我们在新建Servlet时,我们才会去考虑请求方法,从而决定重写哪个do方法
4.Servlet的生命周期
1)生命周期:从出生到死亡的过程就是生命周期。对应servlet中的三个方法:init()、service()、destroy()
2)默认情况下:
第一次接受请求时,这个Servlet会进行实例化(调用构造方法)、初始化(调用init())、然后服务(调用service())
从第二次请求开始,每一次都是服务
当容器关闭时,其中的所有servlet实例会被销毁,调用销毁方法(调用destroy())
3)通过案例发现:Servlet实例tomcat只会创建一个,所有的请求都是这个实例去响应。
默认情况下,第一次请求时,tomcat才回去实例化,初始化,然后再服务
好处:提高系统的启动速度
缺点:第一次请求时,耗时较长
结论:如果需要提高系统的启动速度,当前默认情况即可。
如果需要提高响应速度,我们应该设置Servlet的初始化时机
4)Servlet的初始化时机
默认是第一次接收请求时,实例化,初始化
我们可以通过来设置Servlet启动的向后顺序,数字越小启动越靠前,最小值0
<servlet>
<servlet-name>Demo01Servlet</servlet-name>
<servlet-class>com.example.servlets.Demo01Servlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
5)Servlet在容器中是:单例的、线程不安全的
单例:所有的青后都是同一个实例去响应
线程不安全:一个线程需要根据这个实例中的某个成员变量值去做逻辑判断。但是在中间某个时机,另一个线程该改变了这个成员变量的值,导致第一个线程执行路径发生了变化
启发:尽量不要在Servlet中定义成员变量。如果不得不定义成员变量,那么:①不要去修改成员变量的值 ②不要根据成员变量的值做一些逻辑判断
创建Demo01Servlet类
package com.example.servlets;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Demo01Servlet extends HttpServlet {
public Demo01Servlet(){
System.out.println("正在实例化......");
}
@Override
public void init() throws ServletException {
System.out.println("正在初始化......");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("正在服务......");
}
@Override
public void destroy() {
System.out.println("正在销毁");
}
}
修改web.xml
<servlet>
<servlet-name>Demo01Servlet</servlet-name>
<servlet-class>com.example.servlets.Demo01Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo01Servlet</servlet-name>
<url-pattern>/demo01</url-pattern>
</servlet-mapping>
debug执行,然后在浏览器中输入:http://localhost:8080/demo01
多次刷新后可以在idea中看到:
正在实例化......
正在初始化......
正在服务......
正在服务......
正在服务......
正在服务......
然后容器关闭时销毁。
5.HTTP协议
1)HTTP(超文本传输协议)。HTTP最大的作用就是确定了请求和相应数据的格式。
2)HTTP是无状态的
3)HTTP请求响应包含两个部分:请求报文和响报文
5.1 请求报文
请求报文包含三个部分:请求行、请求消息头、请求主
请求行
作用:展示当前请求的最基本信息
GET /demo01 HTTP/1.1
请求方式
访问地址
HTTP协议的版本
请求消息头
作用:通过具体的参数对本次请求进行详细的说明
格式:键值对,键和值之间使用冒号隔开
相对比较重要的请求消息头
名称 | 功能 |
---|---|
Host | 服务器的主机地址 |
Accept | 声明当前请求能够接受的媒体类型 |
Referer | 当前请求来源页面的地址 |
Content-Length | 请求体内容的长度 |
Content-Type | 请求体内容类型,这一项的具体值是媒体类型中的某一种 |
Cookie | 浏览器访问服务器时携带的Cookie数据 |
请求体
作用:作为请求的主题,发送数据给服务器。具体来说其实就是POST请求方式的请求参数
格式:
①form data
含义:当前请求体是一个表单提交的请求参数
每一组请求参数是一个键值对
键和值中间是等号
键值对之间是&号
②Request Payload
含义:整个请求体以某种特定格式来住址数据,例如JSON格式
请求方式
HTTP1.1中共定义了八种请求方式:
GET:从服务器端获取数据,没有请求体,但是有一个queryString
POST:将数据保存到服务器端,有请求体,form data
PUT:命令服务器对数据执行更新
DELETE:命令服务器删除数据
HEAD
CONNECT
OPTIONS
TRACE
5.2 响应报文
响应报文包含三个部分:响应行、响应头、响应体
响应行
HTTP/1.1 200 OK
HTTP协议版本
响应状态码
响应状态的说明文字
响应消息头
响应体的说明书
服务端对浏览器设置数据,例如:服务器端返回Cookie信息
名称 | 功能 |
---|---|
Content-Type | 响应体的内容类型 |
Content-Length | 响应体的内容长度 |
Set-Cookie | 服务器返回新的Cookie信息给卢兰奇 |
location | 在重定向的情况下,告诉浏览器访问下一个资源的地址 |
响应体
服务器返回的数据主题,有可能是各种数据类型
HTML页面
图片
视频
以下载形式返回的文件
CSS文件
JavaScript文件
响应状态码
作用:以编码的形式告诉浏览器当前请求处理的结果
状态码 | 含义 |
---|---|
200 | 服务器成功处理了当前请求,成功返回响应 |
302 | 重定向 |
400 | [SpringMVC特定环境]请求参数问题 |
403 | 没有权限 |
404 | 找不到目标资源 |
405 | 请求方式和服务器端对应的处理方式不一致 |
406 | [SpringMVC特定环境]请求扩展名和实际返回的响应体类型不一致 |
50X | 服务器端内部错误,通常都是服务器端抛异常了 |
404产生的具体原因:
- 访问地址写错了,确实是没有这个资源
- 访问了WEB-INF目录下的资源
- Web应用启动的时候,控制台已经抛出异常,导致整个Web应用不可用,访问任何资源都是404
- 服务器端缓存
6.会话(session)
1)Http是无状态的
- 服务器无法判断多个请求是同一个客户端发送的,还是不同客户端发送的
- 无状态带来的显示问题:第一次请求是添加商品到购物车,第二次请求是结账;如果是两次请求服务器无法区分是同一个用户的,那么就会混乱。
- 通过会话跟踪技术来解决无状态的问题
创建类
package com.example.servlets;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class Demo02Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取session,如果获取不到,则创建一个新的
HttpSession session = req.getSession();
System.out.println("session ID:" + session.getId());
}
}
修改web.xml
<servlet>
<servlet-name>Demo02Servlet</servlet-name>
<servlet-class>com.example.servlets.Demo02Servlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Demo02Servlet</servlet-name>
<url-pattern>/demo02</url-pattern>
</servlet-mapping>
开启容器,然后在浏览器中多次访问:http://localhost:8080/demo02
idea中显示
session ID:9FBEB916D0FB96DBB44234F3D55A70B0
session ID:9FBEB916D0FB96DBB44234F3D55A70B0
2)会话跟踪技术
客户端第一次发请求给服务器,服务器获取session,获取不到,则创建新的,然后响应给客户端
下一次客户端给服务器发请求时,会把sessionID发送给服务器,从而确认发送请求的客户端
常用的API:
request.getSession() -> 获取当前的会话,没有则创建一个新的会话
request.getSession(true) -> 效果和不带参数一样
request.getSession(false) -> 获取当前会话,没有则返回null,不会创建新的
session.getID() -> 获取sessionID
session.isNew() -> 判断当前session是否是新的
session.getMaxInactiveInterval() -> session的非激活间隔时长,默认1800秒
session.setMaxInactiveInterval()
session.invalidate -> 强制性让会话立即失效
…
3)session保存作用域
session保存作用域是和具体的某个session对应的
常用的API:
void session.setAttribute(k,v)
Object session.getAttribute(k)
void removeAttribute(k)
request.getSession()
向当前session保存作用域保存一个数据“lina”,对应的key为“uname”
session.setAttribute("uname","lina");
从当前session保存作用域取指定的key,可就是uname,对应的value值
session.getAttribute("uname");
实验
①创建类,向HttpSession保存数据
package com.example.servlets;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//演示向HttpSession保存数据
public class Demo03Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getSession().setAttribute("uname","lina");
}
}
②创建类获取unname
package com.example.servlets;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//获取unname
public class Demo04Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object uname = req.getSession().getAttribute("uname");
System.out.println(uname);
}
}
③配置web.xml
<servlet>
<servlet-name>Demo03Servlet</servlet-name>
<servlet-class>com.example.servlets.Demo03Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo03Servlet</servlet-name>
<url-pattern>/demo03</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Demo04Servlet</servlet-name>
<servlet-class>com.example.servlets.Demo04Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo04Servlet</servlet-name>
<url-pattern>/demo04</url-pattern>
</servlet-mapping>
④重启容器,然后访问:http://localhost:8080/demo03
接着在同一浏览器访问:http://localhost:8080/demo04
在idea中返回:lina
⑤在其他浏览器中访问:http://localhost:8080/demo04
返回:null
6.服务器内部转发以及客户端重定向
1)服务器内部转发
request.getRequestDispatcher(“…”).forward(request,response);
一次请求响应的过程,对于客户端而言,内部经过了多少次转发,客户端是不知道的
地址栏没有变化
2)客户端重定向
response.sendRedirect(“…”);
两次请求响应的过程。客户端知道请求url有变化
地址栏有变化
实验
①创建类Demo05Servlet演示服务器端内部转发
package com.example.servlets;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//演示服务器端内部转发以及客户端重定向
public class Demo05Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo05....");
//服务器端内部转发
req.getRequestDispatcher("demo06").forward(req,resp);
}
}
②创建类Demo06Servlet
package com.example.servlets;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Demo06Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo06...");
}
}
③配置web.xml
<servlet>
<servlet-name>Demo05Servlet</servlet-name>
<servlet-class>com.example.servlets.Demo05Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo05Servlet</servlet-name>
<url-pattern>/demo05</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Demo06Servlet</servlet-name>
<servlet-class>com.example.servlets.Demo06Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo06Servlet</servlet-name>
<url-pattern>/demo06</url-pattern>
</servlet-mapping>
④浏览器访问:http://localhost:8080/demo05
idea显示:
demo05…
demo06…
浏览器地址依然是:http://localhost:8080/demo05
实际上显示的已经是demo06页面
⑤Demo05Servlet演示客户端重定向
package com.example.servlets;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//演示服务器端内部转发以及客户端重定向
public class Demo05Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo05....");
//服务器端内部转发
// req.getRequestDispatcher("demo06").forward(req,resp);
//客户端重定向
resp.sendRedirect("demo06");
}
}
⑥访问:http://localhost:8080/demo05
idea显示:
demo05…
demo06…
浏览器地址变为:http://localhost:8080/demo06
7.Thymeleaf(视图模板技术)
1)添加thymeleaf的jar包(链接:https://pan.baidu.com/s/1sZGhKYLD_8VKkOBS233q5A 提取码:aqxd)
2)新建一个Servlet类ViewBassServlet
3)在web.xml文件中添加配置
配置前缀view-prefix
配置后缀view-suffix
4)使得我们的Servlet继承ViewBaseServlet
5)根据逻辑视图明层得到物理视图名称
//此处的视图名称是index
//thymeleaf会将这个 逻辑视图名称 对应的 物理视图 名称上去
//逻辑视图名称:index
//物理视图名称:view-prefix + 逻辑视图名称 + view-suffix
//所以真实的视图名称是:/ index .html
super.processTemplate(“index”,req,resp);
6)使用thymeleaf的标签
th:if, th:unless, th:each, th:text
实验
①新建一个Servlet类ViewBassServlet
package com.example.servlets;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ViewBaseServlet extends HttpServlet {
private TemplateEngine templateEngine;
@Override
public void init() throws ServletException {
// 1.获取ServletContext对象
ServletContext servletContext = this.getServletContext();
// 2.创建Thymeleaf解析器对象
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
// 3.给解析器对象设置参数
// ①HTML是默认模式,明确设置是为了代码更容易理解
templateResolver.setTemplateMode(TemplateMode.HTML);
// ②设置前缀
String viewPrefix = servletContext.getInitParameter("view-prefix");
templateResolver.setPrefix(viewPrefix);
// ③设置后缀
String viewSuffix = servletContext.getInitParameter("view-suffix");
templateResolver.setSuffix(viewSuffix);
// ④设置缓存过期时间(毫秒)
templateResolver.setCacheTTLMs(60000L);
// ⑤设置是否缓存
templateResolver.setCacheable(true);
// ⑥设置服务器端编码方式
templateResolver.setCharacterEncoding("utf-8");
// 4.创建模板引擎对象
templateEngine = new TemplateEngine();
// 5.给模板引擎对象设置模板解析器
templateEngine.setTemplateResolver(templateResolver);
}
protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 1.设置响应体内容类型和字符集
resp.setContentType("text/html;charset=UTF-8");
// 2.创建WebContext对象
WebContext webContext = new WebContext(req, resp, getServletContext());
// 3.处理模板数据
templateEngine.process(templateName, webContext, resp.getWriter());
}
}
② 在web.xml文件中添加配置
<!--配置上下文参数-->
<context-param>
<param-name>view-prefix</param-name>
<param-value>/</param-value>
</context-param>
<context-param>
<param-name>view-suffix</param-name>
<param-value>.html</param-value>
</context-param>
③ 使得我们的Servlet继承ViewBaseServlet
package com.example.servlets;
import com.example.fruit.dao.FruitDAO;
import com.example.fruit.dao.impl.FruitDAOImpl;
import com.example.fruit.pojo.Fruit;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
//Servlet从3.0版本开始支持注解方式的注册
@WebServlet("/index")
public class IndexServlet extends ViewBaseServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
FruitDAO fruitDAO = new FruitDAOImpl();
List<Fruit> fruitList = fruitDAO.getFruitList();
//保存到session作用域
HttpSession session = req.getSession();
session.setAttribute("fruitList",fruitList);
//此处的视图名称是index
//thymeleaf会将这个 逻辑视图名称 对应的 物理视图 名称上去
//逻辑视图名称:index
//物理视图名称:view-prefix + 逻辑视图名称 + view-suffix
//所以真实的视图名称是:/ index .html
super.processTemplate("index",req,resp);
}
}
④ 在webapp/css目录下新建index.css
*{
color: threeddarkshadow;
}
body{
margin:0;
padding:0;
background-color:#808080;
}
div{
position:relative;
float:left;
}
#div_container{
width:80%;
height:100%;
border:0px solid blue;
margin-left:10%;
float:left;
background-color: honeydew;
border-radius:8px;
}
#div_fruit_list{
width:100%;
border:0px solid red;
}
#tbl_fruit{
width:60%;
line-height:28px;
margin-top:16px;
margin-left:20%;
}
#tbl_fruit , #tbl_fruit tr , #tbl_fruit th , #tbl_fruit td{
border:1px solid gray;
border-collapse:collapse;
text-align:center;
font-size:16px;
font-family:"黑体";
font-weight:lighter;
}
.w20{
width:20%;
}
.delImg{
width:24px;
height:24px;
}
.btn{
border:1px solid lightgray;
width:80px;
height:24px;
}
.center{
text-align:center;
}
.f30{
font-size: 30px;
}
⑤ 在webapp下新建index.html
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<div id="div_container">
<div id="div_fruit_list">
<p class="center f30">欢迎使用水果库存后台管理系统</p>
<table id="tbl_fruit">
<tr>
<th class="w20">名称</th>
<th class="w20">单价</th>
<th class="w20">库存</th>
<th>操作</th>
</tr>
<tr th:if="${#lists.isEmpty(session.fruitList)}">
<td colspan="4">对不起,库存为空!</td>
</tr>
<tr th:unless="${#lists.isEmpty(session.fruitList)}" th:each="fruit : ${session.fruitList}">
<td th:text="${fruit.fname}"></td>
<td th:text="${fruit.price}"></td>
<td th:text="${fruit.fcount}"></td>
<td><img src="imgs/del.jpg" class="delImg"/></td>
</tr>
</table>
</div>
</div>
</body>
</html>
⑥ 浏览器访问:http://localhost:8080/index
图片可以使用前面fruit的图片
8.保存作用域
原始情况下,保存作用域我们可以有四个:page(页面级别,现在几乎不用),request(一次请求响应范围),session(一次会话范围),application(整个应用程序范围)
8.1 request(一次请求响应范围)
实验
① 保存数据到保存作用域
package com.example.servlet2;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//演示request保存作用域
@WebServlet("/demo01")
public class Demo01Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.向request保存作用域保存数据
req.setAttribute("uname","lili");
//2.客户端重定向
resp.sendRedirect("demo02");
}
}
② 获取保存作用域的数据
package com.example.servlet2;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/demo02")
public class Demo02Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取request保存作用域保存的数据,key为uname
Object uname = req.getAttribute("uname");
System.out.println(uname);
}
}
③ 访问:http://localhost:8080/demo01
idea显示:null
地址自动跳转到demo02,demo02无法获取demo01保存作用域的数据
④ 修改demo01Servlet
package com.example.servlet2;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/demo01")
public class Demo01Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.向request保存作用域保存数据
req.setAttribute("uname","lili");
//2.客户端重定向
// resp.sendRedirect("demo02");
//3.服务器端转发
req.getRequestDispatcher("demo02").forward(req,resp);
}
}
⑤ 访问:http://localhost:8080/demo01
idea显示:lili
访问地址认为demo01,而且获取到保存作用域的数据
8.2 session(一次会话范围)
实验
演示session保存作用域
① Demo03Servlet
package com.example.servlet2;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//演示session保存作用域
@WebServlet("/demo03")
public class Demo03Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.向session保存作用域保存数据
req.getSession().setAttribute("uname","lili");
//2.客户端重定向
resp.sendRedirect("demo04");
//3.服务器端转发
// req.getRequestDispatcher("demo04").forward(req,resp);
}
}
② Demo04Servlet
package com.example.servlet2;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/demo04")
public class Demo04Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取session保存作用域保存的数据,key为uname
Object uname = req.getSession().getAttribute("uname");
System.out.println(uname);
}
}
③ 访问:http://localhost:8080/demo03
可以获取到保存作用域的数据
8.3 application(整个应用程序范围)
实验
① Demo05Servlet
package com.example.servlet2;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//演示application保存作用域
@WebServlet("/demo05")
public class Demo05Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.向application保存作用域保存数据
//ServletContext:Servlet上下文
ServletContext application = req.getServletContext();
application.setAttribute("uname","lili");
//2.客户端重定向
// resp.sendRedirect("demo06");
//3.服务器端转发
// req.getRequestDispatcher("demo04").forward(req,resp);
}
}
② Demo06Servlet
package com.example.servlet2;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/demo06")
public class Demo06Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取application保存作用域保存的数据,key为uname
ServletContext apllication = req.getServletContext();
Object uname = apllication.getAttribute("uname");
System.out.println(uname);
}
}
③ 在浏览器中访问:http://localhost:8080/demo05
在另一种浏览器中访问:http://localhost:8080/demo06
能够获取到lili
说明保存作用域范围是整个应用程序范围
9.路径问题
1)相对路径
2)绝对路径
<base href="http://localhost:8080/" /> 的作用是当前页面上的所有的路径以这个为基础
<link href="css/shopping.css">
在Thymeleaf中(下面的@表示根目录)
th:href="@{}"
<link th:href="@{css/shopping.css}">